This commit is contained in:
Doug Le Tough 2018-02-27 19:51:43 +01:00
parent 7332af1dc0
commit 738596a13f
9 changed files with 461 additions and 65 deletions

View File

@ -41,6 +41,7 @@ class Tetawebapp_users(db.Model):
name = db.Column(db.Text, nullable=True) name = db.Column(db.Text, nullable=True)
phone = db.Column(db.Text, nullable=True) phone = db.Column(db.Text, nullable=True)
diet = db.Column(db.Text, nullable=True) diet = db.Column(db.Text, nullable=True)
is_admin = db.Column(db.Integer, nullable=False, default=0)
class Tetawebapp_roles(db.Model): class Tetawebapp_roles(db.Model):
__tablename__ = 'participer_thsf_roles' __tablename__ = 'participer_thsf_roles'
@ -48,6 +49,15 @@ class Tetawebapp_roles(db.Model):
role = db.Column(db.Text, nullable=False) role = db.Column(db.Text, nullable=False)
description = db.Column(db.Text, nullable=False) description = db.Column(db.Text, nullable=False)
class Tetawebapp_turns(db.Model):
__tablename__ = 'participer_thsf_turns'
id = db.Column(db.Integer, primary_key=True)
role_id = db.Column(db.Integer, db.ForeignKey('participer_thsf_roles.id'), nullable=False)
user_id = db.Column(db.Integer, db.ForeignKey('participer_thsf_users.id'), nullable=True)
wday = db.Column(db.Enum('J', 'V', 'S', 'D'), nullable=False)
start_time = db.Column(db.Time, nullable=False)
end_time = db.Column(db.Time, nullable=False)
######################################################################## ########################################################################
# Menu and navigation management # Menu and navigation management
######################################################################## ########################################################################
@ -62,14 +72,17 @@ def get_menu(page):
- The int 0 is used to determine which menu entry is actally called. - The int 0 is used to determine which menu entry is actally called.
The value MUST be 0.""" The value MUST be 0."""
menu = [[u'Accueil', {u'/': [u'/']}, 0], menu = [[u'Accueil', {u'/': [u'/']}, 0],
[u'Mon compte', {u'/account': [u'/account', u'/account/<ID>']}, 0], [u'Mon compte', {u'/account': [u'/account', u'/account/update']}, 0],
[u'Mes quarts', {u'/turn': [u'/turn']}, 0], [u'Mes tours de staff', {u'/turn': [u'/turn']}, 0],
[u'Feuille de staff', {u'/staff_sheet': [u'/staff_sheet']}, 0], [u'Feuilles de staff', {u'/staff_sheets': [u'/staff_sheet']}, 0],
[u'Déconnexion', {u'/logout': [u'/logout']}, 0],
]
if session['is_admin']:
menu = [[u'Accueil', {u'/': [u'/']}, 0],
[u'Tours de staff', {u'/staff': [u'/staff']}, 0],
[u'Feuilles de staff', {u'/staff_sheets': [u'/staff_sheet']}, 0],
[u'Liste des staffers', {u'/users': [u'/users', u'/account/<ID>']}, 0],
[u'Déconnexion', {u'/logout': [u'/logout']}, 0], [u'Déconnexion', {u'/logout': [u'/logout']}, 0],
[u'Inputs', {u'/inputs': [u'/inputs']}, 0],
[u'Ajax', {u'/ajax': [u'/ajax']}, 0],
[u'Database', {u'/database': [u'/database']}, 0],
[u'Todo', {u'/todo': [u'/todo']}, 0],
] ]
for item in menu: for item in menu:
for url in item[1]: for url in item[1]:
@ -122,29 +135,153 @@ def check_session(func):
def check(*args, **kwargs): def check(*args, **kwargs):
try: try:
if session['token'] == request.cookies['token'] and len(session['token']) > 0: if session['token'] == request.cookies['token'] and len(session['token']) > 0:
# User is logged in and identified
return func(*args, **kwargs) return func(*args, **kwargs)
else: else:
# User is not logged in or session expired
session['token'] = '' session['token'] = ''
response = app.make_response(render_template('login_or_register.html', message='')) response = app.make_response(render_template('login_or_register.html', message=''))
sync_cookies(response, session) sync_cookies(response, session)
return response return response
except KeyError: except KeyError:
# User is not logged in
return render_template('login_or_register.html', message='') return render_template('login_or_register.html', message='')
return check return check
def check_login(login, password): def check_login(login, password):
""" Puts the login verification code here """ """ Puts the login verification code here """
password = password.encode('utf-8')
hashed_password = bcrypt.hashpw(password, bcrypt.gensalt()) hashed_password = bcrypt.hashpw(password, bcrypt.gensalt())
stored_hash = Tetawebapp_users.query.filter_by(mail=login).with_entities(Tetawebapp_users.password).first() stored_hash = Tetawebapp_users.query.filter_by(mail=login).with_entities(Tetawebapp_users.password).first()
is_admin = Tetawebapp_users.query.filter_by(mail=login).with_entities(Tetawebapp_users.is_admin).first()
if stored_hash: if stored_hash:
if bcrypt.checkpw(password, stored_hash[0].encode('utf-8')): if bcrypt.checkpw(password, stored_hash[0].encode('utf-8')):
session['is_admin'] = is_admin[0]
return True return True
return False return False
def register_user(login, password, confirm):
""" Register new user """
if password != confirm:
# Password does not match confirmation
print "[+] Password mismatch confirmation"
return False
check_user = Tetawebapp_users.query.filter_by(mail=login).count()
if check_user != 0:
# User already exists
print "[+] User already exists"
return False
hashed_password = bcrypt.hashpw(password.encode('utf-8'), bcrypt.gensalt())
user = Tetawebapp_users(mail=login.encode('utf8'), password=hashed_password)
try:
db.session.add(user)
commit = db.session.commit()
except Exception as e:
db.session.rollback()
print "[+] Error at register_user:"
print "------------------------------"
print "%s" % e.message
print "------------------------------"
return False
if commit != None:
return False
return True
def update_user(login, password, confirm, name, phone, diet):
""" Update user infos with provided data """
if password != confirm:
# Password does not match confirmation
print "[+] Password mismatch confirmation"
return False
check_user = Tetawebapp_users.query.filter_by(mail=login).count()
if check_user == 0:
# User does not exist
print "[+] User does not exist"
return False
user = Tetawebapp_users.query.filter_by(mail=login).first()
if len(password) > 0:
# User requested password modification
hashed_password = bcrypt.hashpw(password, bcrypt.gensalt())
setattr(user, 'password', hashed_password)
# Password has been updated if necessary
# Now let's update other data
setattr(user, 'name', name)
setattr(user, 'phone', phone)
setattr(user, 'diet', diet)
try:
db.session.add(user)
commit = db.session.commit()
except Exception as e:
db.session.rollback()
print "[+] Error at update_user:"
print "------------------------------"
print "%s" % e.message
print "------------------------------"
return False
if commit != None:
return False
return True
def update_user_by_id(user_id, login, password, confirm, name, phone, diet):
""" Update user infos with provided data """
if password != confirm:
# Password does not match confirmation
print "[+] Password mismatch confirmation"
return False
check_user = Tetawebapp_users.query.filter_by(id=user_id).count()
if check_user == 0:
# User does not exist
print "[+] User does not exist"
return False
user = Tetawebapp_users.query.filter_by(id=user_id).first()
if len(password) > 0:
# User requested password modification
hashed_password = bcrypt.hashpw(password, bcrypt.gensalt())
setattr(user, 'password', hashed_password)
# Password has been updated if necessary
# Now let's update other data
setattr(user, 'name', name)
setattr(user, 'phone', phone)
setattr(user, 'diet', diet)
try:
db.session.add(user)
commit = db.session.commit()
except Exception as e:
db.session.rollback()
print "[+] Error at update_user:"
print "------------------------------"
print "%s" % e.message
print "------------------------------"
return False
if commit != None:
return False
return True
def delete_user(user_id):
""" Delete user """
try:
Tetawebapp_users.query.filter_by(id=int(user_id)).delete()
db.session.commit()
return True
except ValueError as e:
return False
except Exception as e:
db.session.rollback()
print "[+] Error at delete_user:"
print "------------------------------"
print "%s" % e.message
print "------------------------------"
return False
def check_user_info(): def check_user_info():
""" Check user info and send appropriate message if info are not complete""" """ Check user info and send appropriate message if info are not complete"""
message = "Vos informations personnelles ne sont pas totalement renseignées. N'oubliez pas de remplir votre fiche située dans la section 'Mon compte'" message = ''
user = Tetawebapp_users.query.filter_by(mail=session['login']).first()
name = user.name
phone = user.phone
diet = user.diet
if name == None or phone == None or diet == None or \
len(name) == 0 or len(phone) == 0 or len(diet) == 0:
message = "Vos informations personnelles ne sont pas complètement renseignées. N'oubliez pas de remplir votre fiche située dans la section 'Mon compte'"
return message.decode('utf-8') return message.decode('utf-8')
def gen_token(): def gen_token():
@ -165,44 +302,55 @@ def page_not_found(e):
@app.route("/login", methods=['GET', 'POST']) @app.route("/login", methods=['GET', 'POST'])
def login(): def login():
login = request.form.get('login') try:
password = request.form.get('password') login = request.form.get('login').encode('utf-8')
if check_login(login, password): password = request.form.get('password').encode('utf-8')
# Generate and store a token in session if check_login(login, password):
session['token'] = gen_token() # Generate and store a token in session
# Return user to index page session['token'] = gen_token()
page = '/' session['login'] = login
menu = get_menu(page) # Return user to index page
message = check_user_info() page = '/'
response = app.make_response(render_template('index.html', menu=menu, message=message)) menu = get_menu(page)
# Push token to cookie message = check_user_info()
response = app.make_response(render_template('index.html', menu=menu, message=message, login=login))
# Push token to cookie
sync_cookies(response, session)
return response
# Credentials are not valid
response = app.make_response(render_template('login_or_register.html', message="Utilisateur ou mot de passe invalide"))
session['token'] = ''
sync_cookies(response, session) sync_cookies(response, session)
return response return response
# Credentials are not valid except AttributeError:
response = app.make_response(render_template('login_or_register.html', message='Invalid user or password')) return render_template('login_or_register.html', message="Utilisateur ou mot de passe invalide")
session['token'] = ''
sync_cookies(response, session)
return response
@app.route("/register", methods=['GET', 'POST']) @app.route("/register", methods=['GET', 'POST'])
def register(): def register():
login = request.form.get('login') try:
password = request.form.get('password') login = request.form.get('login').encode('utf-8')
if check_login(login, password): password = request.form.get('password').encode('utf-8')
# Generate and store a token in session confirm = request.form.get('confirm').encode('utf-8')
session['token'] = gen_token() if register_user(login, password, confirm):
# Return user to index page # Generate and store a token in session
page = '/' session['token'] = gen_token()
menu = get_menu(page) session['login'] = login
response = app.make_response(render_template('index.html', menu=menu)) # Return user to index page
# Push token to cookie page = '/'
menu = get_menu(page)
message = check_user_info()
response = app.make_response(render_template('index.html', menu=menu, login=login, message=message))
# Push token to cookie
sync_cookies(response, session)
return response
# Error while registering user
message = "Erreur lors de l'enregsitrement: L'utilisateur existe t-il déjà ?".decode('utf-8')
response = app.make_response(render_template('login_or_register.html', message=message))
session['token'] = ''
sync_cookies(response, session) sync_cookies(response, session)
return response return response
# Credentials are not valid except AttributeError:
response = app.make_response(render_template('login_or_register.html', message='Invalid user or password')) return render_template('login_or_register.html', message="Utilisateur ou mot de passe invalide")
session['token'] = ''
sync_cookies(response, session)
return response
@app.route("/", methods=['GET', 'POST']) @app.route("/", methods=['GET', 'POST'])
@check_session @check_session
@ -211,25 +359,122 @@ def index():
page = str(request.url_rule) page = str(request.url_rule)
menu = get_menu(page) menu = get_menu(page)
message = check_user_info() message = check_user_info()
return render_template('index.html', menu=menu, message=message) return render_template('index.html', menu=menu, message=message, login=session['login'])
@app.route("/account", methods=['GET', 'POST']) @app.route("/account", methods=['GET', 'POST'])
@check_session @check_session
def account(): def account():
""" Arcticles page """ """ Account page """
page = str(request.url_rule) page = str(request.url_rule)
menu = get_menu(page) menu = get_menu(page)
return render_template('account.html', menu=menu) user = Tetawebapp_users.query.filter_by(mail=session['login']).first()
mail = '' if user.mail == None else user.mail
name = '' if user.name == None else user.name
phone = '' if user.phone == None else user.phone
diet = '' if user.diet == None else user.diet
message = check_user_info()
return render_template('account.html', menu=menu, mail=mail, name=name, phone=phone, diet=diet, message=message)
@app.route("/account/update", methods=['GET', 'POST'])
@check_session
def update_account():
""" Update current account """
try:
page = str(request.url_rule)
menu = get_menu(page)
login = session['login']
password = request.form.get('password').encode('utf-8')
confirm = request.form.get('confirm').encode('utf-8')
name = request.form.get('name').encode('utf-8')
phone = request.form.get('phone').encode('utf-8')
diet = request.form.get('diet').encode('utf-8')
if update_user(login, password, confirm, name, phone, diet):
message = check_user_info()
else:
message = "Erreur lors de l'enregistrement des données."
return render_template('account.html',
menu=menu,
mail=login.decode('utf-8'),
name=name.decode('utf-8'),
phone=phone.decode('utf-8'),
diet=diet.decode('utf-8'),
message=message)
except AttributeError:
return render_template('login_or_register.html', message="Utilisateur ou mot de passe invalide")
@app.route("/users", methods=['GET', 'POST'])
@check_session
def list_users():
""" Users list """
page = str(request.url_rule)
menu = get_menu(page)
message = check_user_info()
staffers = Tetawebapp_users.query.filter_by(is_admin=0).order_by(Tetawebapp_users.name).all()
return render_template('list_users.html', menu=menu, staffers=staffers, message=message)
@app.route("/account/<ID>", methods=['GET', 'POST']) @app.route("/account/<ID>", methods=['GET', 'POST'])
@check_session @check_session
def account_by_id(ID): def account_by_id(ID):
""" Arcticles page """ """ Arcticles page """
page = str(request.url_rule) try:
menu = get_menu(page) if session['is_admin']:
selected = page.replace('<ID>', ID) page = str(request.url_rule)
navbar = get_navbar(page, selected) menu = get_menu(page)
return render_template('account_by_id.html', menu=menu, navbar=navbar, ID=ID) user = Tetawebapp_users.query.filter_by(id=ID).first()
return render_template('account_by_id.html', menu=menu, user=user)
# User is not admin
return render_template('login_or_register.html', message="Utilisateur ou mot de passe invalide")
except AttributeError:
# User is not logged in
return render_template('login_or_register.html', message="Utilisateur ou mot de passe invalide")
@app.route("/account/update/<ID>", methods=['GET', 'POST'])
@check_session
def update_account_by_id(ID):
""" Update given account """
try:
if session['is_admin']:
page = str(request.url_rule)
menu = get_menu(page)
login = session['login']
password = request.form.get('password').encode('utf-8')
confirm = request.form.get('confirm').encode('utf-8')
name = request.form.get('name').encode('utf-8')
phone = request.form.get('phone').encode('utf-8')
diet = request.form.get('diet').encode('utf-8')
if update_user_by_id(ID, login, password, confirm, name, phone, diet):
user = Tetawebapp_users.query.filter_by(id=ID).first()
message = check_user_info()
else:
message = "Erreur lors de l'enregistrement des données."
return render_template('account_by_id.html',
menu=menu,
user=user,
message=message)
# User is not admin
return render_template('login_or_register.html', message="Utilisateur ou mot de passe invalide")
except AttributeError:
# User is not logged in
return render_template('login_or_register.html', message="Utilisateur ou mot de passe invalide")
@app.route("/account/delete/<ID>", methods=['GET', 'POST'])
@check_session
def delete_account(ID):
""" Delete given account """
try:
if session['is_admin']:
message = "Erreur lors de la suppression.".decode('utf-8')
if delete_user(ID):
message = ''
page = str(request.url_rule)
menu = get_menu(page)
staffers = Tetawebapp_users.query.filter_by(is_admin=0).order_by(Tetawebapp_users.name).all()
return render_template('list_users.html', menu=menu, staffers=staffers, message=message)
# User is not admin
return render_template('login_or_register.html', message="Utilisateur ou mot de passe invalide")
except AttributeError:
# User is not logged in
return render_template('login_or_register.html', message="Utilisateur ou mot de passe invalide")
@app.route("/logout", methods=['GET', 'POST']) @app.route("/logout", methods=['GET', 'POST'])
@check_session @check_session
@ -237,6 +482,7 @@ def logout():
""" Logout user """ """ Logout user """
# Remove session token # Remove session token
session['token'] = None session['token'] = None
session['login'] = None
# Return user to index page # Return user to index page
response = app.make_response(render_template('login_or_register.html', message='')) response = app.make_response(render_template('login_or_register.html', message=''))
# Push token to cookie # Push token to cookie

