New files for gramps webapp; src/data/templates contains html templates, and src/gen/web contains gramps-Django interface

svn: r13542
This commit is contained in:
Doug Blank 2009-11-10 05:28:35 +00:00
parent b7327e679a
commit 4ab1467845
36 changed files with 3960 additions and 0 deletions

View File

@ -0,0 +1,55 @@
{% load my_tags %}
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE html "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="" lang="">
<head>
<title>{% block title %}GRAMPS Connect{% endblock %}</title>
{% block meta %}
<meta http-equiv="content-type" content="text/html;charset=UTF-8" />
<meta http-equiv="Content-Style-Type" content="text/css" />
<meta name="generator" content="GRAMPS 3.2.0-0.SVN12859M http://gramps-project.org/" />
<meta name="author" content="" />
{% endblock %}
<link href="/images/favicon.ico" type="image/x-icon" rel="shortcut icon" />
{% block css %}
<link media="screen" href="/styles/behaviour.css" type="text/css" rel="stylesheet" />
<link media="screen" href="/styles/Web_Alphabet-Horizontal.css" type="text/css" rel="stylesheet" />
<link media="screen" href="/styles/Web_Mainz.css" type="text/css" rel="stylesheet" />
<link media="print" href="/styles/Web_Print-Default.css" type="text/css" rel="stylesheet" />
{% endblock %}
</head>
<body id= "NarrativeWeb">
<div id="header">
<h1 id="SiteTitle">{% block heading %}GRAMPS Connect{% endblock %}</h1>
</div>
<div id="navigation">
{% block navigation %}
<ul>
<li class="{{ cview|currentSection:"home" }}"><a href="/">Home</a></li>
{% for view in views %}
<li class="{{ cview|currentSection:view.1 }}"><a href="/{{view.1}}/">{{view.0}}</a></li>
{% endfor %}
{% if user.is_authenticated %}
<li><a href="/logout">Logout</a></li>
{% if user.is_superuser %}
<li><a href="/admin">Admin</a></li>
{% endif %}
{% else %}
<li><a href="/login/">Login</a></li>
{% endif %}
</ul>
{% endblock %}
</div>
<div class="content">
<div class="grampsweb">
{% block content %}
{% endblock %}
</div>
</div>
<div id="footer">
{% block footer %}(c) 2009 <a href="http://www.gramps-project.org/">www.gramps-project.net</a>
{% endblock %}
</div>
</body>
</html>

View File

@ -0,0 +1,26 @@
{% extends "gramps-base.html" %}
{% block title %}GRAMPS Connect - main page {% endblock %}
{% block heading %}GRAMPS - main page {% endblock %}
{% block content %}
<p id="description">Welcome to GRAMPS Connect, a new web-based collaboration tool.
{% if user.is_authenticated %}
You are now logged in
as <a href="/user/{{user.username}}">{{user.username}}</a>.
{% endif %}
</p>
<p id="description">
Database information:
<ul>
{% for view in views %}
<li><a href="/{{view.1}}">{{view.0}}</a> ({{view.2}} records)</li>
{% endfor %}
</ul>
</p>
{% endblock %}

View File

@ -0,0 +1,31 @@
{% extends "base.html" %}
{% block windowtitle %}Person Details{% endblock %}
{% block pagetitle %}{{Pname}}{% endblock %}
{% block content %}
<form name="input" action={{URL}} method="post">
<table cellspacing = "2">
<tr><td colspan = "2">Preferred Name</td></tr>
{% for field in NForm %}
<div class="fieldWrapper"><tr>
<td width="10"></td>
<td>{{ field.label_tag }}: </td>
<td width="300">{{ field }}<p>{{ field.help_text }}</p></td>
<td>{{ field.errors }}</td>
</tr></div>
{% endfor %}
</table>
<table cellspacing = "2">
{% for field in PForm %}
<div class="fieldWrapper"><tr>
<td>{{ field.label_tag }}: </td>
<td width="300">{{ field }}<p>{{ field.help_text }}</p></td>
<td>{{ field.errors }}</td>
</tr></div>
{% endfor %}
</table>
<input type="submit" value="Save & Exit" />
</form>
{% endblock %}

View File

@ -0,0 +1,69 @@
{% extends "base.html" %}
{% block windowtitle %}Person Details{% endblock %}
{% block pagetitle %}{{Pname}}{% endblock %}
{% block content %}
<form name="input" action={{URL}} method="post">
{{ NForm.management_form }}
Names (<a id="displayText" href="javascript:toggle('nameset','show');">hide</a>)
<div id="nameset" style="display: block">
<table class="nicetable">
<tr>
<td>Preferred Name?</td>
<td>Prefix</td>
<td>First Name</td>
<td>Surname</td>
<td>Suffix</td>
<td>Type of Name</td>
<td>Delete</td>
</tr>
{% for form in NForm.forms %}
<tr>
{% for field in form %}
<td><p>{{ field }}</p>
<div id="errmsg"><p>{{ field.errors }}</p></div></td>
{% endfor %}
</tr>
{% endfor %}
<tr><td colspan="7"><div id="errmsg">{{ NamesetError }}</div></td></tr>
</table></div>
<table class="nicetable">
<tr>
<td>Reference ID: {{PForm.gramps_id}}</td>
<td>{{PForm.private}} Private </td>
<td>Last Changed: {{PLastChanged}}
<div id="errmsg"><p>{{PForm.last_changed.errors}}</p></div></td>
</tr><tr>
<td>Marker: {{PForm.marker_type}}
<div id="errmsg"><p>{{PForm.marker_type.errors}}</p></div></td>
<td>Gender: {{PForm.gender_type}}
<div id="errmsg"><p>{{PForm.gender_type.errors}}</p></div></td>
</tr><tr>
<td><p>Parent in these families:
(<a id="displayText" href="javascript:toggle('families','Edit');">
Edit</a>)</p><ul>{% for family in ParentF %}
<li>{{family}}</li>
{% endfor %}</ul></td>
<td><p>Child in these families:
(<a id="displayText" href="javascript:toggle('pfamilies','Edit');"> Edit</a>)</p><ul>{% for family in ChildF %}
<li>{{family}}</li>
{% endfor %}</ul></td>
</tr>
</table>
<table class="nicetable">
<tr><td width = "300"><div id="families" style="display: none">
<p>{{PForm.families}}</p>
<p>{{PForm.families.help_text}}</p>
<p>{{PForm.famlies.errors}}</p></div></td>
<td width = "300"><div id="pfamilies" style="display: none">
<p>{{PForm.parent_families}}</p>
<p>{{PForm.parent_families.help_text}}</p>
<p>{{PForm.parent_famlies.errors}}</p></div></td></tr>
</table>
<input type="submit" value="Save & Exit" />
</form>
{% endblock %}

