Compare commits

...

2 Commits

Author SHA1 Message Date
Darks 3fb3ee40d2
fix: better PEP8
Flake8 returns less errors. I ignored lots of them though
2020-08-05 22:52:56 +02:00
Darks 801bd188ae
feat: add .env and .flaskenv to gitignore
Because there is no reason to track them
2020-08-05 22:16:58 +02:00
23 changed files with 54 additions and 58 deletions

9
.gitignore vendored
View File

@ -4,8 +4,12 @@ app/__pycache__/
app/static/avatars/
app/static/images/trophies/
## Devlopement files
# Development files
# Flask env
.env
.flaskenv
# virtualenv
requirements.txt
venv/
@ -14,6 +18,7 @@ venv/
Pipfile
Pipfile.lock
## Deployment files
# uWSGI configuration file
@ -25,10 +30,12 @@ update.sh
# Config to set up some server specific config
local_config.py
## Wiki
wiki/
## Personal folder
exclude/

4
V5.py
View File

@ -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

View File

@ -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

View File

@ -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):

View File

@ -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:
# <topics> List of topics in this exact forum (of type Topic)

View File

@ -1,5 +1,4 @@
from app import db
from app.models.users import User
from datetime import datetime

View File

@ -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

View File

@ -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:

View File

@ -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

View File

@ -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

View File

@ -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():

View File

@ -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,
)

View File

@ -9,7 +9,7 @@ import os
@app.route('/avatar/<filename>')
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)

View File

@ -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')

View File

@ -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')

View File

@ -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):

View File

@ -1,5 +1,5 @@
import os
from random import getrandbits
def filesize(file):
"""Return the filesize. Save in /tmp and delete it when done"""

View File

@ -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):

View File

@ -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.

View File

@ -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

View File

@ -74,7 +74,7 @@ def password(form, password):
"abcdefghijklmnopqrstuvwxyz",
"ABCDFEGHIJKLMNOPQRSTUVWXYZ",
"0123456789",
" !\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~§", # OWASP special chars
" !\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~§", # OWASP special chars
"áàâéèêíìîóòôúùûç",
]
used = set()

View File

@ -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 5Mo)")
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 500ko)")
def namelength(form, files):

View File

@ -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")