diff --git a/services/static-webserver/client/source/class/osparc/auth/Data.js b/services/static-webserver/client/source/class/osparc/auth/Data.js index 4a55c04633d..306d3032558 100644 --- a/services/static-webserver/client/source/class/osparc/auth/Data.js +++ b/services/static-webserver/client/source/class/osparc/auth/Data.js @@ -82,12 +82,9 @@ qx.Class.define("osparc.auth.Data", { event: "changeUsername", }, - /** - * Email of logged in user, otherwise null - */ email: { init: null, - nullable: true, + nullable: true, // email of logged in user, otherwise null check: "String" }, diff --git a/services/static-webserver/client/source/class/osparc/auth/Manager.js b/services/static-webserver/client/source/class/osparc/auth/Manager.js index 0cdda5c49b6..ca497e5eabb 100644 --- a/services/static-webserver/client/source/class/osparc/auth/Manager.js +++ b/services/static-webserver/client/source/class/osparc/auth/Manager.js @@ -241,8 +241,8 @@ qx.Class.define("osparc.auth.Manager", { authData.set({ email: profile["login"], username: profile["userName"], - firstName: profile["first_name"] || profile["login"], - lastName: profile["last_name"] || "", + firstName: profile["first_name"], + lastName: profile["last_name"], expirationDate: "expirationDate" in profile ? new Date(profile["expirationDate"]) : null }); }, diff --git a/services/static-webserver/client/source/class/osparc/dashboard/CardBase.js b/services/static-webserver/client/source/class/osparc/dashboard/CardBase.js index 3bcd200c2ee..0d058644bce 100644 --- a/services/static-webserver/client/source/class/osparc/dashboard/CardBase.js +++ b/services/static-webserver/client/source/class/osparc/dashboard/CardBase.js @@ -674,7 +674,7 @@ qx.Class.define("osparc.dashboard.CardBase", { __showBlockedCardFromStatus: function(lockedStatus) { const status = lockedStatus["status"]; const owner = lockedStatus["owner"]; - let toolTip = osparc.utils.Utils.firstsUp(owner["first_name"] || this.tr("A user"), owner["last_name"] || ""); + let toolTip = osparc.utils.Utils.firstsUp(owner["first_name"] || this.tr("A user"), owner["last_name"] || ""); // it will be replaced by "userName" let image = null; switch (status) { case "CLOSING": diff --git a/services/static-webserver/client/source/class/osparc/data/model/Group.js b/services/static-webserver/client/source/class/osparc/data/model/Group.js index 3afec8ca34b..e345265ba68 100644 --- a/services/static-webserver/client/source/class/osparc/data/model/Group.js +++ b/services/static-webserver/client/source/class/osparc/data/model/Group.js @@ -104,6 +104,10 @@ qx.Class.define("osparc.data.model.Group", { return Object.values(this.getGroupMembers()).find(user => user.getUserId() === userId); }, + getGroupMemberByUsername: function(username) { + return Object.values(this.getGroupMembers()).find(user => user.getUsername() === username); + }, + getGroupMemberByLogin: function(userEmail) { return Object.values(this.getGroupMembers()).find(user => user.getEmail() === userEmail); }, diff --git a/services/static-webserver/client/source/class/osparc/data/model/User.js b/services/static-webserver/client/source/class/osparc/data/model/User.js index dc943c3202a..f0c8a5dabb1 100644 --- a/services/static-webserver/client/source/class/osparc/data/model/User.js +++ b/services/static-webserver/client/source/class/osparc/data/model/User.js @@ -28,22 +28,27 @@ qx.Class.define("osparc.data.model.User", { construct: function(userData) { this.base(arguments); - let label = userData["login"]; + let description = ""; if (userData["first_name"]) { - label = qx.lang.String.firstUp(userData["first_name"]); + description = userData["first_name"]; if (userData["last_name"]) { - label += " " + qx.lang.String.firstUp(userData["last_name"]); + description += " " + userData["last_name"]; } + description += " - "; + } + if (userData["login"]) { + description += userData["login"]; } const thumbnail = osparc.utils.Avatar.emailToThumbnail(userData["login"]); this.set({ - userId: userData["id"], - groupId: userData["gid"], - label: label, - username: userData["username"] || "", + userId: parseInt(userData["id"]), + groupId: parseInt(userData["gid"]), + username: userData["userName"], firstName: userData["first_name"], lastName: userData["last_name"], email: userData["login"], + label: userData["userName"], + description, thumbnail, }); }, @@ -70,24 +75,31 @@ qx.Class.define("osparc.data.model.User", { event: "changeLabel", }, - username: { + description: { check: "String", nullable: true, init: null, + event: "changeDescription", + }, + + username: { + check: "String", + nullable: false, + init: null, event: "changeUsername", }, firstName: { - init: "", - nullable: true, check: "String", + nullable: true, + init: "", event: "changeFirstName" }, lastName: { - init: "", - nullable: true, check: "String", + nullable: true, + init: "", event: "changeLastName" }, diff --git a/services/static-webserver/client/source/class/osparc/desktop/MainPageHandler.js b/services/static-webserver/client/source/class/osparc/desktop/MainPageHandler.js index 0872a1b627b..6e34be5d88c 100644 --- a/services/static-webserver/client/source/class/osparc/desktop/MainPageHandler.js +++ b/services/static-webserver/client/source/class/osparc/desktop/MainPageHandler.js @@ -94,7 +94,7 @@ qx.Class.define("osparc.desktop.MainPageHandler", { lockedBy = studyData["state"]["locked"]["owner"]; } if (locked && lockedBy["user_id"] !== osparc.auth.Data.getInstance().getUserId()) { - const msg = `${studyAlias} ${qx.locale.Manager.tr("is already open by")} ${ + const msg = `${studyAlias} ${qx.locale.Manager.tr("is already open by")} ${ // it will be replaced "userName" "first_name" in lockedBy && lockedBy["first_name"] != null ? lockedBy["first_name"] : qx.locale.Manager.tr("another user.") diff --git a/services/static-webserver/client/source/class/osparc/desktop/organizations/MembersList.js b/services/static-webserver/client/source/class/osparc/desktop/organizations/MembersList.js index 0a3df0faa3b..acd68c25680 100644 --- a/services/static-webserver/client/source/class/osparc/desktop/organizations/MembersList.js +++ b/services/static-webserver/client/source/class/osparc/desktop/organizations/MembersList.js @@ -70,8 +70,8 @@ qx.Class.define("osparc.desktop.organizations.MembersList", { if (sorted !== 0) { return sorted; } - if (("email" in a) && ("email" in b)) { - return a["email"].localeCompare(b["email"]); + if (("label" in a) && ("label" in b)) { + return a["label"].localeCompare(b["label"]); } return 0; } @@ -105,22 +105,17 @@ qx.Class.define("osparc.desktop.organizations.MembersList", { alignY: "middle" })); - const userEmail = new qx.ui.form.TextField().set({ + const newMemberUserName = new qx.ui.form.TextField().set({ required: true, - placeholder: this.tr(" New Member's email") + placeholder: this.tr(" New Member's username") }); - hBox.add(userEmail, { + hBox.add(newMemberUserName, { flex: 1 }); - const validator = new qx.ui.form.validation.Manager(); - validator.add(userEmail, qx.util.Validate.email()); - const addBtn = new qx.ui.form.Button(this.tr("Add")); addBtn.addListener("execute", function() { - if (validator.validate()) { - this.__addMember(userEmail.getValue()); - } + this.__addMember(newMemberUserName.getValue()); }, this); hBox.add(addBtn); @@ -154,9 +149,9 @@ qx.Class.define("osparc.desktop.organizations.MembersList", { ctrl.bindProperty("userId", "model", null, item, id); ctrl.bindProperty("userId", "key", null, item, id); ctrl.bindProperty("thumbnail", "thumbnail", null, item, id); - ctrl.bindProperty("name", "title", null, item, id); + ctrl.bindProperty("label", "title", null, item, id); + ctrl.bindProperty("description", "subtitleMD", null, item, id); ctrl.bindProperty("accessRights", "accessRights", null, item, id); - ctrl.bindProperty("email", "subtitleMD", null, item, id); ctrl.bindProperty("options", "options", null, item, id); ctrl.bindProperty("showOptions", "showOptions", null, item, id); }, @@ -217,7 +212,7 @@ qx.Class.define("osparc.desktop.organizations.MembersList", { const canIDelete = organization.getAccessRights()["delete"]; const introText = canIWrite ? - this.tr("You can add new members and promote or demote existing ones.") : + this.tr("You can add new members and promote or demote existing ones.
In order to add new members, type their username or email if this is public.") : this.tr("You can't add new members to this Organization. Please contact an Administrator or Manager."); this.__introLabel.setValue(introText); @@ -225,15 +220,17 @@ qx.Class.define("osparc.desktop.organizations.MembersList", { enabled: canIWrite }); + const myGroupId = osparc.auth.Data.getInstance().getGroupId(); const membersList = []; const groupMembers = organization.getGroupMembers(); Object.values(groupMembers).forEach(groupMember => { + const gid = parseInt(groupMember.getGroupId()); const member = {}; - member["userId"] = groupMember.getUserId(); - member["groupId"] = groupMember.getGroupId(); + member["userId"] = gid === myGroupId ? osparc.auth.Data.getInstance().getUserId() : groupMember.getUserId(); + member["groupId"] = gid; member["thumbnail"] = groupMember.getThumbnail(); - member["name"] = groupMember.getLabel(); - member["email"] = groupMember.getEmail(); + member["label"] = groupMember.getLabel(); + member["description"] = gid === myGroupId ? osparc.auth.Data.getInstance().getEmail() : groupMember.getDescription(); member["accessRights"] = groupMember.getAccessRights(); let options = []; if (canIDelete) { @@ -287,7 +284,6 @@ qx.Class.define("osparc.desktop.organizations.MembersList", { } // Let me go? const openStudy = osparc.store.Store.getInstance().getCurrentStudy(); - const myGroupId = osparc.store.Groups.getInstance().getMyGroupId(); if ( openStudy === null && canIWrite && @@ -303,16 +299,18 @@ qx.Class.define("osparc.desktop.organizations.MembersList", { membersList.forEach(member => membersModel.append(qx.data.marshal.Json.createModel(member))); }, - __addMember: async function(orgMemberEmail) { + __addMember: async function(newMemberIdentifier) { if (this.__currentOrg === null) { return; } const orgId = this.__currentOrg.getGroupId(); const groupsStore = osparc.store.Groups.getInstance(); - groupsStore.postMember(orgId, orgMemberEmail) + const isEmail = osparc.utils.Utils.isEmail(newMemberIdentifier); + const request = isEmail ? groupsStore.addMember(orgId, null, newMemberIdentifier) : groupsStore.addMember(orgId, newMemberIdentifier); + request .then(newMember => { - const text = orgMemberEmail + this.tr(" successfully added"); + const text = newMemberIdentifier + this.tr(" successfully added"); osparc.FlashMessenger.getInstance().logAs(text); this.__reloadOrgMembers(); diff --git a/services/static-webserver/client/source/class/osparc/desktop/wallets/MembersList.js b/services/static-webserver/client/source/class/osparc/desktop/wallets/MembersList.js index 4f5b1dd796a..dc27a0cfee3 100644 --- a/services/static-webserver/client/source/class/osparc/desktop/wallets/MembersList.js +++ b/services/static-webserver/client/source/class/osparc/desktop/wallets/MembersList.js @@ -70,8 +70,8 @@ qx.Class.define("osparc.desktop.wallets.MembersList", { if (sorted !== 0) { return sorted; } - if (("email" in a) && ("email" in b)) { - return a["email"].localeCompare(b["email"]); + if (("label" in a) && ("label" in b)) { + return a["label"].localeCompare(b["label"]); } return 0; } @@ -170,9 +170,9 @@ qx.Class.define("osparc.desktop.wallets.MembersList", { ctrl.bindProperty("userId", "key", null, item, id); ctrl.bindProperty("groupId", "gid", null, item, id); ctrl.bindProperty("thumbnail", "thumbnail", null, item, id); - ctrl.bindProperty("name", "title", null, item, id); + ctrl.bindProperty("label", "title", null, item, id); + ctrl.bindProperty("description", "subtitleMD", null, item, id); ctrl.bindProperty("accessRights", "accessRights", null, item, id); - ctrl.bindProperty("email", "subtitleMD", null, item, id); ctrl.bindProperty("options", "options", null, item, id); ctrl.bindProperty("showOptions", "showOptions", null, item, id); }, @@ -222,8 +222,8 @@ qx.Class.define("osparc.desktop.wallets.MembersList", { collaborator["userId"] = gid === myGroupId ? osparc.auth.Data.getInstance().getUserId() : collab.getUserId(); collaborator["groupId"] = collab.getGroupId(); collaborator["thumbnail"] = collab.getThumbnail(); - collaborator["name"] = collab.getLabel(); - collaborator["email"] = gid === myGroupId ? osparc.auth.Data.getInstance().getEmail() : collab.getEmail(); + collaborator["label"] = collab.getLabel(); + collaborator["description"] = gid === myGroupId ? osparc.auth.Data.getInstance().getEmail() : collab.getDescription(); collaborator["accessRights"] = { read: accessRights["read"], write: accessRights["write"], diff --git a/services/static-webserver/client/source/class/osparc/filter/CollaboratorToggleButton.js b/services/static-webserver/client/source/class/osparc/filter/CollaboratorToggleButton.js index 23c061cebd3..0008c5d7c48 100644 --- a/services/static-webserver/client/source/class/osparc/filter/CollaboratorToggleButton.js +++ b/services/static-webserver/client/source/class/osparc/filter/CollaboratorToggleButton.js @@ -24,13 +24,16 @@ qx.Class.define("osparc.filter.CollaboratorToggleButton", { }); let label = collaborator.getLabel(); - if ("getEmail" in collaborator) { - // user + if ("getEmail" in collaborator && collaborator.getEmail()) { label += ` (${collaborator.getEmail()})`; - this.setToolTipText(collaborator.getEmail()); } this.setLabel(label); + if (collaborator.getDescription()) { + const ttt = collaborator.getLabel() + "
" + collaborator.getDescription(); + this.setToolTipText(ttt); + } + let iconPath = null; switch (collaborator["collabType"]) { case 0: diff --git a/services/static-webserver/client/source/class/osparc/share/Collaborators.js b/services/static-webserver/client/source/class/osparc/share/Collaborators.js index 426d201d2ab..b012119b025 100644 --- a/services/static-webserver/client/source/class/osparc/share/Collaborators.js +++ b/services/static-webserver/client/source/class/osparc/share/Collaborators.js @@ -293,10 +293,8 @@ qx.Class.define("osparc.share.Collaborators", { ctrl.bindProperty("gid", "key", null, item, id); ctrl.bindProperty("collabType", "collabType", null, item, id); ctrl.bindProperty("thumbnail", "thumbnail", null, item, id); - ctrl.bindProperty("name", "title", null, item, id); // user - ctrl.bindProperty("label", "title", null, item, id); // organization - ctrl.bindProperty("email", "subtitleMD", null, item, id); // user - ctrl.bindProperty("description", "subtitle", null, item, id); // organization + ctrl.bindProperty("label", "title", null, item, id); + ctrl.bindProperty("description", "subtitleMD", null, item, id); ctrl.bindProperty("resourceType", "resourceType", null, item, id); // Resource type ctrl.bindProperty("accessRights", "accessRights", null, item, id); ctrl.bindProperty("showOptions", "showOptions", null, item, id); @@ -409,15 +407,11 @@ qx.Class.define("osparc.share.Collaborators", { const collaborator = { "gid": collab.getGroupId(), "thumbnail": collab.getThumbnail(), + "label": collab.getLabel(), + "description": collab.getDescription(), }; - if ("getUserId" in collab) { - // user - collaborator["name"] = collab.getLabel(); - collaborator["email"] = collab.getEmail(); - } else { - // org/group - collaborator["label"] = collab.getLabel(); - collaborator["description"] = collab.getDescription(); + if (!("getUserId" in collab)) { + // orgnanization if (everyoneGIds.includes(parseInt(gid))) { collaborator["thumbnail"] = "@FontAwesome5Solid/globe/32"; } else if (!collaborator["thumbnail"]) { diff --git a/services/static-webserver/client/source/class/osparc/store/Groups.js b/services/static-webserver/client/source/class/osparc/store/Groups.js index 862f97d06b1..21e2d4b2a29 100644 --- a/services/static-webserver/client/source/class/osparc/store/Groups.js +++ b/services/static-webserver/client/source/class/osparc/store/Groups.js @@ -231,6 +231,7 @@ qx.Class.define("osparc.store.Groups", { }, getOrganization: function(groupId) { + groupId = parseInt(groupId); if (groupId && groupId in this.getOrganizations()) { return this.getOrganizations()[groupId]; } @@ -261,6 +262,14 @@ qx.Class.define("osparc.store.Groups", { return null; }, + getGroupMemberByUsername: function(orgId, username) { + const org = this.getGroup(orgId); + if (org) { + return org.getGroupMemberByUsername(username); + } + return null; + }, + getGroupMemberByLogin: function(orgId, userEmail) { const org = this.getGroup(orgId); if (org) { @@ -330,16 +339,19 @@ qx.Class.define("osparc.store.Groups", { // CRUD GROUP // CRUD GROUP MEMBERS - postMember: function(orgId, newMemberEmail) { + addMember: function(orgId, username, email = null) { const gid = parseInt(orgId); const params = { url: { "gid": gid }, - data: { - "email": newMemberEmail - } + data: {}, }; + if (email) { + params.data["email"] = email; + } else { + params.data["userName"] = username; + } return osparc.data.Resources.fetch("organizationMembers", "post", params) .then(() => { // the backend doesn't return the user back, @@ -347,7 +359,7 @@ qx.Class.define("osparc.store.Groups", { return this.__fetchGroupMembers(gid); }) .then(() => { - const groupMember = this.getGroupMemberByLogin(gid, newMemberEmail); + const groupMember = email ? this.getGroupMemberByLogin(gid, email) : this.getGroupMemberByUsername(gid, username); if (groupMember) { return groupMember; } diff --git a/services/static-webserver/client/source/class/osparc/store/Store.js b/services/static-webserver/client/source/class/osparc/store/Store.js index e560a643980..6b986a0a34d 100644 --- a/services/static-webserver/client/source/class/osparc/store/Store.js +++ b/services/static-webserver/client/source/class/osparc/store/Store.js @@ -55,6 +55,14 @@ qx.Class.define("osparc.store.Store", { check: "Object", init: {} }, + announcements: { + check: "Array", + init: [] + }, + maintenance: { + check: "Object", + init: {} + }, currentStudy: { check: "osparc.data.model.Study", init: null, @@ -111,10 +119,6 @@ qx.Class.define("osparc.store.Store", { init: [], event: "changeIterations" }, - maintenance: { - check: "Object", - init: {} - }, templates: { check: "Array", init: [] diff --git a/services/static-webserver/client/source/class/osparc/utils/Utils.js b/services/static-webserver/client/source/class/osparc/utils/Utils.js index 075db07763e..233198affb8 100644 --- a/services/static-webserver/client/source/class/osparc/utils/Utils.js +++ b/services/static-webserver/client/source/class/osparc/utils/Utils.js @@ -107,6 +107,11 @@ qx.Class.define("osparc.utils.Utils", { return newName; }, + isEmail: function(value) { + const reg = /^([A-Za-z0-9_\-.+])+@([A-Za-z0-9_\-.])+\.([A-Za-z]{2,})$/; + return reg.test(value); + }, + replaceTokens: function(str, key, value) { // `str` might be a a localized string, get the string first str = str.toString ? str.toString() : str;