From 51b016aa69b5dbfbbb24b517cd78e50017a79412 Mon Sep 17 00:00:00 2001 From: kitoy Date: Sat, 27 Dec 2025 07:16:39 +0100 Subject: [PATCH] Rework invitation system and add qrcode --- base.db.old | Bin 0 -> 61440 bytes templates/invitation.html | 18 +++++++++----- tools/utils.py | 18 +++++++++++--- views/inscription.py | 49 ++++++++++++++++++++------------------ views/loginlogout.py | 2 +- views/profil.py | 26 ++++++++++++++------ 6 files changed, 73 insertions(+), 40 deletions(-) create mode 100644 base.db.old diff --git a/base.db.old b/base.db.old new file mode 100644 index 0000000000000000000000000000000000000000..9a2091aa4c0c6399090ec57fefadb611ca8b28d4 GIT binary patch literal 61440 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 Si vous voulez vous pouvez inviter une personne à se crée un compte sur ce serveur - pour cela vous devez crée un lien d'inscription. Ce lien restera valable tant - que la personne ne s'est pas inscrite ou tant que vous ne créez pas un autre lien. - Les invitations se font une par une et sont limité à 20 personnes pour ne pas surcharger notre petit serveur :). - Une fois que la personne s'est incrite votre nombre d'invitations sera mis à jour + pour cela vous devez crée un lien d'inscription. Ce lien restera valable tant que vous ne créez pas un autre lien. + Les invitations sont limité à 20 personnes pour ne pas surcharger notre petit serveur :). + Une fois que la personne s'est inscrite votre nombre d'invitations sera mis à jour

@@ -20,8 +19,15 @@

Votre lien d'inscription en cours:

- {{ url_invitation }} - + {{ url_invitation }} + + + +

ou faîtes scanner ce qrcode :)

+ + + + {% else %}

Pas d'invitation en attente

