Commit 89dc8084 authored by Nicolas G.'s avatar Nicolas G.

Téléversement initial

parent 6b233738
#-*- coding: utf-8 -*-
"""
Django settings for firstjeudy project.
For more information on this file, see
https://docs.djangoproject.com/en/1.6/topics/settings/
For the full list of settings and their values, see
https://docs.djangoproject.com/en/1.6/ref/settings/
"""
# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
import os
BASE_DIR = os.path.dirname(os.path.dirname(__file__))
# Quick-start development settings - unsuitable for production
# See https://docs.djangoproject.com/en/1.6/howto/deployment/checklist/
# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = ''
# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = True
TEMPLATE_DEBUG = True
ALLOWED_HOSTS = ['xxx.domaine.org']
# Application definition
INSTALLED_APPS = (
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'fj',
'redactor',
'django.contrib.gis',
)
MIDDLEWARE_CLASSES = (
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
)
ROOT_URLCONF = 'firstjeudy.urls'
WSGI_APPLICATION = 'firstjeudy.wsgi.application'
# Database
# https://docs.djangoproject.com/en/1.6/ref/settings/#databases
#DATABASES = {
#'default': {
#'ENGINE': 'django.db.backends.sqlite3',
#'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
#}
#}
DATABASES = {
'default': {
'ENGINE': 'django.contrib.gis.db.backends.spatialite',
'NAME': os.path.join(BASE_DIR, 'db.geodjango'),
}
}
# Internationalization
# https://docs.djangoproject.com/en/1.6/topics/i18n/
LANGUAGE_CODE = 'fr'
TIME_ZONE = 'Europe/Paris'
USE_I18N = True
USE_L10N = True
USE_TZ = True
# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/1.6/howto/static-files/
STATIC_URL = '/static/'
# Désactiver au déploiement
STATICFILES_DIRS = (
os.path.join(BASE_DIR, 'static'),
)
# Activer au déploiement (python manage.py collectstatic afin de récupérer les fichiers statics de l'admin)
#STATIC_ROOT = '/var/www/firstjeudi.org/firstjeudy/static/'
# Administrateurs
ADMINS = (
("M. X", "add@xx.xx"),
)
# Gabarits
TEMPLATE_DIRS = (
os.path.join(BASE_DIR, 'templates')
)
#Ajoute un Slash à la fin de chaque URL
APPEND_SLASH = True
# Courrels
#EMAIL_HOST = 'smtp.fai.xx'
# Redactor
REDACTOR_OPTIONS = {'lang': 'fr',
'imageUpload': False,
'linkFileUpload': False,
'fileUpload': False,
'focus': False,
}
REDACTOR_UPLOAD = 'uploads/'
#-*- coding: utf-8 -*-
from django.conf.urls import patterns, include, url
from fj.views import ListeVilles, InscritsDelete
from django.contrib import admin
admin.autodiscover()
urlpatterns = patterns('',
# Examples:
# url(r'^$', 'firstjeudy.views.home', name='home'),
# url(r'^blog/', include('blog.urls')),
# Administration
url(r'^admin/', include(admin.site.urls)),
# Page de désinscription
url(r'^del/?(?P<unique>.+)$', InscritsDelete.as_view(), name='inscrit_delete'),
# Page d'une ville : inscription
url(r'^(?P<code>.+)$', 'fj.views.inscription'),
# Page d'index : la liste des villes
url(r'^$', ListeVilles.as_view(), name='index'),
#url(r'^(?P<code>.+)/stats$', 'fj.views.stats'),
)
"""
WSGI config for firstjeudy project.
It exposes the WSGI callable as a module-level variable named ``application``.
For more information on this file, see
https://docs.djangoproject.com/en/1.6/howto/deployment/wsgi/
"""
import os
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "firstjeudy.settings")
from django.core.wsgi import get_wsgi_application
application = get_wsgi_application()
#-*- coding: utf-8 -*-
from django.contrib import admin
# Register your models here.
from fj.models import Ville, Inscrits
# Ville
class VilleAdmin (admin.ModelAdmin):
list_display = ('code', 'nom', 'description', 'numday', 'numweek')
list_filter = ('code', 'numday', 'numweek',)
admin.site.register(Ville, VilleAdmin)
# Inscriptions
class InscritsAdmin (admin.ModelAdmin):
list_display = ('prenom', 'nom', 'nb', 'asso', 'num', 'ville', 'ip')
list_filter = ('asso', 'ville', 'num',)
admin.site.register(Inscrits, InscritsAdmin)
# -*- coding: utf-8 -*-
#
# forms.py
#
# Copyright 2014 Nicolas Grandjean <nicolas@microniko.net>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU 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 General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
# MA 02110-1301, USA.
#
#
from django import forms
from models import Inscrits
class InscritsForm(forms.ModelForm):
class Meta:
model = Inscrits
fields = ('nom', 'prenom', 'asso', 'courriel', 'nb', 'verif')
def clean_verif(self):
verif = self.cleaned_data['verif']
if verif!=u"quatre":
raise forms.ValidationError("Désolé !")
return verif
#-*- coding: utf-8 -*-
from django.db import models
# Zones de texte avec du Wysiwyg
from redactor.fields import RedactorField
# Create your models here.
from django.contrib.gis.db import models
from django.core.exceptions import ValidationError
def pas_de_zero(value):
if value == 0:
raise ValidationError(u'Vous ne pouvez pas mettre zéro !')
def pas_plus_de_cinq(value):
if value > 5:
raise ValidationError(u"C'est un peu trop, %s, non ?!" % value)
# Description de la base de données
#
# --- ville
class Ville(models.Model):
JOURS = (
(0,u'Dimanche'),
(1,u'Lundi'),
(2,u'Mardi'),
(3,u'Mercredi'),
(4,u'Jeudi'),
(5,u'Vendredi'),
(6,u'Samedi'),
)
code = models.CharField(verbose_name=u"Raccourci (utilisé dans les URL)", max_length =10, unique=True, null=False)
nom = models.CharField(verbose_name=u"Nom complet", max_length=30, unique=True, null=False)
#message = models.TextField(verbose_name=u"Message long (apparaît sur la page de la ville)")
#description = models.TextField(verbose_name=u"Message plus court (apparaît sur le résumé)")
message = RedactorField(
verbose_name=u"Message long (apparaît sur la page de la ville)",
allow_file_upload=False,
allow_image_upload=False,
)
description = RedactorField(
verbose_name=u"Message plus court (apparaît sur le résumé)",
allow_file_upload=False,
allow_image_upload=False,
)
#lat = models.FloatField(verbose_name=u"Latitude (utilisé pour afficher une carte OpenLayers)", null=False, default=47.5963)
#lon = models.FloatField(verbose_name=u"Longitude (utilisé pour afficher une carte OpenLayers)", null=False, default=-2.778)
champGeo = models.PointField(verbose_name=u"Lieu")
zoom = models.FloatField(verbose_name=u"Zoom de la carte", null=False, default=17)
#champGeo = gismodels.PointField(verbose_name=u"Champ point")
numday = models.IntegerField(verbose_name=u"nième jour de la semaine",null=False, choices=JOURS)
numweek = models.IntegerField(verbose_name=u"nième semaine du mois",null=False, validators=[pas_de_zero, pas_plus_de_cinq], max_length=1)
#objects = gismodels.GeoManager()
objects = models.GeoManager()
def __unicode__ (self):
return self.nom
class Meta:
verbose_name=u"Ville (ou lieu) de l'évènement"
verbose_name_plural=u"Villes (ou lieux) des évènements"
# -- inscrits
class Inscrits(models.Model):
unique = models.CharField(verbose_name=u"Numéro unique d'inscription", max_length=32, unique=True, null=False)
nom = models.CharField(verbose_name=u"Nom de l'inscrit", max_length=40, null=False)
prenom = models.CharField(verbose_name=u"Prénom de l'inscrit", max_length=40, null=False)
asso = models.CharField(verbose_name=u"Association", max_length=150, null=False)
verif = models.CharField(verbose_name=u"Anti-spam : indiquer en lettres minuscules, la somme de deux et deux (ça fait 4)", max_length=10, null=False)
courriel = models.CharField(verbose_name=u"Adresse de courriel de l'inscrit", max_length=40, null=False)
nb = models.IntegerField(verbose_name=u"Nombre d'inscrits",validators=[pas_plus_de_cinq], default=1)
num = models.CharField(verbose_name=u"Numéro du rendez-vous correspondant à la date AAAAMMJJ", max_length=8, null=False)
#ville = models.CharField(verbose_name=u"Code de la vile (mais il faudrait une liaison là !", max_length=10)
ville = models.ForeignKey('Ville')
ip = models.CharField(verbose_name=u"Adresse IP (voir IPAdressField ??)", max_length=40)
def __unicode__ (self):
return self.nom
class Meta:
verbose_name=u"Inscription"
verbose_name_plural=u"Inscriptions"
#-*- coding: utf-8 -*-
from django.test import TestCase
# Create your tests here.
#-*- coding: utf-8 -*-
from django.shortcuts import render
from django.http import Http404
from django.shortcuts import render, get_object_or_404
import uuid
from django import http
from django.views.generic import ListView, DeleteView
from django.core.urlresolvers import reverse_lazy
from django.contrib.gis.geos import Point
# Import de bidules pour le calcul de date
from dateutil.rrule import *
from dateutil.parser import *
from datetime import *
# dates en français
import locale, time
locale.setlocale(locale.LC_TIME, "fr_FR.utf8")
# Envoi de courriels
from django.core.mail import send_mail
#import pprint
#import sys
#sys.displayhook = pprint.pprint
# Voilà.
# Create your views here.
from fj.models import Ville, Inscrits
from fj.forms import InscritsForm
class ListeVilles(ListView):
model = Ville
context_object_name= "liste_villes" # url.py
template_name = "fj/index.html"
# ------- Page d'inscription ----------------
def inscription(request, code):
"""Afficher la page d'inscription
- D'abord, sa description
- Ensuite le formulaire d'inscription
- Puis le menu
- Et enfin, la liste des inscrits
"""
# Pour la description de la ville :
ville = get_object_or_404(Ville, code=code)
#jour = ville.numday
#if ville.numday == 0:
# jour = list(rrule(MONTHLY, count=1, byweekday=SU(ville.numweek)))
#if ville.numday == 1:
# jour = list(rrule(MONTHLY, count=1, byweekday=MO(ville.numweek)))
#if ville.numday == 2:
# jour = list(rrule(MONTHLY, count=1, byweekday=TU(ville.numweek)))
#if ville.numday == 3:
# jour = list(rrule(MONTHLY, count=1, byweekday=WE(ville.numweek)))
#if ville.numday == 4:
# jour = list(rrule(MONTHLY, count=1, byweekday=TH(ville.numweek)))
#if ville.numday == 5:
# jour = list(rrule(MONTHLY, count=1, byweekday=FR(ville.numweek)))
#if ville.numday == 6:
# jour = list(rrule(MONTHLY, count=1, byweekday=SA(ville.numweek)))
jr = (
(0,SU(ville.numweek)),
(1,MO(ville.numweek)),
(2,TU(ville.numweek)),
(3,WE(ville.numweek)),
(4,TH(ville.numweek)),
(5,FR(ville.numweek)),
(6,SA(ville.numweek)),
)
jour = list(rrule(MONTHLY, count=1, byweekday=jr[ville.numday][1]))
for foo in jour:
jour = foo.strftime('%A %d %B %Y').capitalize()
court = foo.strftime("%Y%m%d")
humain = str(foo.strftime('%A %d %B %Y')).decode("utf-8")
#humain = foo.strftime("%d/%m/%Y")
# traitements
zoom = str(ville.zoom).replace(',','.',1)
#lat = str(ville.lat).replace(',','.',1)
#lon = str(ville.lon).replace(',','.',1)
#point_carte = GeoQuerySet.geojson(ville.champGeo)
latlong = str(ville.champGeo).split(' ')
lon = latlong[1].replace('(','')
lat = latlong[2].replace(')','')
# Le formulaire d'inscription
if request.method== 'POST':
form = InscritsForm(request.POST)
if form.is_valid():
unique=str(uuid.uuid4())
adresse_ip =request.META["REMOTE_ADDR"]
url_fj =request.META["SERVER_NAME"]
# Est-ce une IPv6 ?
longueur = len(adresse_ip)
i=0
v6=""
while i < longueur:
if adresse_ip[i] == ":":
v6= u"IPv6 :-)"
i = i + 1
# Sauvegarde en base
Inscrits(
nom=form.cleaned_data['nom'],
prenom=form.cleaned_data['prenom'],asso=form.cleaned_data['asso'],courriel=form.cleaned_data['courriel'], nb=form.cleaned_data['nb'], unique=unique, num=court, ville_id=ville.id, ip=adresse_ip).save()
# Envoi d'un courriel
send_mail(
u'Recontre ' + ville.nom +' du ' + humain,
u'Bonjour ' + form.cleaned_data['prenom'] + ' ' + form.cleaned_data['nom'] + u'.\n\n'
u'Vous venez de vous inscrire a pour '+ ville.code + u' : \n'
u'- Ville : ' + ville.nom + u'\n' +
u'- Date : '+ humain + u'\n' +
u'- Adresse IP : ' + adresse_ip + " " + v6 + u'\n\n'
u'Pour annuler votre inscription, vous pouvez cliquer sur le lien suivant : \n http://' + url_fj + '/del/' +unique+ u'' ,
'root@microniko.net',
[form.cleaned_data['courriel']],
fail_silently=False
)
ok = True
else:
form=InscritsForm()
# La liste des villes
liste_villes = Ville.objects.all()
# La liste des inscrits
liste_inscrits = Inscrits.objects.filter(ville_id=ville.id, num=court)
total = 0
for insc in liste_inscrits:
total = total + insc.nb
# Le gabartit
return render(request, 'fj/ville.html', locals())
# ------- Page de suppression ----------------
class InscritsDelete(DeleteView):
model = Inscrits
context_object_name = "supprime_inscrit"
template_name = 'fj/del.html'
success_url = reverse_lazy('index')
supprime = True
def get_object(self, queryset=None):
unique = self.kwargs.get('unique', None)
return get_object_or_404(Inscrits, unique=unique)
# ------- Page des statistiques ----------------
def stats(request, code):
"""Afficher les statistiques d'inscriptions"""
# On récupère la ville :
ville = get_object_or_404(Ville, code=code)
toto = "Coucou c'est moi !"
if ville.numday == 0:
jour = list(rrule(MONTHLY, count=1, byweekday=SU(ville.numweek)))
if ville.numday == 1:
jour = list(rrule(MONTHLY, count=1, byweekday=MO(ville.numweek)))
if ville.numday == 2:
jour = list(rrule(MONTHLY, count=1, byweekday=TU(ville.numweek)))
if ville.numday == 3:
jour = list(rrule(MONTHLY, count=1, byweekday=WE(ville.numweek)))
if ville.numday == 4:
jour = list(rrule(MONTHLY, count=1, byweekday=TH(ville.numweek)))
if ville.numday == 5:
jour = list(rrule(MONTHLY, count=1, byweekday=FR(ville.numweek)))
if ville.numday == 6:
jour = list(rrule(MONTHLY, count=1, byweekday=SA(ville.numweek)))
for foo in jour:
jour = foo.strftime('%A %d %B %Y')
court = foo.strftime("%Y%m%d")
# La liste des villes
liste_villes = Ville.objects.all()
# On compte les inscrits
tous_inscrits = Inscrits.objects.filter(ville_id=ville.id)
# for insc in tous_inscrits:
# total = total + insc.nb
# Le gabartit
return render(request, 'fj/stats.html', locals())
#!/usr/bin/env python
import os
import sys
if __name__ == "__main__":
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "firstjeudy.settings")
from django.core.management import execute_from_command_line
execute_from_command_line(sys.argv)
/* CSS mercredi.rhizomes.org */
body{
background-color: #e7e7e7;
text-align: justify;
}
h1,h2,h4 {
text-align:center;
}
label {
display:block;
clear:right
}
div#sgeg, div#atelier {
margin-left:2%;
margin-right:2%;
border:dashed 1px black;
width:41%;
padding:1%;
margin-bottom:5%;
min-height: 200px;
background-color: #cfcfcf;
}
nav#menu, div#inscrits{
width:15%;
}
div#milieu{
width:60%;
padding:1em;
}
div#milieu h1 {
font-size:215%;
margin-top: 0;
}
div#sgeg,nav#menu,div#milieu {
float:left;
}
div#atelier, div#liste {
float:right;
}
footer {
clear:both;
width:90%;
margin-left:auto;
margin-right:auto;
text-align:center;
min-height:0;
font-size:70%;
}
.date { font-weight: bold }
nav#menu ul {
list-style-type:none;
padding:0;
}
nav#menu ul li{
padding:1em;
margin-left:0;
margin-bottom:2em;
border:dashed 1px black;
background-color:#cfcfcf;
text-align:center;
}
nav#menu ul li.actif {
background-color:black;
}
nav#menu ul li.actif a{
color:white;
}
p.inscription {
text-align:center;
font-size:110%;
font-family:sans-serif;
}
div#map {
margin:0;
margin-left:1em;
margin-bottom:1em;
padding: 5px;
border: 0px solid black;
float:right;
width: 400px;
height: 350px
overflow: hidden;
}
hr.separation {
clear: both;
visibility: hidden;
}
fieldset legend {
font-weight: bold;
font-size:110%;
}
fieldset {
background-color: #cfcfcf;
margin-left:10%;
padding:2em;
margin-right:5%;
}
div#inscrits {
text-align: left;
float: left;
width: 20%;
}
div#inscrits ul {
padding-left: 0;
width: 100%;
}
/*---- Seulement page d'accueil --*/
html.index h1 { text-align: center }
html.index div { float: left; width: 28%; margin: 1%; text-align: justify; padding:1%; }
html.index div.white { border: 1px dashed #cccccc }
html.index div.grey { border: 1px dashed #000000; color: #000000; background-color: #f0f0f0 }
html.index div.wrapper { margin-bottom: 1em; width: 100%; margin: 0; padding: 0 }
html.index br { clear: left; }
html.index .date { font-weight: bold }
/*-Coupure des mots--*/
div#milieu p, div.wrapper p {
hyphens:auto;
-moz-hyphens:auto;
-webkit-hyphens:auto;
}
p.infos {
font-weight: bold;
margin-right: 10%;
margin-left: 10%;
padding: 5px;
text-align: center;
border: dashed 1px grey;
}
p.erreur{
font-style: italic;
}
ul.errorlist {
padding: 5px;
border: dashed 1px grey;
}
ul.errorlist li {
list-style-type: none;
color: red;
font-family: sans-serif;
}
{% load static %}
<!DOCTYPE html>
<html{% block classHTML %}{% endblock %}>