View File

@ -0,0 +1,9 @@
{% extends "base.html" %}
{% block windowtitle %}Places{% endblock %}
{% block pagetitle %}Places{% endblock %}
{% block content %}
Congratulations, you found Places
{% endblock %}

View File

@ -0,0 +1,49 @@
{{ NForm.management_form }}
<table cellspacing = "2">
<tr><td colspan = "2">Names:</td></tr>
<tr><td width="10"></td>
<td><label>Preferred Name?</label></td>
<td width="50"><label>Prefix</label></td>
<td><label>First Name</label></td>
<td><label>Surname</label></td>
<td><label>Suffix</label></td>
<td><label>Type of Name</label></td>
<td><label>Delete</label></td>
</tr>
{% for form in NForm.forms %}
<div class="fieldWrapper"><tr>
<td width="10"></td>
{% for field in form %}
<td align="center">{{ field }}</td>
{% endfor %}
</tr></div>
<tr><td colspan="5>{{form.errors}}</td></tr>
{% endfor %}
</table>
{% for field in PForm %}
<div class="fieldWrapper"><tr>
<td>{{ field.label_tag }}: </td>
<td width="300">{{ field }}<p>{{ field.help_text }}</p></td>
<td>{{ field.errors }}</td>
</tr></div>
{% endfor %}
{{ NForm.management_form }}
<table>
<td>Preferred Name?</td>
<td>Prefix</td>
<td>First Name</td>
<td>Surname</td>
<td>Suffix</td>
<td>Type of Name</td>
<td>Delete</td>
</tr>
{% for form in NForm.forms %}
{% for field in form %}
<td align="left">{{ field }}<p>{{ field.errors }}</p></td>
{% endfor %}
</tr>
<tr><td colspan="7"></td></tr>
{% endfor %}
</table>

View File

@ -0,0 +1,35 @@
{% extends "gramps-base.html" %}
{% block title %}GRAMPS Connect - login {% endblock %}
{% block heading %}GRAMPS - login {% endblock %}
{% block content %}
<h2>User Login</h2>
{% if form.errors %}
<p id="description">Your username or password were not valid. Please try again.</p>
{% else %}
<p id="description">Enter your login ID and password below. </p>
{% endif %}
<form method="post" action=".">
<table>
<tr>
<td>
<label for="id_username">Username: </label>
</td>
<td>
{{form.username}}
</td>
</tr>
<tr>
<td>
<label for="id_password">Password: </label>
</td>
<td>
{{form.password}}
</td>
</tr>
</table>
<input type="hidden" name="next" value="/" />
<input type="submit" value="Login" />
</form>
{% endblock %}

View File

@ -0,0 +1,9 @@
{% extends "base.html" %}
{% block windowtitle %}Data Changes Successfully Saved{% endblock %}
{% block pagetitle %}Data Changes Successfully Saved{% endblock %}
{% block content %}
Congratulations, your data changes were successful!
{% endblock %}

View File

@ -0,0 +1,5 @@
{% for header in headers %}<th{{ header.class_attr }}>
{% if header.sortable %}<a href="{{ header.url|escape }}">{% endif %}
{{ header.text }}
{% if header.sortable %}</a>{% endif %}
</th>{% endfor %}

View File

@ -0,0 +1,20 @@
{% extends "gramps-base.html" %}
{% block title %}GRAMPS Connect - user page {% endblock %}
{% block heading %}GRAMPS - user page {% endblock %}
{% block content %}
<p id="description">Details for <b>{{user.first_name}} {{user.last_name}}</b> ({{user.username}}):</p>
<p id="description">
<ul>
<li>User name: <b>{{user.username}}</b></li>
<li>Email: <b><a href="mailto:{{user.email}}">{{user.email}}></a></b></li>
<li>Superuser?: <b>{{user.is_superuser}}</b></li>
<li>Last login: <b>{{user.last_login}}</b></li>
</ul>
</p>
{% endblock %}

View File

@ -0,0 +1,10 @@
{% extends "gramps-base.html" %}
{% block title %}GRAMPS Connect - {{cview}} detail page {% endblock %}
{% block heading %}GRAMPS - {{cview}} detail page {% endblock %}
{% block content %}
{{cview}} Detail page.
{% endblock %}

View File

@ -0,0 +1,34 @@
{% extends "view_page.html" %}
{% load my_tags %}
{% block table_data %}
<table cellspacing="0" class="infolist surname">
<thead>
<tr>
<th>Item #</th>
<th>ID</th>
<th>Father</th>
<th>Mother</th>
<th>Relationship</th>
</tr>
</thead>
<tbody>
{% for family in page.object_list %}
<tr class="{% cycle odd,even %}">
<td>{{ forloop.counter|row_count:page }}</td>
<td><a href="/{{view}}/{{family.gramps_id|escape}}" class="noThumb"><span class="grampsid">[{{family.gramps_id}}]</span></a>
<td><a href="/{{view}}/{{family.handle|escape}}">{{family.father.name_set|make_name:user}}</a>
<td><a href="/{{view}}/{{family.handle|escape}}">{{family.mother.name_set|make_name:user}}</a>
{% if user.is_authenticated %}
<td><a href="/{{view}}/{{family.handle|escape}}">{{family.family_rel_type|escape}}</a>
{% else %}
<td><a href="/{{view}}/{{family.handle|escape}}">[Private]</a>
{% endif %}
</tr>
{% endfor %}
</tbody>
</table>
{% endblock %}

View File

@ -0,0 +1,34 @@
{% extends "view_page.html" %}
{% load my_tags %}
{% block table_data %}
<table cellspacing="0" class="infolist surname">
<thead>
<tr>
<th>Item #</th>
<th>ID</th>
<th>Father</th>
<th>Mother</th>
<th>Relationship</th>
</tr>
</thead>
<tbody>
{% for family in page.object_list %}
<tr class="{% cycle odd,even %}">
<td>{{ forloop.counter|row_count:page }}</td>
<td><a href="/{{view}}/{{family.gramps_id|escape}}" class="noThumb"><span class="grampsid">[{{family.gramps_id}}]</span></a>
<td><a href="/{{view}}/{{family.handle|escape}}">{{family.father.name_set|make_name:user}}</a>
<td><a href="/{{view}}/{{family.handle|escape}}">{{family.mother.name_set|make_name:user}}</a>
{% if user.is_authenticated %}
<td><a href="/{{view}}/{{family.handle|escape}}">{{family.family_rel_type|escape}}</a>
{% else %}
<td><a href="/{{view}}/{{family.handle|escape}}">[Private]</a>
{% endif %}
</tr>
{% endfor %}
</tbody>
</table>
{% endblock %}

