Skip to content

Commit ff30c29

Browse files
24.02.2025_added error handling and sentry integration and licence
1 parent d8b46bd commit ff30c29

67 files changed

Lines changed: 11634 additions & 2341 deletions

Some content is hidden

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

LICENSE

Lines changed: 375 additions & 374 deletions
Large diffs are not rendered by default.

chrono_des_vignes/__init__.py

Lines changed: 64 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,24 @@
1-
from flask import Flask, redirect, flash, request, session, url_for, render_template
1+
'''
2+
# Chrono Des Vignes
3+
# a timing system for sports events
4+
#
5+
# Copyright © 2024-2025 Romain Maurer
6+
# This file is part of Chrono Des Vignes
7+
#
8+
# Chrono Des Vignes is free software: you can redistribute it and/or modify it under
9+
# the terms of the GNU General Public License as published by the Free Software Foundation,
10+
# either version 3 of the License, or (at your option) any later version.
11+
#
12+
# Chrono Des Vignes is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
13+
# without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
14+
# See the GNU General Public License for more details.
15+
# You should have received a copy of the GNU General Public License along with Foobar.
16+
# If not, see <https://www.gnu.org/licenses/>.
17+
#
18+
# You may contact me at chrono-des-vignes@ikmail.com
19+
'''
20+
21+
from flask import Flask, redirect, flash, request, session, url_for, render_template, Blueprint, abort
222
from flask_login import LoginManager, current_user
323
from flask_sqlalchemy import SQLAlchemy
424
from flask_migrate import Migrate
@@ -15,17 +35,13 @@
1535
install()
1636
load_dotenv()
1737
from sqlalchemy import make_url
38+
from werkzeug import exceptions
39+
from sentry_sdk import init
40+
from sentry_sdk.integrations.flask import FlaskIntegration
1841
# met la langue en francais pour le formatage des dates
1942
import locale
2043
locale.setlocale(locale.LC_TIME,'')
2144

22-
DEFAULT_PROFIL_PIC = 'icone.png'
23-
DEV_ENABLE = True
24-
LANGAGES = ['de', 'fr', 'en']
25-
if DEV_ENABLE:
26-
LANGAGES += ['ids', 'pseudo']
27-
PICTURE_SIZE = (200, 200)
28-
2945
app = Flask(__name__)
3046
app.config['SERVER_NAME'] = 'localhost:5000'
3147
password= os.environ.get('db_password')
@@ -42,6 +58,24 @@
4258
app.jinja_env.add_extension('jinja2.ext.loopcontrols')
4359
app.url_map.default_subdomain = ''
4460

61+
DEFAULT_PROFIL_PIC = 'icone.png'
62+
LANGAGES = ['de', 'fr', 'en']
63+
if app.debug:
64+
LANGAGES += ['ids', 'pseudo']
65+
PICTURE_SIZE = (200, 200)
66+
67+
if not app.debug:
68+
ic('init sentry')
69+
init(
70+
dsn=os.environ.get('SANTRY_DSN'),
71+
send_default_pii=True,
72+
traces_sample_rate=1.0,
73+
profiles_sample_rate=1.0,
74+
integrations=[FlaskIntegration(
75+
transaction_style='endpoint'
76+
)],
77+
)
78+
4579
db = SQLAlchemy(app)
4680

4781
migrate = Migrate(app, db)
@@ -98,10 +132,11 @@ def admin_required(func):
98132

99133
@wraps(func)
100134
def decorated_view(*args, **kwargs):
135+
#ic(current_user, current_user.admin, args, kwargs)
101136
if not current_user.admin:
102137
flash(_('flash.error.mustadmin'), 'danger')
103138
return redirect(url_for('home'))
104-
if not current_user.creations.filter_by(name=kwargs.get('event_name')).first():
139+
if kwargs.get('event_name') and not current_user.creations.filter_by(name=kwargs.get('event_name')).first():
105140
flash(_('flash.error.wrongadminevent'), 'danger')
106141
return redirect(url_for('home'))
107142
return func(*args, **kwargs)
@@ -117,22 +152,37 @@ def lang_url_for(*args, **kwargs):
117152

