diff options
-rw-r--r-- | .gitignore | 6 | ||||
-rw-r--r-- | .gitmodules | 4 | ||||
-rw-r--r-- | .htaccess | 6 | ||||
-rw-r--r-- | GNUmakefile | 14 | ||||
-rw-r--r-- | INSTALL | 79 | ||||
-rw-r--r-- | README | 63 | ||||
-rw-r--r-- | __init__.py | 0 | ||||
m--------- | dico | 0 | ||||
-rw-r--r-- | dicoclient/__init__.py | 19 | ||||
-rw-r--r-- | dicoclient/dicoclient.py | 415 | ||||
-rw-r--r-- | dicoclient/dicoshell.py | 321 | ||||
-rw-r--r-- | dicoclient/setup.py | 39 | ||||
-rw-r--r-- | dicoweb.wsgi | 27 | ||||
-rw-r--r-- | docker-compose.override.yml | 27 | ||||
-rw-r--r-- | docker/Dockerfile | 9 | ||||
-rw-r--r-- | docker/gcide.css (renamed from static/gcide.css) | 0 | ||||
-rw-r--r-- | docker/settings_docker.py | 255 | ||||
-rw-r--r-- | docker/templates/404.html (renamed from templates/404.html) | 0 | ||||
-rw-r--r-- | docker/templates/500.html (renamed from templates/500.html) | 0 | ||||
-rw-r--r-- | docker/templates/about.html (renamed from templates/about.html) | 0 | ||||
-rw-r--r-- | docker/templates/base.html (renamed from templates/base.html) | 31 | ||||
-rw-r--r-- | docker/templates/download.html (renamed from templates/download.html) | 6 | ||||
-rw-r--r-- | docker/templates/index.html (renamed from templates/index.html) | 30 | ||||
-rw-r--r-- | docker/templates/info.html | 38 | ||||
-rw-r--r-- | docker/templates/license.html (renamed from templates/license.html) | 0 | ||||
-rw-r--r-- | docker/templates/opensearch.xml (renamed from templates/opensearch.xml) | 6 | ||||
-rw-r--r-- | docker/urls.py (renamed from templatetags/dictlookup.py) | 23 | ||||
-rw-r--r-- | docker/views.py | 346 | ||||
-rw-r--r-- | docker/withsetting.py (renamed from templatetags/withsetting.py) | 2 | ||||
-rw-r--r-- | dummy_translations.py | 40 | ||||
-rw-r--r-- | gcide.wsgi | 25 | ||||
-rw-r--r-- | index.html | 15 | ||||
-rw-r--r-- | manage.py | 23 | ||||
-rw-r--r-- | settings-sample.py | 125 | ||||
-rw-r--r-- | static/18px-Bulbgraph.png | bin | 1210 -> 0 bytes | |||
-rw-r--r-- | static/dicoweb.css | 134 | ||||
-rw-r--r-- | static/dicoweb.js | 80 | ||||
-rw-r--r-- | static/gnu-head-sm.jpg | bin | 5286 -> 0 bytes | |||
-rw-r--r-- | templatetags/__init__.py | 0 | ||||
-rw-r--r-- | templatetags/macros.py | 160 | ||||
-rw-r--r-- | urls.py | 28 | ||||
-rw-r--r-- | views.py | 253 |
42 files changed, 803 insertions, 1846 deletions
@@ -1,4 +1,4 @@ -.emacs.desktop -settings.py +.emacs* +.env *~ -tmp/ +\#* diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..9529e2c --- /dev/null +++ b/.gitmodules @@ -0,0 +1,4 @@ +[submodule "dico"] + path = dico + url = git://git.gnu.org.ua/dico.git + branch = docker diff --git a/.htaccess b/.htaccess deleted file mode 100644 index 2df5844..0000000 --- a/.htaccess +++ /dev/null @@ -1,6 +0,0 @@ -Options All -Indexes -<Files ~ "^\.emacs"> - Order allow,deny - Deny from all - Satisfy All -</Files> diff --git a/GNUmakefile b/GNUmakefile new file mode 100644 index 0000000..267803f --- /dev/null +++ b/GNUmakefile @@ -0,0 +1,14 @@ +command=docker compose -p gcideweb -f dico/docker/docker-compose.yml -f docker-compose.override.yml --env-file .env --profile=lighttpd +define goal = +$(1): + $$(command) $(1)$(if $(filter-out up, $(1)),, -d) +endef + +$(foreach verb,build config up down restart ps, $(eval $(call goal, $(verb)))) + +bootstrap: + git submodule init + git submodule update + cd dico && ./bootstrap --force --skip-po + + diff --git a/INSTALL b/INSTALL deleted file mode 100644 index ee9a98b..0000000 --- a/INSTALL +++ /dev/null @@ -1,79 +0,0 @@ -GNU Dico - Dicoweb INSTALL -Copyright (C) 2008-2010, 2012 Wojciech Polak - -* Dicoweb requirements -====================== - -- Django 1.0+ -- a Python Web framework (http://www.djangoproject.com/) -- Wit -- a wiki translator distributed within GNU Dico. - (http://puszcza.gnu.org.ua/projects/wit/) - -* Installation instructions -=========================== - -Rename 'settings-sample.py' to 'settings.py' and edit your -local Dicoweb site configuration. - - -** The development/test server ------------------------------- - -Change the current working directory into the `dicoweb' directory -and run the command `python manage.py runserver'. You will see -the following output: - - Validating models... - 0 errors found. - - Django version 1.0, using settings 'dicoweb.settings' - Development server is running at http://127.0.0.1:8000/ - Quit the server with CONTROL-C. - -** Production server with mod_wsgi ----------------------------------- - -Apache configuration: - - LoadModule wsgi_module modules/mod_wsgi.so - WSGIScriptAlias / /usr/local/django/dicoweb/dicoweb.wsgi - Alias /static "/usr/local/django/dicoweb/static" - -More detailed information is available at: -http://code.google.com/p/modwsgi/wiki/IntegrationWithDjango - -** Production server with mod_python ------------------------------------- - -Apache configuration: - - LoadModule python_module modules/mod_python.so - <Location "/"> - SetHandler python-program - PythonHandler django.core.handlers.modpython - PythonPath "sys.path + ['/usr/local/django', '/usr/local/django/dicoweb']" - SetEnv DJANGO_SETTINGS_MODULE dicoweb.settings - PythonInterpreter dicoweb - PythonDebug Off - </Location> - - <Location "/static"> - SetHandler None - </Location> - <Location "/favicon.ico"> - SetHandler None - </Location> - - <Directory "/usr/local/django/dicoweb/"> - AllowOverride All - Options None - Order allow,deny - Allow from all - </Directory> - - - -Local Variables: -mode: outline -paragraph-separate: "[ ]*$" -version-control: never -End: @@ -0,0 +1,63 @@ +* Overview + +This file describes docker-based setup for the gcide web site. + +* Installation + +1. make bootstrap + +This will prepare GNU dico sources for building. + +2. make build + +This will build the docker images. + +3. Edit the .env file. It should contain the following variables: + + DICOWEB_NAME + Domain name of the server. + DICOWEB_PORT + Port the dicoweb container is listening on. + DICOWEB_ADMIN + Email address of the administrator. + DICT_SERVER + IP address or hostname of the dict server to use. The server must + offer the gcide database. + PIES_SYSLOG_SERVER + IP address and port number of the syslog server. + +4. Configure your syslog server to receive and route log messages from + gcideweb. + +5. docker compose up -d + +* Maintenance + +Most commands are performed by invoking `make' with the corresponding +command verb: + +** make config + + Inspect the resulting docker-compose.yml. + +** make build + + Build all images. + +** make up + + Start up the services. + +** make down + + Pull the services down. + +** make ps + + List running services. + +Local Variables: +mode: outline +paragraph-separate: "[ ]*$" +version-control: never +End: diff --git a/__init__.py b/__init__.py deleted file mode 100644 index e69de29..0000000 --- a/__init__.py +++ /dev/null diff --git a/dico b/dico new file mode 160000 +Subproject b6bce074e9bc85002b55d98397d4d3a6a7b540c diff --git a/dicoclient/__init__.py b/dicoclient/__init__.py deleted file mode 100644 index a300cea..0000000 --- a/dicoclient/__init__.py +++ /dev/null @@ -1,19 +0,0 @@ -# This file is part of GNU Dico. -# Copyright (C) 2008-2009, 2012 Wojciech Polak -# -# GNU Dico is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 3, or (at your option) -# any later version. -# -# GNU Dico is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with GNU Dico. If not, see <http://www.gnu.org/licenses/>. - -__all__ = ["dicoclient"] - -from dicoclient import * diff --git a/dicoclient/dicoclient.py b/dicoclient/dicoclient.py deleted file mode 100644 index 76336c2..0000000 --- a/dicoclient/dicoclient.py +++ /dev/null @@ -1,415 +0,0 @@ -# This file is part of GNU Dico. -# Copyright (C) 2008-2010, 2012 Wojciech Polak -# -# GNU Dico is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 3, or (at your option) -# any later version. -# -# GNU Dico is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with GNU Dico. If not, see <http://www.gnu.org/licenses/>. - -import re -import socket -import base64 -import quopri -import hashlib - -__version__ = '1.0' - -class DicoClient: - """GNU Dico client module written in Python - (a part of GNU Dico software)""" - - host = None; - levenshtein_distance = 0 - mime = False - - verbose = 0 - timeout = 10 - transcript = False - __connected = False - - def __init__ (self, host=None): - if host != None: - self.host = host; - - def __del__ (self): - if self.__connected: - self.socket.close () - - def open (self, host=None, port=2628, cred=None): - """Open the connection to the DICT server.""" - if host != None: - self.host = host - if self.verbose: - self.__debug ('Connecting to %s:%d' % (self.host, port)) - socket.setdefaulttimeout (int (self.timeout)) - self.socket = socket.socket (socket.AF_INET, socket.SOCK_STREAM) - self.socket.setsockopt (socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) - self.socket.connect ((self.host, port)) - self.__connected = True - self.fd = self.socket.makefile (); - - self.server_banner = self.__read ()[0] - capas, msgid = re.search ('<(.*)> (<.*>)$', - self.server_banner).groups () - self.server_capas = capas.split ('.') - self.server_msgid = msgid - - self.__send_client () - self.__read () - if cred and 'user' in cred and 'password' in cred: - self.auth(cred['user'], cred['password']) - - def auth (self, user, passwd): - if self.__connected and 'auth' in self.server_capas: - if self.verbose: - self.__debug ('Authenticating on %s' % (self.host)) - m = hashlib.md5() - m.update(self.server_msgid) - m.update(passwd) - self.__send ('AUTH %s %s' % (user, m.hexdigest())) - res = self.__read () - code, msg = res[0].split (' ', 1) - if int (code) == 230: - return True - return False - - def close (self): - """Close the connection.""" - if self.__connected: - self.__send_quit () - self.__read () - self.socket.close () - self.__connected = False - - def option (self, name, *args): - """Send the OPTION command.""" - if self.__connected: - self.__send ('OPTION %s%s' % - (name, reduce (lambda x, y: str (x) +' '+ str (y), - args, ''))) - res = self.__read () - code, msg = res[0].split (' ', 1) - if int (code) == 250: - if name.lower () == 'mime': - self.mime = True - return True - return False - - def __get_mime (self, lines): - cnt = 0 - mimeinfo = {} - firstline = lines[0].lower () - if firstline.find ('content-type:') != -1 or \ - firstline.find ('content-transfer-encoding:') != -1: - cnt += 1 - for line in lines: - if line == '': - break - t = line.split (':', 1) - mimeinfo[t[0].lower ()] = t[1].strip () - cnt += 1 - for i in range (0, cnt): - lines.pop (0) - else: - lines.pop (0) - if 'content-transfer-encoding' in mimeinfo: - if mimeinfo['content-transfer-encoding'].lower () == 'base64': - buf = base64.decodestring ('\n'.join (lines)) - lines[:] = (buf.split ('\r\n')) - if lines[-1] == '': del lines[-1] - del mimeinfo['content-transfer-encoding'] - elif mimeinfo['content-transfer-encoding'].lower () == 'quoted-printable': - buf = quopri.decodestring ('\n'.join (lines)) - lines[:] = buf.split ('\r\n') - if lines[-1] == '': del lines[-1] - del mimeinfo['content-transfer-encoding'] - return mimeinfo - - def __get_rs (self, line): - code, text = line.split (' ', 1) - code = int (code) - return code, text - - def __read (self): - if not self.__connected: - raise DicoNotConnectedError ('Not connected') - buf = [] - line = self.__readline () - if len (line) == 0: - raise DicoNotConnectedError ('Not connected') - buf.append (line) - code, text = self.__get_rs (line) - - if code >= 100 and code < 200: - if code == 150: - while True: - rs = self.__readline () - code, text = self.__get_rs (rs) - if code != 151: - buf.append (rs) - break - buf.append ([rs, self.__readblock ()]) - else: - buf.append (self.__readblock ()) - buf.append (self.__readline ()) - return buf - - def __readline (self): - line = self.fd.readline ().rstrip () - if self.transcript: - self.__debug ('S:%s' % line) - return line - - def __readblock (self): - buf = [] - while True: - line = self.__readline () - if line == '.': - break - buf.append (line) - return buf - - - def __send (self, command): - if not self.__connected: - raise DicoNotConnectedError ('Not connected') - self.socket.send (command.encode ('utf_8') + "\r\n") - if self.transcript: - self.__debug ('C:%s' % command) - - def __send_client (self): - if self.verbose: - self.__debug ('Sending client information') - self.__send ('CLIENT "%s %s"' % ("GNU Dico (Python Edition)", - __version__)) - - def __send_quit (self): - if self.verbose: - self.__debug ('Quitting') - self.__send ('QUIT'); - - def __send_show (self, what, arg=None): - if arg != None: - self.__send ('SHOW %s "%s"' % (what, arg)) - else: - self.__send ('SHOW %s' % what) - return self.__read () - - def __send_define (self, database, word): - if self.verbose: - self.__debug ('Sending query for word "%s" in database "%s"' % - (word, database)) - self.__send ('DEFINE "%s" "%s"' % (database, word)) - return self.__read () - - def __send_match (self, database, strategy, word): - if self.verbose: - self.__debug ('Sending query to match word "%s" in database "%s", using "%s"' - % (word, database, strategy)) - self.__send ('MATCH "%s" "%s" "%s"' % (database, strategy, word)) - return self.__read () - - def __send_xlev (self, distance): - self.__send ('XLEV %u' % distance) - return self.__read () - - def show_databases (self): - """List all accessible databases.""" - if self.verbose: - self.__debug ('Getting list of databases') - res = self.__send_show ('DATABASES') - if self.mime: - mimeinfo = self.__get_mime (res[1]) - dbs_res = res[1:-1][0] - dbs = [] - for d in dbs_res: - short_name, full_name = d.split (' ', 1) - dbs.append ([short_name, self.__unquote (full_name)]) - dct = { - 'count': len (dbs), - 'databases': dbs, - } - return dct - - def show_strategies (self): - """List available matching strategies.""" - if self.verbose: - self.__debug ('Getting list of strategies') - res = self.__send_show ('STRATEGIES') - if self.mime: - mimeinfo = self.__get_mime (res[1]) - sts_res = res[1:-1][0] - sts = [] - for s in sts_res: - short_name, full_name = s.split (' ', 1) - sts.append ([short_name, self.__unquote (full_name)]) - dct = { - 'count': len (sts), - 'strategies': sts, - } - return dct - - def show_info (self, database): - """Provide information about the database.""" - res = self.__send_show ("INFO", database) - code, msg = res[0].split (' ', 1) - if int (code) < 500: - if self.mime: - mimeinfo = self.__get_mime (res[1]) - dsc = res[1] - return {'desc': '\n'.join (dsc), 'type': 'info' } - else: - return {'error': code, 'msg': msg} - - def show_lang_db (self): - """Show databases with their language preferences.""" - res = self.__send_show ('LANG DB') - code, msg = res[0].split (' ', 1) - if int (code) < 500: - if self.mime: - mimeinfo = self.__get_mime (res[1]) - dsc = res[1] - lang_src = {} - lang_dst = {} - for i in dsc: - pair = i.split (' ', 1)[1] - src, dst = pair.split (':', 1) - for j in src: - lang_src[src.strip()] = True - for j in dst: - lang_dst[dst.strip()] = True - return { - 'desc': '\n'.join (dsc), - 'type': 'lang', - 'lang_src': lang_src.keys (), - 'lang_dst': lang_dst.keys (), - } - else: - return {'error': code, 'msg': msg} - - def show_lang_pref (self): - """Show server language preferences.""" - res = self.__send_show ('LANG PREF') - code, msg = res[0].split (' ', 1) - if int (code) < 500: - return {'msg': msg} - else: - return {'error': code, 'msg': msg} - - def show_server (self): - """Provide site-specific information.""" - res = self.__send_show ('SERVER') - code, msg = res[0].split (' ', 1) - if int (code) < 500: - dsc = res[1] - return {'desc': '\n'.join (dsc), 'type': 'server'} - else: - return {'error': code, 'msg': msg} - - def define (self, database, word): - """Look up word in database.""" - database = database.replace ('"', "\\\"") - word = word.replace ('"', "\\\"") - res = self.__send_define (database, word) - code, msg = res[-1].split (' ', 1) - if int (code) < 500: - defs_res = res[1:-1] - defs = [] - rx = re.compile ('^\d+ ("[^"]+"|\w+) ([a-zA-Z0-9_\-]+) ("[^"]*"|\w+)') - for i in defs_res: - term, db, db_fullname = rx.search (i[0]).groups () - df = { - 'term': self.__unquote (term), - 'db': db, - 'db_fullname': self.__unquote (db_fullname), - } - if self.mime: - mimeinfo = self.__get_mime (i[1]) - df.update (mimeinfo) - df['desc'] = '\n'.join (i[1]) - defs.append (df) - dct = { - 'count': len (defs), - 'definitions': defs, - 'type': 'define' - } - return dct - else: - return {'error': code, 'msg': msg} - - def match (self, database, strategy, word): - """Match word in database using strategy.""" - if not self.__connected: - raise DicoNotConnectedError ('Not connected') - - if self.levenshtein_distance and 'xlev' in self.server_capas: - res = self.__send_xlev (self.levenshtein_distance) - code, msg = res[-1].split (' ', 1) - if int (code) != 250 and self.verbose: - self.__debug ('Server rejected XLEV command') - self.__debug ('Server reply: %s' % msg) - - database = database.replace ('"', "\\\"") - strategy = strategy.replace ('"', "\\\"") - word = word.replace ('"', "\\\"") - - res = self.__send_match (database, strategy, word) - code, msg = res[-1].split (' ', 1) - if int (code) < 500: - if self.mime: - mimeinfo = self.__get_mime (res[1]) - mts_refs = res[1:-1][0] - mts = {} - for i in mts_refs: - db, term = i.split (' ', 1) - if mts.has_key (db): - mts[db].append (self.__unquote (term)) - else: - mts[db] = [self.__unquote (term)] - dct = { - 'matches': mts, - } - return dct - else: - return {'error': code, 'msg': msg} - - def xlev (self, distance): - """Set Levenshtein distance.""" - self.levenshtein_distance = distance - res = self.__send_xlev (distance) - code, msg = res[0].split (' ', 1) - if int (code) == 250: - return True - return False - - def __unquote (self, s): - s = s.replace ("\\\\'", "'") - if s[0] == '"' and s[-1] == '"': - s = s[1:-1] - try: - s = self.__decode (s) - except UnicodeEncodeError: - pass - return s - - def __decode (self, encoded): - for octc in (c for c in re.findall (r'\\(\d{3})', encoded)): - encoded = encoded.replace (r'\%s' % octc, chr (int (octc, 8))) - return unicode (encoded, 'utf_8') - - def __debug (self, msg): - print 'dico: Debug: %s' % msg - -class DicoNotConnectedError (Exception): - def __init__ (self, value): - self.parameter = value - def __str__(self): - return repr (self.parameter) diff --git a/dicoclient/dicoshell.py b/dicoclient/dicoshell.py deleted file mode 100644 index 1c0e64d..0000000 --- a/dicoclient/dicoshell.py +++ /dev/null @@ -1,321 +0,0 @@ -# This file is part of GNU Dico. -# Copyright (C) 2008-2010, 2012 Wojciech Polak -# -# GNU Dico is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 3, or (at your option) -# any later version. -# -# GNU Dico is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with GNU Dico. If not, see <http://www.gnu.org/licenses/>. - -import re -import os -import sys -import atexit -import getopt -import readline -import curses.ascii -import socket -import dicoclient - -class Shell: - """Simple GNU Dico-Python Shell.""" - - prompt = 'dico> ' - prefix = '.' - - default_host = 'gnu.org.ua' - database = '!' - strategy = '.' - last_matches = [] - last_databases = [] - last_strategies = [] - transcript = False - - def __init__ (self, opts, args): - for o, a in opts: - if o in ('-h', '--host'): - self.default_host = a - - self.dc = dicoclient.DicoClient (self.default_host) - - def run (self): - histfile = os.path.expanduser ('~/.dico_history') - try: - readline.read_history_file (histfile) - except IOError: - pass - atexit.register (readline.write_history_file, histfile) - - print '\nType ? for help summary\n' - while True: - try: - input = raw_input (self.prompt).strip () - input = unicode (input, 'utf_8') - except (EOFError, KeyboardInterrupt): - print - sys.exit () - - try: - self.parse (input) - except socket.timeout: - self.__error ('socket timed out') - except dicoclient.DicoNotConnectedError: - try: - self.dc.open () - dict = self.dc.show_databases () - self.last_databases = dict['databases'] - dict = self.dc.show_strategies () - self.last_strategies = dict['strategies'] - self.parse (input) - except socket.error, (errno, strerror): - self.__error (strerror) - - def parse (self, input): - if len (input) < 1: - return - if input[0] == self.prefix: - self.parse_command (input[1:]) - elif input == '?': - self.print_help () - elif re.match (r'^[0-9]+$', input): - try: - match = self.last_matches[int (input)] - dict = self.dc.define (match[0], match[1]) - if 'count' in dict: - for d in dict['definitions']: - print 'From %s, %s:' % (d['db'], d['db_fullname']. - encode ('utf_8')) - print d['desc'] - elif 'error' in dict: - print dict['msg'] - except IndexError: - self.__error ('No previous match') - elif input[0] == '/': - if len (input) > 1: - dict = self.dc.match (self.database, self.strategy, input[1:]) - if 'matches' in dict: - self.last_matches = [] - lmi = 0 - for db in dict['matches']: - print 'From %s, %s:' % (db, self.__lookup_db (db). - encode ('utf_8')) - for term in dict['matches'][db]: - print '%4d) "%s"' % (lmi, term.encode ('utf_8')) - self.last_matches.append ([db, term]) - lmi = lmi + 1 - elif 'error' in dict: - print dict['msg'] - else: - if len (self.last_matches) > 0: - m = {} - lmi = 0 - for i, db in enumerate (self.last_matches): - if not db[0] in m: m[db[0]] = [] - m[db[0]].append (self.last_matches[i][1]) - for db in m: - print 'From %s, %s:' % (db, self.__lookup_db (db)) - for term in m[db]: - print '%4d) "%s"' % (lmi, term) - lmi = lmi + 1 - else: - self.__error ('No previous match') - elif input[0] == '!': - if re.match (r'^![0-9]+$', input): - number = int (input[1:]) - |