Skip to content

feat: Add registration page #286

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 31 commits into from
Sep 14, 2021
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
31 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
d34d19d
Added flask limits and fixed some messages
orronai Sep 14, 2021
f44f1a2
Removed formats from strings
orronai Sep 14, 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
32 changes: 32 additions & 0 deletions lms/lmsweb/tools/registration.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,14 @@
import csv
from lms.lmsweb.tools.validators import (
UniqueEmailRequired, UniqueUsernameRequired,
)
import os
import typing

from flask_babel import gettext as _ # type: ignore
from flask_wtf import FlaskForm
from wtforms import PasswordField, StringField
from wtforms.validators import Email, EqualTo, InputRequired, Length

from lms.lmsdb import models
from lms.lmsweb import config
Expand All @@ -11,6 +17,32 @@
import requests


class RegisterForm(FlaskForm):
email = StringField(
'Email', validators=[
InputRequired(), Email(message=_('אימייל לא תקין')),
UniqueEmailRequired, Length(max=60),
],
)
username = StringField(
'Username', validators=[
InputRequired(), UniqueUsernameRequired, Length(min=4, max=20),
],
)
fullname = StringField(
'Full Name', validators=[InputRequired(), Length(min=3, max=60)],
)
password = PasswordField(
'Password', validators=[InputRequired(), Length(min=8)], id='password',
)
confirm = PasswordField(
'Password Confirmation', validators=[
InputRequired(),
EqualTo('password', message=_('הסיסמה שהוקלדה אינה זהה')),
],
)


class UserToCreate(typing.NamedTuple):
name: str
email: str
Expand Down
16 changes: 16 additions & 0 deletions lms/lmsweb/tools/validators.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
from flask_babel import gettext as _ # type: ignore
from wtforms.validators import ValidationError

from lms.lmsdb.models import User


def UniqueUsernameRequired(form, field):
username_exists = User.get_or_none(User.username == field.data)
if username_exists:
raise ValidationError(_('שם המשתמש כבר נמצא בשימוש'))


def UniqueEmailRequired(form, field):
email_exists = User.get_or_none(User.mail_address == field.data)
if email_exists:
raise ValidationError(_('האימייל כבר נמצא בשימוש'))
35 changes: 29 additions & 6 deletions lms/lmsweb/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
from werkzeug.utils import redirect

from lms.lmsdb.models import (
ALL_MODELS, Comment, Note, RoleOptions, SharedSolution,
ALL_MODELS, Comment, Note, Role, RoleOptions, SharedSolution,
Solution, SolutionFile, User, database,
)
from lms.lmsweb import babel, limiter, routes, webapp
Expand All @@ -27,6 +27,7 @@
from lms.lmsweb.redirections import (
PERMISSIVE_CORS, get_next_url, login_manager,
)
from lms.lmsweb.tools.registration import RegisterForm
from lms.models import (
comments, notes, notifications, share_link, solutions, upload,
)
Expand Down Expand Up @@ -83,27 +84,49 @@ def ratelimit_handler(e):
f'{LIMITS_PER_MINUTE}/minute;{LIMITS_PER_HOUR}/hour',
deduct_when=lambda response: response.status_code != 200,
)
def login(login_error: Optional[str] = None):
def login(login_message: Optional[str] = None):

if current_user.is_authenticated:
return get_next_url(request.args.get('next'))

username = request.form.get('username')
password = request.form.get('password')
next_page = request.form.get('next')
login_error = request.args.get('login_error')
login_message = request.args.get('login_message')
user = User.get_or_none(username=username)

if request.method == 'POST':
if user is not None and user.is_password_valid(password):
login_user(user)
return get_next_url(next_page)
elif user is None or not user.is_password_valid(password):
login_error = 'Invalid username or password'
error_details = {'next': next_page, 'login_error': login_error}
login_message = 'Invalid username or password'
error_details = {'next': next_page, 'login_message': login_message}
return redirect(url_for('login', **error_details))

return render_template('login.html', login_error=login_error)
return render_template('login.html', login_message=login_message)


@webapp.route('/signup', methods=['GET', 'POST'])
def signup():
form = RegisterForm()

if form.validate_on_submit():
User.get_or_create(**{
User.mail_address.name: form.email.data,
User.username.name: form.username.data,
}, defaults={
User.fullname.name: form.fullname.data,
User.role.name: Role.get_student_role(),
User.password.name: form.password.data,
User.api_key.name: User.random_password(),
})

return redirect(url_for(
'login', login_message='Registration Successfully',
))