118153
@app.context_processor
119154
def jinja_context():
120-
return dict(_=gettext, url_for=lang_url_for, now=datetime.now())
155+
return dict(_=gettext, url_for=lang_url_for, now=datetime.now(), date=datetime.now().replace(hour=0, minute=0, second=0, microsecond=0))
121156

122-
def set_route(blueprint, path, **options):
157+
def set_route(blueprint:Flask|Blueprint, path, **options):
123158
def decorator(func):
124-
@blueprint.route(path, **options)
125159
@blueprint.route(f'/<lang>{path}', **options)
160+
@blueprint.route(path, **options)
126161
@wraps(func)
127162
def wrap(*args, **kwargs):
128163
lang = kwargs.pop('lang', 'fr')
129-
if lang in LANGAGES:
130-
session['lang'] = lang
164+
#ic('hey', lang, path, func.__name__)
165+
if lang not in LANGAGES:
166+
return abort(404)
167+
session['lang'] = lang
131168
return func(*args, **kwargs)
132169
return wrap
133170

134171
return decorator
135172

173+
# ? error Handling
174+
175+
@app.errorhandler(exceptions.Forbidden)
176+
@app.errorhandler(exceptions.InternalServerError)
177+
@app.errorhandler(exceptions.MethodNotAllowed)
178+
@app.errorhandler(exceptions.NotFound)
179+
@app.errorhandler(exceptions.TooManyRequests)
180+
@app.errorhandler(exceptions.ImATeapot)
181+
def http_error(error:exceptions.HTTPException):
182+
return render_template('error/simple_error.html', error=error), error.code
183+
184+
# ? end error Handling
185+
136186
# defini les pages du site web
137187
from chrono_des_vignes.users import users
138188
from chrono_des_vignes.admin import admin

chrono_des_vignes/admin/__init__.py

Lines changed: 60 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,28 @@
1-
from flask import Blueprint, render_template, flash
1+
'''
2+
# Chrono Des Vignes
3+
# a timing system for sports events
4+
#
5+
# Copyright © 2024-2025 Romain Maurer
6+
# This file is part of Chrono Des Vignes
7+
#
8+
# Chrono Des Vignes is free software: you can redistribute it and/or modify it under
9+
# the terms of the GNU General Public License as published by the Free Software Foundation,
10+
# either version 3 of the License, or (at your option) any later version.
11+
#
12+
# Chrono Des Vignes is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
13+
# without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
14+
# See the GNU General Public License for more details.
15+
# You should have received a copy of the GNU General Public License along with Foobar.
16+
# If not, see <https://www.gnu.org/licenses/>.
17+
#
18+
# You may contact me at chrono-des-vignes@ikmail.com
19+
'''
20+
21+
from flask import Blueprint, render_template, flash, redirect
222
from flask_login import login_required, current_user
3-
from chrono_des_vignes import admin_required, set_route, db
23+
from chrono_des_vignes import admin_required, set_route, db, lang_url_for as url_for, app
424
from chrono_des_vignes.models import Event
5-
from .form import EventForm
25+
from .form import EventForm, NewEventForm
626
from .editions import editions
727
from .parcours import parcours_bp
828
from .coureurs import coureurs
@@ -13,6 +33,43 @@
1333
admin.register_blueprint(coureurs)
1434

1535

