Skip to content

feat: Add change password and forgot my password #299

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 58 commits into from
Sep 26, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
58 commits
Select commit Hold shift + click to select a range
2cf26ed
feat: Add registration page
orronai Sep 9, 2021
3913a5e
feat: Add registration page
orronai Sep 10, 2021
d206c6a
Fixed sourcey-ai issues
orronai Sep 10, 2021
6ad4d4d
fixed resend email confirmation
orronai Sep 10, 2021
5acbda2
Merge branch 'master' of https://github.com/PythonFreeCourse/lms into…
orronai Sep 11, 2021
6b137af
Added translations
orronai Sep 11, 2021
3798a2d
Removed unused module
orronai Sep 11, 2021
1377e9a
Changed versions of requirements
orronai Sep 11, 2021
93da860
Changed versions of requirements
orronai Sep 11, 2021
ec52300
Changed versions of requirements
orronai Sep 11, 2021
4e47d57
Changed versions of requirements
orronai Sep 11, 2021
8d08863
Changed versions of requirements
orronai Sep 11, 2021
366b53f
Changed versions of requirements
orronai Sep 11, 2021
1443bad
Removed versions change
orronai Sep 11, 2021
1d00a27
Fixed tests
orronai Sep 11, 2021
036bdf5
Fixed a test
orronai Sep 11, 2021
b426102
Fixed test and updated client fixture
orronai Sep 11, 2021
c2ffa37
Added tests for coverage
orronai Sep 11, 2021
a9c22c9
Merge branch 'master' into add-signup-page
orronai Sep 11, 2021
b8dff02
- Changed role name from not_confirmed into unverified
orronai Sep 11, 2021
2da74c3
Fixed conflict
orronai Sep 11, 2021
fda1558
Added a test for signature expired
orronai Sep 11, 2021
6ad81a2
Removed unnecessary condition
orronai Sep 11, 2021
eb717f1
Added role attribute
orronai Sep 11, 2021
7e87dad
- Fixed babel translations
orronai Sep 12, 2021
19ecb65
Fixed a test to check bad signature token
orronai Sep 12, 2021
71fbb2f
Fixed a test
orronai Sep 12, 2021
d4bd32a
Moved out the HASHED_PASSWORD in order to be global variable, and add…
orronai Sep 12, 2021
436fc9f
Added a configuration of registration open, and a test
orronai Sep 12, 2021
1c45f57
feat: Add change password page
orronai Sep 14, 2021
ce3d5f8
feat: Add change password
orronai Sep 14, 2021
647378f
Added a comma
orronai Sep 14, 2021
e6dcbd5
Added a comma
orronai Sep 14, 2021
505d187
- Moved the send mails methods into utils/mail.py
orronai Sep 15, 2021
e65511c
Added a test for invalid_tries change password
orronai Sep 15, 2021
f2e5b0f
Added a test for invalid_tries change password
orronai Sep 15, 2021
c4621fd
Added a test for invalid_tries change password
orronai Sep 15, 2021
9e1bd57
- Added forgot my password template and css style
orronai Sep 15, 2021
1d27a18
Fixed some changes requested
orronai Sep 15, 2021
14d8f2b
Fixed translations
orronai Sep 15, 2021
0670c7e
Fixed some issues
orronai Sep 18, 2021
786527b
Changed session token to be uuid
orronai Sep 18, 2021
fa76fdf
Added a test and changed get_or_none to get
orronai Sep 18, 2021
ee88ddd
fix: check test send mail
orronai Sep 19, 2021
3a005f4
Added skipif for sending mail test and split a test function
orronai Sep 19, 2021
e3e633d
Changed skipif condition and split a test
orronai Sep 19, 2021
85c91c7
fix: test mails
orronai Sep 19, 2021
97827c1
Removed unused import
orronai Sep 19, 2021
e1651c7
Changed fixture to be session instead of class scope
orronai Sep 19, 2021
418437d
changed some code style and changed uuidfield
orronai Sep 20, 2021
fa56e55
Add migration
orronai Sep 21, 2021
e7e8043
feat: add migration
orronai Sep 21, 2021
33da242
fix: bool expression
orronai Sep 21, 2021
d6c94b2
Merge branch 'master' of https://github.com/PythonFreeCourse/lms into…
orronai Sep 22, 2021
1ca6102
Changed html name files
orronai Sep 22, 2021
2ffbeed
Removed unused imports and moved out to conftest some client.post's
orronai Sep 25, 2021
7153c46
Removed TestResponse objects
orronai Sep 25, 2021
40b65a1
Merge branch 'master' into add-change-password
yammesicka Sep 26, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 20 additions & 4 deletions lms/lmsdb/bootstrap.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
from typing import Any, Callable, Optional, Tuple, Type
from uuid import uuid4

