Skip to content
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

Add Fullname Support to User Profiles #2608

Open
wants to merge 62 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 60 commits
Commits
Show all changes
62 commits
Select commit Hold shift + click to select a range
3c8b9dc
Add immutable fullname and nickname fields to user profiles
annapurna-gupta Nov 24, 2024
0d0c7e4
Updated fullname and nickname fields
annapurna-gupta Dec 4, 2024
7c311c0
updated fullname
annapurna-gupta Dec 13, 2024
f6180b8
Add full name
annapurna-gupta Dec 13, 2024
aa67a24
updated migration
annapurna-gupta Dec 29, 2024
ed996b1
Revert changes made by mistake
annapurna-gupta Dec 29, 2024
4c6c0e2
Fix test failures
annapurna-gupta Jan 20, 2025
223bd46
resolve conflit
annapurna-gupta Jan 20, 2025
0ff4613
Updated files
annapurna-gupta Jan 20, 2025
8170d8f
fix test
annapurna-gupta Jan 20, 2025
92e1150
adding fullname
annapurna-gupta Jan 22, 2025
61c03a5
fixex test
annapurna-gupta Jan 22, 2025
19f8f69
applied patch file
annapurna-gupta Jan 23, 2025
6e358c3
changes
annapurna-gupta Jan 23, 2025
8283e48
Add fullname to seed data
annapurna-gupta Jan 24, 2025
8b775f9
revert change
annapurna-gupta Jan 25, 2025
a599d5d
fixes lint
annapurna-gupta Jan 25, 2025
a0653f7
updated db
annapurna-gupta Jan 26, 2025
c1b0865
test for fullname
annapurna-gupta Feb 1, 2025
ed812bf
fixex test
annapurna-gupta Feb 1, 2025
d2ec6eb
fixes test
annapurna-gupta Feb 1, 2025
b41036f
update
annapurna-gupta Feb 1, 2025
ec6a07c
updated fix
annapurna-gupta Feb 1, 2025
fb3fa1d
added fullname
annapurna-gupta Feb 1, 2025
978b97b
fix test
annapurna-gupta Feb 1, 2025
799fcad
added test for fullname
annapurna-gupta Feb 6, 2025
d3ac9b5
updated db
annapurna-gupta Feb 6, 2025
b93191b
fixex migration
annapurna-gupta Feb 6, 2025
463ec06
changed migration
annapurna-gupta Feb 7, 2025
dfc0941
changes migration
annapurna-gupta Feb 8, 2025
627ffd2
changes
annapurna-gupta Feb 8, 2025
e7d6d3b
changes models.py
annapurna-gupta Feb 8, 2025
8dc3114
fixex error
annapurna-gupta Feb 8, 2025
80c0b23
updated code
annapurna-gupta Feb 8, 2025
77953ef
fixes test
annapurna-gupta Feb 8, 2025
9407417
modified test function
annapurna-gupta Feb 9, 2025
d2f1f87
fixes flask
annapurna-gupta Feb 9, 2025
dec8102
revert change in register_user and in it tests
annapurna-gupta Feb 9, 2025
a1f5eb0
changes register_user function
annapurna-gupta Feb 9, 2025
77ebba6
tried assertion fix
annapurna-gupta Feb 9, 2025
e831670
updated test_mscolab.py
annapurna-gupta Feb 11, 2025
be8e006
rearranged register_user
annapurna-gupta Feb 12, 2025
aa1766d
updated test function
annapurna-gupta Feb 12, 2025
e5d7755
tried fxing test
annapurna-gupta Feb 13, 2025
76ca1f5
reste db and updated migration
annapurna-gupta Feb 13, 2025
4a33278
modified test for fullname
annapurna-gupta Feb 16, 2025
996cad3
updated test
annapurna-gupta Feb 16, 2025
3420d53
chnages function name and updated
annapurna-gupta Feb 16, 2025
04924ce
Fix fullname validation tests
annapurna-gupta Feb 16, 2025
09de535
Skip digit check
annapurna-gupta Feb 16, 2025
5278ca4
debugging
annapurna-gupta Feb 17, 2025
af0f4ad
updated migration
annapurna-gupta Feb 18, 2025
3bb035a
migration chnaged
annapurna-gupta Feb 18, 2025
7b4acaf
updated process_fullname
annapurna-gupta Feb 18, 2025
7a69294
updated migration
annapurna-gupta Feb 18, 2025
df643b5
updated db
annapurna-gupta Feb 19, 2025
1052604
updated process_fullname
annapurna-gupta Feb 20, 2025
3786696
error fix
annapurna-gupta Feb 20, 2025
e55db70
updated process_fullname and it's test function
annapurna-gupta Feb 20, 2025
49bfa2b
error fix
annapurna-gupta Feb 20, 2025
8734299
suggestion fix
annapurna-gupta Feb 21, 2025
13ec878
fixes lint
annapurna-gupta Feb 21, 2025
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
1 change: 0 additions & 1 deletion mslib/index.py
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,6 @@ def create_app(name="", imprint=None, gdpr=None):

