Skip to content

Commit cd78a28

Browse files
18.1.2025_ ajout documentation (subdomain doc.) avec mkdocs + last minute inscription des coureurs
1 parent 0442153 commit cd78a28

86 files changed

Lines changed: 12593 additions & 412 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

flask_app/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
from flask import Flask, redirect, flash, request, session, url_for
1+
from flask import Flask, redirect, flash, request, session, url_for, render_template
22
from flask_login import LoginManager, current_user
33
from flask_sqlalchemy import SQLAlchemy
44
from flask_migrate import Migrate

flask_app/admin/__init__.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,9 @@
33
from flask_app import admin_required, set_route, db
44
from flask_app.models import Event
55
from .form import EventForm
6-
from flask_app.admin.editions import editions
7-
from flask_app.admin.parcours import parcours_bp
8-
from flask_app.admin.coureurs import coureurs
6+
from .editions import editions
7+
from .parcours import parcours_bp
8+
from .coureurs import coureurs
99

1010
admin = Blueprint('admin', __name__, template_folder='templates')
1111
admin.register_blueprint(parcours_bp)

flask_app/admin/editions/__init__.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,10 @@
44
from flask_login import login_required, current_user
55
from flask_app.models import Event, Parcours, Edition
66
from datetime import datetime
7-
from flask_app.admin.editions.dossard import dossard
8-
from flask_app.admin.editions.passages import passages
9-
from flask_app.admin.editions.parcours import parcours
10-
from flask_app.admin.editions.result import result
7+
from .dossard import dossard
8+
from .passages import passages
9+
from .parcours import parcours
10+
from .result import result
1111
from sqlalchemy import or_
1212

1313
editions = Blueprint('editions', __name__, template_folder='templates')

flask_app/admin/editions/dossard/__init__.py

Lines changed: 138 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,16 @@
1-
from flask import Blueprint, flash, render_template, redirect, url_for, request, session
1+
from flask import Blueprint, flash, render_template, redirect, url_for, request, session, send_file
22
from flask_app import admin_required, db, set_route, socketio
33
from flask_app.admin.editions.form import Edition_form
44
from flask_login import login_required, current_user
5-
from flask_app.models import Event, Parcours, Edition, Inscription
5+
from flask_app.models import Event, Parcours, Edition, Inscription, User
66
from datetime import datetime
77
from flask_socketio import join_room, leave_room
8+
from xlsxwriter import Workbook
9+
from io import BytesIO
10+
from flask_babel import _
11+
from flask_app.custom_validators import DataRequired, Length, EqualTo, DonTExist, DbLength
12+
from .form import NewCoureurForm, ValidateNewCoureurForm
13+
from sqlalchemy import func, and_, or_, not_
814

915
dossard = Blueprint('dossard', __name__, template_folder='templates')
1016

@@ -24,8 +30,88 @@ def generate_dossard(event_name, edition_name):
2430
edition : Edition= event.editions.filter_by(name=edition_name).first_or_404()
2531
user = current_user
2632

33+
form = NewCoureurForm()
34+
choices = edition.parcours
35+
form.parcours.choices = [str((p.name, p.description)) for p in choices]
2736

