Skip to content

Commit

Permalink
Quick interfaces support (#155)
Browse files Browse the repository at this point in the history
* better projects getting

* non-double roles

* another pipeline to prevent lots of calls
  • Loading branch information
cubap authored Nov 7, 2024
1 parent adfa5c7 commit f3a1574
Show file tree
Hide file tree
Showing 4 changed files with 118 additions and 37 deletions.
1 change: 1 addition & 0 deletions classes/Group/Group.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,7 @@ export default class Group {
status: 400,
message: "Cannot remove the last role; each member must have at least one role."
}
roles = roles.split(" ")
}

this.data.members[memberId].roles = this.data.members[memberId].roles.filter(role => !roles.includes(role))
Expand Down
88 changes: 85 additions & 3 deletions classes/Project/ProjectFactory.mjs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import Project from "./Project.mjs"
import Group from "../Group/Group.mjs"
import User from "../User/User.mjs"
import dbDriver from "../../database/driver.mjs"
const database = new dbDriver("mongo")

export default class ProjectFactory {
constructor(data) {
Expand Down Expand Up @@ -104,7 +106,7 @@ export default class ProjectFactory {
layers: projectData.layers ?? [],
manifest: projectData.manifest,
creator: projectData.creator,
contributors: {},
collaborators: {},
license: projectData.license,
tools: projectData.tools,
options: projectData.options,
Expand All @@ -116,16 +118,96 @@ export default class ProjectFactory {
.then(members => {
const loadMembers = []
Object.keys(members).forEach(memberId => {
project.contributors[memberId] = {
project.collaborators[memberId] = {
roles: members[memberId]
}
loadMembers.push(new User(memberId).getPublicInfo().then(profile => {
project.contributors[memberId].profile = profile
project.collaborators[memberId].profile = profile
}))
})
return Promise.all(loadMembers)
})

return project
}

static async loadAsUser(project_id,user_id) {
const pipeline = [
{ $match: { _id: project_id } },
{
$lookup: {
from: 'groups',
localField: 'group',
foreignField: '_id',
as: 'groupData'
}
},
{ $unwind: '$groupData' },
{
$addFields: {
userRoles: {
$ifNull: [`$groupData.members.${user_id}.roles`, []]
}
}
},
{
$match: {
$or: [
{ 'userRoles': { $in: ['*_*_*', 'READ_*_*', 'READ_*_PROJECT'] } },
{ 'creator': user_id }
]
}
},
{
$lookup: {
from: 'users',
localField: 'groupData.members._id',
foreignField: '_id',
as: 'membersData'
}
},
{
$project: {
_id: 1,
label: 1,
metadata: { $ifNull: ['$metadata', []] },
layers: { $ifNull: ['$layers', []] },
manifest: 1,
creator: 1,
license: 1,
tools: 1,
options: 1,
roles: { $mergeObjects: [Group.defaultRoles, '$customRoles'] },
collaborators: {
$arrayToObject: {
$map: {
input: { $objectToArray: '$groupData.members' },
as: 'member',
in: {
k: '$$member.k',
v: {
roles: '$$member.v.roles',
profile: {
$arrayElemAt: [
{
$filter: {
input: '$membersData',
as: 'user',
cond: { $eq: ['$$user._id', { $toObjectId: '$$member.k' }] }
}
},
0
]
}
}
}
}
}
}
}
}
]
const project = await database.controller.db.collection('projects').aggregate(pipeline).toArray()
return project[0]
}
}
52 changes: 30 additions & 22 deletions classes/User/User.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -113,29 +113,37 @@ export default class User {
* @returns project object
*/
async getProjects() {
const user = await this.getSelf()

// gross. I hate it.
return database
.find({ "@type": "Project" })
.then((resp) => {
if (resp instanceof Error) {
throw resp
}
const allProjects = resp
const userProjects = []
allProjects?.map((project) => {
if (project.creator === user.agent) {
userProjects.push(project)
} else {
project?.groups?.members?.map(async (member) => {
if (member.agent === user?.agent || member._id === this.id) {
userProjects.push(project)
}
})
return database.controller
.db.collection('projects').aggregate([
// Step 1: Lookup the related group details
{
$lookup: {
from: "groups",
localField: "group", // Field in `projects` referencing `_id` in `groups`
foreignField: "_id",
as: "groupInfo"
}
})

},
// Step 2: Filter for projects where the user is in the group's members
{
$match: {
"groupInfo.members": { $exists: true },
[`groupInfo.members.${this._id}`]: { $exists: true }
}
},
// Step 3: Project the required fields including the user's roles
{
$project: {
_id: 1, // Project ID
title: 1, // Project title
roles: { $arrayElemAt: [`$groupInfo.members.${this._id}.roles`, 0] } // User roles within the group
}
}
]).toArray()
.then((userProjects) => {
if (userProjects instanceof Error) {
throw userProjects
}
return userProjects
})
}
Expand Down
14 changes: 2 additions & 12 deletions project/index.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -106,21 +106,11 @@ router

(async () => {
try {
const projectObj = await new Project(id)
const accessInfo = await projectObj.checkUserAccess(user._id, ACTIONS.READ, SCOPES.ALL, ENTITIES.PROJECT)
const project = await ProjectFactory.forInterface(projectObj.data)
const project = await ProjectFactory.loadAsUser(id, user._id)
if (!project) {
return respondWithError(res, 404, `No TPEN3 project with ID '${id}' found`)
} else if (!accessInfo.hasAccess) {
return respondWithError(res, 401, accessInfo.message)
}

if (accessInfo.hasAccess) {
res.status(200).json(project)
} else {
respondWithError(res, 403, accessInfo.message)
}

res.status(200).json(project)
} catch (error) {
return respondWithError(
res,
Expand Down

0 comments on commit f3a1574

Please sign in to comment.