View File

@ -0,0 +1,13 @@
{% load my_tags %}
<table cellspacing="0">
<thead>
<tr>
{% table_header %}
</tr>
</thead>
<tbody>
{% for view in view_list %}<tr class="{% cycle odd,even %}">
<td><a href="/{{view.name|lower}}/">{{ view.name|escape }}</a></td>
</tr>{% endfor %}
</tbody>
</table>

View File

@ -0,0 +1,81 @@
{% extends "gramps-base.html" %}
{% load my_tags %}
{% block title %}GRAMPS Connect - {{cview}} view page {% endblock %}
{% block heading %}GRAMPS - {{cview}} view page {% endblock %}
{% block content %}
<p id="description">
<form>
<input type="submit" value="Search:"></submit>
<input name="search" type="input" size="50" value="{{search}}"></input>
</form>
</p>
<div class="pagination">
<span class="step-links">
{% ifequal page.number 1 %}
[first]
{% else %}
[<a href="?page=1{{search_query}}">first</a>]
{% endifequal %}
{% if page.has_previous %}
[<a href="?page={{page.previous_page_number}}{{search_query}}">previous</a>]
{% else %}
[previous]
{% endif %}
<span class="current">
Page {{ page.number }} of {{ page.paginator.num_pages }}
</span>
{% if page.has_next %}
[<a href="?page={{ page.next_page_number }}{{search_query}}">next</a>]
{% else %}
[next]
{% endif %}
{% ifequal page.number page.paginator.num_pages %}
[last]
{% else %}
[<a href="?page={{page.paginator.num_pages}}{{search_query}}">last</a>]
{% endifequal %}
</span>
</div>
<p>&nbsp;</p>
{% block table_data %} TABLE DATA GOES HERE {% endblock %}
<table></table>
<div class="pagination">
<span class="step-links">
{% ifequal page.number 1 %}
[first]
{% else %}
[<a href="?page=1{{search_query}}">first</a>]
{% endifequal %}
{% if page.has_previous %}
[<a href="?page={{page.previous_page_number}}{{search_query}}">previous</a>]
{% else %}
[previous]
{% endif %}
<span class="current">
Page {{ page.number }} of {{ page.paginator.num_pages }}
</span>
{% if page.has_next %}
[<a href="?page={{ page.next_page_number }}{{search_query}}">next</a>]
{% else %}
[next]
{% endif %}
{% ifequal page.number page.paginator.num_pages %}
[last]
{% else %}
[<a href="?page={{page.paginator.num_pages}}{{search_query}}">last</a>]
{% endifequal %}
</span>
</div>
{% endblock %}

View File

@ -0,0 +1,41 @@
{% extends "view_page.html" %}
{% load my_tags %}
{% block table_data %}
<table cellspacing="0" class="infolist IndividualList">
<thead>
<tr>
<th>Item #</th>
<th>Name</th>
<th>ID</th>
<th>Gender</th>
<th>Birth Date</th>
<!-- <td>Birth Place</td> -->
<!-- <td>Death Place</td> -->
<th>Death Date</th>
<!-- <td>Spouse</td> -->
</tr>
</thead>
<tbody>
{% for name in page.object_list %}
<tr class="{% cycle odd,even %}">
<td>{{ forloop.counter|row_count:page }}</td>
<td><a href="/{{view}}/{{name.person.handle|escape}}/" class="noThumb">{{name|make_name:user}}</a>
</td>
<td><a href="/{{view}}/{{name.person.handle|escape}}" class="grampsid">[{{name.person.gramps_id|escape}}]</a></td>
<td><a href="/{{view}}/{{name.person.handle|escape}}" class="noThumb">{{name.person.gender_type|escape}}</a></td>
{% if user.is_authenticated %}
<td><a href="/{{view}}/{{name.person.handle|escape}}" class="noThumb">{{name.person|person_get_birth_date}}</a></td>
<td><a href="/{{view}}/{{name.person.handle|escape}}" class="noThumb">{{name.person|person_get_death_date}}</a></td>
{% else %}
<td><a href="/{{view}}/{{name.person.handle|escape}}/" class="noThumb">[Private]</a>
<td><a href="/{{view}}/{{name.person.handle|escape}}/" class="noThumb">[Private]</a>
{% endif %}
</tr>
{% endfor %}
</tbody>
</table>
{% endblock %}

View File

@ -0,0 +1,34 @@
{% extends "view_page.html" %}
{% load my_tags %}
{% block table_data %}
<table cellspacing="0" class="infolist surname">
<thead>
<tr>
<th>Item #</th>
<th>ID</th>
<th>Father</th>
<th>Mother</th>
<th>Relationship</th>
</tr>
</thead>
<tbody>
{% for family in page.object_list %}
<tr class="{% cycle odd,even %}">
<td>{{ forloop.counter|row_count:page }}</td>
<td><a href="/{{view}}/{{family.gramps_id|escape}}" class="noThumb"><span class="grampsid">[{{family.gramps_id}}]</span></a>
<td><a href="/{{view}}/{{family.handle|escape}}">{{family.father.name_set|make_name:user}}</a>
<td><a href="/{{view}}/{{family.handle|escape}}">{{family.mother.name_set|make_name:user}}</a>
{% if user.is_authenticated %}
<td><a href="/{{view}}/{{family.handle|escape}}">{{family.family_rel_type|escape}}</a>
{% else %}
<td><a href="/{{view}}/{{family.handle|escape}}">[Private]</a>
{% endif %}
</tr>
{% endfor %}
</tbody>
</table>
{% endblock %}

39
src/gen/web/Makefile Normal file
View File

@ -0,0 +1,39 @@
# Initialize GRAMPS Django site
update: grampsdb/fixtures/initial_data.json
python manage.py syncdb
grampsdb/fixtures/initial_data.json:
python init.py > grampsdb/fixtures/initial_data.json
init_gramps:
python init_gramps.py # clear primary and secondary tables
run:
python manage.py runserver
sql:
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,Markup,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,Markup,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,Markup,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,Markup,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

