From 15db2c947ed339a570e221176b95dc700ce1c2d2 Mon Sep 17 00:00:00 2001
From: cucc
Date: Wed, 13 May 2009 08:08:37 +0200
Subject: [PATCH] [svn r8345]
---
troggle/__init__.py | 0
troggle/alwaysUseRequestContext.py | 8 -
troggle/databaseReset.py | 58 -
troggle/expo/__init__.py | 0
troggle/expo/admin.py | 93 -
troggle/expo/context.py | 4 -
troggle/expo/fileAbstraction.py | 43 -
troggle/expo/forms.py | 40 -
troggle/expo/imagekit_specs.py | 23 -
troggle/expo/models.py | 615 ---
troggle/expo/models_survex.py | 66 -
troggle/expo/randSent.py | 32 -
troggle/expo/search.py | 39 -
troggle/expo/templatetags/__init__.py | 0
troggle/expo/templatetags/survex_markup.py | 52 -
troggle/expo/templatetags/wiki_markup.py | 101 -
troggle/expo/view_surveys.py | 161 -
troggle/expo/views.py | 8 -
troggle/expo/views_caves.py | 96 -
troggle/expo/views_logbooks.py | 120 -
troggle/expo/views_other.py | 70 -
troggle/expo/views_survex.py | 44 -
troggle/export/__init__.py | 0
troggle/export/tocavetab.py | 52 -
troggle/export/tologbooks.py | 0
troggle/export/toqms.py | 37 -
troggle/imagekit/__init__.py | 13 -
troggle/imagekit/defaults.py | 21 -
troggle/imagekit/lib.py | 17 -
troggle/imagekit/management/__init__.py | 1 -
.../imagekit/management/commands/__init__.py | 1 -
.../imagekit/management/commands/ikflush.py | 38 -
troggle/imagekit/models.py | 136 -
troggle/imagekit/options.py | 23 -
troggle/imagekit/processors.py | 134 -
troggle/imagekit/specs.py | 119 -
troggle/imagekit/tests.py | 86 -
troggle/imagekit/utils.py | 15 -
troggle/localsettingsserver.py | 31 -
troggle/localsettingsubuntu.py | 20 -
troggle/localsettingswindows.py | 49 -
troggle/manage.py | 11 -
troggle/media/204plan.gif | Bin 39181 -> 0 bytes
troggle/media/SilkRoadsilouetteAndrew.png | Bin 70596 -> 0 bytes
troggle/media/css/main2.css | 339 --
troggle/media/css/main3.css | 374 --
troggle/media/css/nav.css | 12 -
troggle/media/eieshole.jpg | Bin 25220 -> 0 bytes
troggle/media/expoBanner.gif | Bin 254791 -> 0 bytes
troggle/media/goesser.jpg | Bin 61696 -> 0 bytes
troggle/media/js/base.js | 74 -
troggle/media/js/jquery.js | 4376 -----------------
troggle/media/js/jquery.quicksearch.js | 328 --
troggle/media/js/survey.js | 42 -
troggle/media/loserBanner.jpg | Bin 220305 -> 0 bytes
troggle/media/open-quote.gif | Bin 187 -> 0 bytes
troggle/media/surveyHover.gif | Bin 39482 -> 0 bytes
troggle/media/timemachine.gif | Bin 42344 -> 0 bytes
troggle/middleware.py | 49 -
troggle/parsers/QMs.py | 120 -
troggle/parsers/__init__.py | 0
troggle/parsers/cavetab.py | 314 --
troggle/parsers/logbooks.py | 346 --
troggle/parsers/people.py | 166 -
troggle/parsers/survex.py | 152 -
troggle/parsers/surveys.py | 130 -
troggle/profiles/__init__.py | 0
troggle/profiles/urls.py | 46 -
troggle/profiles/utils.py | 45 -
troggle/profiles/views.py | 363 --
troggle/registration/__init__.py | 0
troggle/registration/admin.py | 11 -
troggle/registration/forms.py | 134 -
.../locale/ar/LC_MESSAGES/django.mo | Bin 2135 -> 0 bytes
.../locale/ar/LC_MESSAGES/django.po | 81 -
.../locale/bg/LC_MESSAGES/django.mo | Bin 2302 -> 0 bytes
.../locale/bg/LC_MESSAGES/django.po | 78 -
.../locale/de/LC_MESSAGES/django.mo | Bin 1909 -> 0 bytes
.../locale/de/LC_MESSAGES/django.po | 85 -
.../locale/el/LC_MESSAGES/django.mo | Bin 2424 -> 0 bytes
.../locale/el/LC_MESSAGES/django.po | 84 -
.../locale/en/LC_MESSAGES/django.mo | Bin 367 -> 0 bytes
.../locale/en/LC_MESSAGES/django.po | 81 -
.../locale/es/LC_MESSAGES/django.mo | Bin 1909 -> 0 bytes
.../locale/es/LC_MESSAGES/django.po | 85 -
.../locale/es_AR/LC_MESSAGES/django.mo | Bin 1849 -> 0 bytes
.../locale/es_AR/LC_MESSAGES/django.po | 83 -
.../locale/fr/LC_MESSAGES/django.mo | Bin 1883 -> 0 bytes
.../locale/fr/LC_MESSAGES/django.po | 81 -
.../locale/he/LC_MESSAGES/django.mo | Bin 1896 -> 0 bytes
.../locale/he/LC_MESSAGES/django.po | 86 -
.../locale/it/LC_MESSAGES/django.mo | Bin 1864 -> 0 bytes
.../locale/it/LC_MESSAGES/django.po | 82 -
.../locale/ja/LC_MESSAGES/django.mo | Bin 2035 -> 0 bytes
.../locale/ja/LC_MESSAGES/django.po | 78 -
.../locale/nl/LC_MESSAGES/django.mo | Bin 1898 -> 0 bytes
.../locale/nl/LC_MESSAGES/django.po | 77 -
.../locale/pl/LC_MESSAGES/django.mo | Bin 1769 -> 0 bytes
.../locale/pl/LC_MESSAGES/django.po | 84 -
.../locale/pt_BR/LC_MESSAGES/django.mo | Bin 1796 -> 0 bytes
.../locale/pt_BR/LC_MESSAGES/django.po | 81 -
.../locale/ru/LC_MESSAGES/django.mo | Bin 2360 -> 0 bytes
.../locale/ru/LC_MESSAGES/django.po | 81 -
.../locale/sr/LC_MESSAGES/django.mo | Bin 1966 -> 0 bytes
.../locale/sr/LC_MESSAGES/django.po | 80 -
.../locale/sv/LC_MESSAGES/django.mo | Bin 1687 -> 0 bytes
.../locale/sv/LC_MESSAGES/django.po | 81 -
.../locale/zh_CN/LC_MESSAGES/django.mo | Bin 1669 -> 0 bytes
.../locale/zh_CN/LC_MESSAGES/django.po | 77 -
.../locale/zh_TW/LC_MESSAGES/django.mo | Bin 1669 -> 0 bytes
.../locale/zh_TW/LC_MESSAGES/django.po | 77 -
troggle/registration/management/__init__.py | 0
.../management/commands/__init__.py | 0
.../commands/cleanupregistration.py | 19 -
troggle/registration/models.py | 255 -
troggle/registration/signals.py | 8 -
troggle/registration/tests.py | 355 --
troggle/registration/urls.py | 72 -
troggle/registration/views.py | 163 -
troggle/save_carefully.py | 31 -
troggle/settings.py | 88 -
troggle/templates/admin/base_site.html | 10 -
troggle/templates/base.html | 73 -
troggle/templates/calendar.html | 76 -
troggle/templates/cave.html | 88 -
troggle/templates/cavebase.html | 28 -
troggle/templates/caveindex.html | 23 -
troggle/templates/cavesearch.html | 23 -
troggle/templates/controlPanel.html | 37 -
troggle/templates/entrance.html | 80 -
troggle/templates/expedition.html | 52 -
troggle/templates/fileupload.html | 18 -
troggle/templates/frontpage.html | 42 -
troggle/templates/index.html | 59 -
troggle/templates/listdir.html | 22 -
troggle/templates/logbookentry.html | 71 -
troggle/templates/logbooksearch.html | 21 -
troggle/templates/person.html | 39 -
troggle/templates/personForm.html | 6 -
troggle/templates/personexpedition.html | 66 -
troggle/templates/personindex.html | 43 -
.../templates/profiles/create_profile.html | 13 -
troggle/templates/profiles/edit_profile.html | 13 -
.../templates/profiles/profile_detail.html | 14 -
troggle/templates/profiles/profile_list.html | 0
.../templates/profiles/select_profile.html | 40 -
troggle/templates/qm.html | 41 -
troggle/templates/registration/activate.html | 25 -
.../registration/activation_email.txt | 10 -
.../registration/activation_email_subject.txt | 1 -
troggle/templates/registration/login.html | 19 -
troggle/templates/registration/logout.html | 4 -
.../registration/registration_activate.html | 6 -
.../registration/registration_complete.html | 13 -
.../registration/registration_form.html | 56 -
troggle/templates/statistics.html | 8 -
troggle/templates/subcave.html | 45 -
troggle/templates/survexblock.html | 47 -
troggle/templates/survey.html | 220 -
troggle/templates/svxfile.html | 19 -
troggle/templates/todo.html | 59 -
troggle/urls.py | 87 -
162 files changed, 14048 deletions(-)
delete mode 100644 troggle/__init__.py
delete mode 100644 troggle/alwaysUseRequestContext.py
delete mode 100644 troggle/databaseReset.py
delete mode 100644 troggle/expo/__init__.py
delete mode 100644 troggle/expo/admin.py
delete mode 100644 troggle/expo/context.py
delete mode 100644 troggle/expo/fileAbstraction.py
delete mode 100644 troggle/expo/forms.py
delete mode 100644 troggle/expo/imagekit_specs.py
delete mode 100644 troggle/expo/models.py
delete mode 100644 troggle/expo/models_survex.py
delete mode 100644 troggle/expo/randSent.py
delete mode 100644 troggle/expo/search.py
delete mode 100644 troggle/expo/templatetags/__init__.py
delete mode 100644 troggle/expo/templatetags/survex_markup.py
delete mode 100644 troggle/expo/templatetags/wiki_markup.py
delete mode 100644 troggle/expo/view_surveys.py
delete mode 100644 troggle/expo/views.py
delete mode 100644 troggle/expo/views_caves.py
delete mode 100644 troggle/expo/views_logbooks.py
delete mode 100644 troggle/expo/views_other.py
delete mode 100644 troggle/expo/views_survex.py
delete mode 100644 troggle/export/__init__.py
delete mode 100644 troggle/export/tocavetab.py
delete mode 100644 troggle/export/tologbooks.py
delete mode 100644 troggle/export/toqms.py
delete mode 100644 troggle/imagekit/__init__.py
delete mode 100644 troggle/imagekit/defaults.py
delete mode 100644 troggle/imagekit/lib.py
delete mode 100644 troggle/imagekit/management/__init__.py
delete mode 100644 troggle/imagekit/management/commands/__init__.py
delete mode 100644 troggle/imagekit/management/commands/ikflush.py
delete mode 100644 troggle/imagekit/models.py
delete mode 100644 troggle/imagekit/options.py
delete mode 100644 troggle/imagekit/processors.py
delete mode 100644 troggle/imagekit/specs.py
delete mode 100644 troggle/imagekit/tests.py
delete mode 100644 troggle/imagekit/utils.py
delete mode 100644 troggle/localsettingsserver.py
delete mode 100644 troggle/localsettingsubuntu.py
delete mode 100644 troggle/localsettingswindows.py
delete mode 100644 troggle/manage.py
delete mode 100644 troggle/media/204plan.gif
delete mode 100644 troggle/media/SilkRoadsilouetteAndrew.png
delete mode 100644 troggle/media/css/main2.css
delete mode 100644 troggle/media/css/main3.css
delete mode 100644 troggle/media/css/nav.css
delete mode 100644 troggle/media/eieshole.jpg
delete mode 100644 troggle/media/expoBanner.gif
delete mode 100644 troggle/media/goesser.jpg
delete mode 100644 troggle/media/js/base.js
delete mode 100644 troggle/media/js/jquery.js
delete mode 100644 troggle/media/js/jquery.quicksearch.js
delete mode 100644 troggle/media/js/survey.js
delete mode 100644 troggle/media/loserBanner.jpg
delete mode 100644 troggle/media/open-quote.gif
delete mode 100644 troggle/media/surveyHover.gif
delete mode 100644 troggle/media/timemachine.gif
delete mode 100644 troggle/middleware.py
delete mode 100644 troggle/parsers/QMs.py
delete mode 100644 troggle/parsers/__init__.py
delete mode 100644 troggle/parsers/cavetab.py
delete mode 100644 troggle/parsers/logbooks.py
delete mode 100644 troggle/parsers/people.py
delete mode 100644 troggle/parsers/survex.py
delete mode 100644 troggle/parsers/surveys.py
delete mode 100644 troggle/profiles/__init__.py
delete mode 100644 troggle/profiles/urls.py
delete mode 100644 troggle/profiles/utils.py
delete mode 100644 troggle/profiles/views.py
delete mode 100644 troggle/registration/__init__.py
delete mode 100644 troggle/registration/admin.py
delete mode 100644 troggle/registration/forms.py
delete mode 100644 troggle/registration/locale/ar/LC_MESSAGES/django.mo
delete mode 100644 troggle/registration/locale/ar/LC_MESSAGES/django.po
delete mode 100644 troggle/registration/locale/bg/LC_MESSAGES/django.mo
delete mode 100644 troggle/registration/locale/bg/LC_MESSAGES/django.po
delete mode 100644 troggle/registration/locale/de/LC_MESSAGES/django.mo
delete mode 100644 troggle/registration/locale/de/LC_MESSAGES/django.po
delete mode 100644 troggle/registration/locale/el/LC_MESSAGES/django.mo
delete mode 100644 troggle/registration/locale/el/LC_MESSAGES/django.po
delete mode 100644 troggle/registration/locale/en/LC_MESSAGES/django.mo
delete mode 100644 troggle/registration/locale/en/LC_MESSAGES/django.po
delete mode 100644 troggle/registration/locale/es/LC_MESSAGES/django.mo
delete mode 100644 troggle/registration/locale/es/LC_MESSAGES/django.po
delete mode 100644 troggle/registration/locale/es_AR/LC_MESSAGES/django.mo
delete mode 100644 troggle/registration/locale/es_AR/LC_MESSAGES/django.po
delete mode 100644 troggle/registration/locale/fr/LC_MESSAGES/django.mo
delete mode 100644 troggle/registration/locale/fr/LC_MESSAGES/django.po
delete mode 100644 troggle/registration/locale/he/LC_MESSAGES/django.mo
delete mode 100644 troggle/registration/locale/he/LC_MESSAGES/django.po
delete mode 100644 troggle/registration/locale/it/LC_MESSAGES/django.mo
delete mode 100644 troggle/registration/locale/it/LC_MESSAGES/django.po
delete mode 100644 troggle/registration/locale/ja/LC_MESSAGES/django.mo
delete mode 100644 troggle/registration/locale/ja/LC_MESSAGES/django.po
delete mode 100644 troggle/registration/locale/nl/LC_MESSAGES/django.mo
delete mode 100644 troggle/registration/locale/nl/LC_MESSAGES/django.po
delete mode 100644 troggle/registration/locale/pl/LC_MESSAGES/django.mo
delete mode 100644 troggle/registration/locale/pl/LC_MESSAGES/django.po
delete mode 100644 troggle/registration/locale/pt_BR/LC_MESSAGES/django.mo
delete mode 100644 troggle/registration/locale/pt_BR/LC_MESSAGES/django.po
delete mode 100644 troggle/registration/locale/ru/LC_MESSAGES/django.mo
delete mode 100644 troggle/registration/locale/ru/LC_MESSAGES/django.po
delete mode 100644 troggle/registration/locale/sr/LC_MESSAGES/django.mo
delete mode 100644 troggle/registration/locale/sr/LC_MESSAGES/django.po
delete mode 100644 troggle/registration/locale/sv/LC_MESSAGES/django.mo
delete mode 100644 troggle/registration/locale/sv/LC_MESSAGES/django.po
delete mode 100644 troggle/registration/locale/zh_CN/LC_MESSAGES/django.mo
delete mode 100644 troggle/registration/locale/zh_CN/LC_MESSAGES/django.po
delete mode 100644 troggle/registration/locale/zh_TW/LC_MESSAGES/django.mo
delete mode 100644 troggle/registration/locale/zh_TW/LC_MESSAGES/django.po
delete mode 100644 troggle/registration/management/__init__.py
delete mode 100644 troggle/registration/management/commands/__init__.py
delete mode 100644 troggle/registration/management/commands/cleanupregistration.py
delete mode 100644 troggle/registration/models.py
delete mode 100644 troggle/registration/signals.py
delete mode 100644 troggle/registration/tests.py
delete mode 100644 troggle/registration/urls.py
delete mode 100644 troggle/registration/views.py
delete mode 100644 troggle/save_carefully.py
delete mode 100644 troggle/settings.py
delete mode 100644 troggle/templates/admin/base_site.html
delete mode 100644 troggle/templates/base.html
delete mode 100644 troggle/templates/calendar.html
delete mode 100644 troggle/templates/cave.html
delete mode 100644 troggle/templates/cavebase.html
delete mode 100644 troggle/templates/caveindex.html
delete mode 100644 troggle/templates/cavesearch.html
delete mode 100644 troggle/templates/controlPanel.html
delete mode 100644 troggle/templates/entrance.html
delete mode 100644 troggle/templates/expedition.html
delete mode 100644 troggle/templates/fileupload.html
delete mode 100644 troggle/templates/frontpage.html
delete mode 100644 troggle/templates/index.html
delete mode 100644 troggle/templates/listdir.html
delete mode 100644 troggle/templates/logbookentry.html
delete mode 100644 troggle/templates/logbooksearch.html
delete mode 100644 troggle/templates/person.html
delete mode 100644 troggle/templates/personForm.html
delete mode 100644 troggle/templates/personexpedition.html
delete mode 100644 troggle/templates/personindex.html
delete mode 100644 troggle/templates/profiles/create_profile.html
delete mode 100644 troggle/templates/profiles/edit_profile.html
delete mode 100644 troggle/templates/profiles/profile_detail.html
delete mode 100644 troggle/templates/profiles/profile_list.html
delete mode 100644 troggle/templates/profiles/select_profile.html
delete mode 100644 troggle/templates/qm.html
delete mode 100644 troggle/templates/registration/activate.html
delete mode 100644 troggle/templates/registration/activation_email.txt
delete mode 100644 troggle/templates/registration/activation_email_subject.txt
delete mode 100644 troggle/templates/registration/login.html
delete mode 100644 troggle/templates/registration/logout.html
delete mode 100644 troggle/templates/registration/registration_activate.html
delete mode 100644 troggle/templates/registration/registration_complete.html
delete mode 100644 troggle/templates/registration/registration_form.html
delete mode 100644 troggle/templates/statistics.html
delete mode 100644 troggle/templates/subcave.html
delete mode 100644 troggle/templates/survexblock.html
delete mode 100644 troggle/templates/survey.html
delete mode 100644 troggle/templates/svxfile.html
delete mode 100644 troggle/templates/todo.html
delete mode 100644 troggle/urls.py
diff --git a/troggle/__init__.py b/troggle/__init__.py
deleted file mode 100644
index e69de29bb..000000000
diff --git a/troggle/alwaysUseRequestContext.py b/troggle/alwaysUseRequestContext.py
deleted file mode 100644
index b587b5283..000000000
--- a/troggle/alwaysUseRequestContext.py
+++ /dev/null
@@ -1,8 +0,0 @@
-# this is the snippet from http://www.djangosnippets.org/snippets/3/
-
-from django.shortcuts import render_to_response
-from django.template import RequestContext
-
-def render_response(req, *args, **kwargs):
- kwargs['context_instance'] = RequestContext(req)
- return render_to_response(*args, **kwargs)
\ No newline at end of file
diff --git a/troggle/databaseReset.py b/troggle/databaseReset.py
deleted file mode 100644
index f2c3b51b6..000000000
--- a/troggle/databaseReset.py
+++ /dev/null
@@ -1,58 +0,0 @@
-import os
-import time
-import settings
-os.environ['PYTHONPATH'] = settings.PYTHON_PATH
-os.environ['DJANGO_SETTINGS_MODULE'] = 'settings'
-from django.core import management
-from django.db import connection
-from django.contrib.auth.models import User
-
-def reload_db():
- cursor = connection.cursor()
- cursor.execute("drop database %s" % settings.DATABASE_NAME)
- cursor.execute("create database %s" % settings.DATABASE_NAME)
- cursor.execute("ALTER DATABASE %s CHARACTER SET=utf8" % settings.DATABASE_NAME)
- cursor.execute("USE %s" % settings.DATABASE_NAME)
- management.call_command('syncdb')
- user = User.objects.create_user('m', 'm@m.com', 'm')
- user.is_staff = True
- user.is_superuser = True
- user.save()
-
-def make_dirs():
- """Make directories that troggle requires"""
- if not os.path.isdir(settings.PHOTOS_ROOT):
- os.mkdir(settings.PHOTOS_ROOT)
-
-def import_cavetab():
- import parsers.cavetab
- parsers.cavetab.LoadCaveTab(logfile=settings.LOGFILE)
-
-def import_people():
- import parsers.people
- parsers.people.LoadPersonsExpos()
-
-def import_logbooks():
- settings.LOGFILE.write('\nBegun importing logbooks at ' + time.asctime() +'\n'+'-'*60)
- import parsers.logbooks
- parsers.logbooks.LoadLogbooks()
-
-def import_survex():
- import parsers.survex
- parsers.survex.LoadAllSurvexBlocks()
-
-def import_QMs():
- import parsers.QMs
-
-def import_surveys():
- import parsers.surveys
-
-def reset():
- reload_db()
- make_dirs()
- import_cavetab()
- import_people()
- import_logbooks()
- import_survex()
- import_QMs()
- import_surveys()
\ No newline at end of file
diff --git a/troggle/expo/__init__.py b/troggle/expo/__init__.py
deleted file mode 100644
index e69de29bb..000000000
diff --git a/troggle/expo/admin.py b/troggle/expo/admin.py
deleted file mode 100644
index f2717d920..000000000
--- a/troggle/expo/admin.py
+++ /dev/null
@@ -1,93 +0,0 @@
-from troggle.expo.models import *
-from django.contrib import admin
-from django.forms import ModelForm
-import django.forms as forms
-from expo.forms import LogbookEntryForm
-#from troggle.reversion.admin import VersionAdmin #django-reversion version control
-
-#overriding admin save so we have the new since parsing field
-class TroggleModelAdmin(admin.ModelAdmin):
- def save_model(self, request, obj, form, change):
- obj.new_since_parsing=True
- obj.save()
-
-class RoleInline(admin.TabularInline):
- model = PersonRole
- extra = 4
-
-class SurvexBlockAdmin(TroggleModelAdmin):
- inlines = (RoleInline,)
-
-class ScannedImageInline(admin.TabularInline):
- model = ScannedImage
- extra = 4
-
-class SurveyAdmin(TroggleModelAdmin):
- inlines = (ScannedImageInline,)
- search_fields = ('expedition__year','wallet_number')
-
-class QMInline(admin.TabularInline):
- model=QM
- extra = 4
-
-class PhotoInline(admin.TabularInline):
- model = Photo
- exclude = ['is_mugshot', ]
- extra = 1
-
-class PersonTripInline(admin.TabularInline):
- model = PersonTrip
- exclude = ['persontrip_next','Delete']
- extra = 1
-
-#class LogbookEntryAdmin(VersionAdmin):
-class LogbookEntryAdmin(TroggleModelAdmin):
- prepopulated_fields = {'slug':("title",)}
- search_fields = ('title','expedition__year')
- inlines = (PersonTripInline, PhotoInline)
- form = LogbookEntryForm
- #inlines = (QMInline,) #doesn't work because QM has two foreignkeys to Logbookentry- need workaround
-
-class PersonExpeditionInline(admin.TabularInline):
- model = PersonExpedition
- extra = 1
-
-
-
-class PersonAdmin(TroggleModelAdmin):
- search_fields = ('first_name','last_name')
- inlines = (PersonExpeditionInline,)
-
-class QMAdmin(TroggleModelAdmin):
- search_fields = ('found_by__cave__kataster_number','number')
-
-class PersonExpeditionAdmin(TroggleModelAdmin):
- search_fields = ('person__first_name','expedition__year')
-
-class CaveAdmin(TroggleModelAdmin):
- search_fields = ('official_name','kataster_number','unofficial_number')
- #inlines = (QMInline,)
- extra = 4
-
-
-
-admin.site.register(Photo)
-admin.site.register(Subcave)
-admin.site.register(Cave, CaveAdmin)
-admin.site.register(Area)
-admin.site.register(OtherCaveName)
-admin.site.register(CaveAndEntrance)
-admin.site.register(SurveyStation)
-admin.site.register(Entrance)
-admin.site.register(SurvexBlock, SurvexBlockAdmin)
-admin.site.register(Expedition)
-admin.site.register(Person,PersonAdmin)
-admin.site.register(PersonRole)
-admin.site.register(PersonExpedition,PersonExpeditionAdmin)
-admin.site.register(Role)
-admin.site.register(LogbookEntry, LogbookEntryAdmin)
-admin.site.register(PersonTrip)
-admin.site.register(QM, QMAdmin)
-admin.site.register(Survey, SurveyAdmin)
-admin.site.register(ScannedImage)
-
diff --git a/troggle/expo/context.py b/troggle/expo/context.py
deleted file mode 100644
index 06215cea0..000000000
--- a/troggle/expo/context.py
+++ /dev/null
@@ -1,4 +0,0 @@
-from django.conf import settings
-
-def settings_context(request):
- return { 'settings':settings }
\ No newline at end of file
diff --git a/troggle/expo/fileAbstraction.py b/troggle/expo/fileAbstraction.py
deleted file mode 100644
index 94b8b0c4b..000000000
--- a/troggle/expo/fileAbstraction.py
+++ /dev/null
@@ -1,43 +0,0 @@
-import troggle.settings as settings
-import os
-import urllib
-
-def urljoin(x, y): return x + "/" + y
-
-def listdir(*path):
- try:
- strippedpath = [p for p in path if p]
- root = os.path.join(settings.FILES, *strippedpath )
- l = ""
- #l = root + "\n"
- isdir = os.path.isdir(root) #This seems to be required for os.path.isdir to work...
- #l += str(isdir) + "\n"
- for p in os.listdir(root):
- if os.path.isdir(os.path.join(root, p)):
- l += p + "/\n"
-
- elif os.path.isfile(os.path.join(root, p)):
- l += p + "\n"
- #Ignore non-files and non-directories
- return l
- except:
- if strippedpath:
- c = reduce(urljoin, strippedpath)
- else:
- c = ""
- c = c.replace("#", "%23")
- print "FILE: ", settings.FILES + "listdir/" + c
- return urllib.urlopen(settings.FILES + "listdir/" + c).read()
-
-def dirsAsList(*path):
- return [d for d in listdir(*path).split("\n") if len(d) > 0 and d[-1] == "/"]
-
-def filesAsList(*path):
- return [d for d in listdir(*path).split("\n") if len(d) > 0 and d[-1] != "/"]
-
-def readFile(*path):
- try:
- f = open(os.path.join(settings.FILES, *path))
- except:
- f = urllib.urlopen(settings.FILES + "download/" + reduce(urljoin, path))
- return f.read()
\ No newline at end of file
diff --git a/troggle/expo/forms.py b/troggle/expo/forms.py
deleted file mode 100644
index 2225b0c83..000000000
--- a/troggle/expo/forms.py
+++ /dev/null
@@ -1,40 +0,0 @@
-from django.forms import ModelForm
-from models import Cave, Person, LogbookEntry
-import django.forms as forms
-from django.forms.formsets import formset_factory
-from django.contrib.admin.widgets import AdminDateWidget
-import string
-
-class CaveForm(ModelForm):
- class Meta:
- model = Cave
-
-class PersonForm(ModelForm):
- class Meta:
- model = Person
-
-class LogbookEntryForm(ModelForm):
- class Meta:
- model = LogbookEntry
-
- def wikiLinkHints(LogbookEntry=None):
- res = ["Please use the following wikilinks, which are related to this logbook entry:"]
-
- res.append(r'
QMs found:')
- for QM in LogbookEntry.instance.QMs_found.all():
- res.append(QM.wiki_link())
-
- res.append(r'
QMs ticked off:')
- for QM in LogbookEntry.instance.QMs_ticked_off.all():
- res.append(QM.wiki_link())
-
-# res.append(r'
People')
-# for persontrip in LogbookEntry.instance.persontrip_set.all():
-# res.append(persontrip.wiki_link())
-# res.append(r'
')
-
- return string.join(res, r'
')
-
- def __init__(self, *args, **kwargs):
- super(LogbookEntryForm, self).__init__(*args, **kwargs)
- self.fields['text'].help_text=self.wikiLinkHints()
\ No newline at end of file
diff --git a/troggle/expo/imagekit_specs.py b/troggle/expo/imagekit_specs.py
deleted file mode 100644
index 243cb9f76..000000000
--- a/troggle/expo/imagekit_specs.py
+++ /dev/null
@@ -1,23 +0,0 @@
-from imagekit.specs import ImageSpec
-from imagekit import processors
-
-class ResizeThumb(processors.Resize):
- width = 100
- height = 75
- crop = True
-
-class ResizeDisplay(processors.Resize):
- width = 600
-
-class EnhanceThumb(processors.Adjustment):
- contrast = 1.2
- sharpness = 1.1
-
-class Thumbnail(ImageSpec):
- access_as = 'thumbnail_image'
- pre_cache = True
- processors = [ResizeThumb, EnhanceThumb]
-
-class Display(ImageSpec):
- increment_count = True
- processors = [ResizeDisplay]
diff --git a/troggle/expo/models.py b/troggle/expo/models.py
deleted file mode 100644
index 3472a01b9..000000000
--- a/troggle/expo/models.py
+++ /dev/null
@@ -1,615 +0,0 @@
-import urllib, urlparse, string, os, datetime
-from django.forms import ModelForm
-from django.db import models
-from django.contrib import admin
-from django.core.files.storage import FileSystemStorage
-from django.contrib.auth.models import User
-from django.contrib.contenttypes.models import ContentType
-from django.conf import settings
-from decimal import Decimal, getcontext
-from django.core.urlresolvers import reverse
-from imagekit.models import ImageModel
-getcontext().prec=2 #use 2 significant figures for decimal calculations
-
-from models_survex import *
-
-#This class is for adding fields and methods which all of our models will have.
-class TroggleModel(models.Model):
- new_since_parsing = models.BooleanField(default=False, editable=False)
-
- def get_admin_url(self):
- return settings.URL_ROOT + "/admin/expo/" + self._meta.object_name.lower() + "/" + str(self.pk)
-
- class Meta:
- abstract = True
-
-class TroggleImageModel(ImageModel):
- new_since_parsing = models.BooleanField(default=False, editable=False)
-
- def get_admin_url(self):
- return settings.URL_ROOT + "/admin/expo/" + self._meta.object_name.lower() + "/" + str(self.pk)
-
- class Meta:
- abstract = True
-
-class Expedition(TroggleModel):
- year = models.CharField(max_length=20, unique=True)
- name = models.CharField(max_length=100)
- date_from = models.DateField(blank=True,null=True)
- date_to = models.DateField(blank=True,null=True)
-
- def __unicode__(self):
- return self.year
-
- class Meta:
- ordering = ('year',)
- get_latest_by = 'date_from'
-
- def get_absolute_url(self):
- #return settings.URL_ROOT + "/expedition/%s" % self.year
- return settings.URL_ROOT + reverse('expedition',args=[self.year])
-
-
- # lose these two functions (inelegant, and we may create a file with the dates that we can load from)
- def GuessDateFrom(self):
- try:
- return self.logbookentry_set.order_by('date')[0].date
- except IndexError:
- pass
-
- def GuessDateTo(self): # returns the date of the last logbook entry in the expedition
- try:
- return self.logbookentry_set.order_by('date')[-1].date
- except IndexError:
- pass
-
- def ListDays(self):
- if self.date_from and self.date_to:
- res=[]
- date=self.date_from
- while date <= self.date_to:
- res.append(date)
- date+=datetime.timedelta(days=1)
- return res
- elif self.GuessDateFrom() and self.GuessDateTo(): # if we don't have the real dates, try it with the dates taken from the earliest and latest logbook entries
- date=self.GuessDateFrom()
- while date <= self.GuessDateTo():
- res.append(date)
- date+=datetime.timedelta(days=1)
- return res
-
-
-
-
-class Person(TroggleModel):
- first_name = models.CharField(max_length=100)
- last_name = models.CharField(max_length=100)
- is_vfho = models.BooleanField(help_text="VFHO is the Vereines für Höhlenkunde in Obersteier, a nearby Austrian caving club.")
- mug_shot = models.CharField(max_length=100, blank=True,null=True)
- blurb = models.TextField(blank=True,null=True)
-
- #href = models.CharField(max_length=200)
- orderref = models.CharField(max_length=200) # for alphabetic
-
- #the below have been removed and made methods. I'm not sure what the b in bisnotable stands for. - AC 16 Feb
- #notability = models.FloatField() # for listing the top 20 people
- #bisnotable = models.BooleanField()
- user = models.OneToOneField(User, null=True, blank=True)
- def get_absolute_url(self):
- return settings.URL_ROOT + reverse('person',kwargs={'first_name':self.first_name,'last_name':self.last_name})
-
- class Meta:
- verbose_name_plural = "People"
- class Meta:
- ordering = ('orderref',) # "Wookey" makes too complex for: ('last_name', 'first_name')
-
- def __unicode__(self):
- if self.last_name:
- return "%s %s" % (self.first_name, self.last_name)
- return self.first_name
-
-# Below are no longer needed. Use {{ person.personexpedition_set.all.0.expedition }} for Firstexpedition, and {{ person.personexpedition_set.latest.expedition }} for Lastexpedition
- # these ought to be possible by piping through |min in the template, or getting the first of an ordered list
-# def Firstexpedition(self):
-# return self.personexpedition_set.order_by('expedition')[0]
-# def Lastexpedition(self):
-# return self.personexpedition_set.order_by('-expedition')[0]
-
- def notability(self):
- notability = Decimal(0)
- for personexpedition in self.personexpedition_set.all():
- if not personexpedition.is_guest:
- notability += Decimal(1) / (2012 - int(personexpedition.expedition.year))
- return notability
-
- def bisnotable(self):
- return self.notability() > Decimal(1)/Decimal(3)
-
- #def Sethref(self):
- #if self.last_name:
- #self.href = self.first_name.lower() + "_" + self.last_name.lower()
- #self.orderref = self.last_name + " " + self.first_name
- #else:
- # self.href = self.first_name.lower()
- #self.orderref = self.first_name
- #self.notability = 0.0 # set temporarily
-
-
-class PersonExpedition(TroggleModel):
- expedition = models.ForeignKey(Expedition)
- person = models.ForeignKey(Person)
- date_from = models.DateField(blank=True,null=True)
- date_to = models.DateField(blank=True,null=True)
- is_guest = models.BooleanField(default=False)
- COMMITTEE_CHOICES = (
- ('leader','Expo leader'),
- ('medical','Expo medical officer'),
- ('treasurer','Expo treasurer'),
- ('sponsorship','Expo sponsorship coordinator'),
- ('research','Expo research coordinator'),
- )
- expo_committee_position = models.CharField(blank=True,null=True,choices=COMMITTEE_CHOICES,max_length=200)
- nickname = models.CharField(max_length=100,blank=True,null=True)
-
- def GetPersonroles(self):
- res = [ ]
- for personrole in self.personrole_set.order_by('survex_block'):
- if res and res[-1]['survexpath'] == personrole.survex_block.survexpath:
- res[-1]['roles'] += ", " + str(personrole.role)
- else:
- res.append({'date':personrole.survex_block.date, 'survexpath':personrole.survex_block.survexpath, 'roles':str(personrole.role)})
- return res
-
- class Meta:
- ordering = ('expedition',)
- get_latest_by = 'date_from'
-
- def GetPersonChronology(self):
- res = { }
- for persontrip in self.persontrip_set.all():
- a = res.setdefault(persontrip.date, { })
- a.setdefault("persontrips", [ ]).append(persontrip)
- for personrole in self.personrole_set.all():
- a = res.setdefault(personrole.survex_block.date, { })
- b = a.setdefault("personroles", { })
- survexpath = personrole.survex_block.survexpath
-
- if b.get(survexpath):
- b[survexpath] += ", " + str(personrole.role)
- else:
- b[survexpath] = str(personrole.role)
-# needs converting dict into list
- return sorted(res.items())
-
- # possibly not useful functions anyway -JT
- # if you can find a better way to make the expo calendar table, be my guest. It isn't possible to do this logic in a django template without writing custom tags.
- def ListDays(self):
- if self.date_from and self.date_to:
- res=[]
- date=self.date_from
- while date <= self.date_to:
- res.append(date)
- date+=datetime.timedelta(days=1)
- return res
-
- def ListDaysTF(self):
- if self.date_from and self.date_to:
- res=[]
- for date in self.expedition.ListDays():
- res.append(date in self.ListDays())
- return res
-
- def __unicode__(self):
- return "%s: (%s)" % (self.person, self.expedition)
-
- #why is the below a function in personexpedition, rather than in person? - AC 14 Feb 09
- def name(self):
- if self.nickname:
- return "%s (%s) %s" % (self.person.first_name, self.nickname, self.person.last_name)
- if self.person.last_name:
- return "%s %s" % (self.person.first_name, self.person.last_name)
- return self.person.first_name
-
- def get_absolute_url(self):
- #return settings.URL_ROOT + '/personexpedition/' + str(self.person.first_name) + '_' + str(self.person.last_name) + '/' +self.expedition.year
- return settings.URL_ROOT + reverse('personexpedition',kwargs={'first_name':self.person.first_name,'last_name':self.person.last_name,'year':self.expedition.year})
-
-class LogbookEntry(TroggleModel):
- date = models.DateField()
- expedition = models.ForeignKey(Expedition,blank=True,null=True) # yes this is double-
- author = models.ForeignKey(PersonExpedition,blank=True,null=True) # the person who writes it up doesn't have to have been on the trip
- title = models.CharField(max_length=200)
- cave = models.ForeignKey('Cave',blank=True,null=True)
- place = models.CharField(max_length=100,blank=True,null=True)
- text = models.TextField()
- slug = models.SlugField(max_length=50)
- #href = models.CharField(max_length=100)
-
-
- #logbookentry_next = models.ForeignKey('LogbookEntry', related_name='pnext', blank=True,null=True)
- #logbookentry_prev = models.ForeignKey('LogbookEntry', related_name='pprev', blank=True,null=True)
-
- class Meta:
- verbose_name_plural = "Logbook Entries"
- # several PersonTrips point in to this object
- class Meta:
- ordering = ('-date',)
-
- def get_absolute_url(self):
- return settings.URL_ROOT + reverse('logbookentry',kwargs={'date':self.date,'slug':self.slug})
-
- def __unicode__(self):
- return "%s: (%s)" % (self.date, self.title)
-
- def get_next_by_id(self):
- LogbookEntry.objects.get(id=self.id+1)
-
- def get_previous_by_id(self):
- LogbookEntry.objects.get(id=self.id-1)
-
-class PersonTrip(TroggleModel):
- person_expedition = models.ForeignKey(PersonExpedition,null=True)
-
- # this will be a foreign key of the place(s) the trip went through
- # possibly a trip has a plurality of triplets pointing into it
- place = models.CharField(max_length=100)
- # should add cave thing here (copied from logbook maybe)
- date = models.DateField()
- time_underground = models.FloatField()
- logbook_entry = models.ForeignKey(LogbookEntry)
- is_logbook_entry_author = models.BooleanField()
-
- #persontrip_next = models.ForeignKey('PersonTrip', related_name='pnext', blank=True,null=True)
- #persontrip_prev = models.ForeignKey('PersonTrip', related_name='pprev', blank=True,null=True)
-
- def __unicode__(self):
- return "%s %s (%s)" % (self.person_expedition, self.place, self.date)
-
- def get_persons_next_trip(self):
- try:
- return PersonTrip.objects.filter(person_expedition__person=self.person_expedition.person, date__gt=self.date)[0]
- except:
- return
-
- def get_persons_previous_trip(self):
- try:
- return PersonTrip.objects.filter(person_expedition__person=self.person_expedition.person, date__lt=self.date)[0]
- except:
- return
-
-# def get_persons_previous_trip(self):
-#
-# move following classes into models_cave
-#
-
-class Area(TroggleModel):
- short_name = models.CharField(max_length=100)
- name = models.CharField(max_length=200, blank=True, null=True)
- description = models.TextField(blank=True,null=True)
- parent = models.ForeignKey('Area', blank=True, null=True)
- def __unicode__(self):
- if self.parent:
- return unicode(self.parent) + u" - " + unicode(self.short_name)
- else:
- return unicode(self.short_name)
- def kat_area(self):
- if self.short_name in ["1623", "1626"]:
- return self.short_name
- elif self.parent:
- return self.parent.kat_area()
-
-class CaveAndEntrance(TroggleModel):
- cave = models.ForeignKey('Cave')
- entrance = models.ForeignKey('Entrance')
- entrance_letter = models.CharField(max_length=20,blank=True,null=True)
- def __unicode__(self):
- return unicode(self.cave) + unicode(self.entrance_letter)
-
-class Cave(TroggleModel):
- # too much here perhaps
- official_name = models.CharField(max_length=160)
- area = models.ManyToManyField(Area, blank=True, null=True)
- kataster_code = models.CharField(max_length=20,blank=True,null=True)
- kataster_number = models.CharField(max_length=10,blank=True, null=True)
- unofficial_number = models.CharField(max_length=60,blank=True, null=True)
- entrances = models.ManyToManyField('Entrance', through='CaveAndEntrance')
- explorers = models.TextField(blank=True,null=True)
- underground_description = models.TextField(blank=True,null=True)
- equipment = models.TextField(blank=True,null=True)
- references = models.TextField(blank=True,null=True)
- survey = models.TextField(blank=True,null=True)
- kataster_status = models.TextField(blank=True,null=True)
- underground_centre_line = models.TextField(blank=True,null=True)
- notes = models.TextField(blank=True,null=True)
- length = models.CharField(max_length=100,blank=True,null=True)
- depth = models.CharField(max_length=100,blank=True,null=True)
- extent = models.CharField(max_length=100,blank=True,null=True)
- survex_file = models.CharField(max_length=100,blank=True,null=True) #should be filefield, need to fix parser first
-
- #href = models.CharField(max_length=100)
-
- def get_absolute_url(self):
- if self.kataster_number:
- href = self.kataster_number
- elif self.unofficial_number:
- href = self.unofficial_number
- else:
- href = official_name.lower()
- #return settings.URL_ROOT + '/cave/' + href + '/'
- return settings.URL_ROOT + reverse('cave',kwargs={'cave_id':href,})
-
-
-
- def __unicode__(self):
- if self.kataster_number:
- if self.kat_area():
- return self.kat_area() + u": " + self.kataster_number
- else:
- return unicode("l") + u": " + self.kataster_number
- else:
- if self.kat_area():
- return self.kat_area() + u": " + self.unofficial_number
- else:
- return self.unofficial_number
-
- def get_QMs(self):
- return QM.objects.filter(found_by__cave=self)
-
- def kat_area(self):
- for a in self.area.all():
- if a.kat_area():
- return a.kat_area()
- def entrances(self):
- return CaveAndEntrance.objects.filter(cave=self)
- def entrancelist(self):
- rs = []
- res = ""
- for e in CaveAndEntrance.objects.filter(cave=self):
- rs.append(e.entrance_letter)
- rs.sort()
- prevR = None
- n = 0
- for r in rs:
- if prevR:
- if chr(ord(prevR) + 1 ) == r:
- prevR = r
- n += 1
- else:
- if n == 0:
- res += ", " + prevR
- else:
- res += "–" + prevR
- else:
- prevR = r
- n = 0
- res += r
- if n == 0:
- res += ", " + prevR
- else:
- res += "–" + prevR
- return res
-
-
-
-class OtherCaveName(TroggleModel):
- name = models.CharField(max_length=160)
- cave = models.ForeignKey(Cave)
- def __unicode__(self):
- return unicode(self.name)
-
-class SurveyStation(TroggleModel):
- name = models.CharField(max_length=200)
- def __unicode__(self):
- return unicode(self.name)
-
-class Entrance(TroggleModel):
- name = models.CharField(max_length=100, blank=True,null=True)
- entrance_description = models.TextField(blank=True,null=True)
- explorers = models.TextField(blank=True,null=True)
- map_description = models.TextField(blank=True,null=True)
- location_description = models.TextField(blank=True,null=True)
- approach = models.TextField(blank=True,null=True)
- underground_description = models.TextField(blank=True,null=True)
- photo = models.TextField(blank=True,null=True)
- MARKING_CHOICES = (
- ('P', 'Paint'),
- ('P?', 'Paint (?)'),
- ('T', 'Tag'),
- ('T?', 'Tag (?)'),
- ('R', 'Retagged'),
- ('S', 'Spit'),
- ('S?', 'Spit (?)'),
- ('U', 'Unmarked'),
- ('?', 'Unknown'))
- marking = models.CharField(max_length=2, choices=MARKING_CHOICES)
- marking_comment = models.TextField(blank=True,null=True)
- FINDABLE_CHOICES = (
- ('?', 'To be confirmed ...'),
- ('S', 'Surveyed'),
- ('L', 'Lost'),
- ('R', 'Refindable'))
- findability = models.CharField(max_length=1, choices=FINDABLE_CHOICES, blank=True, null=True)
- findability_description = models.TextField(blank=True,null=True)
- alt = models.TextField(blank=True, null=True)
- northing = models.TextField(blank=True, null=True)
- easting = models.TextField(blank=True, null=True)
- tag_station = models.ForeignKey(SurveyStation, blank=True,null=True, related_name="tag_station")
- exact_station = models.ForeignKey(SurveyStation, blank=True,null=True, related_name="exact_station")
- other_station = models.ForeignKey(SurveyStation, blank=True,null=True, related_name="other_station")
- other_description = models.TextField(blank=True,null=True)
- bearings = models.TextField(blank=True,null=True)
- def __unicode__(self):
- a = CaveAndEntrance.objects.filter(entrance = self)
- name = u''
- if self.name:
- name = unicode(self.name) + u' '
- if len(a) == 1:
- return name + unicode(a[0])
- return name + unicode(a)
- def marking_val(self):
- for m in self.MARKING_CHOICES:
- if m[0] == self.marking:
- return m[1]
- def findability_val(self):
- for f in self.FINDABLE_CHOICES:
- if f[0] == self.findability:
- return f[1]
-
-class Subcave(TroggleModel):
- description = models.TextField()
- name = models.CharField(max_length=200, )
- cave = models.ForeignKey('Cave', blank=True, null=True, help_text="Only the top-level subcave should be linked to a cave")
- parent= models.ForeignKey('Subcave', blank=True, null=True, related_name='children')
- adjoining = models.ManyToManyField('Subcave',blank=True, null=True,)
- survex_file = models.CharField(max_length=200, blank=True, null=True,)
-
- def __unicode__(self):
- return self.name
-
- def get_absolute_url(self):
- urlString=self.name
- if self.parent:
- parent=self.parent
- while parent: #recursively walk up the tree, adding parents to the left of the URL
- urlString=parent.name+'/'+urlString
- if parent.cave:
- cave=parent.cave
- parent=parent.parent
- urlString='cave/'+unicode(cave.kataster_number)+'/'+urlString
- else:
- urlString='cave/'+unicode(self.cave.kataster_number)+'/'+urlString
-
-
- return urlparse.urljoin(settings.URL_ROOT, urlString)
-
-class QM(TroggleModel):
- #based on qm.csv in trunk/expoweb/smkridge/204 which has the fields:
- #"Number","Grade","Area","Description","Page reference","Nearest station","Completion description","Comment"
- found_by = models.ForeignKey(LogbookEntry, related_name='QMs_found',blank=True, null=True )
- ticked_off_by = models.ForeignKey(LogbookEntry, related_name='QMs_ticked_off',null=True,blank=True)
- number = models.IntegerField()
- GRADE_CHOICES=(
- ('A', 'A: Large obvious lead'),
- ('B', 'B: Average lead'),
- ('C', 'C: Tight unpromising lead'),
- ('D', 'D: Dig'),
- ('X', 'X: Unclimbable aven')
- )
- grade = models.CharField(max_length=1, choices=GRADE_CHOICES)
- location_description = models.TextField(blank=True)
- #should be a foreignkey to surveystation
- nearest_station_description = models.CharField(max_length=400,null=True,blank=True)
- nearest_station = models.CharField(max_length=200,blank=True,null=True)
- area = models.CharField(max_length=100,blank=True,null=True)
- completion_description = models.TextField(blank=True,null=True)
- comment=models.TextField(blank=True,null=True)
- #the below are unneeded- instead use the date fields of the QM's trips
- #dateFound = models.DateField(blank=True)
- #dateKilled = models.DateField(blank=True)
- def __str__(self):
- QMnumber=str(self.found_by.cave)+'-'+str(self.found_by.date.year)+"-"+str(self.number)+self.grade
- return str(QMnumber)
-
- def get_absolute_url(self):
- #return settings.URL_ROOT + '/cave/' + self.found_by.cave.kataster_number + '/' + str(self.found_by.date.year) + '-' + '%02d' %self.number
- return settings.URL_ROOT + reverse('qm',kwargs={'cave_id':self.cave.kataster_number,'year':self.found_by.date.year,'qm_id':self.number,'grade':self.grade})
-
- def get_next_by_id(self):
- return QM.objects.get(id=self.id+1)
-
- def get_previous_by_id(self):
- return QM.objects.get(id=self.id-1)
-
- def wiki_link(self):
- res = '[[cave:' + str(self.found_by.cave.kataster_number) + ' '
- res += 'QM:' + str(self.found_by.date.year) + '-'
- res += str(self.number) + self.grade + ']]'
- return res
-
-photoFileStorage = FileSystemStorage(location=settings.PHOTOS_ROOT, base_url=settings.PHOTOS_URL)
-class Photo(TroggleImageModel):
- caption = models.CharField(max_length=1000,blank=True,null=True)
- contains_logbookentry = models.ForeignKey(LogbookEntry,blank=True,null=True)
- contains_person = models.ManyToManyField(Person,blank=True,null=True)
- file = models.ImageField(storage=photoFileStorage, upload_to='.',)
- is_mugshot = models.BooleanField(default=False)
- contains_cave = models.ForeignKey(Cave,blank=True,null=True)
- contains_entrance = models.ForeignKey(Entrance, related_name="photo_file",blank=True,null=True)
- nearest_survey_point = models.ForeignKey(SurveyStation,blank=True,null=True)
- nearest_QM = models.ForeignKey(QM,blank=True,null=True)
- lon_utm = models.FloatField(blank=True,null=True)
- lat_utm = models.FloatField(blank=True,null=True)
-
- class IKOptions:
- spec_module = 'expo.imagekit_specs'
- cache_dir = 'thumbs'
- image_field = 'file'
-
- #content_type = models.ForeignKey(ContentType)
- #object_id = models.PositiveIntegerField()
- #location = generic.GenericForeignKey('content_type', 'object_id')
-
- def __str__(self):
- return self.caption
-
-scansFileStorage = FileSystemStorage(location=settings.SURVEY_SCANS, base_url=settings.SURVEYS_URL)
-def get_scan_path(instance, filename):
- year=instance.survey.expedition.year
- print "WN: ", type(instance.survey.wallet_number), instance.survey.wallet_number
- number="%02d" % instance.survey.wallet_number + str(instance.survey.wallet_letter) #using %02d string formatting because convention was 2009#01
- return os.path.join('./',year,year+r'#'+number,instance.contents+str(instance.number_in_wallet)+r'.jpg')
-
-class ScannedImage(TroggleImageModel):
- file = models.ImageField(storage=scansFileStorage, upload_to=get_scan_path)
- scanned_by = models.ForeignKey(Person,blank=True, null=True)
- scanned_on = models.DateField(null=True)
- survey = models.ForeignKey('Survey')
- contents = models.CharField(max_length=20,choices=(('notes','notes'),('plan','plan_sketch'),('elevation','elevation_sketch')))
- number_in_wallet = models.IntegerField(null=True)
- lon_utm = models.FloatField(blank=True,null=True)
- lat_utm = models.FloatField(blank=True,null=True)
-
- class IKOptions:
- spec_module = 'expo.imagekit_specs'
- cache_dir = 'thumbs'
- image_field = 'file'
- #content_type = models.ForeignKey(ContentType)
- #object_id = models.PositiveIntegerField()
- #location = generic.GenericForeignKey('content_type', 'object_id')
-
- #This is an ugly hack to deal with the #s in our survey scan paths. The correct thing is to write a custom file storage backend which calls urlencode on the name for making file.url but not file.path.
- def correctURL(self):
- return string.replace(self.file.url,r'#',r'%23')
-
- def __str__(self):
- return get_scan_path(self,'')
-
-class Survey(TroggleModel):
- expedition = models.ForeignKey('Expedition')
- wallet_number = models.IntegerField(blank=True,null=True)
- wallet_letter = models.CharField(max_length=1,blank=True,null=True)
- comments = models.TextField(blank=True,null=True)
- location = models.CharField(max_length=400,blank=True,null=True)
- #notes_scan = models.ForeignKey('ScannedImage',related_name='notes_scan',blank=True, null=True) #Replaced by contents field of ScannedImage model
- survex_block = models.ForeignKey('SurvexBlock',blank=True, null=True)
- centreline_printed_on = models.DateField(blank=True, null=True)
- centreline_printed_by = models.ForeignKey('Person',related_name='centreline_printed_by',blank=True,null=True)
- #sketch_scan = models.ForeignKey(ScannedImage,blank=True, null=True) #Replaced by contents field of ScannedImage model
- tunnel_file = models.FileField(upload_to='surveyXMLfiles',blank=True, null=True)
- tunnel_main_sketch = models.ForeignKey('Survey',blank=True,null=True)
- integrated_into_main_sketch_on = models.DateField(blank=True,null=True)
- integrated_into_main_sketch_by = models.ForeignKey('Person' ,related_name='integrated_into_main_sketch_by', blank=True,null=True)
- rendered_image = models.ImageField(upload_to='renderedSurveys',blank=True,null=True)
- def __str__(self):
- return self.expedition.year+"#"+"%02d" % self.wallet_number
-
- def notes(self):
- return self.scannedimage_set.filter(contents='notes')
-
- def plans(self):
- return self.scannedimage_set.filter(contents='plan')
-
- def elevations(self):
- return self.scannedimage_set.filter(contents='elevation')
-
-
diff --git a/troggle/expo/models_survex.py b/troggle/expo/models_survex.py
deleted file mode 100644
index cf339f9fe..000000000
--- a/troggle/expo/models_survex.py
+++ /dev/null
@@ -1,66 +0,0 @@
-from django.db import models
-from django.conf import settings
-import os
-
-class SurvexBlock(models.Model):
- name = models.CharField(max_length=100, blank=True, null=True)
- parent = models.ForeignKey('SurvexBlock', blank=True, null=True)
- text = models.TextField()
-
- # non-useful representation of incomplete data
- start_year = models.IntegerField(blank=True, null=True)
- start_month = models.IntegerField(blank=True, null=True)
- start_day = models.IntegerField(blank=True, null=True)
- end_year = models.IntegerField(blank=True, null=True)
- end_month = models.IntegerField(blank=True, null=True)
- end_day = models.IntegerField(blank=True, null=True)
-
- date = models.DateField(blank=True, null=True)
- survexpath = models.CharField(max_length=100)
-
- # superfluous
- person = models.ManyToManyField('Person', through='PersonRole', blank=True, null=True)
-
- # code for where in the survex data files this block sits
- begin_file = models.CharField(max_length=200)
- begin_char = models.IntegerField()
- end_file = models.CharField(max_length=200, blank=True, null=True)
- end_char = models.IntegerField(blank=True, null=True)
-
- class Meta:
- ordering = ('date', 'survexpath')
-
- def __unicode__(self):
- return unicode(self.name)
-
- def filecontents(self):
- f = os.path.join(settings.SURVEX_DATA, self.begin_file)
- fin = open(f, "rb")
- res = fin.read().decode("latin1")
- fin.close()
- return res
-
- def GetPersonroles(self):
- res = [ ]
- for personrole in self.personrole_set.order_by('personexpedition'):
- if res and res[-1]['person'] == personrole.personexpedition.person:
- res[-1]['roles'] += ", " + str(personrole.role)
- else:
- res.append({'person':personrole.personexpedition.person, 'expeditionyear':personrole.personexpedition.expedition.year, 'roles':str(personrole.role)})
- print res
- return res
-
-
-class PersonRole(models.Model):
- personexpedition = models.ForeignKey('PersonExpedition')
- person = models.ForeignKey('Person')
- survex_block = models.ForeignKey('SurvexBlock')
- role = models.ForeignKey('Role')
- def __unicode__(self):
- return unicode(self.person) + " - " + unicode(self.survex_block) + " - " + unicode(self.role)
-
-class Role(models.Model):
- name = models.CharField(max_length=50)
- def __unicode__(self):
- return unicode(self.name)
-
diff --git a/troggle/expo/randSent.py b/troggle/expo/randSent.py
deleted file mode 100644
index a99b97466..000000000
--- a/troggle/expo/randSent.py
+++ /dev/null
@@ -1,32 +0,0 @@
-import troggle.settings as settings
-from django import forms
-from troggle.expo.models import LogbookEntry
-import random
-import re
-
-def weighted_choice(lst):
- n = random.uniform(0,1)
- for item, weight in lst:
- if n < weight:
- break
- n = n - weight
- return item
-
-def randomLogbookSentence():
- randSent={}
-
- # needs to handle empty logbooks without crashing
-
- #Choose a random logbook entry
- randSent['entry']=LogbookEntry.objects.order_by('?')[0]
-
- #Choose again if there are no sentances (this happens if it is a placeholder entry)
- while len(re.findall('[A-Z].*?\.',randSent['entry'].text))==0:
- randSent['entry']=LogbookEntry.objects.order_by('?')[0]
-
- #Choose a random sentence from that entry. Store the sentence as randSent['sentence'], and the number of that sentence in the entry as randSent['number']
- sentenceList=re.findall('[A-Z].*?\.',randSent['entry'].text)
- randSent['number']=random.randrange(0,len(sentenceList))
- randSent['sentence']=sentenceList[randSent['number']]
-
- return randSent
diff --git a/troggle/expo/search.py b/troggle/expo/search.py
deleted file mode 100644
index 5ec2ce2f1..000000000
--- a/troggle/expo/search.py
+++ /dev/null
@@ -1,39 +0,0 @@
-import re
-
-from django.db.models import Q
-
-# search script from http://www.julienphalip.com/blog/2008/08/16/adding-search-django-site-snap/
-
-def normalize_query(query_string,
- findterms=re.compile(r'"([^"]+)"|(\S+)').findall,
- normspace=re.compile(r'\s{2,}').sub):
- ''' Splits the query string in invidual keywords, getting rid of unecessary spaces
- and grouping quoted words together.
- Example:
-
- >>> normalize_query(' some random words "with quotes " and spaces')
- ['some', 'random', 'words', 'with quotes', 'and', 'spaces']
-
- '''
- return [normspace(' ', (t[0] or t[1]).strip()) for t in findterms(query_string)]
-
-def get_query(query_string, search_fields):
- ''' Returns a query, that is a combination of Q objects. That combination
- aims to search keywords within a model by testing the given search fields.
-
- '''
- query = None # Query to search for every search term
- terms = normalize_query(query_string)
- for term in terms:
- or_query = None # Query to search for a given term in each field
- for field_name in search_fields:
- q = Q(**{"%s__icontains" % field_name: term})
- if or_query is None:
- or_query = q
- else:
- or_query = or_query | q
- if query is None:
- query = or_query
- else:
- query = query & or_query
- return query
\ No newline at end of file
diff --git a/troggle/expo/templatetags/__init__.py b/troggle/expo/templatetags/__init__.py
deleted file mode 100644
index e69de29bb..000000000
diff --git a/troggle/expo/templatetags/survex_markup.py b/troggle/expo/templatetags/survex_markup.py
deleted file mode 100644
index 464a04bc6..000000000
--- a/troggle/expo/templatetags/survex_markup.py
+++ /dev/null
@@ -1,52 +0,0 @@
-from django import template
-from django.utils.html import conditional_escape
-from django.template.defaultfilters import stringfilter
-from django.utils.safestring import mark_safe
-import re
-
-register = template.Library()
-
-# seems to add extra lines between the commented lines, which isn't so great.
-regexes = []
-regexes.append((re.compile(r"(;.*)$", re.IGNORECASE|re.MULTILINE),
- r'\n'))
-regexes.append((re.compile(r"^(\s*)(\*include)(\s+)([^\s]*)(.svx)$", re.IGNORECASE|re.MULTILINE),
- r'\1\2\3\4\5'))
-regexes.append((re.compile(r"^(\s*)(\*include)(\s+)([^\s]*)$", re.IGNORECASE|re.MULTILINE),
- r'\1\2\3\4'))
-regexes.append((re.compile(r"^(\s*)(\*team\s+(?:notes|tape|insts|pics))(\s+)(.*)$", re.IGNORECASE|re.MULTILINE),
- r'\1\2\3\4'))
-regexes.append((re.compile(r"^(\s*)(\*(?:begin|end|copyright|date|entrance|equate|export|fix|prefix|require|SOLVE|title|truncate))(\s+)(.*)$", re.IGNORECASE|re.MULTILINE),
- r'\1\2\3\4'))
-regexes.append((re.compile(r"^(\s*)(\*calibrate\s+(?:TAPE|COMPASS|CLINO|COUNTER|DEPTH|DECLINATION|X|Y|Z)+)(\s+)(.*)$", re.IGNORECASE|re.MULTILINE),
- r'\1\2\3\4'))
-regexes.append((re.compile(r"^(\s*)(\*data\s+(?:DEFAULT|NORMAL|DIVING|CARTESIAN|TOPOFIL|CYLPOLAR|NOSURVEY|passage)(?:\s+station|\s+from|\s+to|\s+FROMDEPTH|\s+TODEPTH|\s+DEPTHCHANGE|\s+newline|\s+direction|\s+tape|\s+compass|\s+clino|\s+northing|\s+easting|\s+altitude|\s+length|\s+bearing|\s+gradient|\s+ignoreall|\sleft|\sright|\sup|\sdown)*)$", re.IGNORECASE|re.MULTILINE),
- r'\1\2'))
-regexes.append((re.compile(r"^(\s*)(\*default\s+(?:CALIBRATE|DATA|UNITS)+)(\s+)(.*)$", re.IGNORECASE|re.MULTILINE),
- r'\1\2\3\4'))
-regexes.append((re.compile(r"^(\s*)(\*flags\s+(?:DUPLICATE|SPLAY|SURFACE|not DUPLICATE|not SPLAY|not SURFACE))(\s+)(.*)$", re.IGNORECASE|re.MULTILINE),
- r'\1\2\3\4'))
-regexes.append((re.compile(r"^(\s*)(\*infer\s+(?:plumbs|equates|exports))(\s+)(.*)$", re.IGNORECASE|re.MULTILINE),
- r'\1\2\3\4'))
-regexes.append((re.compile(r"^(\s*)(\*instrument\s+(?:compass|clino|tape))(\s+)(.*)$", re.IGNORECASE|re.MULTILINE),
- r'\1\2\3\4'))
-regexes.append((re.compile(r"^(\s*)(\*instrument\s+(?:compass|clino|tape))(\s+)(.*)$", re.IGNORECASE|re.MULTILINE),
- r'\1\2\3\4'))
-regexes.append((re.compile(r"^(\s*)(\*sd\s+(?:TAPE|COMPASS|CLINO|COUNTER|DEPTH|DECLINATION|DX|DY|DZ))(\s+)(.*)$", re.IGNORECASE|re.MULTILINE),
- r'\1\2\3\4'))
-regexes.append((re.compile(r"^(\s*)(\*set\s+(?:BLANK|COMMENT|DECIMAL|EOL|KEYWORD|MINUS|NAMES|OMIT|PLUS|ROOT|SEPARATOR))(\s+)(.*)$", re.IGNORECASE|re.MULTILINE),
- r'\1\2\3\4'))
-regexes.append((re.compile(r"^(\s*)(\*units\s+(?:TAPE|LENGTH|COMPASS|BEARING|CLINO|GRADIENT|COUNTER|DEPTH|DECLINATION|X|Y|Z))(\s+)(.*)$", re.IGNORECASE|re.MULTILINE),
- r'\1\2\3\4'))
-regexes.append((re.compile(r"^(.*)$", re.IGNORECASE|re.MULTILINE),
- r'\1
\n'))
-
-@register.filter()
-@stringfilter
-def survex_to_html(value, autoescape=None):
- if autoescape:
- value = conditional_escape(value)
- for regex, sub in regexes:
- print sub
- value = regex.sub(sub, value)
- return mark_safe(value)
\ No newline at end of file
diff --git a/troggle/expo/templatetags/wiki_markup.py b/troggle/expo/templatetags/wiki_markup.py
deleted file mode 100644
index 30c9a087f..000000000
--- a/troggle/expo/templatetags/wiki_markup.py
+++ /dev/null
@@ -1,101 +0,0 @@
-from django import template
-from django.utils.html import conditional_escape
-from django.template.defaultfilters import stringfilter
-from django.utils.safestring import mark_safe
-from django.conf import settings
-from expo.models import QM
-import re
-
-register = template.Library()
-
-def wiki_list(line, listdepth):
- l = ""
- for d in listdepth:
- l += d
- mstar = re.match(l + "\*(.*)", line)
- if mstar:
- listdepth.append("\*")
- return ("\n" + " " * len(listdepth) + "- %s
\n" % mstar.groups()[0], listdepth)
- mhash = re.match(l + "#(.*)", line)
- if mhash:
- listdepth.append("#")
- return ("\n" + " " * len(listdepth) + "- %s
\n" % mhash.groups()[0], listdepth)
- mflat = re.match(l + "(.*)", line)
- if mflat and listdepth:
- return (" " * len(listdepth) + "- %s
\n" % mflat.groups()[0], listdepth)
- if listdepth:
- prev = listdepth.pop()
- if prev == "\*":
- t, l = wiki_list(line, listdepth)
- return ("
\n" + t, l)
- if prev == "#":
- t, l = wiki_list(line, listdepth)
- return ("\n" + t, l)
- return (line, listdepth)
-
-@register.filter()
-@stringfilter
-def wiki_to_html(value, autoescape=None):
- #find paragraphs
- outValue = ""
- for paragraph in re.split("\n\s*?\n", value, re.DOTALL):
- outValue += ""
- outValue += wiki_to_html_short(paragraph, autoescape)
- outValue += "
\n"
- return mark_safe(outValue)
-
-@register.filter()
-@stringfilter
-def wiki_to_html_short(value, autoescape=None):
- if autoescape:
- value = conditional_escape(value)
- #deescape doubly escaped characters
- value = re.sub("&(.*?);", r"&\1;", value, re.DOTALL)
- #italics and bold
- value = re.sub("''''([^']+)''''", r"\1", value, re.DOTALL)
- value = re.sub("'''([^']+)'''", r"\1", value, re.DOTALL)
- value = re.sub("''([^']+)''", r"\1", value, re.DOTALL)
- #make cave links
- value = re.sub("\[\[\s*cave:([^\s]+)\s*\s*\]\]", r'\1' % settings.URL_ROOT, value, re.DOTALL)
-
-
- #function for replacing wikicode qm links with html qm links
- def qmrepl(matchobj):
- if len(matchobj.groups())==4:
- grade=matchobj.groups()[3]
- else:
- grade=''
- qmdict={'urlroot':settings.URL_ROOT,'cave':matchobj.groups()[0],'year':matchobj.groups()[1],'number':matchobj.groups()[2],'grade':grade}
- try:
- qm=QM.objects.get(found_by__cave__kataster_number=qmdict['cave'],found_by__date__year=qmdict['year'], number=qmdict['number'])
- url=r'' + str(qm) + ''
- except QM.DoesNotExist:
- url = r'%(cave)s:%(year)s-%(number)s%(grade)s' % qmdict
- return url
-
- #make qm links
- value = re.sub("\[\[\s*cave:([^\s]+)\s*\s*\QM:(\d*)-(\d*)([ABCDX]?)\]\]",qmrepl, value, re.DOTALL)
-
- #qms=qmfinder.search(value)
- #for qm in qms:
- #if QM.objects.filter(cave__kataster_number=qm[0], found_by__year=qm[1], number=qm[2]).count >= 1: # If there is at lesat one QM matching this query
- #replace qm with link in red
- #else
- #replace qm with link in blue
-
- #turn qm links red if nonexistant
-
- #Make lists from lines starting with lists of [stars and hashes]
- outValue = ""
- listdepth = []
- for line in value.split("\n"):
- t, listdepth = wiki_list(line, listdepth)
- outValue += t
- for item in listdepth:
- if item == "\*":
- outValue += "\n"
- elif item == "#":
- outValue += "\n"
- return mark_safe(outValue)
-
-wiki_to_html.needs_autoescape = True
diff --git a/troggle/expo/view_surveys.py b/troggle/expo/view_surveys.py
deleted file mode 100644
index 846b245fb..000000000
--- a/troggle/expo/view_surveys.py
+++ /dev/null
@@ -1,161 +0,0 @@
-from django.conf import settings
-import fileAbstraction
-from django.shortcuts import render_to_response
-from django.http import HttpResponse, Http404
-import os
-import re
-
-# inline fileabstraction into here if it's not going to be useful anywhere else
-# keep things simple and ignore exceptions everywhere for now
-
-def getMimeType(extension):
- try:
- return {"txt": "text/plain",
- "html": "text/html",
- }[extension]
- except:
- print "unknown file type"
- return "text/plain"
-
-
-def listdir(request, path):
- #try:
- return HttpResponse(fileAbstraction.listdir(path), mimetype = "text/plain")
- #except:
- # raise Http404
-
-def upload(request, path):
- pass
-
-def download(request, path):
- #try:
-
- return HttpResponse(fileAbstraction.readFile(path), mimetype=getMimeType(path.split(".")[-1]))
- #except:
- # raise Http404
-
-
-#
-# julian's quick hack for something that works
-# could signal directories by ending with /, and forward cases where it's missing
-#
-extmimetypes = {".txt": "text/plain",
- ".html": "text/html",
- ".png": "image/png",
- ".jpg": "image/jpeg",
- }
-
-def jgtfile(request, f):
- fp = os.path.join(settings.SURVEYS, f)
- # could also surf through SURVEX_DATA
-
- # directory listing
- if os.path.isdir(fp):
- listdirfiles = [ ]
- listdirdirs = [ ]
-
- for lf in sorted(os.listdir(fp)):
- hpath = os.path.join(f, lf) # not absolute path
- if lf[0] == "." or lf[-1] == "~":
- continue
-
- hpath = hpath.replace("\\", "/") # for windows users
- href = hpath.replace("#", "%23") # '#' in file name annoyance
-
- flf = os.path.join(fp, lf)
- if os.path.isdir(flf):
- nfiles = len([sf for sf in os.listdir(flf) if sf[0] != "."])
- listdirdirs.append((href, hpath + "/", nfiles))
- else:
- listdirfiles.append((href, hpath, os.path.getsize(flf)))
-
- upperdirs = [ ]
- lf = f
- while lf:
- hpath = lf.replace("\\", "/") # for windows users
- if hpath[-1] != "/":
- hpath += "/"
- href = hpath.replace("#", "%23")
- lf = os.path.split(lf)[0]
- upperdirs.append((href, hpath))
- upperdirs.append(("", "/"))
-
- return render_to_response('listdir.html', {'file':f, 'listdirfiles':listdirfiles, 'listdirdirs':listdirdirs, 'upperdirs':upperdirs, 'settings': settings})
-
- # flat output of file when loaded
- if os.path.isfile(fp):
- ext = os.path.splitext(fp)[1].lower()
- mimetype = extmimetypes.get(ext, "text/plain")
- fin = open(fp)
- ftext = fin.read()
- fin.close()
- return HttpResponse(ftext, mimetype=mimetype)
-
- return HttpResponse("unknown file::%s::" % f, mimetype = "text/plain")
-
-
-def UniqueFile(fname):
- while True:
- if not os.path.exists(fname):
- break
- mname = re.match("(.*?)(?:-(\d+))?\.(png|jpg|jpeg)$(?i)", fname)
- if mname:
- fname = "%s-%d.%s" % (mname.group(1), int(mname.group(2) or "0") + 1, mname.group(3))
- return fname
-
-
-# join it all up and then split them off for the directories that don't exist
-# anyway, this mkdir doesn't work
-def SaveImageInDir(name, imgdir, project, fdata, bbinary):
- print ("hihihihi", fdata, settings.SURVEYS)
- fimgdir = os.path.join(settings.SURVEYS, imgdir)
- if not os.path.isdir(fimgdir):
- print "*** Making directory", fimgdir
- os.path.mkdir(fimgdir)
- fprojdir = os.path.join(fimgdir, project)
- if not os.path.isdir(fprojdir):
- print "*** Making directory", fprojdir
- os.path.mkdir(fprojdir)
- print "hhh"
-
- fname = os.path.join(fprojdir, name)
- print fname, "fff"
- fname = UniqueFile(fname)
-
- p2, p1 = os.path.split(fname)
- p3, p2 = os.path.split(p2)
- p4, p3 = os.path.split(p3)
- res = os.path.join(p3, p2, p1)
-
- print "saving file", fname
- fout = open(fname, (bbinary and "wb" or "w"))
- fout.write(fdata.read())
- fout.close()
- res = os.path.join(imgdir, name)
- return res.replace("\\", "/")
-
-
-# do we want to consider saving project/field rather than field/project
-def jgtuploadfile(request):
- filesuploaded = [ ]
- project, user, password, tunnelversion = request.POST["tunnelproject"], request.POST["tunneluser"], request.POST["tunnelpassword"], request.POST["tunnelversion"]
- print (project, user, tunnelversion)
- for uploadedfile in request.FILES.values():
- if uploadedfile.field_name in ["tileimage", "backgroundimage"] and \
- uploadedfile.content_type in ["image/png", "image/jpeg"]:
- fname = user + "_" + re.sub("[\\\\/]", "-", uploadedfile.name) # very escaped \
- print fname
- fileuploaded = SaveImageInDir(fname, uploadedfile.field_name, project, uploadedfile, True)
- filesuploaded.append(settings.URL_ROOT + "/jgtfile/" + fileuploaded)
- if uploadedfile.field_name in ["sketch"] and \
- uploadedfile.content_type in ["text/plain"]:
- fname = user + "_" + re.sub("[\\\\/]", "-", uploadedfile.name) # very escaped \
- print fname
- fileuploaded = SaveImageInDir(fname, uploadedfile.field_name, project, uploadedfile, False)
- filesuploaded.append(settings.URL_ROOT + "/jgtfile/" + fileuploaded)
- #print "FF", request.FILES
- #print ("FFF", request.FILES.values())
- message = ""
- print "gothere"
- return render_to_response('fileupload.html', {'message':message, 'filesuploaded':filesuploaded, 'settings': settings})
-
diff --git a/troggle/expo/views.py b/troggle/expo/views.py
deleted file mode 100644
index 337989a92..000000000
--- a/troggle/expo/views.py
+++ /dev/null
@@ -1,8 +0,0 @@
-# primary namespace
-
-import view_surveys
-import views_caves
-import views_survex
-import views_logbooks
-import views_other
-
diff --git a/troggle/expo/views_caves.py b/troggle/expo/views_caves.py
deleted file mode 100644
index 691cdcb68..000000000
--- a/troggle/expo/views_caves.py
+++ /dev/null
@@ -1,96 +0,0 @@
-from troggle.expo.models import Cave, CaveAndEntrance, Survey, Expedition, QM
-import troggle.expo.models as models
-import troggle.settings as settings
-from django.forms.models import formset_factory
-import search
-from django.core.urlresolvers import reverse
-from troggle.alwaysUseRequestContext import render_response # see views_logbooks for explanation on this.
-from django.http import HttpResponseRedirect
-from django.conf import settings
-import re
-
-def getCave(cave_id):
- """Returns a cave object when given a cave name or number. It is used by views including cavehref, ent, and qm."""
- try:
- cave = Cave.objects.get(kataster_number=cave_id)
- except Cave.DoesNotExist:
- cave = Cave.objects.get(unofficial_number=cave_id)
- return cave
-
-def caveindex(request):
- caves = Cave.objects.all()
- notablecavehrefs = [ "161", "204", "258", "76" ] # could detect notability by trips and notability of people who have been down them
- notablecaves = [Cave.objects.get(kataster_number=kataster_number) for kataster_number in notablecavehrefs ]
- return render_response(request,'caveindex.html', {'caves': caves, 'notablecaves':notablecaves})
-
-def cave(request, cave_id='', offical_name=''):
- return render_response(request,'cave.html', {'cave': getCave(cave_id),})
-
-def qm(request,cave_id,qm_id,year,grade=None):
- year=int(year)
- try:
- qm=getCave(cave_id).get_QMs().get(number=qm_id,found_by__date__year=year)
- return render_response(request,'qm.html',locals())
-
- except QM.DoesNotExist:
- url= settings.URL_ROOT + r'/admin/expo/qm/add/?'+ r'number=' + qm_id
- if grade:
- url += r'&grade=' + grade
- return HttpResponseRedirect(url)
-
-
-def ent(request, cave_id, ent_letter):
- cave = Cave.objects.filter(kataster_number = cave_id)[0]
- cave_and_ent = CaveAndEntrance.objects.filter(cave = cave).filter(entrance_letter = ent_letter)[0]
- return render_response(request,'entrance.html', {'cave': cave,
- 'entrance': cave_and_ent.entrance,
- 'letter': cave_and_ent.entrance_letter,})
-
-def survexblock(request, survexpath):
- survexblock = models.SurvexBlock.objects.get(survexpath=survexpath)
- #ftext = survexblock.filecontents()
- ftext = survexblock.text
- return render_response(request,'survexblock.html', {'survexblock':survexblock, 'ftext':ftext, })
-
-def subcave(request, cave_id, subcave):
- print subcave
- subcaveSeq=re.findall('(?:/)([^/]*)',subcave)
- print subcaveSeq
- cave=models.Cave.objects.get(kataster_number = cave_id)
- subcave=models.Subcave.objects.get(name=subcaveSeq[0], cave=cave)
- if len(subcaveSeq)>1:
- for subcaveUrlSegment in subcaveSeq[1:]:
- if subcaveUrlSegment:
- subcave=subcave.children.get(name=subcaveUrlSegment)
- print subcave
- return render_response(request,'subcave.html', {'subcave': subcave,'cave':cave})
-
-def caveSearch(request):
- query_string = ''
- found_entries = None
- if ('q' in request.GET) and request.GET['q'].strip():
- query_string = request.GET['q']
- entry_query = search.get_query(query_string, ['underground_description','official_name',])
- found_entries = Cave.objects.filter(entry_query)
-
- return render_response(request,'cavesearch.html',
- { 'query_string': query_string, 'found_entries': found_entries,})
-
-def surveyindex(request):
- surveys=Survey.objects.all()
- expeditions=Expedition.objects.order_by("-year")
- return render_response(request,'survey.html',locals())
-
-def survey(request,year,wallet_number):
- surveys=Survey.objects.all()
- expeditions=Expedition.objects.order_by("-year")
- current_expedition=Expedition.objects.filter(year=year)[0]
-
- if wallet_number!='':
- current_survey=Survey.objects.filter(expedition=current_expedition,wallet_number=wallet_number)[0]
- notes=current_survey.scannedimage_set.filter(contents='notes')
- planSketches=current_survey.scannedimage_set.filter(contents='plan')
- elevationSketches=current_survey.scannedimage_set.filter(contents='elevation')
-
- return render_response(request,'survey.html', locals())
-
diff --git a/troggle/expo/views_logbooks.py b/troggle/expo/views_logbooks.py
deleted file mode 100644
index cfebd35e6..000000000
--- a/troggle/expo/views_logbooks.py
+++ /dev/null
@@ -1,120 +0,0 @@
-from django.shortcuts import render_to_response
-from troggle.expo.models import Expedition, Person, PersonExpedition, PersonTrip, LogbookEntry
-import troggle.settings as settings
-from django.db import models
-from troggle.parsers.logbooks import LoadLogbookForExpedition
-from troggle.parsers.people import GetPersonExpeditionNameLookup
-from troggle.expo.forms import PersonForm
-from django.core.urlresolvers import reverse
-from django.http import HttpResponseRedirect
-
-# Django uses Context, not RequestContext when you call render_to_response. We always want to use RequestContext, so that django adds the context from settings.TEMPLATE_CONTEXT_PROCESSORS. This way we automatically get necessary settings variables passed to each template. So we use a custom method, render_response instead of render_to_response. Hopefully future Django releases will make this unnecessary.
-from troggle.alwaysUseRequestContext import render_response
-
-import search
-import re
-
-@models.permalink #this allows the nice get_absolute_url syntax we are using
-
-def getNotablePersons():
- notablepersons = []
- for person in Person.objects.all():
- if person.bisnotable():
- notablepersons.append(person)
- return notablepersons
-
-def personindex(request):
- persons = Person.objects.all()
- # From what I can tell, "persons" seems to be the table rows, while "personss" is the table columns. - AC 16 Feb 09
- personss = [ ]
- ncols = 5
- nc = (len(persons) + ncols - 1) / ncols
- for i in range(ncols):
- personss.append(persons[i * nc: (i + 1) * nc])
-
- notablepersons = []
- for person in Person.objects.all():
- if person.bisnotable():
- notablepersons.append(person)
-
- return render_response(request,'personindex.html', {'persons': persons, 'personss':personss, 'notablepersons':notablepersons, })
-
-def expedition(request, expeditionname):
- year = int(expeditionname)
- expedition = Expedition.objects.get(year=year)
- expedition_next = Expedition.objects.filter(year=year+1) and Expedition.objects.get(year=year+1) or None
- expedition_prev = Expedition.objects.filter(year=year-1) and Expedition.objects.get(year=year-1) or None
- message = "No message"
- if "reload" in request.GET:
- message = LoadLogbookForExpedition(expedition)
- #message = str(GetPersonExpeditionNameLookup(expedition).keys())
- logbookentries = expedition.logbookentry_set.order_by('date')
- return render_response(request,'expedition.html', {'expedition': expedition, 'expedition_next':expedition_next, 'expedition_prev':expedition_prev, 'logbookentries':logbookentries, 'message':message, })
-
- def get_absolute_url(self):
- return ('expedition', (expedition.year))
-
-def person(request, first_name='', last_name='', ):
- person = Person.objects.get(first_name = first_name, last_name = last_name)
-
- #This is for removing the reference to the user's profile, in case they set it to the wrong person
- if request.method == 'GET':
- if request.GET.get('clear_profile')=='True':
- person.user=None
- person.save()
- return HttpResponseRedirect(reverse('profiles_select_profile'))
-
- return render_response(request,'person.html', {'person': person, })
-
- def get_absolute_url(self):
- return settings.URL_ROOT + self.first_name + '_' + self.last_name
-
-#def person(request, name):
-# person = Person.objects.get(href=name)
-#
-
-def personexpedition(request, first_name='', last_name='', year=''):
- person = Person.objects.get(first_name = first_name, last_name = last_name)
- expedition = Expedition.objects.get(year=year)
- personexpedition = person.personexpedition_set.get(expedition=expedition)
- return render_response(request,'personexpedition.html', {'personexpedition': personexpedition, })
-
-def newQMlink(logbookentry):
- biggestQMnumber=0
- if logbookentry.cave:
- for log in logbookentry.cave.logbookentry_set.all():
- try:
- biggestQMnumberInLog = logbookentry.QMs_found.order_by('-number')[0].number
- except IndexError:
- biggestQMnumberInLog = 0
- if biggestQMnumberInLog > biggestQMnumber:
- biggestQMnumber = biggestQMnumberInLog
- else:
- return None
-
-
-
- nextQMnumber=biggestQMnumber+1
- return settings.URL_ROOT + r'/admin/expo/qm/add/?' + r'found_by=' + str(logbookentry.pk) +'&number=' + str(nextQMnumber)
-
-def logbookentry(request, date, slug):
- logbookentry = LogbookEntry.objects.get(date=date, slug=slug)
-
- return render_response(request, 'logbookentry.html', {'logbookentry': logbookentry, 'newQMlink':newQMlink(logbookentry)})
-
-def logbookSearch(request, extra):
- query_string = ''
- found_entries = None
- if ('q' in request.GET) and request.GET['q'].strip():
- query_string = request.GET['q']
- entry_query = search.get_query(query_string, ['text','title',])
- found_entries = LogbookEntry.objects.filter(entry_query)
-
- return render_response(request,'logbooksearch.html',
- { 'query_string': query_string, 'found_entries': found_entries, })
- #context_instance=RequestContext(request))
-
-def personForm(request,pk):
- person=Person.objects.get(pk=pk)
- form=PersonForm(instance=person)
- return render_response(request,'personform.html', {'form':form,})
\ No newline at end of file
diff --git a/troggle/expo/views_other.py b/troggle/expo/views_other.py
deleted file mode 100644
index 0f8cb7935..000000000
--- a/troggle/expo/views_other.py
+++ /dev/null
@@ -1,70 +0,0 @@
-from troggle.expo.models import Cave, Expedition, Person, LogbookEntry, PersonExpedition, PersonTrip, Photo
-import troggle.settings as settings
-from django import forms
-from django.db.models import Q
-import databaseReset
-import re
-import randSent
-from django.http import HttpResponse
-
-from django.core.urlresolvers import reverse
-from troggle.alwaysUseRequestContext import render_response # see views_logbooks for explanation on this.
-
-def showrequest(request):
- return HttpResponse(request.GET)
-
-def stats(request):
- statsDict={}
- statsDict['expoCount'] = int(Expedition.objects.count())
- statsDict['caveCount'] = int(Cave.objects.count())
- statsDict['personCount'] = int(Person.objects.count())
- statsDict['logbookEntryCount'] = int(LogbookEntry.objects.count())
- return render_response(request,'statistics.html', statsDict)
-
-def frontpage(request):
- message = "no test message" #reverse('personn', kwargs={"name":"hkjhjh"})
- if "reloadexpos" in request.GET:
- message = LoadPersonsExpos()
- message = "Reloaded personexpos"
- if "reloadsurvex" in request.POST:
- message = LoadAllSurvexBlocks()
- message = "Reloaded survexblocks"
-
- #'randSent':randSent.randomLogbookSentence(),
- expeditions = Expedition.objects.order_by("-year")
- logbookentry = LogbookEntry
- cave = Cave
- photo = Photo
- return render_response(request,'frontpage.html', locals())
-
-def todo(request):
- message = "no test message" #reverse('personn', kwargs={"name":"hkjhjh"})
- if "reloadexpos" in request.GET:
- message = LoadPersonsExpos()
- message = "Reloaded personexpos"
- if "reloadsurvex" in request.POST:
- message = LoadAllSurvexBlocks()
- message = "Reloaded survexblocks"
-
- #'randSent':randSent.randomLogbookSentence(),
- expeditions = Expedition.objects.order_by("-year")
- totallogbookentries = LogbookEntry.objects.count()
- return render_response(request,'index.html', {'expeditions':expeditions, 'all':'all', 'totallogbookentries':totallogbookentries, "message":message})
-
-def calendar(request,year):
- week=['S','S','M','T','W','T','F']
- if year:
- expedition=Expedition.objects.get(year=year)
- PersonExpeditions=expedition.personexpedition_set.all()
-
- return render_response(request,'calendar.html', locals())
-
-def controlPanel(request):
- message = "no test message" #reverse('personn', kwargs={"name":"hkjhjh"})
- if request.method=='POST':
- for item in request.POST:
- if request.user.is_superuser and item!='item':
- print "running"+ " databaseReset."+item+"()"
- exec "databaseReset."+item+"()"
-
- return render_response(request,'controlPanel.html', )
\ No newline at end of file
diff --git a/troggle/expo/views_survex.py b/troggle/expo/views_survex.py
deleted file mode 100644
index 067d4e34c..000000000
--- a/troggle/expo/views_survex.py
+++ /dev/null
@@ -1,44 +0,0 @@
-from django.shortcuts import render_to_response
-from django.http import HttpResponse, Http404
-import re
-import os
-
-import troggle.settings as settings
-
-def index(request, survex_file):
- process(survex_file)
- f = open(settings.SURVEX_DATA + survex_file + ".svx", "rb")
- a = f.read()
- return render_to_response('svxfile.html', {'settings': settings,
- 'has_3d': os.path.isfile(settings.SURVEX_DATA + survex_file + ".3d"),
- 'title': survex_file,
- 'text': unicode(a, "latin1")})
-
-def svx(request, survex_file):
- svx = open(settings.SURVEX_DATA + survex_file + ".svx", "rb")
- return HttpResponse(svx, mimetype="text")
-
-def threed(request, survex_file):
- process(survex_file)
- try:
- threed = open(settings.SURVEX_DATA + survex_file + ".3d", "rb")
- return HttpResponse(threed, mimetype="model/3d")
- except:
- log = open(settings.SURVEX_DATA + survex_file + ".log", "rb")
- return HttpResponse(log, mimetype="text")
-
-def log(request, survex_file):
- process(survex_file)
- log = open(settings.SURVEX_DATA + survex_file + ".log", "rb")
- return HttpResponse(log, mimetype="text")
-
-def err(request, survex_file):
- process(survex_file)
- err = open(settings.SURVEX_DATA + survex_file + ".err", "rb")
- return HttpResponse(err, mimetype="text")
-
-def process(survex_file):
- cwd = os.getcwd()
- os.chdir(os.path.split(settings.SURVEX_DATA + survex_file)[0])
- os.system(settings.CAVERN + " --log " +settings.SURVEX_DATA + survex_file + ".svx")
- os.chdir(cwd)
diff --git a/troggle/export/__init__.py b/troggle/export/__init__.py
deleted file mode 100644
index e69de29bb..000000000
diff --git a/troggle/export/tocavetab.py b/troggle/export/tocavetab.py
deleted file mode 100644
index 121c36e4a..000000000
--- a/troggle/export/tocavetab.py
+++ /dev/null
@@ -1,52 +0,0 @@
-import troggle.expo.models as models
-from django.conf import settings
-
-import csv
-import re
-import os
-
-#format of CAVETAB2.CSV is
-headers=['KatasterNumber','KatStatusCode','Entrances','UnofficialNumber','MultipleEntrances','AutogenFile','LinkFile','LinkEntrance','Name','UnofficialName',
- 'Comment','Area','Explorers','UndergroundDescription','Equipment','QMList','KatasterStatus','References','UndergroundCentreLine','UndergroundDrawnSurvey',
- 'SurvexFile','Length','Depth','Extent','Notes','EntranceName','TagPoint','OtherPoint','DescriptionOfOtherPoint','ExactEntrance','TypeOfFix','GPSpreSA',
- 'GPSpostSA','Northing','Easting','Altitude','Bearings','Map','Location','Approach','EntranceDescription','PhotoOfLocation','Marking','MarkingComment',
- 'Findability','FindabilityComment']
-
-def cavetabRow(cave):
- #mapping of troggle models to table columns is: (guess this could just be a tuple of tuples rather than a dictionary actually)
- columnsToModelFields={
- 'Name':cave.official_name,
- 'Area':cave.kat_area(),
- 'KatStatusCode':cave.kataster_code,
- 'KatasterNumber':cave.kataster_number,
- 'UnofficialNumber':cave.unofficial_number,
- #'' : cave.entrances This is a multiple foreignkey now, may be tricky to dump back into csv. Work on this.
- 'Explorers':cave.explorers,
- 'UndergroundDescription':cave.underground_description,
- 'Equipment':cave.equipment,
- 'References':cave.references,
- 'UndergroundDrawnSurvey':cave.survey,
- 'KatasterStatus':cave.kataster_status,
- 'UndergroundCentreLine':cave.underground_centre_line,
- 'Notes':cave.notes,
- 'Length':cave.length,
- 'Depth':cave.depth,
- 'Extent':cave.extent,
- 'SurvexFile':cave.survex_file,
- }
-
- caveRow=['' for x in range(len(headers))]
- for column, modelField in columnsToModelFields.items():
- if modelField:
- # Very sorry about the atrocious replace below. I will fix this soon if noone beats me to it. - AC
- caveRow[headers.index(column)]=modelField.replace(u'\xd7','x').replace(u'\u201c','').replace(u'\u2013','').replace(u'\xbd','')
- return caveRow
-
-def writeCaveTab(path):
- outfile=file(path,'w')
- cavewriter=csv.writer(outfile,lineterminator='\r')
- cavewriter.writerow(headers)
- for cave in models.Cave.objects.all():
- cavewriter.writerow(cavetabRow(cave))
-
-
diff --git a/troggle/export/tologbooks.py b/troggle/export/tologbooks.py
deleted file mode 100644
index e69de29bb..000000000
diff --git a/troggle/export/toqms.py b/troggle/export/toqms.py
deleted file mode 100644
index 0597da6d3..000000000
--- a/troggle/export/toqms.py
+++ /dev/null
@@ -1,37 +0,0 @@
-import troggle.expo.models as models
-from django.conf import settings
-
-import csv
-import re
-import os
-
-#format of QM tables
-headers=['Number','Grade','Area','Description','Page reference','Nearest station','Completion description','Comment']
-
-def qmRow(qm):
- #mapping of troggle models to table columns is: (guess this could just be a tuple of tuples rather than a dictionary actually)
- columnsToModelFields={
- 'Number':str(qm.number),
- 'Grade':qm.grade,
- 'Area':qm.area,
- 'Description':qm.location_description,
- #'Page reference': #not implemented
- 'Nearest station':qm.nearest_station_description,
- 'Completion description':qm.completion_description,
- 'Comment':qm.comment
- }
-
- qmRow=['' for x in range(len(headers))]
- for column, modelField in columnsToModelFields.items():
- if modelField:
- # Very sorry about the atrocious replace below. I will fix this soon if noone beats me to it. - AC
- qmRow[headers.index(column)]=modelField.replace(u'\xd7','x').replace(u'\u201c','').replace(u'\u2013','').replace(u'\xbd','')
- return qmRow
-
-def writeQmTable(path,cave):
- outfile=file(path,'w')
- cavewriter=csv.writer(outfile,lineterminator='\r')
- cavewriter.writerow(headers)
- for qm in cave.get_QMs():
- cavewriter.writerow(qmRow(qm))
-
\ No newline at end of file
diff --git a/troggle/imagekit/__init__.py b/troggle/imagekit/__init__.py
deleted file mode 100644
index 2965bbd70..000000000
--- a/troggle/imagekit/__init__.py
+++ /dev/null
@@ -1,13 +0,0 @@
-"""
-
-Django ImageKit
-
-Author: Justin Driscoll
-Version: 0.2
-
-"""
-VERSION = "0.2"
-
-
-
-
\ No newline at end of file
diff --git a/troggle/imagekit/defaults.py b/troggle/imagekit/defaults.py
deleted file mode 100644
index e1a05f600..000000000
--- a/troggle/imagekit/defaults.py
+++ /dev/null
@@ -1,21 +0,0 @@
-""" Default ImageKit configuration """
-
-from imagekit.specs import ImageSpec
-from imagekit import processors
-
-class ResizeThumbnail(processors.Resize):
- width = 100
- height = 50
- crop = True
-
-class EnhanceSmall(processors.Adjustment):
- contrast = 1.2
- sharpness = 1.1
-
-class SampleReflection(processors.Reflection):
- size = 0.5
- background_color = "#000000"
-
-class DjangoAdminThumbnail(ImageSpec):
- access_as = 'admin_thumbnail'
- processors = [ResizeThumbnail, EnhanceSmall, SampleReflection]
diff --git a/troggle/imagekit/lib.py b/troggle/imagekit/lib.py
deleted file mode 100644
index 65646a44e..000000000
--- a/troggle/imagekit/lib.py
+++ /dev/null
@@ -1,17 +0,0 @@
-# Required PIL classes may or may not be available from the root namespace
-# depending on the installation method used.
-try:
- import Image
- import ImageFile
- import ImageFilter
- import ImageEnhance
- import ImageColor
-except ImportError:
- try:
- from PIL import Image
- from PIL import ImageFile
- from PIL import ImageFilter
- from PIL import ImageEnhance
- from PIL import ImageColor
- except ImportError:
- raise ImportError('ImageKit was unable to import the Python Imaging Library. Please confirm it`s installed and available on your current Python path.')
\ No newline at end of file
diff --git a/troggle/imagekit/management/__init__.py b/troggle/imagekit/management/__init__.py
deleted file mode 100644
index 8b1378917..000000000
--- a/troggle/imagekit/management/__init__.py
+++ /dev/null
@@ -1 +0,0 @@
-
diff --git a/troggle/imagekit/management/commands/__init__.py b/troggle/imagekit/management/commands/__init__.py
deleted file mode 100644
index 8b1378917..000000000
--- a/troggle/imagekit/management/commands/__init__.py
+++ /dev/null
@@ -1 +0,0 @@
-
diff --git a/troggle/imagekit/management/commands/ikflush.py b/troggle/imagekit/management/commands/ikflush.py
deleted file mode 100644
index c03440f43..000000000
--- a/troggle/imagekit/management/commands/ikflush.py
+++ /dev/null
@@ -1,38 +0,0 @@
-from django.db.models.loading import cache
-from django.core.management.base import BaseCommand, CommandError
-from optparse import make_option
-from imagekit.models import ImageModel
-from imagekit.specs import ImageSpec
-
-
-class Command(BaseCommand):
- help = ('Clears all ImageKit cached files.')
- args = '[apps]'
- requires_model_validation = True
- can_import_settings = True
-
- def handle(self, *args, **options):
- return flush_cache(args, options)
-
-def flush_cache(apps, options):
- """ Clears the image cache
-
- """
- apps = [a.strip(',') for a in apps]
- if apps:
- print 'Flushing cache for %s...' % ', '.join(apps)
- else:
- print 'Flushing caches...'
-
- for app_label in apps:
- app = cache.get_app(app_label)
- models = [m for m in cache.get_models(app) if issubclass(m, ImageModel)]
-
- for model in models:
- for obj in model.objects.all():
- for spec in model._ik.specs:
- prop = getattr(obj, spec.name(), None)
- if prop is not None:
- prop._delete()
- if spec.pre_cache:
- prop._create()
diff --git a/troggle/imagekit/models.py b/troggle/imagekit/models.py
deleted file mode 100644
index 140715ebc..000000000
--- a/troggle/imagekit/models.py
+++ /dev/null
@@ -1,136 +0,0 @@
-import os
-from datetime import datetime
-from django.conf import settings
-from django.core.files.base import ContentFile
-from django.db import models
-from django.db.models.base import ModelBase
-from django.utils.translation import ugettext_lazy as _
-
-from imagekit import specs
-from imagekit.lib import *
-from imagekit.options import Options
-from imagekit.utils import img_to_fobj
-
-# Modify image file buffer size.
-ImageFile.MAXBLOCK = getattr(settings, 'PIL_IMAGEFILE_MAXBLOCK', 256 * 2 ** 10)
-
-# Choice tuples for specifying the crop origin.
-# These are provided for convenience.
-CROP_HORZ_CHOICES = (
- (0, _('left')),
- (1, _('center')),
- (2, _('right')),
-)
-
-CROP_VERT_CHOICES = (
- (0, _('top')),
- (1, _('center')),
- (2, _('bottom')),
-)
-
-
-class ImageModelBase(ModelBase):
- """ ImageModel metaclass
-
- This metaclass parses IKOptions and loads the specified specification
- module.
-
- """
- def __init__(cls, name, bases, attrs):
- parents = [b for b in bases if isinstance(b, ImageModelBase)]
- if not parents:
- return
- user_opts = getattr(cls, 'IKOptions', None)
- opts = Options(user_opts)
- try:
- module = __import__(opts.spec_module, {}, {}, [''])
- except ImportError:
- raise ImportError('Unable to load imagekit config module: %s' % \
- opts.spec_module)
- for spec in [spec for spec in module.__dict__.values() \
- if isinstance(spec, type) \
- and issubclass(spec, specs.ImageSpec) \
- and spec != specs.ImageSpec]:
- setattr(cls, spec.name(), specs.Descriptor(spec))
- opts.specs.append(spec)
- setattr(cls, '_ik', opts)
-
-
-class ImageModel(models.Model):
- """ Abstract base class implementing all core ImageKit functionality
-
- Subclasses of ImageModel are augmented with accessors for each defined
- image specification and can override the inner IKOptions class to customize
- storage locations and other options.
-
- """
- __metaclass__ = ImageModelBase
-
- class Meta:
- abstract = True
-
- class IKOptions:
- pass
-
- def admin_thumbnail_view(self):
- if not self._imgfield:
- return None
- prop = getattr(self, self._ik.admin_thumbnail_spec, None)
- if prop is None:
- return 'An "%s" image spec has not been defined.' % \
- self._ik.admin_thumbnail_spec
- else:
- if hasattr(self, 'get_absolute_url'):
- return u'
' % \
- (self.get_absolute_url(), prop.url)
- else:
- return u'
' % \
- (self._imgfield.url, prop.url)
- admin_thumbnail_view.short_description = _('Thumbnail')
- admin_thumbnail_view.allow_tags = True
-
- @property
- def _imgfield(self):
- return getattr(self, self._ik.image_field)
-
- def _clear_cache(self):
- for spec in self._ik.specs:
- prop = getattr(self, spec.name())
- prop._delete()
-
- def _pre_cache(self):
- for spec in self._ik.specs:
- if spec.pre_cache:
- prop = getattr(self, spec.name())
- prop._create()
-
- def save(self, clear_cache=True, *args, **kwargs):
- is_new_object = self._get_pk_val is None
- super(ImageModel, self).save(*args, **kwargs)
- if is_new_object:
- clear_cache = False
- spec = self._ik.preprocessor_spec
- if spec is not None:
- newfile = self._imgfield.storage.open(str(self._imgfield))
- img = Image.open(newfile)
- img = spec.process(img, None)
- format = img.format or 'JPEG'
- if format != 'JPEG':
- imgfile = img_to_fobj(img, format)
- else:
- imgfile = img_to_fobj(img, format,
- quality=int(spec.quality),
- optimize=True)
- content = ContentFile(imgfile.read())
- newfile.close()
- name = str(self._imgfield)
- self._imgfield.storage.delete(name)
- self._imgfield.storage.save(name, content)
- if clear_cache and self._imgfield != '':
- self._clear_cache()
- self._pre_cache()
-
- def delete(self):
- assert self._get_pk_val() is not None, "%s object can't be deleted because its %s attribute is set to None." % (self._meta.object_name, self._meta.pk.attname)
- self._clear_cache()
- models.Model.delete(self)
diff --git a/troggle/imagekit/options.py b/troggle/imagekit/options.py
deleted file mode 100644
index 022cc9ef6..000000000
--- a/troggle/imagekit/options.py
+++ /dev/null
@@ -1,23 +0,0 @@
-# Imagekit options
-from imagekit import processors
-from imagekit.specs import ImageSpec
-
-
-class Options(object):
- """ Class handling per-model imagekit options
-
- """
- image_field = 'image'
- crop_horz_field = 'crop_horz'
- crop_vert_field = 'crop_vert'
- preprocessor_spec = None
- cache_dir = 'cache'
- save_count_as = None
- cache_filename_format = "%(filename)s_%(specname)s.%(extension)s"
- admin_thumbnail_spec = 'admin_thumbnail'
- spec_module = 'imagekit.defaults'
-
- def __init__(self, opts):
- for key, value in opts.__dict__.iteritems():
- setattr(self, key, value)
- self.specs = []
\ No newline at end of file
diff --git a/troggle/imagekit/processors.py b/troggle/imagekit/processors.py
deleted file mode 100644
index 6f6b480ef..000000000
--- a/troggle/imagekit/processors.py
+++ /dev/null
@@ -1,134 +0,0 @@
-""" Imagekit Image "ImageProcessors"
-
-A processor defines a set of class variables (optional) and a
-class method named "process" which processes the supplied image using
-the class properties as settings. The process method can be overridden as well allowing user to define their
-own effects/processes entirely.
-
-"""
-from imagekit.lib import *
-
-class ImageProcessor(object):
- """ Base image processor class """
- @classmethod
- def process(cls, image, obj=None):
- return image
-
-
-class Adjustment(ImageProcessor):
- color = 1.0
- brightness = 1.0
- contrast = 1.0
- sharpness = 1.0
-
- @classmethod
- def process(cls, image, obj=None):
- for name in ['Color', 'Brightness', 'Contrast', 'Sharpness']:
- factor = getattr(cls, name.lower())
- if factor != 1.0:
- image = getattr(ImageEnhance, name)(image).enhance(factor)
- return image
-
-
-class Reflection(ImageProcessor):
- background_color = '#FFFFFF'
- size = 0.0
- opacity = 0.6
-
- @classmethod
- def process(cls, image, obj=None):
- # convert bgcolor string to rgb value
- background_color = ImageColor.getrgb(cls.background_color)
- # copy orignial image and flip the orientation
- reflection = image.copy().transpose(Image.FLIP_TOP_BOTTOM)
- # create a new image filled with the bgcolor the same size
- background = Image.new("RGB", image.size, background_color)
- # calculate our alpha mask
- start = int(255 - (255 * cls.opacity)) # The start of our gradient
- steps = int(255 * cls.size) # the number of intermedite values
- increment = (255 - start) / float(steps)
- mask = Image.new('L', (1, 255))
- for y in range(255):
- if y < steps:
- val = int(y * increment + start)
- else:
- val = 255
- mask.putpixel((0, y), val)
- alpha_mask = mask.resize(image.size)
- # merge the reflection onto our background color using the alpha mask
- reflection = Image.composite(background, reflection, alpha_mask)
- # crop the reflection
- reflection_height = int(image.size[1] * cls.size)
- reflection = reflection.crop((0, 0, image.size[0], reflection_height))
- # create new image sized to hold both the original image and the reflection
- composite = Image.new("RGB", (image.size[0], image.size[1]+reflection_height), background_color)
- # paste the orignal image and the reflection into the composite image
- composite.paste(image, (0, 0))
- composite.paste(reflection, (0, image.size[1]))
- # return the image complete with reflection effect
- return composite
-
-
-class Resize(ImageProcessor):
- width = None
- height = None
- crop = False
- upscale = False
-
- @classmethod
- def process(cls, image, obj=None):
- cur_width, cur_height = image.size
- if cls.crop:
- crop_horz = getattr(obj, obj._ik.crop_horz_field, 1)
- crop_vert = getattr(obj, obj._ik.crop_vert_field, 1)
- ratio = max(float(cls.width)/cur_width, float(cls.height)/cur_height)
- resize_x, resize_y = ((cur_width * ratio), (cur_height * ratio))
- crop_x, crop_y = (abs(cls.width - resize_x), abs(cls.height - resize_y))
- x_diff, y_diff = (int(crop_x / 2), int(crop_y / 2))
- box_left, box_right = {
- 0: (0, cls.width),
- 1: (int(x_diff), int(x_diff + cls.width)),
- 2: (int(crop_x), int(resize_x)),
- }[crop_horz]
- box_upper, box_lower = {
- 0: (0, cls.height),
- 1: (int(y_diff), int(y_diff + cls.height)),
- 2: (int(crop_y), int(resize_y)),
- }[crop_vert]
- box = (box_left, box_upper, box_right, box_lower)
- image = image.resize((int(resize_x), int(resize_y)), Image.ANTIALIAS).crop(box)
- else:
- if not cls.width is None and not cls.height is None:
- ratio = min(float(cls.width)/cur_width,
- float(cls.height)/cur_height)
- else:
- if cls.width is None:
- ratio = float(cls.height)/cur_height
- else:
- ratio = float(cls.width)/cur_width
- new_dimensions = (int(round(cur_width*ratio)),
- int(round(cur_height*ratio)))
- if new_dimensions[0] > cur_width or \
- new_dimensions[1] > cur_height:
- if not cls.upscale:
- return image
- image = image.resize(new_dimensions, Image.ANTIALIAS)
- return image
-
-
-class Transpose(ImageProcessor):
- """ Rotates or flips the image
-
- Method should be one of the following strings:
- - FLIP_LEFT RIGHT
- - FLIP_TOP_BOTTOM
- - ROTATE_90
- - ROTATE_270
- - ROTATE_180
-
- """
- method = 'FLIP_LEFT_RIGHT'
-
- @classmethod
- def process(cls, image, obj=None):
- return image.transpose(getattr(Image, cls.method))
diff --git a/troggle/imagekit/specs.py b/troggle/imagekit/specs.py
deleted file mode 100644
index a6832ba9d..000000000
--- a/troggle/imagekit/specs.py
+++ /dev/null
@@ -1,119 +0,0 @@
-""" ImageKit image specifications
-
-All imagekit specifications must inherit from the ImageSpec class. Models
-inheriting from ImageModel will be modified with a descriptor/accessor for each
-spec found.
-
-"""
-import os
-from StringIO import StringIO
-from imagekit.lib import *
-from imagekit.utils import img_to_fobj
-from django.core.files.base import ContentFile
-
-class ImageSpec(object):
- pre_cache = False
- quality = 70
- increment_count = False
- processors = []
-
- @classmethod
- def name(cls):
- return getattr(cls, 'access_as', cls.__name__.lower())
-
- @classmethod
- def process(cls, image, obj):
- processed_image = image.copy()
- for proc in cls.processors:
- processed_image = proc.process(processed_image, obj)
- return processed_image
-
-
-class Accessor(object):
- def __init__(self, obj, spec):
- self._img = None
- self._obj = obj
- self.spec = spec
-
- def _get_imgfile(self):
- format = self._img.format or 'JPEG'
- if format != 'JPEG':
- imgfile = img_to_fobj(self._img, format)
- else:
- imgfile = img_to_fobj(self._img, format,
- quality=int(self.spec.quality),
- optimize=True)
- return imgfile
-
- def _create(self):
- if self._exists():
- return
- # process the original image file
- fp = self._obj._imgfield.storage.open(self._obj._imgfield.name)
- fp.seek(0)
- fp = StringIO(fp.read())
- try:
- self._img = self.spec.process(Image.open(fp), self._obj)
- # save the new image to the cache
- content = ContentFile(self._get_imgfile().read())
- self._obj._imgfield.storage.save(self.name, content)
- except IOError:
- pass
-
- def _delete(self):
- self._obj._imgfield.storage.delete(self.name)
-
- def _exists(self):
- return self._obj._imgfield.storage.exists(self.name)
-
- def _basename(self):
- filename, extension = \
- os.path.splitext(os.path.basename(self._obj._imgfield.name))
- return self._obj._ik.cache_filename_format % \
- {'filename': filename,
- 'specname': self.spec.name(),
- 'extension': extension.lstrip('.')}
-
- @property
- def name(self):
- return os.path.join(self._obj._ik.cache_dir, self._basename())
-
- @property
- def url(self):
- self._create()
- if self.spec.increment_count:
- fieldname = self._obj._ik.save_count_as
- if fieldname is not None:
- current_count = getattr(self._obj, fieldname)
- setattr(self._obj, fieldname, current_count + 1)
- self._obj.save(clear_cache=False)
- return self._obj._imgfield.storage.url(self.name)
-
- @property
- def file(self):
- self._create()
- return self._obj._imgfield.storage.open(self.name)
-
- @property
- def image(self):
- if self._img is None:
- self._create()
- if self._img is None:
- self._img = Image.open(self.file)
- return self._img
-
- @property
- def width(self):
- return self.image.size[0]
-
- @property
- def height(self):
- return self.image.size[1]
-
-
-class Descriptor(object):
- def __init__(self, spec):
- self._spec = spec
-
- def __get__(self, obj, type=None):
- return Accessor(obj, self._spec)
diff --git a/troggle/imagekit/tests.py b/troggle/imagekit/tests.py
deleted file mode 100644
index 8c2eb5ea5..000000000
--- a/troggle/imagekit/tests.py
+++ /dev/null
@@ -1,86 +0,0 @@
-import os
-import tempfile
-import unittest
-from django.conf import settings
-from django.core.files.base import ContentFile
-from django.db import models
-from django.test import TestCase
-
-from imagekit import processors
-from imagekit.models import ImageModel
-from imagekit.specs import ImageSpec
-from imagekit.lib import Image
-
-
-class ResizeToWidth(processors.Resize):
- width = 100
-
-class ResizeToHeight(processors.Resize):
- height = 100
-
-class ResizeToFit(processors.Resize):
- width = 100
- height = 100
-
-class ResizeCropped(ResizeToFit):
- crop = ('center', 'center')
-
-class TestResizeToWidth(ImageSpec):
- access_as = 'to_width'
- processors = [ResizeToWidth]
-
-class TestResizeToHeight(ImageSpec):
- access_as = 'to_height'
- processors = [ResizeToHeight]
-
-class TestResizeCropped(ImageSpec):
- access_as = 'cropped'
- processors = [ResizeCropped]
-
-class TestPhoto(ImageModel):
- """ Minimal ImageModel class for testing """
- image = models.ImageField(upload_to='images')
-
- class IKOptions:
- spec_module = 'imagekit.tests'
-
-
-class IKTest(TestCase):
- """ Base TestCase class """
- def setUp(self):
- # create a test image using tempfile and PIL
- self.tmp = tempfile.TemporaryFile()
- Image.new('RGB', (800, 600)).save(self.tmp, 'JPEG')
- self.tmp.seek(0)
- self.p = TestPhoto()
- self.p.image.save(os.path.basename('test.jpg'),
- ContentFile(self.tmp.read()))
- self.p.save()
- # destroy temp file
- self.tmp.close()
-
- def test_setup(self):
- self.assertEqual(self.p.image.width, 800)
- self.assertEqual(self.p.image.height, 600)
-
- def test_to_width(self):
- self.assertEqual(self.p.to_width.width, 100)
- self.assertEqual(self.p.to_width.height, 75)
-
- def test_to_height(self):
- self.assertEqual(self.p.to_height.width, 133)
- self.assertEqual(self.p.to_height.height, 100)
-
- def test_crop(self):
- self.assertEqual(self.p.cropped.width, 100)
- self.assertEqual(self.p.cropped.height, 100)
-
- def test_url(self):
- tup = (settings.MEDIA_URL, self.p._ik.cache_dir, 'test_to_width.jpg')
- self.assertEqual(self.p.to_width.url, "%s%s/%s" % tup)
-
- def tearDown(self):
- # make sure image file is deleted
- path = self.p.image.path
- self.p.delete()
- self.failIf(os.path.isfile(path))
diff --git a/troggle/imagekit/utils.py b/troggle/imagekit/utils.py
deleted file mode 100644
index 352d40ff2..000000000
--- a/troggle/imagekit/utils.py
+++ /dev/null
@@ -1,15 +0,0 @@
-""" ImageKit utility functions """
-
-import tempfile
-
-def img_to_fobj(img, format, **kwargs):
- tmp = tempfile.TemporaryFile()
- if format != 'JPEG':
- try:
- img.save(tmp, format, **kwargs)
- return
- except KeyError:
- pass
- img.save(tmp, format, **kwargs)
- tmp.seek(0)
- return tmp
diff --git a/troggle/localsettingsserver.py b/troggle/localsettingsserver.py
deleted file mode 100644
index 4148336ca..000000000
--- a/troggle/localsettingsserver.py
+++ /dev/null
@@ -1,31 +0,0 @@
-DATABASE_ENGINE = 'mysql' # 'postgresql_psycopg2', 'postgresql', 'mysql', 'sqlite3' or 'oracle'.
-DATABASE_NAME = 'troggle' # Or path to database file if using sqlite3.
-DATABASE_USER = 'undemocracy' # Not used with sqlite3.
-DATABASE_PASSWORD = 'aiGohsh5' # Not used with sqlite3.
-DATABASE_HOST = '' # Set to empty string for localhost. Not used with sqlite3.
-DATABASE_PORT = '' # Set to empty string for default. Not used with sqlite3.
-
-SURVEX_DATA = '/home/mjg/loser/'
-CAVERN = 'cavern'
-EXPOWEB = '/home/mjg/expoweb/'
-SURVEYS = '/home/mjg/surveys/'
-
-SURVEYS_URL = 'http://framos.lawoftheland.co.uk/troggle/survey_scans/'
-FILES = "http://framos.lawoftheland.co.uk/troggle/survey_files/"
-
-SVX_URL = 'http://framos.lawoftheland.co.uk/troggle/survex/'
-
-PYTHON_PATH = '/home/mjg/expoweb/troggle/'
-
-MEDIA_URL = 'http://framos.lawoftheland.co.uk/troggle/site_media/'
-
-MEDIA_ROOT = '/home/mjg/expoweb/troggle/media/'
-
-URL_ROOT = "http://framos.lawoftheland.co.uk/troggle/"
-
-TEMPLATE_DIRS = (
- "/home/mjg/expoweb/troggle/templates",
- # 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.
-)
diff --git a/troggle/localsettingsubuntu.py b/troggle/localsettingsubuntu.py
deleted file mode 100644
index 22d3d2c3f..000000000
--- a/troggle/localsettingsubuntu.py
+++ /dev/null
@@ -1,20 +0,0 @@
-DATABASE_ENGINE = 'mysql' # 'postgresql_psycopg2', 'postgresql', 'mysql', 'sqlite3' or 'oracle'.
-DATABASE_NAME = 'troggle' # Or path to database file if using sqlite3.
-DATABASE_USER = 'troggler3' # Not used with sqlite3.
-DATABASE_PASSWORD = 'ggg' # Not used with sqlite3.
-DATABASE_HOST = '' # Set to empty string for localhost. Not used with sqlite3.
-DATABASE_PORT = '' # Set to empty string for default. Not used with sqlite3.
-PYTHON_PATH = '/home/goatchurch/expoweb/troggle/'
-
-SURVEX_DATA = '/home/goatchurch/loser/'
-CAVERN = 'cavern'
-EXPOWEB = '/home/goatchurch/expoweb'
-URL_ROOT = '/troggle/'
-
-TEMPLATE_DIRS = (
- "/home/goatchurch/expoweb/troggle/templates",
- # 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.
-)
-
diff --git a/troggle/localsettingswindows.py b/troggle/localsettingswindows.py
deleted file mode 100644
index 53225b2a1..000000000
--- a/troggle/localsettingswindows.py
+++ /dev/null
@@ -1,49 +0,0 @@
-DATABASE_ENGINE = '' # 'postgresql_psycopg2', 'postgresql', 'mysql', 'sqlite3' or 'oracle'.
-DATABASE_NAME = '' # Or path to database file if using sqlite3.
-DATABASE_USER = '' # Not used with sqlite3.
-DATABASE_PASSWORD = '' # Not used with sqlite3.
-DATABASE_HOST = '' # Set to empty string for localhost. Not used with sqlite3.
-DATABASE_PORT = '' # Set to empty string for default. Not used with sqlite3.
-
-SURVEX_DATA = 'c:\\Expo\\loser\\'
-CAVERN = 'cavern'
-EXPOWEB = 'C:\\Expo\\expoweb\\'
-SURVEYS = 'E:\\surveys\\'
-SURVEY_SCANS = 'E:\\surveys\\surveyscans'
-
-LOGFILE = open(EXPOWEB+'troggle\\parsing_log.txt',"a+b")
-
-PHOTOS = 'C:\\Expo\\expoweb\\photos'
-
-URL_ROOT = 'http://127.0.0.1:8000'
-
-PYTHON_PATH = 'C:\\expoweb\\troggle\\'
-
-MEDIA_ROOT = 'C:/Expo/expoweb/troggle/media/'
-
-#FILES = "http://framos.lawoftheland.co.uk/troggle/survey_files/"
-
-EMAIL_HOST = "smtp.gmail.com"
-
-EMAIL_HOST_USER = "cuccexpo@gmail.com"
-
-EMAIL_HOST_PASSWORD = ""
-
-EMAIL_PORT=587
-
-EMAIL_USE_TLS = True
-
-# 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/"
-
-
-
-
-TEMPLATE_DIRS = (
- "C:/Expo/expoweb/troggle/templates",
-
- # 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.
-)
\ No newline at end of file
diff --git a/troggle/manage.py b/troggle/manage.py
deleted file mode 100644
index b8c4be8eb..000000000
--- a/troggle/manage.py
+++ /dev/null
@@ -1,11 +0,0 @@
-#!/usr/bin/env python
-from django.core.management import execute_manager
-try:
- import settings # Assumed to be in the same directory.
-except ImportError:
- import sys
- sys.stderr.write("Error: Can't find the file 'settings.py' in the directory containing %r. It appears you've customized things.\nYou'll have to run django-admin.py, passing it your settings module.\n(If the file settings.py does indeed exist, it's causing an ImportError somehow.)\n" % __file__)
- sys.exit(1)
-
-if __name__ == "__main__":
- execute_manager(settings)
diff --git a/troggle/media/204plan.gif b/troggle/media/204plan.gif
deleted file mode 100644
index b89da049c0fad4a249b8d16ab4f5ad13a3a34f42..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001
literal 39181
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