summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGuillaume Seguin <guillaume@segu.in>2008-08-11 04:36:16 +0200
committerGuillaume Seguin <guillaume@segu.in>2008-08-11 04:36:16 +0200
commitdaa8080ff04165fe8fe80cd2f560750fff073fad (patch)
tree36f7c93964769186d6b7c66a21a84231abb7a508
downloaddusu_website-daa8080ff04165fe8fe80cd2f560750fff073fad.tar.gz
dusu_website-daa8080ff04165fe8fe80cd2f560750fff073fad.tar.bz2
* Initial importHEADmaster
-rw-r--r--.gitignore6
-rw-r--r--__init__.py0
-rw-r--r--main/__init__.py0
-rw-r--r--main/models.py103
-rw-r--r--main/shared.py64
-rw-r--r--main/templatetags/__init__.py0
-rw-r--r--main/templatetags/utils.py33
-rw-r--r--main/views.py102
-rw-r--r--manage.py11
-rw-r--r--settings.py.sample118
-rw-r--r--templates/admin/404.html12
-rw-r--r--templates/admin/500.html12
-rw-r--r--templates/admin/auth/user/add_form.html33
-rw-r--r--templates/admin/auth/user/change_password.html52
-rw-r--r--templates/admin/base.html55
-rw-r--r--templates/admin/base_site.html10
-rw-r--r--templates/admin/change_form.html78
-rw-r--r--templates/admin/change_list.html38
-rw-r--r--templates/admin/change_list_results.html17
-rw-r--r--templates/admin/date_hierarchy.html10
-rw-r--r--templates/admin/delete_confirmation.html31
-rw-r--r--templates/admin/edit_inline/stacked.html26
-rw-r--r--templates/admin/edit_inline/tabular.html67
-rw-r--r--templates/admin/filter.html8
-rw-r--r--templates/admin/includes/fieldset.html17
-rw-r--r--templates/admin/index.html68
-rw-r--r--templates/admin/invalid_setup.html8
-rw-r--r--templates/admin/login.html35
-rw-r--r--templates/admin/object_history.html36
-rw-r--r--templates/admin/pagination.html11
-rw-r--r--templates/admin/search_form.html18
-rw-r--r--templates/admin/submit_line.html8
-rw-r--r--templates/admin/template_validator.html31
-rw-r--r--templates/layout.html40
-rw-r--r--templates/main/base.html28
-rw-r--r--templates/main/calendar_page.html21
-rw-r--r--templates/main/file_page.html17
-rw-r--r--templates/main/file_poly.html1
-rw-r--r--templates/main/file_td.html6
-rw-r--r--templates/main/file_tp.html3
-rw-r--r--templates/main/loggedout.html16
-rw-r--r--templates/main/raw_page.html3
-rw-r--r--templates/main/simple_page.html3
-rw-r--r--templates/redirect.html14
-rw-r--r--urls.py33
45 files changed, 1303 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..1da840b
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,6 @@
+*.swp
+*.swo
+*.pyc
+*.db
+settings.py
+media/charts
diff --git a/__init__.py b/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/__init__.py
diff --git a/main/__init__.py b/main/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/main/__init__.py
diff --git a/main/models.py b/main/models.py
new file mode 100644
index 0000000..56c05cb
--- /dev/null
+++ b/main/models.py
@@ -0,0 +1,103 @@
+# coding: utf8
+
+'''
+Copyright (C) 2008 Guillaume Seguin <guillaume@segu.in>
+
+This application is free software: you can redistribute it and/or modify
+it under the terms of the GNU Affero General Public License as
+published by the Free Software Foundation, either version 3 of the
+License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU Affero General Public License for more details.
+
+You should have received a copy of the GNU Affero General Public License
+along with this application. If not, see <http://www.gnu.org/licenses/>.
+'''
+
+from django.db import models
+from django.utils.encoding import smart_str
+from django.contrib import admin
+from django.core.files.storage import FileSystemStorage
+
+from os.path import join, abspath
+
+import dusu_website.settings as settings
+
+class Page (models.Model):
+ '''Page object'''
+
+ TEMPLATE_CHOICES= (
+ ("simple_page.html", "Page simple"),
+ ("raw_page.html", "Page simple (html brut)"),
+ ("file_page.html", "Page des fichiers"),
+ ("calendar_page.html", "Page du planning")
+ )
+
+ position = models.IntegerField ("Position de la page")
+ enabled = models.BooleanField ("Activée")
+ name = models.CharField ("Nom interne de la page", max_length = 100)
+ title = models.CharField ("Titre de la page", max_length = 200)
+ template = models.CharField ("Nom du modèle", max_length = 100,
+ default = "simple_page.html",
+ choices = TEMPLATE_CHOICES)
+ content = models.TextField ("Contenu de la page")
+
+ def __str__ (self):
+ return smart_str (self.title)
+
+class PageAdmin (admin.ModelAdmin):
+ ordering = ("position",)
+
+fs = FileSystemStorage (location = settings.FILES_ROOT)
+
+def make_file_path (instance, filename):
+ '''Build storage path for given file'''
+ return "%s%s/%s" % (settings.FILES_ROOT, instance.type, filename)
+
+class File (models.Model):
+ '''File object'''
+
+ TYPE_CHOICES = (
+ ("td", "TDs"),
+ ("tp", "TPs"),
+ ("poly", "Polys"),
+ ("colle", "Programme de colles"),
+ )
+
+ type = models.CharField ("Type de fichier", max_length = 5,
+ choices = TYPE_CHOICES)
+ position = models.IntegerField ("Position du fichier")
+ published = models.BooleanField ("Publié")
+ name = models.CharField ("Nom du fichier", max_length = 200)
+ mainfile = models.FileField ("Fichier", max_length = 200,
+ upload_to = make_file_path, storage = fs)
+ solution = models.FileField ("Corrigé", max_length = 200,
+ upload_to = make_file_path, storage = fs)
+
+ def __str__ (self):
+ return smart_str ("%s - %s" % (self.get_type_display (), self.name))
+
+class FileAdmin (admin.ModelAdmin):
+ ordering = ("position",)
+
+class Test (models.Model):
+ '''Test object for calendar'''
+
+ number = models.IntegerField ("Numéro du DS")
+ date = models.DateField ("Date du DS")
+
+ class Meta:
+ verbose_name = "DS"
+
+ def __str__ (self):
+ return smart_str ("DS %s - %s" % (self.number, self.date))
+
+class TestAdmin (admin.ModelAdmin):
+ ordering = ("number",)
+
+admin.site.register (Page, PageAdmin)
+admin.site.register (File, FileAdmin)
+admin.site.register (Test, TestAdmin)
diff --git a/main/shared.py b/main/shared.py
new file mode 100644
index 0000000..7e5ee63
--- /dev/null
+++ b/main/shared.py
@@ -0,0 +1,64 @@
+# coding: utf8
+
+'''
+Copyright (C) 2008 Guillaume Seguin <guillaume@segu.in>
+
+This application is free software: you can redistribute it and/or modify
+it under the terms of the GNU Affero General Public License as
+published by the Free Software Foundation, either version 3 of the
+License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU Affero General Public License for more details.
+
+You should have received a copy of the GNU Affero General Public License
+along with this application. If not, see <http://www.gnu.org/licenses/>.
+'''
+
+from django.template import RequestContext, loader
+from django.http import HttpResponse, HttpResponseRedirect
+from django import forms
+from django.contrib.sites.models import Site
+
+from dusu_website.main.models import *
+
+class LoginForm (forms.Form):
+
+ def __init__ (self, *args, **kwargs):
+ super (LoginForm, self).__init__ (*args, **kwargs)
+ username = forms.CharField (label = "Identifiant", required = True)
+ password = forms.CharField (label = "Mot de passe", required = True,
+ widget = forms.PasswordInput)
+ self.fields["username"] = username
+ self.fields["password"] = password
+
+def context_processor (request):
+ '''Append extra data to the context of the given request'''
+ data = {}
+ data["site"] = Site.objects.get_current ()
+ if not request.user.is_authenticated ():
+ data["login_form"] = LoginForm ()
+ else:
+ data["pages"] = Page.objects.order_by ("position").all ()
+ return data
+
+def render_template (request, data, template = "layout.html"):
+ '''Helper rendering function'''
+ template = loader.get_template (template)
+ context = RequestContext (request, data)
+ return template.render (context)
+
+def render_page (request, data, template = "layout.html"):
+ '''Helper rendering function'''
+ return HttpResponse (render_template (request, data, template))
+
+def redirect (request, to, message, delay = 2000):
+ '''Display a redirect page'''
+ data = {
+ "redirect_message" : message,
+ "redirect_to" : to,
+ "redirect_delay": delay,
+ }
+ return render_page (request, data, template = "redirect.html")
diff --git a/main/templatetags/__init__.py b/main/templatetags/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/main/templatetags/__init__.py
diff --git a/main/templatetags/utils.py b/main/templatetags/utils.py
new file mode 100644
index 0000000..7d111da
--- /dev/null
+++ b/main/templatetags/utils.py
@@ -0,0 +1,33 @@
+# coding: utf8
+
+'''
+Copyright (C) 2008 Guillaume Seguin <guillaume@segu.in>
+
+This application is free software: you can redistribute it and/or modify
+it under the terms of the GNU Affero General Public License as
+published by the Free Software Foundation, either version 3 of the
+License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU Affero General Public License for more details.
+
+You should have received a copy of the GNU Affero General Public License
+along with this application. If not, see <http://www.gnu.org/licenses/>.
+'''
+
+from django import template
+from django.utils.translation import ugettext as _
+
+import os.path
+
+register = template.Library ()
+
+@register.filter
+def hash (dict, key):
+ return dict[key]
+
+@register.filter
+def basename (path):
+ return os.path.basename (str (path))
diff --git a/main/views.py b/main/views.py
new file mode 100644
index 0000000..11814e4
--- /dev/null
+++ b/main/views.py
@@ -0,0 +1,102 @@
+# coding: utf8
+
+'''
+Copyright (C) 2008 Guillaume Seguin <guillaume@segu.in>
+
+This application is free software: you can redistribute it and/or modify
+it under the terms of the GNU Affero General Public License as
+published by the Free Software Foundation, either version 3 of the
+License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU Affero General Public License for more details.
+
+You should have received a copy of the GNU Affero General Public License
+along with this application. If not, see <http://www.gnu.org/licenses/>.
+'''
+
+from django.http import HttpResponseRedirect
+from django.contrib.auth import authenticate, login, logout
+from django.contrib.auth.decorators import login_required
+from django.shortcuts import get_object_or_404
+
+import time
+import hashlib
+
+from dusu_website.main.models import *
+from dusu_website.main.shared import *
+import dusu_website.settings as settings
+
+@login_required
+def page_view (request, page_name):
+ '''Load a given page'''
+ page = get_object_or_404 (Page, name = page_name)
+ data = {
+ "pagetitle": page.title,
+ "content": page.content,
+ }
+ if page.template == "file_page.html":
+ data["files"] = {}
+ data["filetypes"] = []
+ data["filetypenames"] = {}
+ for type in File.TYPE_CHOICES:
+ if type[0] == "colle":
+ continue
+ template = "main/file_%s.html" % type[0]
+ files = File.objects.filter (type = type[0])
+ files = files.order_by ("position").all ()
+ if not len (files):
+ continue
+ files = [render_template (request, {"file": file}, template)
+ for file in files]
+ data["files"][type[0]] = files
+ data["filetypes"].append (type[0])
+ data["filetypenames"][type[0]] = type[1]
+ elif page.template == "calendar_page.html":
+ files = File.objects.filter (type = "colles")
+ files = files.order_by ("position").all ()
+ data["colles"] = files
+ data["tests"] = Test.objects.order_by ("number").all ()
+ return render_page (request, data, "main/%s" % page.template)
+
+@login_required
+def file_view (request, type, file_name):
+ '''Redirect to secure file download page'''
+ secret = settings.SECDOWNLOAD_KEY
+ uri_prefix = settings.SECDOWNLOAD_PREFIX
+ rel_path = "/%s/%s" % (type, file_name)
+ hextime = "%08x" % time.time()
+ token = hashlib.md5 (secret + rel_path + hextime).hexdigest ()
+ dest = "%s%s/%s%s" % (uri_prefix, token, hextime, rel_path)
+ return HttpResponseRedirect (dest)
+
+def login_view (request):
+ '''Attempt to login an user'''
+ if "username" not in request.POST or "password" not in request.POST \
+ or request.user.is_authenticated ():
+ return HttpResponseRedirect ("/")
+ username = request.POST["username"]
+ password = request.POST["password"]
+ user = authenticate (username = username, password = password)
+ if user is not None:
+ if user.is_active:
+ login (request, user)
+ return redirect (request, "/", "Vous êtes maintenant connecté.")
+ else:
+ return redirect (request, "/", "Ce compte n'est pas activé.")
+ else:
+ return redirect (request, "/", "Identifiants incorrects.")
+
+@login_required
+def logout_view (request):
+ '''Logout an user'''
+ logout (request)
+ return redirect (request, "/", "Vous êtes maintenant déconnecté.")
+
+def home_view (request):
+ '''Render the main page'''
+ if not request.user.is_authenticated ():
+ return render_page (request, {}, "main/loggedout.html")
+ return page_view (request, page_name = "index")
diff --git a/manage.py b/manage.py
new file mode 100644
index 0000000..5e78ea9
--- /dev/null
+++ b/manage.py
@@ -0,0 +1,11 @@
+#!/usr/bin/env python
+from django.core.management import execute_manager
+try:
+ import settings # Assumed to be in the same directory.
+except ImportError:
+ import sys
+ sys.stderr.write("Error: Can't find the file 'settings.py' in the directory containing %r. It appears you've customized things.\nYou'll have to run django-admin.py, passing it your settings module.\n(If the file settings.py does indeed exist, it's causing an ImportError somehow.)\n" % __file__)
+ sys.exit(1)
+
+if __name__ == "__main__":
+ execute_manager(settings)
diff --git a/settings.py.sample b/settings.py.sample
new file mode 100644
index 0000000..bd15888
--- /dev/null
+++ b/settings.py.sample
@@ -0,0 +1,118 @@
+# coding: utf8
+
+'''
+Copyright (C) 2008 Guillaume Seguin <guillaume@segu.in>
+
+This application is free software: you can redistribute it and/or modify
+it under the terms of the GNU Affero General Public License as
+published by the Free Software Foundation, either version 3 of the
+License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU Affero General Public License for more details.
+
+You should have received a copy of the GNU Affero General Public License
+along with this application. If not, see <http://www.gnu.org/licenses/>.
+'''
+
+DEBUG = True
+TEMPLATE_DEBUG = DEBUG
+
+ADMINS = (
+ ('You!', 'you@yourhost.com'),
+)
+
+MANAGERS = ADMINS
+
+DATABASE_ENGINE = '' # 'postgresql_psycopg2', 'postgresql', 'mysql', 'sqlite3' or 'oracle'.
+DATABASE_NAME = '' # Or path to database file if using sqlite3.
+DATABASE_USER = '' # Not used with sqlite3.
+DATABASE_PASSWORD = '' # Not used with sqlite3.
+DATABASE_HOST = '' # Set to empty string for localhost. Not used with sqlite3.
+DATABASE_PORT = '' # Set to empty string for default. Not used with sqlite3.
+
+# Local time zone for this installation. Choices can be found here:
+# http://en.wikipedia.org/wiki/List_of_tz_zones_by_name
+# although not all choices may be available on all operating systems.
+# If running in a Windows environment this must be set to the same as your
+# system time zone.
+TIME_ZONE = 'Europe/Paris'
+
+# Language code for this installation. All choices can be found here:
+# http://www.i18nguy.com/unicode/language-identifiers.html
+LANGUAGE_CODE = 'fr-fr'
+
+SITE_ID = 1
+
+# If you set this to False, Django will make some optimizations so as not
+# to load the internationalization machinery.
+USE_I18N = False
+
+# Absolute path to the directory that holds media.
+# Example: "/home/media/media.lawrence.com/"
+MEDIA_ROOT = ''
+
+# URL that handles the media served from MEDIA_ROOT. Make sure to use a
+# trailing slash if there is a path component (optional in other cases).
+# Examples: "http://media.lawrence.com", "http://example.com/media/"
+MEDIA_URL = ''
+
+# URL prefix for admin media -- CSS, JavaScript and images. Make sure to use a
+# trailing slash.
+# Examples: "http://foo.com/media/", "/media/".
+ADMIN_MEDIA_PREFIX = '/admedia/'
+
+# Absolute path to the directory where uploaded files will be stored.
+FILES_ROOT = ''
+
+# SecDownload key and prefix.
+# See http://trac.lighttpd.net/trac/wiki/Docs:ModSecDownload for details.
+SECDOWNLOAD_KEY = ""
+SECDOWNLOAD_PREFIX = ""
+
+# URL path for login page.
+LOGIN_URL = '/'
+
+# Make this unique, and don't share it with anybody.
+SECRET_KEY = 'CHANGEME!!!!!!!!!!!!@@#@#@#@!'
+
+# List of callables that know how to import templates from various sources.
+TEMPLATE_LOADERS = (
+ 'django.template.loaders.filesystem.load_template_source',
+ 'django.template.loaders.app_directories.load_template_source',
+# 'django.template.loaders.eggs.load_template_source',
+)
+
+MIDDLEWARE_CLASSES = (
+ 'django.middleware.common.CommonMiddleware',
+ 'django.contrib.sessions.middleware.SessionMiddleware',
+ 'django.contrib.auth.middleware.AuthenticationMiddleware',
+ 'django.middleware.doc.XViewMiddleware',
+)
+
+ROOT_URLCONF = 'dusu_website.urls'
+
+TEMPLATE_DIRS = (
+ "/path/to/templates/",
+ # Put strings here, like "/home/html/django_templates" or "C:/www/django/templates".
+ # Always use forward slashes, even on Windows.
+ # Don't forget to use absolute paths, not relative paths.
+)
+
+TEMPLATE_CONTEXT_PROCESSORS = (
+ "django.core.context_processors.auth",
+ "django.core.context_processors.debug",
+ "django.core.context_processors.media",
+ "dusu_website.main.shared.context_processor",
+)
+
+INSTALLED_APPS = (
+ 'django.contrib.auth',
+ 'django.contrib.contenttypes',
+ 'django.contrib.sessions',
+ 'django.contrib.sites',
+ 'django.contrib.admin',
+ 'dusu_website.main',
+)
diff --git a/templates/admin/404.html b/templates/admin/404.html
new file mode 100644
index 0000000..9bf4293
--- /dev/null
+++ b/templates/admin/404.html
@@ -0,0 +1,12 @@
+{% extends "admin/base_site.html" %}
+{% load i18n %}
+
+{% block title %}{% trans 'Page not found' %}{% endblock %}
+
+{% block content %}
+
+<h2>{% trans 'Page not found' %}</h2>
+
+<p>{% trans "We're sorry, but the requested page could not be found." %}</p>
+
+{% endblock %}
diff --git a/templates/admin/500.html b/templates/admin/500.html
new file mode 100644
index 0000000..b30e431
--- /dev/null
+++ b/templates/admin/500.html
@@ -0,0 +1,12 @@
+{% extends "admin/base_site.html" %}
+{% load i18n %}
+
+{% block breadcrumbs %}<div class="breadcrumbs"><a href="/">{% trans "Home" %}</a> &rsaquo; {% trans "Server error" %}</div>{% endblock %}
+
+{% block title %}{% trans 'Server error (500)' %}{% endblock %}
+
+{% block content %}
+<h1>{% trans 'Server Error <em>(500)</em>' %}</h1>
+<p>{% trans "There's been an error. It's been reported to the site administrators via e-mail and should be fixed shortly. Thanks for your patience." %}</p>
+
+{% endblock %}
diff --git a/templates/admin/auth/user/add_form.html b/templates/admin/auth/user/add_form.html
new file mode 100644
index 0000000..65824a6
--- /dev/null
+++ b/templates/admin/auth/user/add_form.html
@@ -0,0 +1,33 @@
+{% extends "admin/change_form.html" %}
+{% load i18n %}
+
+{% block after_field_sets %}
+
+<p>{% trans "First, enter a username and password. Then, you'll be able to edit more user options." %}</p>
+
+<fieldset class="module aligned">
+
+<div class="form-row">
+ {{ form.username.errors }}
+ {# TODO: get required class on label_tag #}
+ <label for="id_username" class="required">{% trans 'Username' %}:</label> {{ form.username }}
+ <p class="help">{{ form.username.help_text }}</p>
+</div>
+
+<div class="form-row">
+ {{ form.password1.errors }}
+ {# TODO: get required class on label_tag #}
+ <label for="id_password1" class="required">{% trans 'Password' %}:</label> {{ form.password1 }}
+</div>
+
+<div class="form-row">
+ {{ form.password2.errors }}
+ {# TODO: get required class on label_tag #}
+ <label for="id_password2" class="required">{% trans 'Password (again)' %}:</label> {{ form.password2 }}
+ <p class="help">{% trans 'Enter the same password as above, for verification.' %}</p>
+</div>
+
+<script type="text/javascript">document.getElementById("id_username").focus();</script>
+
+</fieldset>
+{% endblock %}
diff --git a/templates/admin/auth/user/change_password.html b/templates/admin/auth/user/change_password.html
new file mode 100644
index 0000000..f1c4a8d
--- /dev/null
+++ b/templates/admin/auth/user/change_password.html
@@ -0,0 +1,52 @@
+{% extends "admin/base_site.html" %}
+{% load i18n admin_modify adminmedia %}
+{% block extrahead %}{{ block.super }}
+<script type="text/javascript" src="../../../../jsi18n/"></script>
+{% endblock %}
+{% block stylesheet %}{% admin_media_prefix %}css/forms.css{% endblock %}
+{% block bodyclass %}{{ opts.app_label }}-{{ opts.object_name.lower }} change-form{% endblock %}
+{% block breadcrumbs %}{% if not is_popup %}
+<div class="breadcrumbs">
+ <a href="../../../../">{% trans "Home" %}</a> &rsaquo;
+ <a href="../../">{{ opts.verbose_name_plural|capfirst|escape }}</a> &rsaquo;
+ <a href="../">{{ original|truncatewords:"18"|escape }}</a> &rsaquo;
+ {% trans 'Change password' %}
+</div>
+{% endif %}{% endblock %}
+{% block content %}<div id="content-main">
+<form action="{{ form_url }}" method="post" id="{{ opts.module_name }}_form">{% block form_top %}{% endblock %}
+<div>
+{% if is_popup %}<input type="hidden" name="_popup" value="1" />{% endif %}
+{% if form.errors %}
+ <p class="errornote">
+ {% blocktrans count form.errors.items|length as counter %}Please correct the error below.{% plural %}Please correct the errors below.{% endblocktrans %}
+ </p>
+{% endif %}
+
+<p>{% blocktrans with original.username|escape as username %}Enter a new password for the user <strong>{{ username }}</strong>.{% endblocktrans %}</p>
+
+<fieldset class="module aligned">
+
+<div class="form-row">
+ {{ form.password1.errors }}
+ {# TODO: get required class on label_tag #}
+ <label for="id_password1" class="required">{% trans 'Password' %}:</label> {{ form.password1 }}
+</div>
+
+<div class="form-row">
+ {{ form.password2.errors }}
+ {# TODO: get required class on label_tag #}
+ <label for="id_password2" class="required">{% trans 'Password (again)' %}:</label> {{ form.password2 }}
+ <p class="help">{% trans 'Enter the same password as above, for verification.' %}</p>
+</div>
+
+</fieldset>
+
+<div class="submit-row">
+<input type="submit" value="{% trans 'Change password' %}" class="default" />
+</div>
+
+<script type="text/javascript">document.getElementById("id_password1").focus();</script>
+</div>
+</form></div>
+{% endblock %}
diff --git a/templates/admin/base.html b/templates/admin/base.html
new file mode 100644
index 0000000..479e18b
--- /dev/null
+++ b/templates/admin/base.html
@@ -0,0 +1,55 @@
+<!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="{{ LANGUAGE_CODE }}" xml:lang="{{ LANGUAGE_CODE }}" {% if LANGUAGE_BIDI %}dir="rtl"{% endif %}>
+<head>
+<title>{% block title %}{% endblock %}</title>
+<link rel="stylesheet" type="text/css" href="{% block stylesheet %}{% load adminmedia %}{% admin_media_prefix %}css/base.css{% endblock %}" />
+{% if LANGUAGE_BIDI %}<link rel="stylesheet" type="text/css" href="{% block stylesheet_rtl %}{% admin_media_prefix %}css/rtl.css{% endblock %}" />{% endif %}
+{% block extrastyle %}{% endblock %}
+{% block extrahead %}{% endblock %}
+{% block blockbots %}<meta name="robots" content="NONE,NOARCHIVE" />{% endblock %}
+</head>
+{% load i18n %}
+
+<body class="{% if is_popup %}popup {% endif %}{% block bodyclass %}{% endblock %}">
+
+<!-- Container -->
+<div id="container">
+
+ {% if not is_popup %}
+ <!-- Header -->
+ <div id="header">
+ <div id="branding">
+ {% block branding %}{% endblock %}
+ </div>
+ {% if user.is_authenticated and user.is_staff %}
+ <div id="user-tools">{% trans 'Welcome,' %} <strong>{% if user.first_name %}{{ user.first_name|escape }}{% else %}{{ user.username }}{% endif %}</strong>. {% block userlinks %}<a href="{{ root_path }}doc/">{% trans 'Documentation' %}</a> / <a href="{{ root_path }}password_change/">{% trans 'Change password' %}</a> / <a href="{{ root_path }}logout/">{% trans 'Log out' %}</a>{% endblock %}</div>
+ {% endif %}
+ {% block nav-global %}{% endblock %}
+ </div>
+ <!-- END Header -->
+ {% block breadcrumbs %}<div class="breadcrumbs"><a href="/">{% trans 'Home' %}</a>{% if title %} &rsaquo; {{ title|escape }}{% endif %}</div>{% endblock %}
+ {% endif %}
+
+ {% if messages %}
+ <ul class="messagelist">{% for message in messages %}<li>{{ message|escape }}</li>{% endfor %}</ul>
+ {% endif %}
+
+ <!-- Content -->
+ <div id="content" class="{% block coltype %}colM{% endblock %}">
+ {% block pretitle %}{% endblock %}
+ {% block content_title %}{% if title %}<h1>{{ title|escape }}</h1>{% endif %}{% endblock %}
+ {% block content %}
+ {% block object-tools %}{% endblock %}
+ {{ content }}
+ {% endblock %}
+ {% block sidebar %}{% endblock %}
+ <br class="clear" />
+ </div>
+ <!-- END Content -->
+
+ {% block footer %}<div id="footer"></div>{% endblock %}
+</div>
+<!-- END Container -->
+
+</body>
+</html>
diff --git a/templates/admin/base_site.html b/templates/admin/base_site.html
new file mode 100644
index 0000000..b867bd2
--- /dev/null
+++ b/templates/admin/base_site.html
@@ -0,0 +1,10 @@
+{% extends "admin/base.html" %}
+{% load i18n %}
+
+{% block title %}{{ title }} | {% trans 'Django site admin' %}{% endblock %}
+
+{% block branding %}
+<h1 id="site-name">{% trans 'Django administration' %}</h1>
+{% endblock %}
+
+{% block nav-global %}{% endblock %}
diff --git a/templates/admin/change_form.html b/templates/admin/change_form.html
new file mode 100644
index 0000000..e8df6b9
--- /dev/null
+++ b/templates/admin/change_form.html
@@ -0,0 +1,78 @@
+{% extends "admin/base_site.html" %}
+{% load i18n admin_modify adminmedia %}
+
+{% block extrahead %}{{ block.super }}
+<script type="text/javascript" src="../../../jsi18n/"></script>
+{{ media }}
+{% endblock %}
+
+{% block stylesheet %}{% admin_media_prefix %}css/forms.css{% endblock %}
+
+{% block coltype %}{% if ordered_objects %}colMS{% else %}colM{% endif %}{% endblock %}
+
+{% block bodyclass %}{{ opts.app_label }}-{{ opts.object_name.lower }} change-form{% endblock %}
+
+{% block breadcrumbs %}{% if not is_popup %}
+<div class="breadcrumbs">
+ <a href="../../../">{% trans "Home" %}</a> &rsaquo;
+ <a href="../">{{ opts.verbose_name_plural|capfirst }}</a> &rsaquo;
+ {% if add %}{% trans "Add" %} {{ opts.verbose_name }}{% else %}{{ original|truncatewords:"18" }}{% endif %}
+</div>
+{% endif %}{% endblock %}
+
+{% block content %}<div id="content-main">
+{% block object-tools %}
+{% if change %}{% if not is_popup %}
+ <ul class="object-tools"><li><a href="history/" class="historylink">{% trans "History" %}</a></li>
+ {% if has_absolute_url %}<li><a href="../../../r/{{ content_type_id }}/{{ object_id }}/" class="viewsitelink">{% trans "View on site" %}</a></li>{% endif%}
+ </ul>
+{% endif %}{% endif %}
+{% endblock %}
+<form {% if has_file_field %}enctype="multipart/form-data" {% endif %}action="{{ form_url }}" method="post" id="{{ opts.module_name }}_form">{% block form_top %}{% endblock %}
+<div>
+{% if is_popup %}<input type="hidden" name="_popup" value="1" />{% endif %}
+{% if save_on_top %}{% submit_row %}{% endif %}
+{% if errors %}
+ <p class="errornote">
+ {% blocktrans count errors.items|length as counter %}Please correct the error below.{% plural %}Please correct the errors below.{% endblocktrans %}
+ </p>
+ <ul class="errorlist">{% for error in adminform.form.non_field_errors %}<li>{{ error }}</li>{% endfor %}</ul>
+{% endif %}
+
+{% for fieldset in adminform %}
+ {% include "admin/includes/fieldset.html" %}
+{% endfor %}
+
+{% block after_field_sets %}{% endblock %}
+
+{% for inline_admin_formset in inline_admin_formsets %}
+ {% include inline_admin_formset.opts.template %}
+{% endfor %}
+
+{% block after_related_objects %}{% endblock %}
+
+{% submit_row %}
+
+{% if add %}
+ <script type="text/javascript">document.getElementById("{{ adminform.first_field.auto_id }}").focus();</script>
+{% endif %}
+
+{# JavaScript for prepopulated fields #}
+
+{% if add %}
+<script type="text/javascript">
+{% for field in adminform.prepopulated_fields %}
+ document.getElementById("{{ field.field.auto_id }}").onchange = function() { this._changed = true; };
+ {% for dependency in field.dependencies %}
+ document.getElementById("{{ dependency.auto_id }}").onkeyup = function() {
+ var e = document.getElementById("{{ field.field.auto_id }}");
+ if (!e._changed) { e.value = URLify({% for innerdep in field.dependencies %}document.getElementById("{{ innerdep.auto_id }}").value{% if not forloop.last %} + ' ' + {% endif %}{% endfor %}, {{ field.field.field.max_length }}); }
+ }
+ {% endfor %}
+{% endfor %}
+</script>
+{% endif %}
+
+</div>
+</form></div>
+{% endblock %}
diff --git a/templates/admin/change_list.html b/templates/admin/change_list.html
new file mode 100644
index 0000000..24286a5
--- /dev/null
+++ b/templates/admin/change_list.html
@@ -0,0 +1,38 @@
+{% extends "admin/base_site.html" %}
+{% load adminmedia admin_list i18n %}
+
+{% block stylesheet %}{% admin_media_prefix %}css/changelists.css{% endblock %}
+
+{% block bodyclass %}change-list{% endblock %}
+
+{% if not is_popup %}{% block breadcrumbs %}<div class="breadcrumbs"><a href="../../">{% trans "Home" %}</a> &rsaquo; {{ cl.opts.verbose_name_plural|capfirst|escape }}</div>{% endblock %}{% endif %}
+
+{% block coltype %}flex{% endblock %}
+
+{% block content %}
+<div id="content-main">
+{% block object-tools %}
+{% if has_add_permission %}
+<ul class="object-tools"><li><a href="add/{% if is_popup %}?_popup=1{% endif %}" class="addlink">{% blocktrans with cl.opts.verbose_name|escape as name %}Add {{ name }}{% endblocktrans %}</a></li></ul>
+{% endif %}
+{% endblock %}
+<div class="module{% if cl.has_filters %} filtered{% endif %}" id="changelist">
+{% block search %}{% search_form cl %}{% endblock %}
+{% block date_hierarchy %}{% date_hierarchy cl %}{% endblock %}
+
+{% block filters %}
+{% if cl.has_filters %}
+<div id="changelist-filter">
+<h2>{% trans 'Filter' %}</h2>
+{% for spec in cl.filter_specs %}
+ {% admin_list_filter cl spec %}
+{% endfor %}
+</div>
+{% endif %}
+{% endblock %}
+
+{% block result_list %}{% result_list cl %}{% endblock %}
+{% block pagination %}{% pagination cl %}{% endblock %}
+</div>
+</div>
+{% endblock %}
diff --git a/templates/admin/change_list_results.html b/templates/admin/change_list_results.html
new file mode 100644
index 0000000..381dcb5
--- /dev/null
+++ b/templates/admin/change_list_results.html
@@ -0,0 +1,17 @@
+{% if results %}
+<table cellspacing="0">
+<thead>
+<tr>
+{% for header in result_headers %}<th{{ header.class_attrib }}>
+{% if header.sortable %}<a href="{{ header.url }}">{% endif %}
+{{ header.text|capfirst }}
+{% if header.sortable %}</a>{% endif %}</th>{% endfor %}
+</tr>
+</thead>
+<tbody>
+{% for result in results %}
+<tr class="{% cycle 'row1' 'row2' %}">{% for item in result %}{{ item }}{% endfor %}</tr>
+{% endfor %}
+</tbody>
+</table>
+{% endif %}
diff --git a/templates/admin/date_hierarchy.html b/templates/admin/date_hierarchy.html
new file mode 100644
index 0000000..0058510
--- /dev/null
+++ b/templates/admin/date_hierarchy.html
@@ -0,0 +1,10 @@
+{% if show %}
+<div class="xfull">
+<ul class="toplinks">
+{% if back %}<li class="date-back"><a href="{{ back.link }}">&lsaquo; {{ back.title }}</a></li>{% endif %}
+{% for choice in choices %}
+<li> {% if choice.link %}<a href="{{ choice.link }}">{% endif %}{{ choice.title }}{% if choice.link %}</a>{% endif %}</li>
+{% endfor %}
+</ul><br class="clear" />
+</div>
+{% endif %}
diff --git a/templates/admin/delete_confirmation.html b/templates/admin/delete_confirmation.html
new file mode 100644
index 0000000..386e134
--- /dev/null
+++ b/templates/admin/delete_confirmation.html
@@ -0,0 +1,31 @@
+{% extends "admin/base_site.html" %}
+{% load i18n %}
+
+{% block breadcrumbs %}
+<div class="breadcrumbs">
+ <a href="../../../../">{% trans "Home" %}</a> &rsaquo;
+ <a href="../../">{{ opts.verbose_name_plural|capfirst }}</a> &rsaquo;
+ <a href="../">{{ object|escape|truncatewords:"18" }}</a> &rsaquo;
+ {% trans 'Delete' %}
+</div>
+{% endblock %}
+
+{% block content %}
+{% if perms_lacking %}
+ <p>{% blocktrans with object|escape as escaped_object %}Deleting the {{ object_name }} '{{ escaped_object }}' would result in deleting related objects, but your account doesn't have permission to delete the following types of objects:{% endblocktrans %}</p>
+ <ul>
+ {% for obj in perms_lacking %}
+ <li>{{ obj }}</li>
+ {% endfor %}
+ </ul>
+{% else %}
+ <p>{% blocktrans with object|escape as escaped_object %}Are you sure you want to delete the {{ object_name }} "{{ escaped_object }}"? All of the following related items will be deleted:{% endblocktrans %}</p>
+ <ul>{{ deleted_objects|unordered_list }}</ul>
+ <form action="" method="post">
+ <div>
+ <input type="hidden" name="post" value="yes" />
+ <input type="submit" value="{% trans "Yes, I'm sure" %}" />
+ </div>
+ </form>
+{% endif %}
+{% endblock %}
diff --git a/templates/admin/edit_inline/stacked.html b/templates/admin/edit_inline/stacked.html
new file mode 100644
index 0000000..217791f
--- /dev/null
+++ b/templates/admin/edit_inline/stacked.html
@@ -0,0 +1,26 @@
+{% load i18n %}
+<div class="inline-group">
+ <h2>{{ inline_admin_formset.opts.verbose_name_plural|title }}</h2>
+{{ inline_admin_formset.formset.management_form }}
+{{ inline_admin_formset.formset.non_form_errors }}
+
+{% for inline_admin_form in inline_admin_formset %}
+<div class="inline-related {% if forloop.last %}last-related{% endif %}">
+ <h3><b>{{ inline_admin_formset.opts.verbose_name|title }}:</b>&nbsp;{% if inline_admin_form.original %}{{ inline_admin_form.original }}{% else %} #{{ forloop.counter }}{% endif %}
+ {% if inline_admin_formset.formset.can_delete and inline_admin_form.original %}<span class="delete">{{ inline_admin_form.deletion_field.field }} {{ inline_admin_form.deletion_field.label_tag }}</span>{% endif %}
+ </h3>
+ {% if inline_admin_form.show_url %}
+ <p><a href="/r/{{ inline_admin_form.original.content_type_id }}/{{ inline_admin_form.original.id }}/">View on site</a></p>
+ {% endif %}
+
+ {% for fieldset in inline_admin_form %}
+ {% include "admin/includes/fieldset.html" %}
+ {% endfor %}
+ {{ inline_admin_form.pk_field.field }}
+</div>
+{% endfor %}
+
+{# <ul class="tools"> #}
+{# <li><a class="add" href="">Add another {{ inline_admin_formset.opts.verbose_name|title }}</a></li> #}
+{# </ul> #}
+</div>
diff --git a/templates/admin/edit_inline/tabular.html b/templates/admin/edit_inline/tabular.html
new file mode 100644
index 0000000..f3fe378
--- /dev/null
+++ b/templates/admin/edit_inline/tabular.html
@@ -0,0 +1,67 @@
+{% load i18n %}
+<div class="inline-group">
+ <div class="tabular inline-related {% if forloop.last %}last-related{% endif %}">
+{{ inline_admin_formset.formset.management_form }}
+<fieldset class="module">
+ <h2>{{ inline_admin_formset.opts.verbose_name_plural|capfirst|escape }}</h2>
+ {{ inline_admin_formset.formset.non_form_errors }}
+ <table>
+ <thead><tr>
+ {% for field in inline_admin_formset.fields %}
+ {% if not field.is_hidden %}
+ <th {% if forloop.first %}colspan="2"{% endif %}>{{ field.label|capfirst|escape }}</th>
+ {% endif %}
+ {% endfor %}
+ {% if inline_admin_formset.formset.can_delete %}<th>{% trans "Delete" %}?</th>{% endif %}
+ </tr></thead>
+
+ {% for inline_admin_form in inline_admin_formset %}
+
+ <tr class="{% cycle row1,row2 %} {% if inline_admin_form.original or inline_admin_form.show_url %}has_original{% endif %}">
+
+ <td class="original">
+ {% if inline_admin_form.original or inline_admin_form.show_url %}<p>
+ {% if inline_admin_form.original %} {{ inline_admin_form.original }}{% endif %}
+ {% if inline_admin_form.show_url %}<a href="/r/{{ inline_admin_form.original.content_type_id }}/{{ inline_admin_form.original.id }}/">View on site</a>{% endif %}
+ </p>{% endif %}
+ {{ inline_admin_form.pk_field.field }}
+ {% spaceless %}
+ {% for fieldset in inline_admin_form %}
+ {% for line in fieldset %}
+ {% for field in line %}
+ {% if field.is_hidden %} {{ field.field }} {% endif %}
+ {% endfor %}
+ {% endfor %}
+ {% endfor %}
+ {% endspaceless %}
+ </td>
+
+ {% for fieldset in inline_admin_form %}
+ {% for line in fieldset %}
+ {% for field in line %}
+ <td class="{{ field.field.name }}">
+ {{ field.field.errors.as_ul }}
+ {{ field.field }}
+ </td>
+ {% endfor %}
+ {% endfor %}
+ {% endfor %}
+
+ {% if inline_admin_formset.formset.can_delete %}
+ <td class="delete">{% if inline_admin_form.original %}{{ inline_admin_form.deletion_field.field }}{% endif %}</td>
+ {% endif %}
+
+ </tr>
+
+ {% endfor %}
+
+ </table>
+
+</fieldset>
+ </div>
+
+ {# <ul class="tools"> #}
+ {# <li><a class="add" href="">Add another {{ inline_admin_formset.opts.verbose_name|title }}</a></li> #}
+ {# </ul> #}
+
+</div>
diff --git a/templates/admin/filter.html b/templates/admin/filter.html
new file mode 100644
index 0000000..bcc64ac
--- /dev/null
+++ b/templates/admin/filter.html
@@ -0,0 +1,8 @@
+{% load i18n %}
+<h3>{% blocktrans with title|escape as filter_title %} By {{ filter_title }} {% endblocktrans %}</h3>
+<ul>
+{% for choice in choices %}
+ <li{% if choice.selected %} class="selected"{% endif %}>
+ <a href="{{ choice.query_string|iriencode }}">{{ choice.display|escape }}</a></li>
+{% endfor %}
+</ul>
diff --git a/templates/admin/includes/fieldset.html b/templates/admin/includes/fieldset.html
new file mode 100644
index 0000000..27e54c7
--- /dev/null
+++ b/templates/admin/includes/fieldset.html
@@ -0,0 +1,17 @@
+<fieldset class="module aligned {{ fieldset.classes }}">
+ {% if fieldset.name %}<h2>{{ fieldset.name }}</h2>{% endif %}
+ {% if fieldset.description %}<div class="description">{{ fieldset.description|safe }}</div>{% endif %}
+ {% for line in fieldset %}
+ <div class="form-row{% if line.errors %} errors{% endif %} {% for field in line %}{{ field.field.name }} {% endfor %} ">
+ {{ line.errors }}
+ {% for field in line %}
+ {% if field.is_checkbox %}
+ {{ field.field }}{{ field.label_tag }}
+ {% else %}
+ {{ field.label_tag }}{{ field.field }}
+ {% endif %}
+ {% if field.field.field.help_text %}<p class="help">{{ field.field.field.help_text|safe }}</p>{% endif %}
+ {% endfor %}
+ </div>
+ {% endfor %}
+</fieldset>
diff --git a/templates/admin/index.html b/templates/admin/index.html
new file mode 100644
index 0000000..074be03
--- /dev/null
+++ b/templates/admin/index.html
@@ -0,0 +1,68 @@
+{% extends "admin/base_site.html" %}
+{% load i18n %}
+
+{% block stylesheet %}{% load adminmedia %}{% admin_media_prefix %}css/dashboard.css{% endblock %}
+
+{% block coltype %}colMS{% endblock %}
+
+{% block bodyclass %}dashboard{% endblock %}
+
+{% block breadcrumbs %}{% endblock %}
+
+{% block content %}
+<div id="content-main">
+
+{% if app_list %}
+ {% for app in app_list %}
+ <div class="module">
+ <table summary="{% blocktrans with app.name as name %}Models available in the {{ name }} application.{% endblocktrans %}">
+ <caption>{% blocktrans with app.name as name %}{{ name }}{% endblocktrans %}</caption>
+ {% for model in app.models %}
+ <tr>
+ {% if model.perms.change %}
+ <th scope="row"><a href="{{ model.admin_url }}">{{ model.name }}</a></th>
+ {% else %}
+ <th scope="row">{{ model.name }}</th>
+ {% endif %}
+
+ {% if model.perms.add %}
+ <td><a href="{{ model.admin_url }}add/" class="addlink">{% trans 'Add' %}</a></td>
+ {% else %}
+ <td>&nbsp;</td>
+ {% endif %}
+
+ {% if model.perms.change %}
+ <td><a href="{{ model.admin_url }}" class="changelink">{% trans 'Change' %}</a></td>
+ {% else %}
+ <td>&nbsp;</td>
+ {% endif %}
+ </tr>
+ {% endfor %}
+ </table>
+ </div>
+ {% endfor %}
+{% else %}
+ <p>{% trans "You don't have permission to edit anything." %}</p>
+{% endif %}
+</div>
+{% endblock %}
+
+{% block sidebar %}
+<div id="content-related">
+ <div class="module" id="recent-actions-module">
+ <h2>{% trans 'Recent Actions' %}</h2>
+ <h3>{% trans 'My Actions' %}</h3>
+ {% load log %}
+ {% get_admin_log 10 as admin_log for_user user %}
+ {% if not admin_log %}
+ <p>{% trans 'None available' %}</p>
+ {% else %}
+ <ul class="actionlist">
+ {% for entry in admin_log %}
+ <li class="{% if entry.is_addition %}addlink{% endif %}{% if entry.is_change %}changelink{% endif %}{% if entry.is_deletion %}deletelink{% endif %}">{% if not entry.is_deletion %}<a href="{{ entry.get_admin_url }}">{% endif %}{{ entry.object_repr|escape }}{% if not entry.is_deletion %}</a>{% endif %}<br /><span class="mini quiet">{% filter capfirst %}{% trans entry.content_type.name %}{% endfilter %}</span></li>
+ {% endfor %}
+ </ul>
+ {% endif %}
+ </div>
+</div>
+{% endblock %}
diff --git a/templates/admin/invalid_setup.html b/templates/admin/invalid_setup.html
new file mode 100644
index 0000000..f09b316
--- /dev/null
+++ b/templates/admin/invalid_setup.html
@@ -0,0 +1,8 @@
+{% extends "admin/base_site.html" %}
+{% load i18n %}
+
+{% block breadcrumbs %}<div class="breadcrumbs"><a href="../../">{% trans 'Home' %}</a> &rsaquo; {{ title }}</div>{% endblock %}
+
+{% block content %}
+<p>{% trans "Something's wrong with your database installation. Make sure the appropriate database tables have been created, and make sure the database is readable by the appropriate user." %}</p>
+{% endblock %}
diff --git a/templates/admin/login.html b/templates/admin/login.html
new file mode 100644
index 0000000..5dd953b
--- /dev/null
+++ b/templates/admin/login.html
@@ -0,0 +1,35 @@
+{% extends "admin/base_site.html" %}
+{% load i18n %}
+
+{% block stylesheet %}{% load adminmedia %}{% admin_media_prefix %}css/login.css{% endblock %}
+
+{% block bodyclass %}login{% endblock %}
+
+{% block content_title %}{% endblock %}
+
+{% block breadcrumbs %}{% endblock %}
+
+{% block content %}
+{% if error_message %}
+<p class="errornote">{{ error_message }}</p>
+{% endif %}
+<div id="content-main">
+<form action="{{ app_path }}" method="post" id="login-form">
+ <div class="form-row">
+ <label for="id_username">{% trans 'Username:' %}</label> <input type="text" name="username" id="id_username" />
+ </div>
+ <div class="form-row">
+ <label for="id_password">{% trans 'Password:' %}</label> <input type="password" name="password" id="id_password" />
+ <input type="hidden" name="this_is_the_login_form" value="1" />
+ <input type="hidden" name="post_data" value="{{ post_data }}" /> {#<span class="help">{% trans 'Have you <a href="/password_reset/">forgotten your password</a>?' %}</span>#}
+ </div>
+ <div class="submit-row">
+ <label>&nbsp;</label><input type="submit" value="{% trans 'Log in' %}" />
+ </div>
+</form>
+
+<script type="text/javascript">
+document.getElementById('id_username').focus()
+</script>
+</div>
+{% endblock %}
diff --git a/templates/admin/object_history.html b/templates/admin/object_history.html
new file mode 100644
index 0000000..19c037c
--- /dev/null
+++ b/templates/admin/object_history.html
@@ -0,0 +1,36 @@
+{% extends "admin/base_site.html" %}
+{% load i18n %}
+
+{% block breadcrumbs %}
+<div class="breadcrumbs"><a href="../../../../">{% trans 'Home' %}</a> &rsaquo; <a href="../../">{{ module_name }}</a> &rsaquo; <a href="../">{{ object|truncatewords:"18" }}</a> &rsaquo; {% trans 'History' %}</div>
+{% endblock %}
+
+{% block content %}
+<div id="content-main">
+<div class="module">
+
+{% if action_list %}
+ <table id="change-history">
+ <thead>
+ <tr>
+ <th scope="col">{% trans 'Date/time' %}</th>
+ <th scope="col">{% trans 'User' %}</th>
+ <th scope="col">{% trans 'Action' %}</th>
+ </tr>
+ </thead>
+ <tbody>
+ {% for action in action_list %}
+ <tr>
+ <th scope="row">{{ action.action_time|date:_("DATE_WITH_TIME_FULL") }}</th>
+ <td>{{ action.user.username }}{% if action.user.first_name %} ({{ action.user.first_name }} {{ action.user.last_name }}){% endif %}</td>
+ <td>{{ action.change_message }}</td>
+ </tr>
+ {% endfor %}
+ </tbody>
+ </table>
+{% else %}
+ <p>{% trans "This object doesn't have a change history. It probably wasn't added via this admin site." %}</p>
+{% endif %}
+</div>
+</div>
+{% endblock %}
diff --git a/templates/admin/pagination.html b/templates/admin/pagination.html
new file mode 100644
index 0000000..0640a46
--- /dev/null
+++ b/templates/admin/pagination.html
@@ -0,0 +1,11 @@
+{% load admin_list %}
+{% load i18n %}
+<p class="paginator">
+{% if pagination_required %}
+{% for i in page_range %}
+ {% paginator_number cl i %}
+{% endfor %}
+{% endif %}
+{{ cl.result_count }} {% ifequal cl.result_count 1 %}{{ cl.opts.verbose_name|escape }}{% else %}{{ cl.opts.verbose_name_plural }}{% endifequal %}
+{% if show_all_url %}&nbsp;&nbsp;<a href="{{ show_all_url }}" class="showall">{% trans 'Show all' %}</a>{% endif %}
+</p>
diff --git a/templates/admin/search_form.html b/templates/admin/search_form.html
new file mode 100644
index 0000000..b232aa9
--- /dev/null
+++ b/templates/admin/search_form.html
@@ -0,0 +1,18 @@
+{% load adminmedia %}
+{% load i18n %}
+{% if cl.search_fields %}
+<div id="toolbar"><form id="changelist-search" action="" method="get">
+<div><!-- DIV needed for valid HTML -->
+<label for="searchbar"><img src="{% admin_media_prefix %}img/admin/icon_searchbox.png" alt="Search" /></label>
+<input type="text" size="40" name="{{ search_var }}" value="{{ cl.query|escape }}" id="searchbar" />
+<input type="submit" value="{% trans 'Go' %}" />
+{% if show_result_count %}
+ <span class="small quiet">{% blocktrans count cl.result_count as counter %}1 result{% plural %}{{ counter }} results{% endblocktrans %} (<a href="?{% if cl.is_popup %}pop=1{% endif %}">{% blocktrans with cl.full_result_count as full_result_count %}{{ full_result_count }} total{% endblocktrans %}</a>)</span>
+{% endif %}
+{% for pair in cl.params.items %}
+ {% ifnotequal pair.0 search_var %}<input type="hidden" name="{{ pair.0|escape }}" value="{{ pair.1|escape }}"/>{% endifnotequal %}
+{% endfor %}
+</div>
+</form></div>
+<script type="text/javascript">document.getElementById("searchbar").focus();</script>
+{% endif %}
diff --git a/templates/admin/submit_line.html b/templates/admin/submit_line.html
new file mode 100644
index 0000000..3ff80ad
--- /dev/null
+++ b/templates/admin/submit_line.html
@@ -0,0 +1,8 @@
+{% load i18n %}
+<div class="submit-row">
+{% if show_delete_link %}<p class="float-left"><a href="delete/" class="deletelink">{% trans "Delete" %}</a></p>{% endif %}
+{% if show_save_as_new %}<input type="submit" value="{% trans 'Save as new' %}" name="_saveasnew" {{ onclick_attrib }}/>{%endif%}
+{% if show_save_and_add_another %}<input type="submit" value="{% trans 'Save and add another' %}" name="_addanother" {{ onclick_attrib }} />{% endif %}
+{% if show_save_and_continue %}<input type="submit" value="{% trans 'Save and continue editing' %}" name="_continue" {{ onclick_attrib }}/>{% endif %}
+{% if show_save %}<input type="submit" value="{% trans 'Save' %}" class="default" name="_save" {{ onclick_attrib }}/>{% endif %}
+</div>
diff --git a/templates/admin/template_validator.html b/templates/admin/template_validator.html
new file mode 100644
index 0000000..422e902
--- /dev/null
+++ b/templates/admin/template_validator.html
@@ -0,0 +1,31 @@
+{% extends "admin/base_site.html" %}
+
+{% block content %}
+
+<div id="content-main">
+
+<form action="" method="post">
+
+{% if form.error_dict %}
+<p class="errornote">Your template had {{ form.error_dict.items|length }} error{{ form.error_dict.items|pluralize }}:</p>
+{% endif %}
+
+<fieldset class="module aligned">
+<div class="form-row{% if form.site.errors %} error{% endif %} required">
+ {% if form.site.errors %}{{ form.site.html_error_list }}{% endif %}
+ <h4><label for="id_site">Site:</label> {{ form.site }}</h4>
+</div>
+<div class="form-row{% if form.template.errors %} error{% endif %} required">
+ {% if form.template.errors %}{{ form.template.html_error_list }}{% endif %}
+ <h4><label for="id_template">Template:</label> {{ form.template }}</h4>
+</div>
+</fieldset>
+
+<div class="submit-row">
+ <input type="submit" value="Check for errors" class="default" />
+</div>
+
+</form>
+</div>
+
+{% endblock %}
diff --git a/templates/layout.html b/templates/layout.html
new file mode 100644
index 0000000..2da8fa1
--- /dev/null
+++ b/templates/layout.html
@@ -0,0 +1,40 @@
+<!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" xml:lang="en">
+<head>
+ <meta http-equiv="content-type" content="text/html; charset=utf-8" />
+ <meta name="description" content="Your description goes here" />
+ <meta name="keywords" content="your,keywords,goes,here" />
+ <meta name="author" content="Sébastien Dusuel" />
+ <link rel="stylesheet" type="text/css" href="{{ MEDIA_URL }}andreas03.css" />
+ <title>{% block title %}{{ site.name }}{% endblock %}</title>
+ {% block head %}{% endblock %}
+</head>
+
+<body>
+ <div id="top">
+ <p class="hide">Skip to: <a href="#sitemenu" accesskey="2">Site menu</a> | <a href="#maincontent" accesskey="3">Main content</a></p>
+ </div>
+
+ <div id="container">
+ <div id="main">
+ {% block logo %}{% endblock %}
+
+ {% block content %}
+ <div id="intro">
+ <h2 id="maincontent">{{ pagetitle }}</h2>
+ </div>
+ {{ content|safe }}
+ {% endblock %}
+ </div>
+
+ {% block menu %}{% endblock %}
+ <div class="clear">&nbsp;</div>
+ </div>
+
+ <div id="footer">
+ <p>
+ {% block footer %}<br />{% endblock %}
+ </p>
+ </div>
+</body>
+</html>
diff --git a/templates/main/base.html b/templates/main/base.html
new file mode 100644
index 0000000..b8a56a4
--- /dev/null
+++ b/templates/main/base.html
@@ -0,0 +1,28 @@
+{% extends "layout.html" %}
+
+{% block logo %}
+ <div id="logo">
+ <h1><a href="/" accesskey="4">Spé MP1</a></h1>
+ <span id="tagline">@ Saint-Louis</span>
+ </div>
+{% endblock %}
+
+{% block menu %}
+ <div id="sidebar">
+ {% block menucontent %}
+ <h2 id="sitemenu" class="sidelink menuheader">Menu of Physics</h2>
+ {% for page in pages %}
+ <a class="sidelink" href="/{{ page.name }}.html">{{ page.title }}</a><span class="hide"> | </span>
+ {% endfor %}
+ {% if user.is_staff %}
+ <a class="sidelink" href="/admin/">Administration</a><span class="hide"> | </span>
+ {% endif %}
+ <a class="sidelink" href="/logout/">Déconnexion</a><span class="hide"> | </span>
+ <a class="hide" href="#top" accesskey="1">Top of page</a>
+ {% endblock %}
+ </div>
+{% endblock %}
+
+{% block footer %}
+ [<a href="#top">Back to top</a>]
+{% endblock %}
diff --git a/templates/main/calendar_page.html b/templates/main/calendar_page.html
new file mode 100644
index 0000000..f1c21e6
--- /dev/null
+++ b/templates/main/calendar_page.html
@@ -0,0 +1,21 @@
+{% extends "main/simple_page.html" %}
+{% load utils %}
+
+{% block content %}
+ <div id="intro">
+ <h2 id="maincontent">{{ pagetitle }}</h2>
+ {{ content|safe }}
+ </div>
+ <h2 class="headerstyle">DSs</h2>
+ <ol>
+ {% for test in tests %}
+ <li> DS {{ test.number }} : {{ test.date|date:"d/m/y" }}</li>
+ {% endfor %}
+ </ol>
+ <h2 class="headerstyle">Colles</h2>
+ <ol>
+ {% for colle in colles %}
+ <li> <a href="/get/colle/{{ colle.mainfile|basename }}">{{ colle.name }}</a></li>
+ {% endfor %}
+ </ol>
+{% endblock %}
diff --git a/templates/main/file_page.html b/templates/main/file_page.html
new file mode 100644
index 0000000..486e0ea
--- /dev/null
+++ b/templates/main/file_page.html
@@ -0,0 +1,17 @@
+{% extends "main/simple_page.html" %}
+{% load utils %}
+
+{% block content %}
+ <div id="intro">
+ <h2 id="maincontent">{{ pagetitle }}</h2>
+ {{ content|safe }}
+ </div>
+ {% for type in filetypes %}
+ <h2 class="headerstyle">{{ filetypenames|hash:type }}</h2>
+ <ol>
+ {% for file in files|hash:type %}
+ {{ file }}
+ {% endfor %}
+ </ol>
+ {% endfor %}
+{% endblock %}
diff --git a/templates/main/file_poly.html b/templates/main/file_poly.html
new file mode 100644
index 0000000..eaf8de7
--- /dev/null
+++ b/templates/main/file_poly.html
@@ -0,0 +1 @@
+<li> <a href="/get/poly/{{ file.mainfilename }}">{{ file.name }}</a></li>
diff --git a/templates/main/file_td.html b/templates/main/file_td.html
new file mode 100644
index 0000000..bfeeb1b
--- /dev/null
+++ b/templates/main/file_td.html
@@ -0,0 +1,6 @@
+{% load utils %}
+
+<li> {{ file.name }}<br />
+[<a href="/get/td/{{ file.mainfile|basename }}">Énoncé</a>
+| <a href="/get/td/{{ file.solution|basename }}">Corrigé</a>]
+</li>
diff --git a/templates/main/file_tp.html b/templates/main/file_tp.html
new file mode 100644
index 0000000..6718e46
--- /dev/null
+++ b/templates/main/file_tp.html
@@ -0,0 +1,3 @@
+<li> {{ file.name }}<br />
+[<a href="/get/tp/{{ file.mainfilename }}">Énoncé</a>]
+</li>
diff --git a/templates/main/loggedout.html b/templates/main/loggedout.html
new file mode 100644
index 0000000..2157b4c
--- /dev/null
+++ b/templates/main/loggedout.html
@@ -0,0 +1,16 @@
+{% extends "main/base.html" %}
+
+{% block content %}Pour vous connecter, veuillez remplir le formulaire de droite avec les identifiants qui vous ont été communiqués en classe.
+{% endblock %}
+
+{% block menucontent %}
+ <h3>Connexion</h3>
+ <form method="post" action="/login/" id="login">
+ <ul>
+ {{ login_form.as_ul }}
+ </ul>
+ <div style="text-align: center; width: 100%;">
+ <input type="submit" value="Connexion" id="login-submit" />
+ </div>
+ </form>
+{% endblock %}
diff --git a/templates/main/raw_page.html b/templates/main/raw_page.html
new file mode 100644
index 0000000..50e42b6
--- /dev/null
+++ b/templates/main/raw_page.html
@@ -0,0 +1,3 @@
+{% extends "main/simple_page.html" %}
+
+{% block content %}{{ content|safe }}{% endblock %}
diff --git a/templates/main/simple_page.html b/templates/main/simple_page.html
new file mode 100644
index 0000000..ffd3191
--- /dev/null
+++ b/templates/main/simple_page.html
@@ -0,0 +1,3 @@
+{% extends "main/base.html" %}
+
+{% block title %}{{ block.super }} ~ {{ pagetitle }}{% endblock %}
diff --git a/templates/redirect.html b/templates/redirect.html
new file mode 100644
index 0000000..5aedc38
--- /dev/null
+++ b/templates/redirect.html
@@ -0,0 +1,14 @@
+{% extends "layout.html" %}
+
+{% block head %}
+ <script type="text/javascript">
+ function redir () {
+ window.location = "{{ redirect_to }}";
+ }
+ setTimeout (redir, {{ redirect_delay }});
+ </script>
+{% endblock %}
+
+{% block title %}{{ block.super }} ~ Redirection{% endblock %}
+
+{% block content %}<div style="text-align: center; font-size: 1.4em;">{{ redirect_message }}</div>{% endblock %}
diff --git a/urls.py b/urls.py
new file mode 100644
index 0000000..4df1c23
--- /dev/null
+++ b/urls.py
@@ -0,0 +1,33 @@
+# coding: utf8
+
+'''
+Copyright (C) 2008 Guillaume Seguin <guillaume@segu.in>
+
+This application is free software: you can redistribute it and/or modify
+it under the terms of the GNU Affero General Public License as
+published by the Free Software Foundation, either version 3 of the
+License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU Affero General Public License for more details.
+
+You should have received a copy of the GNU Affero General Public License
+along with this application. If not, see <http://www.gnu.org/licenses/>.
+'''
+
+from django.conf.urls.defaults import *
+
+from django.contrib import admin
+admin.autodiscover()
+
+urlpatterns = patterns('',
+ (r'^$', "dusu_website.main.views.home_view"),
+ (r'^logout/$', 'dusu_website.main.views.logout_view'),
+ (r'^login/$', 'dusu_website.main.views.login_view'),
+ (r'^admin/(.*)', admin.site.root),
+ (r'^get/(?P<type>\w{1,5})/(?P<file_name>.+)',
+ "dusu_website.main.views.file_view"),
+ (r'^(?P<page_name>.+)\.html', "dusu_website.main.views.page_view"),
+)