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 and Nickname Feature to User Profiles #2575

Open
wants to merge 2 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
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
Binary file added .coverage
Copy link
Member

Choose a reason for hiding this comment

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

we don't need this in the repository

Copy link
Author

@annapurna-gupta annapurna-gupta Nov 28, 2024

Choose a reason for hiding this comment

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

okk i have removed it..

Binary file not shown.
Binary file added dist/mss-9.2.0-py3.11.egg
Copy link
Member

Choose a reason for hiding this comment

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

we don't need this in the repository

Copy link
Author

@annapurna-gupta annapurna-gupta Nov 28, 2024

Choose a reason for hiding this comment

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

okk i have removed it..

Binary file not shown.
Binary file added instance/mscolab.db
Copy link
Member

Choose a reason for hiding this comment

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

we don't need this in the repository

Copy link
Author

@annapurna-gupta annapurna-gupta Nov 28, 2024

Choose a reason for hiding this comment

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

okk i have removed it..

Binary file not shown.
5 changes: 0 additions & 5 deletions 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 All @@ -96,10 +95,6 @@ def mss_theme(filename):

APP.jinja_env.globals.update(get_topmenu=get_topmenu)

@APP.route("/index")
def index():
return render_template("/index.html")

@APP.route("/mss/about")
@APP.route("/mss")
def about():
Expand Down
8 changes: 7 additions & 1 deletion mslib/mscolab/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -65,8 +65,11 @@ class User(db.Model):
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)
Copy link
Member

@ReimarBauer ReimarBauer Nov 25, 2024

Choose a reason for hiding this comment

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

because you change the dbase model, you need to do additional steps, see
https://github.com/Open-MSS/MSS/blob/develop/docs/development.rst#changing-the-database-model

when that is not done, a annapurna-gupta/MSS$ python mslib/mscolab/mscolab.py db --seed crashes with
sqlite3.OperationalError: table users has no column named fullname

also it may be useful to change the seed.py to add some of this data.

Copy link
Author

Choose a reason for hiding this comment

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

i have generated the migration script but while applying it to database i am facing import error.

Copy link
Member

Choose a reason for hiding this comment

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

please show the failure

Copy link
Author

Choose a reason for hiding this comment

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

Screenshot 2024-11-30 230514

Copy link
Member

Choose a reason for hiding this comment

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

Please show your PYTHONPATH

Copy link
Member

@ReimarBauer ReimarBauer Dec 2, 2024

Choose a reason for hiding this comment

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

likly PYTHONPATH should show D:\LOCAL_CODE COPY\MSS

I think on windows you can use setx PYTHONPATH D:\LOCAL_CODE COPY\MSS

currently python can't find mslib. ...

Copy link
Author

Choose a reason for hiding this comment

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

Screenshot 2024-12-02 172456

nickname = db.Column(db.String(255), nullable=True)

def __init__(self, emailid, username, password, profile_image_path=None, confirmed=False,
confirmed_on=None, authentication_backend='local'):
confirmed_on=None, authentication_backend='local', fullname="", nickname=""):
self.username = str(username)
self.emailid = str(emailid)
self.hash_password(password)
Expand All @@ -76,6 +79,9 @@ def __init__(self, emailid, username, password, profile_image_path=None, confirm
self.confirmed_on = confirmed_on
self.authentication_backend = str(authentication_backend)

self.fullname = str(fullname) if fullname else None
self.nickname = str(nickname) if nickname else None

def __repr__(self):
return f'<User {self.username}>'

Expand Down
45 changes: 40 additions & 5 deletions mslib/mscolab/server.py
Original file line number Diff line number Diff line change
Expand Up @@ -248,9 +248,10 @@ def check_login(emailid, password):
return False


def register_user(email, password, username):
if len(str(email.strip())) == 0 or len(str(username.strip())) == 0:
return {"success": False, "message": "Your username or email cannot be empty"}
def register_user(email, password, username, fullname, nickname):
if len(str(email.strip())) == 0 or len(str(username.strip())) == 0 or len(str(fullname.strip())) == 0 or len(
str(nickname.strip())) == 0:
return {"success": False, "message": "Your username, email, fullname, or nickname cannot be empty"}
is_valid_username = True if username.find("@") == -1 else False
is_valid_email = validate_email(email)
if not is_valid_email:
Expand All @@ -263,11 +264,10 @@ 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)
user = User(email, username, password, fullname=fullname, nickname=nickname)
result = fm.modify_user(user, action="create")
return {"success": result}


