Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
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
28 changes: 28 additions & 0 deletions api/src/api/members.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,22 @@ const {
errorMessages,
} = require('../utils/members');

const MEMBER_ALIASES = {
'Co-Directors': ['CO_DIRECTOR'],
Directors: [
'CO_DIRECTOR',
'COMMUNITY_DIRECTOR',
'EXTERNAL_DIRECTOR',
'TECH_DIRECTOR',
],
Leads: [
'ACADEMY_LEAD',
'TECH_LEAD',
'PRODUCT_RESEARCH_LEAD',
'PRODUCT_MANAGER',
],
};

const validateMemberQuery = (req, res, next) => {
// Middleware that verifies that fields to be inserted/updated actually
// exist in the Member schema, and that user has permission to update them
Expand Down Expand Up @@ -69,6 +85,17 @@ router.get(
}),
);

router.get(
'/aliases',
requireRegistered,
errorWrap(async (req, res) => {
res.json({
success: true,
result: Object.keys(MEMBER_ALIASES),
});
}),
);

// Create a new member
// Requires Director Level
router.post(
Expand Down Expand Up @@ -218,3 +245,4 @@ router.put(
);

module.exports = router;
module.exports.MEMBER_ALIASES = MEMBER_ALIASES;
2 changes: 2 additions & 0 deletions api/src/api/notes.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ const {
const {
validateEditability,
validateReqParams,
parseNoteAliases,
} = require('../middleware/notes');
const { encryptNote, decryptNote } = require('../utils/apiWrapper');

Expand Down Expand Up @@ -167,6 +168,7 @@ router.get(
router.post(
'/',
requireLead,
parseNoteAliases,
errorWrap(async (req, res) => {
const memberID = req.user._id;
const currentVersion = {
Expand Down
43 changes: 43 additions & 0 deletions api/src/middleware/notes.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
const flatten = require('lodash/flatten');

const Note = require('../models/notes');
const Member = require('../models/members');
const { MEMBER_ALIASES } = require('../api/members');
const { isAdmin } = require('./auth');

// middleware to validate if user can edit
Expand Down Expand Up @@ -38,7 +42,46 @@ const validateReqParams = (req, res, next) => {
next();
};

// helper function to convert an alias to its ids
const convertAliasToIds = async (referencedIds) => {
const cleanedIds = await Promise.all(
referencedIds.map(async (idOrAlias) => {
if (!(idOrAlias in MEMBER_ALIASES)) return idOrAlias;

const roles = MEMBER_ALIASES[idOrAlias];
const nestedIds = await Member.find(
{ role: { $in: roles }, status: 'ACTIVE' },
{ _id: 1 },
);
const ids = nestedIds.map((nestedId) => String(nestedId._id));

return ids;
}),
);

const flattenedIds = flatten(cleanedIds);
return flattenedIds;
};

// middleware to parse the aliases into their respective IDs
const parseNoteAliases = async (req, res, next) => {
const note = req.body;

note.metaData.referencedMembers = [
...new Set(await convertAliasToIds(note.metaData.referencedMembers)),
];
note.metaData.access.editableBy = [
...new Set(await convertAliasToIds(note.metaData.access.editableBy)),
];
note.metaData.access.viewableBy = [
...new Set(await convertAliasToIds(note.metaData.access.viewableBy)),
];

next();
};

module.exports = {
validateEditability,
validateReqParams,
parseNoteAliases,
};
8 changes: 5 additions & 3 deletions api/src/models/notes.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,11 @@ const actions = Object.freeze({
});

const labelsEnum = [
'1v1',
'2v1',
'2v2',
'1:1',
'2:1',
'2:2',
'Midpoint Reflection',
'Final Reflection',
'Lead Interview',
'Director Interview',
'Meeting',
Expand Down
15 changes: 14 additions & 1 deletion client/src/pages/Note.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ import {
updateNote,
deleteNote,
getMembers,
getMemberAliases,
getNoteLabels,
endUserSession,
} from '../utils/apiWrapper';
Expand Down Expand Up @@ -191,7 +192,19 @@ const Note = ({ user }: NoteProps): Node => {
text: `${m.firstName} ${m.lastName}`,
value: m._id,
}));
setMembers(cleanedMembers);

// get alias types
const memberAliases = await getMemberAliases();

const cleanedMemberAliases = (memberAliases?.data?.result ?? []).map(
(m) => ({
key: m,
text: m,
value: m,
}),
);

setMembers([...cleanedMemberAliases, ...cleanedMembers]);

const resNoteLabels = await getNoteLabels();
const cleanedNoteLabels = (resNoteLabels?.data?.result ?? []).map(
Expand Down
15 changes: 15 additions & 0 deletions client/src/utils/apiWrapper.js
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,21 @@ export const getMembers = () => {
}));
};

// Retrieves all member aliases
export const getMemberAliases = () => {
const requestString = `${BACKEND_BASE_URL}/members/aliases`;
return axios
.get(requestString, {
headers: {
'Content-Type': 'application/JSON',
},
})
.catch((error) => ({
type: 'GET_MEMBER_ALIASES_FAIL',
error,
}));
};

// Retrieves a member's permissions from their mongo ID
export const updateMember = (member, memberID) => {
const requestString = `${BACKEND_BASE_URL}/members/${memberID}`;
Expand Down