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/*
|
||||
*.sqlite
|
||||
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 models import MetadataType, DocumentType, Document, \
|
||||
DocumentTypeMetadataTypeConnector
|
||||
DocumentTypeMetadataType, DocumentMetadata
|
||||
|
||||
admin.site.register(MetadataType)
|
||||
admin.site.register(DocumentType)
|
||||
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 uuid
|
||||
import mimetypes
|
||||
from datetime import datetime
|
||||
|
||||
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):
|
||||
# First populate the file extension and mimetype
|
||||
instance.file_mimetype, encoding = guess_type(filename) or ""
|
||||
slug, instance.file_extension = os.path.splitext(filename)
|
||||
#instance.slug, instance.extension = os.path.splitext(filename)
|
||||
instance.file_mimetype, encoding = mimetypes.guess_type(filename) or ""
|
||||
instance.file_filename, instance.file_extension = os.path.splitext(filename)
|
||||
|
||||
class DocumentType(models.Model):
|
||||
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'))
|
||||
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)
|
||||
#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_extension = models.CharField(max_length=10, 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)
|
||||
date_added = models.DateTimeField("added", auto_now_add=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:
|
||||
verbose_name = _(u'document')
|
||||
verbose_name_plural = _(u"documents")
|
||||
verbose_name_plural = _(u'documents')
|
||||
|
||||
def __unicode__(self):
|
||||
return self.uuid
|
||||
|
||||
#@property
|
||||
#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.
|
||||
# """
|
||||
# '''
|
||||
# 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):
|
||||
name = models.CharField(max_length=32, verbose_name=_(u'name'))
|
||||
default = models.CharField(max_length=64, blank=True, null=True, verbose_name=_(u'default'))
|
||||
@@ -101,22 +63,36 @@ class MetadataType(models.Model):
|
||||
|
||||
class Meta:
|
||||
verbose_name = _(u'metadata type')
|
||||
verbose_name_plural = _(u"metadata types")
|
||||
verbose_name_plural = _(u'metadata types')
|
||||
|
||||
# @models.permalink
|
||||
# def get_absolute_url(self):
|
||||
# return ('state_list', [])
|
||||
|
||||
|
||||
class DocumentTypeMetadataTypeConnector(models.Model):
|
||||
class DocumentTypeMetadataType(models.Model):
|
||||
document_type = models.ForeignKey(DocumentType, verbose_name=_(u'document type'))
|
||||
metadata_type = models.ForeignKey(MetadataType, verbose_name=_(u'metadata type'))
|
||||
#override default
|
||||
#create index dir
|
||||
#create index dir? -bool
|
||||
#required? -bool
|
||||
|
||||
def __unicode__(self):
|
||||
return '%s <-> %s' %(self.document_type, self.metadata_type)
|
||||
|
||||
class Meta:
|
||||
verbose_name = _(u"document type metadata type connector")
|
||||
verbose_name_plural = _(u"document type metadata type connectors")
|
||||
verbose_name = _(u'document type metadata type connector')
|
||||
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.contrib.auth.middleware.AuthenticationMiddleware',
|
||||
'django.contrib.messages.middleware.MessageMiddleware',
|
||||
'pagination.middleware.PaginationMiddleware',
|
||||
)
|
||||
|
||||
ROOT_URLCONF = 'urls'
|
||||
@@ -115,7 +116,11 @@ INSTALLED_APPS = (
|
||||
'django.contrib.messages',
|
||||
'django.contrib.admin',
|
||||
'django.contrib.admindocs',
|
||||
'web_theme',
|
||||
'main',
|
||||
'common',
|
||||
'documents',
|
||||
'pagination',
|
||||
)
|
||||
|
||||
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.contrib import admin
|
||||
from django.conf import settings
|
||||
|
||||
admin.autodiscover()
|
||||
|
||||
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/', 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