{% endif %} diff --git a/tools/utils.py b/tools/utils.py index 2816952..9c6cab3 100644 --- a/tools/utils.py +++ b/tools/utils.py @@ -43,11 +43,24 @@ def valid_username(username): valid=True # Caractères non autorisés dans la RFC #822 invalid_char = { '(', ')', '<', '>', ',', ';', ':', '"', '[', ']', '|', 'ç', '%', '&', ' ' } - + for character in invalid_char: if character in username: valid=False + conn = sqlite3.connect(DATABASE) # Connexion à la base de donnée + cursor = conn.cursor() # Création de l'objet "curseur" + + cursor.execute("""SELECT name FROM users WHERE name=?""", (username,)) + tmp = cursor.fetchone() + conn.close() + + if tmp: + valid = True + else: + valid = False + + return valid def set_mail_domain(): @@ -109,7 +122,7 @@ def valid_token_register(token, token_type): cursor.execute("""SELECT name FROM users where token=?""", (token,)) tmp = cursor.fetchone() conn.close() - print (tmp) + if tmp: valid = True else: @@ -121,7 +134,6 @@ def valid_token_register(token, token_type): def get_user_by_token(token, token_type): - if len(token) != 30 and len(token) != 64: user = "Invalid Token" diff --git a/views/inscription.py b/views/inscription.py index f7ce23e..d921fa9 100644 --- a/views/inscription.py +++ b/views/inscription.py @@ -35,13 +35,12 @@ def signin(token) : mail_domain = set_mail_domain() - url_inscription = BASE_URL +'/inscription/'+token + url_inscription = BASE_URL +'/'+'inscription/'+token resp = None if valid_token_register(token, "Invitation"): if 'username' in session : resp = redirect(url_for('profil.profile', _external=True)) else : - # Réponse si la requete est de type GET ou si la requete POST echoue resp = render_template('inscription.html', signin_enable=app.config['SIGNIN_ENABLE'], @@ -52,6 +51,16 @@ def signin(token) : if request.method == 'POST': + # Une fois que tout c'est bien passé pour l'inscription on détruit le jeton. + conn = sqlite3.connect(DATABASE) # Connexion à la base de donnée + cursor = conn.cursor() # Création de l'objet "curseur" + + cursor.execute("""SELECT name, invitations FROM users where Token=?""", (token,)) + tmp = cursor.fetchone() + user_invite = tmp[0] + invitations_count=tmp[1] + conn.close() + #On test si aucun champs du formulaire n'est vide. if len(request.form['user']) == 0 or \ len(request.form['passwd']) == 0 or \ @@ -60,7 +69,7 @@ def signin(token) : flash(u'Il faut remplir le formulaire en entier, les champs ne peuvent pas etre vide ', 'error') return render_template('inscription.html', signin_enable=app.config['SIGNIN_ENABLE'], - token=token, hostname=hostname, + token=token, hostname=mail_domain, url_inscription=url_inscription, MAIL_SERVER=MAIL_SERVER, XMPP_SERVER=XMPP_SERVER) @@ -73,16 +82,11 @@ def signin(token) : not_error = True - conn = sqlite3.connect(DATABASE) # Connexion à la base de donnée - cursor = conn.cursor() # Création de l'objet "curseur" - - cursor.execute("""SELECT name FROM users WHERE name=?""", (user,)) - testuser = cursor.fetchone() - conn.close() - - print("user :" +user) - print ("passwd: "+ passwd) - if testuser and valid_username(user): + if invitations_count < 1 : + flash(u'Votre lien d\'inscription est invalide', 'error') + not_error=False + + if not_error and valid_username(user): flash(u'Le Nom d\'utilisateur déjà utilisé ou contient des caractères invalides, merci d\'en choisir un autre', 'error') flash(u'Les caractères espaces et \' ( ) < > , ; : " [ ] | ç % & ne sont pas autorisés', 'error') not_error = False @@ -131,17 +135,16 @@ def signin(token) : with open(log_file, 'x') as file: file.write(log) except FileExistsError: - print('The file '+log_file +' already exists') + print('The file '+log_file +' already exists') - # Une fois que tout c'est bien passé pour l'inscription on détruit le jeton. - cursor.execute("""SELECT name, invitations FROM users where Token=?""", (token,)) - tmp = cursor.fetchone() - username = tmp[0] - invitations_count=tmp[1] - 1 - if username == "pywallter": - cursor.execute("""DELETE from users where name = ?""", (username,)) + + if user_invite == "pywallter": + cursor.execute("""DELETE from users where name = ?""", (user_invite,)) + elif invitations_count > 0: + invitations_count= invitations_count - 1 + cursor.execute("""UPDATE users set invitations=? where name=?""", (invitations_count, user_invite,)) else: - cursor.execute("""UPDATE users set invitations=?, Token='' where name=?""", (invitations_count, username,)) + cursor.execute("""UPDATE users set invitations=?, Token='' where name=?""", (invitations_count, user_invite,)) conn.commit() flash(u'Inscription réalisée avec succés !', 'success') @@ -149,7 +152,7 @@ def signin(token) : else: return render_template('inscription.html', signin_enable=app.config['SIGNIN_ENABLE'], - token=token, hostname=hostname, + token=token, hostname=mail_domain, url_inscription=url_inscription, MAIL_SERVER=MAIL_SERVER, XMPP_SERVER=XMPP_SERVER) else: diff --git a/views/loginlogout.py b/views/loginlogout.py index d81c133..d41eb74 100644 --- a/views/loginlogout.py +++ b/views/loginlogout.py @@ -50,7 +50,7 @@ def index(): else : if token: hostname = gethostname() - url_inscription = BASE_URL+'inscription/'+token + url_inscription = BASE_URL+'/inscription/'+token return render_template('inscription.html', signin_enable=app.config['SIGNIN_ENABLE'], token=token, hostname=hostname, url_inscription=url_inscription, diff --git a/views/profil.py b/views/profil.py index efe90ba..8ff6be4 100644 --- a/views/profil.py +++ b/views/profil.py @@ -349,39 +349,51 @@ def deltoken_passwd_lost(token) : @profil.route('/invitation/', methods=['GET']) @login_required def invitation(): - UTILISATEUR='%s' % escape(session['username']) + user='%s' % escape(session['username']) conn = sqlite3.connect(DATABASE) # Connexion à la base de donnée cursor = conn.cursor() # Création de l'objet "curseur" - cursor.execute("""SELECT Token, invitations FROM users WHERE name=?""", (UTILISATEUR,)) + cursor.execute("""SELECT Token, invitations FROM users WHERE name=?""", (user,)) tmp = cursor.fetchone() token = tmp[0] - if token: - url_invitation = BASE_URL + 'inscription/' + token + nb_invitations = tmp[1] + if token and nb_invitations > 0: + url_invitation = BASE_URL + '/inscription/' + token + img = qrcode.make(url_invitation) + img.save(os.path.join(DOSSIER_PERSO, user, "invitation.png")) else: url_invitation = "" - invitations_count = tmp[1] conn.close() return render_template('invitation.html', section='Profil', - nb_invitation=invitations_count, + nb_invitation=nb_invitations, token=token, url_invitation=url_invitation) +@profil.route('/invitation.png', methods=['GET']) +@login_required +def invitation_qrcode(): + user='%s' % escape(session['username']) + return send_file( + os.path.join(DOSSIER_PERSO, user, "invitation.png")) + @profil.route('/gen_token/', methods=['GET']) @login_required def generate_token(): user='%s' % escape(session['username']) conn = sqlite3.connect(DATABASE) # Connexion à la base de donnée cursor = conn.cursor() # Création de l'objet "curseur" + cursor.execute("""SELECT invitations FROM users WHERE name=?""", (user,)) + tmp = cursor.fetchone() + token = tmp[0] token = gen_token("Invitation") cursor.execute("UPDATE users SET Token=? WHERE name=?", (token, user)) conn.commit() conn.close() - return redirect(BASE_URL+'invitation/') + return redirect(BASE_URL+'/invitation/') @profil.route( '/delete_me/', methods=['GET','POST'])