View File

@ -36,25 +36,64 @@ CREATE TABLE participer_thsf_users (
password text not NULL, password text not NULL,
name text, name text,
phone text, phone text,
diet text diet text,
is_admin integer not NULL
); );
\echo *********************************
\echo * Creating participer_thsf_roles table
\echo *********************************
CREATE TABLE participer_thsf_roles ( CREATE TABLE participer_thsf_roles (
id serial primary key, id serial primary key,
role text not NULL, role text not NULL,
description text not NULL description text not NULL
); );
\echo *********************************
\echo * Creating participer_thsf_turns table
\echo *********************************
CREATE TYPE dow AS ENUM ('J', 'V', 'S', 'D');
CREATE TABLE participer_thsf_turns (
id serial primary key,
role_id integer not NULL,
user_id integer,
wday dow not NULL,
start_time time not NULL,
end_time time not NULL,
constraint fk_turns_role
foreign key (role_id)
REFERENCES participer_thsf_roles (id),
constraint fk_turns_user
foreign key (user_id)
REFERENCES participer_thsf_users (id)
);
\echo ************************************************* \echo *************************************************
\echo * Giving participer_thsf_users ownership to participer_thsf \echo * Giving participer_thsf_users ownership to participer_thsf
\echo ************************************************* \echo *************************************************
alter table participer_thsf_users owner to participer_thsf; alter table participer_thsf_users owner to participer_thsf;
\echo *************************************************
\echo * Giving participer_thsf_roles ownership to participer_thsf
\echo *************************************************
alter table participer_thsf_roles owner to participer_thsf;
\echo *************************************************
\echo * Giving participer_thsf_turns ownership to participer_thsf
\echo *************************************************
alter table participer_thsf_turns owner to participer_thsf;
\echo ********************************************************************* \echo *********************************************************************
\echo * Inserting user demo identified by password demo to participer_thsf_users \echo * Inserting user demo identified by password demo to participer_thsf_users
\echo ********************************************************************* \echo *********************************************************************
insert into participer_thsf_users (mail, password, name) values ('demo', '$2b$12$yjv4QMctGJFj2HmmbF6u5uDq9ATIl/Y9Z96MbaqRrcG6AE0CGHKSS', 'demo'); insert into participer_thsf_users (mail, password, name, phone, diet, is_admin) values ('bofh@tetalab.org',
'$2b$12$wm7PQ9IE7TYGYk1XB11mPusq7HsjYLYxt5G4v5Wz.jZbh5iWDHP5q',
'BOFH',
'0000000000',
'Omnivore',
1);
\echo ********************************************************************* \echo *********************************************************************
\echo * Inserting roles to participer_thsf_roles \echo * Inserting roles to participer_thsf_roles