209
src/gen/web/README Normal file
View File

@ -0,0 +1,209 @@
Setting up everything for gramps webapp grampsweb:
This example will allow you to create a Django Database, populate it
through a GRAMPS export plugin, and then access/edit the data via the
web.
There are two ways to run this example: using a SQL engine via a
webserver, or using a local SQL database. With either way, you'll be
able to access/edit the data over the web. The only difference is
whether GRAMPS and the webserver accesses the data locally or through
a server.
First, the easy way with a local sqlite database (steps 2 and 3 are
the same for both):
1/packages
sudo yum install subversion sqlite
2/DO STEP 2 BELOW
3/DO STEP 3 BELOW
4/Django settings
Go to the branches/geps/gep-013-server/webapp/grampsweb dir and edit
settings.py to reflect your setup:
$ cd webapp/grampsweb
$ gedit settings.py
and make sure to set to the correct values:
----------------------------------------------
DATABASE_ENGINE = 'sqlite3'
# Set the DATABASE_NAME to a full name and path to database file
# This file will be created, so make sure it is in a readable/writeable place.
DATABASE_NAME = '/home/dblank/gramps/gep-013-server/webapp/grampsweb/gramps.sql'
# See file for examples for these:
TIME_ZONE: your time zone
LANGUAGE_CODE: your code
# Full path:
TEMPLATE_DIRS = (
"/home/dblank/gramps/gep-013-server/webapp/html/templates",
)
----------------------------------------------
5/Make database, and then run a webserver:
make clean
make
make run
6/Run the Django Export plugin in this version of GRAMPS:
(you may need to ./autogen.sh; make in top level of branch)
python ../../src/gramps.py
Open a family tree, and select in menu Family Tree the export
entry. Select Django export. (You used to have to give a filename;
that is fixed now.) The django installation is querried and the django
backend as given in the settings is used to write to.
NOTE: You must manually empty the tables or delete them and regenerate
for now if you reexport your data, as the export plugin expects an
empty database. If the database is not empty, duplication errors will
occur.
7/You can (after this plugin has finished running) go back to eg
pgadmin or the http://127.0.0.1:8000/admin to see that the objects
have been saved. You can edit them here, too.
See the following for more details, and for setting up a more
sophisticated database server.
----------------------------------------------
1/packages
benny@antec:sudo apt-get install python-psycopg python-psycopg2 postgresql apache2 libapache2-mod-python subversion pgadmin3 pgadmin3-data
2/get the django code.and install it
See http://docs.djangoproject.com/en/dev/topics/install/
3/get webapp sourcecode
benny@antec:mkdir branches/geps;cd branches/geps
**** extract data here ***
svn co https://gramps.svn.sourceforge.net/svnroot/gramps/branches/geps/gep-013-server/ gep013-server
Now go to the gramps code, and set it up
cd gep013-server
./autogen.sh
make
4/set up PostgreSQL
Reset the password for the 'postgres' admin account for the server
benny@antec:cd ~
benny@antec:sudo su postgres -c psql template1
template1=# ALTER USER postgres WITH PASSWORD 'password';
template1=# \q
Add a new user into postgresql:
benny@antec:sudo su postgres -c createuser gramps
Enter name of role to add: gramps
Shall the new role be a superuser? (y/n) y
Now define the access rules for the database. The easiest is to give access to all databases via md5:
benny@antec:sudo kate /etc/postgresql/8.3/main/pg_hba.conf
and end of file should look like:
# "local" is for Unix domain socket connections only
local all all md5
# IPv4 local connections:
host all all 127.0.0.1/32 md5
# IPv6 local connections:
host all all ::1/128 md5
Restart the server:
benny@antec:~$ sudo /etc/init.d/postgresql-8.3 restart
5/Use pgAdmin3 to access the database server.
benny@antec:pgadmin3
In the new server registration dialog, give a name for your server, and set:
Host: localhost
Maintenance DB: postgres
Username: postgres
Password: 'password' ==> the password entered above in 4/
Do not store the password! Next click to connect (Menu Tools->Connect).
If all is well, postgresql is set up and you see your server running. The login roles should contain the user ´gramps` you created in 4/
First step is to make a database which gramps webapp can use, so right click on your server, and add a database:
name: db_gramps
owner: gramps
encoding: UTF-8
Next, go to the role 'gramps' and assign a password with which the user can
access.
That's it, the tables will be created with django.
6/Django settings
Go to the webapp code and change your settings to reflect your setup.
benny@antec:cd webapp/grampsweb
benny@antec:kate settings.py
and make sure to set to the correct values:
DATABASE_USER: as given in 4/, standard is gramps
DATABASE_PASSWORD: the password for the user in the database grampsonrails will create
TIME_ZONE: your time zone
LANGUAGE_CODE: your code
TEMPLATE_DIRS = (
"/yourfullpath/gep-013-server/webapp/html/templates",
)
....
See the Django site for more info when changing variables:
http://docs.djangoproject.com/en/dev/topics/settings/#topics-settings
7/run your webserver
For production, you should use Apache. For testing locally, you can use the django webserver, which is available via the manage.py file in the webapp directory.
Note that we need GRAMPS libraries, so we give the GRAMPS path for inclusion in PYTHONPATH. For effective distribution, we will ship the required libraries of GRAMPS in the application grampsweb. For my case this is
benny@antec: PYTHONPATH=~/programs/gramps/branches/geps/gep013-server/src/ python manage.py runserver &
Try it in your webbrowser by going to:
http://127.0.0.1:8000/admin
8/Create tables and start the django application
benny@antec: python manage.py syncdb
Create the superuser for django at this moment if needed.
9/To see the SQL to create the tables, do:
PYTHONPATH=~/programs/gramps/branches/geps/gep013-server/src/ python manage.py sqlall grampsdb
10/Now that a beginning of the tables is present, we need to pump data into it. For now, we assume all tables are empty, and we add new data to it. If the tables are not empty, drop them first, eg via pgAdmin for postgresql.
A new export plugin that can write to your django backend is written, ExportDjango. If your database exists, then you can just open a family tree, and select to export this to the django backend. At the moment only markertype and part of the person object are exported as a proof of concept.
11/You can after this plugin is finished go back to eg pgadmin or the http://127.0.0.1:8000/admin to see the objects have been saved.
References:
[1] http://ianlawrence.info/random-stuff/set-up-django-apache-and-postgresql-on-ubuntu-feisty/
[2] http://www.postgresql.org/docs/8.1/static/app-createuser.html
[3] http://antoniocangiano.com/2007/12/26/installing-django-with-postgresql-on-ubuntu/
[4] http://www.mail-archive.com/django-users@googlegroups.com/msg36675.html

0
src/gen/web/__init__.py Normal file
View File

249
src/gen/web/djangodb.py Normal file
View File

@ -0,0 +1,249 @@
import gen
from gen.db import GrampsDbBase
from gen.web.libdjango import DjangoInterface
import Utils
# class Trans(object):
# def __init__(self, dji_model):
# self.dji_model = dji_model
# def get(self, handle):
# return self.dji_model.filter(handle=handle) == 1
# def keys(self):
# return [item.handle for item in self.dji_model.all()]
# from ReportBase._CommandLineReport import run_report_direct
# import djangodb
# db = djangodb.DjangoDb()
# run_report_direct(db, "ancestor_report", off="pdf", of="ar.pdf")
#
def probably_alive(handle):
db = DjangoDb()
return Utils.probably_alive(db.get_person_from_handle(handle), db)
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
class DjangoDb(GrampsDbBase):
"""
A Gramps Database Backend. This replicates the grampsdb functions.
"""
def __init__(self):
super(DjangoDb, self).__init__()
self.dji = DjangoInterface()
self.readonly = False
self.db_is_open = True
def get_event_from_handle(self, handle):
obj = gen.lib.Event()
obj.unserialize(self.dji.get_event(self.dji.Event.get(handle=handle)))
return obj
def get_family_from_handle(self, handle):
obj = gen.lib.Family()
obj.unserialize(self.dji.get_family(self.dji.Family.get(handle=handle)))
return obj
def get_person_from_handle(self, handle):
obj = gen.lib.Person()
data = self.dji.get_person(self.dji.Person.get(handle=handle))
obj.unserialize(data)
return obj
def get_person_from_gramps_id(self, gramps_id):
obj = gen.lib.Person()
data = self.dji.get_person(self.dji.Person.get(gramps_id=gramps_id))
obj.unserialize(data)
return obj
def get_number_of_people(self):
return self.dji.Person.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.dji.get_place)
def get_person_cursor(self):
return Cursor(self.dji.Person, self.dji.get_person)
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):
return self.dji.get_person(self.dji.Person.get(handle=handle))
def get_raw_family_data(self, handle):
return self.dji.get_family(self.dji.Family.get(handle=handle))
def get_raw_source_data(self, handle):
return self.dji.get_source(self.dji.Source.get(handle=handle))
def get_raw_repository_data(self, handle):
return self.dji.get_repository(self.dji.Repository.get(handle=handle))
def get_raw_note_data(self, handle):
return self.dji.get_note(self.dji.Note.get(handle=handle))
def get_raw_place_data(self, handle):
return self.dji.get_place(self.dji.Place.get(handle=handle))
def add_person(self, person, trans, set_gid=True):
pass
# if self.step == 0:
# if not person.handle:
# person.handle = Utils.create_id()
# if not person.gramps_id:
# person.gramps_id = self.find_next_person_gramps_id()
# self.lookup[person.gramps_id] = person.handle
# if self.dji.Person.filter(handle=person.handle).count() == 0:
# print "add_person:", person.handle
# self.dji.add_person(person.serialize())
# else:
# print "update_person:", person.handle
# person.handle = self.lookup[person.gramps_id]
# self.dji.add_person_detail(person.serialize())
def add_family(self, family, trans, set_gid=True):
pass
# if self.step == 0:
# if not family.handle:
# family.handle = Utils.create_id()
# if not family.gramps_id:
# family.gramps_id = self.find_next_family_gramps_id()
# self.lookup[family.gramps_id] = family.handle
# if self.dji.Family.filter(handle=family.handle).count() == 0:
# print "add_family:", family.handle
# self.dji.add_family(family.serialize())
# else:
# family.handle = self.lookup[family.gramps_id]
# self.dji.add_family_detail(family.serialize())
def add_source(self, source, trans, set_gid=True):
pass
#print "add_source:", source.handle
#if not source.handle:
# source.handle = Utils.create_id()
# self.dji.add_source(source.serialize())
#self.dji.add_source_detail(source.serialize())
def add_repository(self, repository, trans, set_gid=True):
pass
#print "add_repository:", repository.handle
#if not repository.handle:
# repository.handle = Utils.create_id()
# self.dji.add_repository(repository.serialize())
#self.dji.add_repository_detail(repository.serialize())
def add_note(self, note, trans, set_gid=True):
pass
#print "add_note:", note.handle
#if not note.handle:
# note.handle = Utils.create_id()
# self.dji.add_note(note.serialize())
#self.dji.add_note_detail(note.serialize())
def add_place(self, place, trans, set_gid=True):
#print "add_place:", place.handle
pass
def add_event(self, event, trans, set_gid=True):
pass
#print "add_event:", event.handle
#if not event.handle:
# event.handle = Utils.create_id()
# self.dji.add_event(event.serialize())
#self.dji.add_event_detail(event.serialize())
def commit_person(self, person, trans, change_time=None):
pass
#print "commit_person:", person.handle
#self.add_person(person, trans)
def commit_family(self, family, trans, change_time=None):
pass
#print "commit_family:", family.handle
#self.add_family(family, trans)
def commit_source(self, source, trans, change_time=None):
pass
#print "commit_source:", source.handle
#self.add_source(source, change_time)
def commit_repository(self, repository, trans, change_time=None):
pass
#print "commit_repository:", repository.handle
#self.add_repository(repository, change_time)
def commit_note(self, note, trans, change_time=None):
pass
#print "commit_note:", note.handle
#self.add_note(note, change_time)
def commit_place(self, place, trans, change_time=None):
pass
#print "commit_place:", place.handle
#if self.dji.Place.filter(handle=place.handle).count() == 0:
# self.dji.add_place(place.serialize())
#self.dji.add_place_detail(place.serialize())
def commit_event(self, event, change_time=None):
pass
#print "commit_event:", event.handle
#self.add_event(event, change_time)
# def find_family_from_handle(self, handle, trans):
# obj = gen.lib.Family()
# results = self.dji.Family.filter(handle=handle)
# if results.count() == 0:
# obj.handle = handle
# new = True
# else:
# data = self.dji.get_family(results[0])
# obj.unserialize(data)
# new = False
# return obj, new

69
src/gen/web/forms.py Normal file
View File

@ -0,0 +1,69 @@
# forms.py forms for Django project gen.web
from django import forms
from gen.web.grampsdb.models import *
from django.forms.models import inlineformset_factory
from django.forms.models import BaseModelFormSet
import datetime
class PersonForm(forms.ModelForm):
class Meta:
model = Person
exclude = ('handle',)
'''def clean(self):
cleaned_data['last_changed'] = datetime.datetime.now()
super(PersonForm, self).clean() # validate based on model
return self.cleaned_data'''
class NameForm(forms.ModelForm):
class Meta:
model = Name
'''class NameFormset(BaseModelFormSet):
def __init__(self, *args, **kwargs):
self.form = NameForm
super(NameFormset, self).__init__(*args, **kwargs)
def makeNameFormset(pid):
class NameFormset(BaseFormSet):
def __init__(self, *args, **kwargs):
self.form = NameForm
self.queryset = Name.objects.filter(person=pid)
super(NameFormset, self).__init__(*args, **kwargs)
def clean(self):
super(NameFormset, self).clean() # validate based on model
if any(self.errors):
# formset is not valid as long as any one form is invalid
return
# allow only one name per person to be preferred
ctPref = 0
for i in range(0, self.total_form_count()):
form = self.forms[i]
ctPref += form.cleaned_data['preferred']
if ctPref > 1:
raise forms.ValidationError, "Only one name may be the preferred name."
return NameFormset'''
NameInlineFormSet = inlineformset_factory(Person, Name,
fields=('preferred','prefix','first_name',
'surname','suffix','name_type'),
form=NameForm)
def cleanPreferred(fmst):
if fmst.total_form_count() == 3: # person has no names (assumes default 3 extra forms)
return "Error: Each person must have at least one name."
ctPref = 0
for i in range (0,fmst.total_form_count()-3):
form = fmst.forms[i]
try: # when preferred is false, its value is not in the form data
if form.data[fmst.prefix + '-' + str(i) + '-preferred'] == 'on':
val = 1
else:
val = 0
except:
val = 0
ctPref += val
if ctPref != 1:
return "Error: Exactly one name may be the preferred name."
else:
return "none"

View File

View File

@ -0,0 +1,6 @@
from gen.web.grampsdb.models import *
from django.contrib import admin
for type_name in get_tables("all"):
admin.site.register(type_name[1])

View File

@ -0,0 +1,873 @@
# 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
#---------------------------------------------------------------------------
#
# 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 MarkerType(mGrampsType):
from gen.lib.markertype import MarkerType
_DATAMAP = get_datamap(MarkerType)
_CUSTOM = MarkerType._CUSTOM
_DEFAULT = _DATAMAP[MarkerType._DEFAULT]
val = models.IntegerField('marker', choices=_DATAMAP, blank=False)
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 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)
#---------------------------------------------------------------------------
#
# Support definitions
#
#---------------------------------------------------------------------------
class DateObject(models.Model):
class Meta: abstract = True
calendar = models.IntegerField()
modifier = models.IntegerField()
quality = models.IntegerField()
day1 = models.IntegerField()
month1 = models.IntegerField()
year1 = models.IntegerField()
slash1 = models.BooleanField()
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()
newyear = models.IntegerField()
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 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
private = models.BooleanField('private')
#attributes = models.ManyToManyField("Attribute", blank=True, null=True)
## Keys:
marker_type = models.ForeignKey('MarkerType')
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')
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")
#lds_list = models.ManyToManyField('Lds', null=True, blank=True)
#url_list = models.ManyToManyField('Url', null=True, blank=True)
# Others keys here:
# .name_set
# .address_set
# .lds_set
# .url_set
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')
#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")
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")
#---------------------------------------------------------------------------
#
# 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
order = models.PositiveIntegerField()
class Name(DateObject, SecondaryObject):
name_type = models.ForeignKey('NameType', related_name="name_code")
preferred = models.BooleanField('preferred name?')
first_name = models.TextField(blank=True)
surname = models.TextField(blank=True)
suffix = models.TextField(blank=True)
title = models.TextField(blank=True)
prefix = models.TextField(blank=True)
patronymic = models.TextField(blank=True)
call = models.TextField(blank=True)
group_as = models.TextField(blank=True)
sort_as = models.IntegerField(blank=True)
display_as = models.IntegerField(blank=True)
## Key:
person = models.ForeignKey("Person")
def __unicode__(self):
return "%s%s%s, %s" % (self.prefix,
["", " "][bool(self.prefix)],
self.surname,
self.first_name)
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)
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
#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)
TABLES = [
("abstract", mGrampsType),
("type", MarkerType),
("type", MarkupType),
("type", NameType),
("type", AttributeType),
("type", UrlType),
("type", ChildRefType),
("type", RepositoryType),
("type", EventType),
("type", FamilyRelType),
("type", SourceMediaType),
("type", EventRoleType),
("type", NoteType),
("type", GenderType),
("type", LdsType),
("type", LdsStatus),
("abstract", DateObject),
("meta", Config),
("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", 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)
]
def clear_tables(*categories):
"""
Clear the entries of categories of tables. Category is:
"abstract", "type", "ref", "meta", "primary" and "secondary".
"""
for pair in get_tables(*categories):
pair[1].objects.all().delete()
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"]
#---------------------------------------------------------------------------
#
# Testing Functions
#
#---------------------------------------------------------------------------
## Primary:
def test_Person():
m = get_default_type(MarkerType)
p = Person(handle=create_id(), marker_type=m)
p.gender_type = GenderType.objects.get(id=1)
p.gramps_id = "P%05d" % (Person.objects.count() + 1)
p.save()
return p
def test_Family():
m = get_default_type(MarkerType)
frt = FamilyRelType.objects.get(id=1)
f = Family(handle=create_id(), marker_type=m, family_rel_type=frt)
f.gramps_id = "F%05d" % (Family.objects.count() + 1)
f.save()
return f
def test_Source():
m = get_default_type(MarkerType)
s = Source(handle=create_id(), marker_type=m)
s.save()
s.gramps_id = "S%05d" % (Source.objects.count() + 1)
s.save()
return s
def test_Event():
m = get_default_type(MarkerType)
et = get_default_type(EventType)
e = Event(handle=create_id(), marker_type=m, event_type=et)
e.set_date_from_gdate( GDate() )
e.gramps_id = "E%05d" % (Event.objects.count() + 1)
e.save()
return e
def test_Repository():
m = get_default_type(MarkerType)
rt = get_default_type(RepositoryType)
r = Repository(handle=create_id(), marker_type=m, repository_type=rt)
r.gramps_id = "R%05d" % (Repository.objects.count() + 1)
r.save()
return r
def test_Place():
m = get_default_type(MarkerType)
p = Place(handle=create_id(), marker_type=m)
p.gramps_id = "L%05d" % (Place.objects.count() + 1)
p.save()
return p
def test_Media():
m = get_default_type(MarkerType)
media = Media(handle=create_id(), marker_type=m)
media.set_date_from_gdate( GDate() )
media.save()
media.gramps_id = "M%05d" % (Media.objects.count() + 1)
return media
def test_Note():
m = get_default_type(MarkerType)
note_type = get_default_type(NoteType)
note = Note(handle=create_id(), marker_type=m, note_type=note_type,
preformatted=False)
note.gramps_id = "N%05d" % (Note.objects.count() + 1)
note.save()
return note
def test_Family_with_children():
father = test_Person()
fname = test_Name(father, "Blank", "Lowell")
mother = test_Person()
mname = test_Name(mother, "Bamford", "Norma")
family_rel_type = get_default_type(FamilyRelType)
m = get_default_type(MarkerType)
f = Family(handle=create_id(), father=father, mother=mother,
family_rel_type=family_rel_type, marker_type=m)
f.save()
for names in [("Blank", "Doug"), ("Blank", "Laura"), ("Blank", "David")]:
p = test_Person()
n = test_Name(p, names[0], names[1])
p.families.add(f)
f.save()
return f
## Secondary:
def test_Name(person=None, surname=None, first=None):
if not person: # Testing
person = test_Person()
m = get_default_type(MarkerType)
n = Name()
if first:
n.first_name = first
if surname:
n.surname = surname
n.set_date_from_gdate(Today())
n.name_type = get_default_type(NameType)
n.order = 1
n.sort_as = 1
n.display_as = 1
person.save()
n.person = person
n.save()
return n
def test_Markup(note=None):
if not note:
note = test_Note()
markup = Markup(note=note,
markup_type=get_type(MarkupType,
(1, "Testing"),
get_or_create=True))
markup.order = 1
markup.save()
return markup
def test_Lds(place=None, famc=None):
if not place:
place = test_Place()
if not famc:
famc = test_Family()
lds = Lds(lds_type=get_default_type(LdsType), status=get_default_type(LdsStatus),
place=place, famc=famc, order=1)
lds.set_date_from_gdate(Today())
lds.save()
return lds
def test_NoteRef():
note = test_Note()
person = test_Person()
note_ref = NoteRef(referenced_by=person, ref_object=note)
note_ref.order = 1
note_ref.save()
family = test_Family()
note_ref = NoteRef(referenced_by=family, ref_object=note)
note_ref.order = 1
note_ref.save()
return note_ref
def test_SourceRef():
note = test_Note()
source = test_Source()
source_ref = SourceRef(referenced_by=note, ref_object=source, confidence=4)
source_ref.set_date_from_gdate(Today())
source_ref.order = 1
source_ref.save()
return source_ref
#---------------------------------------------------------------------------
#
# Testing
#
#---------------------------------------------------------------------------
def main():
for test_Item in [test_Person, test_Family, test_Family_with_children,
test_Source, test_Event,
test_Repository, test_Place, test_Media, test_Note,
test_Name, test_Markup, test_Lds, test_NoteRef,
test_SourceRef]:
print "testing:", test_Item.__name__
obj = test_Item()
sourceref = test_SourceRef()
print sourceref.ref_object.references.all()
if __name__ == "__main__":
main()

View File

@ -0,0 +1,148 @@
from django.template import escape, Library
from gen.web import libdjango
from gen.web import djangodb
import gen.web.grampsdb.models as models
from gen.lib.date import Date as GDate, Today
import DateHandler
dji = libdjango.DjangoInterface()
register = Library()
_dd = DateHandler.displayer.display
_dp = DateHandler.parser.parse
## FIXME: these dji function wrappers just use the functions
## written for the import/export. Can be done much more directly.
def person_get_birth_date(person):
return person_get_event(person, models.EventType.BIRTH)
def person_get_death_date(person):
return person_get_event(person, models.EventType.DEATH)
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)
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 person_get_event(person, event_type):
event_ref_list = dji.get_event_ref_list(person)
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 ""
def make_name(name, user):
if isinstance(name, models.Name):
surname = name.surname.strip()
if not surname:
surname = "[Missing]"
if user.is_authenticated():
return escape("%s, %s" % (surname, name.first_name))
else:
if djangodb.probably_alive(name.person.handle):
return escape("%s, %s" % (surname, "[Living]"))
else:
return escape("%s, %s" % (surname, name.first_name))
elif name:
name = name.get(preferred=True)
if name:
return make_name(name, user)
else:
return ""
else:
return ""
make_name.is_safe = True
register.filter('make_name', make_name)
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 "CurrentSection"
return "OtherSection"
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 view_navigation(context):
# add things for the view here
return context
register.inclusion_tag('view_navigation.html',
takes_context=True)(view_navigation)
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.
"""
## Alternative page_numbers:
page_numbers = range(max(0, context['page']-adjacent_pages),
min(context['pages'],
context['page']+adjacent_pages)+1)
results_this_page = context['object_list'].__len__()
range_base = ((context['page'] - 1) * context['results_per_page'])
# # Original
# # page_numbers = [n for n in range(context['page'] - adjacent_pages,
# # context['page'] + adjacent_pages + 1)
# # if n > 0 and n <= context['pages']]
return {
'hits': context['hits'],
'results_per_page': context['results_per_page'],
'results_this_page': results_this_page,
'first_this_page': range_base + 1,
'last_this_page': range_base + results_this_page,
'page': context['page'],
'pages': context['pages'],
'page_numbers': page_numbers,
'next': context['next'],
'previous': context['previous'],
'has_next': context['has_next'],
'has_previous': context['has_previous'],
'show_first': 1 not in page_numbers,
'show_last': context['pages'] not in page_numbers,
}
register.inclusion_tag('paginator.html',
takes_context=True)(paginator)

View File

@ -0,0 +1,125 @@
# Create your views here.
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
from django.shortcuts import get_object_or_404, render_to_response
from django.template import Context, RequestContext, escape
from django.db.models import Q
import gen
from gen.web.grampsdb.models import *
from gen.web.settings import VIEWS
def get_views():
'''
VIEWS is [("People", "person"), (plural, singular), ...]
'''
return VIEWS
def main_page(request):
context = RequestContext(request)
context["views"] = [(pair[0], pair[1],
getattr(gen.web.grampsdb.models, pair[2]).objects.count())
for pair in get_views()]
context["view"] = 'home'
context["cview"] = 'Home'
return render_to_response("main_page.html", context)
def logout_page(request):
logout(request)
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["views"] = get_views()
context["view"] = 'user'
context["cview"] = 'User'
return render_to_response('user_page.html', context)
def view_detail(request, view, handle):
cview = view.title()
context = RequestContext(request)
context["views"] = get_views()
context["cview"] = cview
context["view"] = view
context["handle"] = handle
return render_to_response('view_detail_page.html', context)
def view(request, view):
cview = view.title()
search = ""
view_template = 'view_page.html'
if view == "event":
object_list = Event.objects.all().order_by("gramps_id")
elif view == "family":
object_list = Family.objects.all().order_by("gramps_id")
view_template = 'view_family.html'
elif view == "media":
object_list = Media.objects.all().order_by("gramps_id")
elif view == "note":
object_list = Note.objects.all().order_by("gramps_id")
elif view == "person":
if request.GET.has_key("search"):
search = request.GET.get("search")
if request.user.is_authenticated():
if "," in search:
surname, first_name = [term.strip() for term in search.split(",", 1)]
object_list = Name.objects. \
select_related().filter(surname__icontains=surname,
first_name__icontains=first_name).order_by("surname", "first_name")
else:
object_list = Name.objects. \
select_related().filter(Q(surname__icontains=search) |
Q(first_name__icontains=search) |
Q(suffix__icontains=search) |
Q(prefix__icontains=search) |
Q(patronymic__icontains=search) |
Q(title__icontains=search) |
Q(person__gramps_id__icontains=search)
).order_by("surname", "first_name")
else:
# FIXME: non-authenticated users don't get to search first_names
if "," in search:
search, first_name = [term.strip() for term in search.split(",", 1)]
object_list = Name.objects. \
select_related().filter(surname__icontains=search).order_by("surname", "first_name")
else:
object_list = Name.objects.select_related().order_by("surname", "first_name")
view_template = 'view_person.html'
elif view == "place":
object_list = Place.objects.all().order_by("gramps_id")
elif view == "repository":
object_list = Repository.objects.all().order_by("gramps_id")
elif view == "source":
object_list = Source.objects.all().order_by("gramps_id")
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["views"] = get_views()
context["view"] = view
context["cview"] = cview
context["search"] = search
if search:
context["search_query"] = ("&search=%s" % escape(search))
else:
context["search_query"] = ""
return render_to_response(view_template, context)

92
src/gen/web/init.py Normal file
View File

@ -0,0 +1,92 @@
"""
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.markertype import MarkerType
from gen.lib.nametype import NameType
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
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.0\"")),
(("setting", "\"db_created\""),
("description", "\"database creation date/time\""),
("value_type", "\"str\""),
("value", ('"%s"' % time.strftime("%Y-%m-%d %H:%M")))),
])]:
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 = [MarkerType, NameType, AttributeType, UrlType, ChildRefType,
RepositoryType, EventType, FamilyRelType, SourceMediaType,
EventRoleType, NoteType, GenderType, LdsType, LdsStatus]
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 "]"

View File

@ -0,0 +1,11 @@
"""
Clears gramps data
"""
import os
os.environ["DJANGO_SETTINGS_MODULE"] = "settings"
import settings
import grampsdb.models as dj
dj.clear_tables("primary", "secondary")

1230
src/gen/web/libdjango.py Normal file

File diff suppressed because it is too large Load Diff

11
src/gen/web/manage.py Executable file
View File

@ -0,0 +1,11 @@
#!/usr/bin/env python
from django.core.management import execute_manager
try:
import settings # Assumed to be in the same directory.
except ImportError:
import sys
sys.stderr.write("Error: Can't find the file 'settings.py' in the directory containing %r. It appears you've customized things.\nYou'll have to run django-admin.py, passing it your settings module.\n(If the file settings.py does indeed exist, it's causing an ImportError somehow.)\n" % __file__)
sys.exit(1)
if __name__ == "__main__":
execute_manager(settings)

73
src/gen/web/settings.py Normal file
View File

@ -0,0 +1,73 @@
# Django settings for gramps project.
DEBUG = True
TEMPLATE_DEBUG = DEBUG
ADMINS = (
('admin', 'your_email@domain.com'),
)
MANAGERS = ADMINS
DATABASE_ENGINE = 'sqlite3'
DATABASE_NAME = '/home/dblank/gramps/trunk/src/gen/web/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.common.CommonMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
)
ROOT_URLCONF = 'gen.web.urls'
TEMPLATE_DIRS = (
# Use absolute paths, not relative paths.
"/home/dblank/gramps/trunk/src/data/templates",
)
INSTALLED_APPS = (
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.sites',
'django.contrib.admin',
'gen.web.grampsdb',
# 'django_extensions',
)
# 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()
# Views: (Nice name plural, /name/handle, Model Name)
VIEWS = [('People', 'person', 'Person'),
('Families', 'family', 'Family'),
('Events', 'event', 'Event'),
('Notes', 'note', 'Note'),
('Media', 'media', 'Media'),
('Sources', 'source', 'Source'),
('Places', 'place', 'Place'),
('Repositories', 'repository', 'Repository'),
]

232
src/gen/web/sortheaders.py Normal file
View File

@ -0,0 +1,232 @@
# Author: insin
# Site: http://www.djangosnippets.org/snippets/308/
from django.core.paginator import InvalidPage, EmptyPage
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' % '&amp;'.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 = {}
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])
if letter not in chunks:
chunks[letter] = []
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)

BIN
src/gen/web/sqlite.db Normal file

Binary file not shown.

38
src/gen/web/urls.py Normal file
View File

@ -0,0 +1,38 @@
from django.conf.urls.defaults import *
from django.contrib import admin
admin.autodiscover()
from gen.web.grampsdb.views import (main_page, user_page, logout_page,
view, view_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':
'/home/dblank/gramps/trunk/src/data',
'show_indexes':
True},
),
(r'^images/(?P<path>.*)$', 'django.views.static.serve',
{'document_root':
'/home/dblank/gramps/trunk/src/images',
'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),
(r'^(?P<view>(\w+))/(?P<handle>(\w+))/$', view_detail),
)