def verify_user(func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
Expand Down Expand Up @@ -616,6 +616,40 @@ def set_version_name():
return jsonify({"success": True, "message": "Successfully set version name"})


@APP.route("/edit_user_info", methods=["POST"])
@verify_user
def edit_user_info():
user = g.user
fullname = request.form.get("fullname")
nickname = request.form.get("nickname")

try:
# Update the user's full name and nickname in the database
user_record = User.query.filter_by(id=int(user.id)).first()
if user_record is None:
return jsonify({"success": False, "error": "User not found."}), 404

# Update fields
user_record.fullname = fullname # Update full name
user_record.nickname = nickname # Update nickname

# Commit changes to the database
db.session.commit()
Copy link
Member

@ReimarBauer ReimarBauer Nov 25, 2024

Choose a reason for hiding this comment

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

all these db commands needs to be moved to the file_manager

likly you can use modify_user
https://github.com/Open-MSS/MSS/blob/develop/mslib/mscolab/file_manager.py#L222

Copy link
Author

Choose a reason for hiding this comment

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

So I need to move all the additional commands to file_manager, and I should revert this part to how it was before.

Copy link
Member

Choose a reason for hiding this comment

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

not mandatory. check if you can use file_manager.modify_user you can maybe reuse the existing method

Copy link
Author

Choose a reason for hiding this comment

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

okk


# Return the updated name and nickname if needed
return jsonify({
"success": True,
"fullname": user_record.fullname,
"nickname": user_record.nickname
}), 200

except Exception as e:
# Log the error message (use logging instead of print for production)
print(f"Error updating user info: {str(e)}") # Replace with proper logging if needed
Copy link
Member

Choose a reason for hiding this comment

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

when you need output, you have to use logging.debug, a print can create a traceback on a webserver

Copy link
Author

Choose a reason for hiding this comment

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

okk

db.session.rollback() # Rollback in case of error
return jsonify({"success": False, "error": "Failed to update user info."}), 500


@APP.route('/authorized_users', methods=['GET'])
@verify_user
def authorized_users():
Expand Down Expand Up @@ -1027,3 +1061,4 @@ def main():

if __name__ == '__main__':
main()

28 changes: 28 additions & 0 deletions mslib/msui/mscolab.py
Original file line number Diff line number Diff line change
Expand Up @@ -966,6 +966,34 @@ def delete_account(self, _=None):
if r.status_code == 200 and json.loads(r.text)["success"] is True:
self.logout()

def editfull_name(self):
if verify_user_token(self.mscolab_server_url, self.token):
Copy link
Member

Choose a reason for hiding this comment

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

there is a newer syntax for this by a decorator. Have a look on the other lines where that is used

Copy link
Author

Choose a reason for hiding this comment

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

okkkk

fullname, ok = QtWidgets.QInputDialog.getText(
self.ui,
self.ui.tr("Edit Full Name"),
self.ui.tr(
f"You're about to change the full name - '{self.active_operation_name}' "
f"Enter new full name: "
),
)
if ok:
data = {
"token": self.token,
"fullname": str(fullname)
}
url = url_join(self.mscolab_server_url, 'edit_full_name')
r = requests.post(url, data=data)
if r.text == "true":
self.error_dialog = QtWidgets.QErrorMessage()
self.error_dialog.showMessage("Fullname is updated successfully.")
self.profile_dialog.fullname_label2.setText(self.user["fullname"])
else:
show_popup(self, "Error", "Your Connection is expired. New Login required!")
self.logout()

def editnick_name(self):
pass

@verify_user_token
def add_operation_handler(self, _=None):
def check_and_enable_operation_accept():
Expand Down
71 changes: 53 additions & 18 deletions mslib/msui/qt5/ui_add_user_dialog.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,16 @@
# -*- coding: utf-8 -*-

# Form implementation generated from reading ui file 'mslib/msui/ui/ui_add_user.ui'
# Form implementation generated from reading ui file 'ui_add_user_dialog.ui'
#
# Created by: PyQt5 UI code generator 5.9.2
# Created by: PyQt5 UI code generator 5.15.9
#
# WARNING! All changes made in this file will be lost!
# WARNING: Any manual changes made to this file will be lost when pyuic5 is
# run again. Do not edit this file unless you know what you are doing.


from PyQt5 import QtCore, QtGui, QtWidgets


class Ui_addUserDialog(object):
def setupUi(self, addUserDialog):
addUserDialog.setObjectName("addUserDialog")
Expand All @@ -19,34 +22,52 @@ def setupUi(self, addUserDialog):
self.formLayout = QtWidgets.QFormLayout()
self.formLayout.setFieldGrowthPolicy(QtWidgets.QFormLayout.ExpandingFieldsGrow)
self.formLayout.setLabelAlignment(QtCore.Qt.AlignRight|QtCore.Qt.AlignTrailing|QtCore.Qt.AlignVCenter)
self.formLayout.setHorizontalSpacing(7)
self.formLayout.setVerticalSpacing(14)
self.formLayout.setObjectName("formLayout")
self.usernameLabel = QtWidgets.QLabel(addUserDialog)
self.usernameLabel.setObjectName("usernameLabel")
self.formLayout.setWidget(1, QtWidgets.QFormLayout.LabelRole, self.usernameLabel)
self.username = QtWidgets.QLineEdit(addUserDialog)
self.username.setObjectName("username")
self.formLayout.setWidget(1, QtWidgets.QFormLayout.FieldRole, self.username)
self.fullnamelabel = QtWidgets.QLabel(addUserDialog)
self.fullnamelabel.setObjectName("fullnamelabel")
self.formLayout.setWidget(2, QtWidgets.QFormLayout.LabelRole, self.fullnamelabel)
self.fullname = QtWidgets.QLineEdit(addUserDialog)
self.fullname.setText("")
self.fullname.setObjectName("fullname")
self.formLayout.setWidget(2, QtWidgets.QFormLayout.FieldRole, self.fullname)
self.nicknameLabel = QtWidgets.QLabel(addUserDialog)
self.nicknameLabel.setObjectName("nicknameLabel")
self.formLayout.setWidget(3, QtWidgets.QFormLayout.LabelRole, self.nicknameLabel)
self.nickname = QtWidgets.QLineEdit(addUserDialog)
self.nickname.setText("")
self.nickname.setObjectName("nickname")
self.formLayout.setWidget(3, QtWidgets.QFormLayout.FieldRole, self.nickname)
self.emailIDLabel = QtWidgets.QLabel(addUserDialog)
self.emailIDLabel.setObjectName("emailIDLabel")
self.formLayout.setWidget(4, QtWidgets.QFormLayout.LabelRole, self.emailIDLabel)
self.emailid = QtWidgets.QLineEdit(addUserDialog)
self.emailid.setObjectName("emailid")
self.formLayout.setWidget(2, QtWidgets.QFormLayout.FieldRole, self.emailid)
self.formLayout.setWidget(4, QtWidgets.QFormLayout.FieldRole, self.emailid)
self.passwordLabel = QtWidgets.QLabel(addUserDialog)
self.passwordLabel.setObjectName("passwordLabel")
self.formLayout.setWidget(3, QtWidgets.QFormLayout.LabelRole, self.passwordLabel)
self.formLayout.setWidget(5, QtWidgets.QFormLayout.LabelRole, self.passwordLabel)
self.password = QtWidgets.QLineEdit(addUserDialog)
self.password.setEchoMode(QtWidgets.QLineEdit.Password)
self.password.setObjectName("password")
self.formLayout.setWidget(3, QtWidgets.QFormLayout.FieldRole, self.password)
self.formLayout.setWidget(5, QtWidgets.QFormLayout.FieldRole, self.password)
self.confirmPasswordLabel = QtWidgets.QLabel(addUserDialog)
self.confirmPasswordLabel.setObjectName("confirmPasswordLabel")
self.formLayout.setWidget(4, QtWidgets.QFormLayout.LabelRole, self.confirmPasswordLabel)
self.formLayout.setWidget(6, QtWidgets.QFormLayout.LabelRole, self.confirmPasswordLabel)
self.rePassword = QtWidgets.QLineEdit(addUserDialog)
self.rePassword.setEchoMode(QtWidgets.QLineEdit.Password)
self.rePassword.setObjectName("rePassword")
self.formLayout.setWidget(4, QtWidgets.QFormLayout.FieldRole, self.rePassword)
self.emailIDLabel = QtWidgets.QLabel(addUserDialog)
self.emailIDLabel.setObjectName("emailIDLabel")
self.formLayout.setWidget(2, QtWidgets.QFormLayout.LabelRole, self.emailIDLabel)
self.usernameLabel = QtWidgets.QLabel(addUserDialog)
self.usernameLabel.setObjectName("usernameLabel")
self.formLayout.setWidget(1, QtWidgets.QFormLayout.LabelRole, self.usernameLabel)
self.formLayout.setWidget(6, QtWidgets.QFormLayout.FieldRole, self.rePassword)
self.verticalLayout_2 = QtWidgets.QVBoxLayout()
self.verticalLayout_2.setObjectName("verticalLayout_2")
self.formLayout.setLayout(7, QtWidgets.QFormLayout.FieldRole, self.verticalLayout_2)
self.verticalLayout.addLayout(self.formLayout)
self.buttonBox = QtWidgets.QDialogButtonBox(addUserDialog)
self.buttonBox.setOrientation(QtCore.Qt.Horizontal)
Expand All @@ -56,18 +77,32 @@ def setupUi(self, addUserDialog):
self.gridLayout.addLayout(self.verticalLayout, 0, 0, 1, 1)

self.retranslateUi(addUserDialog)
self.buttonBox.accepted.connect(addUserDialog.accept)
self.buttonBox.rejected.connect(addUserDialog.reject)
self.buttonBox.accepted.connect(addUserDialog.accept) # type: ignore
self.buttonBox.rejected.connect(addUserDialog.reject) # type: ignore
QtCore.QMetaObject.connectSlotsByName(addUserDialog)

def retranslateUi(self, addUserDialog):
_translate = QtCore.QCoreApplication.translate
addUserDialog.setWindowTitle(_translate("addUserDialog", "Add user"))
self.usernameLabel.setText(_translate("addUserDialog", "Username:"))
self.username.setPlaceholderText(_translate("addUserDialog", "John Doe"))
self.fullnamelabel.setText(_translate("addUserDialog", "Fullname:"))
self.fullname.setPlaceholderText(_translate("addUserDialog", "John Michael Doe"))
self.nicknameLabel.setText(_translate("addUserDialog", "Nickname:"))
self.nickname.setPlaceholderText(_translate("addUserDialog", "Jonny"))
self.emailIDLabel.setText(_translate("addUserDialog", "Email:"))
self.emailid.setPlaceholderText(_translate("addUserDialog", "[email protected]"))
self.passwordLabel.setText(_translate("addUserDialog", "Password:"))
self.password.setPlaceholderText(_translate("addUserDialog", "Your password"))
self.confirmPasswordLabel.setText(_translate("addUserDialog", "Confirm Password:"))
self.rePassword.setPlaceholderText(_translate("addUserDialog", "Confirm your password"))
self.emailIDLabel.setText(_translate("addUserDialog", "Email:"))
self.usernameLabel.setText(_translate("addUserDialog", "Username:"))

Copy link
Member

Choose a reason for hiding this comment

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

this section is not needed, likly this comes from an option of the pyuic5 command.

Copy link
Author

Choose a reason for hiding this comment

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

do you mean all the changes in ui_add_user_dialog.py is not needed??

Copy link
Member

Choose a reason for hiding this comment

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

Add only the fullname

Copy link
Author

Choose a reason for hiding this comment

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

ok


if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
addUserDialog = QtWidgets.QDialog()
ui = Ui_addUserDialog()
ui.setupUi(addUserDialog)
addUserDialog.show()
sys.exit(app.exec_())
Loading
Loading