commit 8e1bf7b70515be585134e4cd03b924e72df8e220 Author: Guillaume Seguin Date: Wed Jun 27 23:28:35 2012 +0200 Initial import diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..1559f2e9 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +*.pyc +*.swp +*.swo diff --git a/__init__.py b/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/apache/django.wsgi b/apache/django.wsgi new file mode 100755 index 00000000..9e0290f7 --- /dev/null +++ b/apache/django.wsgi @@ -0,0 +1,7 @@ +import os, sys +sys.path.append (os.path.expanduser ('~gestion/www')) +os.environ['DJANGO_SETTINGS_MODULE'] = 'settings' + +import django.core.handlers.wsgi + +application = django.core.handlers.wsgi.WSGIHandler() diff --git a/gestioncof/__init__.py b/gestioncof/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/gestioncof/admin.py b/gestioncof/admin.py new file mode 100644 index 00000000..3ebc50f5 --- /dev/null +++ b/gestioncof/admin.py @@ -0,0 +1,65 @@ +# coding: utf-8 + +from django.contrib import admin +from gestioncof.models import Survey, SurveyQuestion, SurveyQuestionAnswer +from gestioncof.models import Event, EventOption, EventOptionChoice +from django.core.urlresolvers import reverse +from django.utils.safestring import mark_safe + +def add_link_field(target_model = '', field = '', link_text = unicode, desc_text = unicode): + def add_link(cls): + reverse_name = target_model or cls.model.__name__.lower() + def link(self, instance): + app_name = instance._meta.app_label + reverse_path = "admin:%s_%s_change" % (app_name, reverse_name) + link_obj = getattr(instance, field, None) or instance + if not link_obj.id: + return "" + url = reverse(reverse_path, args = (link_obj.id,)) + return mark_safe("%s" % (url, link_text(link_obj))) + link.allow_tags = True + link.short_description = desc_text(reverse_name + ' link') + cls.link = link + cls.readonly_fields = list(getattr(cls, 'readonly_fields', [])) + ['link'] + return cls + return add_link + +class SurveyQuestionAnswerInline(admin.TabularInline): + model = SurveyQuestionAnswer + +@add_link_field(desc_text = lambda x: "Réponses", link_text = lambda x: "Éditer les réponses") +class SurveyQuestionInline(admin.TabularInline): + model = SurveyQuestion + +class SurveyQuestionAdmin(admin.ModelAdmin): + inlines = [ + SurveyQuestionAnswerInline, + ] + +class SurveyAdmin(admin.ModelAdmin): + inlines = [ + SurveyQuestionInline, + ] + +@add_link_field() +class EventOptionChoiceInline(admin.StackedInline): + model = EventOptionChoice + +@add_link_field() +class EventOptionInline(admin.StackedInline): + model = EventOption + +class EventOptionAdmin(admin.ModelAdmin): + inlines = [ + EventOptionChoiceInline, + ] + +class EventAdmin(admin.ModelAdmin): + inlines = [ + EventOptionInline, + ] + +admin.site.register(Survey, SurveyAdmin) +admin.site.register(SurveyQuestion, SurveyQuestionAdmin) +admin.site.register(Event, EventAdmin) +admin.site.register(EventOption, EventOptionAdmin) diff --git a/gestioncof/models.py b/gestioncof/models.py new file mode 100644 index 00000000..57e40180 --- /dev/null +++ b/gestioncof/models.py @@ -0,0 +1,130 @@ +# coding: utf-8 + +from django.db import models +from django.contrib.auth.models import User +from django.utils.translation import ugettext_lazy as _ +from django.db.models.signals import post_save + +OCCUPATION_CHOICES = ( + ('exterieur', _(u"Extérieur")), + ('1A', _(u"1A")), + ('2A', _(u"2A")), + ('3A', _(u"3A")), + ('4A', _(u"4A")), + ('archicube', _(u"Archicube")), + ('doctorant', _(u"Doctorant")), + ('CST', _(u"CST")), +) + +TYPE_COTIZ_CHOICES = ( + ('etudiant', _(u"Étudiant")), + ('normalien', _(u"Normalien")), + ('exterieur', _(u"Extérieur")), +) + +def choices_length (choices): + return reduce (lambda m, choice: max (m, len (choice[0])), choices, 0) + +class CofProfile(models.Model): + user = models.OneToOneField(User) + login_clipper = models.CharField("Login clipper", max_length = 8) + is_cof = models.BooleanField("Membre du COF", default = False) + occupation = models.CharField (_(u"Occupation"), + default = "1A", + choices = OCCUPATION_CHOICES, + max_length = choices_length (OCCUPATION_CHOICES)) + type_cotiz = models.CharField (_(u"Type de cotisation"), + default = "normalien", + choices = TYPE_COTIZ_CHOICES, + max_length = choices_length (TYPE_COTIZ_CHOICES)) + mailing_cof = models.BooleanField("Recevoir les mails COF", default = True) + mailing_bda_revente = models.BooleanField("Recevoir les mails de revente de places BDA", default = True) + is_buro = models.BooleanField("Membre du Burô", default = False) + +def create_user_profile(sender, instance, created, **kwargs): + if created: + CofProfile.objects.create(user = instance) +post_save.connect(create_user_profile, sender = User) + +class Event(models.Model): + title = models.CharField("Titre", max_length = 200) + location = models.CharField("Lieu", max_length = 200) + start_date = models.DateField("Date de début", blank = True) + end_date = models.DateField("Date de fin", blank = True) + description = models.TextField("Description", blank = True) + registration_open = models.BooleanField("Inscriptions ouvertes", default = True) + + class Meta: + verbose_name = "Événement" + + def __unicode__(self): + return unicode(self.title) + +class EventOption(models.Model): + event = models.ForeignKey(Event) + name = models.CharField("Option", max_length = 200) + + class Meta: + verbose_name = "Option" + + def __unicode__(self): + return unicode(self.name) + +class EventOptionChoice(models.Model): + event_option = models.ForeignKey(EventOption) + value = models.CharField("Valeur", max_length = 200) + + class Meta: + verbose_name = "Choix" + + def __unicode__(self): + return unicode(self.value) + +class EventRegistration(models.Model): + user = models.ForeignKey(User) + event = models.ForeignKey(Event) + options = models.ManyToManyField(EventOptionChoice) + paid = models.BooleanField("A payé", default = False) + + class Meta: + verbose_name = "Inscription" + +class Survey(models.Model): + title = models.CharField("Titre", max_length = 200) + details = models.TextField("Détails", blank = True) + survey_open = models.BooleanField("Sondage ouvert", default = True) + + class Meta: + verbose_name = "Sondage" + + def __unicode__(self): + return unicode(self.title) + +class SurveyQuestion(models.Model): + survey = models.ForeignKey(Survey, related_name = "questions") + question = models.CharField("Question", max_length = 200) + multi_answers = models.BooleanField("Choix multiples", default = False) + + class Meta: + verbose_name = "Question" + + def __unicode__(self): + return unicode(self.question) + +class SurveyQuestionAnswer(models.Model): + survey_question = models.ForeignKey(SurveyQuestion, related_name = "answers") + answer = models.CharField("Réponse", max_length = 200) + + class Meta: + verbose_name = "Réponse" + + def __unicode__(self): + return unicode(self.answer) + +class SurveyAnswer(models.Model): + user = models.ForeignKey(User) + survey = models.ForeignKey(Survey) + answers = models.ManyToManyField(SurveyQuestionAnswer) + + class Meta: + verbose_name = "Réponses" diff --git a/gestioncof/shared.py b/gestioncof/shared.py new file mode 100644 index 00000000..8c316c6c --- /dev/null +++ b/gestioncof/shared.py @@ -0,0 +1,24 @@ +from django.contrib.sites.models import Site +from django.conf import settings +from django_cas.backends import CASBackend + +class COFCASBackend(CASBackend): + def authenticate(self, ticket, service): + """Authenticates CAS ticket and retrieves user data""" + user = super(COFCASBackend, self).authenticate(ticket, service) + profile = user.get_profile() + if not profile.login_clipper: + profile.login_clipper = user.username + profile.save() + if not user.email: + user.email = settings.CAS_EMAIL_FORMAT % profile.login_clipper + user.save() + return user + +def context_processor (request): + '''Append extra data to the context of the given request''' + data = { + "user": request.user, + "site": Site.objects.get_current(), + } + return data diff --git a/gestioncof/tests.py b/gestioncof/tests.py new file mode 100644 index 00000000..501deb77 --- /dev/null +++ b/gestioncof/tests.py @@ -0,0 +1,16 @@ +""" +This file demonstrates writing tests using the unittest module. These will pass +when you run "manage.py test". + +Replace this 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.assertEqual(1 + 1, 2) diff --git a/gestioncof/views.py b/gestioncof/views.py new file mode 100644 index 00000000..6f1afb3c --- /dev/null +++ b/gestioncof/views.py @@ -0,0 +1,108 @@ +from django.shortcuts import redirect, get_object_or_404 +from django.template import RequestContext, loader +from django.http import HttpResponse, HttpResponseRedirect, Http404 +from django.core.urlresolvers import reverse +from django.contrib.auth.models import User +from django.contrib.auth.decorators import login_required +from django import forms +from django.forms.widgets import RadioSelect, CheckboxSelectMultiple +from gestioncof.models import Survey, SurveyQuestion, SurveyQuestionAnswer, SurveyAnswer +from gestioncof.models import Event, EventOption, EventOptionChoice, EventRegistration + +def render_page (request, data, template): + template = loader.get_template (template) + context = RequestContext (request, data) + return HttpResponse (template.render (context)) + +@login_required +def home(request): + data = {"surveys": Survey.objects.filter(survey_open = True).all(), + "events": Event.objects.filter(registration_open = True).all()} + return render_page(request, data, "home.html") + +def login(request): + if request.user.is_authenticated(): + return redirect("gestioncof.views.home") + return render_page(request, {}, "login_switch.html") + +@login_required +def logout(request): + if request.user.get_profile().login_clipper: + return redirect("django_cas.views.logout") + else: + return redirect("django.contrib.auth.views.logout") + +class SurveyForm(forms.Form): + def __init__(self, *args, **kwargs): + survey = kwargs.pop("survey") + current_answers = kwargs.pop("current_answers", None) + super(SurveyForm, self).__init__(*args, **kwargs) + answers = {} + if current_answers: + for answer in current_answers.all(): + if answer.survey_question.id not in answers: + answers[answer.survey_question.id] = [answer.id] + else: + answers[answer.survey_question.id].append(answer.id) + for question in survey.questions.all(): + choices = [(answer.id, answer.answer) for answer in question.answers.all()] + if question.multi_answers: + initial = [] if question.id not in answers else answers[question.id] + field = forms.MultipleChoiceField(label = question.question, + choices = choices, + widget = CheckboxSelectMultiple, + required = False, + initial = initial) + else: + initial = None if question.id not in answers else answers[question.id][0] + field = forms.ChoiceField(label = question.question, + choices = choices, + widget = RadioSelect, + required = False, + initial = initial) + field.question_id = question.id + self.fields["question_%d" % question.id] = field + + def answers(self): + for name, value in self.cleaned_data.items(): + if name.startswith('question_'): + yield (self.fields[name].question_id, value) + +@login_required +def survey(request, survey_id): + survey = get_object_or_404(Survey, id = survey_id) + if not survey.survey_open: + raise Http404 + success = False + if request.method == "POST": + form = SurveyForm(request.POST, survey = survey) + if form.is_valid(): + all_answers = [] + for question_id, answers_ids in form.answers(): + question = get_object_or_404(SurveyQuestion, id = question_id, + survey = survey) + if type(answers_ids) != list: + answers_ids = [answers_ids] + if not question.multi_answers and len(answers_ids) > 1: + raise Http404 + for answer_id in answers_ids: + answer_id = int(answer_id) + answer = SurveyQuestionAnswer.objects.get( + id = answer_id, + survey_question = question) + all_answers.append(answer) + try: + current_answer = SurveyAnswer.objects.get(user = request.user, survey = survey) + except SurveyAnswer.DoesNotExist: + current_answer = SurveyAnswer(user = request.user, survey = survey) + current_answer.save() + current_answer.answers = all_answers + current_answer.save() + success = True + else: + try: + current_answer = SurveyAnswer.objects.get(user = request.user, survey = survey) + form = SurveyForm(survey = survey, current_answers = current_answer.answers) + except SurveyAnswer.DoesNotExist: + form = SurveyForm(survey = survey) + return render_page(request, {"survey": survey, "form": form, "success": success}, "survey.html") diff --git a/manage.py b/manage.py new file mode 100644 index 00000000..3e4eedc9 --- /dev/null +++ b/manage.py @@ -0,0 +1,14 @@ +#!/usr/bin/env python +from django.core.management import execute_manager +import imp +try: + imp.find_module('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" % __file__) + sys.exit(1) + +import settings + +if __name__ == "__main__": + execute_manager(settings) diff --git a/media/cof.css b/media/cof.css new file mode 100644 index 00000000..6e9e6388 --- /dev/null +++ b/media/cof.css @@ -0,0 +1,298 @@ +html,body { +} + +@font-face { + font-family: 'Droid Serif'; + font-style: normal; + font-weight: bold; + src: local('Droid Serif Bold'), local('DroidSerif-Bold'), url('droidserif.woff') format('woff'); +} + +.spacer { + clear: both; +} + +#cof a:link, #cof a:active, #cof a:visited { + color: #111; + background: transparent; +} + +#cof a:hover { + color: #444; + background: transparent; +} + +#cof form { + display: block; + padding: 0; + width: 100%; + } + +#cof fieldset { + border: 0; + margin: 0; + padding: 0; + float: left; + clear: none; + width: auto; +} + +#cof fieldset legend { + display: none; +} + +#cof #main-login-container { + width: 500px; + margin: 7em auto; +} + +#cof #main-login { + width: 500px; + border: 15px solid #333; + -webkit-border-radius: 20px; + -moz-border-radius: 20px; + border-radius: 20px; +} + +#cof #main-container { + width: 800px; + margin: 7em auto; +} + +#cof #main { + width: 800px; + border: 15px solid #333; + -webkit-border-radius: 20px; + -moz-border-radius: 20px; + border-radius: 20px; + padding: 2em; + box-shadow: 0 0 100px #AAA inset; +} + +#cof #main #main-content { + font-size: 1.25em; + margin-top: 10px; +} + +#cof #main #main-content ul { + line-height: 1.3em; +} + +#cof #main h1 { + font-size: 3em; +} + +#cof #main h1 a { + color: #333; + text-decoration: none; +} + +#cof #main h2 { + font-size: 1.5em; + margin-bottom: 10px; +} + +#cof #main h3 { + font-size: 1.3em; +} + +#cof #main p { + margin-top: 8px; + margin-bottom: 8px; +} + +#cof #main form li { + list-style: none; +} + +#cof .success { + font-weight: bold; + color: #00B000; + background-color: transparent; +} + +#cof #main form ul.errorlist li { + font-weight: bold; + color: #B00000; + background-color: transparent; + list-style: disc; +} + +#cof #main-login.login_block { + padding: 2em; + box-shadow: 0 0 100px #AAA inset; +} + +#cof a#login_clipper, #cof a#login_outsider { + float: left; + display: block; + width: 250px; + height: 200px; + text-align: center; + font-family: 'Droid Serif', serif; + font-size: 2em; + font-weight: bold; + line-height: 190px; + text-decoration: none; + color: #FFF; +} + +#cof a#login_clipper { + background-color: #123E96; + box-shadow: 0 0 100px #040C78 inset; +} + +#cof a#login_clipper:hover { + background-color: #164BB6; +} + +#cof a#login_outsider { + background-color: #961221; + box-shadow: 0 0 100px #780411 inset; +} + +#cof a#login_outsider:hover { + background-color: #B31729; +} + +#cof #main-login label { + font-size: 11px; +} + +#cof #main-login label span.accesskey { + text-decoration: underline; +} + +#cof #main-login input { + letter-spacing: 1px; +} + +#cof #main-login .btn-row { + float: right; +} + +#cof .btn-submit { + float: none; + clear: none; + display: inline; + letter-spacing: 0; + color: #333; + padding: 5px; + text-transform: uppercofe; + font-variant: small-caps; + border: 1px solid #ccc; + background: -webkit-gradient(linear, 0% 0%, 0% 100%, from(#EEE), to(#CCC)); + background: -moz-linear-gradient(19% 75% 90deg,#EEE, #CCC); + background: linear-gradient(center top, #EEE, #CCC); +} + +#cof #main-login .btn-reset { + float: none; + clear: none; + margin-left: 5px; + border: 0; + border-left: 1px solid #ddd; + background: transparent; + color: #777; + text-transform: lowercase; + letter-spacing: 0; +} + +/* RESET --------------------------------- */ +/* reset some properties for elements since defaults are not crossbrowser - http: //meyerweb.com/eric/thoughts/2007/05/01/reset-reloaded/ */ +html,body,div,span,h1,h2,h3,p,a,img,ul,li,fieldset,form,label,legend { + margin: 0; + padding: 0; + border: 0; + outline: 0; + font-weight: inherit; + font-style: inherit; + font-size: 100%; + font-family: inherit; + vertical-align: baseline; +} + +:focus { + outline: 0; +} + +ul { + font-size: 1.1em; + padding: 6px 0 6px 12px; +} + +body { + font: normal 400 62.5%/1.0 Verdana, sans-serif; + background-color: #eee; + color: #333; +} + +/* HEADER --------------------------------- */ +#header h1 { + font-family: 'Droid Serif', serif; + font-weight: bold; + font-size: 18px; + margin-bottom: 5px; +} + +tt { + font-weight: bold; +} + +.error { + color: #BB0000; + background-color: transparent; +} + +/* FORMS --------------------------------- */ +input { + border-width: 1px; + font-family: Verdana,sans-serif; + font-size: 1.1em; + color: #000; + padding: 3px; + min-height: 1.5em; +} + +input[type="text"], input[type=password] { + border: 2px solid #888; + -webkit-border-radius: 8px; + -moz-border-radius: 8px; + border-radius: 8px; + box-shadow: 0 0 12px #AAA inset; + min-height: 2em; +} + +hr { + border: 0; + height: 1px; + background: #333; + background: -webkit-gradient(linear, left top, right top, color-stop(0%,hsla(0,0%,70%,0)), color-stop(50%,hsla(0,0%,70%,.75)), color-stop(100%,hsla(0,0%,70%,0))); + background: -webkit-linear-gradient(left, hsla(0,0%,70%,0) 0%, hsla(0,0%,70%,.75) 50%, hsla(0,0%,70%,0) 100%); + background: -moz-linear-gradient(left, hsla(0,0%,70%,0) 0%, hsla(0,0%,70%,.75) 50%, hsla(0,0%,70%,0) 100%); + background: -ms-linear-gradient(left, hsla(0,0%,70%,0) 0%, hsla(0,0%,70%,.75) 50%, hsla(0,0%,70%,0) 100%); + background: -o-linear-gradient(left, hsla(0,0%,70%,0) 0%, hsla(0,0%,70%,.75) 50%, hsla(0,0%,70%,0) 100%); + background: linear-gradient(left, hsla(0,0%,70%,0) 0%, hsla(0,0%,70%,.75) 50%, hsla(0,0%,70%,0) 100%); +} + +.fm-v div.row { + margin: 0; + padding: .5em 0; + width: 100%; +} + +.fm-v div.row label { + float: left; + width: 100%; + line-height: 1.5; +} + +.fm-v div.row input.btn-submit { + display: block; + margin: 0; +} + +.fm-v div.row.fl-controls-left { + width: 50%; + float: left; +} diff --git a/settings.py b/settings.py new file mode 100644 index 00000000..eab3e36e --- /dev/null +++ b/settings.py @@ -0,0 +1,168 @@ +# Django settings for cof project. + +DEBUG = True +TEMPLATE_DEBUG = DEBUG + +ADMINS = ( + ('Guillaume Seguin', 'guillaume@segu.in'), +) + +MANAGERS = ADMINS + +DATABASES = { + 'default': { + 'ENGINE': 'django.db.backends.mysql', # Add 'postgresql_psycopg2', 'postgresql', 'mysql', 'sqlite3' or 'oracle'. + 'NAME': 'cof_gestion', # Or path to database file if using sqlite3. + 'USER': 'cof_gestion', # Not used with sqlite3. + 'PASSWORD': '1OjKotIbmyro', # Not used with sqlite3. + 'HOST': '', # Set to empty string for localhost. Not used with sqlite3. + '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. +# On Unix systems, a value of None will cause Django to use the same +# timezone as the operating system. +# 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 = True + +# If you set this to False, Django will not format dates, numbers and +# calendars according to the current locale +USE_L10N = True + +# Absolute filesystem path to the directory that will hold user-uploaded files. +# Example: "/home/media/media.lawrence.com/media/" +MEDIA_ROOT = '' + +# URL that handles the media served from MEDIA_ROOT. Make sure to use a +# trailing slash. +# Examples: "http://media.lawrence.com/media/", "http://example.com/media/" +MEDIA_URL = '/gestion/media/' + +# Absolute path to the directory static files should be collected to. +# Don't put anything in this directory yourself; store your static files +# in apps' "static/" subdirectories and in STATICFILES_DIRS. +# Example: "/home/media/media.lawrence.com/static/" +STATIC_ROOT = '/home/gestion/www/static' + +# URL prefix for static files. +# Example: "http://media.lawrence.com/static/" +STATIC_URL = '/gestion/static/' + +# URL prefix for admin static files -- CSS, JavaScript and images. +# Make sure to use a trailing slash. +# Examples: "http://foo.com/static/admin/", "/static/admin/". +ADMIN_MEDIA_PREFIX = '/gestion/static/grappelli/' +GRAPPELLI_ADMIN_HEADLINE = "GestioCOF" +GRAPPELLI_ADMIN_TITLE = "GestioCOF" + +# Additional locations of static files +STATICFILES_DIRS = ( + # Put strings here, like "/home/html/static" or "C:/www/django/static". + # Always use forward slashes, even on Windows. + # Don't forget to use absolute paths, not relative paths. +) + +# List of finder classes that know how to find static files in +# various locations. +STATICFILES_FINDERS = ( + 'django.contrib.staticfiles.finders.FileSystemFinder', + 'django.contrib.staticfiles.finders.AppDirectoriesFinder', +# 'django.contrib.staticfiles.finders.DefaultStorageFinder', +) + +# Make this unique, and don't share it with anybody. +SECRET_KEY = '1d%3zqeyj8dk^@afz9=q12gs&&5k@4qx)5%uc_(&%01)d&74af' + +# List of callables that know how to import templates from various sources. +TEMPLATE_LOADERS = ( + 'django.template.loaders.filesystem.Loader', + 'django.template.loaders.app_directories.Loader', +# 'django.template.loaders.eggs.Loader', +) + +TEMPLATE_CONTEXT_PROCESSORS = ( + "django.core.context_processors.auth", + "django.core.context_processors.debug", + "django.core.context_processors.i18n", + "django.core.context_processors.media", + "django.core.context_processors.static", + "gestioncof.shared.context_processor", +) + +MIDDLEWARE_CLASSES = ( + 'django.middleware.common.CommonMiddleware', + 'django.contrib.sessions.middleware.SessionMiddleware', + 'django.middleware.csrf.CsrfViewMiddleware', + 'django.contrib.auth.middleware.AuthenticationMiddleware', +# 'django_cas.middleware.CASMiddleware', + 'django.contrib.messages.middleware.MessageMiddleware', +) + +ROOT_URLCONF = 'urls' + +TEMPLATE_DIRS = ( + "/home/gestion/www/templates/gestioncof", +) + +LOGIN_URL = "/gestion/login" +LOGIN_REDIRECT_URL = "/gestion/" + +CAS_SERVER_URL = 'https://cas.eleves.ens.fr/' +CAS_IGNORE_REFERER = True +CAS_REDIRECT_URL = '/gestion/' +CAS_EMAIL_FORMAT = "%s@clipper.ens.fr" +AUTH_PROFILE_MODULE = 'gestioncof.CofProfile' +AUTHENTICATION_BACKENDS = ( + 'django.contrib.auth.backends.ModelBackend', + 'gestioncof.shared.COFCASBackend', +) + +INSTALLED_APPS = ( + 'django.contrib.auth', + 'django.contrib.contenttypes', + 'django.contrib.sessions', + 'django.contrib.sites', + 'django.contrib.messages', + 'django.contrib.staticfiles', + 'grappelli', + 'django.contrib.admin', + 'django.contrib.admindocs', + 'gestioncof', +) + +# A sample logging configuration. The only tangible logging +# performed by this configuration is to send an email to +# the site admins on every HTTP 500 error. +# See http://docs.djangoproject.com/en/dev/topics/logging for +# more details on how to customize your logging configuration. +LOGGING = { + 'version': 1, + 'disable_existing_loggers': False, + 'handlers': { + 'mail_admins': { + 'level': 'ERROR', + 'class': 'django.utils.log.AdminEmailHandler' + } + }, + 'loggers': { + 'django.request': { + 'handlers': ['mail_admins'], + 'level': 'ERROR', + 'propagate': True, + }, + } +} diff --git a/templates/gestioncof/base.html b/templates/gestioncof/base.html new file mode 100644 index 00000000..933417ab --- /dev/null +++ b/templates/gestioncof/base.html @@ -0,0 +1,11 @@ + + + + {{ site.name }} + + + + + {% block content %}{% endblock %} + + diff --git a/templates/gestioncof/base_title.html b/templates/gestioncof/base_title.html new file mode 100644 index 00000000..91f6fd73 --- /dev/null +++ b/templates/gestioncof/base_title.html @@ -0,0 +1,16 @@ +{% extends "base.html" %} + +{% block content %} +
+
+ +
+
+ +{% endblock %} diff --git a/templates/gestioncof/home.html b/templates/gestioncof/home.html new file mode 100644 index 00000000..586b6a98 --- /dev/null +++ b/templates/gestioncof/home.html @@ -0,0 +1,28 @@ +{% extends "base_title.html" %} + +{% block realcontent %} +

