Commit 9501a10e authored by Mediatek's avatar Mediatek

Initial commit, projet med

parent 287d60db
...@@ -11,7 +11,7 @@ Ce portail minimaliste permet aux utilisateurs de s'identifier. Leurs mac sont c ...@@ -11,7 +11,7 @@ Ce portail minimaliste permet aux utilisateurs de s'identifier. Leurs mac sont c
## Installation des dépendances ## Installation des dépendances
L'installation comporte 2 parties : le serveur web où se trouve le depot portail_captif ainsi que toutes ses dépendances, et le serveur bdd (mysql ou pgsql). Ces 2 serveurs peuvent en réalité être la même machine, ou séparés (recommandé en production). L'installation comporte 2 parties : le serveur web où se trouve le depot med ainsi que toutes ses dépendances, et le serveur bdd (mysql ou pgsql). Ces 2 serveurs peuvent en réalité être la même machine, ou séparés (recommandé en production).
Le serveur web sera nommé serveur A, le serveur bdd serveur B . Le serveur web sera nommé serveur A, le serveur bdd serveur B .
### Prérequis sur le serveur A ### Prérequis sur le serveur A
...@@ -49,19 +49,19 @@ Sur le serveur B, installer mysql ou postgresql, dans la version jessie ou stret ...@@ -49,19 +49,19 @@ Sur le serveur B, installer mysql ou postgresql, dans la version jessie ou stret
### Installation sur le serveur principal A ### Installation sur le serveur principal A
Cloner le dépot portail_captif à partir du gitlab, par exemple dans /var/www/portail_captif. Cloner le dépot med à partir du gitlab, par exemple dans /var/www/med.
Ensuite, il faut créer le fichier settings_local.py dans le sous dossier portail_captif, un settings_local.example.py est présent. Les options sont commentées, et des options par défaut existent. Ensuite, il faut créer le fichier settings_local.py dans le sous dossier med, un settings_local.example.py est présent. Les options sont commentées, et des options par défaut existent.
En particulier, il est nécessaire de générer un login/mdp admin pour le ldap et un login/mdp pour l'utilisateur sql (cf ci-dessous), à mettre dans settings_local.py En particulier, il est nécessaire de générer un login/mdp admin pour le ldap et un login/mdp pour l'utilisateur sql (cf ci-dessous), à mettre dans settings_local.py
### Installation du serveur mysql/postgresql sur B ### Installation du serveur mysql/postgresql sur B
Sur le serveur mysql ou postgresl, il est nécessaire de créer une base de donnée portail_captif, ainsi qu'un user portail_captif et un mot de passe associé. Ne pas oublier de faire écouter le serveur mysql ou postgresql avec les acl nécessaire pour que A puisse l'utiliser. Sur le serveur mysql ou postgresl, il est nécessaire de créer une base de donnée med, ainsi qu'un user med et un mot de passe associé. Ne pas oublier de faire écouter le serveur mysql ou postgresql avec les acl nécessaire pour que A puisse l'utiliser.
Voici les étapes à éxecuter pour mysql : Voici les étapes à éxecuter pour mysql :
* CREATE DATABASE portail_captif; * CREATE DATABASE med;
* CREATE USER 'newuser'@'localhost' IDENTIFIED BY 'password'; * CREATE USER 'newuser'@'localhost' IDENTIFIED BY 'password';
* GRANT ALL PRIVILEGES ON portail_captif.* TO 'newuser'@'localhost'; * GRANT ALL PRIVILEGES ON med.* TO 'newuser'@'localhost';
* FLUSH PRIVILEGES; * FLUSH PRIVILEGES;
Si les serveurs A et B ne sont pas la même machine, il est nécessaire de remplacer localhost par l'ip avec laquelle A contacte B dans les commandes du dessus. Si les serveurs A et B ne sont pas la même machine, il est nécessaire de remplacer localhost par l'ip avec laquelle A contacte B dans les commandes du dessus.
...@@ -71,7 +71,7 @@ Une fois ces commandes effectuées, ne pas oublier de vérifier que newuser et p ...@@ -71,7 +71,7 @@ Une fois ces commandes effectuées, ne pas oublier de vérifier que newuser et p
Normalement à cette étape, le ldap et la bdd sql sont configurées correctement. Normalement à cette étape, le ldap et la bdd sql sont configurées correctement.
Il faut alors lancer dans le dépot portail_captif '''python3 manage.py migrate''' qui va structurer initialement la base de données. Il faut alors lancer dans le dépot med '''python3 manage.py migrate''' qui va structurer initialement la base de données.
Les migrations sont normalement comitées au fur et à mesure, néanmoins cette étape peut crasher, merci de reporter les bugs. Les migrations sont normalement comitées au fur et à mesure, néanmoins cette étape peut crasher, merci de reporter les bugs.
## Démarer le site web ## Démarer le site web
...@@ -81,13 +81,12 @@ Pour apache2 : ...@@ -81,13 +81,12 @@ Pour apache2 :
* apt install apache2 * apt install apache2
* apt install libapache2-mod-wsgi-py3 (pour le module wsgi) * apt install libapache2-mod-wsgi-py3 (pour le module wsgi)
portail_captif/wsgi.py permet de fonctionner avec apache2 en production med/wsgi.py permet de fonctionner avec apache2 en production
Pour nginx : Pour nginx :
* apt install nginx * apt install nginx
* apt install gunicorn3 * apt install gunicorn3
Utilisez alors un site nginx qui proxifie vers une socket gunicorn. Ensuite, utilisez les fichier portail_captif.service et portail_captif.socket avec systemd pour lancer le sous process gunicorn, présents dans portail_captif/ .
## Configuration avancée ## Configuration avancée
......
...@@ -3,7 +3,7 @@ import os ...@@ -3,7 +3,7 @@ import os
import sys import sys
if __name__ == "__main__": if __name__ == "__main__":
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "portail_captif.settings") os.environ.setdefault("DJANGO_SETTINGS_MODULE", "med.settings")
from django.core.management import execute_from_command_line from django.core.management import execute_from_command_line
......
...@@ -24,9 +24,11 @@ from .settings import SITE_NAME ...@@ -24,9 +24,11 @@ from .settings import SITE_NAME
def context_user(request): def context_user(request):
user = request.user user = request.user
is_admin = user.is_admin if hasattr(user,'is_admin') else False is_perm = user.has_perms(['perm'])
is_bureau = user.has_perms(['bureau'])
return { return {
'is_admin' : is_admin, 'is_perm' : is_perm,
'is_bureau': is_bureau,
'request_user': user, 'request_user': user,
'site_name': SITE_NAME, 'site_name': SITE_NAME,
} }
...@@ -21,7 +21,7 @@ ...@@ -21,7 +21,7 @@
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
""" """
Django settings for portail_captif project. Django settings for med project.
Generated by 'django-admin startproject' using Django 1.8.13. Generated by 'django-admin startproject' using Django 1.8.13.
...@@ -45,7 +45,7 @@ BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) ...@@ -45,7 +45,7 @@ BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
# Auth definition # Auth definition
PASSWORD_HASHERS = ( PASSWORD_HASHERS = (
'portail_captif.login.SSHAPasswordHasher', 'med.login.SSHAPasswordHasher',
'django.contrib.auth.hashers.PBKDF2PasswordHasher', 'django.contrib.auth.hashers.PBKDF2PasswordHasher',
) )
...@@ -65,7 +65,9 @@ INSTALLED_APPS = ( ...@@ -65,7 +65,9 @@ INSTALLED_APPS = (
'django.contrib.staticfiles', 'django.contrib.staticfiles',
'bootstrap3', 'bootstrap3',
'users', 'users',
'portail_captif', 'med',
'media',
'search',
'reversion' 'reversion'
) )
...@@ -80,7 +82,7 @@ MIDDLEWARE_CLASSES = ( ...@@ -80,7 +82,7 @@ MIDDLEWARE_CLASSES = (
'django.middleware.security.SecurityMiddleware', 'django.middleware.security.SecurityMiddleware',
) )
ROOT_URLCONF = 'portail_captif.urls' ROOT_URLCONF = 'med.urls'
TEMPLATES = [ TEMPLATES = [
{ {
...@@ -96,13 +98,13 @@ TEMPLATES = [ ...@@ -96,13 +98,13 @@ TEMPLATES = [
'django.contrib.auth.context_processors.auth', 'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages', 'django.contrib.messages.context_processors.messages',
'django.template.context_processors.request', 'django.template.context_processors.request',
'portail_captif.context_processors.context_user', 'med.context_processors.context_user',
], ],
}, },
}, },
] ]
WSGI_APPLICATION = 'portail_captif.wsgi.application' WSGI_APPLICATION = 'med.wsgi.application'
# Internationalization # Internationalization
......
{% extends "portail_captif/sidebar.html" %} {% extends "med/sidebar.html" %}
{% comment %} {% comment %}
Re2o est un logiciel d'administration développé initiallement au rezometz. Il Re2o est un logiciel d'administration développé initiallement au rezometz. Il
se veut agnostique au réseau considéré, de manière à être installable en se veut agnostique au réseau considéré, de manière à être installable en
...@@ -29,7 +29,7 @@ with this program; if not, write to the Free Software Foundation, Inc., ...@@ -29,7 +29,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
{% block content %} {% block content %}
<h2>Historique de {{ object }}</h2> <h2>Historique de {{ object }}</h2>
{% include "portail_captif/aff_history.html" with reversions=reversions %} {% include "med/aff_history.html" with reversions=reversions %}
<br /> <br />
<br /> <br />
<br /> <br />
......
{% extends "portail_captif/sidebar.html" %} {% extends "med/sidebar.html" %}
{% comment %} {% comment %}
Re2o est un logiciel d'administration développé initiallement au rezometz. Il Re2o est un logiciel d'administration développé initiallement au rezometz. Il
se veut agnostique au réseau considéré, de manière à être installable en se veut agnostique au réseau considéré, de manière à être installable en
...@@ -31,62 +31,8 @@ with this program; if not, write to the Free Software Foundation, Inc., ...@@ -31,62 +31,8 @@ with this program; if not, write to the Free Software Foundation, Inc.,
{% block content %} {% block content %}
<h1>Bienvenue sur {{ site_name }} !</h1> <h1>Bienvenue sur {{ site_name }} !</h1>
<h4>Bienvenue à toi ! Ce portail mis en place par le Cr@ns te permet d'accéder gratuitement à Internet sur le campus durant ton passage</h4>
<center>
<div class="thumbnail">
<img src="/static/logo/logo.png" alt="logo">
</div>
</center>
<div class="row">
<div class="col-sm-6 col-md-6">
<div class="col-12">
<div class="thumbnail">
<div class="caption">
<h3>Inscription</h3>
<p>Si vous n'avez pas de compte, inscrivez-vous pour bénéficier d'un accès à internet !</p>
<p><a href="{% url 'users:new-user' %}" class="btn btn-primary" role="button">Inscription</a></p>
</div>
</div>
</div>
</div>
<div class="col-sm-6 col-md-6">
<div class="col-12">
<div class="thumbnail">
<div class="caption">
<h3>Indentification</h3>
<p>Si avez déjà un compte, identifiez-vous pour accèder à Internet</p>
<p><a href="{% url 'login' %}" class="btn btn-primary" role="button">Identification</a></p>
</div>
</div>
</div>
</div>
</div>
<h1>Liens utiles</h1> <h1>Liens utiles</h1>
<div class="row">
{% for col in services_urls %}
<div class="col-sm-6 col-md-6">
{% for key, s in col.items %}
<div class="col-12">
<div class="thumbnail">
<img src="{% static "logo/"|add:s.logo %}" alt="{{ key }}">
<div class="caption">
<h3>{{ key }}</h3>
<p>{{ s.description }}</p>
<p><a href="{{ s.url }}" class="btn btn-primary" role="button">Accéder</a></p>
</div>
</div>
</div>
{% endfor %}
</div>
{% endfor %}
</div>
<p>Compte tenu des obligations de traçabilité des connexions à internet, vous vous engagez à fournir des informations exactes lors de votre inscription conformément à l'article 441-1 du nouveau code pénal.
Vous êtes seul responsable de l'utilisation du service, conformément aux articles L32 et L33 du code des postes et télécomunications éléctroniques.</p>
{% endblock %} {% endblock %}
...@@ -20,7 +20,7 @@ ...@@ -20,7 +20,7 @@
# with this program; if not, write to the Free Software Foundation, Inc., # with this program; if not, write to the Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
"""portail_captif URL Configuration """med URL Configuration
The `urlpatterns` list routes URLs to views. For more information please see: The `urlpatterns` list routes URLs to views. For more information please see:
https://docs.djangoproject.com/en/1.8/topics/http/urls/ https://docs.djangoproject.com/en/1.8/topics/http/urls/
...@@ -46,4 +46,6 @@ urlpatterns = [ ...@@ -46,4 +46,6 @@ urlpatterns = [
url('^', include('django.contrib.auth.urls')), url('^', include('django.contrib.auth.urls')),
url(r'^admin/', include(admin.site.urls)), url(r'^admin/', include(admin.site.urls)),
url(r'^users/', include('users.urls', namespace='users')), url(r'^users/', include('users.urls', namespace='users')),
url(r'^media/', include('media.urls', namespace='media')),
url(r'^search/', include('search.urls', namespace='search')),
] ]
...@@ -24,7 +24,7 @@ from django.shortcuts import render ...@@ -24,7 +24,7 @@ from django.shortcuts import render
from django.shortcuts import get_object_or_404 from django.shortcuts import get_object_or_404
from django.template.context_processors import csrf from django.template.context_processors import csrf
from django.template import Context, RequestContext, loader from django.template import Context, RequestContext, loader
from portail_captif.settings import services_urls from med.settings import services_urls
def form(ctx, template, request): def form(ctx, template, request):
c = ctx c = ctx
...@@ -40,4 +40,4 @@ def index(request): ...@@ -40,4 +40,4 @@ def index(request):
services[i][key] = s services[i][key] = s
i = i + 1 if i < 2 else 0 i = i + 1 if i < 2 else 0
return form({'services_urls': services}, 'portail_captif/index.html', request) return form({'services_urls': services}, 'med/index.html', request)
...@@ -21,7 +21,7 @@ ...@@ -21,7 +21,7 @@
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
""" """
WSGI config for portail_captif project. WSGI config for med project.
It exposes the WSGI callable as a module-level variable named ``application``. It exposes the WSGI callable as a module-level variable named ``application``.
...@@ -34,9 +34,8 @@ from django.core.wsgi import get_wsgi_application ...@@ -34,9 +34,8 @@ from django.core.wsgi import get_wsgi_application
from os.path import dirname from os.path import dirname
import sys import sys
# On démarre le système du portail
sys.path.append(dirname(dirname(__file__))) sys.path.append(dirname(dirname(__file__)))
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "portail_captif.settings") os.environ.setdefault("DJANGO_SETTINGS_MODULE", "med.settings")
application = get_wsgi_application() application = get_wsgi_application()
from reversion.admin import VersionAdmin
from django.contrib import admin
from django.contrib.auth.models import Group
from .models import Auteur, Emprunt, Media
class AuteurAdmin(VersionAdmin):
list_display = ('nom',)
class MediaAdmin(VersionAdmin):
list_display = ('titre','cote')
class EmpruntAdmin(VersionAdmin):
list_display = ('media','user','date_emprunt', 'date_rendu', 'permanencier_emprunt', 'permanencier_rendu')
admin.site.register(Auteur, AuteurAdmin)
admin.site.register(Media, MediaAdmin)
admin.site.register(Emprunt, EmpruntAdmin)
from django.apps import AppConfig
class MediaConfig(AppConfig):
name = 'media'
# Re2o est un logiciel d'administration développé initiallement au rezometz. Il
# se veut agnostique au réseau considéré, de manière à être installable en
# quelques clics.
#
# Copyright © 2017 Gabriel Détraz
# Copyright © 2017 Goulven Kermarec
# Copyright © 2017 Augustin Lemesle
#
# 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 2 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.forms import ModelForm, Form, ValidationError
from django import forms
from .models import Auteur, Media, Emprunt
class AuteurForm(ModelForm):
class Meta:
model = Auteur
fields = '__all__'
class MediaForm(ModelForm):
class Meta:
model = Media
fields = '__all__'
class EmpruntForm(ModelForm):
class Meta:
model = Emprunt
fields = ['media']
class EditEmpruntForm(ModelForm):
class Meta:
model = Emprunt
fields = ['media', 'permanencier_emprunt', 'permanencier_rendu', 'date_rendu']
# -*- coding: utf-8 -*-
# Generated by Django 1.11.2 on 2017-06-28 10:35
from __future__ import unicode_literals
from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
initial = True
dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
]
operations = [
migrations.CreateModel(
name='Auteur',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('nom', models.CharField(max_length=255)),
],
),
migrations.CreateModel(
name='Emprunt',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('date_emprunt', models.DateTimeField(help_text='%d/%m/%y %H:%M:%S')),
('date_rendu', models.DateTimeField(help_text='%d/%m/%y %H:%M:%S')),
],
),
migrations.CreateModel(
name='Media',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('titre', models.CharField(max_length=255)),
('cote', models.CharField(max_length=31)),
],
),
migrations.AddField(
model_name='emprunt',
name='media',
field=models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to='media.Media'),
),
migrations.AddField(
model_name='emprunt',
name='permanencier_emprunt',
field=models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, related_name='user_permanencier_emprunt', to=settings.AUTH_USER_MODEL),
),
migrations.AddField(
model_name='emprunt',
name='permanencier_rendu',
field=models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, related_name='user_permanencier_rendu', to=settings.AUTH_USER_MODEL),
),
migrations.AddField(
model_name='emprunt',
name='user',
field=models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to=settings.AUTH_USER_MODEL),
),
]
# -*- coding: utf-8 -*-
# Generated by Django 1.11.2 on 2017-06-29 12:38
from __future__ import unicode_literals
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('media', '0001_initial'),
]
operations = [
migrations.AddField(
model_name='media',
name='auteur',
field=models.ForeignKey(default=1, on_delete=django.db.models.deletion.PROTECT, to='media.Auteur'),
preserve_default=False,
),
]
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# Generated by Django 1.11.2 on 2017-06-29 13:36
from __future__ import unicode_literals from __future__ import unicode_literals
from django.conf import settings
from django.db import migrations, models from django.db import migrations, models
import django.db.models.deletion import django.db.models.deletion
import macaddress.fields
from django.conf import settings
class Migration(migrations.Migration): class Migration(migrations.Migration):
dependencies = [ dependencies = [
('users', '0002_auto_20170610_1550'), ('media', '0002_media_auteur'),
] ]
operations = [ operations = [
migrations.CreateModel( migrations.AlterField(
name='Machines', model_name='emprunt',
fields=[ name='date_rendu',
('id', models.AutoField(verbose_name='ID', primary_key=True, auto_created=True, serialize=False)), field=models.DateTimeField(blank=True, help_text='%d/%m/%y %H:%M:%S'),
('mac_address', macaddress.fields.MACAddressField(unique=True, max_length=17, integer=False)), ),
('proprio', models.ForeignKey(to=settings.AUTH_USER_MODEL, on_delete=django.db.models.deletion.PROTECT)), migrations.AlterField(
], model_name='emprunt',
name='permanencier_rendu',
field=models.ForeignKey(blank=True, on_delete=django.db.models.deletion.PROTECT, related_name='user_permanencier_rendu', to=settings.AUTH_USER_MODEL),
), ),
] ]
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# Generated by Django 1.11.2 on 2017-06-29 13:39
from __future__ import unicode_literals from __future__ import unicode_literals
from django.conf import settings
from django.db import migrations, models from django.db import migrations, models
import django.db.models.deletion import django.db.models.deletion
import macaddress.fields
from django.conf import settings
class Migration(migrations.Migration): class Migration(migrations.Migration):
dependencies = [ dependencies = [
('users', '0003_machines'), ('media', '0003_auto_20170629_1536'),
] ]
operations = [ operations = [
migrations.CreateModel( migrations.AlterField(
name='Machine', model_name='emprunt',
fields=[ name='date_rendu',
('id', models.AutoField(verbose_name='ID', primary_key=True, auto_created=True, serialize=False)), field=models.DateTimeField(blank=True, help_text='%d/%m/%y %H:%M:%S', null=True),
('mac_address', macaddress.fields.MACAddressField(max_length=17, unique=True, integer=False)),
('proprio', models.ForeignKey(to=settings.AUTH_USER_MODEL, on_delete=django.db.models.deletion.PROTECT)),
],
),
migrations.RemoveField(
model_name='machines',
name='proprio',
), ),
migrations.DeleteModel( migrations.AlterField(
name='Machines', model_name='emprunt',
name='permanencier_rendu',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, related_name='user_permanencier_rendu', to=settings.AUTH_USER_MODEL),
), ),
] ]
from django.db import models
class Auteur(models.Model):
nom = models.CharField(max_length=255)
def __str__(self):
return self.nom
class Media(models.Model):
titre = models.CharField(max_length=255)
cote = models.CharField(max_length=31)
auteur = models.ForeignKey('Auteur', on_delete=models.PROTECT)
# type = TODO
def __str__(self):
return str(self.titre) + ' - ' + str(self.auteur)
class Emprunt(models.Model):
media = models.ForeignKey('Media', on_delete=models.PROTECT)
user = models.ForeignKey('users.User', on_delete=models.PROTECT)
date_emprunt = models.DateTimeField(help_text='%d/%m/%y %H:%M:%S')
date_rendu = models.DateTimeField(help_text='%d/%m/%y %H:%M:%S', blank=True, null=True)
permanencier_emprunt = models.ForeignKey('users.User', on_delete=models.PROTECT, related_name='user_permanencier_emprunt')
permanencier_rendu = models.ForeignKey('users.User', on_delete=models.PROTECT, related_name='user_permanencier_rendu', blank=True, null=True)
{% comment %}
Re2o est un logiciel d'administration développé initiallement au rezometz. Il
se veut agnostique au réseau considéré, de manière à être installable en
quelques clics.
Copyright © 2017 Gabriel Détraz
Copyright © 2017 Goulven Kermarec
Copyright © 2017 Augustin Lemesle
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 2 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.
{% endcomment %}
<table class="table table-striped">
<thead>
<tr>
<th>Nom</th>
<th></th>
</tr>
</thead>
{% for auteur in auteurs_list %}
<tr>
<td>{{ auteur.nom }}</td>
<td>{% include 'buttons/edit.html' with href='media:edit-auteur' id=auteur.id %}
{% include 'buttons/suppr.html' with href='media:del-auteur' id=auteur.id %}
{% include 'buttons/history.html' with href='media:history' name='auteur' id=auteur.id %}</td>
</tr>
{% endfor %}
</table>
{% comment %}
Re2o est un logiciel d'administration développé initiallement au rezometz. Il
se veut agnostique au réseau considéré, de manière à être installable en