36+
@set_route(admin, '/event/<event_name>/delete', methods=['POST'])
37+
@login_required
38+
@admin_required
39+
def delete_event(event_name):
40+
event:Event = Event.query.filter_by(name=event_name).first_or_404()
41+
if event.parcours.count() or event.editions.count():
42+
flash(_('flash.event_not_deleted'), 'danger')
43+
return redirect(url_for('admin.home_event', event_name=event.name))
44+
db.session.delete(event)
45+
db.session.commit()
46+
return redirect(url_for('home'))
47+
48+
@admin.route('/event/new', methods=['POST'])
49+
@login_required
50+
@admin_required
51+
def new_event():
52+
53+
user = current_user
54+
form = NewEventForm()
55+
ic('coucou')
56+
57+
if form.validate_on_submit():
58+
name=form.name.data
59+
ic(name)
60+
61+
event = Event(name=name, createur_id=user.id)
62+
db.session.add(event)
63+
db.session.commit()
64+
65+
return redirect(url_for('admin.home_event', event_name=event.name))
66+
else:
67+
ic(form.errors)
68+
for error in form.name.errors:
69+
flash(error, 'danger')
70+
return redirect(url_for('home'))
71+
72+
1673
@set_route(admin, '/event/<event_name>', methods=['POST', 'GET'])
1774
@login_required
1875
@admin_required
@@ -31,4 +88,3 @@ def home_event(event_name):
3188
flash('l\'évenement a bien été mise a jour.', 'success')
3289

3390
return render_template("home_event.html", user_data=user, event_data=event_data, form=event_form, event_modif=True)
34-