28-
return render_template('generate_dossard.html', user_data=user, event_data=event, edition_data=edition, now=datetime.now(), inscriptions=edition.inscriptions, event_modif=True, edition_sidebar=True)
37+
if form.validate_on_submit():
38+
users = User.query.filter(and_(or_(func.lower(User.username)==func.lower(form.username.data),
39+
and_(func.lower(User.name)==func.lower(form.name.data), func.lower(User.lastname)==func.lower(form.lastname.data))),
40+
User.datenaiss==form.datenaiss.data)).all()
41+
if len(users) > 0:
42+
validate_form = ValidateNewCoureurForm()
43+
else:
44+
validate_form = None
45+
46+
supp_validators = {
47+
'name':[DataRequired(), DbLength(User, 'name')],
48+
'lastname':[DataRequired(), DbLength(User, 'lastname')],
49+
'username':[DataRequired(), DbLength(User, 'username')],
50+
'email':[DataRequired(), DbLength(User, 'email')]
51+
}
52+
ic('first validation', form.validate(extra_validators=supp_validators), form.parcours.data)
53+
if form.validate(extra_validators=supp_validators):
54+
# create a new user with the form data and add it to all the parcours
55+
username=f'{form.name.data}.{form.lastname.data}'
56+
nb = User.query.filter(User.username.contains(username)).count()
57+
username += str(nb) if nb>0 else ''
58+
hash_pwd= 'dev' #! ''.join(secrets.choice(alphabet) for _ in range(10))
59+
60+
choices = event.parcours.filter(Parcours.name.in_([eval(data)[0] for data in form.parcours.data])).all()
61+
user = User(name=form.name.data,
62+
lastname=form.lastname.data,
63+
username=username,
64+
email=form.email.data if form.email.data else None,
65+
phone=form.phone.data if form.phone.data else None,
66+
datenaiss= form.datenaiss.data,
67+
password=hash_pwd)
68+
db.session.add(user)
69+
db.session.commit()
70+
db.session.refresh(user)
71+
inscriptions = []
72+
for parcours in choices:
73+
inscriptions.append(Inscription(user_id = user.id,
74+
event_id=event.id,
75+
edition_id=edition.id,
76+
parcours_id=parcours.id))
77+
db.session.add_all(inscriptions)
78+
db.session.commit()
79+
80+
else:
81+
users = []
82+
validate_form = None
83+
84+
return render_template('generate_dossard.html', user_data=user, event_data=event, edition_data=edition, now=datetime.now(), inscriptions=edition.inscriptions, event_modif=True, edition_sidebar=True, form=form, validate_form=validate_form, validate_users=users)
85+
86+
@set_route(dossard, '/event/<event_name>/editions/<edition_name>/dossard/newuser', methods=['POST'])
87+
@login_required
88+
@admin_required
89+
def validate_new_user(event_name, edition_name):
90+
event = Event.query.filter_by(name=event_name).first_or_404()
91+
edition : Edition= event.editions.filter_by(name=edition_name).first_or_404()
92+
form = ValidateNewCoureurForm()
93+
form.parcours.choices = [str((p.name, p.description)) for p in edition.parcours]
94+
ic(form.parcours.data)
95+
if form.validate_on_submit():
96+
user = User.query.get_or_404(form.user_id.data)
97+
98+
choices = event.parcours.filter(Parcours.name.in_([eval(data)[0] for data in form.parcours.data]),
99+
not_(Parcours.inscriptions.any(Inscription.user_id==user.id))).all()
100+
101+
inscriptions = []
102+
for parcours in choices:
103+
inscriptions.append(Inscription(user_id = user.id,
104+
event_id=event.id,
105+
edition_id=edition.id,
106+
parcours_id=parcours.id))
107+
db.session.add_all(inscriptions)
108+
db.session.commit()
109+
110+
flash(_('flash.success.newuser:username:name:lastname').format(username=user.username, name=user.name, lastname=user.lastname), 'success')
111+
112+
return redirect(url_for('admin.editions.dossard.generate_dossard', event_name=event_name, edition_name=edition_name))
113+
else:
114+
return {'ok':False}
29115

30116
@socketio.on('connect', namespace='/dossard')
31117
def dossard_connect(auth):
@@ -87,3 +173,52 @@ def generate_all_dossard(event_name, edition_name):
87173
db.session.commit()
88174

