I am working on a small side-project since a couple of weeks, I am using Flask but trying to use as few libraries as possible and no ORMs (for learning purposes.
I am currently working on the User service on my application and currently stuck in the registration email confirmation part regarding my design.
Since I am not using any ORM, I wrote those classes:
UserRepository
: interact with the user table in the database (add, get, delete user and save)UserService
: actions on a User (registration, deactivate user, update stats)User
: representation of a User entity, no methods, methods are in the UserService (most of them take a User as a parameter expect the one to create a new User)
Current issue:
When a new user register, I send a registration email with a URL link to activate the account. I am using URLSafeTimedSerializer
to do that and dump the user.email
to generate the account confirmation URL.
The email is sent and when the user click on the link, I am able to decrypt the user.email
using URLSafeTimedSerializer.loads()
. But with my current design, I am not quite confident how I am going to retrieve the user.email
. Maybe the UserService
class should take the UserRepository
as an argument?
user/views.py
user = Blueprint('user', __name__, template_folder='templates')
# ----------
# STUCK HERE
# ----------
@user.route('/activate/<activation_token>', methods=["GET"])
def activate(activation_token):
private_key = current_app.config['SECRET_KEY']
s = URLSafeTimedSerializer(private_key)
user_email = s.loads(activation_token)
# now I need to check if that user is already confirmed, if not I have to change current User confirmed value from from False to True
# I should probably create a new UserService instance and create a method get_user_by_email(email) ?
def generate_registration_token(email):
private_key = current_app.config['SECRET_KEY']
s = URLSafeTimedSerializer(private_key)
u = s.dumps(email)
return u
def send_registration_email(email):
from prepsmarter.blueprints.user.tasks import deliver_contact_email
token = generate_registration_token(email)
host = current_app.config['HOST']
activation_url = f"{host}/activate/{token}"
try:
deliver_contact_email(email, activation_url)
return "ok"
except Exception as e:
return str(e)
@user.route('/register')
def login():
return render_template('register.html')
@user.route('/new-user',methods = ['POST'])
def register_user():
form_email = request.form.get('email')
form_password = request.form.get('psw')
form_password_repeat = request.form.get('psw-repeat')
registration_form = RegistrationForm(form_email, form_password, form_password_repeat).validate_registration()
if registration_form:
new_user = UserService().register_user(form_email, form_password)
user_repository = UserRepository(conn, 'users')
user_repository.add_user(new_user)
user_repository.save()
send_registration_email(new_user.email)
return "new user created" #will probably change return statements later on
return "new uer not created" #will probably change return statements later on
user/models.py (User class)
class User():
def __init__(self, email, password, registration_date, active, sign_in_count, current_sign_in_on, last_sign_in_on):
self.email = email
self.password = password
self.registration_date = registration_date
self.active = active
self.confirmed = False
user/services.py (UserRepository)
class UserRepository():
def __init__(self, conn, table):
self.conn = conn
self.table = table
#select exists(select 1 from users where email='pamousset75@gmail.com')
def add_user(self, user):
sql = "INSERT INTO users (email, password, is_active, sign_in_count, current_sign_in_on, last_sign_in_on) VALUES (%s, %s, %s, %s, %s, %s)"
cursor = self.conn.cursor()
# the is_active column in the DB is a tinyint(1). True = 1 and False = 0
if user.active == True:
is_active = 1
is_active = 0
cursor.execute(sql, ( user.email, user.password, is_active, user.sign_in_count, user.current_sign_in_on, user.last_sign_in_on))
resp = cursor.fetchall()
return resp
def delete_user(self):
return ""
def get_user(self):
return ""
def save(self):
self.conn.commit()
user/services.py (UserService)
class UserService():
def register_user(self,
email,
password):
sign_in_count = 1
today_date = datetime.today().strftime('%Y-%m-%d')
active = True
new_user = User(email, password, today_date, active,
sign_in_count, today_date, today_date)
return new_user
def desactivate_user(self, User):
if User.active == False:
print(f"User {User.email} is already inactive")
User.active = False
def reactive_user(self, User):
if User.active == True:
print(f"User {User.email} is already active")
User.active = True
def is_active(self, User):
return User.is_active
generate_registration_token
is still off \$\endgroup\$generate_registration_token
's indentation. Unfortunately we aren't allowed to edit the indentation, like I did forUserService
. \$\endgroup\$