Document upload and metadata input working

This commit is contained in:
Roberto Rosario
2011-02-03 17:17:04 -04:00
parent fc6545f45a
commit 986dc5d805
77 changed files with 2851 additions and 57 deletions

1
.gitignore vendored
View File

@@ -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
View File

32
apps/common/api.py Normal file
View 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
View 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)

Binary file not shown.

View 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"

Binary file not shown.

View 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
View File

@@ -0,0 +1,3 @@
from django.db import models
# Create your models here.

View 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 %}

View 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>

View 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 %}

View 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();'>&gt;</button></td>
</tr>
<tr>
<td><button class="button" onclick='document.forms["assign_remove"].action.value="remove";document.forms["assign_remove"].submit();'>&lt;</button></td>
</tr>
</tbody>
</table>
</td>
<td>{{ form.right_list }}{{ form.right_list.errors }}</td>
</tr>
{{ form.media|safe }}
</tbody>
</table>
</form>
</div>
{% endblock %}

View 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 %}

View 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 %}

View 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 %}

View 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 %}

View 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 %}

View 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 %}

View 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="">&nbsp;</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>

View 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 %}

View 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 %}

View 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 %}

View 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 %}

View File

@@ -0,0 +1,11 @@
{% extends "generic_form.html" %}
{% load i18n %}
{% block title %} :: {% trans "Password change" %}{% endblock %}
{% block form_title %}{% trans "Password change" %}{% endblock %}

View File

View 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)

View 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)

View 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
View 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
View 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
View 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
View 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
View 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

View File

@@ -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}])

View File

@@ -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
View 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)))

View File

@@ -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
View 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'),
)

View File

@@ -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
View 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
View File

@@ -0,0 +1,3 @@
from django.db import models
# Create your models here.

21
apps/main/templates/about.html Executable file
View 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 &copy; 2011 Roberto Rosario.</p>
</div>
</div>
{% endblock %}

102
apps/main/templates/base.html Executable file
View 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
View 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 &copy; 2011 Roberto Rosario.</p>
</div>
</div>
{% endblock %}

23
apps/main/tests.py Normal file
View 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
View 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
View 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))

View File

View File

View 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')

Binary file not shown.

View 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"

Binary file not shown.

View 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

Submodule apps/web_theme/media added at c4159791f9

3
apps/web_theme/models.py Normal file
View File

@@ -0,0 +1,3 @@
from django.db import models
# Create your models here.

View 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 }}">&lsaquo;&lsaquo; {% trans "Previous" %}</a>
{% else %}
<span class="disabled prev_page">&lsaquo;&lsaquo; {% 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" %} &rsaquo;&rsaquo;</a>
{% else %}
<span class='disabled next-page'>{% trans "Next" %} &rsaquo;&rsaquo;</span>
{% endif %}
</div>
</div>
{% endif %}

View 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>

View 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 %}

View File

View 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])

View 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
View 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
View File

@@ -0,0 +1 @@
# Create your views here.

6
docs/TODO Normal file
View 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
View 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
View 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

View File

@@ -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 = (

File diff suppressed because it is too large Load Diff

View 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;
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 123 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 290 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 301 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 276 KiB

1
site_media/web_theme_media Symbolic link
View File

@@ -0,0 +1 @@
../apps/web_theme/media/

18
urls.py
View File

@@ -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"),
)