89175
return redirect(url_for("admin.editions.dossard.generate_dossard", event_name=event.name, edition_name=edition.name))
176+
177+
178+
# methode for download dossard as excel
179+
@set_route(dossard, '/event/<event_name>/editions/<edition_name>/dossard/download', methods=['POST', 'GET'])
180+
@login_required
181+
@admin_required
182+
def export_dossard(event_name, edition_name):
183+
event : Event = Event.query.filter_by(name=event_name).first_or_404()
184+
edition : Edition= event.editions.filter_by(name=edition_name).first_or_404()
185+
user = current_user
186+
187+
buffer = BytesIO()
188+
189+
workbook = Workbook(buffer)
190+
worksheet = workbook.add_worksheet()
191+
192+
headers = [_('admin.editions.dossard.dossard'),
193+
_('admin.editions.dossard.name'),
194+
_('admin.editions.dossard.lastname'),
195+
_('admin.editions.dossard.email'),
196+
_('admin.editions.dossard.phone'),
197+
_('admin.editions.dossard.datenaiss'),
198+
_('admin.editions.dossard.username'),
199+
_('admin.editions.dossard.parcours'),
200+
_('admin.editions.dossard.edition_date'),
201+
_('admin.editions.dossard.edition_name'),
202+
_('admin.editions.dossard.event_name')]
203+
204+
row :int
205+
for row, inscription in enumerate(edition.inscriptions.all(), 1):
206+
# dossard, name, lastname, email, phone, datenaiss, username, parcours, edition_date, edition_name, event_name
207+
worksheet.write(row, 0, inscription.dossard)
208+
worksheet.write(row, 1, inscription.inscrit.name)
209+
worksheet.write(row, 2, inscription.inscrit.lastname)
210+
worksheet.write(row, 3, inscription.inscrit.email)
211+
worksheet.write(row, 4, inscription.inscrit.phone)
212+
worksheet.write(row, 5, inscription.inscrit.datenaiss)
213+
worksheet.write(row, 6, inscription.inscrit.username)
214+
worksheet.write(row, 7, inscription.parcours.name)
215+
worksheet.write(row, 8, inscription.edition.edition_date)
216+
worksheet.write(row, 9, inscription.edition.name)
217+
worksheet.write(row, 10, inscription.event.name)
218+
219+
worksheet.add_table(0,0,max(edition.inscriptions.count(), 1),len(headers)-1, {'columns': [{'header': h} for h in headers], 'autofilter': False})
220+
worksheet.autofit()
221+
workbook.close()
222+
223+
buffer.seek(0)
224+
return send_file(buffer, download_name='dossard.xlsx', as_attachment=True)
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
from flask_wtf import FlaskForm
2+
from wtforms import StringField, DateTimeLocalField, FloatField, SubmitField, TextAreaField, EmailField, DateField, IntegerField, TelField
3+
from flask_app.custom_validators import DataRequired, Length, DateTimeNotPast, DateTimeBefore, InputRequired
4+
from flask_app.custom_field import MultiCheckboxFieldWithDescription
5+
from flask_babel import lazy_gettext as _
6+
from flask_app.models import User
7+
8+
from flask_app.custom_validators import DbLength
9+
10+
class NewCoureurForm(FlaskForm):
11+
name = StringField(_('form.name'), validators=[DbLength(table=User, column='name')])
12+
lastname = StringField(_('form.lastname'), validators=[DbLength(table=User, column='lastname')])
13+
username = StringField(_('form.username'))
14+
email = EmailField(_('form.email'))
15+
phone = TelField(_('form.tel'))
16+
datenaiss = DateField(_('form.birth'), validators=[DataRequired()])
17+
18+
parcours = MultiCheckboxFieldWithDescription(_('form.choosedparcours'), validators=[DataRequired()])
19+
20+
submit_btn = SubmitField(_('form.register'))
21+
22+
class ValidateNewCoureurForm(FlaskForm):
23+
user_id = IntegerField('user_id', validators=[DataRequired()])
24+
25+
name = StringField(_('form.name'), validators=[DbLength(table=User, column='name')])
26+
lastname = StringField(_('form.lastname'), validators=[DbLength(table=User, column='lastname')])
27+
username = StringField(_('form.username'))
28+
email = EmailField(_('form.email'))
29+
phone = TelField(_('form.tel'))
30+
datenaiss = DateField(_('form.birth'), validators=[DataRequired()])
31+
32+
parcours = MultiCheckboxFieldWithDescription(_('form.choosedparcours'), validators=[DataRequired()])

flask_app/admin/editions/dossard/templates/generate_dossard.html

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,11 @@
66
<table class="table">
77
<thead>
88
<tr>
9-
<th scope="col">coureur</th>
10-
<th scope="col">dossard</th>
11-
<th scope="col">parcours</th>
9+
<th scope="col">{{ _('admin.editions.dossard.coureur') }}</th>
10+
<th scope="col">{{ _('admin.editions.dossard.dossard') }}</th>
11+
<th scope="col">{{ _('admin.editions.dossard.parcours') }}</th>
1212
{% if now > edition_data.edition_date %}
13-
<th scope="col">present</th>
13+
<th scope="col">{{ _('admin.editions.dossard.present') }}</th>
1414
{% endif %}
1515
</tr>
1616
</thead>
@@ -34,7 +34,10 @@
3434
</tbody>
3535
</table>
3636

37-
<a class="btn bg-info" href="{{ url_for('admin.editions.dossard.generate_all_dossard', event_name=event_data.name, edition_name=edition_data.name) }}">generer</a>
37+
<a class="btn bg-info" href="{{ url_for('admin.editions.dossard.generate_all_dossard', event_name=event_data.name, edition_name=edition_data.name) }}">{{ _('admin.editions.dossard.generer') }}</a>
38+
<a class="btn bg-success" href="{{ url_for('admin.editions.dossard.export_dossard', event_name=event_data.name, edition_name=edition_data.name) }}" target="_blank" rel="noopener noreferrer">{{ _('admin.editions.dossard.export_excel') }}</a>
39+
<br><br>
40+
<a class="btn bg-info" onclick="modal.show()">{{ _('admin.editions.dossard.addnewcoureur') }}</a>
3841

3942
<script>
4043
var socket = io('/dossard', {auth:{'event_id': {{ event_data.id }}, 'edition_id': {{ edition_data.id }} } })
@@ -73,4 +76,6 @@
7376

7477
</script>
7578

79+
{% include "new_coureur_modal.html" %}
80+
7681
{% endblock content %}

0 commit comments

Comments
 (0)