View File

@ -17,3 +17,23 @@ function register() {
} }
return true; return true;
} }
function update_account() {
var password = document.getElementById('password').value;
var confirm = document.getElementById('confirm').value;
if (password != confirm){
alert("Confirmation mot de passe incohérente");
return false;
}
if (password.length > 0 && password.length < 8){
alert("Le mot de passe doit avoir une longueur d'au moins 8 caractères");
return false;
}
return true;
}
function delete_account(id) {
if (confirm("La suppression d'un compte est définitive.\n\nConfirmer ?")) {
document.location='/account/delete/'+id;
}
}

View File

@ -370,7 +370,7 @@ input.upload {
} }
form { form {
width: 350px; width: 400px;
text-align: center; text-align: center;
line-height: 40px; line-height: 40px;
} }
@ -382,3 +382,49 @@ form > label {
form > input[type='text'], form > input[type='password'] { form > input[type='text'], form > input[type='password'] {
float: right; float: right;
} }
div.table_header {
background-color: var(--coloured-bg);
text-align: left;
width: 910px;
}
div.table_row {
text-align: left;
width: 910px;
}
div.table_header > div, div.table_row > div {
display: inline-block;
text-align: center;
font-weight: bold;
width: 200px;
}
div.table_row > div {
border-color: var(--coloured-bg);
border-width: 1px;
font-weight: normal;
}
div.even {
background-color: var(--light-coloured-bg);
border-color: var(--coloured-bg);
border-width: 1px;
border-style: none none solid none;
}
div.odd {
background-color: var(--white);
border-color: var(--coloured-bg);
border-width: 1px;
border-style: none none solid none;
}
div.table_row > div.border_left {
border-style: none none none solid;
}
div.table_row > div.border_right {
border-style: none solid none none;
}

View File

@ -16,13 +16,13 @@
<li>Aucune des données que vous nous transmettrez ne sera fournie à un tiers</li> <li>Aucune des données que vous nous transmettrez ne sera fournie à un tiers</li>
</ul> </ul>
</p> </p>
<form method='POST' action='/account'> <form method='POST' action='/account/update'>
<label>Adresse email: </label><input id='login' name='login' type='text' /><br/> <label>Adresse email: </label><input id='login' name='login' type='text' value='{{ mail }}' disabled='disabled'/><br/>
<label>Prénom ou pseudo: </label><input id='pseudo' name='pseudo' type='text' /><br/> <label>Prénom ou pseudo: </label><input id='name' name='name' type='text' value='{{ name }}'/><br/>
<label>Nouveau mot de passe: </label><input id='password' name='password' type='password' /><br/> <label>Nouveau mot de passe: </label><input id='password' name='password' type='password'/><br/>
<label>Répetez mot de passe: </label><input id='confirm' name='confirm' type='password' /><br/> <label>Confirmation mot de passe: </label><input id='confirm' name='confirm' type='password'/><br/>
<label>Numéro de téléphone: </label><input id='phone' name='phone' type='text' /><br/> <label>Numéro de téléphone: </label><input id='phone' name='phone' type='text' value='{{ phone }}'/><br/>
<label>Régime alimentaire: </label><input id='diet' name='diet' type='text' /><br/> <label>Régime alimentaire et remarques: </label><input id='diet' name='diet' type='text' value='{{ diet }}'/><br/>
<input type='submit' value='Update' onclick='javascript:return update_account();'> <input type='submit' value='Update' onclick='javascript:return update_account();'>
</article> </article>
{% endblock %} {% endblock %}

View File

@ -0,0 +1,15 @@
{% extends "index.html" %}
{% block title %}Articles{% endblock %}
{% block main %}
<article>
<h3>Informations du compte</h3>
<form method='POST' action='/account/update/{{ user.id }}'>
<label>Adresse email: </label><input id='login' name='login' type='text' value='{{ user.mail }}' disabled='disabled'/><br/>
<label>Prénom ou pseudo: </label><input id='name' name='name' type='text' value='{{ user.name }}'/><br/>
<label>Nouveau mot de passe: </label><input id='password' name='password' type='password'/><br/>
<label>Confirmation mot de passe: </label><input id='confirm' name='confirm' type='password'/><br/>
<label>Numéro de téléphone: </label><input id='phone' name='phone' type='text' value='{{ user.phone }}'/><br/>
<label>Régime alimentaire et remarques: </label><input id='diet' name='diet' type='text' value='{{ user.diet }}'/><br/>
<input type='submit' value='Update' onclick='javascript:return update_account();'>
</article>
{% endblock %}

View File

@ -46,12 +46,13 @@
</ul> </ul>
</div> </div>
{% endif %} {% endif %}
{% if message and message != '' %}
<pre>{{ message }}</pre>
{% endif %}
{% block main %} {% block main %}
<article class='right'> <article class='right'>
{% if message != '' %}
<pre>{{ message }}</pre>
{% endif %}
<h3>We Make THSF</h3> <h3>We Make THSF</h3>
<p>Bonjour {{ login }},</p>
<p> <p>
Comme chaque année le <a href='https://www.thsf.net>'>Toulouse Hacker Space Factory</a> aura lieu à Comme chaque année le <a href='https://www.thsf.net>'>Toulouse Hacker Space Factory</a> aura lieu à
<a href='http://mixart-myrys.org'>Mix'Art Myrys</a>. <a href='http://mixart-myrys.org'>Mix'Art Myrys</a>.
@ -71,7 +72,7 @@
de sélectionner le poste et les créneaux horaires pendant lesquels vous souhaitez vous rendre disponible. de sélectionner le poste et les créneaux horaires pendant lesquels vous souhaitez vous rendre disponible.
</li> </li>
<li> <li>
d'être tenu informé des évolutions de l'organisation et du déroulement du THSF via la mailing list du staff. de poser vos questions, obtenir des réponses et être tenu informé des évolutions de l'organisation et du déroulement du THSF via la mailing list du staff.
</li> </li>
</ul> </ul>
</p> </p>

29
templates/list_users.html Normal file
View File

@ -0,0 +1,29 @@
{% extends "index.html" %}
{% block title %}Articles{% endblock %}
{% block main %}
<article>
<h3>Liste des staffers enregistrés</h3>
<div class='table_header'>
<div class='border_right' style='width: 40px;'>ID</div>
<div class='border_right'>Mail</div>
<div class='border_right'>Nom</div>
<div class='border_right'>Téléphone</div>
<div class='border_right'>Régime / Remarques</div>
<div style='width: 50px;'>Action</div>
</div>
{% set row_class = cycler('odd', 'even') %}
{% for staffer in staffers %}
<div class='table_row {{ row_class.next() }}'>
<div class='border_right' style='width: 40px;'>{{ staffer.id }}</div>
<div class='border_right'>{{ staffer.mail }}</div>
<div class='border_right'>{{ staffer.name }}</div>
<div class='border_right'>{{ staffer.phone }}</div>
<div class='border_right'>{{ staffer.diet }}</div>
<div style='width: 50px;'>
<input class='edit' value='' onclick='javascript:document.location="/account/{{ staffer.id }}"' title='Éditer'/>
<input class='trash' value='' onclick='javascript:delete_account({{ staffer.id }});' title='Supprimer'/>
</div>
</div>
{% endfor %}
</article>
{% endblock %}

View File

@ -40,9 +40,6 @@
<p class='note'>Aucun électron n'a été maltraité lors de la mise au point de ce site. <p class='note'>Aucun électron n'a été maltraité lors de la mise au point de ce site.
Par ailleurs ce site n'utilise ni ressources hébergées par des tiers, ni bullshitwares, ni trackers.</p> Par ailleurs ce site n'utilise ni ressources hébergées par des tiers, ni bullshitwares, ni trackers.</p>
</article> </article>
{% if message != '' %}
<pre>{{ message }}</pre>
{% endif %}
<hr/> <hr/>
<article class='login'> <article class='login'>
<h3>Connexion</h3> <h3>Connexion</h3>
@ -53,6 +50,9 @@
<label>Mot de passe: </label><input id='password' name='password' type='password' /><br/> <label>Mot de passe: </label><input id='password' name='password' type='password' /><br/>
<input type='submit' value='Log me in' onclick='javascript:return verify_login();'> <input type='submit' value='Log me in' onclick='javascript:return verify_login();'>
</form> </form>
<p class='note'>
Mot de passe oublié ? Envoyez une <a href='https://bofh.tetalab.org/?do=newtask&project=2'>demande de réinitialisation de votre mot de passe</a>.
</p>
</article> </article>
<hr/> <hr/>
<article class='login'> <article class='login'>