From: Guillaume Pellerin Date: Wed, 13 Apr 2016 11:47:37 +0000 (+0200) Subject: refactor app X-Git-Tag: 1.6.1~1^2~8^2 X-Git-Url: https://git.parisson.com/?a=commitdiff_plain;h=39173b5c7b86564524780b99140fbccf49dcb2c7;p=telemeta.git refactor app --- diff --git a/.gitignore b/.gitignore index 78da6b0f..7267b3b1 100644 --- a/.gitignore +++ b/.gitignore @@ -17,6 +17,7 @@ sdist develop-eggs .installed.cfg *.directory +.init # Installer logs pip-log.txt diff --git a/app/deploy/app.sh b/app/deploy/app.sh deleted file mode 100644 index 723fd388..00000000 --- a/app/deploy/app.sh +++ /dev/null @@ -1,57 +0,0 @@ -#!/bin/sh - -# paths -app='/srv/app' -manage=$app'/manage.py' -wsgi=$app'/wsgi.py' -static='/srv/static/' -media='/srv/media/' -src='/srv/src/' - -# uwsgi params -port=8000 -processes=8 -threads=8 -autoreload=3 -uid='www-data' -gid='www-data' - -# stating apps -# pip install django-angular - -# waiting for other network services -sh $app/deploy/wait.sh - -# django setup -python $manage wait-for-db -python $manage syncdb --noinput -python $manage migrate --noinput -python $manage bower_install -- --allow-root -python $manage collectstatic --noinput -python $manage telemeta-create-admin-user -python $manage telemeta-create-boilerplate - -if [ $DEBUG = "False" ] -then - python $manage update_index --workers $processes & - if [ ! -f .init ] - then - chown -R www-data:www-data $media - touch .init - fi -fi - -if [ $1 = "--runserver" ] -then - python $manage runserver_plus 0.0.0.0:8000 -else - # static files auto update - watchmedo shell-command --patterns="*.js;*.css" --recursive \ - --command='python '$manage' collectstatic --noinput' $src & - - # app start - uwsgi --socket :$port --wsgi-file $wsgi --chdir $app --master \ - --processes $processes --threads $threads \ - --uid $uid --gid $gid \ - --py-autoreload $autoreload -fi diff --git a/app/deploy/apt.list b/app/deploy/apt.list deleted file mode 100644 index 81a807a5..00000000 --- a/app/deploy/apt.list +++ /dev/null @@ -1,12 +0,0 @@ -deb http://ftp.debian.org/debian/ wheezy-backports main contrib non-free -deb-src http://ftp.debian.org/debian/ wheezy-backports main contrib non-free - -deb http://security.debian.org/ wheezy/updates main -deb-src http://security.debian.org/ wheezy/updates main - -deb http://www.deb-multimedia.org wheezy main non-free -deb http://www.deb-multimedia.org wheezy-backports main - -deb http://debian.parisson.com/debian/ wheezy main -deb-src http://debian.parisson.com/debian wheezy main - diff --git a/app/deploy/nginx-dev.conf b/app/deploy/nginx-dev.conf deleted file mode 100644 index 164f71da..00000000 --- a/app/deploy/nginx-dev.conf +++ /dev/null @@ -1,28 +0,0 @@ -server_tokens off; - -server { - listen 80; - server_name nginx; - charset utf-8; - - access_log /var/log/nginx/app-access.log; - error_log /var/log/nginx/app-error.log; - - # max upload size - client_max_body_size 4096M; # adjust to taste - - # phpmyadmin - location /phpmyadmin/ { - proxy_pass http://phpmyadmin/; - #proxy_set_header Host $http_host; - #proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; - #proxy_set_header X-Forwarded-Server $http_host; - #proxy_redirect / /phpmyadmin/; - #proxy_cookie_path / /phpmyadmin/; - } - - location / { - uwsgi_pass app:8000; - include /etc/nginx/uwsgi_params; - } -} diff --git a/app/deploy/nginx.conf b/app/deploy/nginx.conf deleted file mode 100644 index 4cadc469..00000000 --- a/app/deploy/nginx.conf +++ /dev/null @@ -1,37 +0,0 @@ -server_tokens off; - -server { - listen 80; - server_name nginx; - charset utf-8; - - access_log /var/log/nginx/app-access.log; - error_log /var/log/nginx/app-error.log; - - # max upload size - client_max_body_size 4096M; # adjust to taste - - # Django media - location /media/ { - alias /srv/media/; # your Django project's media files - amend as required - } - # Django static - location /static { - alias /srv/static/; # your Django project's static files - amend as required - } - - # phpmyadmin - location /phpmyadmin/ { - proxy_pass http://phpmyadmin/; - #proxy_set_header Host $http_host; - #proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; - #proxy_set_header X-Forwarded-Server $http_host; - #proxy_redirect / /phpmyadmin/; - #proxy_cookie_path / /phpmyadmin/; - } - - location / { - uwsgi_pass app:8000; - include /etc/nginx/uwsgi_params; - } -} diff --git a/app/deploy/wait.sh b/app/deploy/wait.sh deleted file mode 100644 index a3341e05..00000000 --- a/app/deploy/wait.sh +++ /dev/null @@ -1,18 +0,0 @@ -#!/bin/sh - -apt-get install -y --force-yes netcat - -set -e - -host=$(env | grep _TCP_ADDR | cut -d = -f 2) -port=$(env | grep _TCP_PORT | cut -d = -f 2) - -echo -n "waiting for TCP connection to $host:$port..." - -while ! nc -w 1 $host $port 2>/dev/null -do - echo -n . - sleep 1 -done - -echo 'ok' \ No newline at end of file diff --git a/app/deploy/worker.sh b/app/deploy/worker.sh deleted file mode 100644 index 78d23a4e..00000000 --- a/app/deploy/worker.sh +++ /dev/null @@ -1,17 +0,0 @@ -#!/bin/sh - -# paths -app='/srv/app' -manage=$app'/manage.py' -wsgi=$app'/wsgi.py' - -# stating apps -# pip install django-environ redis - -# waiting for other services -sh $app/deploy/wait.sh - -# Starting celery worker with the --autoreload option will enable the worker to watch for file system changes -# This is an experimental feature intended for use in development only -# see http://celery.readthedocs.org/en/latest/userguide/workers.html#autoreloading -python $manage celery worker --autoreload -A worker diff --git a/app/manage.py b/app/manage.py index d18fd971..1f7f7d15 100755 --- a/app/manage.py +++ b/app/manage.py @@ -2,8 +2,6 @@ import os, sys if __name__ == "__main__": - os.environ.setdefault("DJANGO_SETTINGS_MODULE", "sandbox.settings") - + os.environ.setdefault("DJANGO_SETTINGS_MODULE", "settings") from django.core.management import execute_from_command_line - execute_from_command_line(sys.argv) diff --git a/app/robots.txt b/app/robots.txt new file mode 100644 index 00000000..5ac75ebe --- /dev/null +++ b/app/robots.txt @@ -0,0 +1,4 @@ +User-agent: * +Disallow: *.mp3$ +Disallow: */WIDTHxHEIGHT/ +Disallow: */xml/ diff --git a/app/sandbox/__init__.py b/app/sandbox/__init__.py deleted file mode 100644 index 40a96afc..00000000 --- a/app/sandbox/__init__.py +++ /dev/null @@ -1 +0,0 @@ -# -*- coding: utf-8 -*- diff --git a/app/sandbox/diag.sh b/app/sandbox/diag.sh deleted file mode 100755 index 5f6c1e59..00000000 --- a/app/sandbox/diag.sh +++ /dev/null @@ -1,12 +0,0 @@ -#!/bin/sh - -app="telemeta" -dir="../../doc/devel" - -python modelviz.py -a > $dir/$app-all.dot -python modelviz.py $app > $dir/$app.dot - -dot $dir/$app-all.dot -Tpdf -o $dir/$app-all.pdf -dot $dir/$app.dot -Tpdf -o $dir/$app.pdf - -rsync -a $dir/ doc.parisson.com:/var/www/files/doc/$app/diagram/ diff --git a/app/sandbox/modelviz.py b/app/sandbox/modelviz.py deleted file mode 100644 index 24af0627..00000000 --- a/app/sandbox/modelviz.py +++ /dev/null @@ -1,359 +0,0 @@ -#!/usr/bin/env python - -"""Django model to DOT (Graphviz) converter -by Antonio Cavedoni - -Make sure your DJANGO_SETTINGS_MODULE is set to your project or -place this script in the same directory of the project and call -the script like this: - -$ python modelviz.py [-h] [-a] [-d] [-g] [-n] [-L ] [-i ] ... > .dot -$ dot .dot -Tpng -o .png - -options: - -h, --help - show this help message and exit. - - -a, --all_applications - show models from all applications. - - -d, --disable_fields - don't show the class member fields. - - -g, --group_models - draw an enclosing box around models from the same app. - - -i, --include_models=User,Person,Car - only include selected models in graph. - - -n, --verbose_names - use verbose_name for field and models. - - -L, --language - specify language used for verrbose_name localization - - -x, --exclude_columns - exclude specific column(s) from the graph. - - -X, --exclude_models - exclude specific model(s) from the graph. - - -e, --inheritance - show inheritance arrows. -""" -__version__ = "0.9" -__svnid__ = "$Id$" -__license__ = "Python" -__author__ = "Antonio Cavedoni " -__contributors__ = [ - "Stefano J. Attardi ", - "limodou ", - "Carlo C8E Miron", - "Andre Campos ", - "Justin Findlay ", - "Alexander Houben ", - "Bas van Oostveen ", - "Joern Hees " -] - -import os -import sys -import getopt - -from django.core.management import setup_environ - -try: - import settings -except ImportError: - pass -else: - setup_environ(settings) - -from django.utils.translation import activate as activate_language -from django.utils.safestring import mark_safe -from django.template import Template, Context, loader -from django.db import models -from django.db.models import get_models -from django.db.models.fields.related import \ - ForeignKey, OneToOneField, ManyToManyField, RelatedField - -try: - from django.db.models.fields.generic import GenericRelation -except ImportError: - from django.contrib.contenttypes.generic import GenericRelation - -def parse_file_or_list(arg): - if not arg: - return [] - if not ',' in arg and os.path.isfile(arg): - return [e.strip() for e in open(arg).readlines()] - return arg.split(',') - - -def generate_dot(app_labels, **kwargs): - disable_fields = kwargs.get('disable_fields', False) - include_models = parse_file_or_list(kwargs.get('include_models', "")) - all_applications = kwargs.get('all_applications', False) - use_subgraph = kwargs.get('group_models', False) - verbose_names = kwargs.get('verbose_names', False) - inheritance = kwargs.get('inheritance', False) - language = kwargs.get('language', None) - if language is not None: - activate_language(language) - exclude_columns = parse_file_or_list(kwargs.get('exclude_columns', "")) - exclude_models = parse_file_or_list(kwargs.get('exclude_models', "")) - - def skip_field(field): - if exclude_columns: - if verbose_names and field.verbose_name: - if field.verbose_name in exclude_columns: - return True - if field.name in exclude_columns: - return True - return False - - - - - t = loader.get_template('django_extensions/graph_models/head.html') - c = Context({}) - dot = t.render(c) - - apps = [] - if all_applications: - apps = models.get_apps() - - for app_label in app_labels: - app = models.get_app(app_label) - if not app in apps: - apps.append(app) - - graphs = [] - for app in apps: - graph = Context({ - 'name': '"%s"' % app.__name__, - 'app_name': "%s" % '.'.join(app.__name__.split('.')[:-1]), - 'cluster_app_name': "cluster_%s" % app.__name__.replace(".", "_"), - 'disable_fields': disable_fields, - 'use_subgraph': use_subgraph, - 'models': [] - }) - - appmodels = get_models(app) - abstract_models = [] - for appmodel in appmodels: - abstract_models = abstract_models + [abstract_model for abstract_model in appmodel.__bases__ if hasattr(abstract_model, '_meta') and abstract_model._meta.abstract] - abstract_models = list(set(abstract_models)) # remove duplicates - appmodels = abstract_models + appmodels - - - for appmodel in appmodels: - appmodel_abstracts = [abstract_model.__name__ for abstract_model in appmodel.__bases__ if hasattr(abstract_model, '_meta') and abstract_model._meta.abstract] - - # collect all attribs of abstract superclasses - def getBasesAbstractFields(c): - _abstract_fields = [] - for e in c.__bases__: - if hasattr(e, '_meta') and e._meta.abstract: - _abstract_fields.extend(e._meta.fields) - _abstract_fields.extend(getBasesAbstractFields(e)) - return _abstract_fields - abstract_fields = getBasesAbstractFields(appmodel) - - model = { - 'app_name': appmodel.__module__.replace(".", "_"), - 'name': appmodel.__name__, - 'abstracts': appmodel_abstracts, - 'fields': [], - 'relations': [] - } - - # consider given model name ? - def consider(model_name): - if exclude_models and model_name in exclude_models: - return False - return not include_models or model_name in include_models - - if not consider(appmodel._meta.object_name): - continue - - if verbose_names and appmodel._meta.verbose_name: - model['label'] = appmodel._meta.verbose_name - else: - model['label'] = model['name'] - - # model attributes - def add_attributes(field): - if verbose_names and field.verbose_name: - label = field.verbose_name - else: - label = field.name - - t = type(field).__name__ - if isinstance(field, (OneToOneField, ForeignKey)): - t += " ({0})".format(field.rel.field_name) - # TODO: ManyToManyField, GenericRelation - - model['fields'].append({ - 'name': field.name, - 'label': label, - 'type': t, - 'blank': field.blank, - 'abstract': field in abstract_fields, - }) - - # Find all the real attributes. Relations are depicted as graph edges instead of attributes - attributes = [field for field in appmodel._meta.local_fields if not isinstance(field, RelatedField)] - - # find primary key and print it first, ignoring implicit id if other pk exists - pk = appmodel._meta.pk - if not appmodel._meta.abstract and pk in attributes: - add_attributes(pk) - for field in attributes: - if skip_field(field): - continue - if not field.primary_key: - add_attributes(field) - - # FIXME: actually many_to_many fields aren't saved in this model's db table, so why should we add an attribute-line for them in the resulting graph? - #if appmodel._meta.many_to_many: - # for field in appmodel._meta.many_to_many: - # if skip_field(field): - # continue - # add_attributes(field) - - # relations - def add_relation(field, extras=""): - if verbose_names and field.verbose_name: - label = field.verbose_name - else: - label = field.name - - # show related field name - if hasattr(field, 'related_query_name'): - label += ' (%s)' % field.related_query_name() - - _rel = { - 'target_app': field.rel.to.__module__.replace('.', '_'), - 'target': field.rel.to.__name__, - 'type': type(field).__name__, - 'name': field.name, - 'label': label, - 'arrows': extras, - 'needs_node': True - } - if _rel not in model['relations'] and consider(_rel['target']): - model['relations'].append(_rel) - - for field in appmodel._meta.local_fields: - if field.attname.endswith('_ptr_id'): # excluding field redundant with inheritance relation - continue - if field in abstract_fields: # excluding fields inherited from abstract classes. they too show as local_fields - continue - if skip_field(field): - continue - if isinstance(field, OneToOneField): - add_relation(field, '[arrowhead=none, arrowtail=none]') - elif isinstance(field, ForeignKey): - add_relation(field, '[arrowhead=none, arrowtail=dot]') - - for field in appmodel._meta.local_many_to_many: - if skip_field(field): - continue - if isinstance(field, ManyToManyField): - if (getattr(field, 'creates_table', False) or # django 1.1. - (hasattr(field.rel.through, '_meta') and field.rel.through._meta.auto_created)): # django 1.2 - add_relation(field, '[arrowhead=dot arrowtail=dot, dir=both]') - elif isinstance(field, GenericRelation): - add_relation(field, mark_safe('[style="dotted", arrowhead=normal, arrowtail=normal, dir=both]')) - - if inheritance: - # add inheritance arrows - for parent in appmodel.__bases__: - if hasattr(parent, "_meta"): # parent is a model - l = "multi-table" - if parent._meta.abstract: - l = "abstract" - if appmodel._meta.proxy: - l = "proxy" - l += r"\ninheritance" - _rel = { - 'target_app': parent.__module__.replace(".", "_"), - 'target': parent.__name__, - 'type': "inheritance", - 'name': "inheritance", - 'label': l, - 'arrows': '[arrowhead=empty, arrowtail=none]', - 'needs_node': True - } - # TODO: seems as if abstract models aren't part of models.getModels, which is why they are printed by this without any attributes. - if _rel not in model['relations'] and consider(_rel['target']): - model['relations'].append(_rel) - - graph['models'].append(model) - graphs.append(graph) - - nodes = [] - for graph in graphs: - nodes.extend([e['name'] for e in graph['models']]) - - for graph in graphs: - # don't draw duplication nodes because of relations - for model in graph['models']: - for relation in model['relations']: - if relation['target'] in nodes: - relation['needs_node'] = False - # render templates - t = loader.get_template('django_extensions/graph_models/body.html') - dot += '\n' + t.render(graph) - - for graph in graphs: - t = loader.get_template('django_extensions/graph_models/rel.html') - dot += '\n' + t.render(graph) - - - t = loader.get_template('django_extensions/graph_models/tail.html') - c = Context({}) - dot += '\n' + t.render(c) - return dot - -def main(): - try: - opts, args = getopt.getopt(sys.argv[1:], "hadgi:L:x:X:en", - ["help", "all_applications", "disable_fields", "group_models", "include_models=", "inheritance", "verbose_names", "language=", "exclude_columns=", "exclude_models="]) - except getopt.GetoptError, error: - print __doc__ - sys.exit(error) - - kwargs = {} - for opt, arg in opts: - if opt in ("-h", "--help"): - print __doc__ - sys.exit() - if opt in ("-a", "--all_applications"): - kwargs['all_applications'] = True - if opt in ("-d", "--disable_fields"): - kwargs['disable_fields'] = True - if opt in ("-g", "--group_models"): - kwargs['group_models'] = True - if opt in ("-i", "--include_models"): - kwargs['include_models'] = arg - if opt in ("-e", "--inheritance"): - kwargs['inheritance'] = True - if opt in ("-n", "--verbose-names"): - kwargs['verbose_names'] = True - if opt in ("-L", "--language"): - kwargs['language'] = arg - if opt in ("-x", "--exclude_columns"): - kwargs['exclude_columns'] = arg - if opt in ("-X", "--exclude_models"): - kwargs['exclude_models'] = arg - - if not args and not kwargs.get('all_applications', False): - print __doc__ - sys.exit() - - print generate_dot(args, **kwargs) - -if __name__ == "__main__": - main() diff --git a/app/sandbox/robots.txt b/app/sandbox/robots.txt deleted file mode 100644 index 5ac75ebe..00000000 --- a/app/sandbox/robots.txt +++ /dev/null @@ -1,4 +0,0 @@ -User-agent: * -Disallow: *.mp3$ -Disallow: */WIDTHxHEIGHT/ -Disallow: */xml/ diff --git a/app/sandbox/settings.py b/app/sandbox/settings.py deleted file mode 100644 index 5590b2ed..00000000 --- a/app/sandbox/settings.py +++ /dev/null @@ -1,334 +0,0 @@ -# -*- coding: utf-8 -*- -# Django settings for sandbox project. - -import os, sys -from django.core.urlresolvers import reverse_lazy, reverse - -import environ - -# set default values and casting -env = environ.Env(DEBUG=(bool, False), - CELERY_ALWAYS_EAGER=(bool, False), - ) - -# Django settings for server project. -DEBUG = env('DEBUG') # False if not in os.environ -TEMPLATE_DEBUG = DEBUG - -sys.dont_write_bytecode = True - -ALLOWED_HOSTS = ['*'] - -ADMINS = ( - ('Guillaume Pellerin', 'yomguy@parisson.com'), -) - -MANAGERS = ADMINS - -# Full filesystem path to the project. -#PROJECT_ROOT = os.path.dirname(os.path.abspath(__file__)) -PROJECT_ROOT = '/srv/app/' - -DATABASES = { - 'default': { - 'ENGINE': env('ENGINE'), # Add 'postgresql_psycopg2', 'mysql', 'sqlite3' or 'oracle'. - 'USER': env('MYSQL_USER'), # Not used with sqlite3. - 'PASSWORD': env('MYSQL_PASSWORD'), # Not used with sqlite3. - 'NAME': env('MYSQL_DATABASE'), - 'HOST': 'db', # Set to empty string for localhost. Not used with sqlite3. - 'PORT': '3306', # Set to empty string for default. Not used with sqlite3. - } -} - -# Local time zone for this installation. Choices can be found here: -# http://en.wikipedia.org/wiki/List_of_tz_zones_by_name -# although not all choices may be available on all operating systems. -# On Unix systems, a value of None will cause Django to use the same -# timezone as the operating system. -# If running in a Windows environment this must be set to the same as your -# system time zone. -TIME_ZONE = 'Europe/Paris' - -# Language code for this installation. All choices can be found here: -# http://www.i18nguy.com/unicode/language-identifiers.html -#LANGUAGE_CODE = 'fr_FR' - -LANGUAGES = [ ('fr', 'French'), - ('en', 'English'), - ('de', 'German'), - ('zh_CN', 'Simplified Chinese'), - ('ar_TN', 'Arabic'), - ('pt_BR', 'Portuguese'), -] - -SITE_ID = 1 - -# If you set this to False, Django will make some optimizations so as not -# to load the internationalization machinery. -USE_I18N = True - -# If you set this to False, Django will not format dates, numbers and -# calendars according to the current locale -USE_L10N = True - -# Absolute path to the directory that holds media. -# Example: "/home/media/media.lawrence.com/" -# MEDIA_ROOT = PROJECT_ROOT + '/media/' -# -# if not os.path.exists(MEDIA_ROOT): -# os.makedirs(MEDIA_ROOT) -MEDIA_ROOT = '/srv/media/' - -# URL that handles the media served from MEDIA_ROOT. Make sure to use a -# trailing slash if there is a path component (optional in other cases). -# Examples: "http://media.lawrence.com", "http://example.com/media/" -MEDIA_URL = '/media/' - -# Absolute path to the directory static files should be collected to. -# Don't put anything in this directory yourself; store your static files -# in apps' "static/" subdirectories and in STATICFILES_DIRS. -# Example: "/home/media/media.lawrence.com/static/" -# STATIC_ROOT = '/var/www/static' -STATIC_ROOT = '/srv/static/' - -# URL prefix for static files. -# Example: "http://media.lawrence.com/static/" -STATIC_URL = '/static/' - -# Additional locations of static files -STATICFILES_DIRS = ( -# Put strings here, like "/home/html/static" or "C:/www/django/static". -# Always use forward slashes, even on Windows. -# Don't forget to use absolute paths, not relative paths. -) - -# List of finder classes that know how to find static files in -# various locations. -STATICFILES_FINDERS = ( -'django.contrib.staticfiles.finders.FileSystemFinder', -'django.contrib.staticfiles.finders.AppDirectoriesFinder', -'djangobower.finders.BowerFinder', -# 'django.contrib.staticfiles.finders.DefaultStorageFinder', -) -# Make this unique, and don't share it with anybody. -SECRET_KEY = 'a8l7%06wr2k+3=%#*#@#rvop2mmzko)44%7k(zx%lls^ihm9^5' - -# List of callables that know how to import templates from various sources. -TEMPLATE_LOADERS = ( - 'django.template.loaders.filesystem.Loader', - 'django.template.loaders.app_directories.Loader', -# 'django.template.loaders.eggs.Loader', -) - - -MIDDLEWARE_CLASSES = ( - # Manage Django URLs for AngularJS with django-angular - 'djng.middleware.AngularUrlMiddleware', - 'django.middleware.common.CommonMiddleware', - 'django.contrib.sessions.middleware.SessionMiddleware', - 'django.middleware.csrf.CsrfViewMiddleware', - 'django.contrib.auth.middleware.AuthenticationMiddleware', - 'django.contrib.messages.middleware.MessageMiddleware', - 'django.middleware.locale.LocaleMiddleware', - # 'pagination.middleware.PaginationMiddleware', -) - -ROOT_URLCONF = 'sandbox.urls' - -TEMPLATE_DIRS = ( - # Put strings here, like "/home/html/django_templates" or "C:/www/django/templates". - # Always use forward slashes, even on Windows. - # Don't forget to use absolute paths, not relative paths. -) - -INSTALLED_APPS = ( - 'django.contrib.auth', - 'django.contrib.contenttypes', - 'django.contrib.sessions', - 'django.contrib.sites', - 'django.contrib.messages', - 'suit', - 'django.contrib.admin', - 'django.contrib.staticfiles', - 'django_extensions', - 'telemeta', - 'timeside.player', - 'timeside.server', - 'jsonrpc', - 'south', - 'sorl.thumbnail', - 'timezones', - 'jqchat', - 'ipauth', - 'extra_views', - 'debug_toolbar', - 'bootstrap3', - 'bootstrap_pagination', - 'googletools', - 'registration', - 'rest_framework', - 'djcelery', - 'haystack', - 'djangobower', - 'djng', - 'saved_searches', -) - -TEMPLATE_CONTEXT_PROCESSORS = ( - 'django.core.context_processors.request', - 'django.contrib.auth.context_processors.auth', - "django.core.context_processors.i18n", - "django.core.context_processors.media", - 'django.core.context_processors.static', - 'django.contrib.messages.context_processors.messages', -) - -AUTHENTICATION_BACKENDS = ( - 'django.contrib.auth.backends.ModelBackend', - 'ipauth.backend.RangeBackend', -) - -SESSION_ENGINE = "django.contrib.sessions.backends.signed_cookies" - -TELEMETA_ORGANIZATION = 'Telemeta' -TELEMETA_SUBJECTS = ('Telemeta', 'web', 'platform', 'audio', 'semantics') -TELEMETA_DESCRIPTION = "Open web audio platform with semantics" -TELEMETA_LOGO = STATIC_URL + 'telemeta/images/logo_telemeta_2.png' - -TELEMETA_GMAP_KEY = 'ABQIAAAArg7eSfnfTkBRma8glnGrlxRVbMrhnNNvToCbZQtWdaMbZTA_3RRGObu5PDoiBImgalVnnLU2yN4RMA' - -TELEMETA_CACHE_DIR = os.path.join(MEDIA_ROOT, 'cache') -TELEMETA_EXPORT_CACHE_DIR = os.path.join(MEDIA_ROOT, 'export') -TELEMETA_DATA_CACHE_DIR = os.path.join(TELEMETA_CACHE_DIR, 'data') -FILE_UPLOAD_TEMP_DIR = os.path.join(MEDIA_ROOT, 'tmp') -FILE_UPLOAD_PERMISSIONS = 0644 - -TELEMETA_DOWNLOAD_ENABLED = True -TELEMETA_STREAMING_FORMATS = ('mp3', 'ogg') -TELEMETA_DOWNLOAD_FORMATS = ('wav', 'mp3', 'ogg', 'flac') -TELEMETA_PUBLIC_ACCESS_PERIOD = 51 - -TELEMETA_STRICT_CODE = False -COLLECTION_PUBLISHED_CODE_REGEX = '*' -COLLECTION_UNPUBLISHED_CODE_REGEX = '*' -ITEM_PUBLISHED_CODE_REGEX = COLLECTION_PUBLISHED_CODE_REGEX + '' -ITEM_UNPUBLISHED_CODE_REGEX = COLLECTION_UNPUBLISHED_CODE_REGEX + '' - -AUTH_PROFILE_MODULE = 'telemeta.userprofile' -SESSION_EXPIRE_AT_BROWSER_CLOSE = False - -LOGIN_URL = '/login/' -LOGIN_REDIRECT_URL = '/desk/lists/' - -EMAIL_HOST = 'localhost' -DEFAULT_FROM_EMAIL = 'webmaster@parisson.com' - -TIMESIDE_DEFAULT_GRAPHER_ID = 'waveform_centroid' -TIMESIDE_DEFAULT_WAVEFORM_SIZES = ['346x130', '640x130'] -TIMESIDE_AUTO_ZOOM = False - -# Settings for django-bootstrap3 -BOOTSTRAP3 = { - 'set_required': True, - 'set_placeholder': False, - 'error_css_class': 'has-error', - 'required_css_class': 'has-warning', - 'javascript_in_head': True, -} - -PAGINATION_SETTINGS = { - 'PAGE_RANGE_DISPLAYED': 10, - 'MARGIN_PAGES_DISPLAYED': 2, -} - -DEBUG_TOOLBAR_PATCH_SETTINGS = False -DEBUG_TOOLBAR_PANELS = [ - 'debug_toolbar.panels.versions.VersionsPanel', - 'debug_toolbar.panels.timer.TimerPanel', - 'debug_toolbar.panels.settings.SettingsPanel', - 'debug_toolbar.panels.headers.HeadersPanel', - 'debug_toolbar.panels.request.RequestPanel', - 'debug_toolbar.panels.sql.SQLPanel', - 'debug_toolbar.panels.staticfiles.StaticFilesPanel', - 'debug_toolbar.panels.templates.TemplatesPanel', - 'debug_toolbar.panels.cache.CachePanel', - 'debug_toolbar.panels.signals.SignalsPanel', - 'debug_toolbar.panels.logging.LoggingPanel', - 'debug_toolbar.panels.redirects.RedirectsPanel', -] - -SUIT_CONFIG = { - 'ADMIN_NAME': 'Telemeta Admin' -} - -# A sample logging configuration. The only tangible logging -# performed by this configuration is to send an email to -# the site admins on every HTTP 500 error when DEBUG=False. -# See http://docs.djangoproject.com/en/dev/topics/logging for -# more details on how to customize your logging configuration. -LOGGING = { - 'version': 1, - 'disable_existing_loggers': False, - 'filters': { - 'require_debug_false': { - '()': 'django.utils.log.RequireDebugFalse' - } - }, - 'handlers': { - 'mail_admins': { - 'level': 'ERROR', - 'filters': ['require_debug_false'], - 'class': 'django.utils.log.AdminEmailHandler' - } - }, - 'loggers': { - 'django.request': { - 'handlers': ['mail_admins'], - 'level': 'ERROR', - 'propagate': True, - }, - } -} - -BROKER_URL = env('BROKER_URL') - -CELERY_IMPORTS = ("timeside.server.tasks",) -CELERY_RESULT_BACKEND = 'djcelery.backends.database:DatabaseBackend' -CELERY_TASK_SERIALIZER = 'json' -CELERY_RESULT_SERIALIZER = 'json' -CELERY_ACCEPT_CONTENT = ['application/json'] - -from worker import app - -HAYSTACK_CONNECTIONS = { - 'default': { - 'ENGINE': 'haystack.backends.elasticsearch_backend.ElasticsearchSearchEngine', - 'URL': 'http://search:9200/', - 'INDEX_NAME': 'haystack', - 'INLUDE_SPELLING': True, - }, -} -HAYSTACK_SIGNAL_PROCESSOR = 'haystack.signals.RealtimeSignalProcessor' -HAYSTACK_SEARCH_RESULTS_PER_PAGE = 50 - -BOWER_COMPONENTS_ROOT = '/srv/bower/' -BOWER_PATH = '/usr/local/bin/bower' -BOWER_INSTALLED_APPS = ( - 'jquery', - 'jquery-migrate#~1.2.1', - 'underscore', - 'bootstrap', - 'bootstrap-select#1.5.4', - 'font-awesome#4.4.0', - 'angular#1.2.26', - 'angular-bootstrap-select', - 'angular-resource#1.2.26', - 'raphael', - 'soundmanager#V2.97a.20150601', - 'https://github.com/Parisson/loaders.git', - 'https://github.com/Parisson/ui.git', - 'jquery-ui', - 'tablesorter', - 'video.js', - 'sass-bootstrap-glyphicons', -) diff --git a/app/sandbox/update_schema.sh b/app/sandbox/update_schema.sh deleted file mode 100755 index 31c658a1..00000000 --- a/app/sandbox/update_schema.sh +++ /dev/null @@ -1,5 +0,0 @@ -#!/bin/sh - -./manage.py schemamigration telemeta --auto -./manage.py migrate telemeta - diff --git a/app/sandbox/urls.py b/app/sandbox/urls.py deleted file mode 100644 index b1950363..00000000 --- a/app/sandbox/urls.py +++ /dev/null @@ -1,37 +0,0 @@ -# -*- coding: utf-8 -*- -from django.conf.urls import patterns, url, include -from django.http import HttpResponse -import os - -# Uncomment the next two lines to enable the admin: -from django.contrib import admin -admin.autodiscover() - -js_info_dict = { - 'packages': ('telemeta',), -} - -PROJECT_ROOT = os.path.dirname(os.path.abspath(__file__)) -robots_rules = open(PROJECT_ROOT + os.sep + 'robots.txt', 'r').read() - -urlpatterns = patterns('', - # Example: - # (r'^sandbox/', include('sandbox.foo.urls')), - - # Uncomment the admin/doc line below and add 'django.contrib.admindocs' - # to INSTALLED_APPS to enable admin documentation: - # (r'^admin/doc/', include('django.contrib.admindocs.urls')), - - # Uncomment the next line to enable the admin: - (r'^admin/django/', include(admin.site.urls)), - #(r'^grappelli/', include('grappelli.urls')), # grappelli URLS - - # Telemeta - (r'^', include('telemeta.urls')), - - # Languages - (r'^i18n/', include('django.conf.urls.i18n')), - (r'^jsi18n/$', 'django.views.i18n.javascript_catalog', js_info_dict), - (r'^robots\.txt$', lambda r: HttpResponse(robots_rules, mimetype="text/plain")), - - ) diff --git a/app/scripts/app.sh b/app/scripts/app.sh new file mode 100644 index 00000000..dc8eb5cd --- /dev/null +++ b/app/scripts/app.sh @@ -0,0 +1,57 @@ +#!/bin/sh + +# paths +app='/srv/app' +manage=$app'/manage.py' +wsgi=$app'/wsgi.py' +static='/srv/static/' +media='/srv/media/' +src='/srv/src/' + +# uwsgi params +port=8000 +processes=8 +threads=8 +autoreload=3 +uid='www-data' +gid='www-data' + +# stating apps +# pip install django-angular + +# waiting for other network services +sh $app/scripts/wait.sh + +# django setup +python $manage wait-for-db +python $manage syncdb --noinput +python $manage migrate --noinput +python $manage bower_install -- --allow-root +python $manage collectstatic --noinput +python $manage telemeta-create-admin-user +python $manage telemeta-create-boilerplate + +if [ $DEBUG == "False" ] +then + python $manage update_index --workers $processes & + if [ ! -f .init ] + then + chown -R www-data:www-data $media + touch .init + fi +fi + +if [ $1 == "--runserver" ] +then + python $manage runserver_plus 0.0.0.0:8000 +else + # static files auto update + watchmedo shell-command --patterns="*.js;*.css" --recursive \ + --command='python '$manage' collectstatic --noinput' $src & + + # app start + uwsgi --socket :$port --wsgi-file $wsgi --chdir $app --master \ + --processes $processes --threads $threads \ + --uid $uid --gid $gid \ + --py-autoreload $autoreload +fi diff --git a/app/scripts/diag.sh b/app/scripts/diag.sh new file mode 100755 index 00000000..5f6c1e59 --- /dev/null +++ b/app/scripts/diag.sh @@ -0,0 +1,12 @@ +#!/bin/sh + +app="telemeta" +dir="../../doc/devel" + +python modelviz.py -a > $dir/$app-all.dot +python modelviz.py $app > $dir/$app.dot + +dot $dir/$app-all.dot -Tpdf -o $dir/$app-all.pdf +dot $dir/$app.dot -Tpdf -o $dir/$app.pdf + +rsync -a $dir/ doc.parisson.com:/var/www/files/doc/$app/diagram/ diff --git a/app/scripts/modelviz.py b/app/scripts/modelviz.py new file mode 100644 index 00000000..24af0627 --- /dev/null +++ b/app/scripts/modelviz.py @@ -0,0 +1,359 @@ +#!/usr/bin/env python + +"""Django model to DOT (Graphviz) converter +by Antonio Cavedoni + +Make sure your DJANGO_SETTINGS_MODULE is set to your project or +place this script in the same directory of the project and call +the script like this: + +$ python modelviz.py [-h] [-a] [-d] [-g] [-n] [-L ] [-i ] ... > .dot +$ dot .dot -Tpng -o .png + +options: + -h, --help + show this help message and exit. + + -a, --all_applications + show models from all applications. + + -d, --disable_fields + don't show the class member fields. + + -g, --group_models + draw an enclosing box around models from the same app. + + -i, --include_models=User,Person,Car + only include selected models in graph. + + -n, --verbose_names + use verbose_name for field and models. + + -L, --language + specify language used for verrbose_name localization + + -x, --exclude_columns + exclude specific column(s) from the graph. + + -X, --exclude_models + exclude specific model(s) from the graph. + + -e, --inheritance + show inheritance arrows. +""" +__version__ = "0.9" +__svnid__ = "$Id$" +__license__ = "Python" +__author__ = "Antonio Cavedoni " +__contributors__ = [ + "Stefano J. Attardi ", + "limodou ", + "Carlo C8E Miron", + "Andre Campos ", + "Justin Findlay ", + "Alexander Houben ", + "Bas van Oostveen ", + "Joern Hees " +] + +import os +import sys +import getopt + +from django.core.management import setup_environ + +try: + import settings +except ImportError: + pass +else: + setup_environ(settings) + +from django.utils.translation import activate as activate_language +from django.utils.safestring import mark_safe +from django.template import Template, Context, loader +from django.db import models +from django.db.models import get_models +from django.db.models.fields.related import \ + ForeignKey, OneToOneField, ManyToManyField, RelatedField + +try: + from django.db.models.fields.generic import GenericRelation +except ImportError: + from django.contrib.contenttypes.generic import GenericRelation + +def parse_file_or_list(arg): + if not arg: + return [] + if not ',' in arg and os.path.isfile(arg): + return [e.strip() for e in open(arg).readlines()] + return arg.split(',') + + +def generate_dot(app_labels, **kwargs): + disable_fields = kwargs.get('disable_fields', False) + include_models = parse_file_or_list(kwargs.get('include_models', "")) + all_applications = kwargs.get('all_applications', False) + use_subgraph = kwargs.get('group_models', False) + verbose_names = kwargs.get('verbose_names', False) + inheritance = kwargs.get('inheritance', False) + language = kwargs.get('language', None) + if language is not None: + activate_language(language) + exclude_columns = parse_file_or_list(kwargs.get('exclude_columns', "")) + exclude_models = parse_file_or_list(kwargs.get('exclude_models', "")) + + def skip_field(field): + if exclude_columns: + if verbose_names and field.verbose_name: + if field.verbose_name in exclude_columns: + return True + if field.name in exclude_columns: + return True + return False + + + + + t = loader.get_template('django_extensions/graph_models/head.html') + c = Context({}) + dot = t.render(c) + + apps = [] + if all_applications: + apps = models.get_apps() + + for app_label in app_labels: + app = models.get_app(app_label) + if not app in apps: + apps.append(app) + + graphs = [] + for app in apps: + graph = Context({ + 'name': '"%s"' % app.__name__, + 'app_name': "%s" % '.'.join(app.__name__.split('.')[:-1]), + 'cluster_app_name': "cluster_%s" % app.__name__.replace(".", "_"), + 'disable_fields': disable_fields, + 'use_subgraph': use_subgraph, + 'models': [] + }) + + appmodels = get_models(app) + abstract_models = [] + for appmodel in appmodels: + abstract_models = abstract_models + [abstract_model for abstract_model in appmodel.__bases__ if hasattr(abstract_model, '_meta') and abstract_model._meta.abstract] + abstract_models = list(set(abstract_models)) # remove duplicates + appmodels = abstract_models + appmodels + + + for appmodel in appmodels: + appmodel_abstracts = [abstract_model.__name__ for abstract_model in appmodel.__bases__ if hasattr(abstract_model, '_meta') and abstract_model._meta.abstract] + + # collect all attribs of abstract superclasses + def getBasesAbstractFields(c): + _abstract_fields = [] + for e in c.__bases__: + if hasattr(e, '_meta') and e._meta.abstract: + _abstract_fields.extend(e._meta.fields) + _abstract_fields.extend(getBasesAbstractFields(e)) + return _abstract_fields + abstract_fields = getBasesAbstractFields(appmodel) + + model = { + 'app_name': appmodel.__module__.replace(".", "_"), + 'name': appmodel.__name__, + 'abstracts': appmodel_abstracts, + 'fields': [], + 'relations': [] + } + + # consider given model name ? + def consider(model_name): + if exclude_models and model_name in exclude_models: + return False + return not include_models or model_name in include_models + + if not consider(appmodel._meta.object_name): + continue + + if verbose_names and appmodel._meta.verbose_name: + model['label'] = appmodel._meta.verbose_name + else: + model['label'] = model['name'] + + # model attributes + def add_attributes(field): + if verbose_names and field.verbose_name: + label = field.verbose_name + else: + label = field.name + + t = type(field).__name__ + if isinstance(field, (OneToOneField, ForeignKey)): + t += " ({0})".format(field.rel.field_name) + # TODO: ManyToManyField, GenericRelation + + model['fields'].append({ + 'name': field.name, + 'label': label, + 'type': t, + 'blank': field.blank, + 'abstract': field in abstract_fields, + }) + + # Find all the real attributes. Relations are depicted as graph edges instead of attributes + attributes = [field for field in appmodel._meta.local_fields if not isinstance(field, RelatedField)] + + # find primary key and print it first, ignoring implicit id if other pk exists + pk = appmodel._meta.pk + if not appmodel._meta.abstract and pk in attributes: + add_attributes(pk) + for field in attributes: + if skip_field(field): + continue + if not field.primary_key: + add_attributes(field) + + # FIXME: actually many_to_many fields aren't saved in this model's db table, so why should we add an attribute-line for them in the resulting graph? + #if appmodel._meta.many_to_many: + # for field in appmodel._meta.many_to_many: + # if skip_field(field): + # continue + # add_attributes(field) + + # relations + def add_relation(field, extras=""): + if verbose_names and field.verbose_name: + label = field.verbose_name + else: + label = field.name + + # show related field name + if hasattr(field, 'related_query_name'): + label += ' (%s)' % field.related_query_name() + + _rel = { + 'target_app': field.rel.to.__module__.replace('.', '_'), + 'target': field.rel.to.__name__, + 'type': type(field).__name__, + 'name': field.name, + 'label': label, + 'arrows': extras, + 'needs_node': True + } + if _rel not in model['relations'] and consider(_rel['target']): + model['relations'].append(_rel) + + for field in appmodel._meta.local_fields: + if field.attname.endswith('_ptr_id'): # excluding field redundant with inheritance relation + continue + if field in abstract_fields: # excluding fields inherited from abstract classes. they too show as local_fields + continue + if skip_field(field): + continue + if isinstance(field, OneToOneField): + add_relation(field, '[arrowhead=none, arrowtail=none]') + elif isinstance(field, ForeignKey): + add_relation(field, '[arrowhead=none, arrowtail=dot]') + + for field in appmodel._meta.local_many_to_many: + if skip_field(field): + continue + if isinstance(field, ManyToManyField): + if (getattr(field, 'creates_table', False) or # django 1.1. + (hasattr(field.rel.through, '_meta') and field.rel.through._meta.auto_created)): # django 1.2 + add_relation(field, '[arrowhead=dot arrowtail=dot, dir=both]') + elif isinstance(field, GenericRelation): + add_relation(field, mark_safe('[style="dotted", arrowhead=normal, arrowtail=normal, dir=both]')) + + if inheritance: + # add inheritance arrows + for parent in appmodel.__bases__: + if hasattr(parent, "_meta"): # parent is a model + l = "multi-table" + if parent._meta.abstract: + l = "abstract" + if appmodel._meta.proxy: + l = "proxy" + l += r"\ninheritance" + _rel = { + 'target_app': parent.__module__.replace(".", "_"), + 'target': parent.__name__, + 'type': "inheritance", + 'name': "inheritance", + 'label': l, + 'arrows': '[arrowhead=empty, arrowtail=none]', + 'needs_node': True + } + # TODO: seems as if abstract models aren't part of models.getModels, which is why they are printed by this without any attributes. + if _rel not in model['relations'] and consider(_rel['target']): + model['relations'].append(_rel) + + graph['models'].append(model) + graphs.append(graph) + + nodes = [] + for graph in graphs: + nodes.extend([e['name'] for e in graph['models']]) + + for graph in graphs: + # don't draw duplication nodes because of relations + for model in graph['models']: + for relation in model['relations']: + if relation['target'] in nodes: + relation['needs_node'] = False + # render templates + t = loader.get_template('django_extensions/graph_models/body.html') + dot += '\n' + t.render(graph) + + for graph in graphs: + t = loader.get_template('django_extensions/graph_models/rel.html') + dot += '\n' + t.render(graph) + + + t = loader.get_template('django_extensions/graph_models/tail.html') + c = Context({}) + dot += '\n' + t.render(c) + return dot + +def main(): + try: + opts, args = getopt.getopt(sys.argv[1:], "hadgi:L:x:X:en", + ["help", "all_applications", "disable_fields", "group_models", "include_models=", "inheritance", "verbose_names", "language=", "exclude_columns=", "exclude_models="]) + except getopt.GetoptError, error: + print __doc__ + sys.exit(error) + + kwargs = {} + for opt, arg in opts: + if opt in ("-h", "--help"): + print __doc__ + sys.exit() + if opt in ("-a", "--all_applications"): + kwargs['all_applications'] = True + if opt in ("-d", "--disable_fields"): + kwargs['disable_fields'] = True + if opt in ("-g", "--group_models"): + kwargs['group_models'] = True + if opt in ("-i", "--include_models"): + kwargs['include_models'] = arg + if opt in ("-e", "--inheritance"): + kwargs['inheritance'] = True + if opt in ("-n", "--verbose-names"): + kwargs['verbose_names'] = True + if opt in ("-L", "--language"): + kwargs['language'] = arg + if opt in ("-x", "--exclude_columns"): + kwargs['exclude_columns'] = arg + if opt in ("-X", "--exclude_models"): + kwargs['exclude_models'] = arg + + if not args and not kwargs.get('all_applications', False): + print __doc__ + sys.exit() + + print generate_dot(args, **kwargs) + +if __name__ == "__main__": + main() diff --git a/app/scripts/update_schema.sh b/app/scripts/update_schema.sh new file mode 100755 index 00000000..31c658a1 --- /dev/null +++ b/app/scripts/update_schema.sh @@ -0,0 +1,5 @@ +#!/bin/sh + +./manage.py schemamigration telemeta --auto +./manage.py migrate telemeta + diff --git a/app/scripts/wait.sh b/app/scripts/wait.sh new file mode 100644 index 00000000..02289edf --- /dev/null +++ b/app/scripts/wait.sh @@ -0,0 +1,18 @@ +#!/bin/sh + +# apt-get install -y --force-yes netcat + +set -e + +host=$(env | grep _TCP_ADDR | cut -d = -f 2) +port=$(env | grep _TCP_PORT | cut -d = -f 2) + +echo -n "waiting for TCP connection to $host:$port..." + +while ! nc -w 1 $host $port 2>/dev/null +do + echo -n . + sleep 1 +done + +echo 'ok' diff --git a/app/scripts/worker.sh b/app/scripts/worker.sh new file mode 100644 index 00000000..76bb4652 --- /dev/null +++ b/app/scripts/worker.sh @@ -0,0 +1,17 @@ +#!/bin/sh + +# paths +app='/srv/app' +manage=$app'/manage.py' +wsgi=$app'/wsgi.py' + +# stating apps +# pip install django-environ redis + +# waiting for other services +sh $app/scripts/wait.sh + +# Starting celery worker with the --autoreload option will enable the worker to watch for file system changes +# This is an experimental feature intended for use in development only +# see http://celery.readthedocs.org/en/latest/userguide/workers.html#autoreloading +python $manage celery worker --autoreload -A worker diff --git a/app/settings.py b/app/settings.py new file mode 100644 index 00000000..bc2f5600 --- /dev/null +++ b/app/settings.py @@ -0,0 +1,334 @@ +# -*- coding: utf-8 -*- +# Django settings for sandbox project. + +import os, sys +from django.core.urlresolvers import reverse_lazy, reverse + +import environ + +# set default values and casting +env = environ.Env(DEBUG=(bool, False), + CELERY_ALWAYS_EAGER=(bool, False), + ) + +# Django settings for server project. +DEBUG = env('DEBUG') # False if not in os.environ +TEMPLATE_DEBUG = DEBUG + +sys.dont_write_bytecode = True + +ALLOWED_HOSTS = ['*'] + +ADMINS = ( + ('Guillaume Pellerin', 'yomguy@parisson.com'), +) + +MANAGERS = ADMINS + +# Full filesystem path to the project. +#PROJECT_ROOT = os.path.dirname(os.path.abspath(__file__)) +PROJECT_ROOT = '/srv/app/' + +DATABASES = { + 'default': { + 'ENGINE': env('ENGINE'), # Add 'postgresql_psycopg2', 'mysql', 'sqlite3' or 'oracle'. + 'USER': env('MYSQL_USER'), # Not used with sqlite3. + 'PASSWORD': env('MYSQL_PASSWORD'), # Not used with sqlite3. + 'NAME': env('MYSQL_DATABASE'), + 'HOST': 'db', # Set to empty string for localhost. Not used with sqlite3. + 'PORT': '3306', # Set to empty string for default. Not used with sqlite3. + } +} + +# Local time zone for this installation. Choices can be found here: +# http://en.wikipedia.org/wiki/List_of_tz_zones_by_name +# although not all choices may be available on all operating systems. +# On Unix systems, a value of None will cause Django to use the same +# timezone as the operating system. +# If running in a Windows environment this must be set to the same as your +# system time zone. +TIME_ZONE = 'Europe/Paris' + +# Language code for this installation. All choices can be found here: +# http://www.i18nguy.com/unicode/language-identifiers.html +#LANGUAGE_CODE = 'fr_FR' + +LANGUAGES = [ ('fr', 'French'), + ('en', 'English'), + ('de', 'German'), + ('zh_CN', 'Simplified Chinese'), + ('ar_TN', 'Arabic'), + ('pt_BR', 'Portuguese'), +] + +SITE_ID = 1 + +# If you set this to False, Django will make some optimizations so as not +# to load the internationalization machinery. +USE_I18N = True + +# If you set this to False, Django will not format dates, numbers and +# calendars according to the current locale +USE_L10N = True + +# Absolute path to the directory that holds media. +# Example: "/home/media/media.lawrence.com/" +# MEDIA_ROOT = PROJECT_ROOT + '/media/' +# +# if not os.path.exists(MEDIA_ROOT): +# os.makedirs(MEDIA_ROOT) +MEDIA_ROOT = '/srv/media/' + +# URL that handles the media served from MEDIA_ROOT. Make sure to use a +# trailing slash if there is a path component (optional in other cases). +# Examples: "http://media.lawrence.com", "http://example.com/media/" +MEDIA_URL = '/media/' + +# Absolute path to the directory static files should be collected to. +# Don't put anything in this directory yourself; store your static files +# in apps' "static/" subdirectories and in STATICFILES_DIRS. +# Example: "/home/media/media.lawrence.com/static/" +# STATIC_ROOT = '/var/www/static' +STATIC_ROOT = '/srv/static/' + +# URL prefix for static files. +# Example: "http://media.lawrence.com/static/" +STATIC_URL = '/static/' + +# Additional locations of static files +STATICFILES_DIRS = ( +# Put strings here, like "/home/html/static" or "C:/www/django/static". +# Always use forward slashes, even on Windows. +# Don't forget to use absolute paths, not relative paths. +) + +# List of finder classes that know how to find static files in +# various locations. +STATICFILES_FINDERS = ( +'django.contrib.staticfiles.finders.FileSystemFinder', +'django.contrib.staticfiles.finders.AppDirectoriesFinder', +'djangobower.finders.BowerFinder', +# 'django.contrib.staticfiles.finders.DefaultStorageFinder', +) +# Make this unique, and don't share it with anybody. +SECRET_KEY = 'a8l7%06wr2k+3=%#*#@#rvop2mmzko)44%7k(zx%lls^ihm9^5' + +# List of callables that know how to import templates from various sources. +TEMPLATE_LOADERS = ( + 'django.template.loaders.filesystem.Loader', + 'django.template.loaders.app_directories.Loader', +# 'django.template.loaders.eggs.Loader', +) + + +MIDDLEWARE_CLASSES = ( + # Manage Django URLs for AngularJS with django-angular + 'djng.middleware.AngularUrlMiddleware', + 'django.middleware.common.CommonMiddleware', + 'django.contrib.sessions.middleware.SessionMiddleware', + 'django.middleware.csrf.CsrfViewMiddleware', + 'django.contrib.auth.middleware.AuthenticationMiddleware', + 'django.contrib.messages.middleware.MessageMiddleware', + 'django.middleware.locale.LocaleMiddleware', + # 'pagination.middleware.PaginationMiddleware', +) + +ROOT_URLCONF = 'urls' + +TEMPLATE_DIRS = ( + # Put strings here, like "/home/html/django_templates" or "C:/www/django/templates". + # Always use forward slashes, even on Windows. + # Don't forget to use absolute paths, not relative paths. +) + +INSTALLED_APPS = ( + 'django.contrib.auth', + 'django.contrib.contenttypes', + 'django.contrib.sessions', + 'django.contrib.sites', + 'django.contrib.messages', + 'suit', + 'django.contrib.admin', + 'django.contrib.staticfiles', + 'django_extensions', + 'telemeta', + 'timeside.player', + 'timeside.server', + 'jsonrpc', + 'south', + 'sorl.thumbnail', + 'timezones', + 'jqchat', + 'ipauth', + 'extra_views', + 'debug_toolbar', + 'bootstrap3', + 'bootstrap_pagination', + 'googletools', + 'registration', + 'rest_framework', + 'djcelery', + 'haystack', + 'djangobower', + 'djng', + 'saved_searches', +) + +TEMPLATE_CONTEXT_PROCESSORS = ( + 'django.core.context_processors.request', + 'django.contrib.auth.context_processors.auth', + "django.core.context_processors.i18n", + "django.core.context_processors.media", + 'django.core.context_processors.static', + 'django.contrib.messages.context_processors.messages', +) + +AUTHENTICATION_BACKENDS = ( + 'django.contrib.auth.backends.ModelBackend', + 'ipauth.backend.RangeBackend', +) + +SESSION_ENGINE = "django.contrib.sessions.backends.signed_cookies" + +TELEMETA_ORGANIZATION = 'Telemeta' +TELEMETA_SUBJECTS = ('Telemeta', 'web', 'platform', 'audio', 'semantics') +TELEMETA_DESCRIPTION = "Open web audio platform with semantics" +TELEMETA_LOGO = STATIC_URL + 'telemeta/images/logo_telemeta_2.png' + +TELEMETA_GMAP_KEY = 'ABQIAAAArg7eSfnfTkBRma8glnGrlxRVbMrhnNNvToCbZQtWdaMbZTA_3RRGObu5PDoiBImgalVnnLU2yN4RMA' + +TELEMETA_CACHE_DIR = os.path.join(MEDIA_ROOT, 'cache') +TELEMETA_EXPORT_CACHE_DIR = os.path.join(MEDIA_ROOT, 'export') +TELEMETA_DATA_CACHE_DIR = os.path.join(TELEMETA_CACHE_DIR, 'data') +FILE_UPLOAD_TEMP_DIR = os.path.join(MEDIA_ROOT, 'tmp') +FILE_UPLOAD_PERMISSIONS = 0644 + +TELEMETA_DOWNLOAD_ENABLED = True +TELEMETA_STREAMING_FORMATS = ('mp3', 'ogg') +TELEMETA_DOWNLOAD_FORMATS = ('wav', 'mp3', 'ogg', 'flac') +TELEMETA_PUBLIC_ACCESS_PERIOD = 51 + +TELEMETA_STRICT_CODE = False +COLLECTION_PUBLISHED_CODE_REGEX = '*' +COLLECTION_UNPUBLISHED_CODE_REGEX = '*' +ITEM_PUBLISHED_CODE_REGEX = COLLECTION_PUBLISHED_CODE_REGEX + '' +ITEM_UNPUBLISHED_CODE_REGEX = COLLECTION_UNPUBLISHED_CODE_REGEX + '' + +AUTH_PROFILE_MODULE = 'telemeta.userprofile' +SESSION_EXPIRE_AT_BROWSER_CLOSE = False + +LOGIN_URL = '/login/' +LOGIN_REDIRECT_URL = '/desk/lists/' + +EMAIL_HOST = 'localhost' +DEFAULT_FROM_EMAIL = 'webmaster@parisson.com' + +TIMESIDE_DEFAULT_GRAPHER_ID = 'waveform_centroid' +TIMESIDE_DEFAULT_WAVEFORM_SIZES = ['346x130', '640x130'] +TIMESIDE_AUTO_ZOOM = False + +# Settings for django-bootstrap3 +BOOTSTRAP3 = { + 'set_required': True, + 'set_placeholder': False, + 'error_css_class': 'has-error', + 'required_css_class': 'has-warning', + 'javascript_in_head': True, +} + +PAGINATION_SETTINGS = { + 'PAGE_RANGE_DISPLAYED': 10, + 'MARGIN_PAGES_DISPLAYED': 2, +} + +DEBUG_TOOLBAR_PATCH_SETTINGS = False +DEBUG_TOOLBAR_PANELS = [ + 'debug_toolbar.panels.versions.VersionsPanel', + 'debug_toolbar.panels.timer.TimerPanel', + 'debug_toolbar.panels.settings.SettingsPanel', + 'debug_toolbar.panels.headers.HeadersPanel', + 'debug_toolbar.panels.request.RequestPanel', + 'debug_toolbar.panels.sql.SQLPanel', + 'debug_toolbar.panels.staticfiles.StaticFilesPanel', + 'debug_toolbar.panels.templates.TemplatesPanel', + 'debug_toolbar.panels.cache.CachePanel', + 'debug_toolbar.panels.signals.SignalsPanel', + 'debug_toolbar.panels.logging.LoggingPanel', + 'debug_toolbar.panels.redirects.RedirectsPanel', +] + +SUIT_CONFIG = { + 'ADMIN_NAME': 'Telemeta Admin' +} + +# A sample logging configuration. The only tangible logging +# performed by this configuration is to send an email to +# the site admins on every HTTP 500 error when DEBUG=False. +# See http://docs.djangoproject.com/en/dev/topics/logging for +# more details on how to customize your logging configuration. +LOGGING = { + 'version': 1, + 'disable_existing_loggers': False, + 'filters': { + 'require_debug_false': { + '()': 'django.utils.log.RequireDebugFalse' + } + }, + 'handlers': { + 'mail_admins': { + 'level': 'ERROR', + 'filters': ['require_debug_false'], + 'class': 'django.utils.log.AdminEmailHandler' + } + }, + 'loggers': { + 'django.request': { + 'handlers': ['mail_admins'], + 'level': 'ERROR', + 'propagate': True, + }, + } +} + +BROKER_URL = env('BROKER_URL') + +CELERY_IMPORTS = ("timeside.server.tasks",) +CELERY_RESULT_BACKEND = 'djcelery.backends.database:DatabaseBackend' +CELERY_TASK_SERIALIZER = 'json' +CELERY_RESULT_SERIALIZER = 'json' +CELERY_ACCEPT_CONTENT = ['application/json'] + +from worker import app + +HAYSTACK_CONNECTIONS = { + 'default': { + 'ENGINE': 'haystack.backends.elasticsearch_backend.ElasticsearchSearchEngine', + 'URL': 'http://search:9200/', + 'INDEX_NAME': 'haystack', + 'INLUDE_SPELLING': True, + }, +} +HAYSTACK_SIGNAL_PROCESSOR = 'haystack.signals.RealtimeSignalProcessor' +HAYSTACK_SEARCH_RESULTS_PER_PAGE = 50 + +BOWER_COMPONENTS_ROOT = '/srv/bower/' +BOWER_PATH = '/usr/local/bin/bower' +BOWER_INSTALLED_APPS = ( + 'jquery', + 'jquery-migrate#~1.2.1', + 'underscore', + 'bootstrap', + 'bootstrap-select#1.5.4', + 'font-awesome#4.4.0', + 'angular#1.2.26', + 'angular-bootstrap-select', + 'angular-resource#1.2.26', + 'raphael', + 'soundmanager#V2.97a.20150601', + 'https://github.com/Parisson/loaders.git', + 'https://github.com/Parisson/ui.git', + 'jquery-ui', + 'tablesorter', + 'video.js', + 'sass-bootstrap-glyphicons', +) diff --git a/app/urls.py b/app/urls.py new file mode 100644 index 00000000..b1950363 --- /dev/null +++ b/app/urls.py @@ -0,0 +1,37 @@ +# -*- coding: utf-8 -*- +from django.conf.urls import patterns, url, include +from django.http import HttpResponse +import os + +# Uncomment the next two lines to enable the admin: +from django.contrib import admin +admin.autodiscover() + +js_info_dict = { + 'packages': ('telemeta',), +} + +PROJECT_ROOT = os.path.dirname(os.path.abspath(__file__)) +robots_rules = open(PROJECT_ROOT + os.sep + 'robots.txt', 'r').read() + +urlpatterns = patterns('', + # Example: + # (r'^sandbox/', include('sandbox.foo.urls')), + + # Uncomment the admin/doc line below and add 'django.contrib.admindocs' + # to INSTALLED_APPS to enable admin documentation: + # (r'^admin/doc/', include('django.contrib.admindocs.urls')), + + # Uncomment the next line to enable the admin: + (r'^admin/django/', include(admin.site.urls)), + #(r'^grappelli/', include('grappelli.urls')), # grappelli URLS + + # Telemeta + (r'^', include('telemeta.urls')), + + # Languages + (r'^i18n/', include('django.conf.urls.i18n')), + (r'^jsi18n/$', 'django.views.i18n.javascript_catalog', js_info_dict), + (r'^robots\.txt$', lambda r: HttpResponse(robots_rules, mimetype="text/plain")), + + ) diff --git a/app/worker.py b/app/worker.py index b7779a0a..6d06656d 100644 --- a/app/worker.py +++ b/app/worker.py @@ -3,12 +3,13 @@ import os, sys from celery import Celery from django.conf import settings -sys.path.append(os.path.dirname('sandbox')) +sys.path.append(os.path.dirname('.')) +sys.path.append(os.path.dirname('..')) # set the default Django settings module for the 'celery' program. os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'settings') -app = Celery('sandbox') +app = Celery('app') # Using a string here means the worker will not have to # pickle the object when using Windows. diff --git a/app/wsgi.py b/app/wsgi.py index 58447f97..a16968d4 100644 --- a/app/wsgi.py +++ b/app/wsgi.py @@ -4,14 +4,14 @@ import os import sys -sys.path.append(os.path.dirname('sandbox')) +sys.path.append(os.path.dirname('.')) # os.environ['DJANGO_SETTINGS_MODULE'] = 'settings' # # import django.core.handlers.wsgi # application = django.core.handlers.wsgi.WSGIHandler() -os.environ.setdefault("DJANGO_SETTINGS_MODULE", "sandbox.settings") +os.environ.setdefault("DJANGO_SETTINGS_MODULE", "settings") from django.core.wsgi import get_wsgi_application application = get_wsgi_application() diff --git a/docker-compose.yml b/docker-compose.yml index 95de519f..a6cef527 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -55,7 +55,7 @@ app: - data env_file: - env/prod.env - command: /bin/sh deploy/app.sh + command: /bin/sh scripts/app.sh links: - broker - db @@ -67,7 +67,7 @@ worker: - app env_file: - env/prod.env - command: /bin/sh deploy/worker.sh + command: /bin/sh scripts/worker.sh links: - broker - db @@ -77,7 +77,7 @@ nginx: ports: - "8000:80" volumes: - - ./app/deploy/nginx.conf:/etc/nginx/conf.d/default.conf + - ./etc/nginx.conf:/etc/nginx/conf.d/default.conf volumes_from: - data links: diff --git a/env/build.yml b/env/build.yml deleted file mode 100644 index 3ee1e4c0..00000000 --- a/env/build.yml +++ /dev/null @@ -1,28 +0,0 @@ -# -*- coding: utf-8 -*- -# -# Copyright (c) 2015-2016 Parisson SARL - -# This file is part of Telemeta. - -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Affero General Public License as published by -# the Free Software Foundation, either version 2 of the License, or -# (at your option) any later version. - -# TimeSide 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 Affero General Public License for more details. - -# You should have received a copy of the GNU Affero General Public License -# along with TimeSide. If not, see . - -# Authors: -# Guillaume Pellerin -# Thomas Fillon - -app: - build: . - -worker: - build: . diff --git a/env/debug.yml b/env/debug.yml index 7a5301ab..d41b0df9 100644 --- a/env/debug.yml +++ b/env/debug.yml @@ -23,9 +23,6 @@ app: - volumes: - - ./app/:/srv/app - - ./telemeta/:/srv/src/telemeta/telemeta env_file: - env/debug.env diff --git a/env/dev.yml b/env/dev.yml index 4667e01e..2142946d 100644 --- a/env/dev.yml +++ b/env/dev.yml @@ -25,7 +25,7 @@ app: env_file: - env/debug.env - command: /bin/sh deploy/app.sh --runserver + command: /bin/sh scripts/app.sh --runserver ports: - 8000:8000 diff --git a/etc/apt.list b/etc/apt.list new file mode 100644 index 00000000..81a807a5 --- /dev/null +++ b/etc/apt.list @@ -0,0 +1,12 @@ +deb http://ftp.debian.org/debian/ wheezy-backports main contrib non-free +deb-src http://ftp.debian.org/debian/ wheezy-backports main contrib non-free + +deb http://security.debian.org/ wheezy/updates main +deb-src http://security.debian.org/ wheezy/updates main + +deb http://www.deb-multimedia.org wheezy main non-free +deb http://www.deb-multimedia.org wheezy-backports main + +deb http://debian.parisson.com/debian/ wheezy main +deb-src http://debian.parisson.com/debian wheezy main + diff --git a/etc/nginx.conf b/etc/nginx.conf new file mode 100644 index 00000000..4cadc469 --- /dev/null +++ b/etc/nginx.conf @@ -0,0 +1,37 @@ +server_tokens off; + +server { + listen 80; + server_name nginx; + charset utf-8; + + access_log /var/log/nginx/app-access.log; + error_log /var/log/nginx/app-error.log; + + # max upload size + client_max_body_size 4096M; # adjust to taste + + # Django media + location /media/ { + alias /srv/media/; # your Django project's media files - amend as required + } + # Django static + location /static { + alias /srv/static/; # your Django project's static files - amend as required + } + + # phpmyadmin + location /phpmyadmin/ { + proxy_pass http://phpmyadmin/; + #proxy_set_header Host $http_host; + #proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + #proxy_set_header X-Forwarded-Server $http_host; + #proxy_redirect / /phpmyadmin/; + #proxy_cookie_path / /phpmyadmin/; + } + + location / { + uwsgi_pass app:8000; + include /etc/nginx/uwsgi_params; + } +}