@APP.route('/xstatic/<name>/<path:filename>')
def files(name, filename):

base_path = _xstatic(name)
if base_path is None:
abort(404)
Expand Down
1 change: 1 addition & 0 deletions mslib/mscolab/file_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -246,6 +246,7 @@ def modify_user(self, user, attribute=None, value=None, action=None):
db.session.commit()
else:
return False
# This is the default, when we not have a special action
user_query = User.query.filter_by(id=user.id).first()
if user_query is None:
return False
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,15 +21,22 @@ def upgrade():
# ### commands auto generated by Alembic - please adjust! ###
with op.batch_alter_table('users', schema=None) as batch_op:
batch_op.add_column(sa.Column('profile_image_path', sa.String(length=255), nullable=True))
batch_op.add_column(sa.Column('fullname',
sa.String(length=255), nullable=True))

op.execute("UPDATE changes SET version_name = NULL WHERE version_name = 'None';")
op.execute("UPDATE changes SET comment = NULL WHERE comment = 'None';")

# ### end Alembic commands ###


def downgrade():
# ### commands auto generated by Alembic - please adjust! ###
with op.batch_alter_table('users', schema=None) as batch_op:
batch_op.drop_column('profile_image_path')
batch_op.drop_column('fullname')

op.execute("UPDATE changes SET version_name = 'None' WHERE version_name IS NULL;")
op.execute("UPDATE changes SET comment = 'None' WHERE comment IS NULL;")
# ### end Alembic commands ###

# ### end Alembic commands ###
4 changes: 3 additions & 1 deletion mslib/mscolab/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -64,11 +64,13 @@ class User(db.Model):
confirmed_on = db.Column(AwareDateTime, nullable=True)
permissions = db.relationship('Permission', cascade='all,delete,delete-orphan', backref='user')
authentication_backend = db.Column(db.String(255), nullable=False, default='local')
fullname = db.Column(db.String(255), nullable=True)

