Document upload and metadata input working
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -5,3 +5,4 @@ site_media/photologue/photos/*
|
|||||||
site_media/photologue/photos/cache/*
|
site_media/photologue/photos/cache/*
|
||||||
*.sqlite
|
*.sqlite
|
||||||
settings_local.py
|
settings_local.py
|
||||||
|
site_media/documents/*
|
||||||
|
|||||||
0
apps/common/__init__.py
Normal file
0
apps/common/__init__.py
Normal file
32
apps/common/api.py
Normal file
32
apps/common/api.py
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
import copy
|
||||||
|
|
||||||
|
object_navigation = {}
|
||||||
|
menu_links = []
|
||||||
|
|
||||||
|
def register_links(src, links, menu_name=None):
|
||||||
|
if menu_name in object_navigation:
|
||||||
|
if hasattr(src, '__iter__'):
|
||||||
|
for one_src in src:
|
||||||
|
if one_src in object_navigation[menu_name]:
|
||||||
|
object_navigation[menu_name][one_src]['links'].extend(links)
|
||||||
|
else:
|
||||||
|
object_navigation[menu_name][one_src]={'links':copy.copy(links)}
|
||||||
|
else:
|
||||||
|
if src in object_navigation[menu_name]:
|
||||||
|
object_navigation[menu_name][src]['links'].extend(links)
|
||||||
|
else:
|
||||||
|
object_navigation[menu_name][src] = {'links':links}
|
||||||
|
else:
|
||||||
|
object_navigation[menu_name] = {}
|
||||||
|
if hasattr(src, '__iter__'):
|
||||||
|
for one_src in src:
|
||||||
|
object_navigation[menu_name][one_src] = {'links':links}
|
||||||
|
else:
|
||||||
|
object_navigation[menu_name] = {src:{'links':links}}
|
||||||
|
|
||||||
|
|
||||||
|
def register_menu(links):
|
||||||
|
for link in links:
|
||||||
|
menu_links.append(link)
|
||||||
|
|
||||||
|
menu_links.sort(lambda x,y: 1 if x>y else -1, lambda x:x['position'] if 'position' in x else 1)
|
||||||
109
apps/common/forms.py
Normal file
109
apps/common/forms.py
Normal file
@@ -0,0 +1,109 @@
|
|||||||
|
from django import forms
|
||||||
|
from django.utils.safestring import mark_safe
|
||||||
|
from django.utils.translation import ugettext as _
|
||||||
|
from django.db import models
|
||||||
|
import types
|
||||||
|
|
||||||
|
|
||||||
|
def return_attrib(obj, attrib, arguments=None):
|
||||||
|
try:
|
||||||
|
result = reduce(getattr, attrib.split("."), obj)
|
||||||
|
if isinstance(result, types.MethodType):
|
||||||
|
if arguments:
|
||||||
|
return result(**arguments)
|
||||||
|
else:
|
||||||
|
return result()
|
||||||
|
else:
|
||||||
|
return result
|
||||||
|
except Exception, err:
|
||||||
|
if settings.DEBUG:
|
||||||
|
return "Attribute error: %s; %s" % (attrib, err)
|
||||||
|
else:
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class DetailSelectMultiple(forms.widgets.SelectMultiple):
|
||||||
|
def __init__(self, queryset=None, *args, **kwargs):
|
||||||
|
self.queryset=queryset
|
||||||
|
super(DetailSelectMultiple, self).__init__(*args, **kwargs)
|
||||||
|
|
||||||
|
def render(self, name, value, attrs=None, choices=()):
|
||||||
|
if value is None: value = ''
|
||||||
|
#final_attrs = self.build_attrs(attrs, name=name)
|
||||||
|
output = u'<ul class="list">'
|
||||||
|
options = None
|
||||||
|
if value:
|
||||||
|
if getattr(value, '__iter__', None):
|
||||||
|
options = [(index, string) for index, string in self.choices if index in value]
|
||||||
|
else:
|
||||||
|
options = [(index, string) for index, string in self.choices if index == value]
|
||||||
|
else:
|
||||||
|
if self.choices:
|
||||||
|
if self.choices[0] != (u'', u'---------') and value != []:
|
||||||
|
options = [(index, string) for index, string in self.choices]
|
||||||
|
|
||||||
|
if options:
|
||||||
|
for index, string in options:
|
||||||
|
if self.queryset:
|
||||||
|
try:
|
||||||
|
output += u'<li><a href="%s">%s</a></li>' % (self.queryset.get(pk=index).get_absolute_url(), string)
|
||||||
|
except AttributeError:
|
||||||
|
output += u'<li>%s</li>' % (string)
|
||||||
|
else:
|
||||||
|
output += u'<li>%s</li>' % string
|
||||||
|
else:
|
||||||
|
output += u'<li>%s</li>' % _(u"None")
|
||||||
|
return mark_safe(output + u'</ul>\n')
|
||||||
|
|
||||||
|
|
||||||
|
class DetailForm(forms.ModelForm):
|
||||||
|
def __init__(self, extra_fields=None, *args, **kwargs):
|
||||||
|
super(DetailForm, self).__init__(*args, **kwargs)
|
||||||
|
if extra_fields:
|
||||||
|
for extra_field in extra_fields:
|
||||||
|
result = return_attrib(self.instance, extra_field['field'])
|
||||||
|
label = 'label' in extra_field and extra_field['label'] or None
|
||||||
|
#TODO: Add others result types <=> Field types
|
||||||
|
if isinstance(result, models.query.QuerySet):
|
||||||
|
self.fields[extra_field['field']]=forms.ModelMultipleChoiceField(queryset=result, label=label)
|
||||||
|
|
||||||
|
for field_name, field in self.fields.items():
|
||||||
|
if isinstance(field.widget, forms.widgets.SelectMultiple):
|
||||||
|
self.fields[field_name].widget = DetailSelectMultiple(
|
||||||
|
choices=field.widget.choices,
|
||||||
|
attrs=field.widget.attrs,
|
||||||
|
queryset=getattr(field, 'queryset', None),
|
||||||
|
)
|
||||||
|
self.fields[field_name].help_text=''
|
||||||
|
elif isinstance(field.widget, forms.widgets.Select):
|
||||||
|
self.fields[field_name].widget = DetailSelectMultiple(
|
||||||
|
choices=field.widget.choices,
|
||||||
|
attrs=field.widget.attrs,
|
||||||
|
queryset=getattr(field, 'queryset', None),
|
||||||
|
)
|
||||||
|
self.fields[field_name].help_text=''
|
||||||
|
|
||||||
|
|
||||||
|
class GenericConfirmForm(forms.Form):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class GenericAssignRemoveForm(forms.Form):
|
||||||
|
left_list = forms.ModelMultipleChoiceField(required=False, queryset=None)
|
||||||
|
right_list = forms.ModelMultipleChoiceField(required=False, queryset=None)
|
||||||
|
def __init__(self, left_list_qryset=None, right_list_qryset=None, left_filter=None, *args, **kwargs):
|
||||||
|
super(GenericAssignRemoveForm, self).__init__(*args, **kwargs)
|
||||||
|
if left_filter:
|
||||||
|
self.fields['left_list'].queryset = left_list_qryset.filter(*left_filter)
|
||||||
|
else:
|
||||||
|
self.fields['left_list'].queryset = left_list_qryset
|
||||||
|
|
||||||
|
self.fields['right_list'].queryset = right_list_qryset
|
||||||
|
|
||||||
|
|
||||||
|
class FilterForm(forms.Form):
|
||||||
|
def __init__(self, list_filters, *args, **kwargs):
|
||||||
|
super(FilterForm, self).__init__(*args, **kwargs)
|
||||||
|
for list_filter in list_filters:
|
||||||
|
label = list_filter.get('title', list_filter['name'])
|
||||||
|
self.fields[list_filter['name']] = forms.ModelChoiceField(queryset=list_filter['queryset'], label=label[0].upper() + label[1:], required=False)
|
||||||
BIN
apps/common/locale/es/LC_MESSAGES/django.mo
Normal file
BIN
apps/common/locale/es/LC_MESSAGES/django.mo
Normal file
Binary file not shown.
33
apps/common/locale/es/LC_MESSAGES/django.po
Normal file
33
apps/common/locale/es/LC_MESSAGES/django.po
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
# SOME DESCRIPTIVE TITLE.
|
||||||
|
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
|
||||||
|
# This file is distributed under the same license as the PACKAGE package.
|
||||||
|
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
|
||||||
|
#
|
||||||
|
#, fuzzy
|
||||||
|
msgid ""
|
||||||
|
msgstr ""
|
||||||
|
"Project-Id-Version: PACKAGE VERSION\n"
|
||||||
|
"Report-Msgid-Bugs-To: \n"
|
||||||
|
"POT-Creation-Date: 2011-01-28 09:33-0400\n"
|
||||||
|
"PO-Revision-Date: 2011-01-28 09:33\n"
|
||||||
|
"Last-Translator: <admin@admin.com>\n"
|
||||||
|
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||||
|
"MIME-Version: 1.0\n"
|
||||||
|
"Content-Type: text/plain; charset=UTF-8\n"
|
||||||
|
"Content-Transfer-Encoding: 8bit\n"
|
||||||
|
"Language: \n"
|
||||||
|
"X-Translated-Using: django-rosetta 0.5.6\n"
|
||||||
|
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||||
|
|
||||||
|
#: views.py:6 templates/password_change_done.html:5
|
||||||
|
msgid "Your password has been successfully changed."
|
||||||
|
msgstr "Su contraseña se ha modificado correctamente."
|
||||||
|
|
||||||
|
#: templates/login.html:5
|
||||||
|
msgid "Login"
|
||||||
|
msgstr "Iniciar sesión"
|
||||||
|
|
||||||
|
#: templates/password_change_done.html:3 templates/password_change_form.html:3
|
||||||
|
#: templates/password_change_form.html:5
|
||||||
|
msgid "Password change"
|
||||||
|
msgstr "Cambio de contraseña"
|
||||||
BIN
apps/common/locale/ru/LC_MESSAGES/django.mo
Normal file
BIN
apps/common/locale/ru/LC_MESSAGES/django.mo
Normal file
Binary file not shown.
33
apps/common/locale/ru/LC_MESSAGES/django.po
Normal file
33
apps/common/locale/ru/LC_MESSAGES/django.po
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
# SOME DESCRIPTIVE TITLE.
|
||||||
|
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
|
||||||
|
# This file is distributed under the same license as the PACKAGE package.
|
||||||
|
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
|
||||||
|
#
|
||||||
|
#, fuzzy
|
||||||
|
msgid ""
|
||||||
|
msgstr ""
|
||||||
|
"Project-Id-Version: PACKAGE VERSION\n"
|
||||||
|
"Report-Msgid-Bugs-To: \n"
|
||||||
|
"POT-Creation-Date: 2011-01-30 16:51+0300\n"
|
||||||
|
"PO-Revision-Date: 2011-01-30 13:08\n"
|
||||||
|
"Last-Translator: <garison2004@gmail.com>\n"
|
||||||
|
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||||
|
"MIME-Version: 1.0\n"
|
||||||
|
"Content-Type: text/plain; charset=UTF-8\n"
|
||||||
|
"Content-Transfer-Encoding: 8bit\n"
|
||||||
|
"Language: \n"
|
||||||
|
"X-Translated-Using: django-rosetta 0.5.5\n"
|
||||||
|
"Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n"
|
||||||
|
|
||||||
|
#: views.py:6 templates/password_change_done.html:5
|
||||||
|
msgid "Your password has been successfully changed."
|
||||||
|
msgstr "Ваш пароль был успешно изменен."
|
||||||
|
|
||||||
|
#: templates/login.html:5
|
||||||
|
msgid "Login"
|
||||||
|
msgstr "Логин"
|
||||||
|
|
||||||
|
#: templates/password_change_done.html:3 templates/password_change_form.html:3
|
||||||
|
#: templates/password_change_form.html:5
|
||||||
|
msgid "Password change"
|
||||||
|
msgstr "Сменить пароль"
|
||||||
3
apps/common/models.py
Normal file
3
apps/common/models.py
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
from django.db import models
|
||||||
|
|
||||||
|
# Create your models here.
|
||||||
9
apps/common/templates/404.html
Normal file
9
apps/common/templates/404.html
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
{% extends "base.html" %}
|
||||||
|
|
||||||
|
{% block title %}Page not found{% endblock %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
<h1>Page not found</h1>
|
||||||
|
|
||||||
|
<p>Sorry, but the requested page could not be found.</p>
|
||||||
|
{% endblock %}
|
||||||
15
apps/common/templates/500.html
Normal file
15
apps/common/templates/500.html
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN"
|
||||||
|
"http://www.w3.org/TR/html4/strict.dtd">
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<title>Page unavailable</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<h1>Page unavailable</h1>
|
||||||
|
|
||||||
|
<p>Sorry, but the requested page is unavailable due to a
|
||||||
|
server problem.</p>
|
||||||
|
|
||||||
|
<p>Administrators have been notified, so check back later.</p>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
30
apps/common/templates/calculate_form_title.html
Normal file
30
apps/common/templates/calculate_form_title.html
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
{% load i18n %}
|
||||||
|
{% if title %}
|
||||||
|
{% if striptags %}
|
||||||
|
{{ title|capfirst|striptags }}
|
||||||
|
{% else %}
|
||||||
|
{{ title|capfirst|safe }}
|
||||||
|
{% endif %}
|
||||||
|
{% else %}
|
||||||
|
{% if read_only %}
|
||||||
|
{% if object_name %}
|
||||||
|
{% blocktrans %}Details for {{ object_name }}: {{ object }}{% endblocktrans %}
|
||||||
|
{% else %}
|
||||||
|
{% blocktrans %}Details for: {{ object }}{% endblocktrans %}
|
||||||
|
{% endif %}
|
||||||
|
{% else %}
|
||||||
|
{% if object %}
|
||||||
|
{% if object_name %}
|
||||||
|
{% blocktrans %}Edit {{ object_name }}:{% endblocktrans %} {% if not striptags %}<a href="{{ object.get_absolute_url }}">{% endif %}{{ object|capfirst }}{% if not striptags %}</a>{% endif %}
|
||||||
|
{% else %}
|
||||||
|
{% trans "Edit" %}: {% if not striptags %}<a href="{{ object.get_absolute_url }}">{% endif %}{{ object|capfirst }}{% if not striptags %}</a>{% endif %}
|
||||||
|
{% endif %}
|
||||||
|
{% else %}
|
||||||
|
{% if object_name %}
|
||||||
|
{% blocktrans %}Create new {{ object_name }}{% endblocktrans %}
|
||||||
|
{% else %}
|
||||||
|
{% trans "Create" %}
|
||||||
|
{% endif %}
|
||||||
|
{% endif %}
|
||||||
|
{% endif %}
|
||||||
|
{% endif %}
|
||||||
43
apps/common/templates/generic_assign_remove.html
Normal file
43
apps/common/templates/generic_assign_remove.html
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
{% extends "base.html" %}
|
||||||
|
{% load i18n %}
|
||||||
|
{% block title %} :: {% blocktrans %}Assign {{ title }} {{ object }}{% endblocktrans %}{% endblock %}
|
||||||
|
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
<style>
|
||||||
|
#id_right_list,#id_left_list { min-width: 28em; min-height: 13em; }
|
||||||
|
</style>
|
||||||
|
<div class="content">
|
||||||
|
<h2 class="title">{{ title|safe }}</h2>
|
||||||
|
|
||||||
|
<form method='POST' action='' id='assign_remove'>{% csrf_token %}
|
||||||
|
<input name='action' value='' type='hidden' />
|
||||||
|
<table>
|
||||||
|
<tbody>
|
||||||
|
<tr>
|
||||||
|
<th style='text-align:center;'>{{ left_list_title }}</th><td></td><th style='text-align:center;'>{{ right_list_title }}</th>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
{{ form.left_list }}{{ form.left_list.errors }}
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<table>
|
||||||
|
<tbody>
|
||||||
|
<tr>
|
||||||
|
<td><button class="button" onclick='document.forms["assign_remove"].action.value="assign";document.forms["assign_remove"].submit();'>></button></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><button class="button" onclick='document.forms["assign_remove"].action.value="remove";document.forms["assign_remove"].submit();'><</button></td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</td>
|
||||||
|
<td>{{ form.right_list }}{{ form.right_list.errors }}</td>
|
||||||
|
</tr>
|
||||||
|
{{ form.media|safe }}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
||||||
51
apps/common/templates/generic_confirm.html
Executable file
51
apps/common/templates/generic_confirm.html
Executable file
@@ -0,0 +1,51 @@
|
|||||||
|
{% extends 'base.html' %}
|
||||||
|
{% load i18n %}
|
||||||
|
{% block title %} :: {% trans 'Confirm' %} {{ title }}{% endblock %}
|
||||||
|
|
||||||
|
{% block sidebar %}
|
||||||
|
{% for subtemplate in subtemplates %}
|
||||||
|
{% include subtemplate %}
|
||||||
|
{% endfor %}
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
<div id="box">
|
||||||
|
<div class="block" id="block-login">
|
||||||
|
{% if delete_view %}
|
||||||
|
<h2>{% trans 'Confirm delete' %}</h2>
|
||||||
|
{% else %}
|
||||||
|
<h2>{% trans 'Confirm' %}</h2>
|
||||||
|
{% endif %}
|
||||||
|
<div class="content login">
|
||||||
|
<form action="" method="post" class="form login">{% csrf_token %}
|
||||||
|
{% if next %}
|
||||||
|
<input name='next' type='hidden' value='{{ next }}' />
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% if delete_view %}
|
||||||
|
{% if object_name %}
|
||||||
|
<h3>{% blocktrans %}Are you sure you wish to delete {{ object_name }}: {{ object }}?{% endblocktrans %}</h3>
|
||||||
|
{% else %}
|
||||||
|
<h3>{% blocktrans %}Are you sure you wish to delete: {{ object }}?{% endblocktrans %}</h3>
|
||||||
|
{% endif %}
|
||||||
|
{% else %}
|
||||||
|
<h3>{{ title }}</h3>
|
||||||
|
{% endif %}
|
||||||
|
<h4>{{ message }}</h4>
|
||||||
|
|
||||||
|
<div class="group navform wat-cf">
|
||||||
|
<button class="button" type="submit">
|
||||||
|
<img src="{{ MEDIA_URL }}web_theme_media/images/icons/tick.png" alt="{% trans 'Yes' %}" /> {% trans 'Yes' %}
|
||||||
|
</button>
|
||||||
|
{# TODO: Fix back button #}
|
||||||
|
{% comment %}
|
||||||
|
<a href="#header" onclick='{% if previous %}window.location.replace("{{ previous }}");{% else %}history.go(-1);{% endif %}' class="button">
|
||||||
|
<img src="{{ MEDIA_URL }}web_theme_media/images/icons/cross.png" alt="{% trans 'No' %}"/> {% trans 'No' %}
|
||||||
|
</a>
|
||||||
|
{% endcomment %}
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
||||||
64
apps/common/templates/generic_detail.html
Executable file
64
apps/common/templates/generic_detail.html
Executable file
@@ -0,0 +1,64 @@
|
|||||||
|
{% extends "base.html" %}
|
||||||
|
{% load i18n %}
|
||||||
|
{% load styling %}
|
||||||
|
{% load generic_views_helpers %}
|
||||||
|
{% block title %} :: {% with "true" as read_only %}{% with "true" as striptags %}{% include "calculate_form_title.html" %}{% endwith %}{% endwith %}{% endblock %}
|
||||||
|
|
||||||
|
{% block javascript %}
|
||||||
|
<script type="text/javascript">
|
||||||
|
$(function() {
|
||||||
|
$("#subform form :input").each(function() {
|
||||||
|
this.disabled = true;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block sidebar %}
|
||||||
|
{% for subtemplate in sidebar_subtemplates %}
|
||||||
|
{% include subtemplate %}
|
||||||
|
{% endfor %}
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block stylesheets %}
|
||||||
|
<style type="text/css">
|
||||||
|
#subform form textarea,
|
||||||
|
#subform form select option,
|
||||||
|
#subform form input,
|
||||||
|
#subform form select,
|
||||||
|
#subform form input { background: none; color: black; border: none; }
|
||||||
|
</style>
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
<div id="subform">
|
||||||
|
{% with "true" as read_only %}
|
||||||
|
{% include "generic_form_subtemplate.html" %}
|
||||||
|
{% endwith %}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{% for subtemplate in subtemplates %}
|
||||||
|
<div class="content">
|
||||||
|
{% include subtemplate %}
|
||||||
|
</div>
|
||||||
|
{% endfor %}
|
||||||
|
|
||||||
|
{% for subtemplate in subtemplates_dict %}
|
||||||
|
{% with subtemplate.title as title %}
|
||||||
|
{% with subtemplate.object_list as object_list %}
|
||||||
|
{% with subtemplate.extra_columns as extra_columns %}
|
||||||
|
{% with subtemplate.hide_object as hide_object %}
|
||||||
|
{% with subtemplate.main_object as main_object %}
|
||||||
|
<div class="content">
|
||||||
|
{% include subtemplate.name %}
|
||||||
|
</div>
|
||||||
|
{% endwith %}
|
||||||
|
{% endwith %}
|
||||||
|
{% endwith %}
|
||||||
|
{% endwith %}
|
||||||
|
{% endwith %}
|
||||||
|
{% endfor %}
|
||||||
|
|
||||||
|
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
6
apps/common/templates/generic_form.html
Executable file
6
apps/common/templates/generic_form.html
Executable file
@@ -0,0 +1,6 @@
|
|||||||
|
{% extends "base.html" %}
|
||||||
|
{% block title %} :: {% with "true" as striptags %}{% include "calculate_form_title.html" %}{% endwith %}{% endblock %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
{% include "generic_form_subtemplate.html" %}
|
||||||
|
{% endblock %}
|
||||||
39
apps/common/templates/generic_form_instance.html
Normal file
39
apps/common/templates/generic_form_instance.html
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
{% load i18n %}
|
||||||
|
{% load styling %}
|
||||||
|
{{ form.media|safe }}
|
||||||
|
{% add_classes_to_form form %}
|
||||||
|
|
||||||
|
{% if form.non_field_errors %}
|
||||||
|
<div class="flash">
|
||||||
|
{% for value in form.non_field_errors %}
|
||||||
|
<div class="message error">
|
||||||
|
<p>{{ value }}</p>
|
||||||
|
</div>
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% if form_display_mode_table %}
|
||||||
|
{% for field in form.hidden_fields %}
|
||||||
|
{{ field }}
|
||||||
|
{% endfor %}
|
||||||
|
<tr class="{% cycle 'odd' 'even2' %}">
|
||||||
|
{% for field in form.visible_fields %}
|
||||||
|
<td title="{% if field.errors %}{% for error in field.errors %}{{ error }}{% if not forloop.last %} | {% endif %}{% endfor %}{% else %}{{ field.help_text }}{% endif %}">
|
||||||
|
{% if field.errors %}<div class="flash"><div class="error">{% endif %}
|
||||||
|
{{ field }}
|
||||||
|
{% if field.errors %}</div></div>{% endif %}
|
||||||
|
</td>
|
||||||
|
{% endfor %}
|
||||||
|
</tr>
|
||||||
|
{% else %}
|
||||||
|
{% for field in form %}
|
||||||
|
<div class="group">
|
||||||
|
{% if field.errors %}<div class="fieldWithErrors">{% endif %}
|
||||||
|
<label class="label">{{ field.label_tag }}{% if field.field.required and not read_only %} ({% trans 'required' %}){% endif %}</label>
|
||||||
|
{% if field.errors %}<span class="error">{% for error in field.errors %}{{ error }}{% if not forloop.last %} | {% endif %}{% endfor %}</span></div>{% endif %}
|
||||||
|
{{ field }}
|
||||||
|
{% if field.help_text %}<span class="description">{{ field.help_text }}</span>{% endif %}
|
||||||
|
</div>
|
||||||
|
{% endfor %}
|
||||||
|
{% endif %}
|
||||||
87
apps/common/templates/generic_form_subtemplate.html
Executable file
87
apps/common/templates/generic_form_subtemplate.html
Executable file
@@ -0,0 +1,87 @@
|
|||||||
|
{% load i18n %}
|
||||||
|
|
||||||
|
{% if side_bar %}
|
||||||
|
<div class="block">
|
||||||
|
<h3>
|
||||||
|
{% else %}
|
||||||
|
<div class="content">
|
||||||
|
<h2 class="title">
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% include "calculate_form_title.html" %}
|
||||||
|
|
||||||
|
{% if side_bar %}
|
||||||
|
</h3>
|
||||||
|
<div class="content">
|
||||||
|
<p>
|
||||||
|
{% else %}
|
||||||
|
</h2>
|
||||||
|
<div class="inner">
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% if form.is_multipart %}
|
||||||
|
<form enctype="multipart/form-data" method="{{ submit_method|default:'post' }}" action="" class="form">
|
||||||
|
{% else %}
|
||||||
|
<form method="{{ submit_method|default:'post' }}" action="" class="form">
|
||||||
|
{% endif %}
|
||||||
|
{% if step_field %}
|
||||||
|
<input type="hidden" name="{{ step_field }}" value="{{ step0 }}" />
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% if submit_method != 'GET' and submit_method != 'get' %}
|
||||||
|
{% csrf_token %}
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% for hidden_field in hidden_fields %}
|
||||||
|
{{ hidden_field.as_hidden }}
|
||||||
|
{% endfor %}
|
||||||
|
|
||||||
|
{% if form.management_form %}
|
||||||
|
{% with form as formset %}
|
||||||
|
{{ formset.management_form }}
|
||||||
|
|
||||||
|
{% if form_display_mode_table %}
|
||||||
|
<table class="table">
|
||||||
|
<tbody>
|
||||||
|
<tr>
|
||||||
|
{% for field in formset.forms.0.visible_fields %}
|
||||||
|
<th>
|
||||||
|
{{ field.label_tag }}{% if field.field.required and not read_only %} ({% trans 'required' %}){% endif %}
|
||||||
|
</th>
|
||||||
|
{#{% if field.help_text %}<span class="description">{{ field.help_text }}</span>{% endif %}#}
|
||||||
|
{% endfor %}
|
||||||
|
</tr>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% for form in formset.forms %}
|
||||||
|
{% include "generic_form_instance.html" %}
|
||||||
|
{% endfor %}
|
||||||
|
{% if form_display_mode_table %}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
{% endif %}
|
||||||
|
{% endwith %}
|
||||||
|
{% else %}
|
||||||
|
{% include "generic_form_instance.html" %}
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% if not read_only %}
|
||||||
|
<div class="group navform wat-cf">
|
||||||
|
<button class="button" type="submit">
|
||||||
|
<img src="{{ MEDIA_URL }}web_theme_media/images/icons/tick.png" alt="{% if object %}{% trans 'Save' %}{% else %}{% trans 'Submit' %}{% endif %}" /> {% if object %}{% trans 'Save' %}{% else %}{% trans 'Submit' %}{% endif %}
|
||||||
|
</button>
|
||||||
|
{% comment %}
|
||||||
|
<a href="#header" class="button">
|
||||||
|
<img src="{{ MEDIA_URL }}web_theme_media/images/icons/cross.png" alt="{% trans 'Cancel' %}"/> {% trans 'Cancel' %}
|
||||||
|
</a>
|
||||||
|
{% endcomment %}
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
</form>
|
||||||
|
{% if sidebar %}
|
||||||
|
</p></div></div>
|
||||||
|
{% else %}
|
||||||
|
</div></div>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
|
||||||
8
apps/common/templates/generic_list.html
Executable file
8
apps/common/templates/generic_list.html
Executable file
@@ -0,0 +1,8 @@
|
|||||||
|
{% extends "base.html" %}
|
||||||
|
{% load i18n %}
|
||||||
|
{% block title %} :: {% blocktrans %}List of {{ title }}{% endblocktrans %}{% endblock %}
|
||||||
|
{#{% block secondary_links %}{{ secondary_links|safe }}{% endblock %}#}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
{% include 'generic_list_subtemplate.html' %}
|
||||||
|
{% endblock %}
|
||||||
71
apps/common/templates/generic_list_subtemplate.html
Normal file
71
apps/common/templates/generic_list_subtemplate.html
Normal file
@@ -0,0 +1,71 @@
|
|||||||
|
{% load i18n %}
|
||||||
|
{% load attribute_tags %}
|
||||||
|
{% load pagination_tags %}
|
||||||
|
{% load navigation %}
|
||||||
|
|
||||||
|
{% if side_bar %}
|
||||||
|
<div class="block">
|
||||||
|
<h3>
|
||||||
|
{{ title }}
|
||||||
|
</h3>
|
||||||
|
<div class="content">
|
||||||
|
<p>
|
||||||
|
{% else %}
|
||||||
|
{% autopaginate object_list %}
|
||||||
|
<div class="content">
|
||||||
|
<h2 class="title">
|
||||||
|
{% ifnotequal page_obj.paginator.num_pages 1 %}
|
||||||
|
{% blocktrans with page_obj.start_index as start and page_obj.end_index as end and page_obj.paginator.object_list|length as total %}List of {{ title }} ({{ start }} - {{ end }} out of {{ total }}){% endblocktrans %}
|
||||||
|
{% else %}
|
||||||
|
{% blocktrans with page_obj.paginator.object_list|length as total %}List of {{ title }} ({{ total }}){% endblocktrans %}
|
||||||
|
{% endifnotequal %}
|
||||||
|
</h2>
|
||||||
|
|
||||||
|
<div class="inner">
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
<form action="#" class="form">
|
||||||
|
<table class="table">
|
||||||
|
<tbody>
|
||||||
|
{% if not hide_header %}
|
||||||
|
<tr>
|
||||||
|
{% if not hide_object %}
|
||||||
|
<th>{% trans 'Identifier' %}</th>
|
||||||
|
{% endif %}
|
||||||
|
{% for column in extra_columns %}
|
||||||
|
<th>{{ column.name|capfirst }}</th>
|
||||||
|
{% endfor %}
|
||||||
|
{% if not hide_links %}
|
||||||
|
<th class=""> </th>
|
||||||
|
{% endif %}
|
||||||
|
</tr>
|
||||||
|
{% endif %}
|
||||||
|
{% for object in object_list %}
|
||||||
|
<tr class="{% cycle 'odd' 'even2' %}">
|
||||||
|
{% if not hide_object %}
|
||||||
|
{% if main_object %}
|
||||||
|
{% with object|object_property:main_object as object %}
|
||||||
|
<td>{% if not hide_link %}<a href="{{ object.get_absolute_url }}">{{ object }}</a>{% else %}{{ object }}{% endif %}</td>
|
||||||
|
{% endwith %}
|
||||||
|
{% else %}
|
||||||
|
<td>{% if not hide_link %}<a href="{{ object.get_absolute_url }}">{{ object }}</a>{% else %}{{ object }}{% endif %}</td>
|
||||||
|
{% endif %}
|
||||||
|
{% endif %}
|
||||||
|
{% for column in extra_columns %}
|
||||||
|
<td>{{ object|object_property:column.attribute|safe }}</td>
|
||||||
|
{% endfor %}
|
||||||
|
{% if not hide_links %}
|
||||||
|
<td class='last'>
|
||||||
|
{% object_navigation_template %}
|
||||||
|
</td>
|
||||||
|
{% endif %}
|
||||||
|
</tr>
|
||||||
|
{% empty %}
|
||||||
|
<tr><td colspan=99 class="tc">{% blocktrans %}There are no {{ title }}{% endblocktrans %}</td></tr>
|
||||||
|
{% endfor %}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
{% paginate %}
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
7
apps/common/templates/generic_navigation.html
Executable file
7
apps/common/templates/generic_navigation.html
Executable file
@@ -0,0 +1,7 @@
|
|||||||
|
{% load i18n %}
|
||||||
|
|
||||||
|
{% for link in object_navigation_links %}
|
||||||
|
{% if as_li %}<li>{% endif %}
|
||||||
|
<a href="{{ link.url }}">{% if link.famfam %}<span class="famfam active famfam-{{ link.famfam|default:'link' }}"></span>{% endif %}{{ link.text|capfirst }}{% if link.error %} - {{ link.error }}{% endif %}{% if link.active %}<span class="famfam active famfam-resultset_previous"></span>{% endif %}</a>{% if horizontal %}{% if not forloop.last %} | {% endif %}{% endif %}
|
||||||
|
{% if as_li %}</li>{% endif %}
|
||||||
|
{% endfor %}
|
||||||
17
apps/common/templates/generic_wizard.html
Normal file
17
apps/common/templates/generic_wizard.html
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
{% extends "base.html" %}
|
||||||
|
{% load i18n %}
|
||||||
|
{% load styling %}
|
||||||
|
{% add_classes_to_form form %}
|
||||||
|
{% block content %}
|
||||||
|
{% with step_title as title %}
|
||||||
|
{% with previous_fields as hidden_fields %}
|
||||||
|
{% if form.management_form %}
|
||||||
|
{% with "true" as form_display_mode_table %}
|
||||||
|
{% include "generic_form_subtemplate.html" %}
|
||||||
|
{% endwith %}
|
||||||
|
{% else %}
|
||||||
|
{% include "generic_form_subtemplate.html" %}
|
||||||
|
{% endif %}
|
||||||
|
{% endwith %}
|
||||||
|
{% endwith %}
|
||||||
|
{% endblock %}
|
||||||
6
apps/common/templates/login.html
Executable file
6
apps/common/templates/login.html
Executable file
@@ -0,0 +1,6 @@
|
|||||||
|
{% extends "web_theme_login.html" %}
|
||||||
|
{% load i18n %}
|
||||||
|
{% load project_tags %}
|
||||||
|
|
||||||
|
{% block html_title %}{% project_name %} :: {% trans "Login" %}{% endblock %}
|
||||||
|
{% block project_name %}{% project_name %}{% endblock %}
|
||||||
6
apps/common/templates/password_change_done.html
Executable file
6
apps/common/templates/password_change_done.html
Executable file
@@ -0,0 +1,6 @@
|
|||||||
|
{% extends "base.html" %}
|
||||||
|
{% load i18n %}
|
||||||
|
{% block title %} :: {% trans "Password change" %}{% endblock %}
|
||||||
|
{% block content %}
|
||||||
|
<h2>{% trans "Your password has been successfully changed." %}</h2>
|
||||||
|
{% endblock %}
|
||||||
11
apps/common/templates/password_change_form.html
Executable file
11
apps/common/templates/password_change_form.html
Executable file
@@ -0,0 +1,11 @@
|
|||||||
|
{% extends "generic_form.html" %}
|
||||||
|
{% load i18n %}
|
||||||
|
{% block title %} :: {% trans "Password change" %}{% endblock %}
|
||||||
|
|
||||||
|
{% block form_title %}{% trans "Password change" %}{% endblock %}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
0
apps/common/templatetags/__init__.py
Normal file
0
apps/common/templatetags/__init__.py
Normal file
34
apps/common/templatetags/attribute_tags.py
Normal file
34
apps/common/templatetags/attribute_tags.py
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
import types
|
||||||
|
|
||||||
|
from django.core.urlresolvers import reverse
|
||||||
|
from django.conf import settings
|
||||||
|
from django.template.defaultfilters import stringfilter
|
||||||
|
from django.template import Library, Node, Variable, VariableDoesNotExist
|
||||||
|
|
||||||
|
|
||||||
|
register = Library()
|
||||||
|
|
||||||
|
def return_attrib(obj, attrib, arguments={}):
|
||||||
|
try:
|
||||||
|
if isinstance(obj, types.DictType) or isinstance(obj, types.DictionaryType):
|
||||||
|
return obj[attrib]
|
||||||
|
elif isinstance(attrib, types.FunctionType):
|
||||||
|
return attrib(obj)
|
||||||
|
else:
|
||||||
|
result = reduce(getattr, attrib.split("."), obj)
|
||||||
|
if isinstance(result, types.MethodType):
|
||||||
|
if arguments:
|
||||||
|
return result(**arguments)
|
||||||
|
else:
|
||||||
|
return result()
|
||||||
|
else:
|
||||||
|
return result
|
||||||
|
except Exception, err:
|
||||||
|
if settings.DEBUG:
|
||||||
|
return "Error: %s; %s" % (attrib, err)
|
||||||
|
else:
|
||||||
|
pass
|
||||||
|
|
||||||
|
@register.filter
|
||||||
|
def object_property(value, arg):
|
||||||
|
return return_attrib(value, arg)
|
||||||
228
apps/common/templatetags/navigation.py
Normal file
228
apps/common/templatetags/navigation.py
Normal file
@@ -0,0 +1,228 @@
|
|||||||
|
import types
|
||||||
|
|
||||||
|
from django.conf import settings
|
||||||
|
from django.core.urlresolvers import reverse, NoReverseMatch
|
||||||
|
from django.core.urlresolvers import RegexURLResolver, RegexURLPattern, Resolver404, get_resolver
|
||||||
|
from django.template import TemplateSyntaxError, Library, \
|
||||||
|
VariableDoesNotExist, Node, Variable
|
||||||
|
from django.utils.text import unescape_string_literal
|
||||||
|
|
||||||
|
from common.api import object_navigation, menu_links as menu_navigation
|
||||||
|
|
||||||
|
register = Library()
|
||||||
|
|
||||||
|
|
||||||
|
def process_links(links, view_name, url):
|
||||||
|
items = []
|
||||||
|
active_item = None
|
||||||
|
for item, count in zip(links, range(len(links))):
|
||||||
|
item_view = 'view' in item and item['view']
|
||||||
|
item_url = 'url' in item and item['url']
|
||||||
|
if view_name == item_view or url == item_url:
|
||||||
|
active = True
|
||||||
|
active_item = item
|
||||||
|
else:
|
||||||
|
active = False
|
||||||
|
if 'links' in item:
|
||||||
|
for child_link in item['links']:
|
||||||
|
child_view = 'view' in child_link and child_link['view']
|
||||||
|
child_url = 'url' in child_link and child_link['url']
|
||||||
|
if view_name == child_view or url == child_url:
|
||||||
|
active = True
|
||||||
|
active_item = item
|
||||||
|
|
||||||
|
items.append(
|
||||||
|
{
|
||||||
|
'first':count==0,
|
||||||
|
'active':active,
|
||||||
|
'url':item_view and reverse(item_view) or item_url or '#',
|
||||||
|
'text':unicode(item['text']),
|
||||||
|
'famfam':'famfam' in item and item['famfam'],
|
||||||
|
}
|
||||||
|
)
|
||||||
|
return items, active_item
|
||||||
|
|
||||||
|
|
||||||
|
class NavigationNode(Node):
|
||||||
|
def __init__(self, navigation, *args, **kwargs):
|
||||||
|
self.navigation = navigation
|
||||||
|
|
||||||
|
def render(self, context):
|
||||||
|
request = Variable('request').resolve(context)
|
||||||
|
view_name = resolve_to_name(request.META['PATH_INFO'])
|
||||||
|
|
||||||
|
main_items, active_item = process_links(links=self.navigation, view_name=view_name, url=request.META['PATH_INFO'])
|
||||||
|
context['navigation_main_links'] = main_items
|
||||||
|
if active_item and 'links' in active_item:
|
||||||
|
secondary_links, active_item = process_links(links=active_item['links'], view_name=view_name, url=request.META['PATH_INFO'])
|
||||||
|
context['navigation_secondary_links'] = secondary_links
|
||||||
|
return ''
|
||||||
|
|
||||||
|
|
||||||
|
@register.tag
|
||||||
|
def main_navigation(parser, token):
|
||||||
|
args = token.split_contents()
|
||||||
|
|
||||||
|
# if len(args) != 3 or args[1] != 'as':
|
||||||
|
# raise TemplateSyntaxError("'get_all_states' requires 'as variable' (got %r)" % args)
|
||||||
|
|
||||||
|
#return NavigationNode(variable=args[2], navigation=navigation)
|
||||||
|
return NavigationNode(navigation=menu_navigation)
|
||||||
|
|
||||||
|
|
||||||
|
#http://www.djangosnippets.org/snippets/1378/
|
||||||
|
__all__ = ('resolve_to_name',)
|
||||||
|
|
||||||
|
def _pattern_resolve_to_name(self, path):
|
||||||
|
match = self.regex.search(path)
|
||||||
|
if match:
|
||||||
|
name = ""
|
||||||
|
if self.name:
|
||||||
|
name = self.name
|
||||||
|
elif hasattr(self, '_callback_str'):
|
||||||
|
name = self._callback_str
|
||||||
|
else:
|
||||||
|
name = "%s.%s" % (self.callback.__module__, self.callback.func_name)
|
||||||
|
return name
|
||||||
|
|
||||||
|
def _resolver_resolve_to_name(self, path):
|
||||||
|
tried = []
|
||||||
|
match = self.regex.search(path)
|
||||||
|
if match:
|
||||||
|
new_path = path[match.end():]
|
||||||
|
for pattern in self.url_patterns:
|
||||||
|
try:
|
||||||
|
name = pattern.resolve_to_name(new_path)
|
||||||
|
except Resolver404, e:
|
||||||
|
tried.extend([(pattern.regex.pattern + ' ' + t) for t in e.args[0]['tried']])
|
||||||
|
else:
|
||||||
|
if name:
|
||||||
|
return name
|
||||||
|
tried.append(pattern.regex.pattern)
|
||||||
|
raise Resolver404, {'tried': tried, 'path': new_path}
|
||||||
|
|
||||||
|
|
||||||
|
# here goes monkeypatching
|
||||||
|
RegexURLPattern.resolve_to_name = _pattern_resolve_to_name
|
||||||
|
RegexURLResolver.resolve_to_name = _resolver_resolve_to_name
|
||||||
|
|
||||||
|
def resolve_to_name(path, urlconf=None):
|
||||||
|
return get_resolver(urlconf).resolve_to_name(path)
|
||||||
|
|
||||||
|
@register.filter
|
||||||
|
def resolve_url_name(value):
|
||||||
|
return resolve_to_name(value)
|
||||||
|
|
||||||
|
def resolve_arguments(context, src_args):
|
||||||
|
args = []
|
||||||
|
kwargs = {}
|
||||||
|
if type(src_args) == type([]):
|
||||||
|
for i in src_args:
|
||||||
|
val = resolve_template_variable(context, i)
|
||||||
|
if val:
|
||||||
|
args.append(val)
|
||||||
|
elif type(src_args) == type({}):
|
||||||
|
for key, value in src_args.items():
|
||||||
|
val = resolve_template_variable(context, value)
|
||||||
|
if val:
|
||||||
|
kwargs[key] = val
|
||||||
|
else:
|
||||||
|
val = resolve_template_variable(context, src_args)
|
||||||
|
if val:
|
||||||
|
args.append(val)
|
||||||
|
|
||||||
|
return args, kwargs
|
||||||
|
|
||||||
|
|
||||||
|
def resolve_links(context, links, current_view, current_path):
|
||||||
|
context_links = []
|
||||||
|
for link in links:
|
||||||
|
args, kwargs = resolve_arguments(context, link.get('args', {}))
|
||||||
|
|
||||||
|
if 'view' in link:
|
||||||
|
link['active'] = link['view'] == current_view
|
||||||
|
args, kwargs = resolve_arguments(context, link.get('args', {}))
|
||||||
|
|
||||||
|
try:
|
||||||
|
if kwargs:
|
||||||
|
link['url'] = reverse(link['view'], kwargs=kwargs)
|
||||||
|
else:
|
||||||
|
link['url'] = reverse(link['view'], args=args)
|
||||||
|
except NoReverseMatch, err:
|
||||||
|
link['url'] = '#'
|
||||||
|
link['error'] = err
|
||||||
|
elif 'url' in link:
|
||||||
|
link['active'] = link['url'] == current_path
|
||||||
|
else:
|
||||||
|
link['active'] = False
|
||||||
|
context_links.append(link)
|
||||||
|
|
||||||
|
return context_links
|
||||||
|
|
||||||
|
def _get_object_navigation_links(context, menu_name=None):
|
||||||
|
current_path = Variable('request').resolve(context).META['PATH_INFO']
|
||||||
|
current_view = resolve_to_name(current_path)#.get_full_path())
|
||||||
|
context_links = []
|
||||||
|
|
||||||
|
try:
|
||||||
|
object_name = Variable('navigation_object_name').resolve(context)
|
||||||
|
except VariableDoesNotExist:
|
||||||
|
object_name = 'object'
|
||||||
|
|
||||||
|
try:
|
||||||
|
obj = Variable(object_name).resolve(context)
|
||||||
|
except VariableDoesNotExist:
|
||||||
|
obj = None
|
||||||
|
|
||||||
|
try:
|
||||||
|
links = object_navigation[menu_name][current_view]['links']
|
||||||
|
for link in resolve_links(context, links, current_view, current_path):
|
||||||
|
context_links.append(link)
|
||||||
|
except KeyError:
|
||||||
|
pass
|
||||||
|
|
||||||
|
try:
|
||||||
|
links = object_navigation[menu_name][type(obj)]['links']
|
||||||
|
for link in resolve_links(context, links, current_view, current_path):
|
||||||
|
context_links.append(link)
|
||||||
|
except KeyError:
|
||||||
|
pass
|
||||||
|
|
||||||
|
return context_links
|
||||||
|
|
||||||
|
|
||||||
|
def resolve_template_variable(context, name):
|
||||||
|
try:
|
||||||
|
return unescape_string_literal(name)
|
||||||
|
except ValueError:
|
||||||
|
return Variable(name).resolve(context)
|
||||||
|
except TypeError:
|
||||||
|
return name
|
||||||
|
|
||||||
|
|
||||||
|
class GetNavigationLinks(Node):
|
||||||
|
def __init__(self, *args):
|
||||||
|
self.menu_name = None
|
||||||
|
if args:
|
||||||
|
self.menu_name = args[0]
|
||||||
|
|
||||||
|
def render(self, context):
|
||||||
|
menu_name = resolve_template_variable(context, self.menu_name)
|
||||||
|
context['object_navigation_links'] = _get_object_navigation_links(context, menu_name)
|
||||||
|
return ''
|
||||||
|
|
||||||
|
|
||||||
|
@register.tag
|
||||||
|
def get_object_navigation_links(parser, token):
|
||||||
|
args = token.split_contents()
|
||||||
|
return GetNavigationLinks(*args[1:])
|
||||||
|
|
||||||
|
|
||||||
|
def object_navigation_template(context):
|
||||||
|
return {
|
||||||
|
'horizontal':True,
|
||||||
|
'object_navigation_links':_get_object_navigation_links(context)
|
||||||
|
}
|
||||||
|
return new_context
|
||||||
|
register.inclusion_tag('generic_navigation.html', takes_context=True)(object_navigation_template)
|
||||||
|
|
||||||
8
apps/common/templatetags/project_tags.py
Normal file
8
apps/common/templatetags/project_tags.py
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
from django.template import TemplateSyntaxError, Library, VariableDoesNotExist
|
||||||
|
from django.conf import settings
|
||||||
|
|
||||||
|
register = Library()
|
||||||
|
|
||||||
|
@register.simple_tag
|
||||||
|
def project_name():
|
||||||
|
return settings.PROJECT_TITLE
|
||||||
23
apps/common/tests.py
Normal file
23
apps/common/tests.py
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
"""
|
||||||
|
This file demonstrates two different styles of tests (one doctest and one
|
||||||
|
unittest). These will both pass when you run "manage.py test".
|
||||||
|
|
||||||
|
Replace these with more appropriate tests for your application.
|
||||||
|
"""
|
||||||
|
|
||||||
|
from django.test import TestCase
|
||||||
|
|
||||||
|
class SimpleTest(TestCase):
|
||||||
|
def test_basic_addition(self):
|
||||||
|
"""
|
||||||
|
Tests that 1 + 1 always equals 2.
|
||||||
|
"""
|
||||||
|
self.failUnlessEqual(1 + 1, 2)
|
||||||
|
|
||||||
|
__test__ = {"doctest": """
|
||||||
|
Another way to test that 1 + 1 is equal to 2.
|
||||||
|
|
||||||
|
>>> 1 + 1 == 2
|
||||||
|
True
|
||||||
|
"""}
|
||||||
|
|
||||||
25
apps/common/urls.py
Normal file
25
apps/common/urls.py
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
from django.conf.urls.defaults import *
|
||||||
|
from django.views.generic.simple import direct_to_template
|
||||||
|
|
||||||
|
|
||||||
|
urlpatterns = patterns('common.views',
|
||||||
|
url(r'^about/$', direct_to_template, { 'template' : 'about.html'}, 'about'),
|
||||||
|
url(r'^password/change/done/$', 'password_change_done', (), name='password_change_done'),
|
||||||
|
)
|
||||||
|
|
||||||
|
urlpatterns += patterns('',
|
||||||
|
url(r'^login/$', 'django.contrib.auth.views.login', {'template_name': 'login.html'}, name='login_view'),
|
||||||
|
url(r'^logout/$', 'django.contrib.auth.views.logout', {'next_page' : '/'}, name='logout_view' ),
|
||||||
|
|
||||||
|
url(r'^password/change/$', 'django.contrib.auth.views.password_change', {'template_name': 'password_change_form.html', 'post_change_redirect': '/password/change/done/'}, name='password_change_view'),
|
||||||
|
#url(r'^password/change/done/$', 'django.contrib.auth.views.password_change_done', {'template_name': 'password_change_done.html'}),
|
||||||
|
|
||||||
|
url(r'^password/reset/$', 'django.contrib.auth.views.password_reset', {'email_template_name' : 'password_reset_email.html', 'template_name': 'password_reset_form.html', 'post_reset_redirect' : '/password/reset/done'}, name='password_reset_view'),
|
||||||
|
url(r'^password/reset/confirm/(?P<uidb36>[0-9A-Za-z]+)-(?P<token>.+)/$', 'django.contrib.auth.views.password_reset_confirm', { 'template_name' : 'password_reset_confirm.html', 'post_reset_redirect' : '/password/reset/complete/'}, name='password_reset_confirm_view'),
|
||||||
|
url(r'^password/reset/complete/$', 'django.contrib.auth.views.password_reset_complete', { 'template_name' : 'password_reset_complete.html' }, name='password_reset_complete_view'),
|
||||||
|
url(r'^password/reset/done/$', 'django.contrib.auth.views.password_reset_done', { 'template_name' : 'password_reset_done.html'}, name='password_reset_done_view'),
|
||||||
|
)
|
||||||
|
|
||||||
|
urlpatterns += patterns('',
|
||||||
|
url(r'^set_language/$', 'django.views.i18n.set_language', name='set_language'),
|
||||||
|
)
|
||||||
40
apps/common/utils.py
Normal file
40
apps/common/utils.py
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
from django.utils.http import urlquote as django_urlquote
|
||||||
|
from django.utils.http import urlencode as django_urlencode
|
||||||
|
from django.utils.datastructures import MultiValueDict
|
||||||
|
|
||||||
|
def urlquote(link=None, get={}):
|
||||||
|
u'''
|
||||||
|
This method does both: urlquote() and urlencode()
|
||||||
|
|
||||||
|
urlqoute(): Quote special characters in 'link'
|
||||||
|
|
||||||
|
urlencode(): Map dictionary to query string key=value&...
|
||||||
|
|
||||||
|
HTML escaping is not done.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
urlquote('/wiki/Python_(programming_language)') --> '/wiki/Python_%28programming_language%29'
|
||||||
|
urlquote('/mypath/', {'key': 'value'}) --> '/mypath/?key=value'
|
||||||
|
urlquote('/mypath/', {'key': ['value1', 'value2']}) --> '/mypath/?key=value1&key=value2'
|
||||||
|
urlquote({'key': ['value1', 'value2']}) --> 'key=value1&key=value2'
|
||||||
|
'''
|
||||||
|
assert link or get
|
||||||
|
if isinstance(link, dict):
|
||||||
|
# urlqoute({'key': 'value', 'key2': 'value2'}) --> key=value&key2=value2
|
||||||
|
assert not get, get
|
||||||
|
get=link
|
||||||
|
link=''
|
||||||
|
assert isinstance(get, dict), 'wrong type "%s", dict required' % type(get)
|
||||||
|
#assert not (link.startswith('http://') or link.startswith('https://')), \
|
||||||
|
# 'This method should only quote the url path. It should not start with http(s):// (%s)' % (
|
||||||
|
# link)
|
||||||
|
if get:
|
||||||
|
# http://code.djangoproject.com/ticket/9089
|
||||||
|
if isinstance(get, MultiValueDict):
|
||||||
|
get=get.lists()
|
||||||
|
if link:
|
||||||
|
link='%s?' % django_urlquote(link)
|
||||||
|
return u'%s%s' % (link, django_urlencode(get, doseq=True))
|
||||||
|
else:
|
||||||
|
return django_urlquote(link)
|
||||||
7
apps/common/views.py
Normal file
7
apps/common/views.py
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
from django.shortcuts import redirect
|
||||||
|
from django.utils.translation import ugettext as _
|
||||||
|
from django.contrib import messages
|
||||||
|
|
||||||
|
def password_change_done(request):
|
||||||
|
messages.success(request, _(u'Your password has been successfully changed.'))
|
||||||
|
return redirect('home')
|
||||||
82
apps/common/wizard.py
Normal file
82
apps/common/wizard.py
Normal file
@@ -0,0 +1,82 @@
|
|||||||
|
"""Common abstract classes for forms."""
|
||||||
|
try:
|
||||||
|
import cPickle as pickle
|
||||||
|
except ImportError:
|
||||||
|
import pickle
|
||||||
|
|
||||||
|
from django import forms
|
||||||
|
from django.conf import settings
|
||||||
|
from django.contrib.formtools.wizard import FormWizard
|
||||||
|
from django.forms.forms import BoundField
|
||||||
|
from django.forms.formsets import BaseFormSet
|
||||||
|
from django.utils.hashcompat import md5_constructor
|
||||||
|
|
||||||
|
__all__ = ('security_hash', 'BoundFormWizard')
|
||||||
|
|
||||||
|
def security_hash(request, form, exclude=None, *args):
|
||||||
|
"""Calculates a security hash for the given Form/FormSet instance.
|
||||||
|
|
||||||
|
This creates a list of the form field names/values in a deterministic
|
||||||
|
order, pickles the result with the SECRET_KEY setting, then takes an md5
|
||||||
|
hash of that.
|
||||||
|
"""
|
||||||
|
|
||||||
|
data = []
|
||||||
|
if exclude is None:
|
||||||
|
exclude = ()
|
||||||
|
if isinstance(form, BaseFormSet):
|
||||||
|
for _form in form.forms + [form.management_form]:
|
||||||
|
for bf in _form:
|
||||||
|
value = bf.field.clean(bf.data) or ''
|
||||||
|
if isinstance(value, basestring):
|
||||||
|
value = value.strip()
|
||||||
|
data.append((bf.name, value))
|
||||||
|
else:
|
||||||
|
for bf in form:
|
||||||
|
if bf.name in exclude:
|
||||||
|
continue
|
||||||
|
value = bf.field.clean(bf.data) or ''
|
||||||
|
if isinstance(value, basestring):
|
||||||
|
value = value.strip()
|
||||||
|
data.append((bf.name, value))
|
||||||
|
data.extend(args)
|
||||||
|
data.append(settings.SECRET_KEY)
|
||||||
|
|
||||||
|
# Use HIGHEST_PROTOCOL because it's the most efficient. It requires
|
||||||
|
# Python 2.3, but Django requires 2.3 anyway, so that's OK.
|
||||||
|
pickled = pickle.dumps(data, pickle.HIGHEST_PROTOCOL)
|
||||||
|
|
||||||
|
return md5_constructor(pickled).hexdigest()
|
||||||
|
|
||||||
|
class BoundFormWizard(FormWizard):
|
||||||
|
"""Render prev_fields as a list of bound form fields in the template
|
||||||
|
context rather than raw html."""
|
||||||
|
def security_hash(self, request, form):
|
||||||
|
"""Calculates the security hash for the given HttpRequest and
|
||||||
|
Form/FormSet instances.
|
||||||
|
|
||||||
|
Subclasses may want to take into account request-specific information,
|
||||||
|
such as the IP address.
|
||||||
|
"""
|
||||||
|
return security_hash(request, form)
|
||||||
|
|
||||||
|
def render(self, form, request, step, context=None):
|
||||||
|
"Renders the given Form object, returning an HttpResponse."
|
||||||
|
old_data = request.POST
|
||||||
|
prev_fields = []
|
||||||
|
if old_data:
|
||||||
|
for i in range(step):
|
||||||
|
old_form = self.get_form(i, old_data)
|
||||||
|
hash_name = 'hash_%s' % i
|
||||||
|
if isinstance(old_form, BaseFormSet):
|
||||||
|
for _form in old_form.forms + [old_form.management_form]:
|
||||||
|
prev_fields.extend([bf for bf in _form])
|
||||||
|
else:
|
||||||
|
prev_fields.extend([bf for bf in old_form])
|
||||||
|
hash_field = forms.Field(initial=old_data.get(hash_name,
|
||||||
|
self.security_hash(request, old_form)))
|
||||||
|
bf = BoundField(forms.Form(), hash_field, hash_name)
|
||||||
|
prev_fields.append(bf)
|
||||||
|
return self.render_template(request, form, prev_fields, step, context)
|
||||||
|
|
||||||
|
# vim: ai ts=4 sts=4 et sw=4
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
from django.utils.translation import ugettext_lazy as _
|
||||||
|
|
||||||
|
from common.api import register_links, register_menu
|
||||||
|
|
||||||
|
document_list = {'text':_(u'documents'), 'view':'document_list', 'famfam':'page'}
|
||||||
|
document_create = {'text':_('create document'), 'view':'document_create', 'famfam':'page_add'}
|
||||||
|
|
||||||
|
register_menu([
|
||||||
|
{'text':_('documents'), 'view':'document_list', 'links':[
|
||||||
|
document_list, document_create
|
||||||
|
],'famfam':'page','position':4}])
|
||||||
|
|
||||||
|
|||||||
@@ -1,10 +1,11 @@
|
|||||||
from django.contrib import admin
|
from django.contrib import admin
|
||||||
|
|
||||||
from models import MetadataType, DocumentType, Document, \
|
from models import MetadataType, DocumentType, Document, \
|
||||||
DocumentTypeMetadataTypeConnector
|
DocumentTypeMetadataType, DocumentMetadata
|
||||||
|
|
||||||
admin.site.register(MetadataType)
|
admin.site.register(MetadataType)
|
||||||
admin.site.register(DocumentType)
|
admin.site.register(DocumentType)
|
||||||
admin.site.register(Document)
|
admin.site.register(Document)
|
||||||
admin.site.register(DocumentTypeMetadataTypeConnector)
|
admin.site.register(DocumentTypeMetadataType)
|
||||||
|
admin.site.register(DocumentMetadata)
|
||||||
|
|
||||||
|
|||||||
68
apps/documents/forms.py
Normal file
68
apps/documents/forms.py
Normal file
@@ -0,0 +1,68 @@
|
|||||||
|
from django import forms
|
||||||
|
from django.utils.translation import ugettext_lazy as _
|
||||||
|
from django.http import HttpResponseRedirect
|
||||||
|
from django.utils.http import urlencode
|
||||||
|
from django.core.urlresolvers import reverse
|
||||||
|
|
||||||
|
from common.wizard import BoundFormWizard
|
||||||
|
from common.utils import urlquote
|
||||||
|
|
||||||
|
from models import Document, DocumentType, DocumentTypeMetadataType
|
||||||
|
|
||||||
|
|
||||||
|
class DocumentForm(forms.ModelForm):
|
||||||
|
class Meta:
|
||||||
|
model = Document
|
||||||
|
|
||||||
|
|
||||||
|
class DocumentTypeSelectForm(forms.Form):
|
||||||
|
document_type = forms.ModelChoiceField(queryset=DocumentType.objects.all())
|
||||||
|
|
||||||
|
|
||||||
|
class MetadataForm(forms.Form):
|
||||||
|
def __init__(self, *args, **kwargs):
|
||||||
|
if 'initial' in kwargs:
|
||||||
|
self.metadata_type = kwargs['initial'].pop('metadata_type', None)
|
||||||
|
super(MetadataForm, self).__init__(*args, **kwargs)
|
||||||
|
self.fields['id'] = forms.CharField(label=_(u'id'), widget=forms.HiddenInput)
|
||||||
|
self.fields['name'] = forms.CharField(label=_(u'Name'),
|
||||||
|
required=False, widget=forms.TextInput(attrs={'readonly':'readonly'}))
|
||||||
|
self.fields['value'] = forms.CharField(label=_(u'Value'))
|
||||||
|
if hasattr(self, 'metadata_type'):
|
||||||
|
self.fields['name'].initial=self.metadata_type.name
|
||||||
|
self.fields['id'].initial=self.metadata_type.id
|
||||||
|
|
||||||
|
|
||||||
|
class DocumentCreateWizard(BoundFormWizard):
|
||||||
|
def render_template(self, request, form, previous_fields, step, context=None):
|
||||||
|
context = {'step_title':self.extra_context['step_titles'][step]}
|
||||||
|
return super(DocumentCreateWizard, self).render_template(request, form, previous_fields, step, context)
|
||||||
|
|
||||||
|
def parse_params(self, request, *args, **kwargs):
|
||||||
|
self.extra_context={'step_titles':[
|
||||||
|
_(u'step 1 of 2: Document type'),
|
||||||
|
_(u'step 2 of 2: Document metadata'),
|
||||||
|
]}
|
||||||
|
|
||||||
|
def process_step(self, request, form, step):
|
||||||
|
if step == 0:
|
||||||
|
self.document_type = form.cleaned_data['document_type']
|
||||||
|
|
||||||
|
initial=[]
|
||||||
|
for item in DocumentTypeMetadataType.objects.filter(document_type=self.document_type):
|
||||||
|
initial.append({
|
||||||
|
'metadata_type':item.metadata_type,
|
||||||
|
})
|
||||||
|
self.initial = {1:initial}
|
||||||
|
if step == 1:
|
||||||
|
self.urldata = []
|
||||||
|
for metadata in form.cleaned_data:
|
||||||
|
self.urldata.append((metadata['id'],metadata['value']))
|
||||||
|
|
||||||
|
|
||||||
|
def get_template(self, step):
|
||||||
|
return 'generic_wizard.html'
|
||||||
|
|
||||||
|
def done(self, request, form_list):
|
||||||
|
url = reverse('upload_document_with_type', args=[self.document_type.id])
|
||||||
|
return HttpResponseRedirect('%s?%s' % (url, urlencode(self.urldata)))
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
import os
|
import os
|
||||||
import uuid
|
import uuid
|
||||||
|
import mimetypes
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
|
||||||
from django.db import models
|
from django.db import models
|
||||||
@@ -13,9 +14,8 @@ def get_filename_from_uuid(instance, filename, directory='documents'):
|
|||||||
|
|
||||||
def populate_file_extension_and_mimetype(instance, filename):
|
def populate_file_extension_and_mimetype(instance, filename):
|
||||||
# First populate the file extension and mimetype
|
# First populate the file extension and mimetype
|
||||||
instance.file_mimetype, encoding = guess_type(filename) or ""
|
instance.file_mimetype, encoding = mimetypes.guess_type(filename) or ""
|
||||||
slug, instance.file_extension = os.path.splitext(filename)
|
instance.file_filename, instance.file_extension = os.path.splitext(filename)
|
||||||
#instance.slug, instance.extension = os.path.splitext(filename)
|
|
||||||
|
|
||||||
class DocumentType(models.Model):
|
class DocumentType(models.Model):
|
||||||
name = models.CharField(max_length=32, verbose_name=_(u'name'))
|
name = models.CharField(max_length=32, verbose_name=_(u'name'))
|
||||||
@@ -30,66 +30,28 @@ class Document(models.Model):
|
|||||||
"""
|
"""
|
||||||
document_type = models.ForeignKey(DocumentType, verbose_name=_(u'document type'))
|
document_type = models.ForeignKey(DocumentType, verbose_name=_(u'document type'))
|
||||||
file = models.FileField(upload_to=get_filename_from_uuid)#lambda i,f: 'documents/%s' % i.uuid)
|
file = models.FileField(upload_to=get_filename_from_uuid)#lambda i,f: 'documents/%s' % i.uuid)
|
||||||
|
|
||||||
uuid = models.CharField(max_length=36, default=lambda:unicode(uuid.uuid4()), blank=True, editable=False)
|
uuid = models.CharField(max_length=36, default=lambda:unicode(uuid.uuid4()), blank=True, editable=False)
|
||||||
#file = models.FileField(upload_to=get_filename_from_uuid)#lambda i,f: 'documents/%s' % i.uuid)
|
file_mimetype = models.CharField(max_length=50, default="", editable=False)
|
||||||
#file_mimetype = models.CharField(max_length=50, default="", editable=False)
|
file_filename = models.CharField(max_length=64, default="", editable=False)
|
||||||
#file_extension = models.CharField(max_length=10, default="", editable=False)
|
file_extension = models.CharField(max_length=10, default="", editable=False)
|
||||||
|
|
||||||
date_added = models.DateTimeField("added", auto_now_add=True)
|
date_added = models.DateTimeField("added", auto_now_add=True)
|
||||||
date_updated = models.DateTimeField("updated", auto_now=True)
|
date_updated = models.DateTimeField("updated", auto_now=True)
|
||||||
|
|
||||||
|
|
||||||
#def save_file(self, contents, save=False):
|
|
||||||
# " Save a file, creating a new document_version if necessary. "
|
|
||||||
# self.file.save(contents.name, contents, save=save)
|
|
||||||
# # This is now done elsewhere
|
|
||||||
# #self.file_mimetype = guess_type(contents.name) or ""
|
|
||||||
# #try:
|
|
||||||
# #self.file_extension = contents[contents.rindex(".")+1:] or ""
|
|
||||||
# #except ValueError:
|
|
||||||
# #pass
|
|
||||||
# #self.save()
|
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
verbose_name = _(u'document')
|
verbose_name = _(u'document')
|
||||||
verbose_name_plural = _(u"documents")
|
verbose_name_plural = _(u'documents')
|
||||||
|
|
||||||
def __unicode__(self):
|
def __unicode__(self):
|
||||||
return self.uuid
|
return self.uuid
|
||||||
|
|
||||||
#@property
|
#@property
|
||||||
#def friendly_filename(self):
|
#def friendly_filename(self):
|
||||||
# """ A friendly filename (ie not the UUID) for the user to see when they download.
|
# ''' A friendly filename (ie not the UUID) for the user to see when they download.
|
||||||
# Overload this with eg a slug field.
|
# Overload this with eg a slug field.
|
||||||
# """
|
# '''
|
||||||
# return 'untitled.%s' % self.file_extension
|
# return 'untitled.%s' % self.file_extension
|
||||||
|
|
||||||
|
|
||||||
#def already(self, mode, request):
|
|
||||||
# """ Tests if a user has already viewed, downloaded or sent this document.
|
|
||||||
# Assumes this model has a log of document interactions.
|
|
||||||
# """
|
|
||||||
# mode = getattr(DocumentInteractionBase.MODES, mode.upper())
|
|
||||||
#
|
|
||||||
# if request.user.is_anonymous():
|
|
||||||
# return bool(self.interactions.filter(mode=mode, session_key=request.session.session_key))
|
|
||||||
# else:
|
|
||||||
# return bool(self.interactions.filter(mode=mode, user=request.user))
|
|
||||||
|
|
||||||
#@property
|
|
||||||
#def file_thumbnail_small(self):
|
|
||||||
# # TODO: subclass DjangoThumbnail to remove UUID from URL
|
|
||||||
# if DjangoThumbnail:
|
|
||||||
# return DjangoThumbnail(self.file.name, (200,200))
|
|
||||||
|
|
||||||
#@property
|
|
||||||
#def file_thumbnail_medium(self):
|
|
||||||
# # TODO: subclass DjangoThumbnail to remove UUID from URL
|
|
||||||
# if DjangoThumbnail:
|
|
||||||
# return DjangoThumbnail(self.file.name, (600,600))
|
|
||||||
|
|
||||||
|
|
||||||
class MetadataType(models.Model):
|
class MetadataType(models.Model):
|
||||||
name = models.CharField(max_length=32, verbose_name=_(u'name'))
|
name = models.CharField(max_length=32, verbose_name=_(u'name'))
|
||||||
default = models.CharField(max_length=64, blank=True, null=True, verbose_name=_(u'default'))
|
default = models.CharField(max_length=64, blank=True, null=True, verbose_name=_(u'default'))
|
||||||
@@ -101,22 +63,36 @@ class MetadataType(models.Model):
|
|||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
verbose_name = _(u'metadata type')
|
verbose_name = _(u'metadata type')
|
||||||
verbose_name_plural = _(u"metadata types")
|
verbose_name_plural = _(u'metadata types')
|
||||||
|
|
||||||
# @models.permalink
|
# @models.permalink
|
||||||
# def get_absolute_url(self):
|
# def get_absolute_url(self):
|
||||||
# return ('state_list', [])
|
# return ('state_list', [])
|
||||||
|
|
||||||
|
|
||||||
class DocumentTypeMetadataTypeConnector(models.Model):
|
class DocumentTypeMetadataType(models.Model):
|
||||||
document_type = models.ForeignKey(DocumentType, verbose_name=_(u'document type'))
|
document_type = models.ForeignKey(DocumentType, verbose_name=_(u'document type'))
|
||||||
metadata_type = models.ForeignKey(MetadataType, verbose_name=_(u'metadata type'))
|
metadata_type = models.ForeignKey(MetadataType, verbose_name=_(u'metadata type'))
|
||||||
#override default
|
#override default
|
||||||
#create index dir
|
#create index dir? -bool
|
||||||
|
#required? -bool
|
||||||
|
|
||||||
def __unicode__(self):
|
def __unicode__(self):
|
||||||
return '%s <-> %s' %(self.document_type, self.metadata_type)
|
return '%s <-> %s' %(self.document_type, self.metadata_type)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
verbose_name = _(u"document type metadata type connector")
|
verbose_name = _(u'document type metadata type connector')
|
||||||
verbose_name_plural = _(u"document type metadata type connectors")
|
verbose_name_plural = _(u'document type metadata type connectors')
|
||||||
|
|
||||||
|
|
||||||
|
class DocumentMetadata(models.Model):
|
||||||
|
document = models.ForeignKey(Document, verbose_name=_(u'document'))
|
||||||
|
metadata_type = models.ForeignKey(MetadataType, verbose_name=_(u'metadata type'))
|
||||||
|
value = models.TextField(blank=True, null=True, verbose_name=_(u'metadata value'))
|
||||||
|
|
||||||
|
def __unicode__(self):
|
||||||
|
return '%s <-> %s' %(self.document, self.metadata_type)
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
verbose_name = _(u'document metadata')
|
||||||
|
verbose_name_plural = _(u'document metadata')
|
||||||
|
|||||||
11
apps/documents/urls.py
Normal file
11
apps/documents/urls.py
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
from django.conf.urls.defaults import *
|
||||||
|
from django.utils.translation import ugettext_lazy as _
|
||||||
|
from django.views.generic.create_update import create_object, update_object
|
||||||
|
|
||||||
|
|
||||||
|
urlpatterns = patterns('documents.views',
|
||||||
|
url(r'^document/list/$', 'document_list', (), 'document_list'),
|
||||||
|
url(r'^document/create/$', 'document_create', (), 'document_create'),
|
||||||
|
#url(r'^document/upload/$', 'upload_document', (), 'upload_document'),
|
||||||
|
url(r'^document/type/(?P<document_type_id>\d+)/upload/$', 'upload_document_with_type', (), 'upload_document_with_type'),
|
||||||
|
)
|
||||||
@@ -1 +1,65 @@
|
|||||||
# Create your views here.
|
import datetime
|
||||||
|
|
||||||
|
from django.utils.translation import ugettext as _
|
||||||
|
from django.http import HttpResponse, HttpResponseRedirect
|
||||||
|
from django.shortcuts import render_to_response, get_object_or_404, redirect
|
||||||
|
from django.template import RequestContext
|
||||||
|
from django.contrib import messages
|
||||||
|
from django.views.generic.list_detail import object_detail, object_list
|
||||||
|
from django.core.urlresolvers import reverse
|
||||||
|
from django.views.generic.create_update import create_object
|
||||||
|
from django.forms.formsets import formset_factory
|
||||||
|
|
||||||
|
|
||||||
|
from models import Document, DocumentMetadata, DocumentType, MetadataType
|
||||||
|
from forms import DocumentTypeSelectForm, DocumentCreateWizard, \
|
||||||
|
MetadataForm, DocumentForm
|
||||||
|
|
||||||
|
|
||||||
|
def document_list(request):
|
||||||
|
return object_list(
|
||||||
|
request,
|
||||||
|
queryset=Document.objects.all(),
|
||||||
|
template_name='generic_list.html',
|
||||||
|
extra_context={
|
||||||
|
'title':_(u'documents'),
|
||||||
|
'extra_columns':[
|
||||||
|
{'name':_(u'filename'), 'attribute':'file_filename'},
|
||||||
|
{'name':_(u'extension'), 'attribute':'file_extension'},
|
||||||
|
{'name':_(u'mimetype'), 'attribute':'file_mimetype'},
|
||||||
|
{'name':_(u'added'), 'attribute':'date_added'},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def document_create(request):
|
||||||
|
MetadataFormSet = formset_factory(MetadataForm, extra=0)
|
||||||
|
wizard = DocumentCreateWizard(form_list=[DocumentTypeSelectForm, MetadataFormSet])
|
||||||
|
return wizard(request)
|
||||||
|
|
||||||
|
|
||||||
|
def upload_document_with_type(request, document_type_id):
|
||||||
|
document_type = get_object_or_404(DocumentType, pk=document_type_id)
|
||||||
|
if request.method == 'POST':
|
||||||
|
form = DocumentForm(request.POST, request.FILES, initial={'document_type':document_type})
|
||||||
|
if form.is_valid():
|
||||||
|
instance = form.save()
|
||||||
|
for key, value in request.GET.items():
|
||||||
|
document_metadata = DocumentMetadata(
|
||||||
|
document=instance,
|
||||||
|
metadata_type=get_object_or_404(MetadataType, pk=key),
|
||||||
|
value=value
|
||||||
|
)
|
||||||
|
document_metadata.save()
|
||||||
|
messages.success(request, _(u'Document uploaded successfully.'))
|
||||||
|
return HttpResponseRedirect(reverse('document_list'))
|
||||||
|
else:
|
||||||
|
form = DocumentForm(initial={'document_type':document_type})
|
||||||
|
|
||||||
|
return render_to_response('generic_form.html', {
|
||||||
|
'form':form
|
||||||
|
}, context_instance=RequestContext(request))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
13
apps/main/__init__.py
Normal file
13
apps/main/__init__.py
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
from django.utils.translation import ugettext_lazy as _
|
||||||
|
|
||||||
|
from common.api import register_menu
|
||||||
|
|
||||||
|
|
||||||
|
register_menu([
|
||||||
|
{'text':_(u'home'), 'view':'home', 'famfam':'house', 'position':0},
|
||||||
|
|
||||||
|
{'text':_(u'setup'), 'view':'', 'links': [
|
||||||
|
],'famfam':'cog', 'name':'setup','position':7},
|
||||||
|
|
||||||
|
{'text':_(u'about'), 'view':'about', 'position':8},
|
||||||
|
])
|
||||||
3
apps/main/models.py
Normal file
3
apps/main/models.py
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
from django.db import models
|
||||||
|
|
||||||
|
# Create your models here.
|
||||||
21
apps/main/templates/about.html
Executable file
21
apps/main/templates/about.html
Executable file
@@ -0,0 +1,21 @@
|
|||||||
|
{% extends "base.html" %}
|
||||||
|
{% load i18n %}
|
||||||
|
{% load project_tags %}
|
||||||
|
{% block title %} :: {% trans 'About this program' %}{% endblock %}
|
||||||
|
{% block content %}
|
||||||
|
|
||||||
|
<div class="content">
|
||||||
|
<h3 class="tc">
|
||||||
|
{% project_name %}<br /><br />
|
||||||
|
{% trans 'Django based document manager with custom metadata indexing and samba file serving integration' %}<br /><br />
|
||||||
|
<a href="http://www.github.com/rosarior/mayan/">http://www.github.com/rosarior/mayan/</a><br /><br />
|
||||||
|
</h3>
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
||||||
|
{% block footer %}
|
||||||
|
<div id="footer">
|
||||||
|
<div class="block">
|
||||||
|
<p>Copyright © 2011 Roberto Rosario.</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
||||||
102
apps/main/templates/base.html
Executable file
102
apps/main/templates/base.html
Executable file
@@ -0,0 +1,102 @@
|
|||||||
|
{% extends "web_theme_base.html" %}
|
||||||
|
{% load i18n %}
|
||||||
|
{% load project_tags %}
|
||||||
|
{% load navigation %}
|
||||||
|
|
||||||
|
{% block html_title %}{% project_name %}{% block title %}{% endblock %}{% endblock %}
|
||||||
|
|
||||||
|
{% block web_theme_project_name %}{% project_name %}{% endblock %}
|
||||||
|
|
||||||
|
{% block web_theme_stylesheets %}
|
||||||
|
<link rel="stylesheet" href="{{ MEDIA_URL }}css/override.css" type="text/css" media="screen" />
|
||||||
|
<link rel="stylesheet" href="{{ MEDIA_URL }}css/famfamfam-silk-sprite.css" type="text/css" media="screen" />
|
||||||
|
{% block stylesheets %}{% endblock %}
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block web_theme_user_navigation %}
|
||||||
|
<li><strong>{% trans 'User' %}:</strong>
|
||||||
|
{% if user.is_anonymous %}
|
||||||
|
{% trans 'Anonymous' %}
|
||||||
|
{% else %}
|
||||||
|
{{ user }}
|
||||||
|
<a href="{% url password_change_view %}">({% trans 'New password' %})</a>
|
||||||
|
{% endif %}
|
||||||
|
</li>
|
||||||
|
{% if user.is_staff %}
|
||||||
|
<li><a href="/admin">{% trans "Admin site" %}</a></li>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
|
||||||
|
<li>
|
||||||
|
<form action="{% url set_language %}" method="post">{% csrf_token %}
|
||||||
|
<select name="language">
|
||||||
|
{% for lang in LANGUAGES %}
|
||||||
|
<option value="{{ lang.0 }}">{{ lang.1 }}</option>
|
||||||
|
{% endfor %}
|
||||||
|
</select>
|
||||||
|
<input type="submit" value="{% trans 'Go' %}" />
|
||||||
|
</form>
|
||||||
|
</li>
|
||||||
|
<li><a class="logout" href="{% if user.is_anonymous %}{% url login_view %}?next=/{% else %}{% url logout_view %}{% endif %}">{% if user.is_anonymous %}{% trans 'Login' %}{% else %}{% trans 'Logout' %}{% endif %}</a></li>
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block web_theme_main_navigation %}
|
||||||
|
{% main_navigation %}
|
||||||
|
{% for link in navigation_main_links %}
|
||||||
|
<li class="{% if link.first %}first {% endif %}{% if link.active %}active{% endif %}"><a href="{{ link.url }}">{{ link.text|capfirst }}{% if link.famfam %}<span class="famfam active famfam-{{ link.famfam|default:'link' }}"></span>{% endif %}</a></li>
|
||||||
|
{% endfor %}
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block web_theme_secondary_navigation %}
|
||||||
|
{% main_navigation %}
|
||||||
|
{% if navigation_secondary_links %}
|
||||||
|
<div class="secondary-navigation">
|
||||||
|
<ul class="wat-cf">
|
||||||
|
{% for link in navigation_secondary_links %}
|
||||||
|
<li class="{% if link.first %}first {% endif %}{% if link.active %}active{% endif %}"><a href="{{ link.url }}">{{ link.text|capfirst }}{% if link.famfam %}<span class="famfam active famfam-{{ link.famfam|default:'link' }}"></span>{% endif %}</a></li>
|
||||||
|
{% endfor %}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block web_theme_sidebar %}
|
||||||
|
{% get_object_navigation_links %}
|
||||||
|
{% if object_navigation_links %}
|
||||||
|
<div class="block">
|
||||||
|
{% if object %}
|
||||||
|
{% if object_name %}
|
||||||
|
<h3>{% blocktrans %}Actions for {{ object_name }}: {{ object }}{% endblocktrans %}</h3>
|
||||||
|
{% else %}
|
||||||
|
<h3>{% blocktrans %}Actions for: {{ object }}{% endblocktrans %}</h3>
|
||||||
|
{% endif %}
|
||||||
|
{% else %}
|
||||||
|
<h3>}{% trans 'Actions' %}</h3>
|
||||||
|
{% endif %}
|
||||||
|
<ul class="navigation">
|
||||||
|
{% with 'true' as as_li %}
|
||||||
|
{% include 'generic_navigation.html' %}
|
||||||
|
{% endwith %}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% get_object_navigation_links "sidebar" %}
|
||||||
|
{% if object_navigation_links %}
|
||||||
|
<div class="block">
|
||||||
|
<h3>{% trans 'Other available actions' %}</h3>
|
||||||
|
<ul class="navigation">
|
||||||
|
{% with 'true' as as_li %}
|
||||||
|
{% include 'generic_navigation.html' %}
|
||||||
|
{% endwith %}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% block sidebar %}{% endblock %}
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
|
||||||
|
{% block web_theme_content %}{% block content %}{% endblock %}{% endblock %}
|
||||||
|
|
||||||
|
{% block web_theme_footer %}{% block footer %}{% endblock %}{% endblock %}
|
||||||
16
apps/main/templates/home.html
Executable file
16
apps/main/templates/home.html
Executable file
@@ -0,0 +1,16 @@
|
|||||||
|
{% extends "base.html" %}
|
||||||
|
{% load project_tags %}
|
||||||
|
{% load i18n %}
|
||||||
|
{% block content %}
|
||||||
|
<div class="content">
|
||||||
|
<div class="tc"><h1>{% project_name %}</h1></div>
|
||||||
|
<div class="tc"><img src="{{ MEDIA_URL }}images/1068504_92921456.jpg" /></div>
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
||||||
|
{% block footer %}
|
||||||
|
<div id="footer">
|
||||||
|
<div class="block">
|
||||||
|
<p>Copyright © 2011 Roberto Rosario.</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
||||||
23
apps/main/tests.py
Normal file
23
apps/main/tests.py
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
"""
|
||||||
|
This file demonstrates two different styles of tests (one doctest and one
|
||||||
|
unittest). These will both pass when you run "manage.py test".
|
||||||
|
|
||||||
|
Replace these with more appropriate tests for your application.
|
||||||
|
"""
|
||||||
|
|
||||||
|
from django.test import TestCase
|
||||||
|
|
||||||
|
class SimpleTest(TestCase):
|
||||||
|
def test_basic_addition(self):
|
||||||
|
"""
|
||||||
|
Tests that 1 + 1 always equals 2.
|
||||||
|
"""
|
||||||
|
self.failUnlessEqual(1 + 1, 2)
|
||||||
|
|
||||||
|
__test__ = {"doctest": """
|
||||||
|
Another way to test that 1 + 1 is equal to 2.
|
||||||
|
|
||||||
|
>>> 1 + 1 == 2
|
||||||
|
True
|
||||||
|
"""}
|
||||||
|
|
||||||
6
apps/main/urls.py
Normal file
6
apps/main/urls.py
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
from django.conf.urls.defaults import *
|
||||||
|
|
||||||
|
|
||||||
|
urlpatterns = patterns('main.views',
|
||||||
|
url(r'^$', 'home', (), 'home'),
|
||||||
|
)
|
||||||
6
apps/main/views.py
Normal file
6
apps/main/views.py
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
from django.shortcuts import render_to_response
|
||||||
|
from django.template import RequestContext
|
||||||
|
|
||||||
|
def home(request):
|
||||||
|
return render_to_response('home.html', {},
|
||||||
|
context_instance=RequestContext(request))
|
||||||
0
apps/web_theme/__init__.py
Normal file
0
apps/web_theme/__init__.py
Normal file
0
apps/web_theme/conf/__init__.py
Normal file
0
apps/web_theme/conf/__init__.py
Normal file
7
apps/web_theme/conf/settings.py
Normal file
7
apps/web_theme/conf/settings.py
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
from django.conf import settings
|
||||||
|
|
||||||
|
#Theme options are:
|
||||||
|
#amro, bec, bec-green, blue, default, djime-cerulean, drastic-dark,
|
||||||
|
#kathleene, olive, orange, red, reidb-greenish, warehouse
|
||||||
|
|
||||||
|
THEME = getattr(settings, 'WEB_THEME', 'default')
|
||||||
BIN
apps/web_theme/locale/es/LC_MESSAGES/django.mo
Normal file
BIN
apps/web_theme/locale/es/LC_MESSAGES/django.mo
Normal file
Binary file not shown.
24
apps/web_theme/locale/es/LC_MESSAGES/django.po
Normal file
24
apps/web_theme/locale/es/LC_MESSAGES/django.po
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
# SOME DESCRIPTIVE TITLE.
|
||||||
|
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
|
||||||
|
# This file is distributed under the same license as the PACKAGE package.
|
||||||
|
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
|
||||||
|
#
|
||||||
|
#, fuzzy
|
||||||
|
msgid ""
|
||||||
|
msgstr ""
|
||||||
|
"Project-Id-Version: PACKAGE VERSION\n"
|
||||||
|
"Report-Msgid-Bugs-To: \n"
|
||||||
|
"POT-Creation-Date: 2011-01-28 09:43-0400\n"
|
||||||
|
"PO-Revision-Date: 2011-01-28 09:43\n"
|
||||||
|
"Last-Translator: <admin@admin.com>\n"
|
||||||
|
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||||
|
"MIME-Version: 1.0\n"
|
||||||
|
"Content-Type: text/plain; charset=UTF-8\n"
|
||||||
|
"Content-Transfer-Encoding: 8bit\n"
|
||||||
|
"Language: \n"
|
||||||
|
"X-Translated-Using: django-rosetta 0.5.6\n"
|
||||||
|
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||||
|
|
||||||
|
#: templates/web_theme_login.html:3 templates/web_theme_login.html.py:8
|
||||||
|
msgid "Login"
|
||||||
|
msgstr "Iniciar sesión"
|
||||||
BIN
apps/web_theme/locale/ru/LC_MESSAGES/django.mo
Normal file
BIN
apps/web_theme/locale/ru/LC_MESSAGES/django.mo
Normal file
Binary file not shown.
24
apps/web_theme/locale/ru/LC_MESSAGES/django.po
Normal file
24
apps/web_theme/locale/ru/LC_MESSAGES/django.po
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
# SOME DESCRIPTIVE TITLE.
|
||||||
|
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
|
||||||
|
# This file is distributed under the same license as the PACKAGE package.
|
||||||
|
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
|
||||||
|
#
|
||||||
|
#, fuzzy
|
||||||
|
msgid ""
|
||||||
|
msgstr ""
|
||||||
|
"Project-Id-Version: PACKAGE VERSION\n"
|
||||||
|
"Report-Msgid-Bugs-To: \n"
|
||||||
|
"POT-Creation-Date: 2011-01-30 16:51+0300\n"
|
||||||
|
"PO-Revision-Date: 2011-01-30 13:12\n"
|
||||||
|
"Last-Translator: <garison2004@gmail.com>\n"
|
||||||
|
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||||
|
"MIME-Version: 1.0\n"
|
||||||
|
"Content-Type: text/plain; charset=UTF-8\n"
|
||||||
|
"Content-Transfer-Encoding: 8bit\n"
|
||||||
|
"Language: \n"
|
||||||
|
"X-Translated-Using: django-rosetta 0.5.5\n"
|
||||||
|
"Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n"
|
||||||
|
|
||||||
|
#: templates/web_theme_login.html:3 templates/web_theme_login.html.py:8
|
||||||
|
msgid "Login"
|
||||||
|
msgstr "Пользователь"
|
||||||
1
apps/web_theme/media
Submodule
1
apps/web_theme/media
Submodule
Submodule apps/web_theme/media added at c4159791f9
3
apps/web_theme/models.py
Normal file
3
apps/web_theme/models.py
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
from django.db import models
|
||||||
|
|
||||||
|
# Create your models here.
|
||||||
33
apps/web_theme/templates/pagination/pagination.html
Normal file
33
apps/web_theme/templates/pagination/pagination.html
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
{% if is_paginated %}
|
||||||
|
{% load i18n %}
|
||||||
|
<div class="actions-bar wat-cf">
|
||||||
|
<div class="pagination">
|
||||||
|
{% if page_obj.has_previous %}
|
||||||
|
<a class="prev_page" href="?page={{ page_obj.previous_page_number }}{{ getvars }}">‹‹ {% trans "Previous" %}</a>
|
||||||
|
{% else %}
|
||||||
|
<span class="disabled prev_page">‹‹ {% trans "Previous" %}</span>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% for page in pages %}
|
||||||
|
|
||||||
|
{% if page %}
|
||||||
|
|
||||||
|
{% ifequal page page_obj.number %}
|
||||||
|
<span class='current'>{{ page }}</span>
|
||||||
|
{% else %}
|
||||||
|
<a href="?page={{ page }}{{ getvars }}{{ hashtag }}">{{ page }}</a>
|
||||||
|
{% endifequal %}
|
||||||
|
{% else %}
|
||||||
|
<span class="disabled">...</span>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% endfor %}
|
||||||
|
{% if page_obj.has_next %}
|
||||||
|
<a class="next_page" href="?page={{ page_obj.next_page_number }}{{ getvars }}">{% trans "Next" %} ››</a>
|
||||||
|
{% else %}
|
||||||
|
<span class='disabled next-page'>{% trans "Next" %} ››</span>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{% endif %}
|
||||||
72
apps/web_theme/templates/web_theme_base.html
Normal file
72
apps/web_theme/templates/web_theme_base.html
Normal file
@@ -0,0 +1,72 @@
|
|||||||
|
{% load i18n %}
|
||||||
|
{% load theme_tags %}
|
||||||
|
{% get_theme as web_theme %}
|
||||||
|
<!DOCTYPE html PUBLIC "-//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" lang="en">
|
||||||
|
<head>
|
||||||
|
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||||
|
<meta http-equiv="Content-Language" content="{{ LANGUAGE_CODE }}" />
|
||||||
|
|
||||||
|
<title>{% block html_title %}{% endblock %}</title>
|
||||||
|
|
||||||
|
{% block keywords %}{% endblock %}
|
||||||
|
|
||||||
|
<link rel="stylesheet" href="{{ MEDIA_URL }}web_theme_media/stylesheets/base.css" type="text/css" media="screen" />
|
||||||
|
<link rel="stylesheet" id="current-theme" href="{{ MEDIA_URL }}web_theme_media/stylesheets/themes/{{ web_theme }}/style.css" type="text/css" media="screen" />
|
||||||
|
{% block web_theme_stylesheets %}{% endblock %}
|
||||||
|
|
||||||
|
<script type="text/javascript" charset="utf-8" src="{{ MEDIA_URL }}web_theme_media/javascripts/jquery-1.3.min.js"></script>
|
||||||
|
<script type="text/javascript" charset="utf-8" src="{{ MEDIA_URL }}web_theme_media/javascripts/jquery.scrollTo.js"></script>
|
||||||
|
<script type="text/javascript" charset="utf-8" src="{{ MEDIA_URL }}web_theme_media/javascripts/jquery.localscroll.js"></script>
|
||||||
|
{% block web_theme_javascript %}{% endblock %}
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id="container">
|
||||||
|
{% if user.is_anonymous %}
|
||||||
|
<div id="box">
|
||||||
|
{% block content_plain %}{% endblock %}
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
{% if not user.is_anonymous %}
|
||||||
|
<div id="header">
|
||||||
|
<h1><a href="{% url home %}">{% block web_theme_project_name %}{% endblock %}</a></h1>
|
||||||
|
<div id="user-navigation">
|
||||||
|
<ul class="wat-cf">
|
||||||
|
{% block web_theme_user_navigation %}{% endblock %}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
<div id="main-navigation">
|
||||||
|
<ul class="wat-cf">
|
||||||
|
{% block web_theme_main_navigation %}{% endblock %}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div id="wrapper" class="wat-cf">
|
||||||
|
<div id="main">
|
||||||
|
<div class="block" id="block-text">
|
||||||
|
{% block web_theme_secondary_navigation %}{% endblock %}
|
||||||
|
{% if messages %}
|
||||||
|
<div class="inner">
|
||||||
|
<div class="flash">
|
||||||
|
{% for message in messages %}
|
||||||
|
<div class="message{% if message.tags %}{% if 'success' in message.tags %} notice{% endif %} {{ message.tags }}{% else %} notice{% endif %}">
|
||||||
|
<p onclick="$(this).parent().parent().fadeOut(); return false;">{{ message }}</p>
|
||||||
|
</div>
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
{% block web_theme_messages %}{% endblock %}
|
||||||
|
{% block web_theme_content %}{% endblock %}
|
||||||
|
</div>
|
||||||
|
{% block web_theme_footer %}{% endblock %}
|
||||||
|
</div>
|
||||||
|
<div id="sidebar">
|
||||||
|
{% block web_theme_sidebar %}{% endblock %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
23
apps/web_theme/templates/web_theme_login.html
Normal file
23
apps/web_theme/templates/web_theme_login.html
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
{% extends "web_theme_base.html" %}
|
||||||
|
{% load i18n %}
|
||||||
|
{% block html_title %}{% trans "Login" %}{% endblock %}
|
||||||
|
{% block content_plain %}
|
||||||
|
<div id="box">
|
||||||
|
<h1>{% block project_name %}{% endblock %}</h1>
|
||||||
|
<div class="block" id="block-login">
|
||||||
|
<h2>{% trans "Login" %}</h2>
|
||||||
|
<div class="content login">
|
||||||
|
<form action="." method="post" class="form login">{% csrf_token %}
|
||||||
|
<div class="group wat-cf">
|
||||||
|
{% include "generic_form_instance.html" %}
|
||||||
|
<input type="hidden" name="next" value="{{ next|escape }}" />
|
||||||
|
<div class="group navform wat-cf">
|
||||||
|
<button class="button" type="submit">
|
||||||
|
<img src="{{ MEDIA_URL }}web_theme_media/images/icons/key.png" alt="Save" /> Login
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
||||||
0
apps/web_theme/templatetags/__init__.py
Normal file
0
apps/web_theme/templatetags/__init__.py
Normal file
32
apps/web_theme/templatetags/styling.py
Normal file
32
apps/web_theme/templatetags/styling.py
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
from django import forms
|
||||||
|
from django.template import TemplateSyntaxError, Library, \
|
||||||
|
VariableDoesNotExist, Node, Variable
|
||||||
|
from django.conf import settings
|
||||||
|
|
||||||
|
register = Library()
|
||||||
|
|
||||||
|
|
||||||
|
class StylingNode(Node):
|
||||||
|
def __init__(self, form_name, *args, **kwargs):
|
||||||
|
self.form_name = form_name
|
||||||
|
|
||||||
|
def render(self, context):
|
||||||
|
form = Variable(self.form_name).resolve(context)
|
||||||
|
for field_name, field in form.fields.items():
|
||||||
|
|
||||||
|
if isinstance(field.widget, forms.widgets.TextInput):
|
||||||
|
field.widget.attrs['class'] = 'text_field'
|
||||||
|
elif isinstance(field.widget, forms.widgets.PasswordInput):
|
||||||
|
field.widget.attrs['class'] = 'text_field'
|
||||||
|
elif isinstance(field.widget, forms.widgets.Textarea):
|
||||||
|
field.widget.attrs['class'] = 'text_area'
|
||||||
|
|
||||||
|
context[self.form_name] = form
|
||||||
|
return ''
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@register.tag
|
||||||
|
def add_classes_to_form(parser, token):
|
||||||
|
args = token.split_contents()
|
||||||
|
return StylingNode(args[1])
|
||||||
44
apps/web_theme/templatetags/theme_tags.py
Normal file
44
apps/web_theme/templatetags/theme_tags.py
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
import types
|
||||||
|
|
||||||
|
from django.conf import settings
|
||||||
|
from django.core.urlresolvers import reverse, NoReverseMatch
|
||||||
|
from django.core.urlresolvers import RegexURLResolver, RegexURLPattern, Resolver404, get_resolver
|
||||||
|
from django.template import TemplateSyntaxError, Library, \
|
||||||
|
VariableDoesNotExist, Node, Variable
|
||||||
|
from django.utils.text import unescape_string_literal
|
||||||
|
|
||||||
|
#from common.api import object_navigation
|
||||||
|
from web_theme.conf import settings as web_theme_settings
|
||||||
|
|
||||||
|
register = Library()
|
||||||
|
|
||||||
|
|
||||||
|
class GetThemeNode(Node):
|
||||||
|
def __init__(self, var_name, *args):
|
||||||
|
self.var_name = var_name
|
||||||
|
|
||||||
|
def render(self, context):
|
||||||
|
context['web_theme'] = web_theme_settings.THEME
|
||||||
|
return ''
|
||||||
|
|
||||||
|
|
||||||
|
import re
|
||||||
|
|
||||||
|
@register.tag
|
||||||
|
def get_theme(parser, token):
|
||||||
|
try:
|
||||||
|
# Splitting by None == splitting by spaces.
|
||||||
|
tag_name, arg = token.contents.split(None, 1)
|
||||||
|
except ValueError:
|
||||||
|
raise template.TemplateSyntaxError, "%r tag requires arguments" % token.contents.split()[0]
|
||||||
|
|
||||||
|
#m = re.search(r'(.*?) as (\w+)', arg)
|
||||||
|
m = re.search(r'as (\w+)', arg)
|
||||||
|
if not m:
|
||||||
|
raise template.TemplateSyntaxError, "%r tag had invalid arguments" % tag_name
|
||||||
|
#format_string, var_name = m.groups()
|
||||||
|
var_name = m.groups()
|
||||||
|
|
||||||
|
#if not (format_string[0] == format_string[-1] and format_string[0] in ('"', "'")):
|
||||||
|
# raise template.TemplateSyntaxError, "%r tag's argument should be in quotes" % tag_name
|
||||||
|
return GetThemeNode(var_name)
|
||||||
23
apps/web_theme/tests.py
Normal file
23
apps/web_theme/tests.py
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
"""
|
||||||
|
This file demonstrates two different styles of tests (one doctest and one
|
||||||
|
unittest). These will both pass when you run "manage.py test".
|
||||||
|
|
||||||
|
Replace these with more appropriate tests for your application.
|
||||||
|
"""
|
||||||
|
|
||||||
|
from django.test import TestCase
|
||||||
|
|
||||||
|
class SimpleTest(TestCase):
|
||||||
|
def test_basic_addition(self):
|
||||||
|
"""
|
||||||
|
Tests that 1 + 1 always equals 2.
|
||||||
|
"""
|
||||||
|
self.failUnlessEqual(1 + 1, 2)
|
||||||
|
|
||||||
|
__test__ = {"doctest": """
|
||||||
|
Another way to test that 1 + 1 is equal to 2.
|
||||||
|
|
||||||
|
>>> 1 + 1 == 2
|
||||||
|
True
|
||||||
|
"""}
|
||||||
|
|
||||||
1
apps/web_theme/views.py
Normal file
1
apps/web_theme/views.py
Normal file
@@ -0,0 +1 @@
|
|||||||
|
# Create your views here.
|
||||||
6
docs/TODO
Normal file
6
docs/TODO
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
* Filter by metadata
|
||||||
|
* Jquery upload document upload form with ajax widget
|
||||||
|
* Filterform date filtering widget
|
||||||
|
* Create indexing filesystem folders from document type metadata type
|
||||||
|
* Validate GET data before saving file
|
||||||
|
* Handle NULL mimetypes during model save
|
||||||
6
runserver.sh
Executable file
6
runserver.sh
Executable file
@@ -0,0 +1,6 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
if [ -n "$1" ]; then
|
||||||
|
./manage.py runserver $1 --adminmedia ./site_media/admin_media/
|
||||||
|
else
|
||||||
|
./manage.py runserver --adminmedia ./site_media/admin_media/
|
||||||
|
fi
|
||||||
6
runserver_plus.sh
Executable file
6
runserver_plus.sh
Executable file
@@ -0,0 +1,6 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
if [ -n "$1" ]; then
|
||||||
|
./manage.py runserver_plus $1 --adminmedia ./site_media/admin_media/
|
||||||
|
else
|
||||||
|
./manage.py runserver_plus --adminmedia ./site_media/admin_media/
|
||||||
|
fi
|
||||||
@@ -95,6 +95,7 @@ MIDDLEWARE_CLASSES = (
|
|||||||
'django.middleware.csrf.CsrfViewMiddleware',
|
'django.middleware.csrf.CsrfViewMiddleware',
|
||||||
'django.contrib.auth.middleware.AuthenticationMiddleware',
|
'django.contrib.auth.middleware.AuthenticationMiddleware',
|
||||||
'django.contrib.messages.middleware.MessageMiddleware',
|
'django.contrib.messages.middleware.MessageMiddleware',
|
||||||
|
'pagination.middleware.PaginationMiddleware',
|
||||||
)
|
)
|
||||||
|
|
||||||
ROOT_URLCONF = 'urls'
|
ROOT_URLCONF = 'urls'
|
||||||
@@ -115,7 +116,11 @@ INSTALLED_APPS = (
|
|||||||
'django.contrib.messages',
|
'django.contrib.messages',
|
||||||
'django.contrib.admin',
|
'django.contrib.admin',
|
||||||
'django.contrib.admindocs',
|
'django.contrib.admindocs',
|
||||||
|
'web_theme',
|
||||||
|
'main',
|
||||||
|
'common',
|
||||||
'documents',
|
'documents',
|
||||||
|
'pagination',
|
||||||
)
|
)
|
||||||
|
|
||||||
TEMPLATE_CONTEXT_PROCESSORS = (
|
TEMPLATE_CONTEXT_PROCESSORS = (
|
||||||
|
|||||||
1007
site_media/css/famfamfam-silk-sprite.css
Normal file
1007
site_media/css/famfamfam-silk-sprite.css
Normal file
File diff suppressed because it is too large
Load Diff
12
site_media/css/override.css
Normal file
12
site_media/css/override.css
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
.tc {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
#main-navigation ul li a {
|
||||||
|
line-height: 22px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.secondary-navigation ul li a {
|
||||||
|
line-height: 23px;
|
||||||
|
}
|
||||||
|
|
||||||
BIN
site_media/images/1068504_92921456.jpg
Normal file
BIN
site_media/images/1068504_92921456.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 123 KiB |
BIN
site_media/images/famfamfam-silk-sprites/famfam-active.png
Normal file
BIN
site_media/images/famfamfam-silk-sprites/famfam-active.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 290 KiB |
BIN
site_media/images/famfamfam-silk-sprites/famfam-hover.png
Normal file
BIN
site_media/images/famfamfam-silk-sprites/famfam-hover.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 301 KiB |
BIN
site_media/images/famfamfam-silk-sprites/famfam-inactive.png
Normal file
BIN
site_media/images/famfamfam-silk-sprites/famfam-inactive.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 276 KiB |
1
site_media/web_theme_media
Symbolic link
1
site_media/web_theme_media
Symbolic link
@@ -0,0 +1 @@
|
|||||||
|
../apps/web_theme/media/
|
||||||
18
urls.py
18
urls.py
@@ -1,11 +1,25 @@
|
|||||||
from django.conf.urls.defaults import *
|
from django.conf.urls.defaults import *
|
||||||
from django.contrib import admin
|
from django.contrib import admin
|
||||||
|
from django.conf import settings
|
||||||
|
|
||||||
admin.autodiscover()
|
admin.autodiscover()
|
||||||
|
|
||||||
urlpatterns = patterns('',
|
urlpatterns = patterns('',
|
||||||
# (r'^mayan/', include('mayan.foo.urls')),
|
(r'^', include('common.urls')),
|
||||||
|
(r'^', include('main.urls')),
|
||||||
|
(r'^documents/', include('documents.urls')),
|
||||||
(r'^admin/doc/', include('django.contrib.admindocs.urls')),
|
(r'^admin/doc/', include('django.contrib.admindocs.urls')),
|
||||||
(r'^admin/', include(admin.site.urls)),
|
(r'^admin/', include(admin.site.urls)),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
if settings.DEVELOPMENT:
|
||||||
|
urlpatterns += patterns('',
|
||||||
|
(r'^%s-site_media/(?P<path>.*)$' % settings.PROJECT_NAME,
|
||||||
|
'django.views.static.serve',
|
||||||
|
{'document_root': 'site_media', 'show_indexes': True}),
|
||||||
|
)
|
||||||
|
|
||||||
|
if 'rosetta' in settings.INSTALLED_APPS:
|
||||||
|
urlpatterns += patterns('',
|
||||||
|
url(r'^rosetta/', include('rosetta.urls'), name = "rosetta"),
|
||||||
|
)
|
||||||
|
|||||||
Reference in New Issue
Block a user