return render_template('signup.html', form=form)


@webapp.route('/logout')
Expand Down
12 changes: 8 additions & 4 deletions lms/static/my.css
Original file line number Diff line number Diff line change
Expand Up @@ -46,25 +46,29 @@ a {
text-align: right;
}

#login-container {
#login-container,
#signup-container {
height: 100%;
align-items: center;
display: flex;
align-self: center;
}

#login {
#login,
#signup {
margin: auto;
max-width: 420px;
padding: 15px;
width: 100%;
}

#login-logo {
#login-logo,
#signup-logo {
margin-bottom: 1rem;
}

#login-messege-box {
#login-message-box,
#signup-errors {
background: #f1c8c8;
color: #860606;
}
Expand Down
13 changes: 13 additions & 0 deletions lms/templates/_formhelpers.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{% macro render_field(field, cls) %}
<div class="row mb-3">
<label for="{{ field.id }}" class="visually-hidden">{{ field.label }}</label>
{{ field(class=cls, **kwargs) | safe }}
<div id="signup-errors" class="text-center">
{% if field.errors %}
{% for error in field.errors %}
<span>{{ error }}</span>
{% endfor %}
{% endif %}
</div>
</div>
{% endmacro %}
8 changes: 5 additions & 3 deletions lms/templates/login.html
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,10 @@ <h1 id="main-title" class="h3 font-weight-normal">{{ _('התחברות') }}</h1>
{{ _('ברוכים הבאים למערכת התרגילים!') }}<br>
{{ _('הזינו את שם המשתמש והסיסמה שלכם:') }}
</p>
{% if login_error %}
<div id="login-messege-box" class="text-center">
{% if login_message %}
<div id="login-message-box" class="text-center">
<p>
{{ login_error }}
{{ login_message }}
</p>
</div>
{% endif %}
Expand All @@ -34,6 +34,8 @@ <h1 id="main-title" class="h3 font-weight-normal">{{ _('התחברות') }}</h1>
<input class="form-control form-control-lg" type="hidden" name="next" id="next" value="{{ request.args.get('next', '') }}">
<button class="btn btn-primary btn-lg btn-block">{{ _('התחבר') }}</button>
</form>
<hr class="mt-3 mb-3"/>
<a href="/signup" class="btn btn-success btn-sm" role="button">{{ _('הרשם') }}</a>
</div>
</div>
</div>
Expand Down
29 changes: 29 additions & 0 deletions lms/templates/signup.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
{% extends 'base.html' %}
{% from "_formhelpers.html" import render_field %}

{% block page_content %}
<div class="container">
<div id="signup-container">
<div id="signup" class="text-center">
<img id="signup-logo" src="{{ url_for('static', filename='avatar.jpg') }}" alt="{{ _('תמונת הפרופיל של קורס פייתון') }}" width="72" height="72">
<h1 id="main-title" class="h3 font-weight-normal">{{ _('הרשמה') }}</h1>
<p>
{{ _('ברוכים הבאים למערכת התרגילים!') }}<br>
{{ _('הזינו אימייל וסיסמה לצורך רישום למערכת:') }}
</p>
<form class="align-items-center" method="post" action="/signup">
{{ render_field(form.email, cls="form-control form-control-lg", placeholder="Email Address") }}
{{ render_field(form.username, cls="form-control form-control-lg", placeholder="User Name") }}
{{ render_field(form.fullname, cls="form-control form-control-lg", placeholder="Full Name") }}
{{ render_field(form.password, cls="form-control form-control-lg", placeholder="Password") }}
{{ render_field(form.confirm, cls="form-control form-control-lg", placeholder="Password Verification") }}
<input class="form-control form-control-lg" type="hidden" name="csrf_token" id="csrf_token" value="{{ csrf_token() }}" required>
<input class="form-control form-control-lg" type="hidden" name="next" id="next" value="{{ request.args.get('next', '') }}">
<button class="btn btn-primary btn-lg btn-block">{{ _('הירשם') }}</button>
</form>
<hr class="mt-3 mb-3"/>
<a href="/" class="btn btn-success btn-sm" role="button">{{ _('חזרה לדף ההתחברות') }}</a>
</div>
</div>
</div>
{% endblock %}
1 change: 1 addition & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ debugpy==1.0.0rc2
decorator==4.4.2
diff-cover==2.6.1
docker-pycreds==0.4.0
email-validator==1.1.3
entrypoints==0.3
eradicate==1.0
flake8-alfred==1.1.1
Expand Down