Bienvenue, {% if user.first_name %}{{ user.first_name }}{% else %}{{ user.username }}{% endif %}

+ {% if events %} +

Événements

+ + {% endif %} + {% if surveys %} +

Sondages

+ + {% endif %} +

Divers

+ +{% endblock %} diff --git a/templates/gestioncof/login.html b/templates/gestioncof/login.html new file mode 100644 index 00000000..e075b546 --- /dev/null +++ b/templates/gestioncof/login.html @@ -0,0 +1,32 @@ +{% extends "base.html" %} + +{% block content %} +
+ +
+ +{% endblock %} diff --git a/templates/gestioncof/login_switch.html b/templates/gestioncof/login_switch.html new file mode 100644 index 00000000..1497b1d8 --- /dev/null +++ b/templates/gestioncof/login_switch.html @@ -0,0 +1,16 @@ +{% extends "base.html" %} + +{% block content %} +
+ +
+ +{% endblock %} diff --git a/templates/gestioncof/survey.html b/templates/gestioncof/survey.html new file mode 100644 index 00000000..1de9e174 --- /dev/null +++ b/templates/gestioncof/survey.html @@ -0,0 +1,16 @@ +{% extends "base_title.html" %} + +{% block realcontent %} +

Sondage: {{ survey.title }}