def __init__(self, emailid, username, password, profile_image_path=None, confirmed=False,
def __init__(self, emailid, username, password, fullname="", profile_image_path=None, confirmed=False,
confirmed_on=None, authentication_backend='local'):
self.username = str(username)
self.emailid = str(emailid)
self.fullname = str(fullname)
self.hash_password(password)
self.profile_image_path = profile_image_path
self.registered_on = datetime.datetime.now(tz=datetime.timezone.utc)
Expand Down
3 changes: 2 additions & 1 deletion mslib/mscolab/mscolab.py
Original file line number Diff line number Diff line change
Expand Up @@ -429,9 +429,10 @@ def main():
for line in args.users_by_file.readlines():
info = line.split()
username = info[0]
fullname = info[1]
emailid = info[-1][1:-1]
password = secrets.token_hex(8)
add_user(emailid, username, password)
add_user(emailid, username, password, fullname)
elif args.default_operation:
confirmation = confirm_action(
"Are you sure you want to add users to the default TEMPLATE operation? (y/[n]):")
Expand Down
38 changes: 24 additions & 14 deletions mslib/mscolab/seed.py
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ def delete_user(email):
return False


def add_user(email, username, password):
def add_user(email, username, password, fullname):
"""
on db level we add a user
"""
Expand All @@ -118,11 +118,11 @@ def add_user(email, username, password):
user_email_exists = User.query.filter_by(emailid=str(email)).first()
user_name_exists = User.query.filter_by(username=str(username)).first()
if not user_email_exists and not user_name_exists:
db_user = User(email, username, password)
db_user = User(email, username, password, fullname)
db.session.add(db_user)
db.session.commit()
db.session.close()
logging.info("Userdata: %s %s %s", email, username, password)
logging.info("Userdata: %s %s %s %s", email, username, password, fullname)
return True
else:
logging.info("%s already in db", user_name_exists)
Expand Down Expand Up @@ -225,55 +225,65 @@ def seed_data():
'username': 'a',
'id': 8,
'password': 'a',
'emailid': 'a@notexisting.org'
'emailid': 'a@notexisting.org',
'fullname': 'A User'
}, {
'username': 'b',
'id': 9,
'password': 'b',
'emailid': 'b@notexisting.org'
'emailid': 'b@notexisting.org',
'fullname': 'B User'
}, {
'username': 'c',
'id': 10,
'password': 'c',
'emailid': 'c@notexisting.org'
'emailid': 'c@notexisting.org',
'fullname': 'C User'
}, {
'username': 'd',
'id': 11,
'password': 'd',
'emailid': 'd@notexisting.org'
'emailid': 'd@notexisting.org',
'fullname': 'D User'
}, {
'username': 'test1',
'id': 12,
'password': 'test1',
'emailid': 'test1@notexisting.org'
'emailid': 'test1@notexisting.org',
'fullname': 'Test User one'
}, {
'username': 'test2',
'id': 13,
'password': 'test2',
'emailid': 'test2@notexisting.org'
'emailid': 'test2@notexisting.org',
'fullname': 'Test User two'
}, {
'username': 'test3',
'id': 14,
'password': 'test3',
'emailid': 'test3@notexisting.org'
'emailid': 'test3@notexisting.org',
'fullname': 'Test User three'
}, {
'username': 'test4',
'id': 15,
'password': 'test4',
'emailid': 'test4@notexisting.org'
'emailid': 'test4@notexisting.org',
'fullname': 'Test User four'
}, {
'username': 'mscolab_user',
'id': 16,
'password': 'password',
'emailid': 'mscolab_user@notexisting.org'
'emailid': 'mscolab_user@notexisting.org',
'fullname': 'mscolab user'
}, {
'username': 'merge_waypoints_user',
'id': 17,
'password': 'password',
'emailid': 'merge_waypoints_user@notexisting.org'
'emailid': 'merge_waypoints_user@notexisting.org',
'fullname': 'merge waypoints user'
}]
for user in users:
db_user = User(user['emailid'], user['username'], user['password'])
db_user = User(user['emailid'], user['username'], user['password'], user['fullname'])
db_user.id = user['id']
db.session.add(db_user)

Expand Down
28 changes: 22 additions & 6 deletions mslib/mscolab/server.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@
from mslib.index import create_app
from mslib.mscolab.forms import ResetRequestForm, ResetPasswordForm
from mslib.mscolab import migrations
from slugify import slugify


def _handle_db_upgrade():
Expand Down Expand Up @@ -248,7 +249,16 @@ def check_login(emailid, password):
return False


def register_user(email, password, username):
def process_fullname(fullname):
fullname = " ".join(fullname.split())
Copy link
Member

@ReimarBauer ReimarBauer Feb 21, 2025

Choose a reason for hiding this comment

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

the reason for this is to have only 1 blank used in a name?
maybe add a comment if so.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

yes, the reason of this is to handle multiple spaces between fullname, i will add commant.

result_with_regex = slugify(fullname, regex_pattern=r"[^a-zA-Z\s\-]")
if fullname.lower() == result_with_regex:
return {"success": True, "processed_name": fullname}
else:
return {"success": False, "message": "Invalid chars detected"}


def register_user(email, password, username, fullname):
if len(str(email.strip())) == 0 or len(str(username.strip())) == 0:
return {"success": False, "message": "Your username or email cannot be empty"}
is_valid_username = True if username.find("@") == -1 else False
Expand All @@ -263,7 +273,12 @@ def register_user(email, password, username):
user_exists = User.query.filter_by(username=str(username)).first()
if user_exists:
return {"success": False, "message": "This username is already registered"}
user = User(email, username, password)
checking_fullname = process_fullname(fullname)
if not checking_fullname["success"]:
return {"success": False, "message": checking_fullname["message"]}

processed_fullname = checking_fullname["processed_name"]
user = User(email, username, password, processed_fullname)
result = fm.modify_user(user, action="create")
return {"success": result}

