diff --git a/.gitignore b/.gitignore
index 0686785..baab8ce 100644
--- a/.gitignore
+++ b/.gitignore
@@ -29,4 +29,8 @@ pip-log.txt
*bootstrap*.js
*bootstrap*.css
-*d3.*.js
\ No newline at end of file
+*d3.*.js
+
+.files/
+*.ged
+settings_local.py
diff --git a/Dockerfile b/Dockerfile
new file mode 100644
index 0000000..d94821c
--- /dev/null
+++ b/Dockerfile
@@ -0,0 +1,10 @@
+FROM python:2.7
+
+COPY ./ /src/
+
+WORKDIR /src/
+RUN pip install -r reqs.pip
+
+RUN adduser --disabled-password --gecos '' gedgo
+RUN chown -R gedgo:gedgo /src
+USER gedgo
diff --git a/__init__.py b/__init__.py
index 75d82e3..e69de29 100644
--- a/__init__.py
+++ b/__init__.py
@@ -1,7 +0,0 @@
-from django.conf import settings
-import redis
-
-REDIS = None
-if hasattr(settings, 'GEDGO_REDIS_SERVER'):
- REDIS = redis.StrictRedis(host=settings.GEDGO_REDIS_SERVER)
- REDIS.ping()
diff --git a/api.py b/api.py
deleted file mode 100644
index 9f2f726..0000000
--- a/api.py
+++ /dev/null
@@ -1,44 +0,0 @@
-from tastypie.resources import ModelResource
-from gedgo.models import Person, Family
-from tastypie.authentication import BasicAuthentication
-from tastypie.authorization import ReadOnlyAuthorization
-
-from functools import wraps
-
-
-def add_photos(f):
- @wraps(f)
- def wrapper(self, bundle):
- photos = bundle.obj.photos()
- if not photos:
- return bundle
- images = map(lambda i: i.docfile.url, photos)
- bundle.data['images'] = images
- return bundle
- return wrapper
-
-
-class PersonResource(ModelResource):
- class Meta:
- list_allowed_methods = ['get']
- queryset = Person.objects.all()
- resource_name = 'person'
- authentication = BasicAuthentication()
- authorization = ReadOnlyAuthorization()
-
- @add_photos
- def dehydrate(self, bundle):
- return bundle
-
-
-class FamilyResource(ModelResource):
- class Meta:
- list_allowed_methods = ['get']
- queryset = Family.objects.all()
- resource_name = 'family'
- authentication = BasicAuthentication()
- authorization = ReadOnlyAuthorization()
-
- @add_photos
- def dehydrate(self, bundle):
- return bundle
diff --git a/docker-compose.yml b/docker-compose.yml
new file mode 100644
index 0000000..e89d45a
--- /dev/null
+++ b/docker-compose.yml
@@ -0,0 +1,42 @@
+# Dev services
+avahi:
+ image: 'enernoclabs/avahi:latest'
+ net: 'host'
+ log_driver: 'none'
+ restart: 'on-failure'
+db:
+ image: 'mysql'
+ ports:
+ - '3306:3306'
+ environment:
+ MYSQL_ROOT_PASSWORD: 'docker'
+ MYSQL_DATABASE: 'gedgo'
+ MYSQL_USER: 'gedgo'
+ MYSQL_PASSWORD: 'gedgo'
+ log_driver: 'none'
+redis:
+ image: 'redis'
+ ports:
+ - '6379'
+ log_driver: 'none'
+# Application
+app:
+ build: '.'
+ container_name: 'gedgo_app'
+ command: ['python', 'manage.py', 'runserver', '0.0.0.0:8000']
+ volumes:
+ - './:/src'
+ ports:
+ - '8000:8000'
+ links:
+ - 'db'
+ - 'redis'
+worker:
+ image: 'gedgo_app'
+ command: ['python', 'manage.py', 'celeryd', '-c', '1', '--loglevel=info']
+ volumes:
+ - './:/src'
+ links:
+ - 'app'
+ - 'db'
+ - 'redis'
diff --git a/gedgo/__init__.py b/gedgo/__init__.py
new file mode 100644
index 0000000..ae6f887
--- /dev/null
+++ b/gedgo/__init__.py
@@ -0,0 +1,7 @@
+from django.conf import settings
+import redis as Redis
+
+redis = None
+if hasattr(settings, 'GEDGO_REDIS_SERVER'):
+ redis = Redis.StrictRedis(host=settings.GEDGO_REDIS_SERVER)
+ redis.ping()
diff --git a/admin.py b/gedgo/admin.py
similarity index 100%
rename from admin.py
rename to gedgo/admin.py
diff --git a/forms.py b/gedgo/forms.py
similarity index 100%
rename from forms.py
rename to gedgo/forms.py
diff --git a/gedcom_parser.py b/gedgo/gedcom_parser.py
similarity index 100%
rename from gedcom_parser.py
rename to gedgo/gedcom_parser.py
diff --git a/gedcom_update.py b/gedgo/gedcom_update.py
similarity index 91%
rename from gedcom_update.py
rename to gedgo/gedcom_update.py
index 8687171..46226ca 100644
--- a/gedcom_update.py
+++ b/gedgo/gedcom_update.py
@@ -6,6 +6,7 @@
from django.utils import timezone
from django.conf import settings
from datetime import datetime
+from dropbox.dropbox import Dropbox
from re import findall
from os import path, mkdir
@@ -54,7 +55,7 @@ def update(g, file_name, verbose=True):
g.save()
-#--- Second Level script functions
+# --- Second Level script functions
def __process_all_relations(gedcom, parsed, verbose=True):
if verbose:
print ' Starting Person objects.'
@@ -254,7 +255,7 @@ def __process_Document(entry, obj, g):
else:
thumb = None
- known = Document.objects.filter(docfile=unicode(file_name))
+ known = Document.objects.filter(docfile=file_name.decode('utf-8').strip())
if len(known) > 0:
m = known[0]
@@ -353,12 +354,20 @@ def __child_by_tag(entry, tag):
return child
+# TODO: Proper Storage class approach to this code
def __valid_document_entry(e):
- file_name = __child_value_by_tags(e, 'FILE')
- img_presence = path.join(settings.MEDIA_ROOT, path.basename(file_name))
+ file_name = __strip_files_directories(e)
+ media_file = path.join(settings.MEDIA_ROOT, file_name)
+
+ # The file exists already
+ if isinstance(file_name, basestring) and file_name and \
+ path.exists(media_file):
+ return True
+
+ if __get_from_dropbox(file_name, media_file, ):
+ return True
- return isinstance(file_name, basestring) and file_name and \
- path.exists(img_presence)
+ return False
def __strip_files_directories(e):
@@ -366,6 +375,19 @@ def __strip_files_directories(e):
return path.basename(file_name)
+def __get_from_dropbox(file_name, media_file_name):
+ if not getattr(settings, 'DROPBOX_ACCESS_TOKEN', None):
+ return False
+ d = Dropbox(settings.DROPBOX_ACCESS_TOKEN)
+ resource_path = path.join(settings.DROPBOX_BASE_PATH, file_name)
+ print ' .. %s' % resource_path
+ try:
+ d.files_download_to_file(media_file_name, resource_path)
+ return True
+ except:
+ return False
+
+
def make_thumbnail(file_name):
base_name = path.basename(file_name)
dir_name = path.dirname(file_name)
diff --git a/management/__init__.py b/gedgo/management/__init__.py
similarity index 100%
rename from management/__init__.py
rename to gedgo/management/__init__.py
diff --git a/management/commands/__init__.py b/gedgo/management/commands/__init__.py
similarity index 100%
rename from management/commands/__init__.py
rename to gedgo/management/commands/__init__.py
diff --git a/management/commands/add_gedcom.py b/gedgo/management/commands/add_gedcom.py
similarity index 100%
rename from management/commands/add_gedcom.py
rename to gedgo/management/commands/add_gedcom.py
diff --git a/management/commands/update_gedcom.py b/gedgo/management/commands/update_gedcom.py
similarity index 100%
rename from management/commands/update_gedcom.py
rename to gedgo/management/commands/update_gedcom.py
diff --git a/middleware.py b/gedgo/middleware.py
similarity index 78%
rename from middleware.py
rename to gedgo/middleware.py
index 0de3230..bd1ed43 100644
--- a/middleware.py
+++ b/gedgo/middleware.py
@@ -1,4 +1,4 @@
-from gedgo import REDIS
+from gedgo import redis
import json
import time
import re
@@ -16,8 +16,8 @@ class SimpleTrackerMiddleware(object):
"""
def process_response(self, request, response):
- # Don't process if REDIS isn't configured or non-200 response
- if REDIS is None or response.status_code != 200:
+ # Don't process if redis isn't configured or non-200 response
+ if redis is None or response.status_code != 200:
return response
# Only track non-superuser visitors
@@ -41,15 +41,15 @@ def process_response(self, request, response):
'path': request.path_info,
'time': int(time.time())
}
- REDIS.lpush('gedgo_user_%d_page_views' % id_, json.dumps(page_view))
- REDIS.ltrim('gedgo_user_%d_page_views' % id_, 0, 100)
+ redis.lpush('gedgo_user_%d_page_views' % id_, json.dumps(page_view))
+ redis.ltrim('gedgo_user_%d_page_views' % id_, 0, 100)
return response
def _increment_key(key_name):
try:
- pvc = int(REDIS.get(key_name))
+ pvc = int(redis.get(key_name))
except TypeError:
pvc = 0
- REDIS.set(key_name, pvc + 1)
+ redis.set(key_name, pvc + 1)
diff --git a/gedgo/migrations/0001_initial.py b/gedgo/migrations/0001_initial.py
new file mode 100644
index 0000000..0468a1f
--- /dev/null
+++ b/gedgo/migrations/0001_initial.py
@@ -0,0 +1,200 @@
+# -*- coding: utf-8 -*-
+# Generated by Django 1.9.2 on 2016-02-12 06:49
+from __future__ import unicode_literals
+
+from django.db import migrations, models
+import django.db.models.deletion
+
+
+class Migration(migrations.Migration):
+
+ initial = True
+
+ dependencies = [
+ ]
+
+ operations = [
+ migrations.CreateModel(
+ name='BlogPost',
+ fields=[
+ ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+ ('title', models.CharField(max_length=60)),
+ ('body', models.TextField()),
+ ('created', models.DateTimeField(auto_now_add=True)),
+ ],
+ ),
+ migrations.CreateModel(
+ name='Document',
+ fields=[
+ ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+ ('title', models.CharField(blank=True, max_length=40, null=True)),
+ ('description', models.TextField(blank=True, null=True)),
+ ('docfile', models.FileField(upload_to=b'uploaded')),
+ ('last_updated', models.DateTimeField(auto_now_add=True)),
+ ('thumb', models.FileField(blank=True, null=True, upload_to=b'uploaded/thumbs')),
+ ('kind', models.CharField(choices=[(b'DOCUM', b'Document'), (b'VIDEO', b'Video'), (b'PHOTO', b'Image')], max_length=5)),
+ ],
+ ),
+ migrations.CreateModel(
+ name='Documentary',
+ fields=[
+ ('title', models.CharField(max_length=100, primary_key=True, serialize=False)),
+ ('tagline', models.CharField(max_length=100)),
+ ('location', models.CharField(blank=True, max_length=100, null=True)),
+ ('description', models.TextField(blank=True, null=True)),
+ ('last_updated', models.DateTimeField(auto_now_add=True)),
+ ],
+ options={
+ 'verbose_name_plural': 'Documentaries',
+ },
+ ),
+ migrations.CreateModel(
+ name='Event',
+ fields=[
+ ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+ ('date', models.DateField(null=True)),
+ ('year_range_end', models.IntegerField(null=True)),
+ ('date_format', models.CharField(max_length=10, null=True)),
+ ('date_approxQ', models.BooleanField(verbose_name=b'Date is approximate')),
+ ('place', models.CharField(max_length=50)),
+ ],
+ ),
+ migrations.CreateModel(
+ name='Family',
+ fields=[
+ ('pointer', models.CharField(max_length=10, primary_key=True, serialize=False)),
+ ('kind', models.CharField(blank=True, max_length=10, null=True, verbose_name=b'Event')),
+ ],
+ ),
+ migrations.CreateModel(
+ name='Gedcom',
+ fields=[
+ ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+ ('file_name', models.CharField(blank=True, max_length=40, null=True)),
+ ('title', models.CharField(blank=True, max_length=40, null=True)),
+ ('description', models.TextField(blank=True, null=True)),
+ ('last_updated', models.DateTimeField()),
+ ('key_families', models.ManyToManyField(blank=True, related_name='gedcom_key_families', to='gedgo.Family')),
+ ],
+ ),
+ migrations.CreateModel(
+ name='Note',
+ fields=[
+ ('pointer', models.CharField(max_length=10, primary_key=True, serialize=False)),
+ ('text', models.TextField()),
+ ('gedcom', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='gedgo.Gedcom')),
+ ],
+ ),
+ migrations.CreateModel(
+ name='Person',
+ fields=[
+ ('pointer', models.CharField(max_length=10, primary_key=True, serialize=False)),
+ ('first_name', models.CharField(max_length=255)),
+ ('last_name', models.CharField(max_length=255)),
+ ('prefix', models.CharField(max_length=255)),
+ ('suffix', models.CharField(max_length=255)),
+ ('education', models.TextField(null=True)),
+ ('religion', models.CharField(blank=True, max_length=255, null=True)),
+ ('birth', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='person_birth', to='gedgo.Event')),
+ ('child_family', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='person_child_family', to='gedgo.Family')),
+ ('death', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='person_death', to='gedgo.Event')),
+ ('gedcom', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='gedgo.Gedcom')),
+ ('notes', models.ManyToManyField(blank=True, to='gedgo.Note')),
+ ('profile', models.ManyToManyField(blank=True, to='gedgo.Document')),
+ ('spousal_families', models.ManyToManyField(related_name='person_spousal_families', to='gedgo.Family')),
+ ],
+ options={
+ 'verbose_name_plural': 'People',
+ },
+ ),
+ migrations.AddField(
+ model_name='gedcom',
+ name='key_people',
+ field=models.ManyToManyField(blank=True, related_name='gedcom_key_people', to='gedgo.Person'),
+ ),
+ migrations.AddField(
+ model_name='family',
+ name='children',
+ field=models.ManyToManyField(related_name='family_children', to='gedgo.Person'),
+ ),
+ migrations.AddField(
+ model_name='family',
+ name='gedcom',
+ field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='gedgo.Gedcom'),
+ ),
+ migrations.AddField(
+ model_name='family',
+ name='husbands',
+ field=models.ManyToManyField(related_name='family_husbands', to='gedgo.Person'),
+ ),
+ migrations.AddField(
+ model_name='family',
+ name='joined',
+ field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='family_joined', to='gedgo.Event'),
+ ),
+ migrations.AddField(
+ model_name='family',
+ name='notes',
+ field=models.ManyToManyField(blank=True, to='gedgo.Note'),
+ ),
+ migrations.AddField(
+ model_name='family',
+ name='separated',
+ field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='family_separated', to='gedgo.Event'),
+ ),
+ migrations.AddField(
+ model_name='family',
+ name='wives',
+ field=models.ManyToManyField(related_name='family_wives', to='gedgo.Person'),
+ ),
+ migrations.AddField(
+ model_name='event',
+ name='gedcom',
+ field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='gedgo.Gedcom'),
+ ),
+ migrations.AddField(
+ model_name='documentary',
+ name='gedcom',
+ field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='gedgo.Gedcom'),
+ ),
+ migrations.AddField(
+ model_name='documentary',
+ name='tagged_families',
+ field=models.ManyToManyField(blank=True, related_name='documentaries_tagged_families', to='gedgo.Family'),
+ ),
+ migrations.AddField(
+ model_name='documentary',
+ name='tagged_people',
+ field=models.ManyToManyField(blank=True, related_name='documentaries_tagged_people', to='gedgo.Person'),
+ ),
+ migrations.AddField(
+ model_name='documentary',
+ name='thumb',
+ field=models.ForeignKey(blank=True, on_delete=django.db.models.deletion.CASCADE, related_name='documentaries_thumb', to='gedgo.Document'),
+ ),
+ migrations.AddField(
+ model_name='document',
+ name='gedcom',
+ field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='gedgo.Gedcom'),
+ ),
+ migrations.AddField(
+ model_name='document',
+ name='tagged_families',
+ field=models.ManyToManyField(blank=True, related_name='media_tagged_families', to='gedgo.Family'),
+ ),
+ migrations.AddField(
+ model_name='document',
+ name='tagged_people',
+ field=models.ManyToManyField(blank=True, related_name='media_tagged_people', to='gedgo.Person'),
+ ),
+ migrations.AddField(
+ model_name='blogpost',
+ name='tagged_people',
+ field=models.ManyToManyField(blank=True, related_name='blogpost_tagged_people', to='gedgo.Person'),
+ ),
+ migrations.AddField(
+ model_name='blogpost',
+ name='tagged_photos',
+ field=models.ManyToManyField(blank=True, related_name='blogpost_tagged_photos', to='gedgo.Document'),
+ ),
+ ]
diff --git a/migrations/__init__.py b/gedgo/migrations/__init__.py
similarity index 100%
rename from migrations/__init__.py
rename to gedgo/migrations/__init__.py
diff --git a/models/__init__.py b/gedgo/models/__init__.py
similarity index 100%
rename from models/__init__.py
rename to gedgo/models/__init__.py
diff --git a/models/blogpost.py b/gedgo/models/blogpost.py
similarity index 93%
rename from models/blogpost.py
rename to gedgo/models/blogpost.py
index 898a077..d048e93 100644
--- a/models/blogpost.py
+++ b/gedgo/models/blogpost.py
@@ -12,13 +12,11 @@ class Meta:
tagged_photos = models.ManyToManyField(
'Document',
related_name='blogpost_tagged_photos',
- null=True,
blank=True
)
tagged_people = models.ManyToManyField(
'Person',
related_name='blogpost_tagged_people',
- null=True,
blank=True
)
diff --git a/models/document.py b/gedgo/models/document.py
similarity index 91%
rename from models/document.py
rename to gedgo/models/document.py
index 2753f5a..92759df 100644
--- a/models/document.py
+++ b/gedgo/models/document.py
@@ -24,11 +24,11 @@ class Meta:
)
tagged_people = models.ManyToManyField(
'Person',
- related_name='media_tagged_people', null=True, blank=True
+ related_name='media_tagged_people', blank=True
)
tagged_families = models.ManyToManyField(
'Family',
- related_name='media_tagged_families', null=True, blank=True
+ related_name='media_tagged_families', blank=True
)
def __unicode__(self):
diff --git a/models/documentary.py b/gedgo/models/documentary.py
similarity index 96%
rename from models/documentary.py
rename to gedgo/models/documentary.py
index 4a7b92a..bf2d000 100644
--- a/models/documentary.py
+++ b/gedgo/models/documentary.py
@@ -21,13 +21,11 @@ class Meta:
tagged_people = models.ManyToManyField(
'Person',
related_name='documentaries_tagged_people',
- null=True,
blank=True
)
tagged_families = models.ManyToManyField(
'Family',
related_name='documentaries_tagged_families',
- null=True,
blank=True
)
diff --git a/models/event.py b/gedgo/models/event.py
similarity index 100%
rename from models/event.py
rename to gedgo/models/event.py
diff --git a/models/family.py b/gedgo/models/family.py
similarity index 97%
rename from models/family.py
rename to gedgo/models/family.py
index e361753..9e9c9c0 100644
--- a/models/family.py
+++ b/gedgo/models/family.py
@@ -13,7 +13,7 @@ class Meta:
wives = models.ManyToManyField('Person', related_name='family_wives')
children = models.ManyToManyField('Person', related_name='family_children')
- notes = models.ManyToManyField('Note', null=True)
+ notes = models.ManyToManyField('Note', blank=True)
kind = models.CharField('Event', max_length=10, blank=True, null=True)
joined = models.ForeignKey(
diff --git a/models/gedcom.py b/gedgo/models/gedcom.py
similarity index 96%
rename from models/gedcom.py
rename to gedgo/models/gedcom.py
index 492cc2f..703c58e 100644
--- a/models/gedcom.py
+++ b/gedgo/models/gedcom.py
@@ -16,13 +16,11 @@ class Meta:
key_people = models.ManyToManyField(
'Person',
related_name='gedcom_key_people',
- null=True,
blank=True
)
key_families = models.ManyToManyField(
'Family',
related_name='gedcom_key_families',
- null=True,
blank=True
)
diff --git a/models/note.py b/gedgo/models/note.py
similarity index 100%
rename from models/note.py
rename to gedgo/models/note.py
diff --git a/models/person.py b/gedgo/models/person.py
similarity index 96%
rename from models/person.py
rename to gedgo/models/person.py
index 54ad62e..c3a18d7 100644
--- a/models/person.py
+++ b/gedgo/models/person.py
@@ -49,10 +49,10 @@ class Meta:
)
# Notes
- notes = models.ManyToManyField('Note', null=True)
+ notes = models.ManyToManyField('Note', blank=True)
# Profile
- profile = models.ManyToManyField('Document', null=True, blank=True)
+ profile = models.ManyToManyField('Document', blank=True)
def __unicode__(self):
return '%s, %s (%s)' % (self.last_name, self.first_name, self.pointer)
diff --git a/static/img/generic_person.gif b/gedgo/static/img/generic_person.gif
similarity index 100%
rename from static/img/generic_person.gif
rename to gedgo/static/img/generic_person.gif
diff --git a/static/img/sad.jpg b/gedgo/static/img/sad.jpg
similarity index 100%
rename from static/img/sad.jpg
rename to gedgo/static/img/sad.jpg
diff --git a/static/js/pedigree.js b/gedgo/static/js/pedigree.js
similarity index 100%
rename from static/js/pedigree.js
rename to gedgo/static/js/pedigree.js
diff --git a/static/js/timeline.js b/gedgo/static/js/timeline.js
similarity index 100%
rename from static/js/timeline.js
rename to gedgo/static/js/timeline.js
diff --git a/static/screenshots/individualview.png b/gedgo/static/screenshots/individualview.png
similarity index 100%
rename from static/screenshots/individualview.png
rename to gedgo/static/screenshots/individualview.png
diff --git a/static/screenshots/timeline.png b/gedgo/static/screenshots/timeline.png
similarity index 100%
rename from static/screenshots/timeline.png
rename to gedgo/static/screenshots/timeline.png
diff --git a/static/styles/style-default.css b/gedgo/static/styles/style-default.css
similarity index 100%
rename from static/styles/style-default.css
rename to gedgo/static/styles/style-default.css
diff --git a/static/styles/style-login.css b/gedgo/static/styles/style-login.css
similarity index 100%
rename from static/styles/style-login.css
rename to gedgo/static/styles/style-login.css
diff --git a/gedgo/storages.py b/gedgo/storages.py
new file mode 100644
index 0000000..9c28e1e
--- /dev/null
+++ b/gedgo/storages.py
@@ -0,0 +1,56 @@
+from django.core.files.storage import Storage
+from django.utils._os import safe_join
+from django.conf import settings
+
+import os
+from dropbox.client import DropboxClient
+
+
+class DropboxStorage(Storage):
+ def __init__(self, *args, **kwargs):
+ self.client = DropboxClient(settings.DROPBOX_ACCESS_TOKEN)
+ self.location = kwargs.get('location', settings.MEDIA_ROOT)
+
+ def path(self, name):
+ return safe_join(self.location, name)
+
+ def created_time(self, name):
+ raise NotImplementedError
+
+ def exists(self, name):
+ raise NotImplementedError
+
+ def get_available_name(self, name):
+ raise NotImplementedError
+
+ def get_valid_name(self, name):
+ raise NotImplementedError
+
+ def listdir(self, path):
+ meta = self.client.metadata(self.path(path))
+ directories, files = [], []
+ for entry in meta['contents']:
+ name = os.path.basename(entry['path'])
+ if entry['is_dir']:
+ directories.append(name)
+ else:
+ files.append(name)
+ return (directories, files)
+
+ def preview(self, name):
+ return self.client.thumbnail(self.path(name)).read()
+
+ def modified_time(self, name):
+ raise NotImplementedError
+
+ def open(self, name, mode='rb'):
+ raise NotImplementedError
+
+ def save(self, name, content, max_length=None):
+ raise NotImplementedError
+
+ def size(self, name):
+ raise NotImplementedError
+
+ def url(self, name):
+ return self.client.media(self.path(name))['url']
diff --git a/tasks.py b/gedgo/tasks.py
similarity index 95%
rename from tasks.py
rename to gedgo/tasks.py
index 2439189..bb2a342 100644
--- a/tasks.py
+++ b/gedgo/tasks.py
@@ -2,7 +2,7 @@
from __future__ import absolute_import
from gedgo.gedcom_update import update
-from gedgo import REDIS
+from gedgo import redis
from gedgo.models import Gedcom
import os
from celery import Celery
@@ -63,12 +63,12 @@ def async_update(gedcom_id, file_name, recipient_ids,
@app.task
def geo_resolve_ip(ip_address):
- if REDIS is None:
+ if redis is None:
return
try:
response = requests.get('ipinfo.io/%s/json' % ip_address)
j = response.json()
j['requested'] = datetime.utcnow().isoformat()
- REDIS.set('gedgo_ip_%s', json.dumps(j))
+ redis.set('gedgo_ip_%s', json.dumps(j))
except (requests.exceptions.RequestsException, ValueError):
return
diff --git a/templates/404.html b/gedgo/templates/404.html
similarity index 100%
rename from templates/404.html
rename to gedgo/templates/404.html
diff --git a/templates/500.html b/gedgo/templates/500.html
similarity index 100%
rename from templates/500.html
rename to gedgo/templates/500.html
diff --git a/templates/admin/base_site.html b/gedgo/templates/admin/base_site.html
similarity index 100%
rename from templates/admin/base_site.html
rename to gedgo/templates/admin/base_site.html
diff --git a/templates/auth/base.html b/gedgo/templates/auth/base.html
similarity index 100%
rename from templates/auth/base.html
rename to gedgo/templates/auth/base.html
diff --git a/templates/auth/login.html b/gedgo/templates/auth/login.html
similarity index 100%
rename from templates/auth/login.html
rename to gedgo/templates/auth/login.html
diff --git a/templates/auth/password_reset_confirm.html b/gedgo/templates/auth/password_reset_confirm.html
similarity index 100%
rename from templates/auth/password_reset_confirm.html
rename to gedgo/templates/auth/password_reset_confirm.html
diff --git a/templates/auth/password_reset_done.html b/gedgo/templates/auth/password_reset_done.html
similarity index 100%
rename from templates/auth/password_reset_done.html
rename to gedgo/templates/auth/password_reset_done.html
diff --git a/templates/auth/password_reset_email.html b/gedgo/templates/auth/password_reset_email.html
similarity index 100%
rename from templates/auth/password_reset_email.html
rename to gedgo/templates/auth/password_reset_email.html
diff --git a/templates/default/base.html b/gedgo/templates/default/base.html
similarity index 100%
rename from templates/default/base.html
rename to gedgo/templates/default/base.html
diff --git a/templates/default/blogpost.html b/gedgo/templates/default/blogpost.html
similarity index 100%
rename from templates/default/blogpost.html
rename to gedgo/templates/default/blogpost.html
diff --git a/templates/default/blogpost_list.html b/gedgo/templates/default/blogpost_list.html
similarity index 100%
rename from templates/default/blogpost_list.html
rename to gedgo/templates/default/blogpost_list.html
diff --git a/templates/default/comment_form.html b/gedgo/templates/default/comment_form.html
similarity index 100%
rename from templates/default/comment_form.html
rename to gedgo/templates/default/comment_form.html
diff --git a/templates/default/dashboard.html b/gedgo/templates/default/dashboard.html
similarity index 100%
rename from templates/default/dashboard.html
rename to gedgo/templates/default/dashboard.html
diff --git a/templates/default/documentaries.html b/gedgo/templates/default/documentaries.html
similarity index 100%
rename from templates/default/documentaries.html
rename to gedgo/templates/default/documentaries.html
diff --git a/templates/default/gedcom.html b/gedgo/templates/default/gedcom.html
similarity index 100%
rename from templates/default/gedcom.html
rename to gedgo/templates/default/gedcom.html
diff --git a/templates/default/person-card.html b/gedgo/templates/default/person-card.html
similarity index 100%
rename from templates/default/person-card.html
rename to gedgo/templates/default/person-card.html
diff --git a/templates/default/person.html b/gedgo/templates/default/person.html
similarity index 100%
rename from templates/default/person.html
rename to gedgo/templates/default/person.html
diff --git a/templates/default/research.html b/gedgo/templates/default/research.html
similarity index 60%
rename from templates/default/research.html
rename to gedgo/templates/default/research.html
index 8fae9cb..181aba4 100644
--- a/templates/default/research.html
+++ b/gedgo/templates/default/research.html
@@ -23,12 +23,23 @@
{% endif %}
{{ current_level }}
+
+
+
{% endblock %}
diff --git a/templates/default/search_results.html b/gedgo/templates/default/search_results.html
similarity index 100%
rename from templates/default/search_results.html
rename to gedgo/templates/default/search_results.html
diff --git a/templates/default/user_tracking.html b/gedgo/templates/default/user_tracking.html
similarity index 100%
rename from templates/default/user_tracking.html
rename to gedgo/templates/default/user_tracking.html
diff --git a/tests.py b/gedgo/tests.py
similarity index 100%
rename from tests.py
rename to gedgo/tests.py
diff --git a/gedgo/urls.py b/gedgo/urls.py
new file mode 100644
index 0000000..a68de07
--- /dev/null
+++ b/gedgo/urls.py
@@ -0,0 +1,55 @@
+from django.conf.urls import url
+from django.shortcuts import redirect
+from django.contrib.auth.views import password_reset, password_reset_done, \
+ password_reset_confirm
+
+from gedgo import views
+
+urlpatterns = [
+ url(
+ r'^(?P\d+)/(?PI\d+)/$',
+ views.person,
+ name='person'
+ ),
+ url(r'^(?P\d+)/$', views.gedcom, name='gedcom'),
+
+ # XHR Data views
+ url(r'^(?P\d+)/pedigree/(?PI\d+)/$', views.pedigree),
+ url(r'^(?P\d+)/timeline/(?PI\d+)/$', views.timeline),
+ url(r'^dashboard/worker/status$', views.worker_status),
+
+ url(r'^blog/$', views.blog_list),
+ url(r'^blog/(?P\d+)/(?P\d+)/$', views.blog),
+ url(r'^blog/post/(?P\d+)/$', views.blogpost),
+ url(r'^documentaries/$', views.documentaries),
+ url(r'^research/(?P.*)$', views.research),
+ url(r'^search/$', views.search),
+ url(r'^dashboard/$', views.dashboard),
+ url(r'^dashboard/user/(?P\d+)/$', views.user_tracking),
+
+ # Auth
+ url(r'^logout/$', views.logout_view),
+ url(r'^password_reset/$',
+ password_reset,
+ {
+ 'template_name': 'auth/login.html',
+ 'email_template_name': 'auth/password_reset_email.html',
+ 'post_reset_redirect': '/gedgo/password_reset/done/'
+ }),
+ url(r'^password_reset/done/$',
+ password_reset_done,
+ {
+ 'template_name': 'auth/password_reset_done.html'
+ }),
+ url(r'^password_reset/(?P[0-9A-Za-z]+)-(?P.+)/$',
+ password_reset_confirm,
+ {
+ 'post_reset_redirect': '/',
+ 'template_name': 'auth/password_reset_confirm.html'
+ }),
+
+ # Backup media fileserve view
+ url(r'^media/(?P.*)$', views.media),
+
+ url(r'^$', lambda r: redirect('/gedgo/1/')),
+]
diff --git a/views/__init__.py b/gedgo/views/__init__.py
similarity index 100%
rename from views/__init__.py
rename to gedgo/views/__init__.py
diff --git a/views/blog.py b/gedgo/views/blog.py
similarity index 100%
rename from views/blog.py
rename to gedgo/views/blog.py
diff --git a/views/dashboard.py b/gedgo/views/dashboard.py
similarity index 84%
rename from views/dashboard.py
rename to gedgo/views/dashboard.py
index 1e9b59b..f3cb671 100644
--- a/views/dashboard.py
+++ b/gedgo/views/dashboard.py
@@ -2,7 +2,7 @@
from gedgo.tasks import app, async_update
from gedgo.views.util import render
from gedgo.models import Gedcom
-from gedgo import REDIS
+from gedgo import redis
from django.http import Http404, HttpResponse
from django.contrib.auth.decorators import login_required
@@ -10,7 +10,6 @@
from django.core.files.storage import default_storage
from django.contrib import messages
from django.shortcuts import redirect
-from django.contrib.sites.models import get_current_site
from django.conf import settings
from django.shortcuts import get_object_or_404
@@ -37,7 +36,7 @@ def dashboard(request):
if form is None:
form = UpdateForm()
- # Collect tracking stats from Redis storage
+ # Collect tracking stats from redis storage
tracking_start, user_views, total = _page_view_stats()
# Render list page with the documents and the form
@@ -77,11 +76,11 @@ def user_tracking(request, user_id):
raise Http404
user = get_object_or_404(User, id=user_id)
- count = REDIS.keys('gedgo_user_%d_page_view_count' % user.id)
+ count = redis.keys('gedgo_user_%d_page_view_count' % user.id)
if not count:
raise Http404
- views = REDIS.lrange('gedgo_user_%d_page_views' % user.id, 0, -1)
+ views = redis.lrange('gedgo_user_%d_page_views' % user.id, 0, -1)
views = [_load_page_view(v) for v in views]
return render(
@@ -105,7 +104,7 @@ def _handle_upload(request, form):
os.path.join(settings.MEDIA_ROOT, file_name),
form.cleaned_data['email_users'],
form.cleaned_data['message'],
- get_current_site(request).domain,
+ request.get_host(),
request.user.id
)
messages.success(
@@ -122,29 +121,29 @@ def _handle_upload(request, form):
def _reset_tracking():
- if REDIS is None:
+ if redis is None:
return {}
- keys = REDIS.keys('gedgo_*')
+ keys = redis.keys('gedgo_*')
for key in keys:
- REDIS.delete(key)
+ redis.delete(key)
- REDIS.set('gedgo_tracking_start', int(time.time()))
+ redis.set('gedgo_tracking_start', int(time.time()))
def _page_view_stats():
- if REDIS is None:
- return {}
+ if redis is None:
+ return datetime.datetime.utcnow(), {}, 0
- user_keys = REDIS.keys('gedgo_user_*_page_view_count')
+ user_keys = redis.keys('gedgo_user_*_page_view_count')
users = User.objects.filter(
id__in=[int(k.split('_')[2]) for k in user_keys]
)
user_views = []
for user in users:
- last = REDIS.lrange('gedgo_user_%d_page_views' % user.id, 0, 0)[0]
- pvc = REDIS.get('gedgo_user_%d_page_view_count' % user.id)
+ last = redis.lrange('gedgo_user_%d_page_views' % user.id, 0, 0)[0]
+ pvc = redis.get('gedgo_user_%d_page_view_count' % user.id)
user_views.append({
'user': user,
'last_view': _load_page_view(last)['timestamp'],
@@ -154,7 +153,7 @@ def _page_view_stats():
tracking_start = _timestamp_from_redis('gedgo_tracking_start')
- return tracking_start, user_views, REDIS.get('gedgo_page_view_count')
+ return tracking_start, user_views, redis.get('gedgo_page_view_count')
def _load_page_view(json_str):
@@ -165,7 +164,7 @@ def _load_page_view(json_str):
def _timestamp_from_redis(key):
try:
- timestamp = REDIS.get(key)
+ timestamp = redis.get(key)
return datetime.datetime.fromtimestamp(int(timestamp))
except:
pass
diff --git a/views/model_views.py b/gedgo/views/model_views.py
similarity index 100%
rename from views/model_views.py
rename to gedgo/views/model_views.py
diff --git a/gedgo/views/research.py b/gedgo/views/research.py
new file mode 100644
index 0000000..35bd772
--- /dev/null
+++ b/gedgo/views/research.py
@@ -0,0 +1,78 @@
+from django.conf import settings
+from django.http import Http404, HttpResponseRedirect
+from django.contrib.auth.decorators import login_required
+from django.utils.module_loading import import_string
+
+from os import path
+import mimetypes
+
+from gedgo.views.util import render
+
+
+storage = None
+if getattr(settings, 'GEDGO_RESEARCH_FILE_STORAGE', None):
+ storage = import_string(settings.GEDGO_RESEARCH_FILE_STORAGE)(
+ location=settings.GEDGO_RESEARCH_FILE_ROOT)
+
+
+@login_required
+def research(request, pathname):
+ if storage is None:
+ raise Http404
+
+ name = pathname.strip('/')
+
+ # Serve the content through xsendfile or directly.
+ try:
+ if '.' in name:
+ return HttpResponseRedirect(storage.url(name))
+ else:
+ directories, files = storage.listdir(name)
+ directories = [__process(name, d, True) for d in directories]
+ files = [__process(name, f, False) for f in files]
+
+ # Build a depth tree of the directories above this one for
+ # navigation
+ levels = [('Research Files', '')]
+ if name:
+ lp = ''
+ for l in name.split('/'):
+ lp = '%s/%s' % (lp, l)
+ levels.append((l, lp))
+
+ return render(
+ request,
+ 'research.html',
+ {
+ 'directories': directories,
+ 'files': files,
+ 'levels': levels
+ }
+ )
+ except Exception as e:
+ raise e
+ raise Http404
+
+
+def __process(name, p, is_dir=False):
+ type_ = 'folder_open' if is_dir else _get_type(p)
+ return {
+ 'type': type_,
+ 'path': path.join(name, p),
+ 'name': p,
+ 'preview': type_ == 'image'
+ }
+
+# glyphicon name mappings
+MIMETYPE_MAPPING = {
+ 'video': 'facetime-video',
+ 'audio': 'volume-up',
+ 'image': 'picture'
+}
+
+
+def _get_type(c):
+ guess, _ = mimetypes.guess_type(c)
+ if guess and guess.split('/')[0] in MIMETYPE_MAPPING:
+ return MIMETYPE_MAPPING[guess.split('/')[0]]
+ return 'file'
diff --git a/views/search.py b/gedgo/views/search.py
similarity index 100%
rename from views/search.py
rename to gedgo/views/search.py
diff --git a/views/util.py b/gedgo/views/util.py
similarity index 69%
rename from views/util.py
rename to gedgo/views/util.py
index 2751fa6..0436c58 100644
--- a/views/util.py
+++ b/gedgo/views/util.py
@@ -1,10 +1,9 @@
-from django.http import HttpResponse
-from django.core.servers.basehttp import FileWrapper
+from wsgiref.util import FileWrapper
+from django.http import HttpResponse, HttpResponseRedirect
from django.core.files.storage import default_storage
from django.contrib.auth.decorators import login_required
from django.http import Http404
from django.conf import settings
-from django.contrib.sites.models import get_current_site
from django.shortcuts import redirect
from django.contrib.auth import logout
from django.contrib import messages
@@ -25,8 +24,8 @@ def media(request, file_base_name):
it's much better to have a webserver handle this through
an authenticated proxy
"""
- filename = path.join(settings.MEDIA_ROOT, file_base_name.strip('/'))
- return serve_content(filename)
+ filename = file_base_name.strip('/')
+ return serve_content(request, filename)
def process_comments(request, noun):
@@ -83,12 +82,12 @@ def site_context(request):
show_blog = BlogPost.objects.exists()
show_documentaries = Documentary.objects.exists()
show_researchfiles = isinstance(
- getattr(settings, 'RESEARCH_FILES_ROOT', None),
+ getattr(settings, 'GEDGO_RESEARCH_FILE_ROOT', None),
basestring
)
show_file_uploads = getattr(
settings, 'GEDGO_ALLOW_FILE_UPLOADS', True) is True
- site_title = get_current_site(request).name
+ site_title = settings.GEDGO_SITE_TITLE
user = request.user
return {
@@ -101,31 +100,40 @@ def site_context(request):
}
-def serve_content(filename):
+def serve_content(request, filename):
"""
Generate a response to server protected content.
http://djangosnippets.org/snippets/365/
http://www.chicagodjango.com/blog/permission-based-file-serving/
"""
- if not path.exists(filename):
- raise Http404
- media_server = getattr(settings, 'GEDGO_MEDIA_SERVER', '').lower()
- if media_server == 'apache':
- response = HttpResponse()
- response['X-Sendfile'] = filename
- elif media_server == 'nginx':
- response = HttpResponse()
- response['X-Accel-Redirect'] = filename
+ storage_class = default_storage.__class__.__name__
+ if storage_class == 'FileSystemStorage':
+ file_path = default_storage.path(filename)
+ if not default_storage.exists(filename):
+ raise Http404
+ if settings.DEBUG:
+ # Serve it ourselves in debug mode only
+ wrapper = FileWrapper(file(file_path))
+ response = HttpResponse(wrapper)
+ else:
+ # Set sendfile headers
+ response['X-Sendfile'] = file_path # apache
+ response['X-Accel-Redirect'] = file_path # nginx
+ response = HttpResponse()
+ file_type = mimetypes.guess_type(filename)[0]
+ response['Content-Type'] = file_type
+ response['Content-Length'] = path.getsize(file_path)
+ if file_type is None:
+ response['Content-Disposition'] = "attachment; filename=%s;" % (
+ path.basename(filename))
+ return response
else:
- wrapper = FileWrapper(file(filename))
- response = HttpResponse(wrapper)
- file_type = mimetypes.guess_type(filename)[0]
- response['Content-Type'] = file_type
- response['Content-Length'] = path.getsize(filename)
- if file_type is None:
- response['Content-Disposition'] = "attachment; filename=%s;" % (
- path.basename(filename))
- return response
+ # Other storages we'll use the url attribute
+ try:
+ url = default_storage.url(filename)
+ return HttpResponseRedirect(url)
+ except Exception as e:
+ raise e # Http404
def logout_view(request):
diff --git a/views/visualizations.py b/gedgo/views/visualizations.py
similarity index 100%
rename from views/visualizations.py
rename to gedgo/views/visualizations.py
diff --git a/manage.py b/manage.py
new file mode 100644
index 0000000..f9726f9
--- /dev/null
+++ b/manage.py
@@ -0,0 +1,10 @@
+#!/usr/bin/env python
+import os
+import sys
+
+if __name__ == "__main__":
+ 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/migrations/0001_initial.py b/migrations/0001_initial.py
deleted file mode 100644
index 773b5f0..0000000
--- a/migrations/0001_initial.py
+++ /dev/null
@@ -1,399 +0,0 @@
-# -*- coding: utf-8 -*-
-# flake8: noqa
-
-from south.db import db
-from south.v2 import SchemaMigration
-from django.db import models
-
-
-class Migration(SchemaMigration):
-
- def forwards(self, orm):
- # Adding model 'Document'
- db.create_table('gedgo_document', (
- ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
- ('title', self.gf('django.db.models.fields.CharField')(max_length=40, null=True, blank=True)),
- ('description', self.gf('django.db.models.fields.TextField')(null=True, blank=True)),
- ('docfile', self.gf('django.db.models.fields.files.FileField')(max_length=100)),
- ('thumb', self.gf('django.db.models.fields.files.FileField')(max_length=100, null=True, blank=True)),
- ('kind', self.gf('django.db.models.fields.CharField')(max_length=5)),
- ('last_updated', self.gf('django.db.models.fields.DateTimeField')(auto_now_add=True, blank=True)),
- ('gedcom', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['gedgo.Gedcom'], null=True, blank=True)),
- ))
- db.send_create_signal('gedgo', ['Document'])
-
- # Adding M2M table for field tagged_people on 'Document'
- m2m_table_name = db.shorten_name('gedgo_document_tagged_people')
- db.create_table(m2m_table_name, (
- ('id', models.AutoField(verbose_name='ID', primary_key=True, auto_created=True)),
- ('document', models.ForeignKey(orm['gedgo.document'], null=False)),
- ('person', models.ForeignKey(orm['gedgo.person'], null=False))
- ))
- db.create_unique(m2m_table_name, ['document_id', 'person_id'])
-
- # Adding M2M table for field tagged_families on 'Document'
- m2m_table_name = db.shorten_name('gedgo_document_tagged_families')
- db.create_table(m2m_table_name, (
- ('id', models.AutoField(verbose_name='ID', primary_key=True, auto_created=True)),
- ('document', models.ForeignKey(orm['gedgo.document'], null=False)),
- ('family', models.ForeignKey(orm['gedgo.family'], null=False))
- ))
- db.create_unique(m2m_table_name, ['document_id', 'family_id'])
-
- # Adding model 'Gedcom'
- db.create_table('gedgo_gedcom', (
- ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
- ('file_name', self.gf('django.db.models.fields.CharField')(max_length=40, null=True, blank=True)),
- ('title', self.gf('django.db.models.fields.CharField')(max_length=40, null=True, blank=True)),
- ('description', self.gf('django.db.models.fields.TextField')(null=True, blank=True)),
- ('last_updated', self.gf('django.db.models.fields.DateTimeField')()),
- ))
- db.send_create_signal('gedgo', ['Gedcom'])
-
- # Adding M2M table for field key_people on 'Gedcom'
- m2m_table_name = db.shorten_name('gedgo_gedcom_key_people')
- db.create_table(m2m_table_name, (
- ('id', models.AutoField(verbose_name='ID', primary_key=True, auto_created=True)),
- ('gedcom', models.ForeignKey(orm['gedgo.gedcom'], null=False)),
- ('person', models.ForeignKey(orm['gedgo.person'], null=False))
- ))
- db.create_unique(m2m_table_name, ['gedcom_id', 'person_id'])
-
- # Adding M2M table for field key_families on 'Gedcom'
- m2m_table_name = db.shorten_name('gedgo_gedcom_key_families')
- db.create_table(m2m_table_name, (
- ('id', models.AutoField(verbose_name='ID', primary_key=True, auto_created=True)),
- ('gedcom', models.ForeignKey(orm['gedgo.gedcom'], null=False)),
- ('family', models.ForeignKey(orm['gedgo.family'], null=False))
- ))
- db.create_unique(m2m_table_name, ['gedcom_id', 'family_id'])
-
- # Adding model 'Documentary'
- db.create_table('gedgo_documentary', (
- ('title', self.gf('django.db.models.fields.CharField')(max_length=100, primary_key=True)),
- ('tagline', self.gf('django.db.models.fields.CharField')(max_length=100)),
- ('location', self.gf('django.db.models.fields.CharField')(max_length=100, null=True, blank=True)),
- ('thumb', self.gf('django.db.models.fields.related.ForeignKey')(related_name='documentaries_thumb', blank=True, to=orm['gedgo.Document'])),
- ('description', self.gf('django.db.models.fields.TextField')(null=True, blank=True)),
- ('gedcom', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['gedgo.Gedcom'])),
- ('last_updated', self.gf('django.db.models.fields.DateTimeField')(auto_now_add=True, blank=True)),
- ))
- db.send_create_signal('gedgo', ['Documentary'])
-
- # Adding M2M table for field tagged_people on 'Documentary'
- m2m_table_name = db.shorten_name('gedgo_documentary_tagged_people')
- db.create_table(m2m_table_name, (
- ('id', models.AutoField(verbose_name='ID', primary_key=True, auto_created=True)),
- ('documentary', models.ForeignKey(orm['gedgo.documentary'], null=False)),
- ('person', models.ForeignKey(orm['gedgo.person'], null=False))
- ))
- db.create_unique(m2m_table_name, ['documentary_id', 'person_id'])
-
- # Adding M2M table for field tagged_families on 'Documentary'
- m2m_table_name = db.shorten_name('gedgo_documentary_tagged_families')
- db.create_table(m2m_table_name, (
- ('id', models.AutoField(verbose_name='ID', primary_key=True, auto_created=True)),
- ('documentary', models.ForeignKey(orm['gedgo.documentary'], null=False)),
- ('family', models.ForeignKey(orm['gedgo.family'], null=False))
- ))
- db.create_unique(m2m_table_name, ['documentary_id', 'family_id'])
-
- # Adding model 'Person'
- db.create_table('gedgo_person', (
- ('pointer', self.gf('django.db.models.fields.CharField')(max_length=10, primary_key=True)),
- ('gedcom', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['gedgo.Gedcom'])),
- ('first_name', self.gf('django.db.models.fields.CharField')(max_length=255)),
- ('last_name', self.gf('django.db.models.fields.CharField')(max_length=255)),
- ('prefix', self.gf('django.db.models.fields.CharField')(max_length=255)),
- ('suffix', self.gf('django.db.models.fields.CharField')(max_length=255)),
- ('birth', self.gf('django.db.models.fields.related.ForeignKey')(blank=True, related_name='person_birth', null=True, to=orm['gedgo.Event'])),
- ('death', self.gf('django.db.models.fields.related.ForeignKey')(blank=True, related_name='person_death', null=True, to=orm['gedgo.Event'])),
- ('education', self.gf('django.db.models.fields.TextField')(null=True)),
- ('religion', self.gf('django.db.models.fields.CharField')(max_length=255, null=True, blank=True)),
- ('child_family', self.gf('django.db.models.fields.related.ForeignKey')(blank=True, related_name='person_child_family', null=True, to=orm['gedgo.Family'])),
- ))
- db.send_create_signal('gedgo', ['Person'])
-
- # Adding M2M table for field spousal_families on 'Person'
- m2m_table_name = db.shorten_name('gedgo_person_spousal_families')
- db.create_table(m2m_table_name, (
- ('id', models.AutoField(verbose_name='ID', primary_key=True, auto_created=True)),
- ('person', models.ForeignKey(orm['gedgo.person'], null=False)),
- ('family', models.ForeignKey(orm['gedgo.family'], null=False))
- ))
- db.create_unique(m2m_table_name, ['person_id', 'family_id'])
-
- # Adding M2M table for field notes on 'Person'
- m2m_table_name = db.shorten_name('gedgo_person_notes')
- db.create_table(m2m_table_name, (
- ('id', models.AutoField(verbose_name='ID', primary_key=True, auto_created=True)),
- ('person', models.ForeignKey(orm['gedgo.person'], null=False)),
- ('note', models.ForeignKey(orm['gedgo.note'], null=False))
- ))
- db.create_unique(m2m_table_name, ['person_id', 'note_id'])
-
- # Adding M2M table for field profile on 'Person'
- m2m_table_name = db.shorten_name('gedgo_person_profile')
- db.create_table(m2m_table_name, (
- ('id', models.AutoField(verbose_name='ID', primary_key=True, auto_created=True)),
- ('person', models.ForeignKey(orm['gedgo.person'], null=False)),
- ('document', models.ForeignKey(orm['gedgo.document'], null=False))
- ))
- db.create_unique(m2m_table_name, ['person_id', 'document_id'])
-
- # Adding model 'Family'
- db.create_table('gedgo_family', (
- ('pointer', self.gf('django.db.models.fields.CharField')(max_length=10, primary_key=True)),
- ('gedcom', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['gedgo.Gedcom'])),
- ('kind', self.gf('django.db.models.fields.CharField')(max_length=10, null=True, blank=True)),
- ('joined', self.gf('django.db.models.fields.related.ForeignKey')(blank=True, related_name='family_joined', null=True, to=orm['gedgo.Event'])),
- ('separated', self.gf('django.db.models.fields.related.ForeignKey')(blank=True, related_name='family_separated', null=True, to=orm['gedgo.Event'])),
- ))
- db.send_create_signal('gedgo', ['Family'])
-
- # Adding M2M table for field husbands on 'Family'
- m2m_table_name = db.shorten_name('gedgo_family_husbands')
- db.create_table(m2m_table_name, (
- ('id', models.AutoField(verbose_name='ID', primary_key=True, auto_created=True)),
- ('family', models.ForeignKey(orm['gedgo.family'], null=False)),
- ('person', models.ForeignKey(orm['gedgo.person'], null=False))
- ))
- db.create_unique(m2m_table_name, ['family_id', 'person_id'])
-
- # Adding M2M table for field wives on 'Family'
- m2m_table_name = db.shorten_name('gedgo_family_wives')
- db.create_table(m2m_table_name, (
- ('id', models.AutoField(verbose_name='ID', primary_key=True, auto_created=True)),
- ('family', models.ForeignKey(orm['gedgo.family'], null=False)),
- ('person', models.ForeignKey(orm['gedgo.person'], null=False))
- ))
- db.create_unique(m2m_table_name, ['family_id', 'person_id'])
-
- # Adding M2M table for field children on 'Family'
- m2m_table_name = db.shorten_name('gedgo_family_children')
- db.create_table(m2m_table_name, (
- ('id', models.AutoField(verbose_name='ID', primary_key=True, auto_created=True)),
- ('family', models.ForeignKey(orm['gedgo.family'], null=False)),
- ('person', models.ForeignKey(orm['gedgo.person'], null=False))
- ))
- db.create_unique(m2m_table_name, ['family_id', 'person_id'])
-
- # Adding M2M table for field notes on 'Family'
- m2m_table_name = db.shorten_name('gedgo_family_notes')
- db.create_table(m2m_table_name, (
- ('id', models.AutoField(verbose_name='ID', primary_key=True, auto_created=True)),
- ('family', models.ForeignKey(orm['gedgo.family'], null=False)),
- ('note', models.ForeignKey(orm['gedgo.note'], null=False))
- ))
- db.create_unique(m2m_table_name, ['family_id', 'note_id'])
-
- # Adding model 'Event'
- db.create_table('gedgo_event', (
- ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
- ('date', self.gf('django.db.models.fields.DateField')(null=True)),
- ('year_range_end', self.gf('django.db.models.fields.IntegerField')(null=True)),
- ('date_format', self.gf('django.db.models.fields.CharField')(max_length=10, null=True)),
- ('date_approxQ', self.gf('django.db.models.fields.BooleanField')(default=False)),
- ('gedcom', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['gedgo.Gedcom'])),
- ('place', self.gf('django.db.models.fields.CharField')(max_length=50)),
- ))
- db.send_create_signal('gedgo', ['Event'])
-
- # Adding model 'Note'
- db.create_table('gedgo_note', (
- ('pointer', self.gf('django.db.models.fields.CharField')(max_length=10, primary_key=True)),
- ('text', self.gf('django.db.models.fields.TextField')()),
- ('gedcom', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['gedgo.Gedcom'])),
- ))
- db.send_create_signal('gedgo', ['Note'])
-
- # Adding model 'BlogPost'
- db.create_table('gedgo_blogpost', (
- ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
- ('title', self.gf('django.db.models.fields.CharField')(max_length=60)),
- ('body', self.gf('django.db.models.fields.TextField')()),
- ('created', self.gf('django.db.models.fields.DateTimeField')(auto_now_add=True, blank=True)),
- ))
- db.send_create_signal('gedgo', ['BlogPost'])
-
- # Adding M2M table for field tagged_photos on 'BlogPost'
- m2m_table_name = db.shorten_name('gedgo_blogpost_tagged_photos')
- db.create_table(m2m_table_name, (
- ('id', models.AutoField(verbose_name='ID', primary_key=True, auto_created=True)),
- ('blogpost', models.ForeignKey(orm['gedgo.blogpost'], null=False)),
- ('document', models.ForeignKey(orm['gedgo.document'], null=False))
- ))
- db.create_unique(m2m_table_name, ['blogpost_id', 'document_id'])
-
- # Adding M2M table for field tagged_people on 'BlogPost'
- m2m_table_name = db.shorten_name('gedgo_blogpost_tagged_people')
- db.create_table(m2m_table_name, (
- ('id', models.AutoField(verbose_name='ID', primary_key=True, auto_created=True)),
- ('blogpost', models.ForeignKey(orm['gedgo.blogpost'], null=False)),
- ('person', models.ForeignKey(orm['gedgo.person'], null=False))
- ))
- db.create_unique(m2m_table_name, ['blogpost_id', 'person_id'])
-
- def backwards(self, orm):
- # Deleting model 'Document'
- db.delete_table('gedgo_document')
-
- # Removing M2M table for field tagged_people on 'Document'
- db.delete_table(db.shorten_name('gedgo_document_tagged_people'))
-
- # Removing M2M table for field tagged_families on 'Document'
- db.delete_table(db.shorten_name('gedgo_document_tagged_families'))
-
- # Deleting model 'Gedcom'
- db.delete_table('gedgo_gedcom')
-
- # Removing M2M table for field key_people on 'Gedcom'
- db.delete_table(db.shorten_name('gedgo_gedcom_key_people'))
-
- # Removing M2M table for field key_families on 'Gedcom'
- db.delete_table(db.shorten_name('gedgo_gedcom_key_families'))
-
- # Deleting model 'Documentary'
- db.delete_table('gedgo_documentary')
-
- # Removing M2M table for field tagged_people on 'Documentary'
- db.delete_table(db.shorten_name('gedgo_documentary_tagged_people'))
-
- # Removing M2M table for field tagged_families on 'Documentary'
- db.delete_table(db.shorten_name('gedgo_documentary_tagged_families'))
-
- # Deleting model 'Person'
- db.delete_table('gedgo_person')
-
- # Removing M2M table for field spousal_families on 'Person'
- db.delete_table(db.shorten_name('gedgo_person_spousal_families'))
-
- # Removing M2M table for field notes on 'Person'
- db.delete_table(db.shorten_name('gedgo_person_notes'))
-
- # Removing M2M table for field profile on 'Person'
- db.delete_table(db.shorten_name('gedgo_person_profile'))
-
- # Deleting model 'Family'
- db.delete_table('gedgo_family')
-
- # Removing M2M table for field husbands on 'Family'
- db.delete_table(db.shorten_name('gedgo_family_husbands'))
-
- # Removing M2M table for field wives on 'Family'
- db.delete_table(db.shorten_name('gedgo_family_wives'))
-
- # Removing M2M table for field children on 'Family'
- db.delete_table(db.shorten_name('gedgo_family_children'))
-
- # Removing M2M table for field notes on 'Family'
- db.delete_table(db.shorten_name('gedgo_family_notes'))
-
- # Deleting model 'Event'
- db.delete_table('gedgo_event')
-
- # Deleting model 'Note'
- db.delete_table('gedgo_note')
-
- # Deleting model 'BlogPost'
- db.delete_table('gedgo_blogpost')
-
- # Removing M2M table for field tagged_photos on 'BlogPost'
- db.delete_table(db.shorten_name('gedgo_blogpost_tagged_photos'))
-
- # Removing M2M table for field tagged_people on 'BlogPost'
- db.delete_table(db.shorten_name('gedgo_blogpost_tagged_people'))
-
- models = {
- 'gedgo.blogpost': {
- 'Meta': {'object_name': 'BlogPost'},
- 'body': ('django.db.models.fields.TextField', [], {}),
- 'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
- 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
- 'tagged_people': ('django.db.models.fields.related.ManyToManyField', [], {'blank': 'True', 'related_name': "'blogpost_tagged_people'", 'null': 'True', 'symmetrical': 'False', 'to': "orm['gedgo.Person']"}),
- 'tagged_photos': ('django.db.models.fields.related.ManyToManyField', [], {'blank': 'True', 'related_name': "'blogpost_tagged_photos'", 'null': 'True', 'symmetrical': 'False', 'to': "orm['gedgo.Document']"}),
- 'title': ('django.db.models.fields.CharField', [], {'max_length': '60'})
- },
- 'gedgo.document': {
- 'Meta': {'object_name': 'Document'},
- 'description': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
- 'docfile': ('django.db.models.fields.files.FileField', [], {'max_length': '100'}),
- 'gedcom': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['gedgo.Gedcom']", 'null': 'True', 'blank': 'True'}),
- 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
- 'kind': ('django.db.models.fields.CharField', [], {'max_length': '5'}),
- 'last_updated': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
- 'tagged_families': ('django.db.models.fields.related.ManyToManyField', [], {'blank': 'True', 'related_name': "'media_tagged_families'", 'null': 'True', 'symmetrical': 'False', 'to': "orm['gedgo.Family']"}),
- 'tagged_people': ('django.db.models.fields.related.ManyToManyField', [], {'blank': 'True', 'related_name': "'media_tagged_people'", 'null': 'True', 'symmetrical': 'False', 'to': "orm['gedgo.Person']"}),
- 'thumb': ('django.db.models.fields.files.FileField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}),
- 'title': ('django.db.models.fields.CharField', [], {'max_length': '40', 'null': 'True', 'blank': 'True'})
- },
- 'gedgo.documentary': {
- 'Meta': {'object_name': 'Documentary'},
- 'description': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
- 'gedcom': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['gedgo.Gedcom']"}),
- 'last_updated': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
- 'location': ('django.db.models.fields.CharField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}),
- 'tagged_families': ('django.db.models.fields.related.ManyToManyField', [], {'blank': 'True', 'related_name': "'documentaries_tagged_families'", 'null': 'True', 'symmetrical': 'False', 'to': "orm['gedgo.Family']"}),
- 'tagged_people': ('django.db.models.fields.related.ManyToManyField', [], {'blank': 'True', 'related_name': "'documentaries_tagged_people'", 'null': 'True', 'symmetrical': 'False', 'to': "orm['gedgo.Person']"}),
- 'tagline': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
- 'thumb': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'documentaries_thumb'", 'blank': 'True', 'to': "orm['gedgo.Document']"}),
- 'title': ('django.db.models.fields.CharField', [], {'max_length': '100', 'primary_key': 'True'})
- },
- 'gedgo.event': {
- 'Meta': {'object_name': 'Event'},
- 'date': ('django.db.models.fields.DateField', [], {'null': 'True'}),
- 'date_approxQ': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
- 'date_format': ('django.db.models.fields.CharField', [], {'max_length': '10', 'null': 'True'}),
- 'gedcom': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['gedgo.Gedcom']"}),
- 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
- 'place': ('django.db.models.fields.CharField', [], {'max_length': '50'}),
- 'year_range_end': ('django.db.models.fields.IntegerField', [], {'null': 'True'})
- },
- 'gedgo.family': {
- 'Meta': {'object_name': 'Family'},
- 'children': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'family_children'", 'symmetrical': 'False', 'to': "orm['gedgo.Person']"}),
- 'gedcom': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['gedgo.Gedcom']"}),
- 'husbands': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'family_husbands'", 'symmetrical': 'False', 'to': "orm['gedgo.Person']"}),
- 'joined': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'family_joined'", 'null': 'True', 'to': "orm['gedgo.Event']"}),
- 'kind': ('django.db.models.fields.CharField', [], {'max_length': '10', 'null': 'True', 'blank': 'True'}),
- 'notes': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['gedgo.Note']", 'null': 'True', 'symmetrical': 'False'}),
- 'pointer': ('django.db.models.fields.CharField', [], {'max_length': '10', 'primary_key': 'True'}),
- 'separated': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'family_separated'", 'null': 'True', 'to': "orm['gedgo.Event']"}),
- 'wives': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'family_wives'", 'symmetrical': 'False', 'to': "orm['gedgo.Person']"})
- },
- 'gedgo.gedcom': {
- 'Meta': {'object_name': 'Gedcom'},
- 'description': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
- 'file_name': ('django.db.models.fields.CharField', [], {'max_length': '40', 'null': 'True', 'blank': 'True'}),
- 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
- 'key_families': ('django.db.models.fields.related.ManyToManyField', [], {'blank': 'True', 'related_name': "'gedcom_key_families'", 'null': 'True', 'symmetrical': 'False', 'to': "orm['gedgo.Family']"}),
- 'key_people': ('django.db.models.fields.related.ManyToManyField', [], {'blank': 'True', 'related_name': "'gedcom_key_people'", 'null': 'True', 'symmetrical': 'False', 'to': "orm['gedgo.Person']"}),
- 'last_updated': ('django.db.models.fields.DateTimeField', [], {}),
- 'title': ('django.db.models.fields.CharField', [], {'max_length': '40', 'null': 'True', 'blank': 'True'})
- },
- 'gedgo.note': {
- 'Meta': {'object_name': 'Note'},
- 'gedcom': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['gedgo.Gedcom']"}),
- 'pointer': ('django.db.models.fields.CharField', [], {'max_length': '10', 'primary_key': 'True'}),
- 'text': ('django.db.models.fields.TextField', [], {})
- },
- 'gedgo.person': {
- 'Meta': {'object_name': 'Person'},
- 'birth': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'person_birth'", 'null': 'True', 'to': "orm['gedgo.Event']"}),
- 'child_family': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'person_child_family'", 'null': 'True', 'to': "orm['gedgo.Family']"}),
- 'death': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'person_death'", 'null': 'True', 'to': "orm['gedgo.Event']"}),
- 'education': ('django.db.models.fields.TextField', [], {'null': 'True'}),
- 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
- 'gedcom': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['gedgo.Gedcom']"}),
- 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
- 'notes': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['gedgo.Note']", 'null': 'True', 'symmetrical': 'False'}),
- 'pointer': ('django.db.models.fields.CharField', [], {'max_length': '10', 'primary_key': 'True'}),
- 'prefix': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
- 'profile': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'to': "orm['gedgo.Document']", 'null': 'True', 'blank': 'True'}),
- 'religion': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}),
- 'spousal_families': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'person_spousal_families'", 'symmetrical': 'False', 'to': "orm['gedgo.Family']"}),
- 'suffix': ('django.db.models.fields.CharField', [], {'max_length': '255'})
- }
- }
-
- complete_apps = ['gedgo']
diff --git a/reqs.pip b/reqs.pip
index 301490d..dfa08f7 100644
--- a/reqs.pip
+++ b/reqs.pip
@@ -1,8 +1,7 @@
-django
-django-celery
-South
-django-tastypie
-pillow
+django==1.9.2
+django-celery==3.1.17
+pillow==3.1.1
+dropbox
mysql-python
redis
flake8
diff --git a/settings.py b/settings.py
new file mode 100644
index 0000000..c8c58f7
--- /dev/null
+++ b/settings.py
@@ -0,0 +1,139 @@
+import os
+project_root = os.path.dirname(__file__)
+# Django settings for gedgo project.
+
+DEBUG = True
+
+ADMINS = ()
+
+MANAGERS = ADMINS
+
+DATABASES = {
+ 'default': {
+ 'ENGINE': 'django.db.backends.mysql',
+ 'NAME': 'gedgo',
+ 'USER': 'gedgo',
+ 'PASSWORD': 'gedgo',
+ 'HOST': 'db',
+ 'PORT': '',
+ }
+}
+
+ALLOWED_HOSTS = []
+TIME_ZONE = 'America/New_York'
+LANGUAGE_CODE = 'en-us'
+
+SITE_ID = 1
+USE_I18N = True
+USE_L10N = True
+USE_TZ = True
+
+MEDIA_ROOT = '/src/.files/'
+MEDIA_URL = '/gedgo/media/'
+
+STATIC_ROOT = ''
+STATIC_URL = '/static/'
+
+STATICFILES_FINDERS = (
+ 'django.contrib.staticfiles.finders.FileSystemFinder',
+ 'django.contrib.staticfiles.finders.AppDirectoriesFinder',
+)
+
+SECRET_KEY = 'not_a_secret'
+
+TEMPLATES = [
+ {
+ 'BACKEND': 'django.template.backends.django.DjangoTemplates',
+ 'DIRS': [
+ os.path.join(project_root, 'gedgo/templates'),
+ os.path.join(project_root, 'gedgo/templates/default'),
+ ],
+ 'APP_DIRS': True,
+ 'OPTIONS': {
+ 'context_processors': [
+ # Insert your TEMPLATE_CONTEXT_PROCESSORS here or use this
+ # list if you haven't customized them:
+ 'django.contrib.auth.context_processors.auth',
+ 'django.template.context_processors.debug',
+ 'django.template.context_processors.i18n',
+ 'django.template.context_processors.media',
+ 'django.template.context_processors.static',
+ 'django.template.context_processors.tz',
+ 'django.contrib.messages.context_processors.messages',
+ ],
+ },
+ },
+]
+
+
+MIDDLEWARE_CLASSES = (
+ 'django.middleware.common.CommonMiddleware',
+ 'django.contrib.sessions.middleware.SessionMiddleware',
+ 'django.middleware.csrf.CsrfViewMiddleware',
+ 'django.contrib.auth.middleware.AuthenticationMiddleware',
+ 'django.contrib.messages.middleware.MessageMiddleware',
+ # Uncomment the next line for simple clickjacking protection:
+ # 'django.middleware.clickjacking.XFrameOptionsMiddleware',
+)
+
+ROOT_URLCONF = 'urls'
+# WSGI_APPLICATION = 'wsgi.application'
+
+
+INSTALLED_APPS = (
+ 'django.contrib.auth',
+ 'django.contrib.contenttypes',
+ 'django.contrib.sessions',
+ 'django.contrib.sites',
+ 'django.contrib.messages',
+ 'django.contrib.staticfiles',
+ 'djcelery',
+ 'django.contrib.admin',
+ 'gedgo'
+)
+
+MESSAGE_STORAGE = 'django.contrib.messages.storage.cookie.CookieStorage'
+
+# Just send emails to the console.
+EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend'
+SERVER_EMAIL = ['noreply@example.com']
+
+GEDGO_SITE_TITLE = 'My Genealogy Site'
+GEDGO_REDIS_SERVER = 'redis'
+
+BROKER_BACKEND = 'redis'
+BROKER_URL = 'redis://redis:6379/0'
+CELERY_RESULT_BACKEND = 'redis://redis:6379/0'
+CELERY_ACCEPT_CONTENT = ["json"]
+
+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,
+ },
+ }
+}
+
+try:
+ from settings_local import * # noqa
+except ImportError:
+ pass
+
+import djcelery
+djcelery.setup_loader()
diff --git a/static/test/test.ged b/static/test/test.ged
deleted file mode 100644
index 8a9ebaf..0000000
--- a/static/test/test.ged
+++ /dev/null
@@ -1,80 +0,0 @@
-0 HEAD
-1 SOUR Test
-2 VERS V9.0
-1 DEST Test
-1 DATE 21 JUN 2012
-1 TITL Test Gedcom
-1 FILE Test
-1 GEDC
-2 VERS 5.5
-1 CHAR UTF-8
-0 @I1@ INDI
-1 NAME John /Doe/
-1 SEX M
-1 BIRT
-2 DATE 22 MAR 1950
-2 PLAC Houston, Texas
-1 _CONTACT
-2 TYPE home
-2 ADDR Paris, France
-1 NOTE @N1@
-1 FAMC @F2@
-1 FAMS @F1@
-1 CHAN
-2 DATE 5 JUL 2004
-0 @I2@ INDI
-1 NAME Jill /Jillian/
-1 SEX F
-1 BIRT
-2 DATE 8 JUN 1952
-2 PLAC Honolulu, Hawaii
-1 FAMS @F1@
-0 @I3@ INDI
-1 NAME John /Doe/
-1 NSFX , Jr.
-1 SEX M
-1 BIRT
-2 DATE 10 MAR 1984
-2 PLAC Arlington, Virgina
-1 FAMC @F19@
-0 @I4@ INDI
-1 NAME Jane /Doe/
-1 SEX F
-1 BIRT
-2 DATE 3 NOV 1986
-2 PLAC Arlington, Virginia
-1 FAMC @F1@
-0 @I5@ INDI
-1 NAME Smith /Joe/
-1 SEX M
-1 BIRT
-2 DATE 10 MAY 1945
-2 PLAC Mount Plesant, Titus, Texas
-1 DEAT
-2 DATE 7 FEB 1987
-2 PLAC Fort Worth, Tarrant, Texas
-1 FAMS @F2@
-0 @I6@ INDI
-1 NAME Jayda /Doe/
-1 SEX F
-1 BIRT
-2 DATE BET. 1946 1953
-2 PLAC Fort Worth, Tarrant, Texas
-1 FAMC @F2@
-0 @F1@ FAM
-1 HUSB @I1@
-1 WIFE @I2@
-1 MARR
-2 DATE 7 JUN 1972
-2 PLAC The Moon
-1 CHIL @I3@
-1 CHIL @I4@
-0 @F2@ FAM
-1 HUSB @I5@
-1 CHIL @I1@
-1 CHIL @I6@
-0 @N1@ NOTE
-1 CONT John Doe is an American Musician, known for the bop, the beep, and the Whoa Nelly. He incorporated elements of jazz, ja
-1 CONC xx and trip-hop to form an influential style. He garnered a large following, including notable musicians such as Cab
-1 CONC Calloway and Tribe Called Quest's Q-Tip. [Citation Needed]
-0 TRLR
diff --git a/urls.py b/urls.py
index 3ec1f6d..10c6c96 100644
--- a/urls.py
+++ b/urls.py
@@ -1,62 +1,21 @@
-from django.conf.urls import patterns, url
-from django.conf.urls import include
+from django.conf.urls import include, url
from django.shortcuts import redirect
-from tastypie.api import Api
-from gedgo.api import PersonResource, FamilyResource
-
-from gedgo import views
-
-v1_api = Api(api_name='v1')
-v1_api.register(PersonResource())
-v1_api.register(FamilyResource())
-
-urlpatterns = patterns(
- '',
- url(
- r'^(?P\d+)/(?PI\d+)/$',
- views.person,
- name='person'
- ),
- url(r'^(?P\d+)/$', views.gedcom, name='gedcom'),
-
- # XHR Data views
- url(r'^(?P\d+)/pedigree/(?PI\d+)/$', views.pedigree),
- url(r'^(?P\d+)/timeline/(?PI\d+)/$', views.timeline),
- url(r'^dashboard/worker/status$', views.worker_status),
-
- url(r'^blog/$', views.blog_list),
- url(r'^blog/(?P\d+)/(?P\d+)/$', views.blog),
- url(r'^blog/post/(?P\d+)/$', views.blogpost),
- url(r'^documentaries/$', views.documentaries),
- url(r'^research/(?P.*)$', views.research),
- url(r'^api/', include(v1_api.urls)),
- url(r'^search/$', views.search),
- url(r'^dashboard/$', views.dashboard),
- url(r'^dashboard/user/(?P\d+)/$', views.user_tracking),
-
- # Auth
- url(r'^logout/$', views.logout_view),
- url(r'^password_reset/$',
- 'django.contrib.auth.views.password_reset',
- {
- 'template_name': 'auth/login.html',
- 'email_template_name': 'auth/password_reset_email.html',
- 'post_reset_redirect': '/gedgo/password_reset/done/'
- }),
- url(r'^password_reset/done/$',
- 'django.contrib.auth.views.password_reset_done',
- {
- 'template_name': 'auth/password_reset_done.html'
- }),
- url(r'^password_reset/(?P[0-9A-Za-z]+)-(?P.+)/$',
- 'django.contrib.auth.views.password_reset_confirm',
- {
- 'post_reset_redirect': '/',
- 'template_name': 'auth/password_reset_confirm.html'
- }),
-
- # Backup media fileserve view
- url(r'^media/(?P.*)$', views.media),
-
- url(r'^$', lambda r: redirect('/gedgo/1/')),
-)
+from django.http import HttpResponse
+from django.contrib import admin
+from django.contrib.auth.views import login
+
+admin.autodiscover()
+
+urlpatterns = [
+ url(r'^$', lambda r: redirect('/gedgo/')),
+ url(r'^gedgo/', include('gedgo.urls')),
+ url(r'^admin/', include(admin.site.urls)),
+ url(r'^accounts/login/$', login,
+ {'template_name': 'auth/login.html'}),
+ url(r'^login/$', login,
+ {'template_name': 'auth/login.html'}),
+ url(r'^robots\.txt$',
+ lambda r: HttpResponse(
+ "User-agent: *\nDisallow: /",
+ mimetype="text/plain"))
+]
diff --git a/views/research.py b/views/research.py
deleted file mode 100644
index f95718b..0000000
--- a/views/research.py
+++ /dev/null
@@ -1,79 +0,0 @@
-from django.conf import settings
-from django.http import Http404
-from django.contrib.auth.decorators import login_required
-
-from os import path
-from os import listdir
-import mimetypes
-
-from gedgo.views.util import serve_content, render
-
-# glyphicon name mappings
-MIMETYPE_MAPPING = {
- 'video': 'facetime-video',
- 'audio': 'volume-up',
- 'image': 'picture'
-}
-
-
-@login_required
-def research(request, pathname):
- try:
- root = path.abspath(settings.RESEARCH_FILES_ROOT)
- except:
- raise Http404
-
- # Force join the path with the research root to prevent serving
- # private files.
- pathname = pathname.strip('/')
- r = path.join(root, pathname)
-
- # Don't allow relative path locations outside of the root.
- if '..' in pathname:
- raise Http404
-
- # Serve the content through xsendfile or directly.
- if path.isfile(r):
- return serve_content(r)
-
- elif path.isdir(r) and '.' not in pathname:
- # List the contents of the directory
- contents = [
- (_get_type(r, c), c, _normalize('%s/%s' % (pathname, c)))
- for c in listdir(r) if not c.startswith('.')
- ]
-
- # Build a depth tree of the directories above this one for navigation
- levels = [('Research Files', '')]
- if pathname:
- lp = ''
- for l in pathname.split('/'):
- lp = _normalize('%s/%s' % (lp, l))
- levels.append((l, lp))
-
- return render(
- request,
- 'research.html',
- {
- 'contents': contents,
- 'levels': levels
- }
- )
- else:
- raise Http404
-
-
-def _normalize(p):
- p = path.normpath(p)
- if not p.startswith('/'):
- p = '/' + p
- return p
-
-
-def _get_type(r, c):
- if path.isdir(path.join(r, c)):
- return 'folder-open'
- guess, _ = mimetypes.guess_type(c)
- if guess and guess.split('/')[0] in ['audio', 'video', 'image']:
- return MIMETYPE_MAPPING[guess.split('/')[0]]
- return 'file'