from peewee import (
Database, Entity, Expression, Field, Model, OP,
Expand Down Expand Up @@ -88,9 +89,7 @@ def get_details(table: Model, column: Field) -> Tuple[bool, str, str]:
column_name = column.column_name

cols = {col.name for col in db_config.database.get_columns(table_name)}
if column_name in cols:
return True, table_name, column_name
return False, table_name, column_name
return column_name in cols, table_name, column_name


def _add_not_null_column(
Expand Down Expand Up @@ -227,22 +226,39 @@ def _add_api_keys_to_users_table(table: Model, _column: Field) -> None:
user.save()


def _add_uuid_to_users_table(table: Model, _column: Field) -> None:
log.info('Adding UUIDs for all users, might take some extra time...')
with db_config.database.transaction():
for user in table:
user.uuid = uuid4()
user.save()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can't we save at the end of the transaction? I think it would take significantly less time



def _api_keys_migration() -> bool:
User = models.User
_add_not_null_column(User, User.api_key, _add_api_keys_to_users_table)
return True


def _uuid_migration() -> bool:
User = models.User
_add_not_null_column(User, User.uuid, _add_uuid_to_users_table)
return True


def main():
with models.database.connection_context():
if models.database.table_exists(models.User.__name__.lower()):
_api_keys_migration()
_uuid_migration()

models.database.create_tables(models.ALL_MODELS, safe=True)

if models.Role.select().count() == 0:
models.create_basic_roles()
if models.User.select().count() == 0:
models.create_demo_users()

_api_keys_migration()
text_fixer.fix_texts()
import_tests.load_tests_from_path('/app_dir/notebooks-tests')

Expand Down
10 changes: 8 additions & 2 deletions lms/lmsdb/models.py
Original file line number Diff line number Diff line change
@@ -1,19 +1,20 @@
from collections import Counter
import enum
import html
import secrets
import string
from collections import Counter
from datetime import datetime
from typing import (
Any, Dict, Iterable, List, Optional, TYPE_CHECKING, Tuple,
Type, Union, cast,
)
from uuid import uuid4

from flask_babel import gettext as _ # type: ignore
from flask_login import UserMixin, current_user # type: ignore
from peewee import ( # type: ignore
BooleanField, Case, CharField, Check, DateTimeField, ForeignKeyField,
IntegerField, JOIN, ManyToManyField, TextField, fn,
IntegerField, JOIN, ManyToManyField, TextField, UUIDField, fn,
)
from playhouse.signals import Model, post_save, pre_save # type: ignore
from werkzeug.security import (
Expand Down Expand Up @@ -138,6 +139,10 @@ class User(UserMixin, BaseModel):
password = CharField()
role = ForeignKeyField(Role, backref='users')
api_key = CharField()
uuid = UUIDField(default=uuid4, unique=True)

def get_id(self):
return str(self.uuid)

def is_password_valid(self, password):
return check_password_hash(self.password, password)
Expand Down Expand Up @@ -201,6 +206,7 @@ def on_save_handler(model_class, instance, created):
is_password_changed = not instance.password.startswith('pbkdf2:sha256')
if created or is_password_changed:
instance.password = generate_password_hash(instance.password)
instance.uuid = uuid4()

is_api_key_changed = not instance.api_key.startswith('pbkdf2:sha256')
if created or is_api_key_changed:
Expand Down
3 changes: 3 additions & 0 deletions lms/lmsweb/config.py.example
Original file line number Diff line number Diff line change
Expand Up @@ -63,3 +63,6 @@ LOCALE = 'en'
# Limiter settings
LIMITS_PER_MINUTE = 5
LIMITS_PER_HOUR = 50

# Change password settings
MAX_INVALID_PASSWORD_TRIES = 5
33 changes: 33 additions & 0 deletions lms/lmsweb/forms/change_password.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
from flask import session
from flask_babel import gettext as _ # type: ignore
from flask_wtf import FlaskForm
from wtforms import PasswordField
from wtforms.validators import EqualTo, InputRequired, Length, ValidationError

from lms.lmsweb.config import MAX_INVALID_PASSWORD_TRIES


class ChangePasswordForm(FlaskForm):
current_password = PasswordField(
'Password', validators=[InputRequired(), Length(min=8)], id='password',
)
password = PasswordField(
'Password', validators=[InputRequired(), Length(min=8)], id='password',
)
confirm = PasswordField(
'Password Confirmation', validators=[
InputRequired(),
EqualTo('password', message=_('הסיסמאות שהוקלדו אינן זהות')),
],
)

def __init__(self, user, *args, **kwargs):
super(ChangePasswordForm, self).__init__(*args, **kwargs)
self.user = user

def validate_current_password(self, field):
if session['_invalid_password_tries'] >= MAX_INVALID_PASSWORD_TRIES:
raise ValidationError(_('הזנת סיסמה שגויה מספר רב מדי של פעמים'))
if not self.user.is_password_valid(field.data):
session['_invalid_password_tries'] += 1
raise ValidationError(_('הסיסמה הנוכחית שהוזנה שגויה'))
27 changes: 27 additions & 0 deletions lms/lmsweb/forms/reset_password.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
from lms.lmsweb.tools.validators import EmailNotExists
from flask_babel import gettext as _ # type: ignore
from flask_wtf import FlaskForm
from wtforms import StringField
from wtforms.fields.simple import PasswordField
from wtforms.validators import Email, EqualTo, InputRequired, Length


class ResetPassForm(FlaskForm):
email = StringField(
'Email', validators=[
InputRequired(), Email(message=_('אימייל לא תקין')),
EmailNotExists,
],
)


class RecoverPassForm(FlaskForm):
password = PasswordField(
'Password', validators=[InputRequired(), Length(min=8)], id='password',
)
confirm = PasswordField(
'Password Confirmation', validators=[
InputRequired(),
EqualTo('password', message=_('הסיסמאות שהוקלדו אינן זהות')),
],
)
8 changes: 8 additions & 0 deletions lms/lmsweb/tools/validators.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,3 +19,11 @@ def UniqueEmailRequired(
email_exists = User.get_or_none(User.mail_address == field.data)
if email_exists:
raise ValidationError(_('האימייל כבר נמצא בשימוש'))


def EmailNotExists(
_form: 'ResetPassForm', field: StringField, # type: ignore # NOQA: F821
) -> None:
email_exists = User.get_or_none(User.mail_address == field.data)
if not email_exists:
raise ValidationError(_('האימייל לא רשום במערכת'))
Loading