diff --git a/V5.py b/V5.py index f395e0e..5745db6 100644 --- a/V5.py +++ b/V5.py @@ -1,6 +1,4 @@ -from app import app, db -from app.models.users import User, Guest, Member, Group, GroupPrivilege -from app.models.topic import Topic +from app import app @app.shell_context_processor diff --git a/app/forms/account.py b/app/forms/account.py index 3115ddb..72b22c5 100644 --- a/app/forms/account.py +++ b/app/forms/account.py @@ -1,9 +1,8 @@ from flask_wtf import FlaskForm from wtforms import StringField, PasswordField, BooleanField, TextAreaField, SubmitField, DecimalField, SelectField from wtforms.fields.html5 import DateField, EmailField -from wtforms.validators import DataRequired, InputRequired, Optional, Email, EqualTo +from wtforms.validators import DataRequired, Optional, Email, EqualTo from flask_wtf.file import FileField # Cuz' wtforms' FileField is shitty -from app.models.trophies import Trophy import app.utils.validators as vd diff --git a/app/forms/forum.py b/app/forms/forum.py index c9ab038..01480ff 100644 --- a/app/forms/forum.py +++ b/app/forms/forum.py @@ -1,7 +1,6 @@ from flask_wtf import FlaskForm -from wtforms import StringField, FormField, SubmitField, TextAreaField, \ - MultipleFileField -from wtforms.validators import DataRequired, Length, Optional +from wtforms import StringField, SubmitField, TextAreaField, MultipleFileField +from wtforms.validators import DataRequired, Length import app.utils.validators as vd class CommentForm(FlaskForm): diff --git a/app/models/forum.py b/app/models/forum.py index 48aaffc..d661b4b 100644 --- a/app/models/forum.py +++ b/app/models/forum.py @@ -16,8 +16,8 @@ class Forum(db.Model): # Relationships parent_id = db.Column(db.Integer, db.ForeignKey('forum.id'), nullable=True) - parent = db.relationship('Forum', backref='sub_forums', remote_side=id, - lazy=True, foreign_keys=parent_id) + parent = db.relationship('Forum', backref='sub_forums', remote_side=id, + lazy=True, foreign_keys=parent_id) # Other fields populated automatically through relations: # List of topics in this exact forum (of type Topic) diff --git a/app/models/post.py b/app/models/post.py index 88daabb..0f6dc2c 100644 --- a/app/models/post.py +++ b/app/models/post.py @@ -1,5 +1,4 @@ from app import db -from app.models.users import User from datetime import datetime diff --git a/app/models/program.py b/app/models/program.py index ef762f2..8ce6095 100644 --- a/app/models/program.py +++ b/app/models/program.py @@ -16,8 +16,8 @@ class Program(Post): # TODO: Compatible calculator models thread_id = db.Column(db.Integer,db.ForeignKey('thread.id'),nullable=False) - thread = db.relationship('Thread', foreign_keys=thread_id, - back_populates='owner_program') + thread = db.relationship('Thread', foreign_keys=thread_id, + back_populates='owner_program') # TODO: Number of views, statistics, attached files, etc diff --git a/app/models/thread.py b/app/models/thread.py index 6b62341..e623fee 100644 --- a/app/models/thread.py +++ b/app/models/thread.py @@ -10,11 +10,11 @@ class Thread(db.Model): # Top comment top_comment_id = db.Column(db.Integer, db.ForeignKey('comment.id')) - top_comment = db.relationship('Comment', foreign_keys=top_comment_id) + top_comment = db.relationship('Comment', foreign_keys=top_comment_id) # Post owning the thread, set only by Topic, Program, etc. In general, you # should use [owner_post] which groups them together. - owner_topic = db.relationship('Topic') + owner_topic = db.relationship('Topic') owner_program = db.relationship('Program') # Other fields populated automatically through relations: diff --git a/app/models/topic.py b/app/models/topic.py index 4afe5db..1dcd8a8 100644 --- a/app/models/topic.py +++ b/app/models/topic.py @@ -16,19 +16,19 @@ class Topic(Post): # Post that the topic was promoted into. If this is not None, then the # topic was published into a project and a redirection should be emitted promotion_id = db.Column(db.Integer,db.ForeignKey('post.id'),nullable=True) - promotion = db.relationship('Post', foreign_keys=promotion_id) + promotion = db.relationship('Post', foreign_keys=promotion_id) # Topic title title = db.Column(db.Unicode(128)) # Parent forum forum_id = db.Column(db.Integer, db.ForeignKey('forum.id'), nullable=False) - forum = db.relationship('Forum', - backref=backref('topics', lazy='dynamic'),foreign_keys=forum_id) + forum = db.relationship('Forum', + backref=backref('topics', lazy='dynamic'), foreign_keys=forum_id) # Associated thread thread_id = db.Column(db.Integer,db.ForeignKey('thread.id'),nullable=False) - thread = db.relationship('Thread', foreign_keys=thread_id, + thread = db.relationship('Thread', foreign_keys=thread_id, back_populates='owner_topic') # Number of views in the forum diff --git a/app/models/users.py b/app/models/users.py index 63493c2..40c45de 100644 --- a/app/models/users.py +++ b/app/models/users.py @@ -1,5 +1,4 @@ from datetime import date -from flask import flash from flask_login import UserMixin from sqlalchemy import func as SQLfunc from os.path import isfile @@ -10,12 +9,10 @@ from app.models.privs import SpecialPrivilege, Group, GroupMember, \ from app.models.trophies import Trophy, TrophyMember, Title from app.models.notification import Notification import app.utils.unicode_names as unicode_names -from app.utils.notify import notify import app.utils.ldap as ldap from config import V5Config import werkzeug.security -import re import math import app import os @@ -78,8 +75,7 @@ class Member(User): # Primary attributes (needed for the system to work) name = db.Column(db.Unicode(User.NAME_MAXLEN), index=True) - norm = db.Column(db.Unicode(User.NAME_MAXLEN), index=True, - unique=True) + norm = db.Column(db.Unicode(User.NAME_MAXLEN), index=True, unique=True) email = db.Column(db.Unicode(120), index=True, unique=True) email_confirmed = db.Column(db.Boolean) password_hash = db.Column(db.String(255)) @@ -107,7 +103,7 @@ class Member(User): # Displayed title, if set title_id = db.Column(db.Integer, db.ForeignKey('title.id'), nullable=True) - title = db.relationship('Title', foreign_keys=title_id) + title = db.relationship('Title', foreign_keys=title_id) # Settings newsletter = db.Column(db.Boolean, default=False) @@ -158,7 +154,7 @@ class Member(User): if SpecialPrivilege.query.filter_by(mid=self.id, priv=priv).first(): return True return db.session.query(Group, GroupPrivilege).filter( - Group.id.in_([ g.id for g in self.groups ]), + Group.id.in_([g.id for g in self.groups]), GroupPrivilege.gid==Group.id, GroupPrivilege.priv==priv).first() is not None diff --git a/app/processors/menu.py b/app/processors/menu.py index eae5737..d7b2007 100644 --- a/app/processors/menu.py +++ b/app/processors/menu.py @@ -3,9 +3,7 @@ from app.forms.login import LoginForm from app.forms.search import SearchForm from app.models.forum import Forum from app.models.topic import Topic -from app.models.thread import Thread -from app.models.comment import Comment -from app.models.users import Member + @app.context_processor def menu_processor(): diff --git a/app/processors/utilities.py b/app/processors/utilities.py index ad6dbde..7200fb8 100644 --- a/app/processors/utilities.py +++ b/app/processors/utilities.py @@ -9,7 +9,7 @@ def utilities_processor(): return dict( len=len, # enumerate=enumerate, - _url_for = lambda route, args, **other: url_for(route, **args, **other), - V5Config = V5Config, + _url_for=lambda route, args, **other: url_for(route, **args, **other), + V5Config=V5Config, slugify=slugify, ) diff --git a/app/routes/development.py b/app/routes/development.py index 0cbad14..f4f4cc0 100644 --- a/app/routes/development.py +++ b/app/routes/development.py @@ -9,7 +9,7 @@ import os @app.route('/avatar/') def avatar(filename): - filename = secure_filename(filename) # No h4ckers allowed + filename = secure_filename(filename) # No h4ckers allowed filepath = os.path.join(V5Config.DATA_FOLDER, "avatars", filename) if os.path.isfile(filepath): return send_file(filepath) diff --git a/app/routes/forum/index.py b/app/routes/forum/index.py index 892ad90..8843824 100644 --- a/app/routes/forum/index.py +++ b/app/routes/forum/index.py @@ -72,7 +72,7 @@ def forum_page(f, page=1): # Update member's xp and trophies if current_user.is_authenticated: - current_user.add_xp(2) # 2 points for a topic + current_user.add_xp(2) # 2 points for a topic current_user.update_trophies('new-post') flash('Le sujet a bien été créé', 'ok') diff --git a/app/routes/forum/topic.py b/app/routes/forum/topic.py index f3ab5ec..d150c65 100644 --- a/app/routes/forum/topic.py +++ b/app/routes/forum/topic.py @@ -53,7 +53,7 @@ def forum_topic(f, page): # Update member's xp and trophies if current_user.is_authenticated: - current_user.add_xp(1) # 1 point for a comment + current_user.add_xp(1) # 1 point for a comment current_user.update_trophies('new-post') flash('Message envoyé', 'ok') diff --git a/app/utils/converters.py b/app/utils/converters.py index 7fb7a81..3caae7b 100644 --- a/app/utils/converters.py +++ b/app/utils/converters.py @@ -20,8 +20,7 @@ from werkzeug.routing import BaseConverter, ValidationError from app.models.forum import Forum from app.models.topic import Topic from slugify import slugify -import re -import sys + class ForumConverter(BaseConverter): diff --git a/app/utils/filesize.py b/app/utils/filesize.py index 56e900e..888afff 100644 --- a/app/utils/filesize.py +++ b/app/utils/filesize.py @@ -1,5 +1,5 @@ import os -from random import getrandbits + def filesize(file): """Return the filesize. Save in /tmp and delete it when done""" diff --git a/app/utils/ldap.py b/app/utils/ldap.py index c3d21fb..4e62639 100644 --- a/app/utils/ldap.py +++ b/app/utils/ldap.py @@ -1,9 +1,11 @@ import ldap from ldap.modlist import addModlist, modifyModlist +from app.utils.unicode_names import normalize from config import V5Config def get_member(username): - """ Get informations about member. Username must be normalized! """ + """ Get informations about member""" + username = normalize(username) # Never safe enough conn = ldap.initialize("ldap://localhost") # Search for user r = conn.search_s(V5Config.LDAP_ORGANIZATION, ldap.SCOPE_SUBTREE, @@ -17,13 +19,15 @@ def get_member(username): def edit(user, fields): """ Edit a user. Fields is {'name': ['value'], …} """ conn = ldap.initialize("ldap://localhost") + # TODO: do this # Connect as root - # conn.simple_bind_s(f'cn=ldap-root,{LDAP_ORGANIZATION}', LDAP_PASSWORD) + # conn.simple_bind_s(f'cn=ldap-root,{V5Config.LDAP_ORGANIZATION}', + # V5Config.LDAP_PASSWORD) # old_value = {"userPassword": ["my_old_password"]} # new_value = {"userPassword": ["my_new_password"]} - modlist = ldap.modlist.modifyModlist(old_value, new_value) - con.modify_s(dn, modlist) + # modlist = modifyModlist(old_value, new_value) + # conn.modify_s(dn, modlist) def set_email(user, email): diff --git a/app/utils/notify.py b/app/utils/notify.py index 2a98dc8..86d9f80 100644 --- a/app/utils/notify.py +++ b/app/utils/notify.py @@ -1,6 +1,6 @@ from app import db from app.models.notification import Notification -# from app.models.users import Member +from app.models.users import Member def notify(user, message, href=None): """ Notify a user (by id, name or object reference) with a message. diff --git a/app/utils/render.py b/app/utils/render.py index f2f9f75..262944f 100644 --- a/app/utils/render.py +++ b/app/utils/render.py @@ -1,7 +1,4 @@ from flask import render_template -from app.forms.login import LoginForm -from app.forms.search import SearchForm -from app.models.forum import Forum def render(*args, styles=[], scripts=[], **kwargs): # TODO: debugguer cette merde : au logout, ça foire diff --git a/app/utils/validators/__init__.py b/app/utils/validators/__init__.py index b93b9e6..c02d089 100644 --- a/app/utils/validators/__init__.py +++ b/app/utils/validators/__init__.py @@ -74,7 +74,7 @@ def password(form, password): "abcdefghijklmnopqrstuvwxyz", "ABCDFEGHIJKLMNOPQRSTUVWXYZ", "0123456789", - " !\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~§", # OWASP special chars + " !\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~§", # OWASP special chars "áàâéèêíìîóòôúùûç", ] used = set() diff --git a/app/utils/validators/file.py b/app/utils/validators/file.py index fd1f743..c120ef6 100644 --- a/app/utils/validators/file.py +++ b/app/utils/validators/file.py @@ -12,7 +12,7 @@ def count(form, files): if current_user.is_authenticated: if current_user.priv("no-upload-limits"): return - if len(files.data) > 100: # 100 files for a authenticated user + if len(files.data) > 100: # 100 files for a authenticated user raise ValidationError("100 fichiers maximum autorisés") else: if len(files.data) > 3: @@ -20,11 +20,11 @@ def count(form, files): def extension(form, files): valid_extensions = [ - "g[123][a-z]|cpa|c1a|fxi|cat|mcs|xcp|fls", # Casio files - "png|jpg|jpeg|bmp|tiff|gif|xcf", # Images - "[ch](pp|\+\+|xx)?|s|py|bide|lua|lc", # Source code - "txt|md|tex|pdf|odt|ods|docx|xlsx", # Office files - "zip|7z|tar|bz2?|t?gz|xz|zst", # Archives + "g[123][a-z]|cpa|c1a|fxi|cat|mcs|xcp|fls", # Casio files + "png|jpg|jpeg|bmp|tiff|gif|xcf", # Images + "[ch](pp|\+\+|xx)?|s|py|bide|lua|lc", # Source code + "txt|md|tex|pdf|odt|ods|docx|xlsx", # Office files + "zip|7z|tar|bz2?|t?gz|xz|zst", # Archives ] r = re.compile("|".join(valid_extensions), re.IGNORECASE) errors = [] @@ -44,10 +44,10 @@ def size(form, files): if current_user.is_authenticated: if current_user.priv("no-upload-limits"): return - if size > 5e6: # 5 Mo per comment for an authenticated user + if size > 5e6: # 5 Mo per comment for an authenticated user raise ValidationError("Fichiers trop lourds (max 5 Mo)") else: - if size > 500e3: # 500 ko per comment for a guest + if size > 500e3: # 500 ko per comment for a guest raise ValidationError("Fichiers trop lourds (max 500 ko)") def namelength(form, files): diff --git a/master.py b/master.py index 5e617c8..f03ccc8 100755 --- a/master.py +++ b/master.py @@ -3,16 +3,16 @@ from app import app, db from app.models.users import Member, Group, GroupPrivilege from app.models.privs import SpecialPrivilege -from app.models.trophies import Trophy, Title, TrophyMember +from app.models.trophies import Trophy, Title from app.models.forum import Forum from app.utils import unicode_names import os import sys import yaml -import readline import slugify from PIL import Image + help_msg = """ This is the Planète Casio master shell. Type 'exit' or C-D to leave. @@ -186,7 +186,7 @@ def create_trophies(): print(f"Created {len(tr)} trophies.") # Create their icons in /app/static/images/trophies - names = [ slugify.slugify(t["name"]) for t in tr ] + names = [slugify.slugify(t["name"]) for t in tr] src = os.path.join(app.root_path, "data", "trophies.png") dst = os.path.join(app.root_path, "static", "images", "trophies")