Expand Down Expand Up @@ -370,14 +385,14 @@ def get_auth_token():
token = user.generate_auth_token()
return json.dumps({
'token': token,
'user': {'username': user.username, 'id': user.id}})
'user': {'username': user.username, 'id': user.id}, 'fullname': user.fullname})
else:
return "False"
else:
token = user.generate_auth_token()
return json.dumps({
'token': token,
'user': {'username': user.username, 'id': user.id}})
'user': {'username': user.username, 'id': user.id, 'fullname': user.fullname}})
else:
logging.debug("Unauthorized user: %s", emailid)
return "False"
Expand Down Expand Up @@ -405,7 +420,8 @@ def user_register_handler():
email = request.form['email']
password = request.form['password']
username = request.form['username']
result = register_user(email, password, username)
fullname = request.form['fullname']
result = register_user(email, password, username, fullname)
status_code = 200
try:
if result["success"]:
Expand Down Expand Up @@ -443,7 +459,7 @@ def confirm_email(token):
@APP.route('/user', methods=["GET"])
@verify_user
def get_user():
return json.dumps({'user': {'id': g.user.id, 'username': g.user.username}})
return json.dumps({'user': {'id': g.user.id, 'username': g.user.username, 'fullname': g.user.fullname}})


@APP.route('/upload_profile_image', methods=["POST"])
Expand Down
11 changes: 8 additions & 3 deletions mslib/msui/mscolab.py
Original file line number Diff line number Diff line change
Expand Up @@ -445,14 +445,16 @@ def new_user_handler(self):
password = self.newPasswordLe.text()
re_password = self.newConfirmPasswordLe.text()
username = self.newUsernameLe.text()
fullname = self.newFullnameLe.text()
if password != re_password:
self.set_status("Error", 'Your passwords don\'t match.')
return

data = {
"email": emailid,
"password": password,
"username": username
"username": username,
"fullname": fullname
}
session = requests.Session()
session.auth = self.auth
Expand Down Expand Up @@ -870,6 +872,7 @@ def on_context_menu(point):
self.profile_dialog.setupUi(self.prof_diag)
self.profile_dialog.buttonBox.accepted.connect(lambda: self.prof_diag.close())
self.profile_dialog.usernameLabel_2.setText(self.user['username'])
self.profile_dialog.fullNameLabel_2.setText(self.user['fullname'])
self.profile_dialog.mscolabURLLabel_2.setText(self.mscolab_server_url)
self.profile_dialog.emailLabel_2.setText(self.email)
self.profile_dialog.deleteAccountBtn.clicked.connect(self.delete_account)
Expand Down Expand Up @@ -931,9 +934,11 @@ def upload_image(self, _=None):
def delete_account(self, _=None):
# ToDo rename to delete_own_account
reply = QMessageBox.question(
self.ui, self.tr('Continue?'),
self.ui,
self.tr('Continue?'),
self.tr("You're about to delete your account. You cannot undo this operation!"),
QMessageBox.Yes | QMessageBox.No, QMessageBox.No)
QMessageBox.Yes | QMessageBox.No,
QMessageBox.No)
if reply == QMessageBox.No:
return
try:
Expand Down
4 changes: 2 additions & 2 deletions mslib/msui/msui_mainwindow.py
Original file line number Diff line number Diff line change
Expand Up @@ -628,7 +628,7 @@ def add_import_plugins(self, picker_default):
except Exception as ex:
logging.error("Error on import: %s: %s", type(ex), ex)
QtWidgets.QMessageBox.critical(
self.tr(f"ERROR: Configuration\n\n{plugins,}\n\nthrows {type(ex)} error:\n{ex}"))
self.tr(f"ERROR: Configuration\n\n{plugins, }\n\nthrows {type(ex)} error:\n{ex}"))
continue
try:
self.add_plugin_submenu(name, extension, imported_function, picker_type, plugin_type="Import")
Expand Down Expand Up @@ -656,7 +656,7 @@ def add_export_plugins(self, picker_default):
logging.error("Error on import: %s: %s", type(ex), ex)
QtWidgets.QMessageBox.critical(
self, self.tr("file io plugin error export plugins"),
self.tr(f"ERROR: Configuration\n\n{plugins,}\n\nthrows {type(ex)} error:\n{ex}"))
self.tr(f"ERROR: Configuration\n\n{plugins, }\n\nthrows {type(ex)} error:\n{ex}"))
continue
try:
self.add_plugin_submenu(name, extension, imported_function, picker_type, plugin_type="Export")
Expand Down
Loading
Loading