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

♻️ [Frontend] New projects/groups endpoints #6070

Merged
Merged
Original file line number Diff line number Diff line change
Expand Up @@ -247,6 +247,21 @@ qx.Class.define("osparc.data.Resources", {
method: "GET",
url: statics.API + "/projects/{studyId}/nodes/-/services:access?for_gid={gid}"
},
postAccessRights: {
useCache: false,
method: "POST",
url: statics.API + "/projects/{studyId}/groups/{gId}"
},
deleteAccessRights: {
useCache: false,
method: "DELETE",
url: statics.API + "/projects/{studyId}/groups/{gId}"
},
putAccessRights: {
useCache: false,
method: "PUT",
url: statics.API + "/projects/{studyId}/groups/{gId}"
},
addTag: {
useCache: false,
method: "PUT",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,11 @@ qx.Class.define("osparc.data.model.Study", {
"dev"
],

OwnPatch: [
"accessRights",
"workbench"
],

createMyNewStudyObject: function() {
let myNewStudyObject = {};
const props = qx.util.PropertyUtil.getProperties(osparc.data.model.Study);
Expand Down Expand Up @@ -578,6 +583,12 @@ qx.Class.define("osparc.data.model.Study", {
},

patchStudy: function(studyChanges) {
const matches = this.self().OwnPatch.filter(el => Object.keys(studyChanges).indexOf(el) !== -1);
if (matches.length) {
console.error(matches, "has it's own PATCH path");
return null;
}

return new Promise((resolve, reject) => {
const params = {
url: {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -241,6 +241,10 @@ qx.Class.define("osparc.desktop.MainPage", {
if (templateBrowser) {
templateBrowser.taskToTemplateReceived(task, data["studyData"].name);
}
task.addListener("resultReceived", e => {
const templateData = e.getData();
osparc.info.StudyUtils.addCollaborators(templateData, data["accessRights"]);
});
})
.catch(errMsg => {
const msg = this.tr("Something went wrong Duplicating the study<br>") + errMsg;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -244,7 +244,9 @@ qx.Class.define("osparc.info.StudyLarge", {
},

__openAccessRights: function() {
const permissionsView = osparc.info.StudyUtils.openAccessRights(this.getStudy().serialize());
const studyData = this.getStudy().serialize();
studyData["resourceType"] = this.__isTemplate ? "template" : "study";
const permissionsView = osparc.info.StudyUtils.openAccessRights(studyData);
permissionsView.addListener("updateAccessRights", e => {
const updatedData = e.getData();
this.getStudy().setAccessRights(updatedData["accessRights"]);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -392,39 +392,113 @@ qx.Class.define("osparc.info.StudyUtils", {
return box;
},

patchNodeData: function(studyData, nodeId, fieldKey, value) {
patchStudyData: function(studyData, fieldKey, value) {
if (osparc.data.model.Study.OwnPatch.includes(fieldKey)) {
console.error(fieldKey, "has it's own PATCH path");
return null;
}

const patchData = {};
patchData[fieldKey] = value;
const params = {
url: {
"studyId": studyData["uuid"],
"nodeId": nodeId
"studyId": studyData["uuid"]
},
data: patchData
};
return osparc.data.Resources.fetch("studies", "patchNode", params)
return osparc.data.Resources.fetch("studies", "patch", params)
.then(() => {
studyData["workbench"][nodeId][fieldKey] = value;
studyData[fieldKey] = value;
// A bit hacky, but it's not sent back to the backend
studyData["lastChangeDate"] = new Date().toISOString();
});
},

patchStudyData: function(studyData, fieldKey, value) {
patchNodeData: function(studyData, nodeId, fieldKey, value) {
const patchData = {};
patchData[fieldKey] = value;
const params = {
url: {
"studyId": studyData["uuid"]
"studyId": studyData["uuid"],
"nodeId": nodeId
},
data: patchData
};
return osparc.data.Resources.fetch("studies", "patch", params)
return osparc.data.Resources.fetch("studies", "patchNode", params)
.then(() => {
studyData[fieldKey] = value;
studyData["workbench"][nodeId][fieldKey] = value;
// A bit hacky, but it's not sent back to the backend
studyData["lastChangeDate"] = new Date().toISOString();
});
},

addCollaborator: function(studyData, gid, permissions) {
const params = {
url: {
"studyId": studyData["uuid"],
"gId": gid
},
data: permissions
};
return osparc.data.Resources.fetch("studies", "postAccessRights", params)
.then(() => {
studyData["accessRights"][gid] = permissions;
studyData["lastChangeDate"] = new Date().toISOString();
})
.catch(err => osparc.FlashMessenger.logAs(err.message, "ERROR"));
},

addCollaborators: function(studyData, newCollaborators) {
const promises = [];
Object.keys(newCollaborators).forEach(gid => {
const params = {
url: {
"studyId": studyData["uuid"],
"gId": gid
},
data: newCollaborators[gid]
};
promises.push(osparc.data.Resources.fetch("studies", "postAccessRights", params));
});
return Promise.all(promises)
.then(() => {
Object.keys(newCollaborators).forEach(gid => {
studyData["accessRights"][gid] = newCollaborators[gid];
});
studyData["lastChangeDate"] = new Date().toISOString();
})
.catch(err => osparc.FlashMessenger.logAs(err.message, "ERROR"));
},

removeCollaborator: function(studyData, gid) {
const params = {
url: {
"studyId": studyData["uuid"],
"gId": gid
}
};
return osparc.data.Resources.fetch("studies", "deleteAccessRights", params)
.then(() => {
delete studyData["accessRights"]["gid"];
studyData["lastChangeDate"] = new Date().toISOString();
})
.catch(err => osparc.FlashMessenger.logAs(err.message, "ERROR"));
},

updateCollaborator: function(studyData, gid, newPermissions) {
const params = {
url: {
"studyId": studyData["uuid"],
"gId": gid
},
data: newPermissions
};
return osparc.data.Resources.fetch("studies", "putAccessRights", params)
.then(() => {
studyData["accessRights"][gid] = newPermissions;
studyData["lastChangeDate"] = new Date().toISOString();
})
.catch(err => osparc.FlashMessenger.logAs(err.message, "ERROR"));
}
}
});
Original file line number Diff line number Diff line change
Expand Up @@ -133,88 +133,32 @@ qx.Class.define("osparc.share.CollaboratorsStudy", {
return;
}

const newAccessRights = this._serializedDataCopy["accessRights"];
const newCollaborators = {};
gids.forEach(gid => {
newAccessRights[gid] = this._resourceType === "study" ? this.self().getCollaboratorAccessRight() : this.self().getViewerAccessRight();
newCollaborators[gid] = this._resourceType === "study" ? this.self().getCollaboratorAccessRight() : this.self().getViewerAccessRight();
});
osparc.info.StudyUtils.patchStudyData(this._serializedDataCopy, "accessRights", newAccessRights)
osparc.info.StudyUtils.addCollaborators(this._serializedDataCopy, newCollaborators)
.then(() => {
this.fireDataEvent("updateAccessRights", this._serializedDataCopy);
const text = this.tr("User(s) successfully added.");
osparc.FlashMessenger.getInstance().logAs(text);
this._reloadCollaboratorsList();

this.__pushNotifications(gids);
this.__checkShareePermissions(gids);
})
.catch(err => {
console.error(err);
osparc.FlashMessenger.getInstance().logAs(this.tr("Something went adding user(s)"), "ERROR");
});

// push 'STUDY_SHARED'/'TEMPLATE_SHARED' notification
osparc.store.Store.getInstance().getPotentialCollaborators()
.then(potentialCollaborators => {
gids.forEach(gid => {
if (gid in potentialCollaborators && "id" in potentialCollaborators[gid]) {
// it's a user, not an organization
const collab = potentialCollaborators[gid];
const uid = collab["id"];
if (this._resourceType === "study") {
osparc.notification.Notifications.postNewStudy(uid, this._serializedDataCopy["uuid"]);
} else {
osparc.notification.Notifications.postNewTemplate(uid, this._serializedDataCopy["uuid"]);
}
}
});
});
},

__checkShareePermissions: function(gids) {
if (gids.length === 0) {
return;
}

const promises = [];
gids.forEach(gid => {
const params = {
url: {
"studyId": this._serializedDataCopy["uuid"],
"gid": gid
}
};
promises.push(osparc.data.Resources.fetch("studies", "checkShareePermissions", params));
});
Promise.all(promises)
.then(values => {
const noAccessible = values.filter(value => value["accessible"] === false);
if (noAccessible.length) {
const shareePermissions = new osparc.share.ShareePermissions(noAccessible);
const win = osparc.ui.window.Window.popUpInWindow(shareePermissions, this.tr("Sharee permissions"), 500, 500, "@FontAwesome5Solid/exclamation-triangle/14").set({
clickAwayClose: false,
resizable: true,
showClose: true
});
win.getChildControl("icon").set({
textColor: "warning-yellow"
});
}
});
},

_deleteMember: function(collaborator, item) {
if (item) {
item.setEnabled(false);
}
const success = delete this._serializedDataCopy["accessRights"][collaborator["gid"]];
if (!success) {
osparc.FlashMessenger.getInstance().logAs(this.tr("Something went wrong removing Member"), "ERROR");
if (item) {
item.setEnabled(true);
}
return;
}

osparc.info.StudyUtils.patchStudyData(this._serializedDataCopy, "accessRights", this._serializedDataCopy["accessRights"])
osparc.info.StudyUtils.removeCollaborator(this._serializedDataCopy, collaborator["gid"])
.then(() => {
this.fireDataEvent("updateAccessRights", this._serializedDataCopy);
osparc.FlashMessenger.getInstance().logAs(this.tr("Member successfully removed"));
Expand All @@ -233,8 +177,8 @@ qx.Class.define("osparc.share.CollaboratorsStudy", {

__make: function(collaboratorGId, newAccessRights, successMsg, failureMsg, item) {
item.setEnabled(false);
this._serializedDataCopy["accessRights"][collaboratorGId] = newAccessRights;
osparc.info.StudyUtils.patchStudyData(this._serializedDataCopy, "accessRights", this._serializedDataCopy["accessRights"])

osparc.info.StudyUtils.updateCollaborator(this._serializedDataCopy, collaboratorGId, newAccessRights[collaboratorGId])
.then(() => {
this.fireDataEvent("updateAccessRights", this._serializedDataCopy);
osparc.FlashMessenger.getInstance().logAs(successMsg);
Expand All @@ -244,7 +188,11 @@ qx.Class.define("osparc.share.CollaboratorsStudy", {
console.error(err);
osparc.FlashMessenger.getInstance().logAs(failureMsg, "ERROR");
})
.finally(() => item.setEnabled(true));
.finally(() => {
if (item) {
item.setEnabled(true);
}
});
},

_promoteToEditor: function(collaborator, item) {
Expand Down Expand Up @@ -307,6 +255,57 @@ qx.Class.define("osparc.share.CollaboratorsStudy", {
this.tr(`Something went wrong changing ${osparc.data.Roles.STUDY[3].label} to ${osparc.data.Roles.STUDY[2].label}`),
item
);
},

__pushNotifications: function(gids) {
// push 'STUDY_SHARED'/'TEMPLATE_SHARED' notification
osparc.store.Store.getInstance().getPotentialCollaborators()
.then(potentialCollaborators => {
gids.forEach(gid => {
if (gid in potentialCollaborators && "id" in potentialCollaborators[gid]) {
// it's a user, not an organization
const collab = potentialCollaborators[gid];
const uid = collab["id"];
if (this._resourceType === "study") {
osparc.notification.Notifications.postNewStudy(uid, this._serializedDataCopy["uuid"]);
} else {
osparc.notification.Notifications.postNewTemplate(uid, this._serializedDataCopy["uuid"]);
}
}
});
});
},

__checkShareePermissions: function(gids) {
if (gids.length === 0) {
return;
}

const promises = [];
gids.forEach(gid => {
const params = {
url: {
"studyId": this._serializedDataCopy["uuid"],
"gid": gid
}
};
promises.push(osparc.data.Resources.fetch("studies", "checkShareePermissions", params));
});
Promise.all(promises)
.then(values => {
const noAccessible = values.filter(value => value["accessible"] === false);
if (noAccessible.length) {
const shareePermissions = new osparc.share.ShareePermissions(noAccessible);
const win = osparc.ui.window.Window.popUpInWindow(shareePermissions, this.tr("Sharee permissions"), 500, 500, "@FontAwesome5Solid/exclamation-triangle/14").set({
clickAwayClose: false,
resizable: true,
showClose: true
});
win.getChildControl("icon").set({
textColor: "warning-yellow"
});
}
});
}
}
});
Original file line number Diff line number Diff line change
Expand Up @@ -67,18 +67,21 @@ qx.Class.define("osparc.study.SaveAsTemplate", {
},

__publishTemplate: function() {
// AccessRights will be POSTed after the template is created
const accessRights = {}
this.__studyDataClone["accessRights"] = {};
const selectedGroupIDs = this.__shareWith.getSelectedGroups();
selectedGroupIDs.forEach(gid => {
this.__studyDataClone["accessRights"][gid] = osparc.share.CollaboratorsStudy.getViewerAccessRight();
accessRights[gid] = osparc.share.CollaboratorsStudy.getViewerAccessRight();
});
// Make publisher owner
const myGroupId = osparc.auth.Data.getInstance().getGroupId();
this.__studyDataClone["accessRights"][myGroupId] = osparc.share.CollaboratorsStudy.getOwnerAccessRight();
accessRights[myGroupId] = osparc.share.CollaboratorsStudy.getOwnerAccessRight();

this.fireDataEvent("publishTemplate", {
"studyData": this.__studyDataClone,
"copyData": this.__copyWData.getValue()
"copyData": this.__copyWData.getValue(),
"accessRights": accessRights
});
},

Expand Down
Loading