from ..extensions import db, mail from ..tools.encryption import decrypt, encrypt from ..tools.logs import write from flask import flash, jsonify, session from flask.helpers import url_for from flask_login import current_user, login_user, logout_user, UserMixin from flask_mail import Message from werkzeug.security import check_password_hash, generate_password_hash import secrets from uuid import uuid4 class User(UserMixin, db.Model): id = db.Column(db.String(36), primary_key=True) username = db.Column(db.String(128), nullable=False) password = db.Column(db.String(128), nullable=False) email = db.Column(db.String(128), nullable=False) reset_token = db.Column(db.String(20), nullable=True) verification_token = db.Column(db.String(20), nullable=True) tests = db.relationship('Test', backref='creator') datasets = db.relationship('Dataset', backref='creator') def __repr__(self): return f' was added with .' @property def generate_id(self): raise AttributeError('generate_id is not a readable attribute.') generate_id.setter def generate_id(self): self.id = uuid4().hex @property def set_username(self): raise AttributeError('set_username is not a readable attribute.') set_username.setter def set_username(self, username:str): self.username = encrypt(username) def get_username(self): return decrypt(self.username) @property def set_password(self): raise AttributeError('set_password is not a readable attribute.') set_password.setter def set_password(self, password:str): self.password = generate_password_hash(password, method="sha256") def verify_password(self, password:str): return check_password_hash(self.password, password) @property def set_email(self): raise AttributeError('set_email is not a readable attribute.') set_email.setter def set_email(self, email:str): self.email = encrypt(email) def get_email(self): return decrypt(self.email) def register(self, notify:bool=False, password:str=None): self.generate_id() users = User.query.all() for user in users: if user.get_username() == self.get_username(): return False, f'Username {self.get_username()} already in use.' if user.get_email() == self.get_email(): return False, f'Email address {self.get_email()} already in use.' self.set_password(password=password) db.session.add(self) db.session.commit() write('users.log', f'User \'{self.get_username()}\' was created with id \'{self.id}\'.') if notify: email = Message( subject='RefTest | Registration Confirmation', recipients=[self.email], body=f""" Hello {self.get_username()},\n\n You have been registered as an administrator on the SKA RefTest App!\n\n You can access your account using the username '{self.get_username()}'\n\n Your password is as follows:\n\n {password}\n\n You can log in to the admin console via the following URL, where you can administer the test or change your password:\n\n {url_for('admin._home', _external=True)}\n\n Have a nice day!\n\n SKA Refereeing """, html=f"""

Hello {self.get_username()},

You have been registered as an administrator on the SKA RefTest App!

You can access your account using the username '{self.get_username()}'

Your password is as follows:

{password}

You can log in to the admin console via the following URL, where you can administer the test or change your password:

{url_for('admin._home', _external=True)}

Have a nice day!

SKA Refereeing

""" ) mail.send(email) return True, f'User {self.get_username()} was created successfully.' def login(self, remember:bool=False): login_user(self, remember = remember) write('users.log', f'User \'{self.get_username()}\' has logged in.') flash(message=f'Welcome {self.get_username()}', category='success') def logout(self): session['remembered_username'] = self.get_username() logout_user() write('users.log', f'User \'{self.get_username()}\' has logged out.') flash(message='You have successfully logged out.', category='success') def reset_password(self): new_password = secrets.token_hex(12) self.set_password(new_password) self.reset_token = secrets.token_urlsafe(16) self.verification_token = secrets.token_urlsafe(16) db.session.commit() email = Message( subject='RefTest | Password Reset', recipients=[self.get_email()], body=f""" Hello {self.get_username()},\n\n This email was generated because we received a request to reset the password for your administrator account for the SKA RefTest app.\n\n If you did not make this request, please ignore this email.\n\n If you did make this request, then you have two options to recover your account.\n\n Your password has been reset to the following:\n\n {new_password}\n\n You may use this to log back in to your account, and subsequently change your password to something more suitable.\n\n Alternatively, you may visit the following private link using your unique token to override your password. Copy and paste the following link in a web browser. Please note that this token is only valid once:\n\n {url_for('admin._reset', token = self.reset_token, verification = self.verification_token, _external = True)}\n\n Hopefully, this should enable access to your account once again.\n\n Have a nice day!\n\n SKA Refereeing """, html=f"""

Hello {self.get_username()},

This email was generated because we received a request to reset the password for your administrator account for the SKA RefTest app.

If you did not make this request, please ignore this email.

If you did make this request, then you have two options to recover your account.

Your password has been reset to the following:

{new_password}

You may use this to log back in to your account, and subsequently change your password to something more suitable.

Alternatively, you may visit the following private link using your unique token to override your password. Copy and paste the following link in a web browser. Please note that this token is only valid once:

{url_for('admin._reset', token = self.reset_token, verification = self.verification_token, _external = True)}

Hopefully, this should enable access to your account once again.

Have a nice day!

SKA Refereeing

""" ) mail.send(email) print('Password', new_password) print('Reset Token', self.reset_token) print('Verification Token', self.verification_token) print('Reset Link', f'{url_for("admin._reset", token=self.reset_token, verification=self.verification_token, _external=True)}') return jsonify({'success': 'Your password reset link has been generated.'}), 200 def clear_reset_tokens(self): self.reset_token = self.verification_token = None db.session.commit() def delete(self, notify:bool=False): username = self.get_username() email_address = self.get_email() db.session.delete(self) db.session.commit() message = f'User \'{username}\' was deleted by \'{current_user.get_username()}\'.' write('users.log', message) if notify: email = Message( subject='RefTest | Account Deletion', recipients=[email_address], bcc=[current_user.get_email()], body=f""" Hello {username},\n\n Your administrator account for the SKA RefTest App, as well as all data associated with the account, have been deleted by {current_user.get_username()}.\n\n If you believe this was done in error, please contact them immediately.\n\n If you would like to register to administer the app, please ask an existing administrator to create a new account.\n\n Have a nice day!\n\n SKA Refereeing """, html=f"""

Hello {username},

Your administrator account for the SKA RefTest App, as well as all data associated with the account, have been deleted by {current_user.get_username()}.

If you believe this was done in error, please contact them immediately.

If you would like to register to administer the app, please ask an existing administrator to create a new account.

Have a nice day!

SKA Refereeing

""" ) mail.send(email) return True, message def update(self, password:str=None, email:str=None, notify:bool=False): if not password and not email: return False, 'There were no changes requested.' if password: self.set_password(password) old_email = self.get_email() if email: self.set_email(email) db.session.commit() write('system.log', f'Information for user {self.get_username()} has been updated by {current_user.get_username()}.') if notify: message = Message( subject='RefTest | Account Update', recipients=[email], bcc=[old_email,current_user.get_email()], body=f""" Hello {self.get_username()},\n\n Your administrator account for the SKA RefTest App has been updated by {current_user.get_username()}.\n\n Your new account details are as follows:\n\n Email: {email}\n Password: {password if password else ''}\n\n You can update your email address and password by logging in to the admin console using the following URL:\n\n {url_for('admin._home', _external=True)}\n\n Have a nice day!\n\n SKA Refereeing """, html=f"""

Hello {self.get_username()},

Your administrator account for the SKA RefTest App has been updated by {current_user.get_username()}.

Your new account details are as follows:

Email: {email}
Password: {password if password else '<same as old>'}

You can update your email address and password by logging in to the admin console using the following URL:

{url_for('admin._home', _external=True)}

Have a nice day!

SKA Refereeing

""" ) mail.send(message) return True, f'Account {self.get_username()} has been updated.'