Sigmanificient /
bday-reminder
| 1 | import re |
||
| 2 | import secrets |
||
| 3 | from datetime import datetime |
||
| 4 | |||
| 5 | from flask import Flask, render_template, redirect, url_for, request, session |
||
| 6 | from flask_sqlalchemy import SQLAlchemy |
||
| 7 | |||
| 8 | from src.security import sha512 |
||
| 9 | |||
| 10 | app = Flask(__name__) |
||
| 11 | app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///bday.db' |
||
| 12 | app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False |
||
| 13 | db = SQLAlchemy(app) |
||
| 14 | |||
| 15 | app.config.from_object(__name__) |
||
| 16 | app.secret_key = secrets.token_urlsafe(32) |
||
| 17 | |||
| 18 | USERNAME_PATTERN = r'^([\w\d-]){4,32}$' |
||
| 19 | PASSWORD_PATTERN = ( |
||
| 20 | r'^.*(?=.{8,})(?=.*\d)(?=.*[a-z])(?=.*[A-Z])(?=.*[-_ @#$%^&+=]).*$' |
||
| 21 | ) |
||
| 22 | |||
| 23 | |||
| 24 | # DB Model |
||
| 25 | class User(db.Model): |
||
| 26 | id = db.Column(db.Integer, primary_key=True, autoincrement=True) |
||
| 27 | pseudo = db.Column(db.String(32)) |
||
| 28 | password = db.Column(db.String(128)) |
||
| 29 | birthday = db.Column(db.String(10), default=None) |
||
| 30 | |||
| 31 | |||
| 32 | class Birthday(db.Model): |
||
| 33 | id = db.Column(db.Integer, primary_key=True, autoincrement=True) |
||
| 34 | user_id = db.Column(db.Integer) |
||
| 35 | person_name = db.Column(db.String(32)) |
||
| 36 | person_birthday = db.Column(db.String(10)) |
||
| 37 | |||
| 38 | |||
| 39 | db.drop_all() |
||
| 40 | db.create_all() |
||
| 41 | |||
| 42 | dummy_user = User( |
||
| 43 | pseudo="dummy", |
||
| 44 | password=( |
||
| 45 | "ee26b0dd4af7e749aa1a8ee3c10ae9923f618980772e473f8819a5d4940e0db27ac185" |
||
| 46 | "f8a0e1d5f84f88bc887fd67b143732c304cc5fa9ad8e6f57f50028a8ff" |
||
| 47 | ), |
||
| 48 | birthday="2001-12-11" |
||
| 49 | ) |
||
| 50 | db.session.add(dummy_user) |
||
| 51 | db.session.commit() |
||
| 52 | |||
| 53 | |||
| 54 | @app.route('/', methods=('GET', 'POST')) |
||
| 55 | def index_page(): |
||
| 56 | return render_template('index.jinja2') |
||
| 57 | |||
| 58 | |||
| 59 | @app.route('/auth/login', methods=('GET', 'POST')) |
||
| 60 | def login_page(): |
||
| 61 | if session.get('user'): |
||
|
0 ignored issues
–
show
Comprehensibility
Best Practice
introduced
by
Loading history...
|
|||
| 62 | return redirect(url_for('dashboard_page')) |
||
| 63 | if request.method == 'POST': |
||
| 64 | username = request.form['username'] |
||
| 65 | password = request.form['password'] |
||
| 66 | |||
| 67 | if username and password: |
||
| 68 | login = User.query.filter_by( |
||
| 69 | pseudo=username, |
||
| 70 | password=sha512(password) |
||
| 71 | ).first() |
||
| 72 | |||
| 73 | if login is not None: |
||
| 74 | session['user'] = { |
||
| 75 | 'name': username, |
||
| 76 | 'id': login.id |
||
| 77 | } |
||
| 78 | |||
| 79 | return redirect(url_for('dashboard_page')) |
||
| 80 | |||
| 81 | return render_template('auth/login.jinja2') |
||
| 82 | |||
| 83 | |||
| 84 | @app.route('/auth/register', methods=('GET', 'POST')) |
||
| 85 | def register_page(): |
||
| 86 | if session.get('user'): |
||
|
0 ignored issues
–
show
Comprehensibility
Best Practice
introduced
by
|
|||
| 87 | return redirect(url_for('dashboard_page')) |
||
| 88 | if request.method == 'POST': |
||
| 89 | username = request.form['username'] |
||
| 90 | password = request.form['password'] |
||
| 91 | confirm_password = request.form['confirm_password'] |
||
| 92 | birthday = request.form['date'] |
||
| 93 | |||
| 94 | if ( |
||
| 95 | re.match(USERNAME_PATTERN, username) |
||
| 96 | and re.match(PASSWORD_PATTERN, password) |
||
| 97 | and confirm_password |
||
| 98 | and confirm_password == password |
||
| 99 | and birthday |
||
| 100 | ): |
||
| 101 | new_user = User( |
||
| 102 | pseudo=username, |
||
| 103 | password=sha512(password), |
||
| 104 | birthday=birthday |
||
| 105 | ) |
||
| 106 | |||
| 107 | db.session.add(new_user) |
||
| 108 | db.session.commit() |
||
| 109 | |||
| 110 | session['user'] = {'name': username} |
||
| 111 | return redirect(url_for('dashboard_page')) |
||
| 112 | |||
| 113 | return render_template( |
||
| 114 | 'auth/register.jinja2', |
||
| 115 | USERNAME_PATTERN=USERNAME_PATTERN, |
||
| 116 | PASSWORD_PATTERN=PASSWORD_PATTERN |
||
| 117 | ) |
||
| 118 | |||
| 119 | |||
| 120 | @app.route('/dashboard', methods=('GET', 'POST')) |
||
| 121 | def dashboard_page(): |
||
| 122 | user = session.get('user') |
||
| 123 | |||
| 124 | if not user: |
||
| 125 | return redirect(url_for('login_page')) |
||
| 126 | |||
| 127 | if not user.get('name'): |
||
| 128 | return redirect(url_for('login_page')) |
||
| 129 | |||
| 130 | if request.method == 'POST': |
||
| 131 | username = request.form['username'] |
||
| 132 | date = request.form['date'] |
||
| 133 | |||
| 134 | if username and date: |
||
| 135 | new_birthday = Birthday( |
||
| 136 | person_name=username, |
||
| 137 | person_birthday=date, |
||
| 138 | user_id=user.get('id') |
||
| 139 | ) |
||
| 140 | |||
| 141 | db.session.add(new_birthday) |
||
| 142 | db.session.commit() |
||
| 143 | |||
| 144 | birthdays = Birthday.query.filter_by(user_id=user.get('id')).all() |
||
| 145 | now = datetime.now() |
||
| 146 | |||
| 147 | return render_template( |
||
| 148 | 'dashboard.jinja2', |
||
| 149 | birthdays=birthdays, |
||
| 150 | today_birthdays=[ |
||
| 151 | birthday |
||
| 152 | for birthday in birthdays |
||
| 153 | if birthday.person_birthday.endswith( |
||
| 154 | f'-{now.month:02}-{now.day:02}' |
||
| 155 | ) |
||
| 156 | ] |
||
| 157 | ) |
||
| 158 | |||
| 159 | |||
| 160 | @app.route('/auth/delete', methods=('GET', 'POST')) |
||
| 161 | def delete_account_page(): |
||
| 162 | user = session.get('user') |
||
| 163 | |||
| 164 | if not user: |
||
| 165 | return redirect(url_for('login_page')) |
||
| 166 | |||
| 167 | if not user.get('name'): |
||
| 168 | return redirect(url_for('login_page')) |
||
| 169 | if request.method == 'POST' and user.get('name') == request.form.get( |
||
| 170 | 'account_name' |
||
| 171 | ): |
||
| 172 | db.session.delete(User.query.filter_by(pseudo=user.get('name')).first()) |
||
| 173 | db.session.commit() |
||
| 174 | return redirect(url_for('logout')) |
||
| 175 | return render_template('auth/delete.jinja2') |
||
| 176 | |||
| 177 | |||
| 178 | @app.route('/legal') |
||
| 179 | def legal_page(): |
||
| 180 | return render_template('legal.jinja2') |
||
| 181 | |||
| 182 | |||
| 183 | @app.route('/auth/edit', methods=('GET', 'POST')) |
||
| 184 | def edit_page(): |
||
| 185 | user = session.get('user') |
||
|
0 ignored issues
–
show
Comprehensibility
Best Practice
introduced
by
|
|||
| 186 | |||
| 187 | if not user: |
||
| 188 | return redirect(url_for('login_page')) |
||
| 189 | |||
| 190 | if not user.get('name'): |
||
| 191 | return redirect(url_for('login_page')) |
||
| 192 | |||
| 193 | if request.method == 'POST': |
||
| 194 | if request.form.get('new_password'): |
||
| 195 | new_password = request.form['new_password'] |
||
| 196 | confirm_password = request.form['confirm_new_password'] |
||
| 197 | old_password = request.form['old_password'] |
||
| 198 | |||
| 199 | if ( |
||
| 200 | User.query.filter_by( |
||
| 201 | pseudo=user.get('name'), password=sha512(old_password) |
||
| 202 | ).first() |
||
| 203 | and new_password == confirm_password |
||
| 204 | ): |
||
| 205 | user = User.query.filter_by(pseudo=user.get('name')).first() |
||
| 206 | user.password = sha512(new_password) |
||
| 207 | db.session.commit() |
||
| 208 | |||
| 209 | elif request.form.get('new_username'): |
||
| 210 | new_username = request.form['new_username'] |
||
| 211 | confirm_username = request.form['confirm_new_username'] |
||
| 212 | |||
| 213 | if ( |
||
| 214 | new_username == confirm_username |
||
| 215 | and not User.query.filter_by(pseudo=new_username).first() |
||
| 216 | ): |
||
| 217 | user = User.query.filter_by(pseudo=user.get('name')).first() |
||
| 218 | user.pseudo = new_username |
||
| 219 | db.session.commit() |
||
| 220 | |||
| 221 | session['user'] = {'name': new_username} |
||
| 222 | |||
| 223 | return render_template('auth/edit.jinja2') |
||
| 224 | |||
| 225 | |||
| 226 | @app.route('/delete/<index>') |
||
| 227 | def delete_user(index): |
||
| 228 | user = session.get('user') |
||
| 229 | |||
| 230 | if not user: |
||
| 231 | return {} |
||
| 232 | |||
| 233 | if not user.get('name'): |
||
| 234 | return {} |
||
| 235 | |||
| 236 | if not index.isdigit(): |
||
| 237 | return {} |
||
| 238 | |||
| 239 | db.session.delete( |
||
| 240 | Birthday.query.filter_by( |
||
| 241 | user_id=user.get('id'), |
||
| 242 | id=int(index) |
||
| 243 | ).first() |
||
| 244 | ) |
||
| 245 | |||
| 246 | db.session.commit() |
||
| 247 | |||
| 248 | return {} |
||
| 249 | |||
| 250 | |||
| 251 | @app.route('/api/search/<user>') |
||
| 252 | def search_user(user): |
||
| 253 | found_user: User = User.query.filter_by(pseudo=user).first() |
||
| 254 | if not found_user: |
||
| 255 | return {} |
||
| 256 | |||
| 257 | return { |
||
| 258 | 'id': found_user.id, |
||
| 259 | 'name': found_user.pseudo, |
||
| 260 | 'birthday': found_user.birthday |
||
| 261 | } |
||
| 262 | |||
| 263 | |||
| 264 | @app.route('/logout/') |
||
| 265 | def logout(): |
||
| 266 | if session.get('user'): |
||
| 267 | session.pop('user') |
||
| 268 | |||
| 269 | return redirect(url_for('index_page')) |
||
| 270 | |||
| 271 | |||
| 272 | if __name__ == '__main__': |
||
| 273 | app.run(debug=True) |
||
| 274 |