chrono_des_vignes/admin/editions/__init__.py

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,23 @@
1+
'''
2+
# Chrono Des Vignes
3+
# a timing system for sports events
4+
#
5+
# Copyright © 2024-2025 Romain Maurer
6+
# This file is part of Chrono Des Vignes
7+
#
8+
# Chrono Des Vignes is free software: you can redistribute it and/or modify it under
9+
# the terms of the GNU General Public License as published by the Free Software Foundation,
10+
# either version 3 of the License, or (at your option) any later version.
11+
#
12+
# Chrono Des Vignes is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
13+
# without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
14+
# See the GNU General Public License for more details.
15+
# You should have received a copy of the GNU General Public License along with Foobar.
16+
# If not, see <https://www.gnu.org/licenses/>.
17+
#
18+
# You may contact me at chrono-des-vignes@ikmail.com
19+
'''
20+
121
from flask import Blueprint, flash, render_template, redirect, request
222
from chrono_des_vignes import admin_required, db, set_route, lang_url_for as url_for
323
from chrono_des_vignes.admin.editions.form import Edition_form
@@ -28,11 +48,13 @@ def editions_page(event_name):
2848
if form.validate_on_submit():
2949
if not event.editions.filter_by(name=form.name.data).first():
3050
#ok nom pas utilisé
51+
parcours = [eval(p)[0] for p in form.parcours.data]
52+
parcours = event.parcours.filter(Parcours.name.in_(parcours)).all()
3153
edition = Edition(name = form.name.data,
3254
event_id=event.id,
33-
parcours=event.parcours.filter(Parcours.name.in_(form.parcours.data)).all(),
55+
parcours=parcours,
3456
edition_date=form.edition_date.data,
35-
description = form.description,
57+
description = form.description.data,
3658
first_inscription=form.first_inscription.data,
3759
last_inscription=form.last_inscription.data,
3860
rdv_lat=form.rdv_lat.data,

chrono_des_vignes/admin/editions/dossard/templates/dossard.html

Lines changed: 22 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,23 @@
1+
<!--
2+
* Chrono Des Vignes
3+
* a timing system for sports events
4+
*
5+
* Copyright © 2024-2025 Romain Maurer
6+
* This file is part of Chrono Des Vignes
7+
*
8+
* Chrono Des Vignes is free software: you can redistribute it and/or modify it under
9+
* the terms of the GNU General Public License as published by the Free Software Foundation,
10+
* either version 3 of the License, or (at your option) any later version.
11+
*
12+
* Chrono Des Vignes is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
13+
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
14+
* See the GNU General Public License for more details.
15+
* You should have received a copy of the GNU General Public License along with Foobar.
16+
* If not, see <https://www.gnu.org/licenses/>.
17+
*
18+
* You may contact me at chrono-des-vignes@ikmail.com
19+
-->
20+
121
{% extends 'layout.html' %}
222
{% block import %}
323
<script src="https://cdnjs.cloudflare.com/ajax/libs/socket.io/4.0.1/socket.io.js" integrity="sha512-q/dWJ3kcmjBLU4Qc47E4A9kTB4m3wuTY7vkFJDTZKjTs8jhyGQnaUrxa0Ytd0ssMZhbNua9hE+E7Qv1j+DyZwA==" crossorigin="anonymous"></script>
@@ -21,7 +41,7 @@
2141
<td id="inscription_{{inscription.id}}"><a href="javascript:change_dossard({{inscription.id}})"><i class="fa-solid fa-pen-to-square"></i></a> {% if inscription.dossard %}{{inscription.dossard}}{% endif %}</td>
2242
<td>{{inscription.parcours.name}}</td>
2343
{% if now > edition_data.edition_date %}
24-
<td><div class="form-check form-switch"><input id="presence_{{inscription.id}}" class="form-check-input" type="checkbox" {% if inscription.present %}checked{% endif %} ></div></td>
44+
<td><div class="form-check form-switch"><input id="presence_{{inscription.id}}" class="form-check-input" type="checkbox" {% if inscription.present %}checked{% endif %} /></div></td>
2545
<script>
2646
document.getElementById("presence_{{inscription.id}}").addEventListener('click', function(event){
2747
event.preventDefault()
@@ -33,11 +53,7 @@
3353
{% endfor %}
3454
</tbody>
3555
</table>
36-
<script>
37-
$('table tbody tr').on('click', function() {
38-
window.location.href = $(this).data('href');
39-
});
40-
</script>
56+
4157

4258
<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>
4359
<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>

chrono_des_vignes/admin/editions/form.py

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,23 @@
1+
'''
2+
# Chrono Des Vignes
3+
# a timing system for sports events
4+
#
5+
# Copyright © 2024-2025 Romain Maurer
6+
# This file is part of Chrono Des Vignes
7+
#
8+
# Chrono Des Vignes is free software: you can redistribute it and/or modify it under
9+
# the terms of the GNU General Public License as published by the Free Software Foundation,
10+
# either version 3 of the License, or (at your option) any later version.
11+
#
12+
# Chrono Des Vignes is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
13+
# without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
14+
# See the GNU General Public License for more details.
15+
# You should have received a copy of the GNU General Public License along with Foobar.
16+
# If not, see <https://www.gnu.org/licenses/>.
17+
#
18+
# You may contact me at chrono-des-vignes@ikmail.com
19+
'''
20+
121
from flask_wtf import FlaskForm
222
from wtforms import StringField, DateTimeLocalField, FloatField, SubmitField, TextAreaField
323
from chrono_des_vignes.custom_validators import DataRequired, Length, DateTimeNotPast, DateTimeBefore, InputRequired
@@ -11,6 +31,6 @@ class Edition_form(FlaskForm):
1131
parcours = MultiCheckboxFieldWithDescription(_('form.parcours'), validators=[DataRequired()])
1232
first_inscription = DateTimeLocalField(_('form.firstinscriptiondate'), format='%Y-%m-%dT%H:%M', render_kw={}, validators=[DataRequired(), DateTimeNotPast(), DateTimeBefore('last_inscription')])
1333
last_inscription = DateTimeLocalField(_('form.lastinscriptiondate'), format='%Y-%m-%dT%H:%M', render_kw={}, validators=[DataRequired(), DateTimeNotPast(), DateTimeBefore('edition_date')])
14-
rdv_lat= FloatField(_('form.rdvlng'), validators=[DataRequired()], default=0)
15-
rdv_lng= FloatField(_('form.rdvlat'), validators=[DataRequired()], default=0)
34+
rdv_lat= FloatField(_('form.rdvlng'), validators=[DataRequired()], default=46.54685605692591)
35+
rdv_lng= FloatField(_('form.rdvlat'), validators=[DataRequired()], default=6.449900437449806)
1636
submit_btn = SubmitField(_('form.save'))

0 commit comments

Comments
 (0)