Move src/web to src/webapp to make it more clear what this dir is for
svn: r18327
This commit is contained in:
38
src/webapp/Makefile
Normal file
38
src/webapp/Makefile
Normal file
@@ -0,0 +1,38 @@
|
||||
# Initialize GRAMPS Django site
|
||||
|
||||
update: grampsdb/fixtures/initial_data.json
|
||||
PYTHONPATH=../../src python manage.py syncdb
|
||||
|
||||
grampsdb/fixtures/initial_data.json:
|
||||
PYTHONPATH=../../src python init.py > grampsdb/fixtures/initial_data.json
|
||||
|
||||
init_gramps:
|
||||
PYTHONPATH=../../src python init_gramps.py # clear primary and secondary tables
|
||||
|
||||
run:
|
||||
PYTHONPATH=../../src python manage.py runserver
|
||||
|
||||
sql:
|
||||
PYTHONPATH=../../src python manage.py sqlall > gramps_sql.txt
|
||||
|
||||
docs:
|
||||
mkdir -p docs
|
||||
python manage.py graph_models grampsdb -i Person,Family,Source,Event,Repository,Place,Media,Note -o docs/primary-tables.png
|
||||
python manage.py graph_models grampsdb -i Note -o docs/note-table.png
|
||||
python manage.py graph_models grampsdb -i Media -o docs/media-table.png
|
||||
python manage.py graph_models grampsdb -i Place -o docs/place-table.png
|
||||
python manage.py graph_models grampsdb -i Repository -o docs/repository-table.png
|
||||
python manage.py graph_models grampsdb -i Event -o docs/event-table.png
|
||||
python manage.py graph_models grampsdb -i Source -o docs/source-table.png
|
||||
python manage.py graph_models grampsdb -i Family -o docs/family-table.png
|
||||
python manage.py graph_models grampsdb -i Person -o docs/person-table.png
|
||||
python manage.py graph_models grampsdb -o docs/all-tables.png
|
||||
python manage.py graph_models grampsdb -i Attribute,Datamap,Name,Lds,Tag,Address,Location,Url -o docs/secondary-tables.png
|
||||
python manage.py graph_models grampsdb -i Person,Family,Source,Event,Repository,Place,Media,Note,Attribute,Datamap,Name,Lds,Tag,Address,Location,Url -o docs/prim-sec-tables.png
|
||||
python manage.py graph_models grampsdb -i Person,Family,Source,Event,Repository,Place,Media,Note,Attribute,Datamap,Name,Lds,Tag,Address,Location,Url -o docs/prim-sec-tables.png
|
||||
python manage.py graph_models grampsdb -i Person,Family,Source,Event,Repository,Place,Media,Note,Attribute,Datamap,Name,Lds,Tag,Address,Location,Url,NoteRef,SourceRef,EventRef,RepositoryRef,PersonRef,ChildRef,MediaRef -o docs/prim-sec-ref-tables.png
|
||||
|
||||
clean:
|
||||
rm -f sqlite.db
|
||||
rm -f *~ *.pyc *.pyo
|
||||
rm -f grampsdb/fixtures/initial_data.json
|
||||
0
src/webapp/__init__.py
Normal file
0
src/webapp/__init__.py
Normal file
850
src/webapp/dbdjango.py
Normal file
850
src/webapp/dbdjango.py
Normal file
@@ -0,0 +1,850 @@
|
||||
# Gramps - a GTK+/GNOME based genealogy program
|
||||
#
|
||||
# Copyright (C) 2009 Douglas S. Blank <doug.blank@gmail.com>
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 2 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
#
|
||||
# $Id$
|
||||
#
|
||||
|
||||
""" Implements a Db interface """
|
||||
|
||||
#------------------------------------------------------------------------
|
||||
#
|
||||
# Gramps Modules
|
||||
#
|
||||
#------------------------------------------------------------------------
|
||||
import cPickle
|
||||
import base64
|
||||
import gen
|
||||
import re
|
||||
from gen.db import DbReadBase, DbWriteBase, DbTxn
|
||||
from gen.db import (PERSON_KEY,
|
||||
FAMILY_KEY,
|
||||
SOURCE_KEY,
|
||||
EVENT_KEY,
|
||||
MEDIA_KEY,
|
||||
PLACE_KEY,
|
||||
REPOSITORY_KEY,
|
||||
NOTE_KEY)
|
||||
import Utils
|
||||
from webapp.libdjango import DjangoInterface
|
||||
|
||||
class Cursor(object):
|
||||
def __init__(self, model, func):
|
||||
self.model = model
|
||||
self.func = func
|
||||
def __enter__(self):
|
||||
return self
|
||||
def __iter__(self):
|
||||
return self.__next__()
|
||||
def __next__(self):
|
||||
for item in self.model.all():
|
||||
yield (item.handle, self.func(item))
|
||||
def __exit__(self, *args, **kwargs):
|
||||
pass
|
||||
def iter(self):
|
||||
for item in self.model.all():
|
||||
yield (item.handle, self.func(item))
|
||||
yield None
|
||||
|
||||
class Bookmarks:
|
||||
def get(self):
|
||||
return [] # handles
|
||||
|
||||
class DjangoTxn(DbTxn):
|
||||
def __init__(self, message, db, table=None):
|
||||
DbTxn.__init__(self, message, db)
|
||||
self.table = table
|
||||
|
||||
def get(self, key, default=None, txn=None, **kwargs):
|
||||
"""
|
||||
Returns the data object associated with key
|
||||
"""
|
||||
try:
|
||||
return self.table.objects(handle=key)
|
||||
except:
|
||||
if txn and key in txn:
|
||||
return txn[key]
|
||||
else:
|
||||
return None
|
||||
|
||||
class DbDjango(DbWriteBase, DbReadBase):
|
||||
"""
|
||||
A Gramps Database Backend. This replicates the grampsdb functions.
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
DbReadBase.__init__(self)
|
||||
DbWriteBase.__init__(self)
|
||||
self.dji = DjangoInterface()
|
||||
self.readonly = False
|
||||
self.db_is_open = True
|
||||
self.name_formats = []
|
||||
self.bookmarks = Bookmarks()
|
||||
self.family_bookmarks = Bookmarks()
|
||||
self.event_bookmarks = Bookmarks()
|
||||
self.place_bookmarks = Bookmarks()
|
||||
self.source_bookmarks = Bookmarks()
|
||||
self.repo_bookmarks = Bookmarks()
|
||||
self.media_bookmarks = Bookmarks()
|
||||
self.note_bookmarks = Bookmarks()
|
||||
self.set_person_id_prefix('I%04d')
|
||||
self.set_object_id_prefix('O%04d')
|
||||
self.set_family_id_prefix('F%04d')
|
||||
self.set_source_id_prefix('S%04d')
|
||||
self.set_place_id_prefix('P%04d')
|
||||
self.set_event_id_prefix('E%04d')
|
||||
self.set_repository_id_prefix('R%04d')
|
||||
self.set_note_id_prefix('N%04d')
|
||||
# ----------------------------------
|
||||
self.id_trans = DjangoTxn("ID Transaction", self, self.dji.Person)
|
||||
self.fid_trans = DjangoTxn("FID Transaction", self, self.dji.Family)
|
||||
self.pid_trans = DjangoTxn("PID Transaction", self, self.dji.Place)
|
||||
self.sid_trans = DjangoTxn("SID Transaction", self, self.dji.Source)
|
||||
self.oid_trans = DjangoTxn("OID Transaction", self, self.dji.Media)
|
||||
self.rid_trans = DjangoTxn("RID Transaction", self, self.dji.Repository)
|
||||
self.nid_trans = DjangoTxn("NID Transaction", self, self.dji.Note)
|
||||
self.eid_trans = DjangoTxn("EID Transaction", self, self.dji.Event)
|
||||
self.smap_index = 0
|
||||
self.emap_index = 0
|
||||
self.pmap_index = 0
|
||||
self.fmap_index = 0
|
||||
self.lmap_index = 0
|
||||
self.omap_index = 0
|
||||
self.rmap_index = 0
|
||||
self.nmap_index = 0
|
||||
self.env = None
|
||||
self.person_map = {}
|
||||
self.family_map = {}
|
||||
self.place_map = {}
|
||||
self.source_map = {}
|
||||
self.repository_map = {}
|
||||
self.note_map = {}
|
||||
self.media_map = {}
|
||||
self.event_map = {}
|
||||
self.metadata = {}
|
||||
self.name_group = {}
|
||||
self.undo_callback = None
|
||||
self.redo_callback = None
|
||||
self.undo_history_callback = None
|
||||
self.modified = 0
|
||||
self.txn = DjangoTxn("DbDjango Transaction", self)
|
||||
# Import cache for gedcom import, uses transactions, and
|
||||
# two step adding of objects.
|
||||
self.import_cache = {}
|
||||
self.use_import_cache = False
|
||||
self.use_db_cache = True
|
||||
|
||||
def prepare_import(self):
|
||||
"""
|
||||
DbDjango does not commit data on gedcom import, but saves them
|
||||
for later commit.
|
||||
"""
|
||||
self.use_import_cache = True
|
||||
self.import_cache = {}
|
||||
|
||||
def commit_import(self):
|
||||
"""
|
||||
Commits the items that were queued up during the last gedcom
|
||||
import for two step adding.
|
||||
"""
|
||||
# First we add the primary objects:
|
||||
for key in self.import_cache.keys():
|
||||
obj = self.import_cache[key]
|
||||
if isinstance(obj, gen.lib.Person):
|
||||
self.dji.add_person(obj.serialize())
|
||||
elif isinstance(obj, gen.lib.Family):
|
||||
self.dji.add_family(obj.serialize())
|
||||
elif isinstance(obj, gen.lib.Event):
|
||||
self.dji.add_event(obj.serialize())
|
||||
elif isinstance(obj, gen.lib.Place):
|
||||
self.dji.add_place(obj.serialize())
|
||||
elif isinstance(obj, gen.lib.Repository):
|
||||
self.dji.add_repository(obj.serialize())
|
||||
elif isinstance(obj, gen.lib.Source):
|
||||
self.dji.add_source(obj.serialize())
|
||||
elif isinstance(obj, gen.lib.Note):
|
||||
self.dji.add_note(obj.serialize())
|
||||
# Next we add the links:
|
||||
for key in self.import_cache.keys():
|
||||
obj = self.import_cache[key]
|
||||
if isinstance(obj, gen.lib.Person):
|
||||
self.dji.add_person_detail(obj.serialize())
|
||||
elif isinstance(obj, gen.lib.Family):
|
||||
self.dji.add_family_detail(obj.serialize())
|
||||
elif isinstance(obj, gen.lib.Event):
|
||||
self.dji.add_event_detail(obj.serialize())
|
||||
elif isinstance(obj, gen.lib.Place):
|
||||
self.dji.add_place_detail(obj.serialize())
|
||||
elif isinstance(obj, gen.lib.Repository):
|
||||
self.dji.add_repository_detail(obj.serialize())
|
||||
elif isinstance(obj, gen.lib.Source):
|
||||
self.dji.add_source_detail(obj.serialize())
|
||||
elif isinstance(obj, gen.lib.Note):
|
||||
self.dji.add_note_detail(obj.serialize())
|
||||
self.use_import_cache = False
|
||||
self.import_cache = {}
|
||||
|
||||
def transaction_commit(self, txn):
|
||||
pass
|
||||
|
||||
def enable_signals(self):
|
||||
pass
|
||||
|
||||
def request_rebuild(self):
|
||||
self.dji.rebuild_caches()
|
||||
|
||||
def get_undodb(self):
|
||||
return None
|
||||
|
||||
def transaction_abort(self, txn):
|
||||
pass
|
||||
|
||||
@staticmethod
|
||||
def _validated_id_prefix(val, default):
|
||||
if isinstance(val, basestring) and val:
|
||||
try:
|
||||
str_ = val % 1
|
||||
except TypeError: # missing conversion specifier
|
||||
prefix_var = val + "%d"
|
||||
except ValueError: # incomplete format
|
||||
prefix_var = default+"%04d"
|
||||
else:
|
||||
prefix_var = val # OK as given
|
||||
else:
|
||||
prefix_var = default+"%04d" # not a string or empty string
|
||||
return prefix_var
|
||||
|
||||
@staticmethod
|
||||
def __id2user_format(id_pattern):
|
||||
"""
|
||||
Return a method that accepts a Gramps ID and adjusts it to the users
|
||||
format.
|
||||
"""
|
||||
pattern_match = re.match(r"(.*)%[0 ](\d+)[diu]$", id_pattern)
|
||||
if pattern_match:
|
||||
str_prefix = pattern_match.group(1)
|
||||
nr_width = pattern_match.group(2)
|
||||
def closure_func(gramps_id):
|
||||
if gramps_id and gramps_id.startswith(str_prefix):
|
||||
id_number = gramps_id[len(str_prefix):]
|
||||
if id_number.isdigit():
|
||||
id_value = int(id_number, 10)
|
||||
if len(str(id_value)) > nr_width:
|
||||
# The ID to be imported is too large to fit in the
|
||||
# users format. For now just create a new ID,
|
||||
# because that is also what happens with IDs that
|
||||
# are identical to IDs already in the database. If
|
||||
# the problem of colliding import and already
|
||||
# present IDs is solved the code here also needs
|
||||
# some solution.
|
||||
gramps_id = id_pattern % 1
|
||||
else:
|
||||
gramps_id = id_pattern % id_value
|
||||
return gramps_id
|
||||
else:
|
||||
def closure_func(gramps_id):
|
||||
return gramps_id
|
||||
return closure_func
|
||||
|
||||
def set_person_id_prefix(self, val):
|
||||
"""
|
||||
Set the naming template for GRAMPS Person ID values.
|
||||
|
||||
The string is expected to be in the form of a simple text string, or
|
||||
in a format that contains a C/Python style format string using %d,
|
||||
such as I%d or I%04d.
|
||||
"""
|
||||
self.person_prefix = self._validated_id_prefix(val, "I")
|
||||
self.id2user_format = self.__id2user_format(self.person_prefix)
|
||||
|
||||
def set_source_id_prefix(self, val):
|
||||
"""
|
||||
Set the naming template for GRAMPS Source ID values.
|
||||
|
||||
The string is expected to be in the form of a simple text string, or
|
||||
in a format that contains a C/Python style format string using %d,
|
||||
such as S%d or S%04d.
|
||||
"""
|
||||
self.source_prefix = self._validated_id_prefix(val, "S")
|
||||
self.sid2user_format = self.__id2user_format(self.source_prefix)
|
||||
|
||||
def set_object_id_prefix(self, val):
|
||||
"""
|
||||
Set the naming template for GRAMPS MediaObject ID values.
|
||||
|
||||
The string is expected to be in the form of a simple text string, or
|
||||
in a format that contains a C/Python style format string using %d,
|
||||
such as O%d or O%04d.
|
||||
"""
|
||||
self.mediaobject_prefix = self._validated_id_prefix(val, "O")
|
||||
self.oid2user_format = self.__id2user_format(self.mediaobject_prefix)
|
||||
|
||||
def set_place_id_prefix(self, val):
|
||||
"""
|
||||
Set the naming template for GRAMPS Place ID values.
|
||||
|
||||
The string is expected to be in the form of a simple text string, or
|
||||
in a format that contains a C/Python style format string using %d,
|
||||
such as P%d or P%04d.
|
||||
"""
|
||||
self.place_prefix = self._validated_id_prefix(val, "P")
|
||||
self.pid2user_format = self.__id2user_format(self.place_prefix)
|
||||
|
||||
def set_family_id_prefix(self, val):
|
||||
"""
|
||||
Set the naming template for GRAMPS Family ID values. The string is
|
||||
expected to be in the form of a simple text string, or in a format
|
||||
that contains a C/Python style format string using %d, such as F%d
|
||||
or F%04d.
|
||||
"""
|
||||
self.family_prefix = self._validated_id_prefix(val, "F")
|
||||
self.fid2user_format = self.__id2user_format(self.family_prefix)
|
||||
|
||||
def set_event_id_prefix(self, val):
|
||||
"""
|
||||
Set the naming template for GRAMPS Event ID values.
|
||||
|
||||
The string is expected to be in the form of a simple text string, or
|
||||
in a format that contains a C/Python style format string using %d,
|
||||
such as E%d or E%04d.
|
||||
"""
|
||||
self.event_prefix = self._validated_id_prefix(val, "E")
|
||||
self.eid2user_format = self.__id2user_format(self.event_prefix)
|
||||
|
||||
def set_repository_id_prefix(self, val):
|
||||
"""
|
||||
Set the naming template for GRAMPS Repository ID values.
|
||||
|
||||
The string is expected to be in the form of a simple text string, or
|
||||
in a format that contains a C/Python style format string using %d,
|
||||
such as R%d or R%04d.
|
||||
"""
|
||||
self.repository_prefix = self._validated_id_prefix(val, "R")
|
||||
self.rid2user_format = self.__id2user_format(self.repository_prefix)
|
||||
|
||||
def set_note_id_prefix(self, val):
|
||||
"""
|
||||
Set the naming template for GRAMPS Note ID values.
|
||||
|
||||
The string is expected to be in the form of a simple text string, or
|
||||
in a format that contains a C/Python style format string using %d,
|
||||
such as N%d or N%04d.
|
||||
"""
|
||||
self.note_prefix = self._validated_id_prefix(val, "N")
|
||||
self.nid2user_format = self.__id2user_format(self.note_prefix)
|
||||
|
||||
def __find_next_gramps_id(self, prefix, map_index, trans):
|
||||
"""
|
||||
Helper function for find_next_<object>_gramps_id methods
|
||||
"""
|
||||
index = prefix % map_index
|
||||
while trans.get(str(index), txn=self.txn) is not None:
|
||||
map_index += 1
|
||||
index = prefix % map_index
|
||||
map_index += 1
|
||||
return (map_index, index)
|
||||
|
||||
def find_next_person_gramps_id(self):
|
||||
"""
|
||||
Return the next available GRAMPS' ID for a Person object based off the
|
||||
person ID prefix.
|
||||
"""
|
||||
self.pmap_index, gid = self.__find_next_gramps_id(self.person_prefix,
|
||||
self.pmap_index, self.id_trans)
|
||||
return gid
|
||||
|
||||
def find_next_place_gramps_id(self):
|
||||
"""
|
||||
Return the next available GRAMPS' ID for a Place object based off the
|
||||
place ID prefix.
|
||||
"""
|
||||
self.lmap_index, gid = self.__find_next_gramps_id(self.place_prefix,
|
||||
self.lmap_index, self.pid_trans)
|
||||
return gid
|
||||
|
||||
def find_next_event_gramps_id(self):
|
||||
"""
|
||||
Return the next available GRAMPS' ID for a Event object based off the
|
||||
event ID prefix.
|
||||
"""
|
||||
self.emap_index, gid = self.__find_next_gramps_id(self.event_prefix,
|
||||
self.emap_index, self.eid_trans)
|
||||
return gid
|
||||
|
||||
def find_next_object_gramps_id(self):
|
||||
"""
|
||||
Return the next available GRAMPS' ID for a MediaObject object based
|
||||
off the media object ID prefix.
|
||||
"""
|
||||
self.omap_index, gid = self.__find_next_gramps_id(self.mediaobject_prefix,
|
||||
self.omap_index, self.oid_trans)
|
||||
return gid
|
||||
|
||||
def find_next_source_gramps_id(self):
|
||||
"""
|
||||
Return the next available GRAMPS' ID for a Source object based off the
|
||||
source ID prefix.
|
||||
"""
|
||||
self.smap_index, gid = self.__find_next_gramps_id(self.source_prefix,
|
||||
self.smap_index, self.sid_trans)
|
||||
return gid
|
||||
|
||||
def find_next_family_gramps_id(self):
|
||||
"""
|
||||
Return the next available GRAMPS' ID for a Family object based off the
|
||||
family ID prefix.
|
||||
"""
|
||||
self.fmap_index, gid = self.__find_next_gramps_id(self.family_prefix,
|
||||
self.fmap_index, self.fid_trans)
|
||||
return gid
|
||||
|
||||
def find_next_repository_gramps_id(self):
|
||||
"""
|
||||
Return the next available GRAMPS' ID for a Respository object based
|
||||
off the repository ID prefix.
|
||||
"""
|
||||
self.rmap_index, gid = self.__find_next_gramps_id(self.repository_prefix,
|
||||
self.rmap_index, self.rid_trans)
|
||||
return gid
|
||||
|
||||
def find_next_note_gramps_id(self):
|
||||
"""
|
||||
Return the next available GRAMPS' ID for a Note object based off the
|
||||
note ID prefix.
|
||||
"""
|
||||
self.nmap_index, gid = self.__find_next_gramps_id(self.note_prefix,
|
||||
self.nmap_index, self.nid_trans)
|
||||
return gid
|
||||
|
||||
def get_mediapath(self):
|
||||
return None
|
||||
|
||||
def get_name_group_keys(self):
|
||||
return []
|
||||
|
||||
def get_name_group_mapping(self, key):
|
||||
return None
|
||||
|
||||
def get_researcher(self):
|
||||
obj = gen.lib.Researcher()
|
||||
return obj
|
||||
|
||||
def get_person_handles(self):
|
||||
return [item.handle for item in self.dji.Person.all()]
|
||||
|
||||
def get_family_handles(self):
|
||||
return [item.handle for item in self.dji.Family.all()]
|
||||
|
||||
def get_event_handles(self):
|
||||
return [item.handle for item in self.dji.Event.all()]
|
||||
|
||||
def get_source_handles(self):
|
||||
return [item.handle for item in self.dji.Source.all()]
|
||||
|
||||
def get_place_handles(self):
|
||||
return [item.handle for item in self.dji.Place.all()]
|
||||
|
||||
def get_repository_handles(self):
|
||||
return [item.handle for item in self.dji.Repository.all()]
|
||||
|
||||
def get_media_object_handles(self):
|
||||
return [item.handle for item in self.dji.Media.all()]
|
||||
|
||||
def get_note_handles(self):
|
||||
return [item.handle for item in self.dji.Note.all()]
|
||||
|
||||
def get_tag_handles(self, sort_handles=False):
|
||||
return []
|
||||
|
||||
def get_event_from_handle(self, handle):
|
||||
if handle in self.import_cache:
|
||||
return self.import_cache[handle]
|
||||
try:
|
||||
event = self.dji.Event.get(handle=handle)
|
||||
except:
|
||||
return None
|
||||
return self.make_event(event)
|
||||
|
||||
def get_family_from_handle(self, handle):
|
||||
if handle in self.import_cache:
|
||||
return self.import_cache[handle]
|
||||
try:
|
||||
family = self.dji.Family.get(handle=handle)
|
||||
except:
|
||||
return None
|
||||
return self.make_family(family)
|
||||
|
||||
def get_family_from_gramps_id(self, gramps_id):
|
||||
if self.import_cache:
|
||||
for handle in self.import_cache:
|
||||
if self.import_cache[handle].gramps_id == gramps_id:
|
||||
return self.import_cache[handle]
|
||||
try:
|
||||
family = self.dji.Family.get(gramps_id=gramps_id)
|
||||
except:
|
||||
return None
|
||||
return self.make_family(family)
|
||||
|
||||
def get_repository_from_handle(self, handle):
|
||||
if handle in self.import_cache:
|
||||
return self.import_cache[handle]
|
||||
try:
|
||||
repository = self.dji.Repository.get(handle=handle)
|
||||
except:
|
||||
return None
|
||||
return self.make_repository(repository)
|
||||
|
||||
def get_person_from_handle(self, handle):
|
||||
if handle in self.import_cache:
|
||||
return self.import_cache[handle]
|
||||
try:
|
||||
person = self.dji.Person.get(handle=handle)
|
||||
except:
|
||||
return None
|
||||
return self.make_person(person)
|
||||
|
||||
def make_repository(self, repository):
|
||||
if self.use_db_cache and repository.cache:
|
||||
data = cPickle.loads(base64.decodestring(repository.cache))
|
||||
else:
|
||||
data = self.dji.get_repository(repository)
|
||||
return gen.lib.Repository.create(data)
|
||||
|
||||
def make_source(self, source):
|
||||
if self.use_db_cache and source.cache:
|
||||
data = cPickle.loads(base64.decodestring(source.cache))
|
||||
else:
|
||||
data = self.dji.get_source(source)
|
||||
return gen.lib.Source.create(data)
|
||||
|
||||
def make_family(self, family):
|
||||
if self.use_db_cache and family.cache:
|
||||
data = cPickle.loads(base64.decodestring(family.cache))
|
||||
else:
|
||||
data = self.dji.get_family(family)
|
||||
return gen.lib.Family.create(data)
|
||||
|
||||
def make_person(self, person):
|
||||
if self.use_db_cache and person.cache:
|
||||
data = cPickle.loads(base64.decodestring(person.cache))
|
||||
else:
|
||||
data = self.dji.get_person(person)
|
||||
return gen.lib.Person.create(data)
|
||||
|
||||
def make_event(self, event):
|
||||
if self.use_db_cache and event.cache:
|
||||
data = cPickle.loads(base64.decodestring(event.cache))
|
||||
else:
|
||||
data = self.dji.get_event(event)
|
||||
return gen.lib.Event.create(data)
|
||||
|
||||
def make_note(self, note):
|
||||
if self.use_db_cache and note.cache:
|
||||
data = cPickle.loads(base64.decodestring(note.cache))
|
||||
else:
|
||||
data = self.dji.get_note(note)
|
||||
return gen.lib.Note.create(data)
|
||||
|
||||
def make_place(self, place):
|
||||
if self.use_db_cache and place.cache:
|
||||
data = cPickle.loads(base64.decodestring(place.cache))
|
||||
else:
|
||||
data = self.dji.get_place(place)
|
||||
return gen.lib.Place.create(data)
|
||||
|
||||
def make_media(self, media):
|
||||
if self.use_db_cache and media.cache:
|
||||
data = cPickle.loads(base64.decodestring(media.cache))
|
||||
else:
|
||||
data = self.dji.get_media(media)
|
||||
return gen.lib.Media.create(data)
|
||||
|
||||
def get_place_from_handle(self, handle):
|
||||
if handle in self.import_cache:
|
||||
return self.import_cache[handle]
|
||||
# FIXME: use object cache
|
||||
try:
|
||||
dji_obj = self.dji.Place.get(handle=handle)
|
||||
except:
|
||||
dji_obj = None
|
||||
if dji_obj:
|
||||
tuple_obj = self.dji.get_place(dji_obj)
|
||||
if tuple_obj:
|
||||
obj = gen.lib.Place()
|
||||
obj.unserialize(tuple_obj)
|
||||
return obj
|
||||
return None
|
||||
|
||||
def get_source_from_handle(self, handle):
|
||||
if handle in self.import_cache:
|
||||
return self.import_cache[handle]
|
||||
try:
|
||||
source = self.dji.Source.get(handle=handle)
|
||||
except:
|
||||
return None
|
||||
return self.make_source(source)
|
||||
|
||||
def get_note_from_handle(self, handle):
|
||||
if handle in self.import_cache:
|
||||
return self.import_cache[handle]
|
||||
try:
|
||||
note = self.dji.Note.get(handle=handle)
|
||||
except:
|
||||
return None
|
||||
return self.make_note(note)
|
||||
|
||||
def get_object_from_handle(self, handle):
|
||||
if handle in self.import_cache:
|
||||
return self.import_cache[handle]
|
||||
try:
|
||||
media = self.dji.Media.get(handle=handle)
|
||||
except:
|
||||
return None
|
||||
return self.make_media(media)
|
||||
|
||||
def get_media_object_handles(self):
|
||||
return [media.handle for media in self.dji.Media.all()]
|
||||
|
||||
def get_person_handles(self, sort_handles=False):
|
||||
return [person.handle for person in self.dji.Person.all()]
|
||||
|
||||
def get_default_person(self):
|
||||
return None
|
||||
|
||||
def iter_people(self):
|
||||
return (self.get_person_from_handle(person.handle)
|
||||
for person in self.dji.Person.all())
|
||||
|
||||
def iter_person_handles(self):
|
||||
return (person.handle for person in self.dji.Person.all())
|
||||
|
||||
def iter_families(self):
|
||||
return (self.get_family_from_handle(family.handle)
|
||||
for family in self.dji.Family.all())
|
||||
|
||||
def iter_family_handles(self):
|
||||
return (family.handle for family in self.dji.Family.all())
|
||||
|
||||
def get_person_from_gramps_id(self, gramps_id):
|
||||
if self.import_cache:
|
||||
for handle in self.import_cache:
|
||||
if self.import_cache[handle].gramps_id == gramps_id:
|
||||
return self.import_cache[handle]
|
||||
match_list = self.dji.Person.filter(gramps_id=gramps_id)
|
||||
if match_list.count() > 0:
|
||||
return self.make_person(match_list[0])
|
||||
else:
|
||||
return None
|
||||
|
||||
def get_number_of_people(self):
|
||||
return self.dji.Person.count()
|
||||
|
||||
def get_number_of_events(self):
|
||||
return self.dji.Event.count()
|
||||
|
||||
def get_number_of_places(self):
|
||||
return self.dji.Place.count()
|
||||
|
||||
def get_number_of_tags(self):
|
||||
return 0 # self.dji.Tag.count()
|
||||
|
||||
def get_number_of_families(self):
|
||||
return self.dji.Family.count()
|
||||
|
||||
def get_number_of_notes(self):
|
||||
return self.dji.Note.count()
|
||||
|
||||
def get_number_of_sources(self):
|
||||
return self.dji.Source.count()
|
||||
|
||||
def get_number_of_media_objects(self):
|
||||
return self.dji.Media.count()
|
||||
|
||||
def get_number_of_repositories(self):
|
||||
return self.dji.Repository.count()
|
||||
|
||||
def get_place_cursor(self):
|
||||
return Cursor(self.dji.Place, self.make_place).iter()
|
||||
|
||||
def get_person_cursor(self):
|
||||
return Cursor(self.dji.Person, self.make_person).iter()
|
||||
|
||||
def get_family_cursor(self):
|
||||
return Cursor(self.dji.Family, self.make_family).iter()
|
||||
|
||||
def get_events_cursor(self):
|
||||
return Cursor(self.dji.Event, self.make_event).iter()
|
||||
|
||||
def get_source_cursor(self):
|
||||
return Cursor(self.dji.Source, self.make_source).iter()
|
||||
|
||||
def has_person_handle(self, handle):
|
||||
return self.dji.Person.filter(handle=handle).count() == 1
|
||||
|
||||
def has_family_handle(self, handle):
|
||||
return self.dji.Family.filter(handle=handle).count() == 1
|
||||
|
||||
def has_source_handle(self, handle):
|
||||
return self.dji.Source.filter(handle=handle).count() == 1
|
||||
|
||||
def has_repository_handle(self, handle):
|
||||
return self.dji.Repository.filter(handle=handle).count() == 1
|
||||
|
||||
def has_note_handle(self, handle):
|
||||
return self.dji.Note.filter(handle=handle).count() == 1
|
||||
|
||||
def has_place_handle(self, handle):
|
||||
return self.dji.Place.filter(handle=handle).count() == 1
|
||||
|
||||
def get_raw_person_data(self, handle):
|
||||
# FIXME?: not cached
|
||||
try:
|
||||
return self.dji.get_person(self.dji.Person.get(handle=handle))
|
||||
except:
|
||||
return None
|
||||
|
||||
def get_raw_family_data(self, handle):
|
||||
try:
|
||||
return self.dji.get_family(self.dji.Family.get(handle=handle))
|
||||
except:
|
||||
return None
|
||||
|
||||
def get_raw_source_data(self, handle):
|
||||
try:
|
||||
return self.dji.get_source(self.dji.Source.get(handle=handle))
|
||||
except:
|
||||
return None
|
||||
|
||||
def get_raw_repository_data(self, handle):
|
||||
try:
|
||||
return self.dji.get_repository(self.dji.Repository.get(handle=handle))
|
||||
except:
|
||||
return None
|
||||
|
||||
def get_raw_note_data(self, handle):
|
||||
try:
|
||||
return self.dji.get_note(self.dji.Note.get(handle=handle))
|
||||
except:
|
||||
return None
|
||||
|
||||
def get_raw_place_data(self, handle):
|
||||
try:
|
||||
return self.dji.get_place(self.dji.Place.get(handle=handle))
|
||||
except:
|
||||
return None
|
||||
|
||||
def add_person(self, person, trans, set_gid=True):
|
||||
if not person.handle:
|
||||
person.handle = Utils.create_id()
|
||||
if not person.gramps_id or set_gid:
|
||||
person.gramps_id = self.find_next_person_gramps_id()
|
||||
self.commit_person(person, trans)
|
||||
return person.handle
|
||||
|
||||
def add_family(self, family, trans, set_gid=True):
|
||||
if not family.handle:
|
||||
family.handle = Utils.create_id()
|
||||
if not family.gramps_id or set_gid:
|
||||
family.gramps_id = self.find_next_family_gramps_id()
|
||||
self.commit_family(family, trans)
|
||||
return family.handle
|
||||
|
||||
def add_source(self, source, trans, set_gid=True):
|
||||
if not source.handle:
|
||||
source.handle = Utils.create_id()
|
||||
if not source.gramps_id or set_gid:
|
||||
source.gramps_id = self.find_next_source_gramps_id()
|
||||
self.commit_source(source, trans)
|
||||
return source.handle
|
||||
|
||||
def add_repository(self, repository, trans, set_gid=True):
|
||||
if not repository.handle:
|
||||
repository.handle = Utils.create_id()
|
||||
if not repository.gramps_id or set_gid:
|
||||
repository.gramps_id = self.find_next_repository_gramps_id()
|
||||
self.commit_repository(repository, trans)
|
||||
return repository.handle
|
||||
|
||||
def add_note(self, note, trans, set_gid=True):
|
||||
if not note.handle:
|
||||
note.handle = Utils.create_id()
|
||||
if not note.gramps_id or set_gid:
|
||||
note.gramps_id = self.find_next_note_gramps_id()
|
||||
self.commit_note(note, trans)
|
||||
return note.handle
|
||||
|
||||
def add_place(self, place, trans, set_gid=True):
|
||||
if not place.handle:
|
||||
place.handle = Utils.create_id()
|
||||
if not place.gramps_id or set_gid:
|
||||
place.gramps_id = self.find_next_place_gramps_id()
|
||||
self.commit_place(place, trans)
|
||||
return place.handle
|
||||
|
||||
def add_event(self, event, trans, set_gid=True):
|
||||
if not event.handle:
|
||||
event.handle = Utils.create_id()
|
||||
if not event.gramps_id or set_gid:
|
||||
event.gramps_id = self.find_next_event_gramps_id()
|
||||
self.commit_event(event, trans)
|
||||
return event.handle
|
||||
|
||||
def commit_person(self, person, trans, change_time=None):
|
||||
self.import_cache[person.handle] = person
|
||||
|
||||
def commit_family(self, family, trans, change_time=None):
|
||||
self.import_cache[family.handle] = family
|
||||
|
||||
def commit_source(self, source, trans, change_time=None):
|
||||
self.import_cache[source.handle] = source
|
||||
|
||||
def commit_repository(self, repository, trans, change_time=None):
|
||||
self.import_cache[repository.handle] = repository
|
||||
|
||||
def commit_note(self, note, trans, change_time=None):
|
||||
self.import_cache[note.handle] = note
|
||||
|
||||
def commit_place(self, place, trans, change_time=None):
|
||||
self.import_cache[place.handle] = place
|
||||
|
||||
def commit_event(self, event, trans, change_time=None):
|
||||
self.import_cache[event.handle] = event
|
||||
|
||||
def get_gramps_ids(self, obj_key):
|
||||
key2table = {
|
||||
PERSON_KEY: self.id_trans,
|
||||
FAMILY_KEY: self.fid_trans,
|
||||
SOURCE_KEY: self.sid_trans,
|
||||
EVENT_KEY: self.eid_trans,
|
||||
MEDIA_KEY: self.oid_trans,
|
||||
PLACE_KEY: self.pid_trans,
|
||||
REPOSITORY_KEY: self.rid_trans,
|
||||
NOTE_KEY: self.nid_trans,
|
||||
}
|
||||
|
||||
table = key2table[obj_key]
|
||||
return table.keys()
|
||||
|
||||
def transaction_begin(self, transaction):
|
||||
return
|
||||
|
||||
def disable_signals(self):
|
||||
pass
|
||||
|
||||
def set_researcher(self, owner):
|
||||
pass
|
||||
|
||||
0
src/webapp/grampsdb/__init__.py
Normal file
0
src/webapp/grampsdb/__init__.py
Normal file
7
src/webapp/grampsdb/admin.py
Normal file
7
src/webapp/grampsdb/admin.py
Normal file
@@ -0,0 +1,7 @@
|
||||
from web.grampsdb.models import *
|
||||
from django.contrib import admin
|
||||
|
||||
for type_name in get_tables("all"):
|
||||
admin.site.register(type_name[1])
|
||||
|
||||
admin.site.register(Profile)
|
||||
64
src/webapp/grampsdb/forms.py
Normal file
64
src/webapp/grampsdb/forms.py
Normal file
@@ -0,0 +1,64 @@
|
||||
# forms.py forms for Django web project
|
||||
|
||||
from django import forms
|
||||
from web.grampsdb.models import *
|
||||
from django.forms.models import inlineformset_factory
|
||||
from django.forms.models import BaseModelFormSet
|
||||
from django.forms.widgets import TextInput
|
||||
import datetime
|
||||
|
||||
class PersonForm(forms.ModelForm):
|
||||
class Meta:
|
||||
model = Person
|
||||
exclude = ["death", "birth", "handle", "birth_ref_index", "death_ref_index"]
|
||||
|
||||
surname = forms.CharField(required=False,
|
||||
widget=TextInput(attrs={'size':'30'}))
|
||||
prefix = forms.CharField(required=False,
|
||||
widget=TextInput(attrs={'size':'30'}))
|
||||
|
||||
class NameForm(forms.ModelForm):
|
||||
class Meta:
|
||||
model = Name
|
||||
# Exclude these, so they don't get checked:
|
||||
exclude = ["order", "calendar", "modifier",
|
||||
"quality",
|
||||
#"quality_estimated", "quality_calculated",
|
||||
#"quality_interpreted",
|
||||
"year1", "day1", "month1",
|
||||
"sortval", "newyear", "person"]
|
||||
# Add these because they are TextFields, which render as
|
||||
# Textareas:
|
||||
surname = forms.CharField(required=False,
|
||||
widget=TextInput(attrs={'size':'30'}))
|
||||
first_name = forms.CharField(label="Given",
|
||||
required=False,
|
||||
widget=TextInput(attrs={'size':'30'}))
|
||||
title = forms.CharField(required=False,
|
||||
widget=TextInput(attrs={'size':'30'}))
|
||||
prefix = forms.CharField(required=False,
|
||||
widget=TextInput(attrs={'size':'30'}))
|
||||
suffix = forms.CharField(required=False,
|
||||
widget=TextInput(attrs={'size':'30'}))
|
||||
call = forms.CharField(label="Callname",
|
||||
required=False,
|
||||
widget=TextInput(attrs={'size':'30'}))
|
||||
patronymic = forms.CharField(required=False,
|
||||
widget=TextInput(attrs={'size':'30'}))
|
||||
group_as = forms.CharField(required=False,
|
||||
widget=TextInput(attrs={'size':'30'}))
|
||||
text = forms.CharField(label="Date",
|
||||
required=False,
|
||||
widget=TextInput(attrs={'size':'30'}))
|
||||
|
||||
class NameFormFromPerson(NameForm):
|
||||
class Meta:
|
||||
model = Name
|
||||
# Exclude these, so they don't get checked:
|
||||
exclude = ["order", "calendar", "modifier",
|
||||
"quality",
|
||||
#"quality_estimated", "quality_calculated",
|
||||
#"quality_interpreted",
|
||||
"year1", "day1", "month1",
|
||||
"sortval", "newyear", "person",
|
||||
"sort_as", "display_as"]
|
||||
915
src/webapp/grampsdb/models.py
Normal file
915
src/webapp/grampsdb/models.py
Normal file
@@ -0,0 +1,915 @@
|
||||
# Gramps - a GTK+/GNOME based genealogy program
|
||||
#
|
||||
# Copyright (C) 2009 B. Malengier <benny.malengier@gmail.com>
|
||||
# Copyright (C) 2009 Douglas S. Blank <doug.blank@gmail.com>
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 2 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
#
|
||||
# $Id$
|
||||
#
|
||||
|
||||
"""
|
||||
All of the models for the grampsdb Django data schema.
|
||||
This requires initial data for all of the Types, which
|
||||
is loaded by the fixtures/initial_data.json, which is
|
||||
created by init.py.
|
||||
"""
|
||||
|
||||
_DEBUG = True
|
||||
|
||||
from django.db import models
|
||||
from django.contrib.contenttypes.models import ContentType
|
||||
from django.contrib.contenttypes import generic
|
||||
|
||||
from gen.lib.date import Date as GDate, Today
|
||||
from Utils import create_id, create_uid
|
||||
|
||||
from web.grampsdb.profile import Profile
|
||||
|
||||
#---------------------------------------------------------------------------
|
||||
#
|
||||
# Support functions
|
||||
#
|
||||
#---------------------------------------------------------------------------
|
||||
|
||||
def get_type(the_type, data, get_or_create=False):
|
||||
"""
|
||||
Gets the default row for a given Type and data. Data is
|
||||
a pair, (VAL, NAME). VAL + NAME should be unique. Will create
|
||||
one if it doesn't already exist.
|
||||
"""
|
||||
if type(data) == type(1):
|
||||
return the_type.objects.get(val=data)
|
||||
elif data[0] == the_type._CUSTOM or get_or_create:
|
||||
(obj, new) = the_type.objects.get_or_create(val=data[0],
|
||||
name=data[1])
|
||||
if new and _DEBUG:
|
||||
print "DEBUG: Made new type:", the_type, data
|
||||
return obj
|
||||
else:
|
||||
return the_type.objects.get(val=data[0])
|
||||
|
||||
def get_default_type(the_type):
|
||||
"""
|
||||
Gets the default row for a given Type.
|
||||
"""
|
||||
val, name = the_type._DEFAULT
|
||||
return the_type.objects.get(val=val, name=name)
|
||||
|
||||
def get_datamap(grampsclass):
|
||||
return [(x[0],x[2]) for x in grampsclass._DATAMAP]
|
||||
|
||||
#---------------------------------------------------------------------------
|
||||
#
|
||||
# Types
|
||||
#
|
||||
#---------------------------------------------------------------------------
|
||||
|
||||
class mGrampsType(models.Model):
|
||||
"""
|
||||
The abstract base class for all types.
|
||||
Types are enumerated integers. One integer corresponds with custom, then
|
||||
custom_type holds the type name
|
||||
"""
|
||||
class Meta: abstract = True
|
||||
|
||||
_CUSTOM = 0
|
||||
_DEFAULT = 0
|
||||
_DATAMAP = []
|
||||
|
||||
name = models.CharField(max_length=40)
|
||||
|
||||
def __unicode__(self): return self.name
|
||||
|
||||
def get_default_type(self):
|
||||
""" return a tuple default (val,name) """
|
||||
return self._DATAMAP[self._DEFAULT]
|
||||
|
||||
def __len__(self):
|
||||
""" For use as a sequence for getting (val, name) """
|
||||
return 2
|
||||
|
||||
def __getitem__(self, pos):
|
||||
""" for getting the parts as if they were the original tuples."""
|
||||
if pos == 0:
|
||||
return self.val
|
||||
elif pos == 1:
|
||||
return self.name
|
||||
else:
|
||||
raise IndexError("type index is out of range (use 0 or 1)")
|
||||
|
||||
class NameType(mGrampsType):
|
||||
from gen.lib.nametype import NameType
|
||||
_DATAMAP = get_datamap(NameType)
|
||||
_CUSTOM = NameType._CUSTOM
|
||||
_DEFAULT = _DATAMAP[NameType._DEFAULT]
|
||||
val = models.IntegerField('name type', choices=_DATAMAP, blank=False)
|
||||
|
||||
class NameOriginType(mGrampsType):
|
||||
from gen.lib.nameorigintype import NameOriginType
|
||||
_DATAMAP = get_datamap(NameOriginType)
|
||||
_CUSTOM = NameOriginType._CUSTOM
|
||||
_DEFAULT = _DATAMAP[NameOriginType._DEFAULT]
|
||||
val = models.IntegerField('name origin type', choices=_DATAMAP, blank=False)
|
||||
|
||||
class AttributeType(mGrampsType):
|
||||
from gen.lib.attrtype import AttributeType
|
||||
_DATAMAP = get_datamap(AttributeType)
|
||||
_CUSTOM = AttributeType._CUSTOM
|
||||
_DEFAULT = _DATAMAP[AttributeType._DEFAULT]
|
||||
val = models.IntegerField('attribute type', choices=_DATAMAP, blank=False)
|
||||
|
||||
class UrlType(mGrampsType):
|
||||
from gen.lib.urltype import UrlType
|
||||
_DATAMAP = get_datamap(UrlType)
|
||||
_CUSTOM = UrlType._CUSTOM
|
||||
_DEFAULT = _DATAMAP[UrlType._DEFAULT]
|
||||
val = models.IntegerField('url type', choices=_DATAMAP, blank=False)
|
||||
|
||||
class ChildRefType(mGrampsType):
|
||||
from gen.lib.childreftype import ChildRefType
|
||||
_DATAMAP = get_datamap(ChildRefType)
|
||||
_CUSTOM = ChildRefType._CUSTOM
|
||||
_DEFAULT = _DATAMAP[ChildRefType._DEFAULT]
|
||||
val = models.IntegerField('child reference type', choices=_DATAMAP,
|
||||
blank=False)
|
||||
|
||||
class RepositoryType(mGrampsType):
|
||||
from gen.lib.repotype import RepositoryType
|
||||
_DATAMAP = get_datamap(RepositoryType)
|
||||
_CUSTOM = RepositoryType._CUSTOM
|
||||
_DEFAULT = _DATAMAP[RepositoryType._DEFAULT]
|
||||
val = models.IntegerField('repository type', choices=_DATAMAP, blank=False)
|
||||
|
||||
class EventType(mGrampsType):
|
||||
from gen.lib.eventtype import EventType
|
||||
_DATAMAP = get_datamap(EventType)
|
||||
_CUSTOM = EventType._CUSTOM
|
||||
_DEFAULT = _DATAMAP[EventType._DEFAULT]
|
||||
BIRTH = 12
|
||||
DEATH = 13
|
||||
val = models.IntegerField('event type', choices=_DATAMAP, blank=False)
|
||||
|
||||
class FamilyRelType(mGrampsType):
|
||||
from gen.lib.familyreltype import FamilyRelType
|
||||
_DATAMAP = get_datamap(FamilyRelType)
|
||||
_CUSTOM = FamilyRelType._CUSTOM
|
||||
_DEFAULT = _DATAMAP[FamilyRelType._DEFAULT]
|
||||
val = models.IntegerField('family relation type', choices=_DATAMAP,
|
||||
blank=False)
|
||||
|
||||
class SourceMediaType(mGrampsType):
|
||||
from gen.lib.srcmediatype import SourceMediaType
|
||||
_DATAMAP = get_datamap(SourceMediaType)
|
||||
_CUSTOM = SourceMediaType._CUSTOM
|
||||
_DEFAULT = _DATAMAP[SourceMediaType._DEFAULT]
|
||||
val = models.IntegerField('source medium type', choices=_DATAMAP,
|
||||
blank=False)
|
||||
|
||||
class EventRoleType(mGrampsType):
|
||||
from gen.lib.eventroletype import EventRoleType
|
||||
_DATAMAP = get_datamap(EventRoleType)
|
||||
_CUSTOM = EventRoleType._CUSTOM
|
||||
_DEFAULT = _DATAMAP[EventRoleType._DEFAULT]
|
||||
val = models.IntegerField('event role type', choices=_DATAMAP, blank=False)
|
||||
|
||||
class NoteType(mGrampsType):
|
||||
from gen.lib.notetype import NoteType
|
||||
_DATAMAP = get_datamap(NoteType)
|
||||
_CUSTOM = NoteType._CUSTOM
|
||||
_DEFAULT = _DATAMAP[NoteType._DEFAULT]
|
||||
val = models.IntegerField('note type', choices=_DATAMAP, blank=False)
|
||||
|
||||
class MarkupType(mGrampsType):
|
||||
from gen.lib.notetype import NoteType
|
||||
_DATAMAP = [(0, "Custom")]
|
||||
_CUSTOM = 0
|
||||
_DEFAULT = _DATAMAP[0]
|
||||
val = models.IntegerField('note type', choices=_DATAMAP, blank=False)
|
||||
|
||||
class GenderType(mGrampsType):
|
||||
_DATAMAP = [(2, 'Unknown'), (1, 'Male'), (0, 'Female')]
|
||||
_DEFAULT = _DATAMAP[0]
|
||||
val = models.IntegerField('gender type', choices=_DATAMAP, blank=False)
|
||||
|
||||
class LdsType(mGrampsType):
|
||||
_DATAMAP = [(0, "Baptism" ),
|
||||
(1, "Endowment" ),
|
||||
(2, "Seal to Parents"),
|
||||
(3, "Seal to Spouse"),
|
||||
(4, "Confirmation")]
|
||||
_DEFAULT = _DATAMAP[0]
|
||||
val = models.IntegerField('lds type', choices=_DATAMAP, blank=False)
|
||||
|
||||
class LdsStatus(mGrampsType):
|
||||
_DATAMAP = [(0, "None"),
|
||||
(1, "BIC"),
|
||||
(2, "Canceled"),
|
||||
(3, "Child"),
|
||||
(4, "Cleared"),
|
||||
(5, "Completed"),
|
||||
(6, "Dns"),
|
||||
(7, "Infant"),
|
||||
(8, "Pre 1970"),
|
||||
(9, "Qualified"),
|
||||
(10, "DNSCAN"),
|
||||
(11, "Stillborn"),
|
||||
(12, "Submitted"),
|
||||
(13, "Uncleared")]
|
||||
_DEFAULT = _DATAMAP[0]
|
||||
val = models.IntegerField('lds status', choices=_DATAMAP, blank=False)
|
||||
|
||||
class NameFormatType(mGrampsType):
|
||||
_DATAMAP = [(0, "Default format"),
|
||||
(1, "Surname, Given Patronymic"),
|
||||
(2, "Given Surname"),
|
||||
(3, "Patronymic, Given"),]
|
||||
_DEFAULT = _DATAMAP[0]
|
||||
val = models.IntegerField('Name formats', choices=_DATAMAP, blank=False)
|
||||
|
||||
class CalendarType(mGrampsType):
|
||||
CAL_GREGORIAN = 0 # CODE
|
||||
CAL_JULIAN = 1
|
||||
CAL_HEBREW = 2
|
||||
CAL_FRENCH = 3
|
||||
CAL_PERSIAN = 4
|
||||
CAL_ISLAMIC = 5
|
||||
CAL_SWEDISH = 6
|
||||
|
||||
_DATAMAP = [(CAL_GREGORIAN, "Gregorian"),
|
||||
(CAL_JULIAN, "Julian"),
|
||||
(CAL_HEBREW, "Hebrew"),
|
||||
(CAL_FRENCH, "French Republican"),
|
||||
(CAL_PERSIAN, "Persian"),
|
||||
(CAL_ISLAMIC, "Islamic"),
|
||||
(CAL_SWEDISH, "Swedish")]
|
||||
|
||||
_DEFAULT = _DATAMAP[CAL_GREGORIAN]
|
||||
val = models.IntegerField('Calendar', choices=_DATAMAP, blank=False)
|
||||
|
||||
class DateModifierType(mGrampsType):
|
||||
MOD_NONE = 0 # CODE
|
||||
MOD_BEFORE = 1
|
||||
MOD_AFTER = 2
|
||||
MOD_ABOUT = 3
|
||||
MOD_RANGE = 4
|
||||
MOD_SPAN = 5
|
||||
MOD_TEXTONLY = 6
|
||||
|
||||
_DATAMAP = [(MOD_NONE, ""),
|
||||
(MOD_BEFORE, "Before"),
|
||||
(MOD_AFTER, "After"),
|
||||
(MOD_ABOUT, "About"),
|
||||
(MOD_RANGE, "Range"),
|
||||
(MOD_SPAN, "Span"),
|
||||
(MOD_TEXTONLY, "Text only")]
|
||||
|
||||
_DEFAULT = _DATAMAP[MOD_NONE]
|
||||
val = models.IntegerField('Date modifier', choices=_DATAMAP, blank=False)
|
||||
|
||||
class DateNewYearType(mGrampsType):
|
||||
NEWYEAR_JAN1 = 0 # CODE
|
||||
NEWYEAR_MAR1 = 1
|
||||
NEWYEAR_MAR25 = 2
|
||||
NEWYEAR_SEP1 = 3
|
||||
|
||||
_DATAMAP = [(NEWYEAR_JAN1, ""),
|
||||
(NEWYEAR_MAR1, "March 1"),
|
||||
(NEWYEAR_MAR25, "March 25"),
|
||||
(NEWYEAR_SEP1, "September 1")]
|
||||
|
||||
_DEFAULT = _DATAMAP[NEWYEAR_JAN1]
|
||||
val = models.IntegerField('New Year start date', choices=_DATAMAP, blank=False)
|
||||
|
||||
class ThemeType(mGrampsType):
|
||||
_DATAMAP = list(enumerate(["Web_Mainz.css",
|
||||
"Web_Basic-Ash.css",
|
||||
"Web_Basic-Cypress.css",
|
||||
"Web_Nebraska.css",
|
||||
"Web_Basic-Lilac.css",
|
||||
"Web_Print-Default.css",
|
||||
"Web_Basic-Peach.css",
|
||||
"Web_Visually.css",
|
||||
"Web_Basic-Spruce.css",]))
|
||||
|
||||
_DEFAULT = _DATAMAP[0]
|
||||
val = models.IntegerField('Theme', choices=_DATAMAP, blank=False)
|
||||
|
||||
#---------------------------------------------------------------------------
|
||||
#
|
||||
# Support definitions
|
||||
#
|
||||
#---------------------------------------------------------------------------
|
||||
|
||||
class DateObject(models.Model):
|
||||
class Meta: abstract = True
|
||||
|
||||
calendar = models.IntegerField(default=0)
|
||||
modifier = models.IntegerField(default=0)
|
||||
quality = models.IntegerField(default=0)
|
||||
#quality_estimated = models.BooleanField()
|
||||
#quality_calculated = models.BooleanField()
|
||||
#quality_interpreted = models.BooleanField()
|
||||
day1 = models.IntegerField(default=0)
|
||||
month1 = models.IntegerField(default=0)
|
||||
year1 = models.IntegerField(default=0)
|
||||
slash1 = models.BooleanField(default=False)
|
||||
day2 = models.IntegerField(blank=True, null=True)
|
||||
month2 = models.IntegerField(blank=True, null=True)
|
||||
year2 = models.IntegerField(blank=True, null=True)
|
||||
slash2 = models.NullBooleanField(blank=True, null=True)
|
||||
text = models.CharField(max_length=80, blank=True)
|
||||
sortval = models.IntegerField(default=0)
|
||||
newyear = models.IntegerField(default=0)
|
||||
|
||||
def set_date_from_datetime(self, date_time, text=""):
|
||||
"""
|
||||
Sets Date fields from an object that has year, month, and day
|
||||
properties.
|
||||
"""
|
||||
y, m, d = date_time.year, date_time.month, date_time.day
|
||||
self.set_ymd(self, y, m, d, text=text)
|
||||
|
||||
def set_date_from_ymd(self, y, m, d, text=""):
|
||||
"""
|
||||
Sets Date fields from a year, month, and day.
|
||||
"""
|
||||
gdate = GDate(y, m, d)
|
||||
gdate.text = text
|
||||
self.set_date_from_gdate(gdate)
|
||||
|
||||
def set_date_from_gdate(self, gdate):
|
||||
"""
|
||||
Sets Date fields from a Gramps date object.
|
||||
"""
|
||||
(self.calendar, self.modifier, self.quality, dateval, self.text,
|
||||
self.sortval, self.newyear) = gdate.serialize()
|
||||
if dateval is None:
|
||||
(self.day1, self.month1, self.year1, self.slash1) = 0, 0, 0, False
|
||||
(self.day2, self.month2, self.year2, self.slash2) = 0, 0, 0, False
|
||||
elif len(dateval) == 8:
|
||||
(self.day1, self.month1, self.year1, self.slash1,
|
||||
self.day2, self.month2, self.year2, self.slash2) = dateval
|
||||
elif len(dateval) == 4:
|
||||
(self.day1, self.month1, self.year1, self.slash1) = dateval
|
||||
(self.day2, self.month2, self.year2, self.slash2) = 0, 0, 0, False
|
||||
|
||||
#---------------------------------------------------------------------------
|
||||
#
|
||||
# Primary Tables
|
||||
#
|
||||
#---------------------------------------------------------------------------
|
||||
|
||||
class Config(models.Model):
|
||||
"""
|
||||
All of the meta config items for the entire system.
|
||||
"""
|
||||
setting = models.CharField('config setting', max_length=25)
|
||||
description = models.TextField('description')
|
||||
value_type = models.CharField('type of value', max_length=25)
|
||||
value = models.TextField('value')
|
||||
|
||||
class Tag(models.Model):
|
||||
handle = models.CharField(max_length=19, unique=True)
|
||||
last_saved = models.DateTimeField('last changed', auto_now=True)
|
||||
last_changed = models.DateTimeField('last changed', null=True,
|
||||
blank=True) # user edits
|
||||
last_changed_by = models.TextField(blank=True, null=True)
|
||||
|
||||
name = models.TextField('name')
|
||||
color = models.CharField(max_length=13) # "#000000000000" # Black
|
||||
priority = models.IntegerField('priority', blank=False)
|
||||
|
||||
# Just the following have tag lists:
|
||||
# ---------------------------------
|
||||
#src/gen/lib/family.py
|
||||
#src/gen/lib/mediaobj.py
|
||||
#src/gen/lib/note.py
|
||||
#src/gen/lib/person.py
|
||||
|
||||
class PrimaryObject(models.Model):
|
||||
"""
|
||||
Common attribute of all primary objects with key on the handle
|
||||
"""
|
||||
class Meta: abstract = True
|
||||
|
||||
## Fields:
|
||||
id = models.AutoField(primary_key=True)
|
||||
handle = models.CharField(max_length=19, unique=True)
|
||||
gramps_id = models.CharField('gramps id', max_length=25, blank=True)
|
||||
last_saved = models.DateTimeField('last changed', auto_now=True)
|
||||
last_changed = models.DateTimeField('last changed', null=True,
|
||||
blank=True) # user edits
|
||||
last_changed_by = models.TextField(blank=True, null=True)
|
||||
|
||||
private = models.BooleanField('private')
|
||||
#attributes = models.ManyToManyField("Attribute", blank=True, null=True)
|
||||
cache = models.TextField(blank=True, null=True)
|
||||
|
||||
def __unicode__(self): return "%s: %s" % (self.__class__.__name__,
|
||||
self.gramps_id)
|
||||
|
||||
class Person(PrimaryObject):
|
||||
"""
|
||||
The model for the person object
|
||||
"""
|
||||
gender_type = models.ForeignKey('GenderType')
|
||||
probably_alive = models.BooleanField("Probably alive")
|
||||
families = models.ManyToManyField('Family', blank=True, null=True)
|
||||
parent_families = models.ManyToManyField('Family',
|
||||
related_name="parent_families",
|
||||
blank=True, null=True)
|
||||
#addresses = models.ManyToManyField('Address', null=True, blank=True)
|
||||
references = generic.GenericRelation('PersonRef', related_name="refs",
|
||||
content_type_field="object_type",
|
||||
object_id_field="object_id")
|
||||
birth = models.ForeignKey("Event", related_name="birth", blank=True, null=True)
|
||||
death = models.ForeignKey("Event", related_name="death", blank=True, null=True)
|
||||
|
||||
birth_ref_index = models.IntegerField("Birth Reference Index", default=-1)
|
||||
death_ref_index = models.IntegerField("Death Reference Index", default=-1)
|
||||
|
||||
tags = models.ManyToManyField('Tag', blank=True, null=True)
|
||||
|
||||
# Others keys here:
|
||||
# .name_set
|
||||
# .address_set
|
||||
# .lds_set
|
||||
# .url_set
|
||||
|
||||
def get_primary_name(self):
|
||||
"""
|
||||
Return the preferred name of a person.
|
||||
"""
|
||||
try:
|
||||
return self.name_set.get(preferred=True)
|
||||
except:
|
||||
return ""
|
||||
|
||||
def __unicode__(self):
|
||||
return str(self.get_primary_name())
|
||||
|
||||
def make_tag_list(self):
|
||||
return tuple()
|
||||
|
||||
class Family(PrimaryObject):
|
||||
father = models.ForeignKey('Person', related_name="father_ref",
|
||||
null=True, blank=True)
|
||||
mother = models.ForeignKey('Person', related_name="mother_ref",
|
||||
null=True, blank=True)
|
||||
family_rel_type = models.ForeignKey('FamilyRelType')
|
||||
tags = models.ManyToManyField('Tag', blank=True, null=True)
|
||||
|
||||
def make_tag_list(self):
|
||||
return tuple()
|
||||
|
||||
#lds_list = models.ManyToManyField('Lds', null=True, blank=True)
|
||||
|
||||
# Others keys here:
|
||||
# .lds_set
|
||||
|
||||
class Source(PrimaryObject):
|
||||
title = models.CharField(max_length=50, blank=True)
|
||||
author = models.CharField(max_length=50, blank=True)
|
||||
pubinfo = models.CharField(max_length=50, blank=True)
|
||||
abbrev = models.CharField(max_length=50, blank=True)
|
||||
#datamaps = models.ManyToManyField('Datamap', null=True, blank=True)
|
||||
references = generic.GenericRelation('SourceRef', related_name="refs",
|
||||
content_type_field="object_type",
|
||||
object_id_field="object_id")
|
||||
# Other keys here:
|
||||
# .datamap_set
|
||||
|
||||
class Event(DateObject, PrimaryObject):
|
||||
event_type = models.ForeignKey('EventType')
|
||||
description = models.CharField('description', max_length=50, blank=True)
|
||||
place = models.ForeignKey('Place', null=True)
|
||||
references = generic.GenericRelation('EventRef', related_name="refs",
|
||||
content_type_field="object_type",
|
||||
object_id_field="object_id")
|
||||
|
||||
class Repository(PrimaryObject):
|
||||
repository_type = models.ForeignKey('RepositoryType')
|
||||
name = models.TextField(blank=True)
|
||||
#addresses = models.ManyToManyField('Address', null=True, blank=True)
|
||||
references = generic.GenericRelation('RepositoryRef', related_name="refs",
|
||||
content_type_field="object_type",
|
||||
object_id_field="object_id")
|
||||
#url_list = models.ManyToManyField('Url', null=True, blank=True)
|
||||
|
||||
# Others keys here:
|
||||
# .address_set
|
||||
# .url_set
|
||||
|
||||
class Place(PrimaryObject):
|
||||
title = models.TextField(blank=True)
|
||||
#locations = models.ManyToManyField('Location', null=True, blank=True)
|
||||
long = models.TextField(blank=True)
|
||||
lat = models.TextField(blank=True)
|
||||
#url_list = models.ManyToManyField('Url', null=True, blank=True)
|
||||
|
||||
# Others keys here:
|
||||
# .url_set
|
||||
# .location_set
|
||||
|
||||
class Media(DateObject, PrimaryObject):
|
||||
path = models.TextField(blank=True)
|
||||
mime = models.TextField(blank=True, null=True)
|
||||
desc = models.TextField(blank=True)
|
||||
references = generic.GenericRelation('MediaRef', related_name="refs",
|
||||
content_type_field="object_type",
|
||||
object_id_field="object_id")
|
||||
tags = models.ManyToManyField('Tag', blank=True, null=True)
|
||||
|
||||
def make_tag_list(self):
|
||||
return tuple()
|
||||
|
||||
class Note(PrimaryObject):
|
||||
note_type = models.ForeignKey('NoteType')
|
||||
text = models.TextField(blank=True)
|
||||
preformatted = models.BooleanField('preformatted')
|
||||
references = generic.GenericRelation('NoteRef', related_name="refs",
|
||||
content_type_field="object_type",
|
||||
object_id_field="object_id")
|
||||
tags = models.ManyToManyField('Tag', blank=True, null=True)
|
||||
|
||||
def make_tag_list(self):
|
||||
return tuple()
|
||||
|
||||
#---------------------------------------------------------------------------
|
||||
#
|
||||
# Secondary Tables
|
||||
#
|
||||
#---------------------------------------------------------------------------
|
||||
|
||||
class SecondaryObject(models.Model):
|
||||
"""
|
||||
We use interlinked objects, secondary object is the table for primary
|
||||
objects to refer to when linking to non primary objects
|
||||
"""
|
||||
class Meta: abstract = True
|
||||
|
||||
private = models.BooleanField()
|
||||
last_saved = models.DateTimeField('last changed', auto_now=True)
|
||||
last_changed = models.DateTimeField('last changed', null=True,
|
||||
blank=True) # user edits
|
||||
last_changed_by = models.TextField(blank=True, null=True)
|
||||
order = models.PositiveIntegerField(default=1)
|
||||
|
||||
class Surname(models.Model):
|
||||
"""
|
||||
Surname table, which links to name.
|
||||
"""
|
||||
name_origin_type = models.ForeignKey('NameOriginType',
|
||||
related_name="name_origin_code",
|
||||
default=2)
|
||||
surname = models.TextField(blank=True)
|
||||
prefix = models.TextField(blank=True)
|
||||
primary = models.BooleanField('Primary surname?')
|
||||
connector = models.TextField(blank=True)
|
||||
name = models.ForeignKey("Name")
|
||||
|
||||
def __unicode__(self):
|
||||
return "%s" % self.surname
|
||||
|
||||
class Name(DateObject, SecondaryObject):
|
||||
name_type = models.ForeignKey('NameType',
|
||||
related_name="name_code",
|
||||
default=2)
|
||||
preferred = models.BooleanField('Preferred name?')
|
||||
first_name = models.TextField(blank=True)
|
||||
suffix = models.TextField(blank=True)
|
||||
title = models.TextField(blank=True)
|
||||
call = models.TextField(blank=True)
|
||||
nick = models.TextField(blank=True)
|
||||
famnick = models.TextField(blank=True)
|
||||
group_as = models.TextField(blank=True)
|
||||
sort_as = models.ForeignKey('NameFormatType',
|
||||
related_name="sort_as",
|
||||
default=1)
|
||||
display_as = models.ForeignKey('NameFormatType',
|
||||
related_name="display_as",
|
||||
default=1)
|
||||
## Key:
|
||||
person = models.ForeignKey("Person")
|
||||
_sanitized = False
|
||||
|
||||
def get_primary_surname(self):
|
||||
try:
|
||||
return self.surname_set.get(primary=True).surname
|
||||
except:
|
||||
return ""
|
||||
|
||||
def __unicode__(self):
|
||||
return "%s, %s" % (self.get_primary_surname(),
|
||||
self.first_name)
|
||||
@staticmethod
|
||||
def get_dummy():
|
||||
name = Name()
|
||||
#name.
|
||||
|
||||
def sanitize(self):
|
||||
if not self._sanitized:
|
||||
self._sanitized = True
|
||||
if self.person.probably_alive:
|
||||
self.first_name = "[Living]"
|
||||
self.call = ""
|
||||
self.group_as = ""
|
||||
self.title = ""
|
||||
|
||||
def make_surname_list(self):
|
||||
return [(x.surname, x.prefix, x.primary,
|
||||
tuple(x.name_origin_type), x.connector) for x in
|
||||
self.surname_set.all()]
|
||||
|
||||
class Lds(DateObject, SecondaryObject):
|
||||
"""
|
||||
BAPTISM = 0
|
||||
ENDOWMENT = 1
|
||||
SEAL_TO_PARENTS = 2
|
||||
SEAL_TO_SPOUSE = 3
|
||||
CONFIRMATION = 4
|
||||
|
||||
DEFAULT_TYPE = BAPTISM
|
||||
|
||||
|
||||
STATUS_NONE = 0
|
||||
STATUS_BIC = 1
|
||||
STATUS_CANCELED = 2
|
||||
STATUS_CHILD = 3
|
||||
STATUS_CLEARED = 4
|
||||
STATUS_COMPLETED = 5
|
||||
STATUS_DNS = 6
|
||||
STATUS_INFANT = 7
|
||||
STATUS_PRE_1970 = 8
|
||||
STATUS_QUALIFIED = 9
|
||||
STATUS_DNS_CAN = 10
|
||||
STATUS_STILLBORN = 11
|
||||
STATUS_SUBMITTED = 12
|
||||
STATUS_UNCLEARED = 13
|
||||
|
||||
DEFAULT_STATUS = STATUS_NONE
|
||||
"""
|
||||
lds_type = models.ForeignKey('LdsType')
|
||||
place = models.ForeignKey('Place', null=True)
|
||||
famc = models.ForeignKey('Family', related_name="famc", null=True)
|
||||
temple = models.TextField(blank=True)
|
||||
status = models.ForeignKey('LdsStatus')
|
||||
|
||||
person = models.ForeignKey("Person", null=True, blank=True)
|
||||
family = models.ForeignKey("Family", null=True, blank=True)
|
||||
|
||||
class Markup(models.Model):
|
||||
note = models.ForeignKey('Note')
|
||||
markup_type = models.ForeignKey('MarkupType')
|
||||
order = models.PositiveIntegerField()
|
||||
string = models.TextField(blank=True, null=True)
|
||||
start_stop_list = models.TextField(default="[]")
|
||||
|
||||
class Datamap(models.Model):
|
||||
key = models.CharField(max_length=80, blank=True)
|
||||
value = models.CharField(max_length=80, blank=True)
|
||||
|
||||
source = models.ForeignKey("Source", null=True, blank=True)
|
||||
|
||||
class Address(DateObject, SecondaryObject):
|
||||
#locations = models.ManyToManyField('Location', null=True)
|
||||
person = models.ForeignKey('Person', null=True, blank=True)
|
||||
repository = models.ForeignKey('Repository', null=True, blank=True)
|
||||
|
||||
# Others keys here:
|
||||
# .location_set
|
||||
|
||||
|
||||
class Location(models.Model):
|
||||
street = models.TextField(blank=True)
|
||||
locality = models.TextField(blank=True)
|
||||
city = models.TextField(blank=True)
|
||||
county = models.TextField(blank=True)
|
||||
state = models.TextField(blank=True)
|
||||
country = models.TextField(blank=True)
|
||||
postal = models.TextField(blank=True)
|
||||
phone = models.TextField(blank=True)
|
||||
parish = models.TextField(blank=True, null=True)
|
||||
order = models.PositiveIntegerField()
|
||||
|
||||
place = models.ForeignKey("Place", null=True, blank=True)
|
||||
address = models.ForeignKey("Address", null=True, blank=True)
|
||||
|
||||
class Url(models.Model):
|
||||
private = models.BooleanField('private url?')
|
||||
path = models.TextField(blank=True, null=True)
|
||||
desc = models.TextField(blank=True, null=True)
|
||||
url_type = models.ForeignKey('UrlType')
|
||||
order = models.PositiveIntegerField()
|
||||
|
||||
person = models.ForeignKey("Person", null=True, blank=True)
|
||||
place = models.ForeignKey("Place", null=True, blank=True)
|
||||
repository = models.ForeignKey("Repository", null=True, blank=True)
|
||||
|
||||
class Attribute(models.Model):
|
||||
private = models.BooleanField('private attribute?')
|
||||
attribute_type = models.ForeignKey('AttributeType')
|
||||
value = models.TextField(blank=True, null=True)
|
||||
|
||||
object_type = models.ForeignKey(ContentType)
|
||||
object_id = models.PositiveIntegerField()
|
||||
attribute_of = generic.GenericForeignKey("object_type", "object_id")
|
||||
|
||||
## consider using:
|
||||
## URLField
|
||||
|
||||
#---------------------------------------------------------------------------
|
||||
#
|
||||
# Reference Objects
|
||||
#
|
||||
#---------------------------------------------------------------------------
|
||||
|
||||
class BaseRef(models.Model):
|
||||
class Meta: abstract = True
|
||||
|
||||
object_type = models.ForeignKey(ContentType)
|
||||
object_id = models.PositiveIntegerField()
|
||||
referenced_by = generic.GenericForeignKey("object_type", "object_id")
|
||||
|
||||
order = models.PositiveIntegerField()
|
||||
last_saved = models.DateTimeField('last changed', auto_now=True)
|
||||
last_changed = models.DateTimeField('last changed', null=True) # user edits
|
||||
last_changed_by = models.TextField(blank=True, null=True)
|
||||
|
||||
#attributes = models.ManyToManyField("Attribute", null=True)
|
||||
private = models.BooleanField()
|
||||
|
||||
class NoteRef(BaseRef):
|
||||
ref_object = models.ForeignKey('Note')
|
||||
|
||||
def __unicode__(self):
|
||||
return "NoteRef to " + str(self.ref_object)
|
||||
|
||||
class SourceRef(DateObject, BaseRef):
|
||||
ref_object = models.ForeignKey('Source')
|
||||
page = models.CharField(max_length=50)
|
||||
confidence = models.IntegerField()
|
||||
|
||||
def __unicode__(self):
|
||||
return "SourceRef to " + str(self.ref_object)
|
||||
|
||||
class EventRef(BaseRef):
|
||||
ref_object = models.ForeignKey('Event')
|
||||
role_type = models.ForeignKey('EventRoleType')
|
||||
|
||||
def __unicode__(self):
|
||||
return "EventRef to " + str(self.ref_object)
|
||||
|
||||
class RepositoryRef(BaseRef):
|
||||
ref_object = models.ForeignKey('Repository')
|
||||
source_media_type = models.ForeignKey('SourceMediaType')
|
||||
call_number = models.CharField(max_length=50)
|
||||
|
||||
def __unicode__(self):
|
||||
return "RepositoryRef to " + str(self.ref_object)
|
||||
|
||||
class PersonRef(BaseRef):
|
||||
ref_object = models.ForeignKey('Person')
|
||||
description = models.CharField(max_length=50)
|
||||
|
||||
def __unicode__(self):
|
||||
return "PersonRef to " + str(self.ref_object)
|
||||
|
||||
class ChildRef(BaseRef):
|
||||
father_rel_type = models.ForeignKey('ChildRefType',
|
||||
related_name="child_father_rel")
|
||||
mother_rel_type = models.ForeignKey('ChildRefType',
|
||||
related_name="child_mother_rel")
|
||||
ref_object = models.ForeignKey('Person')
|
||||
|
||||
def __unicode__(self):
|
||||
return "ChildRef to " + str(self.ref_object)
|
||||
|
||||
class MediaRef(BaseRef):
|
||||
x1 = models.IntegerField()
|
||||
y1 = models.IntegerField()
|
||||
x2 = models.IntegerField()
|
||||
y2 = models.IntegerField()
|
||||
ref_object = models.ForeignKey('Media')
|
||||
|
||||
def __unicode__(self):
|
||||
return "MediaRef to " + str(self.ref_object)
|
||||
|
||||
class Report(models.Model):
|
||||
name = models.TextField(blank=True, null=True)
|
||||
handle = models.TextField(blank=True, null=True) # report_id
|
||||
report_type = models.TextField(blank=True, null=True)
|
||||
options = models.TextField(blank=True, null=True)
|
||||
|
||||
class Result(models.Model):
|
||||
name = models.TextField(blank=True, null=True)
|
||||
filename = models.TextField(blank=True, null=True)
|
||||
run_on = models.DateTimeField('run on', auto_now=True)
|
||||
run_by = models.TextField('run by', blank=True, null=True)
|
||||
status = models.TextField(blank=True, null=True)
|
||||
|
||||
TABLES = [
|
||||
("abstract", mGrampsType),
|
||||
("type", NameType),
|
||||
("type", NameOriginType),
|
||||
("type", NameFormatType),
|
||||
("type", AttributeType),
|
||||
("type", UrlType),
|
||||
("type", ChildRefType),
|
||||
("type", RepositoryType),
|
||||
("type", EventType),
|
||||
("type", FamilyRelType),
|
||||
("type", SourceMediaType),
|
||||
("type", EventRoleType),
|
||||
("type", NoteType),
|
||||
("type", GenderType),
|
||||
("type", LdsType),
|
||||
("type", LdsStatus),
|
||||
("type", ThemeType),
|
||||
("abstract", DateObject),
|
||||
("abstract", PrimaryObject),
|
||||
("primary", Person),
|
||||
("primary", Family),
|
||||
("primary", Source),
|
||||
("primary", Event),
|
||||
("primary", Repository),
|
||||
("primary", Place),
|
||||
("primary", Media),
|
||||
("primary", Note),
|
||||
("abstract", SecondaryObject),
|
||||
("secondary", Attribute),
|
||||
("secondary", Datamap),
|
||||
("secondary", Name),
|
||||
("secondary", Surname),
|
||||
("secondary", Lds),
|
||||
("secondary", Markup),
|
||||
("secondary", Address),
|
||||
("secondary", Location),
|
||||
("secondary", Url),
|
||||
("abstract", BaseRef),
|
||||
("ref", NoteRef),
|
||||
("ref", SourceRef),
|
||||
("ref", EventRef),
|
||||
("ref", RepositoryRef),
|
||||
("ref", PersonRef),
|
||||
("ref", ChildRef),
|
||||
("ref", MediaRef),
|
||||
("system", Config),
|
||||
("system", Report),
|
||||
("system", Result),
|
||||
]
|
||||
|
||||
def no_style():
|
||||
"""Returns a Django Style object that has no colors."""
|
||||
class dummy(object):
|
||||
def __getattr__(self, attr):
|
||||
return lambda x: x
|
||||
return dummy()
|
||||
|
||||
def clear_tables(*categories):
|
||||
"""
|
||||
Clear the entries of categories of tables. Category is:
|
||||
"abstract", "type", "ref", "system", "primary" and "secondary".
|
||||
"""
|
||||
# FIXME: I don't think this works anymore...
|
||||
from django.db import connection, transaction
|
||||
cursor = connection.cursor()
|
||||
flush_tables = []
|
||||
for (category, model) in get_tables(*categories):
|
||||
flush_tables.append(model._meta.db_table)
|
||||
# tables = connection.introspection.table_names()
|
||||
# flush_tables = [table for table in tables if not table.endswith("type")]
|
||||
statements = connection.ops.sql_flush(no_style(),
|
||||
flush_tables,
|
||||
connection.introspection.sequence_list())
|
||||
for statement in statements:
|
||||
cursor.execute(statement)
|
||||
transaction.commit_unless_managed()
|
||||
|
||||
def table_stats(*categories):
|
||||
"""
|
||||
Shows the record counts for each table category.
|
||||
"""
|
||||
tables = get_tables(*categories)
|
||||
tables.sort()
|
||||
for pair in tables:
|
||||
print ("%-25s" % pair[1].__name__), ":", \
|
||||
pair[1].objects.all().count()
|
||||
|
||||
def get_tables(*categories):
|
||||
return [pair for pair in TABLES if (pair[0] in categories) or
|
||||
("all" in categories) and pair[0] != "abstract"]
|
||||
|
||||
46
src/webapp/grampsdb/profile.py
Normal file
46
src/webapp/grampsdb/profile.py
Normal file
@@ -0,0 +1,46 @@
|
||||
# Gramps - a GTK+/GNOME based genealogy program
|
||||
#
|
||||
# Copyright (C) 2009 Douglas S. Blank <doug.blank@gmail.com>
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 2 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
#
|
||||
# $Id$
|
||||
#
|
||||
|
||||
from django.db import models
|
||||
from django.db.models.signals import post_save
|
||||
from django.contrib.auth.models import User
|
||||
|
||||
class Profile(models.Model):
|
||||
"""
|
||||
Used to save additional information of a user, such as
|
||||
themes, bookmarks, etc.
|
||||
"""
|
||||
user = models.ForeignKey(User, unique=True)
|
||||
css_theme = models.CharField(max_length=40,
|
||||
default="Web_Mainz.css")
|
||||
|
||||
def __unicode__(self):
|
||||
return unicode(self.user)
|
||||
|
||||
def save_profile(sender, instance, created, **kwargs):
|
||||
"""
|
||||
Creates the profile when the user gets created.
|
||||
"""
|
||||
if created:
|
||||
profile = Profile(user=instance)
|
||||
profile.save()
|
||||
|
||||
post_save.connect(save_profile, sender=User)
|
||||
3
src/webapp/grampsdb/sql/childref.sql
Normal file
3
src/webapp/grampsdb/sql/childref.sql
Normal file
@@ -0,0 +1,3 @@
|
||||
|
||||
CREATE INDEX grampsdb_childref_object_id_object_type_id
|
||||
ON grampsdb_childref (object_id, object_type_id);
|
||||
3
src/webapp/grampsdb/sql/eventref.sql
Normal file
3
src/webapp/grampsdb/sql/eventref.sql
Normal file
@@ -0,0 +1,3 @@
|
||||
|
||||
CREATE INDEX grampsdb_eventref_object_id_object_type_id
|
||||
ON grampsdb_eventref (object_id, object_type_id);
|
||||
1
src/webapp/grampsdb/sql/name.sql
Normal file
1
src/webapp/grampsdb/sql/name.sql
Normal file
@@ -0,0 +1 @@
|
||||
|
||||
3
src/webapp/grampsdb/sql/noteref.sql
Normal file
3
src/webapp/grampsdb/sql/noteref.sql
Normal file
@@ -0,0 +1,3 @@
|
||||
|
||||
CREATE INDEX grampsdb_noteref_object_id_object_type_id
|
||||
ON grampsdb_noteref (object_id, object_type_id);
|
||||
3
src/webapp/grampsdb/sql/sourceref.sql
Normal file
3
src/webapp/grampsdb/sql/sourceref.sql
Normal file
@@ -0,0 +1,3 @@
|
||||
|
||||
CREATE INDEX grampsdb_sourceref_object_id_object_type_id
|
||||
ON grampsdb_sourceref (object_id, object_type_id);
|
||||
0
src/webapp/grampsdb/templatetags/__init__.py
Normal file
0
src/webapp/grampsdb/templatetags/__init__.py
Normal file
142
src/webapp/grampsdb/templatetags/my_tags.py
Normal file
142
src/webapp/grampsdb/templatetags/my_tags.py
Normal file
@@ -0,0 +1,142 @@
|
||||
import re
|
||||
|
||||
from django import template
|
||||
from django.template import escape, Library
|
||||
from django.utils.safestring import mark_safe
|
||||
from web.utils import *
|
||||
import web.utils
|
||||
|
||||
register = Library()
|
||||
|
||||
def eval_template_exp(item, context):
|
||||
"""
|
||||
Wrapper to allow negation of variables in templates. Use
|
||||
"!variable".
|
||||
"""
|
||||
if item.var.startswith("!"):
|
||||
return not template.Variable(item.var[1:]).resolve(context)
|
||||
else:
|
||||
return item.resolve(context)
|
||||
|
||||
class TemplateNode(template.Node):
|
||||
def __init__(self, args, var_name, func):
|
||||
self.args = map(template.Variable, args)
|
||||
self.var_name = var_name
|
||||
self.func = func
|
||||
|
||||
def render(self, context):
|
||||
value = self.func(*[eval_template_exp(item, context)
|
||||
for item in self.args])
|
||||
if self.var_name:
|
||||
context[self.var_name] = value
|
||||
return ''
|
||||
else:
|
||||
return value
|
||||
|
||||
def parse_tokens(tokens):
|
||||
items = tokens.split_contents()
|
||||
# {% tag_name arg1 arg2 arg3 as variable %}
|
||||
# {% tag_name arg1 arg2 arg3 %}
|
||||
tag_name = items[0]
|
||||
if "as" == items[-2]:
|
||||
var_name = items[-1]
|
||||
args = items[1:-2]
|
||||
else:
|
||||
var_name = None
|
||||
args = items[1:]
|
||||
return (tag_name, args, var_name)
|
||||
|
||||
def make_tag(func):
|
||||
def do_func(parser, tokens):
|
||||
tag_name, args, var_name = parse_tokens(tokens)
|
||||
return TemplateNode(args, var_name, func)
|
||||
return do_func
|
||||
|
||||
for filter_name in util_filters:
|
||||
func = getattr(web.utils, filter_name)
|
||||
func.is_safe = True
|
||||
register.filter(filter_name, func)
|
||||
|
||||
for tag_name in util_tags:
|
||||
func = getattr(web.utils, tag_name)
|
||||
register.tag(tag_name, make_tag(func))
|
||||
|
||||
probably_alive.is_safe = True
|
||||
register.filter('probably_alive', probably_alive)
|
||||
|
||||
format_number.is_safe = True
|
||||
register.filter('format_number', format_number)
|
||||
|
||||
person_get_birth_date.is_safe = True
|
||||
register.filter('person_get_birth_date', person_get_birth_date)
|
||||
|
||||
person_get_death_date.is_safe = True
|
||||
register.filter('person_get_death_date', person_get_death_date)
|
||||
|
||||
display_date.is_safe = True
|
||||
register.filter('display_date', display_date)
|
||||
|
||||
person_get_event.is_safe = True
|
||||
register.filter('person_get_events', person_get_event)
|
||||
|
||||
def preview(text, width=40):
|
||||
text = text.replace("\n", " ")
|
||||
return escape(text[:width])
|
||||
preview.is_safe = True
|
||||
register.filter('preview', preview)
|
||||
|
||||
make_name.is_safe = True
|
||||
register.filter('make_name', make_name)
|
||||
|
||||
def preferred(person):
|
||||
try:
|
||||
name = person.name_set.get(preferred=True)
|
||||
except:
|
||||
name = None
|
||||
return name
|
||||
preferred.is_safe = True
|
||||
register.filter('preferred', preferred)
|
||||
|
||||
def missing(data):
|
||||
if data.strip() == "":
|
||||
return "[Missing]"
|
||||
return escape(data)
|
||||
missing.is_safe = True
|
||||
register.filter('missing', missing)
|
||||
|
||||
def currentSection(view1, view2):
|
||||
if view1.strip().lower() == view2.strip().lower():
|
||||
return "class=CurrentSection"
|
||||
return ""
|
||||
currentSection.is_safe = True
|
||||
register.filter('currentSection', currentSection)
|
||||
|
||||
def row_count(row, page):
|
||||
return row + (page.number - 1) * page.paginator.per_page
|
||||
|
||||
register.filter('row_count', row_count)
|
||||
|
||||
def table_header(context, headers = None):
|
||||
# add things for the header here
|
||||
if headers:
|
||||
context["headers"] = headers
|
||||
return context
|
||||
|
||||
register.inclusion_tag('table_header.html',
|
||||
takes_context=True)(table_header)
|
||||
|
||||
def paginator(context, adjacent_pages=2):
|
||||
"""
|
||||
To be used in conjunction with the object_list generic view.
|
||||
|
||||
Adds pagination context variables for use in displaying first, adjacent and
|
||||
last page links in addition to those created by the object_list generic
|
||||
view.
|
||||
|
||||
"""
|
||||
results_this_page = context["page"].object_list.count()
|
||||
context.update({'results_this_page': results_this_page,})
|
||||
return context
|
||||
|
||||
register.inclusion_tag('paginator.html',
|
||||
takes_context=True)(paginator)
|
||||
726
src/webapp/grampsdb/views.py
Normal file
726
src/webapp/grampsdb/views.py
Normal file
@@ -0,0 +1,726 @@
|
||||
# Gramps - a GTK+/GNOME based genealogy program
|
||||
#
|
||||
# Copyright (C) 2009 Douglas S. Blank <doug.blank@gmail.com>
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 2 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
#
|
||||
# $Id$
|
||||
#
|
||||
|
||||
""" Main view handlers """
|
||||
|
||||
import os
|
||||
|
||||
#------------------------------------------------------------------------
|
||||
#
|
||||
# Django Modules
|
||||
#
|
||||
#------------------------------------------------------------------------
|
||||
from django.contrib.auth import logout
|
||||
from django.contrib.auth.models import User
|
||||
from django.core.paginator import Paginator, InvalidPage, EmptyPage
|
||||
from django.http import Http404, HttpResponseRedirect, HttpResponse
|
||||
from django.shortcuts import get_object_or_404, render_to_response, redirect
|
||||
from django.template import Context, RequestContext, escape
|
||||
from django.db.models import Q
|
||||
|
||||
#------------------------------------------------------------------------
|
||||
#
|
||||
# Gramps Modules
|
||||
#
|
||||
#------------------------------------------------------------------------
|
||||
import web
|
||||
from web.grampsdb.models import *
|
||||
from web.grampsdb.forms import *
|
||||
from web.dbdjango import DbDjango
|
||||
|
||||
import gen.proxy
|
||||
from Utils import create_id
|
||||
import const
|
||||
|
||||
_ = lambda text: text
|
||||
|
||||
# Views: [(<Nice name plural>, /<name>/handle, <Model>), ]
|
||||
VIEWS = [(_('People'), 'person', Name),
|
||||
(_('Families'), 'family', Family),
|
||||
(_('Events'), 'event', Event),
|
||||
(_('Notes'), 'note', Note),
|
||||
(_('Media'), 'media', Media),
|
||||
(_('Sources'), 'source', Source),
|
||||
(_('Places'), 'place', Place),
|
||||
(_('Repositories'), 'repository', Repository),
|
||||
(_('Tags'), 'tag', Tag),
|
||||
]
|
||||
|
||||
def context_processor(request):
|
||||
"""
|
||||
This function is executed before template processing.
|
||||
takes a request, and returns a dictionary context.
|
||||
"""
|
||||
context = {}
|
||||
if request.user.is_authenticated():
|
||||
profile = request.user.get_profile()
|
||||
context["css_theme"] = profile.css_theme
|
||||
else:
|
||||
context["css_theme"] = "Web_Mainz.css"
|
||||
# Other things for all environments:
|
||||
context["gramps_version"] = const.VERSION
|
||||
context["views"] = VIEWS
|
||||
context["True"] = True
|
||||
context["False"] = False
|
||||
context["default"] = ""
|
||||
return context
|
||||
|
||||
def main_page(request):
|
||||
context = RequestContext(request)
|
||||
context["view"] = 'home'
|
||||
context["tview"] = _('Home')
|
||||
return render_to_response("main_page.html", context)
|
||||
|
||||
def logout_page(request):
|
||||
context = RequestContext(request)
|
||||
context["view"] = 'home'
|
||||
context["tview"] = _('Home')
|
||||
logout(request)
|
||||
# TODO: allow this once we have an error page
|
||||
#if request.GET.has_key("next"):
|
||||
# return redirect(request.GET.get("next"), context)
|
||||
return HttpResponseRedirect('/')
|
||||
|
||||
def user_page(request, username):
|
||||
try:
|
||||
user = User.objects.get(username=username)
|
||||
except User.DoesNotExist:
|
||||
raise Http404(_('Requested user not found.'))
|
||||
context = RequestContext(request)
|
||||
context["username"] = username
|
||||
context["view"] = 'user'
|
||||
context["tview"] = _('User')
|
||||
return render_to_response('user_page.html', context)
|
||||
|
||||
def fix_person(request, person):
|
||||
try:
|
||||
name = person.name_set.get(preferred=True)
|
||||
except:
|
||||
names = person.name_set.all().order_by("order")
|
||||
if names.count() == 0:
|
||||
name = Name(person=person,
|
||||
surname_set=[Surname(surname="? Fixed")],
|
||||
first_name="? Missing name",
|
||||
preferred=True)
|
||||
name.save()
|
||||
else:
|
||||
order = 1
|
||||
for name in names:
|
||||
if order == 1:
|
||||
name.preferred = True
|
||||
else:
|
||||
name.preferred = False
|
||||
name.order = order
|
||||
name.save()
|
||||
order += 1
|
||||
if request:
|
||||
return redirect("/person/%s" % person.handle, request)
|
||||
|
||||
def set_date(obj):
|
||||
obj.calendar = 0
|
||||
obj.modifier = 0
|
||||
obj.quality = 0
|
||||
obj.text = ""
|
||||
obj.sortval = 0
|
||||
obj.newyear = 0
|
||||
obj.day1, obj.month1, obj.year1, obj.slash1 = 0, 0, 0, 0
|
||||
obj.day2, obj.month2, obj.year2, obj.slash2 = 0, 0, 0, 0
|
||||
|
||||
def view_name_detail(request, handle, order, action="view"):
|
||||
if order == "add":
|
||||
order = 0
|
||||
action = "add"
|
||||
if request.POST.has_key("action"):
|
||||
action = request.POST.get("action")
|
||||
if action == "view":
|
||||
person = Person.objects.get(handle=handle)
|
||||
try:
|
||||
name = person.name_set.filter(order=order)[0]
|
||||
except:
|
||||
return fix_person(request, person)
|
||||
form = NameForm(instance=name)
|
||||
form.model = name
|
||||
elif action == "edit":
|
||||
person = Person.objects.get(handle=handle)
|
||||
name = person.name_set.filter(order=order)[0]
|
||||
form = NameForm(instance=name)
|
||||
form.model = name
|
||||
elif action == "delete":
|
||||
person = Person.objects.get(handle=handle)
|
||||
names = person.name_set.all().order_by("order")
|
||||
if names.count() > 1:
|
||||
name_to_delete = names[0]
|
||||
was_preferred = name_to_delete.preferred
|
||||
name_to_delete.delete()
|
||||
names = person.name_set.all().order_by("order")
|
||||
for count in range(names[1:].count()):
|
||||
if was_preferred:
|
||||
names[count].preferred = True
|
||||
was_preferred = False
|
||||
names[count].order = count
|
||||
names[count].save()
|
||||
form = NameForm()
|
||||
name = Name()
|
||||
action = "back"
|
||||
elif action == "add": # add name
|
||||
person = Person.objects.get(handle=handle)
|
||||
name = Name(person=person,
|
||||
display_as=NameFormatType.objects.get(val=0),
|
||||
sort_as=NameFormatType.objects.get(val=0),
|
||||
name_type=NameType.objects.get(val=2))
|
||||
form = NameForm(instance=name)
|
||||
form.model = name
|
||||
action = "edit"
|
||||
elif action == "save":
|
||||
person = Person.objects.get(handle=handle)
|
||||
try:
|
||||
name = person.name_set.filter(order=order)[0]
|
||||
except:
|
||||
order = person.name_set.count() + 1
|
||||
name = Name(person=person, order=order)
|
||||
form = NameForm(request.POST, instance=name)
|
||||
form.model = name
|
||||
if form.is_valid():
|
||||
# now it is preferred:
|
||||
if name.preferred: # was preferred, stil must be
|
||||
form.cleaned_data["preferred"] = True
|
||||
elif form.cleaned_data["preferred"]: # now is
|
||||
# set all of the other names to be
|
||||
# not preferred:
|
||||
person.name_set.filter(~ Q(id=name.id)) \
|
||||
.update(preferred=False)
|
||||
# else some other name is preferred
|
||||
set_date(name)
|
||||
n = form.save()
|
||||
else:
|
||||
action = "edit"
|
||||
context = RequestContext(request)
|
||||
context["action"] = action
|
||||
context["tview"] = _('Name')
|
||||
context["view"] = 'name'
|
||||
context["handle"] = handle
|
||||
context["id"] = id
|
||||
context["person"] = person
|
||||
context["form"] = form
|
||||
context["order"] = name.order
|
||||
context["next"] = "/person/%s/name/%d" % (person.handle, name.order)
|
||||
view_template = "view_name_detail.html"
|
||||
if action == "save":
|
||||
context["action"] = "view"
|
||||
return redirect("/person/%s/name/%d" %
|
||||
(person.handle, name.order), context)
|
||||
elif action == "back":
|
||||
return redirect("/person/%s/" %
|
||||
(person.handle), context)
|
||||
else:
|
||||
return render_to_response(view_template, context)
|
||||
|
||||
def send_file(request, filename, mimetype):
|
||||
"""
|
||||
Send a file through Django without loading the whole file into
|
||||
memory at once. The FileWrapper will turn the file object into an
|
||||
iterator for chunks of 8KB.
|
||||
"""
|
||||
from django.core.servers.basehttp import FileWrapper
|
||||
wrapper = FileWrapper(file(filename))
|
||||
response = HttpResponse(wrapper, mimetype=mimetype)
|
||||
path, base = os.path.split(filename)
|
||||
response['Content-Length'] = os.path.getsize(filename)
|
||||
response['Content-Disposition'] = 'attachment; filename=%s' % base
|
||||
return response
|
||||
|
||||
def process_action(request, view, handle, action):
|
||||
from web.reports import import_file
|
||||
from web.reports import export_file
|
||||
from cli.plug import run_report
|
||||
db = DbDjango()
|
||||
if view == "report":
|
||||
if request.user.is_authenticated():
|
||||
profile = request.user.get_profile()
|
||||
report = Report.objects.get(handle=handle)
|
||||
if action == "run":
|
||||
args = {"off": "pdf"} # basic defaults
|
||||
# override from given defaults in table:
|
||||
if report.options:
|
||||
for pair in str(report.options).split(" "):
|
||||
if "=" in pair:
|
||||
key, value = pair.split("=", 1)
|
||||
args[key] = value
|
||||
# override from options on webpage:
|
||||
if request.GET.has_key("options"):
|
||||
options = str(request.GET.get("options"))
|
||||
if options:
|
||||
for pair in options.split("%3D"): # from webpage
|
||||
if "=" in pair:
|
||||
key, value = pair.split("=", 1)
|
||||
args[key] = value
|
||||
if report.report_type == "textreport":
|
||||
filename = "/tmp/%s-%s.%s" % (str(profile.user.username), str(handle), args["off"])
|
||||
run_report(db, handle, of=filename, **args)
|
||||
mimetype = 'application/%s' % args["off"]
|
||||
elif report.report_type == "export":
|
||||
filename = "/tmp/%s-%s.%s" % (str(profile.user.username), str(handle), args["off"])
|
||||
export_file(db, filename, lambda n: n) # callback
|
||||
mimetype = 'text/plain'
|
||||
else:
|
||||
pass # FIXME: error
|
||||
return send_file(request, filename, mimetype)
|
||||
# If failure, just fail for now:
|
||||
context = RequestContext(request)
|
||||
context["tview"] = "Results"
|
||||
#context["view"] = view
|
||||
#context["handle"] = handle
|
||||
#context["action"] = action
|
||||
context["message"] = "You need to be logged in."
|
||||
#context["message"] = filename
|
||||
return render_to_response("process_action.html", context)
|
||||
|
||||
def view_detail(request, view, handle, action="view"):
|
||||
context = RequestContext(request)
|
||||
context["action"] = action
|
||||
context["view"] = view
|
||||
if view == "event":
|
||||
try:
|
||||
obj = Event.objects.get(handle=handle)
|
||||
except:
|
||||
raise Http404(_("Requested %s does not exist.") % view)
|
||||
view_template = 'view_event_detail.html'
|
||||
context["tview"] = _("Event")
|
||||
elif view == "family":
|
||||
try:
|
||||
obj = Family.objects.get(handle=handle)
|
||||
except:
|
||||
raise Http404(_("Requested %s does not exist.") % view)
|
||||
view_template = 'view_family_detail.html'
|
||||
context["tview"] = _("Family")
|
||||
elif view == "media":
|
||||
try:
|
||||
obj = Media.objects.get(handle=handle)
|
||||
except:
|
||||
raise Http404(_("Requested %s does not exist.") % view)
|
||||
view_template = 'view_media_detail.html'
|
||||
context["tview"] = _("Media")
|
||||
elif view == "note":
|
||||
try:
|
||||
obj = Note.objects.get(handle=handle)
|
||||
except:
|
||||
raise Http404(_("Requested %s does not exist.") % view)
|
||||
view_template = 'view_note_detail.html'
|
||||
context["tview"] = _("Note")
|
||||
elif view == "person":
|
||||
return view_person_detail(request, view, handle, action)
|
||||
elif view == "place":
|
||||
try:
|
||||
obj = Place.objects.get(handle=handle)
|
||||
except:
|
||||
raise Http404(_("Requested %s does not exist.") % view)
|
||||
view_template = 'view_place_detail.html'
|
||||
context["tview"] = _("Place")
|
||||
elif view == "repository":
|
||||
try:
|
||||
obj = Repository.objects.get(handle=handle)
|
||||
except:
|
||||
raise Http404(_("Requested %s does not exist.") % view)
|
||||
view_template = 'view_repository_detail.html'
|
||||
context["tview"] = _("Repository")
|
||||
elif view == "source":
|
||||
try:
|
||||
obj = Source.objects.get(handle=handle)
|
||||
except:
|
||||
raise Http404(_("Requested %s does not exist.") % view)
|
||||
view_template = 'view_source_detail.html'
|
||||
context["tview"] = _("Source")
|
||||
elif view == "tag":
|
||||
try:
|
||||
obj = Tag.objects.get(handle=handle)
|
||||
except:
|
||||
raise Http404(_("Requested %s does not exist.") % view)
|
||||
view_template = 'view_tag_detail.html'
|
||||
context["tview"] = _("Tag")
|
||||
elif view == "report":
|
||||
try:
|
||||
obj = Report.objects.get(handle=handle)
|
||||
except:
|
||||
raise Http404(_("Requested %s does not exist.") % view)
|
||||
view_template = 'view_report_detail.html'
|
||||
context["tview"] = _("Report")
|
||||
else:
|
||||
raise Http404(_("Requested page type not known"))
|
||||
context[view] = obj
|
||||
context["next"] = "/%s/%s" % (view, obj.handle)
|
||||
return render_to_response(view_template, context)
|
||||
|
||||
def view_person_detail(request, view, handle, action="view"):
|
||||
context = RequestContext(request)
|
||||
if handle == "add":
|
||||
if request.POST.has_key("action"):
|
||||
action = request.POST.get("action")
|
||||
else:
|
||||
action = "add"
|
||||
elif request.POST.has_key("action"):
|
||||
action = request.POST.get("action")
|
||||
if request.user.is_authenticated():
|
||||
if action == "edit":
|
||||
# get all of the data:
|
||||
person = Person.objects.get(handle=handle)
|
||||
try:
|
||||
name = person.name_set.get(preferred=True)
|
||||
except:
|
||||
name = Name(person=person, preferred=True)
|
||||
pf = PersonForm(instance=person)
|
||||
pf.model = person
|
||||
nf = NameForm(instance=name)
|
||||
nf.model = name
|
||||
elif action == "add":
|
||||
# make new data:
|
||||
person = Person()
|
||||
name = Name(person=person, preferred=True,
|
||||
display_as=NameFormatType.objects.get(val=0),
|
||||
sort_as=NameFormatType.objects.get(val=0),
|
||||
name_type=NameType.objects.get(val=2))
|
||||
nf = NameForm(instance=name)
|
||||
nf.model = name
|
||||
pf = PersonForm(instance=person)
|
||||
pf.model = person
|
||||
action = "edit"
|
||||
elif action == "save":
|
||||
try:
|
||||
person = Person.objects.get(handle=handle)
|
||||
except:
|
||||
person = Person(handle=create_id())
|
||||
if person.id: # editing
|
||||
name = person.name_set.get(preferred=True)
|
||||
else: # adding a new person with new name
|
||||
name = Name(person=person, preferred=True)
|
||||
pf = PersonForm(request.POST, instance=person)
|
||||
pf.model = person
|
||||
nf = NameFormFromPerson(request.POST, instance=name)
|
||||
nf.model = name
|
||||
if nf.is_valid() and pf.is_valid():
|
||||
person = pf.save()
|
||||
name = nf.save(commit=False)
|
||||
name.person = person
|
||||
name.save()
|
||||
else:
|
||||
action = "edit"
|
||||
else: # view
|
||||
person = Person.objects.get(handle=handle)
|
||||
try:
|
||||
name = person.name_set.get(preferred=True)
|
||||
except:
|
||||
return fix_person(request, person)
|
||||
pf = PersonForm(instance=person)
|
||||
pf.model = person
|
||||
nf = NameForm(instance=name)
|
||||
nf.model = name
|
||||
else: # view person detail
|
||||
# BEGIN NON-AUTHENTICATED ACCESS
|
||||
person = Person.objects.get(handle=handle)
|
||||
if person:
|
||||
if person.private:
|
||||
raise Http404(_("Requested %s is not accessible.") % view)
|
||||
name = person.name_set.get(preferred=True)
|
||||
if person.probably_alive:
|
||||
name.sanitize()
|
||||
else:
|
||||
raise Http404(_("Requested %s does not exist.") % view)
|
||||
pf = PersonForm(instance=person)
|
||||
pf.model = person
|
||||
nf = NameForm(instance=name)
|
||||
nf.model = name
|
||||
# END NON-AUTHENTICATED ACCESS
|
||||
if action == "save":
|
||||
context["action"] = "view"
|
||||
return redirect("/person/%s" % person.handle, context)
|
||||
context["action"] = action
|
||||
context["view"] = view
|
||||
context["tview"] = _("Person")
|
||||
context["personform"] = pf
|
||||
context["nameform"] = nf
|
||||
context["person"] = person
|
||||
context["next"] = "/person/%s" % person.handle
|
||||
view_template = 'view_person_detail.html'
|
||||
return render_to_response(view_template, context)
|
||||
|
||||
def view(request, view):
|
||||
search = ""
|
||||
if view == "event":
|
||||
if request.user.is_authenticated():
|
||||
private = Q()
|
||||
else:
|
||||
# NON-AUTHENTICATED users
|
||||
private = Q(private=False)
|
||||
if request.GET.has_key("search"):
|
||||
search = request.GET.get("search")
|
||||
object_list = Event.objects \
|
||||
.filter((Q(gramps_id__icontains=search) |
|
||||
Q(event_type__name__icontains=search) |
|
||||
Q(place__title__icontains=search)) &
|
||||
private
|
||||
) \
|
||||
.order_by("gramps_id")
|
||||
else:
|
||||
object_list = Event.objects.filter(private).order_by("gramps_id")
|
||||
view_template = 'view_events.html'
|
||||
total = Event.objects.all().count()
|
||||
elif view == "family":
|
||||
if request.user.is_authenticated():
|
||||
if request.GET.has_key("search"):
|
||||
search = request.GET.get("search")
|
||||
if "," in search:
|
||||
surname, first = [term.strip() for term in
|
||||
search.split(",", 1)]
|
||||
object_list = Family.objects \
|
||||
.filter((Q(father__name__surname__surname__istartswith=surname) &
|
||||
Q(father__name__first_name__istartswith=first)) |
|
||||
(Q(mother__name__surname__surname__istartswith=surname) &
|
||||
Q(mother__name__first_name__istartswith=first))
|
||||
) \
|
||||
.order_by("gramps_id")
|
||||
else: # no comma
|
||||
object_list = Family.objects \
|
||||
.filter(Q(gramps_id__icontains=search) |
|
||||
Q(family_rel_type__name__icontains=search) |
|
||||
Q(father__name__surname__surname__istartswith=search) |
|
||||
Q(father__name__first_name__istartswith=search) |
|
||||
Q(mother__name__surname__surname__istartswith=search) |
|
||||
Q(mother__name__first_name__istartswith=search)
|
||||
) \
|
||||
.order_by("gramps_id")
|
||||
else: # no search
|
||||
object_list = Family.objects.all().order_by("gramps_id")
|
||||
else:
|
||||
# NON-AUTHENTICATED users
|
||||
if request.GET.has_key("search"):
|
||||
search = request.GET.get("search")
|
||||
if "," in search:
|
||||
search_text, trash = [term.strip() for term in search.split(",", 1)]
|
||||
else:
|
||||
search_text = search
|
||||
object_list = Family.objects \
|
||||
.filter((Q(gramps_id__icontains=search_text) |
|
||||
Q(family_rel_type__name__icontains=search_text) |
|
||||
Q(father__name__surname__surname__istartswith=search_text) |
|
||||
Q(mother__name__surname__surname__istartswith=search_text)) &
|
||||
Q(private=False) &
|
||||
Q(mother__private=False) &
|
||||
Q(father__private=False)
|
||||
) \
|
||||
.order_by("gramps_id")
|
||||
else:
|
||||
object_list = Family.objects \
|
||||
.filter(Q(private=False) &
|
||||
Q(mother__private=False) &
|
||||
Q(father__private=False)
|
||||
) \
|
||||
.order_by("gramps_id")
|
||||
view_template = 'view_families.html'
|
||||
total = Family.objects.all().count()
|
||||
elif view == "media":
|
||||
if request.user.is_authenticated():
|
||||
private = Q()
|
||||
else:
|
||||
# NON-AUTHENTICATED users
|
||||
private = Q(private=False)
|
||||
if request.GET.has_key("search"):
|
||||
search = request.GET.get("search")
|
||||
object_list = Media.objects \
|
||||
.filter(Q(gramps_id__icontains=search) &
|
||||
private
|
||||
) \
|
||||
.order_by("gramps_id")
|
||||
else:
|
||||
object_list = Media.objects.filter(private).order_by("gramps_id")
|
||||
view_template = 'view_media.html'
|
||||
total = Media.objects.all().count()
|
||||
elif view == "note":
|
||||
if request.user.is_authenticated():
|
||||
private = Q()
|
||||
else:
|
||||
# NON-AUTHENTICATED users
|
||||
private = Q(private=False)
|
||||
if request.GET.has_key("search"):
|
||||
search = request.GET.get("search")
|
||||
object_list = Note.objects \
|
||||
.filter((Q(gramps_id__icontains=search) |
|
||||
Q(note_type__name__icontains=search) |
|
||||
Q(text__icontains=search)) &
|
||||
private
|
||||
) \
|
||||
.order_by("gramps_id")
|
||||
else:
|
||||
object_list = Note.objects.filter(private).order_by("gramps_id")
|
||||
view_template = 'view_notes.html'
|
||||
total = Note.objects.all().count()
|
||||
elif view == "person":
|
||||
if request.user.is_authenticated():
|
||||
if request.GET.has_key("search"):
|
||||
search = request.GET.get("search")
|
||||
if "," in search:
|
||||
surname, first_name = [term.strip() for term in
|
||||
search.split(",", 1)]
|
||||
object_list = Name.objects \
|
||||
.filter(Q(surname__surname__istartswith=surname,
|
||||
first_name__istartswith=first_name)) \
|
||||
.order_by("surname__surname", "first_name")
|
||||
else:
|
||||
object_list = Name.objects \
|
||||
.filter((Q(surname__surname__icontains=search) |
|
||||
Q(first_name__icontains=search) |
|
||||
Q(suffix__icontains=search) |
|
||||
Q(surname__prefix__icontains=search) |
|
||||
Q(title__icontains=search) |
|
||||
Q(person__gramps_id__icontains=search))
|
||||
) \
|
||||
.order_by("surname__surname", "first_name")
|
||||
else:
|
||||
object_list = Name.objects.all().order_by("surname__surname", "first_name")
|
||||
else:
|
||||
# BEGIN NON-AUTHENTICATED users
|
||||
if request.GET.has_key("search"):
|
||||
search = request.GET.get("search")
|
||||
if "," in search:
|
||||
search_text, trash = [term.strip() for term in search.split(",", 1)]
|
||||
else:
|
||||
search_text = search
|
||||
object_list = Name.objects \
|
||||
.select_related() \
|
||||
.filter(Q(surname__surname__istartswith=search_text) &
|
||||
Q(private=False) &
|
||||
Q(person__private=False)
|
||||
) \
|
||||
.order_by("surname__surname", "first_name")
|
||||
else:
|
||||
object_list = Name.objects \
|
||||
.select_related() \
|
||||
.filter(Q(private=False) &
|
||||
Q(person__private=False)) \
|
||||
.order_by("surname__surname", "first_name")
|
||||
# END NON-AUTHENTICATED users
|
||||
view_template = 'view_people.html'
|
||||
total = Name.objects.all().count()
|
||||
elif view == "place":
|
||||
if request.user.is_authenticated():
|
||||
private = Q()
|
||||
else:
|
||||
# NON-AUTHENTICATED users
|
||||
private = Q(private=False)
|
||||
if request.GET.has_key("search"):
|
||||
search = request.GET.get("search")
|
||||
object_list = Place.objects \
|
||||
.filter((Q(gramps_id__icontains=search) |
|
||||
Q(title__icontains=search)
|
||||
) &
|
||||
private
|
||||
) \
|
||||
.order_by("gramps_id")
|
||||
else:
|
||||
object_list = Place.objects.filter(private).order_by("gramps_id")
|
||||
view_template = 'view_places.html'
|
||||
total = Place.objects.all().count()
|
||||
elif view == "repository":
|
||||
if request.user.is_authenticated():
|
||||
private = Q()
|
||||
else:
|
||||
# NON-AUTHENTICATED users
|
||||
private = Q(private=False)
|
||||
if request.GET.has_key("search"):
|
||||
search = request.GET.get("search")
|
||||
object_list = Repository.objects \
|
||||
.filter((Q(gramps_id__icontains=search) |
|
||||
Q(name__icontains=search) |
|
||||
Q(repository_type__name__icontains=search)
|
||||
) &
|
||||
private
|
||||
) \
|
||||
.order_by("gramps_id")
|
||||
else:
|
||||
object_list = Repository.objects.filter(private).order_by("gramps_id")
|
||||
view_template = 'view_repositories.html'
|
||||
total = Repository.objects.all().count()
|
||||
elif view == "source":
|
||||
if request.user.is_authenticated():
|
||||
private = Q()
|
||||
else:
|
||||
# NON-AUTHENTICATED users
|
||||
private = Q(private=False)
|
||||
if request.GET.has_key("search"):
|
||||
search = request.GET.get("search")
|
||||
object_list = Source.objects \
|
||||
.filter(Q(gramps_id__icontains=search) &
|
||||
private
|
||||
) \
|
||||
.order_by("gramps_id")
|
||||
else:
|
||||
object_list = Source.objects.filter(private).order_by("gramps_id")
|
||||
view_template = 'view_sources.html'
|
||||
total = Source.objects.all().count()
|
||||
elif view == "tag":
|
||||
if request.GET.has_key("search"):
|
||||
search = request.GET.get("search")
|
||||
object_list = Tag.objects \
|
||||
.filter(Q(name__icontains=search)) \
|
||||
.order_by("name")
|
||||
else:
|
||||
object_list = Tag.objects.order_by("name")
|
||||
view_template = 'view_tags.html'
|
||||
total = Tag.objects.all().count()
|
||||
elif view == "report":
|
||||
if request.GET.has_key("search"):
|
||||
search = request.GET.get("search")
|
||||
object_list = Report.objects \
|
||||
.filter(Q(name__icontains=search)) \
|
||||
.order_by("name")
|
||||
else:
|
||||
object_list = Report.objects.all().order_by("name")
|
||||
view_template = 'view_report.html'
|
||||
total = Report.objects.all().count()
|
||||
else:
|
||||
raise Http404("Requested page type '%s' not known" % view)
|
||||
|
||||
if request.user.is_authenticated():
|
||||
paginator = Paginator(object_list, 20)
|
||||
else:
|
||||
paginator = Paginator(object_list, 20)
|
||||
|
||||
try:
|
||||
page = int(request.GET.get('page', '1'))
|
||||
except ValueError:
|
||||
page = 1
|
||||
|
||||
try:
|
||||
page = paginator.page(page)
|
||||
except (EmptyPage, InvalidPage):
|
||||
page = paginator.page(paginator.num_pages)
|
||||
|
||||
context = RequestContext(request)
|
||||
context["page"] = page
|
||||
context["view"] = view
|
||||
context["tview"] = _(view.title())
|
||||
context["search"] = search
|
||||
context["total"] = total
|
||||
context["object_list"] = object_list
|
||||
context["next"] = "/%s/" % view
|
||||
if search:
|
||||
context["search_query"] = ("&search=%s" % search)
|
||||
else:
|
||||
context["search_query"] = ""
|
||||
return render_to_response(view_template, context)
|
||||
170
src/webapp/init.py
Normal file
170
src/webapp/init.py
Normal file
@@ -0,0 +1,170 @@
|
||||
# Gramps - a GTK+/GNOME based genealogy program
|
||||
#
|
||||
# Copyright (C) 2009 Douglas S. Blank <doug.blank@gmail.com>
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 2 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
#
|
||||
# $Id$
|
||||
#
|
||||
|
||||
"""
|
||||
Creates a JSON representation of data for Django's fixture
|
||||
architecture. We could have done this in Python, or SQL,
|
||||
but this makes it useful for all Django-based backends
|
||||
but still puts it into their syncdb API.
|
||||
"""
|
||||
|
||||
import time
|
||||
import os
|
||||
os.environ["DJANGO_SETTINGS_MODULE"] = "settings"
|
||||
import settings
|
||||
|
||||
from gen.lib.nametype import NameType
|
||||
from gen.lib.nameorigintype import NameOriginType
|
||||
from gen.lib.attrtype import AttributeType
|
||||
from gen.lib.urltype import UrlType
|
||||
from gen.lib.childreftype import ChildRefType
|
||||
from gen.lib.repotype import RepositoryType
|
||||
from gen.lib.eventtype import EventType
|
||||
from gen.lib.familyreltype import FamilyRelType
|
||||
from gen.lib.srcmediatype import SourceMediaType
|
||||
from gen.lib.eventroletype import EventRoleType
|
||||
from gen.lib.notetype import NoteType
|
||||
|
||||
from grampsdb.models import (GenderType, LdsType, LdsStatus,
|
||||
NameFormatType, NameOriginType, ThemeType)
|
||||
|
||||
def get_datamap(x):
|
||||
"""
|
||||
Returns (code, Name) for a Gramps type tuple.
|
||||
"""
|
||||
return (x[0],x[2])
|
||||
|
||||
print "["
|
||||
for table, entries in [("grampsdb.config",
|
||||
[(("setting", "\"db_version\""),
|
||||
("description", "\"database scheme version\""),
|
||||
("value_type", "\"str\""),
|
||||
("value", "\"0.5.1\"")),
|
||||
(("setting", "\"db_created\""),
|
||||
("description", "\"database creation date/time\""),
|
||||
("value_type", "\"str\""),
|
||||
("value", ('"%s"' % time.strftime("%Y-%m-%d %H:%M")))),
|
||||
]),
|
||||
("grampsdb.report",
|
||||
[(("name", '"Ahnentafel Report"'),
|
||||
("handle", '"ancestor_report"'),
|
||||
("report_type", '"textreport"')),
|
||||
(("name", '"birthday_report"'),
|
||||
("handle", '"birthday_report"'),
|
||||
("report_type", '"textreport"')),
|
||||
(("name", '"custom_text"'),
|
||||
("handle", '"custom_text"'),
|
||||
("report_type", '"textreport"')),
|
||||
(("name", '"descend_report"'),
|
||||
("handle", '"descend_report"'),
|
||||
("report_type", '"textreport"')),
|
||||
(("name", '"det_ancestor_report"'),
|
||||
("handle", '"det_ancestor_report"'),
|
||||
("report_type", '"textreport"')),
|
||||
(("name", '"det_descendant_report"'),
|
||||
("handle", '"det_descendant_report"'),
|
||||
("report_type", '"textreport"')),
|
||||
(("name", '"endofline_report"'),
|
||||
("handle", '"endofline_report"'),
|
||||
("report_type", '"textreport"')),
|
||||
(("name", '"family_group"'),
|
||||
("handle", '"family_group"'),
|
||||
("report_type", '"textreport"')),
|
||||
(("name", '"indiv_complete"'),
|
||||
("handle", '"indiv_complete"'),
|
||||
("report_type", '"textreport"')),
|
||||
(("name", '"kinship_report"'),
|
||||
("handle", '"kinship_report"'),
|
||||
("report_type", '"textreport"')),
|
||||
(("name", '"tag_report"'),
|
||||
("handle", '"tag_report"'),
|
||||
("report_type", '"textreport"')),
|
||||
(("name", '"number_of_ancestors_report"'),
|
||||
("handle", '"number_of_ancestors_report"'),
|
||||
("report_type", '"textreport"')),
|
||||
(("name", '"place_report"'),
|
||||
("handle", '"place_report"'),
|
||||
("report_type", '"textreport"')),
|
||||
(("name", '"simple_book_title"'),
|
||||
("handle", '"simple_book_title"'),
|
||||
("report_type", '"textreport"')),
|
||||
(("name", '"summary"'),
|
||||
("handle", '"summary"'),
|
||||
("report_type", '"textreport"')),
|
||||
(("name", '"GEDCOM Export"'),
|
||||
("handle", '"gedcom_export"'),
|
||||
("options", '"off=ged"'),
|
||||
("report_type", '"export"')),
|
||||
(("name", '"Gramps XML Export"'),
|
||||
("handle", '"ex_gpkg"'),
|
||||
("options", '"off=gramps"'),
|
||||
("report_type", '"export"')),
|
||||
])]:
|
||||
entry_count = 0
|
||||
for entry in entries:
|
||||
print " {"
|
||||
print " \"model\": \"%s\"," % table
|
||||
print " \"pk\": %d," % (entry_count + 1)
|
||||
print " \"fields\":"
|
||||
print " {"
|
||||
key_count = 0
|
||||
for items in entry:
|
||||
key, value = items
|
||||
print (" \"%s\" : %s" % (key, value)),
|
||||
key_count += 1
|
||||
if key_count < len(entry):
|
||||
print ","
|
||||
else:
|
||||
print
|
||||
print " }"
|
||||
print " },"
|
||||
entry_count += 1
|
||||
|
||||
## Add the data for the type models:
|
||||
|
||||
type_models = [NameType, NameOriginType, AttributeType, UrlType, ChildRefType,
|
||||
RepositoryType, EventType, FamilyRelType, SourceMediaType,
|
||||
EventRoleType, NoteType, GenderType, LdsType, LdsStatus,
|
||||
NameFormatType]
|
||||
for type in type_models:
|
||||
count = 1
|
||||
# Add each code:
|
||||
for tuple in type._DATAMAP:
|
||||
if len(tuple) == 3: # GRAMPS BSDDB style
|
||||
val, name = get_datamap(tuple)
|
||||
else: # NEW SQL based
|
||||
val, name = tuple
|
||||
print " {"
|
||||
print " \"model\": \"grampsdb.%s\"," % type.__name__.lower()
|
||||
print " \"pk\": %d," % count
|
||||
print " \"fields\":"
|
||||
print " {"
|
||||
print " \"val\" : %d," % val
|
||||
print " \"name\": \"%s\"" % name
|
||||
print " }"
|
||||
print " }",
|
||||
# if it is the last one of the last one, no comma
|
||||
if type == type_models[-1] and count == len(type._DATAMAP):
|
||||
print
|
||||
else:
|
||||
print ","
|
||||
count += 1
|
||||
print "]"
|
||||
32
src/webapp/init_gramps.py
Normal file
32
src/webapp/init_gramps.py
Normal file
@@ -0,0 +1,32 @@
|
||||
# Gramps - a GTK+/GNOME based genealogy program
|
||||
#
|
||||
# Copyright (C) 2009 Douglas S. Blank <doug.blank@gmail.com>
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 2 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
#
|
||||
# $Id$
|
||||
#
|
||||
|
||||
"""
|
||||
Clears gramps data
|
||||
"""
|
||||
|
||||
import os
|
||||
os.environ["DJANGO_SETTINGS_MODULE"] = "settings"
|
||||
import settings
|
||||
|
||||
import grampsdb.models as dj
|
||||
|
||||
dj.clear_tables("primary", "secondary", "ref", "system")
|
||||
1484
src/webapp/libdjango.py
Normal file
1484
src/webapp/libdjango.py
Normal file
File diff suppressed because it is too large
Load Diff
40
src/webapp/manage.py
Executable file
40
src/webapp/manage.py
Executable file
@@ -0,0 +1,40 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
# Gramps - a GTK+/GNOME based genealogy program
|
||||
#
|
||||
# Copyright (C) 2009 Douglas S. Blank <doug.blank@gmail.com>
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 2 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
#
|
||||
# $Id$
|
||||
#
|
||||
|
||||
""" Manage Django """
|
||||
|
||||
#------------------------------------------------------------------------
|
||||
#
|
||||
# Django Modules
|
||||
#
|
||||
#------------------------------------------------------------------------
|
||||
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)
|
||||
74
src/webapp/reports.py
Normal file
74
src/webapp/reports.py
Normal file
@@ -0,0 +1,74 @@
|
||||
# imports for import/export:
|
||||
|
||||
import DbState
|
||||
from cli.grampscli import CLIManager
|
||||
from gen.plug import BasePluginManager
|
||||
import os
|
||||
|
||||
# Example for running a report:
|
||||
# ------------------------------
|
||||
# from cli.plug import run_report
|
||||
# from django.conf import settings
|
||||
# import web.settings as default_settings
|
||||
# try:
|
||||
# settings.configure(default_settings)
|
||||
# except:
|
||||
# pass
|
||||
# import dbdjango
|
||||
# db = dbdjango.DbDjango()
|
||||
# run_report(db, "ancestor_report", off="txt", of="ar.txt", pid="I0363")
|
||||
|
||||
def import_file(db, filename, callback):
|
||||
"""
|
||||
Import a file (such as a GEDCOM file) into the given db.
|
||||
|
||||
>>> import_file(DbDjango(), "/home/user/Untitled_1.ged", lambda a: a)
|
||||
"""
|
||||
dbstate = DbState.DbState()
|
||||
climanager = CLIManager(dbstate, False) # do not load db_loader
|
||||
climanager.do_reg_plugins(dbstate, None)
|
||||
pmgr = BasePluginManager.get_instance()
|
||||
(name, ext) = os.path.splitext(os.path.basename(filename))
|
||||
format = ext[1:].lower()
|
||||
import_list = pmgr.get_reg_importers()
|
||||
for pdata in import_list:
|
||||
if format == pdata.extension:
|
||||
mod = pmgr.load_plugin(pdata)
|
||||
if not mod:
|
||||
for name, error_tuple in pmgr.get_fail_list():
|
||||
etype, exception, traceback = error_tuple
|
||||
print "ERROR:", name, exception
|
||||
return False
|
||||
import_function = getattr(mod, pdata.import_function)
|
||||
db.prepare_import()
|
||||
import_function(db, filename, callback)
|
||||
db.commit_import()
|
||||
return True
|
||||
return False
|
||||
|
||||
def export_file(db, filename, callback):
|
||||
"""
|
||||
Export the db to a file (such as a GEDCOM file).
|
||||
|
||||
>>> export_file(DbDjango(), "/home/user/Untitled_1.ged", lambda a: a)
|
||||
"""
|
||||
dbstate = DbState.DbState()
|
||||
climanager = CLIManager(dbstate, False) # do not load db_loader
|
||||
climanager.do_reg_plugins(dbstate, None)
|
||||
pmgr = BasePluginManager.get_instance()
|
||||
(name, ext) = os.path.splitext(os.path.basename(filename))
|
||||
format = ext[1:].lower()
|
||||
export_list = pmgr.get_reg_exporters()
|
||||
for pdata in export_list:
|
||||
if format == pdata.extension:
|
||||
mod = pmgr.load_plugin(pdata)
|
||||
if not mod:
|
||||
for name, error_tuple in pmgr.get_fail_list():
|
||||
etype, exception, traceback = error_tuple
|
||||
print "ERROR:", name, exception
|
||||
return False
|
||||
export_function = getattr(mod, pdata.export_function)
|
||||
export_function(db, filename, callback)
|
||||
return True
|
||||
return False
|
||||
|
||||
142
src/webapp/settings.py
Normal file
142
src/webapp/settings.py
Normal file
@@ -0,0 +1,142 @@
|
||||
# Gramps - a GTK+/GNOME based genealogy program
|
||||
#
|
||||
# Copyright (C) 2009 Douglas S. Blank <doug.blank@gmail.com>
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 2 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
#
|
||||
# $Id$
|
||||
#
|
||||
|
||||
""" Django settings for gramps project. """
|
||||
|
||||
# Need to be able to import Gramps files from here.
|
||||
|
||||
import const
|
||||
import os
|
||||
|
||||
DEBUG = True
|
||||
TEMPLATE_DEBUG = DEBUG
|
||||
|
||||
INTERNAL_IPS = ('127.0.0.1',)
|
||||
|
||||
ADMINS = (
|
||||
('admin', 'your_email@domain.com'),
|
||||
)
|
||||
|
||||
MANAGERS = ADMINS
|
||||
DATABASE_ROUTERS = []
|
||||
DATABASES = {
|
||||
'default': {
|
||||
'ENGINE': 'django.db.backends.sqlite3',
|
||||
'NAME': os.path.join(const.WEB_DIR, 'sqlite.db'),
|
||||
}
|
||||
}
|
||||
DATABASE_ENGINE = 'sqlite3'
|
||||
DATABASE_NAME = os.path.join(const.WEB_DIR, 'sqlite.db')
|
||||
DATABASE_USER = ''
|
||||
DATABASE_PASSWORD = ''
|
||||
DATABASE_HOST = ''
|
||||
DATABASE_PORT = ''
|
||||
TIME_ZONE = 'America/New_York'
|
||||
LANGUAGE_CODE = 'en-us'
|
||||
SITE_ID = 1
|
||||
USE_I18N = True
|
||||
MEDIA_ROOT = ''
|
||||
MEDIA_URL = ''
|
||||
ADMIN_MEDIA_PREFIX = '/gramps-media/'
|
||||
SECRET_KEY = 'zd@%vslj5sqhx94_8)0hsx*rk9tj3^ly$x+^*tq4bggr&uh$ac'
|
||||
|
||||
TEMPLATE_LOADERS = (
|
||||
'django.template.loaders.filesystem.load_template_source',
|
||||
'django.template.loaders.app_directories.load_template_source',
|
||||
)
|
||||
|
||||
MIDDLEWARE_CLASSES = (
|
||||
'django.middleware.csrf.CsrfViewMiddleware',
|
||||
'django.middleware.common.CommonMiddleware',
|
||||
'django.contrib.sessions.middleware.SessionMiddleware',
|
||||
'django.contrib.auth.middleware.AuthenticationMiddleware',
|
||||
# 'debug_toolbar.middleware.DebugToolbarMiddleware',
|
||||
)
|
||||
|
||||
ROOT_URLCONF = 'web.urls'
|
||||
|
||||
TEMPLATE_DIRS = (
|
||||
# Use absolute paths, not relative paths.
|
||||
os.path.join(const.DATA_DIR, "templates"),
|
||||
)
|
||||
|
||||
TEMPLATE_CONTEXT_PROCESSORS = (
|
||||
"django.core.context_processors.auth",
|
||||
# "django.core.context_processors.debug",
|
||||
"django.core.context_processors.i18n",
|
||||
"django.core.context_processors.media",
|
||||
"web.grampsdb.views.context_processor",
|
||||
)
|
||||
|
||||
INSTALLED_APPS = (
|
||||
'django.contrib.auth',
|
||||
'django.contrib.contenttypes',
|
||||
'django.contrib.sessions',
|
||||
'django.contrib.sites',
|
||||
'django.contrib.admin',
|
||||
'web.grampsdb',
|
||||
# 'django_extensions',
|
||||
# 'debug_toolbar',
|
||||
)
|
||||
|
||||
DEBUG_TOOLBAR_PANELS = (
|
||||
'debug_toolbar.panels.version.VersionDebugPanel',
|
||||
'debug_toolbar.panels.timer.TimerDebugPanel',
|
||||
'debug_toolbar.panels.settings_vars.SettingsVarsDebugPanel',
|
||||
'debug_toolbar.panels.headers.HeaderDebugPanel',
|
||||
'debug_toolbar.panels.request_vars.RequestVarsDebugPanel',
|
||||
'debug_toolbar.panels.template.TemplateDebugPanel',
|
||||
'debug_toolbar.panels.sql.SQLDebugPanel',
|
||||
'debug_toolbar.panels.signals.SignalDebugPanel',
|
||||
'debug_toolbar.panels.logger.LoggingPanel',
|
||||
)
|
||||
|
||||
def custom_show_toolbar(request):
|
||||
return True # Always show toolbar, for example purposes only.
|
||||
|
||||
DEBUG_TOOLBAR_CONFIG = {
|
||||
'INTERCEPT_REDIRECTS': False,
|
||||
# 'SHOW_TOOLBAR_CALLBACK': custom_show_toolbar,
|
||||
# 'EXTRA_SIGNALS': ['myproject.signals.MySignal'],
|
||||
'HIDE_DJANGO_SQL': False,
|
||||
}
|
||||
|
||||
AUTH_PROFILE_MODULE = "grampsdb.Profile"
|
||||
|
||||
# Had to add these to use settings.configure():
|
||||
DATABASE_OPTIONS = ''
|
||||
URL_VALIDATOR_USER_AGENT = ''
|
||||
DEFAULT_INDEX_TABLESPACE = ''
|
||||
DEFAULT_TABLESPACE = ''
|
||||
CACHE_BACKEND = 'locmem://'
|
||||
TRANSACTIONS_MANAGED = False
|
||||
LOCALE_PATHS = tuple()
|
||||
|
||||
# In versions < 2.7 python does not properly copy methods when doing a
|
||||
# deepcopy. This workaround makes the copy work properly. When Gramps no longer
|
||||
# supports python 2.6, this workaround can be removed.
|
||||
import sys
|
||||
if sys.version_info < (2, 7) :
|
||||
import copy
|
||||
import types
|
||||
def _deepcopy_method(x, memo):
|
||||
return type(x)(x.im_func, copy.deepcopy(x.im_self, memo), x.im_class)
|
||||
copy._deepcopy_dispatch[types.MethodType] = _deepcopy_method
|
||||
229
src/webapp/sortheaders.py
Normal file
229
src/webapp/sortheaders.py
Normal file
@@ -0,0 +1,229 @@
|
||||
# Author: insin
|
||||
# Site: http://www.djangosnippets.org/snippets/308/
|
||||
|
||||
from django.core.paginator import InvalidPage, EmptyPage
|
||||
from collections import defaultdict
|
||||
|
||||
from unicodedata import normalize
|
||||
import locale
|
||||
|
||||
ORDER_VAR = 'o'
|
||||
ORDER_TYPE_VAR = 'ot'
|
||||
|
||||
def first_letter(text):
|
||||
"""
|
||||
Text should be a unicode string. Returns first letter.
|
||||
"""
|
||||
if len(text) > 0:
|
||||
letter = normalize('NFKC', text)[0].upper()
|
||||
(lang_country, modifier ) = locale.getlocale()
|
||||
if lang_country == "sv_SE" and letter in [u'W', u'V']:
|
||||
letter = u'V,W'
|
||||
return letter
|
||||
else:
|
||||
return u'?'
|
||||
|
||||
class SortHeaders:
|
||||
"""
|
||||
Handles generation of an argument for the Django ORM's
|
||||
``order_by`` method and generation of table headers which reflect
|
||||
the currently selected sort, based on defined table headers with
|
||||
matching sort criteria.
|
||||
|
||||
Based in part on the Django Admin application's ``ChangeList``
|
||||
functionality.
|
||||
"""
|
||||
def __init__(self, request, headers, default_order_field=None,
|
||||
default_order_type='asc', additional_params=None):
|
||||
"""
|
||||
request
|
||||
The request currently being processed - the current sort
|
||||
order field and type are determined based on GET
|
||||
parameters.
|
||||
|
||||
headers
|
||||
A list of two-tuples of header text and matching ordering
|
||||
criteria for use with the Django ORM's ``order_by``
|
||||
method. A criterion of ``None`` indicates that a header
|
||||
is not sortable.
|
||||
|
||||
default_order_field
|
||||
The index of the header definition to be used for default
|
||||
ordering and when an invalid or non-sortable header is
|
||||
specified in GET parameters. If not specified, the index
|
||||
of the first sortable header will be used.
|
||||
|
||||
default_order_type
|
||||
The default type of ordering used - must be one of
|
||||
``'asc`` or ``'desc'``.
|
||||
|
||||
additional_params:
|
||||
Query parameters which should always appear in sort links,
|
||||
specified as a dictionary mapping parameter names to
|
||||
values. For example, this might contain the current page
|
||||
number if you're sorting a paginated list of items.
|
||||
"""
|
||||
if default_order_field is None:
|
||||
for i, (header, query_lookup) in enumerate(headers):
|
||||
if query_lookup is not None:
|
||||
default_order_field = i
|
||||
break
|
||||
if default_order_field is None:
|
||||
raise AttributeError('No default_order_field was specified and none of the header definitions given were sortable.')
|
||||
if default_order_type not in ('asc', 'desc'):
|
||||
raise AttributeError('If given, default_order_type must be one of \'asc\' or \'desc\'.')
|
||||
if additional_params is None: additional_params = {}
|
||||
|
||||
self.header_defs = headers
|
||||
self.additional_params = additional_params
|
||||
self.order_field, self.order_type = default_order_field, default_order_type
|
||||
|
||||
# Determine order field and order type for the current request
|
||||
params = dict(request.GET.items())
|
||||
if ORDER_VAR in params:
|
||||
try:
|
||||
new_order_field = int(params[ORDER_VAR])
|
||||
if headers[new_order_field][1] is not None:
|
||||
self.order_field = new_order_field
|
||||
except (IndexError, ValueError):
|
||||
pass # Use the default
|
||||
if ORDER_TYPE_VAR in params and params[ORDER_TYPE_VAR] in ('asc', 'desc'):
|
||||
self.order_type = params[ORDER_TYPE_VAR]
|
||||
|
||||
def headers(self):
|
||||
"""
|
||||
Generates dicts containing header and sort link details for
|
||||
all defined headers.
|
||||
"""
|
||||
for i, (header, order_criterion) in enumerate(self.header_defs):
|
||||
th_classes = []
|
||||
new_order_type = 'asc'
|
||||
if i == self.order_field:
|
||||
th_classes.append('sorted %sending' % self.order_type)
|
||||
new_order_type = {'asc': 'desc', 'desc': 'asc'}[self.order_type]
|
||||
yield {
|
||||
'text': header,
|
||||
'sortable': order_criterion is not None,
|
||||
'url': self.get_query_string({ORDER_VAR: i, ORDER_TYPE_VAR: new_order_type}),
|
||||
'class_attr': (th_classes and ' class="%s"' % ' '.join(th_classes) or ''),
|
||||
}
|
||||
|
||||
def get_query_string(self, params):
|
||||
"""
|
||||
Creates a query string from the given dictionary of
|
||||
parameters, including any additonal parameters which should
|
||||
always be present.
|
||||
"""
|
||||
params.update(self.additional_params)
|
||||
return '?%s' % '&'.join(['%s=%s' % (param, value)
|
||||
for param, value in params.items()])
|
||||
|
||||
def get_order_by(self):
|
||||
"""
|
||||
Creates an ordering criterion based on the current order
|
||||
field and order type, for use with the Django ORM's
|
||||
``order_by`` method.
|
||||
"""
|
||||
return '%s%s' % (
|
||||
self.order_type == 'desc' and '-' or '',
|
||||
self.header_defs[self.order_field][1],
|
||||
)
|
||||
|
||||
class NamePaginator(object):
|
||||
"""Pagination for string-based objects"""
|
||||
|
||||
def __init__(self, object_list, on=None, per_page=25):
|
||||
self.object_list = object_list
|
||||
self.count = len(object_list)
|
||||
self.pages = []
|
||||
|
||||
# chunk up the objects so we don't need to iterate over the whole list for each letter
|
||||
chunks = defaultdict(list)
|
||||
|
||||
for obj in self.object_list:
|
||||
if on:
|
||||
obj_str = unicode(getattr(obj, on))
|
||||
else:
|
||||
obj_str = unicode(obj)
|
||||
|
||||
letter = first_letter(obj_str[0])
|
||||
chunks[letter].append(obj)
|
||||
|
||||
# the process for assigning objects to each page
|
||||
current_page = NamePage(self)
|
||||
|
||||
for letter in string.ascii_uppercase:
|
||||
if letter not in chunks:
|
||||
current_page.add([], letter)
|
||||
continue
|
||||
|
||||
sub_list = chunks[letter] # the items in object_list starting with this letter
|
||||
|
||||
new_page_count = len(sub_list) + current_page.count
|
||||
# first, check to see if sub_list will fit or it needs to go onto a new page.
|
||||
# if assigning this list will cause the page to overflow...
|
||||
# and an underflow is closer to per_page than an overflow...
|
||||
# and the page isn't empty (which means len(sub_list) > per_page)...
|
||||
if (new_page_count > per_page and
|
||||
abs(per_page - current_page.count) < abs(per_page - new_page_count) and
|
||||
current_page.count > 0):
|
||||
# make a new page
|
||||
self.pages.append(current_page)
|
||||
current_page = NamePage(self)
|
||||
|
||||
current_page.add(sub_list, letter)
|
||||
|
||||
# if we finished the for loop with a page that isn't empty, add it
|
||||
if current_page.count > 0: self.pages.append(current_page)
|
||||
|
||||
def page(self, num):
|
||||
"""Returns a Page object for the given 1-based page number."""
|
||||
if len(self.pages) == 0:
|
||||
return None
|
||||
elif num > 0 and num <= len(self.pages):
|
||||
return self.pages[num-1]
|
||||
else:
|
||||
raise InvalidPage
|
||||
|
||||
@property
|
||||
def num_pages(self):
|
||||
"""Returns the total number of pages"""
|
||||
return len(self.pages)
|
||||
|
||||
class NamePage(object):
|
||||
def __init__(self, paginator):
|
||||
self.paginator = paginator
|
||||
self.object_list = []
|
||||
self.letters = []
|
||||
|
||||
@property
|
||||
def count(self):
|
||||
return len(self.object_list)
|
||||
|
||||
@property
|
||||
def start_letter(self):
|
||||
if len(self.letters) > 0:
|
||||
self.letters.sort(key=locale.strxfrm)
|
||||
return first_letter(self.letters)
|
||||
else: return None
|
||||
|
||||
@property
|
||||
def end_letter(self):
|
||||
if len(self.letters) > 0:
|
||||
self.letters.sort(key=locale.strxfrm)
|
||||
return self.letters[-1]
|
||||
else: return None
|
||||
|
||||
@property
|
||||
def number(self):
|
||||
return self.paginator.pages.index(self) + 1
|
||||
|
||||
def add(self, new_list, letter=None):
|
||||
if len(new_list) > 0: self.object_list = self.object_list + new_list
|
||||
if letter: self.letters.append(letter)
|
||||
|
||||
def __unicode__(self):
|
||||
if self.start_letter == self.end_letter:
|
||||
return self.start_letter
|
||||
else:
|
||||
return u'%c-%c' % (self.start_letter, self.end_letter)
|
||||
99
src/webapp/urls.py
Normal file
99
src/webapp/urls.py
Normal file
@@ -0,0 +1,99 @@
|
||||
# Gramps - a GTK+/GNOME based genealogy program
|
||||
#
|
||||
# Copyright (C) 2009 Douglas S. Blank <doug.blank@gmail.com>
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 2 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
#
|
||||
# $Id$
|
||||
#
|
||||
|
||||
""" Url handler """
|
||||
|
||||
#------------------------------------------------------------------------
|
||||
#
|
||||
# Python Modules
|
||||
#
|
||||
#------------------------------------------------------------------------
|
||||
import os
|
||||
|
||||
#------------------------------------------------------------------------
|
||||
#
|
||||
# Django and Gramps Modules
|
||||
#
|
||||
#------------------------------------------------------------------------
|
||||
import const
|
||||
from django.conf.urls.defaults import *
|
||||
from django.contrib import admin
|
||||
admin.autodiscover()
|
||||
|
||||
from web.grampsdb.views import (main_page, user_page, logout_page,
|
||||
process_action, view, view_detail,
|
||||
view_name_detail)
|
||||
|
||||
urlpatterns = patterns('',
|
||||
# Specific matches first:
|
||||
(r'^admin/(.*)', admin.site.root),
|
||||
)
|
||||
|
||||
urlpatterns += patterns('',
|
||||
# Static serves! DANGEROUS in production:
|
||||
(r'^styles/(?P<path>.*)$', 'django.views.static.serve',
|
||||
{'document_root':
|
||||
os.path.join(const.ROOT_DIR, "plugins", "webstuff"),
|
||||
'show_indexes': True},
|
||||
),
|
||||
(r'^images/(?P<path>.*)$', 'django.views.static.serve',
|
||||
{'document_root': const.IMAGE_DIR,
|
||||
'show_indexes': True},
|
||||
),
|
||||
)
|
||||
|
||||
# The rest will match views:
|
||||
urlpatterns += patterns('',
|
||||
(r'^$', main_page),
|
||||
(r'^user/(\w+)/$', user_page),
|
||||
(r'^login/$', 'django.contrib.auth.views.login'),
|
||||
(r'^logout/$', logout_page),
|
||||
(r'^(?P<view>(\w+))/$', view),
|
||||
url(r'^person/(?P<handle>(\w+))/$', view_detail,
|
||||
{"view": "person"}, name="view-person-detail"),
|
||||
url(r'^person/(?P<handle>(\w+))/(?P<action>(\w+))$', view_detail,
|
||||
{"view": "person"}, name="view-person-detail"),
|
||||
(r'^(?P<view>(\w+))/(?P<handle>(\w+))/$', view_detail),
|
||||
(r'^person/(?P<handle>(\w+))/name/(?P<order>(\w+))$', view_name_detail),
|
||||
(r'^person/(?P<handle>(\w+))/name/(?P<order>(\w+))/(?P<action>(\w+))$', view_name_detail),
|
||||
(r'^(?P<view>(\w+))/(?P<handle>(\w+))/(?P<action>(\w+))$', process_action),
|
||||
(r'^favicon\.ico$', 'django.views.generic.simple.redirect_to', {'url': '/styles/images/favicon.ico'}),
|
||||
)
|
||||
|
||||
# In urls:
|
||||
# urlpatterns = patterns('',
|
||||
# url(r'^archive/(\d{4})/$', archive, name="full-archive"),
|
||||
# url(r'^archive-summary/(\d{4})/$', archive, {'summary': True}, "arch-summary"),
|
||||
# )
|
||||
|
||||
# In template:
|
||||
# {% url arch-summary 1945 %}
|
||||
# {% url full-archive 2007 %}
|
||||
#{% url path.to.view as the_url %}
|
||||
#{% if the_url %}
|
||||
# <a href="{{ the_url }}">Link to optional stuff</a>
|
||||
#{% endif %}
|
||||
|
||||
# In code:
|
||||
#from django.core.urlresolvers import reverse
|
||||
#
|
||||
#def myview(request):
|
||||
# return HttpResponseRedirect(reverse('arch-summary', args=[1945]))
|
||||
612
src/webapp/utils.py
Normal file
612
src/webapp/utils.py
Normal file
@@ -0,0 +1,612 @@
|
||||
# Gramps - a GTK+/GNOME based genealogy program
|
||||
#
|
||||
# Copyright (C) 2009 Douglas S. Blank <doug.blank@gmail.com>
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 2 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
#
|
||||
# $Id$
|
||||
#
|
||||
|
||||
""" Django/Gramps utilities """
|
||||
|
||||
#------------------------------------------------------------------------
|
||||
#
|
||||
# Python Modules
|
||||
#
|
||||
#------------------------------------------------------------------------
|
||||
import locale
|
||||
import sys
|
||||
|
||||
#------------------------------------------------------------------------
|
||||
#
|
||||
# Django Modules
|
||||
#
|
||||
#------------------------------------------------------------------------
|
||||
from django.template import escape
|
||||
from django.utils.safestring import mark_safe
|
||||
from django.contrib.contenttypes.models import ContentType
|
||||
|
||||
#------------------------------------------------------------------------
|
||||
#
|
||||
# Gramps-Connect Modules
|
||||
#
|
||||
#------------------------------------------------------------------------
|
||||
import web.grampsdb.models as models
|
||||
import web.grampsdb.forms as forms
|
||||
from web import libdjango
|
||||
from web.dbdjango import DbDjango
|
||||
|
||||
#------------------------------------------------------------------------
|
||||
#
|
||||
# Gramps Modules
|
||||
#
|
||||
#------------------------------------------------------------------------
|
||||
from Simple import SimpleTable, SimpleAccess, make_basic_stylesheet
|
||||
import Utils
|
||||
import DbState
|
||||
import DateHandler
|
||||
from gen.lib.date import Date as GDate, Today
|
||||
import gen.lib
|
||||
from gen.utils import get_birth_or_fallback, get_death_or_fallback
|
||||
from gen.plug import BasePluginManager
|
||||
from cli.grampscli import CLIManager
|
||||
|
||||
_ = lambda msg: msg
|
||||
|
||||
util_filters = [
|
||||
'nbsp',
|
||||
'render_date',
|
||||
'render_name',
|
||||
]
|
||||
|
||||
util_tags = [
|
||||
'render',
|
||||
"get_person_from_handle",
|
||||
"event_table",
|
||||
"name_table",
|
||||
"source_table",
|
||||
"note_table",
|
||||
"attribute_table",
|
||||
"address_table",
|
||||
"gallery_table",
|
||||
"internet_table",
|
||||
"association_table",
|
||||
"lds_table",
|
||||
"reference_table",
|
||||
"children_table",
|
||||
"make_button",
|
||||
]
|
||||
|
||||
#------------------------------------------------------------------------
|
||||
#
|
||||
# Module Constants
|
||||
#
|
||||
#------------------------------------------------------------------------
|
||||
dji = libdjango.DjangoInterface()
|
||||
_dd = DateHandler.displayer.display
|
||||
_dp = DateHandler.parser.parse
|
||||
|
||||
def register_plugins():
|
||||
dbstate = DbState.DbState()
|
||||
climanager = CLIManager(dbstate, False) # don't load db
|
||||
climanager.do_reg_plugins(dbstate, None)
|
||||
pmgr = BasePluginManager.get_instance()
|
||||
return pmgr
|
||||
|
||||
def get_person_from_handle(db, handle):
|
||||
# db is a Gramps Db interface
|
||||
# handle is a Person Handle
|
||||
try:
|
||||
return db.get_person_from_handle(handle)
|
||||
except:
|
||||
print >> sys.stderr, "error in get_person_from_handle:"
|
||||
import sys, traceback
|
||||
cla, exc, trbk = sys.exc_info()
|
||||
print >> sys.stderr, _("Error") + (" : %s %s" %(cla, exc))
|
||||
traceback.print_exc()
|
||||
return None
|
||||
|
||||
def probably_alive(handle):
|
||||
return False
|
||||
db = DbDjango()
|
||||
person = db.get_person_from_handle(handle)
|
||||
return Utils.probably_alive(person, db)
|
||||
|
||||
def format_number(number, with_grouping=True):
|
||||
# FIXME: should be user's setting
|
||||
locale.setlocale(locale.LC_ALL, "en_US.utf8")
|
||||
return locale.format("%d", number, with_grouping)
|
||||
|
||||
def nbsp(string):
|
||||
"""
|
||||
"""
|
||||
if string:
|
||||
return string
|
||||
else:
|
||||
return mark_safe(" ")
|
||||
|
||||
class Table(object):
|
||||
"""
|
||||
>>> table = Table()
|
||||
>>> table.columns("Col1", "Col2", "Col3")
|
||||
>>> table.row("1", "2", "3")
|
||||
>>> table.row("4", "5", "6")
|
||||
>>> table.get_html()
|
||||
"""
|
||||
def __init__(self):
|
||||
self.db = DbDjango()
|
||||
self.access = SimpleAccess(self.db)
|
||||
self.table = SimpleTable(self.access)
|
||||
class Doc(object):
|
||||
def __init__(self, doc):
|
||||
self.doc = doc
|
||||
# None is paperstyle, which is ignored:
|
||||
self.doc = Doc(HtmlDoc.HtmlDoc(make_basic_stylesheet(Table={"set_width":95}), None))
|
||||
self.doc.doc._backend = HtmlBackend()
|
||||
# You can set elements id, class, etc:
|
||||
self.doc.doc.htmllist += [Html('div', class_="content", id="Gallery", style="overflow: auto; height:150px; background-color: #261803;")]
|
||||
|
||||
def columns(self, *args):
|
||||
self.table.columns(*args)
|
||||
|
||||
def row(self, *args):
|
||||
self.table.row(*map(nbsp, args))
|
||||
|
||||
def link(self, object_type_name, handle):
|
||||
self.table.set_link_col((object_type_name, handle))
|
||||
|
||||
def links(self, links):
|
||||
"""
|
||||
A list of (object_type_name, handle) pairs, one per row.
|
||||
"""
|
||||
self.table.set_link_col(links)
|
||||
|
||||
def get_html(self):
|
||||
# The HTML writer escapes data:
|
||||
self.table.write(self.doc) # forces to htmllist
|
||||
# We have a couple of HTML bits that we want to unescape:
|
||||
return str(self.doc.doc.htmllist[0]).replace("&nbsp;", " ")
|
||||
|
||||
_ = lambda text: text
|
||||
|
||||
def make_button(text, url, *args):
|
||||
url = url % args
|
||||
return """[ <a href="%s">%s</a> ] """ % (url, text)
|
||||
|
||||
def event_table(obj, user, action, url=None, *args):
|
||||
retval = ""
|
||||
table = Table()
|
||||
table.columns(_("Description"),
|
||||
_("Type"),
|
||||
_("ID"),
|
||||
_("Date"),
|
||||
_("Place"),
|
||||
_("Role"))
|
||||
if user.is_authenticated():
|
||||
obj_type = ContentType.objects.get_for_model(obj)
|
||||
event_ref_list = models.EventRef.objects.filter(
|
||||
object_id=obj.id,
|
||||
object_type=obj_type).order_by("order")
|
||||
event_list = [(obj.ref_object, obj) for obj in event_ref_list]
|
||||
for (djevent, event_ref) in event_list:
|
||||
table.row(
|
||||
djevent.description,
|
||||
table.db.get_event_from_handle(djevent.handle),
|
||||
djevent.gramps_id,
|
||||
display_date(djevent),
|
||||
get_title(djevent.place),
|
||||
str(event_ref.role_type))
|
||||
retval += table.get_html()
|
||||
if user.is_authenticated() and url and action == "view":
|
||||
retval += make_button(_("Add event"), (url + "/add") % args)
|
||||
else:
|
||||
retval += nbsp("") # to keep tabs same height
|
||||
return retval
|
||||
|
||||
def name_table(obj, user, action, url=None, *args):
|
||||
retval = ""
|
||||
table = Table()
|
||||
table.columns(_("Name"),
|
||||
_("Type"),
|
||||
_("Group As"),
|
||||
_("Source"),
|
||||
_("Note Preview"))
|
||||
if user.is_authenticated():
|
||||
links = []
|
||||
for name in obj.name_set.all().order_by("order"):
|
||||
obj_type = ContentType.objects.get_for_model(name)
|
||||
sourceq = dji.SourceRef.filter(object_type=obj_type,
|
||||
object_id=name.id).count() > 0
|
||||
note_refs = dji.NoteRef.filter(object_type=obj_type,
|
||||
object_id=name.id)
|
||||
note = ""
|
||||
if note_refs.count() > 0:
|
||||
try:
|
||||
note = dji.Note.get(id=note_refs[0].object_id).text[:50]
|
||||
except:
|
||||
note = None
|
||||
table.row(make_name(name, user),
|
||||
str(name.name_type) + ["", " (preferred)"][int(name.preferred)],
|
||||
name.group_as,
|
||||
["No", "Yes"][sourceq],
|
||||
note)
|
||||
links.append(('URL',
|
||||
# url is "/person/%s/name"
|
||||
(url % name.person.handle) + ("/%s" % name.order)))
|
||||
table.links(links)
|
||||
retval += table.get_html()
|
||||
if user.is_authenticated() and url and action == "view":
|
||||
retval += make_button(_("Add name"), (url + "/add") % args)
|
||||
else:
|
||||
retval += nbsp("") # to keep tabs same height
|
||||
return retval
|
||||
|
||||
def source_table(obj, user, action, url=None, *args):
|
||||
retval = ""
|
||||
table = Table()
|
||||
table.columns(_("ID"),
|
||||
_("Title"),
|
||||
_("Author"),
|
||||
_("Page"))
|
||||
if user.is_authenticated():
|
||||
obj_type = ContentType.objects.get_for_model(obj)
|
||||
source_refs = dji.SourceRef.filter(object_type=obj_type,
|
||||
object_id=obj.id)
|
||||
for source_ref in source_refs:
|
||||
source = table.db.get_source_from_handle(source_ref.ref_object.handle)
|
||||
table.row(source,
|
||||
source_ref.ref_object.title,
|
||||
source_ref.ref_object.author,
|
||||
source_ref.page,
|
||||
)
|
||||
retval += table.get_html()
|
||||
if user.is_authenticated() and url and action == "view":
|
||||
retval += make_button(_("Add source"), (url + "/add") % args)
|
||||
else:
|
||||
retval += nbsp("") # to keep tabs same height
|
||||
return retval
|
||||
|
||||
def note_table(obj, user, action, url=None, *args):
|
||||
retval = ""
|
||||
table = Table()
|
||||
table.columns(
|
||||
_("ID"),
|
||||
_("Type"),
|
||||
_("Note"))
|
||||
if user.is_authenticated():
|
||||
obj_type = ContentType.objects.get_for_model(obj)
|
||||
note_refs = dji.NoteRef.filter(object_type=obj_type,
|
||||
object_id=obj.id)
|
||||
for note_ref in note_refs:
|
||||
note = table.db.get_note_from_handle(
|
||||
note_ref.ref_object.handle)
|
||||
table.row(table.db.get_note_from_handle(note.handle),
|
||||
str(note_ref.ref_object.note_type),
|
||||
note_ref.ref_object.text[:50])
|
||||
retval += table.get_html()
|
||||
if user.is_authenticated() and url and action == "view":
|
||||
retval += make_button(_("Add note"), (url + "/add") % args)
|
||||
else:
|
||||
retval += nbsp("") # to keep tabs same height
|
||||
return retval
|
||||
|
||||
def attribute_table(obj, user, action, url=None, *args):
|
||||
retval = ""
|
||||
table = Table()
|
||||
table.columns(_("Type"),
|
||||
_("Value"),
|
||||
)
|
||||
if user.is_authenticated():
|
||||
obj_type = ContentType.objects.get_for_model(obj)
|
||||
attributes = dji.Attribute.filter(object_type=obj_type,
|
||||
object_id=obj.id)
|
||||
for attribute in attributes:
|
||||
table.row(attribute.attribute_type.name,
|
||||
attribute.value)
|
||||
retval += table.get_html()
|
||||
if user.is_authenticated() and url and action == "view":
|
||||
retval += make_button(_("Add attribute"), (url + "/add") % args)
|
||||
else:
|
||||
retval += nbsp("") # to keep tabs same height
|
||||
return retval
|
||||
|
||||
def address_table(obj, user, action, url=None, *args):
|
||||
retval = ""
|
||||
table = Table()
|
||||
table.columns(_("Date"),
|
||||
_("Address"),
|
||||
_("City"),
|
||||
_("State"),
|
||||
_("Country"))
|
||||
if user.is_authenticated():
|
||||
for address in obj.address_set.all().order_by("order"):
|
||||
locations = address.location_set.all().order_by("order")
|
||||
for location in locations:
|
||||
table.row(display_date(address),
|
||||
location.street,
|
||||
location.city,
|
||||
location.state,
|
||||
location.country)
|
||||
retval += table.get_html()
|
||||
if user.is_authenticated() and url and action == "view":
|
||||
retval += make_button(_("Add address"), (url + "/add") % args)
|
||||
else:
|
||||
retval += nbsp("") # to keep tabs same height
|
||||
return retval
|
||||
|
||||
def gallery_table(obj, user, action, url=None, *args):
|
||||
retval = ""
|
||||
table = Table()
|
||||
table.columns(_("Name"),
|
||||
_("Type"),
|
||||
)
|
||||
retval += table.get_html()
|
||||
if user.is_authenticated() and url and action == "view":
|
||||
retval += make_button(_("Add gallery"), (url + "/add") % args)
|
||||
else:
|
||||
retval += nbsp("") # to keep tabs same height
|
||||
return retval
|
||||
|
||||
def internet_table(obj, user, action, url=None, *args):
|
||||
retval = ""
|
||||
table = Table()
|
||||
table.columns(_("Type"),
|
||||
_("Path"),
|
||||
_("Description"))
|
||||
if user.is_authenticated():
|
||||
urls = dji.Url.filter(person=obj)
|
||||
for url_obj in urls:
|
||||
table.row(str(url_obj.url_type),
|
||||
url_obj.path,
|
||||
url_obj.desc)
|
||||
retval += table.get_html()
|
||||
if user.is_authenticated() and url and action == "view":
|
||||
retval += make_button(_("Add internet"), ((str(url) % args) + "/add"))
|
||||
else:
|
||||
retval += nbsp("") # to keep tabs same height
|
||||
return retval
|
||||
|
||||
def association_table(obj, user, action, url=None, *args):
|
||||
retval = ""
|
||||
table = Table()
|
||||
table.columns(_("Name"),
|
||||
_("ID"),
|
||||
_("Association"))
|
||||
if user.is_authenticated():
|
||||
gperson = table.db.get_person_from_handle(obj.handle)
|
||||
if gperson:
|
||||
associations = gperson.get_person_ref_list()
|
||||
for association in associations:
|
||||
table.row()
|
||||
retval += table.get_html()
|
||||
if user.is_authenticated() and url and action == "view":
|
||||
retval += make_button(_("Add association"), (url + "/add") % args)
|
||||
else:
|
||||
retval += nbsp("") # to keep tabs same height
|
||||
return retval
|
||||
|
||||
def lds_table(obj, user, action, url=None, *args):
|
||||
retval = ""
|
||||
table = Table()
|
||||
table.columns(_("Type"),
|
||||
_("Date"),
|
||||
_("Status"),
|
||||
_("Temple"),
|
||||
_("Place"))
|
||||
if user.is_authenticated():
|
||||
obj_type = ContentType.objects.get_for_model(obj)
|
||||
ldss = obj.lds_set.all().order_by("order")
|
||||
for lds in ldss:
|
||||
table.row(str(lds.lds_type),
|
||||
display_date(lds),
|
||||
str(lds.status),
|
||||
lds.temple,
|
||||
get_title(lds.place))
|
||||
retval += table.get_html()
|
||||
if user.is_authenticated() and url and action == "view":
|
||||
retval += make_button(_("Add LDS"), (url + "/add") % args)
|
||||
else:
|
||||
retval += nbsp("") # to keep tabs same height
|
||||
return retval
|
||||
|
||||
def reference_table(obj, user, action, url=None, *args):
|
||||
retval = ""
|
||||
table = Table()
|
||||
table.columns(_("Type"),
|
||||
_("ID"),
|
||||
_("Name"))
|
||||
if user.is_authenticated():
|
||||
references = dji.PersonRef.filter(ref_object=obj)
|
||||
for reference in references:
|
||||
table.row(str(reference.ref_object),
|
||||
reference.ref_object.gramps_id,
|
||||
make_name(reference.ref_object.name_set, user))
|
||||
retval += table.get_html()
|
||||
retval += nbsp("") # to keep tabs same height
|
||||
return retval
|
||||
|
||||
def children_table(obj, user, action, url=None, *args):
|
||||
retval = ""
|
||||
table = Table()
|
||||
table.columns(
|
||||
_("#"),
|
||||
_("ID"),
|
||||
_("Name"),
|
||||
_("Gender"),
|
||||
_("Paternal"),
|
||||
_("Maternal"),
|
||||
_("Birth Date"),
|
||||
)
|
||||
|
||||
family = obj
|
||||
obj_type = ContentType.objects.get_for_model(family)
|
||||
childrefs = dji.ChildRef.filter(object_id=family.id,
|
||||
object_type=obj_type).order_by("order")
|
||||
links = []
|
||||
count = 1
|
||||
for childref in childrefs:
|
||||
child = childref.ref_object
|
||||
if user.is_authenticated():
|
||||
table.row(str(count),
|
||||
"[%s]" % child.gramps_id,
|
||||
render_name(child, user),
|
||||
child.gender_type,
|
||||
childref.father_rel_type,
|
||||
childref.mother_rel_type,
|
||||
render_date(child.birth, user),
|
||||
)
|
||||
links.append(('URL', ("/person/%s" % child.handle)))
|
||||
else:
|
||||
table.row(str(count),
|
||||
"[%s]" % child.gramps_id,
|
||||
render_name(child, user),
|
||||
child.gender_type,
|
||||
"[Private]",
|
||||
"[Private]",
|
||||
"[Private]",
|
||||
)
|
||||
links.append(('URL', ("/person/%s" % child.handle)))
|
||||
count += 1
|
||||
table.links(links)
|
||||
retval += table.get_html()
|
||||
retval += nbsp("") # to keep tabs same height
|
||||
return retval
|
||||
|
||||
## FIXME: these dji function wrappers just use the functions
|
||||
## written for the import/export. Can be done much more directly.
|
||||
|
||||
def get_title(place):
|
||||
if place:
|
||||
return place.title
|
||||
else:
|
||||
return ""
|
||||
|
||||
def person_get_birth_date(person):
|
||||
#db = DbDjango()
|
||||
#event = get_birth_or_fallback(db, db.get_person_from_handle(person.handle))
|
||||
#if event:
|
||||
# return event.date
|
||||
return None
|
||||
|
||||
def person_get_death_date(person):
|
||||
#db = DbDjango()
|
||||
#event = get_death_or_fallback(db, db.get_person_from_handle(person.handle))
|
||||
#if event:
|
||||
# return event.date
|
||||
return None
|
||||
|
||||
def display_date(obj):
|
||||
date_tuple = dji.get_date(obj)
|
||||
if date_tuple:
|
||||
gdate = GDate()
|
||||
gdate.unserialize(date_tuple)
|
||||
return _dd(gdate)
|
||||
else:
|
||||
return ""
|
||||
|
||||
def render(formfield, user, action, test=False, truetext=""):
|
||||
if not user.is_authenticated():
|
||||
action = "view"
|
||||
if action == "view":
|
||||
if (not user.is_authenticated() and not test) or user.is_authenticated():
|
||||
fieldname = formfield.name # 'surname'
|
||||
retval = str(getattr(formfield.form.model, fieldname))
|
||||
else:
|
||||
retval = truetext
|
||||
else:
|
||||
retval = formfield.as_widget()
|
||||
return retval
|
||||
|
||||
def render_name(name, user):
|
||||
"""
|
||||
Given a Django or Gramps object, render the name and return. This
|
||||
function uses authentication, privacy and probably_alive settings.
|
||||
"""
|
||||
if isinstance(name, models.Name):
|
||||
if not user.is_authenticated():
|
||||
name.sanitize()
|
||||
return "%s, %s" % (name.get_primary_surname(), name.first_name)
|
||||
elif isinstance(name, forms.NameForm):
|
||||
if not user.is_authenticated():
|
||||
name.model.sanitize()
|
||||
return "%s, %s" % (name.model.get_primary_surname(),
|
||||
name.model.first_name)
|
||||
elif isinstance(name, gen.lib.Person): # name is a gen.lib.Person
|
||||
person = name
|
||||
try:
|
||||
name = person.get_primary_name()
|
||||
except:
|
||||
name = None
|
||||
if name is None:
|
||||
return "[No preferred name]"
|
||||
if not user.is_authenticated():
|
||||
name.sanitize()
|
||||
return "%s, %s" % (name.get_primary_surname(), name.first_name)
|
||||
elif isinstance(name, models.Person): # django person
|
||||
person = name
|
||||
try:
|
||||
name = person.name_set.get(preferred=True)
|
||||
except:
|
||||
return "Error"
|
||||
return render_name(name, user)
|
||||
else: # no name object
|
||||
return "[No preferred name]"
|
||||
|
||||
def make_name(name, user):
|
||||
return render_name(name, user)
|
||||
|
||||
def render_date(obj, user):
|
||||
"""
|
||||
Given a Django object, render the date as text and return. This
|
||||
function uses authentication settings.
|
||||
"""
|
||||
if (user.is_authenticated() or
|
||||
(not user.is_authenticated() and obj and not obj.private)):
|
||||
if obj:
|
||||
date_tuple = dji.get_date(obj)
|
||||
if date_tuple:
|
||||
gdate = GDate().unserialize(date_tuple)
|
||||
return _dd(gdate)
|
||||
return ""
|
||||
return "[Private]"
|
||||
|
||||
def person_get_event(person, event_type=None):
|
||||
event_ref_list = dji.get_event_ref_list(person)
|
||||
if event_type:
|
||||
index = libdjango.lookup_role_index(event_type, event_ref_list)
|
||||
if index >= 0:
|
||||
event_handle = event_ref_list[index][3]
|
||||
# (False, [], [], u'b2cfa6cdec87392cf3b', (1, u'Primary'))
|
||||
# WARNING: the same object can be referred to more than once
|
||||
objs = models.EventRef.objects.filter(ref_object__handle=event_handle)
|
||||
if objs.count() > 0:
|
||||
return display_date(objs[0].ref_object)
|
||||
else:
|
||||
return ""
|
||||
else:
|
||||
return ""
|
||||
else:
|
||||
retval = [[obj.ref_object for obj in
|
||||
models.EventRef.objects.filter(ref_object__handle=event_handle[3])]
|
||||
for event_handle in event_ref_list]
|
||||
return [j for i in retval for j in i]
|
||||
|
||||
register_plugins()
|
||||
|
||||
# works after registering plugins:
|
||||
import HtmlDoc
|
||||
from libhtmlbackend import HtmlBackend
|
||||
from libhtml import Html
|
||||
|
||||
Reference in New Issue
Block a user