+ {% if success %} +

Votre réponse a bien été enregistrée ! Vous pouvez cependant la modifier jusqu'à la fin du sondage.

+ {% endif %} + {% if survey.details %} +

{{ survey.details }}

+ {% endif %} +
+ {% csrf_token %} + {{ form.as_p }} + +
+{% endblock %} diff --git a/urls.py b/urls.py new file mode 100644 index 00000000..c3f23942 --- /dev/null +++ b/urls.py @@ -0,0 +1,18 @@ +from django.conf.urls.defaults import patterns, include, url +from django.contrib import admin +admin.autodiscover() + +urlpatterns = patterns('', + url(r'^$', 'gestioncof.views.home', name='home'), + url(r'^cas/login$', 'django_cas.views.login'), + url(r'^cas/logout$', 'django_cas.views.logout'), + url(r'^outsider/login$', 'django.contrib.auth.views.login', {'template_name': 'login.html'}), + url(r'^outsider/logout$', 'django.contrib.auth.views.logout', {'next_page': '/gestion/'}), + url(r'^login$', 'gestioncof.views.login'), + url(r'^logout$', 'gestioncof.views.logout'), + url(r'^survey/(?P\d+)$', 'gestioncof.views.survey'), + url(r'^admin/doc/', include('django.contrib.admindocs.urls')), + url(r'^admin/', include(admin.site.urls)), + url(r'^grappelli/', include('grappelli.urls')), +) +