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

21 context menu backend #48

Open
wants to merge 12 commits into
base: dev
Choose a base branch
from
19 changes: 18 additions & 1 deletion apps/backend/api/graphql/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import {
createAffiliation,
createCollection,
createComment,
createContextWidget,
createGroup,
createInvitation,
createJoinRequest,
Expand Down Expand Up @@ -80,7 +81,7 @@ import {
reinviteAll,
rejectGroupRelationshipInvite,
register,
reorderPostInCollection,
removeWidgetFromMenu,
removeMember,
removeModerator,
removePost,
Expand All @@ -91,6 +92,8 @@ import {
removeSkill,
removeSkillToLearn,
removeSuggestedSkillFromGroup,
reorderContextWidget,
reorderPostInCollection,
resendInvitation,
respondToEvent,
sendEmailVerification,
Expand All @@ -102,6 +105,7 @@ import {
unfulfillPost,
unlinkAccount,
updateComment,
updateContextWidget,
updateGroup,
updateGroupResponsibility,
updateGroupRole,
Expand Down Expand Up @@ -226,6 +230,7 @@ export function makeAuthenticatedQueries (userId, fetchOne, fetchMany) {
comment: (root, { id }) => fetchOne('Comment', id),
commonRoles: (root, args) => CommonRole.fetchAll(args),
connections: (root, args) => fetchMany('PersonConnection', args),
// contextWidgets: (root, args) => fetchMany('ContextWidget', args), // TODO CONTEXT: check if this is the best way to fetch context widgets
group: async (root, { id, slug, updateLastViewed }) => {
// you can specify id or slug, but not both
const group = await fetchOne('Group', slug || id, slug ? 'slug' : 'id')
Expand Down Expand Up @@ -349,6 +354,9 @@ export function makeMutations (expressContext, userId, isAdmin, fetchOne) {

createComment: (root, { data }) => createComment(userId, data),

createContextWidget: (root, { groupId, data }) =>
createContextWidget({ userId, groupId, data }),

createGroup: (root, { data }) => createGroup(userId, data),

createInvitation: (root, { groupId, data }) =>
Expand Down Expand Up @@ -460,6 +468,9 @@ export function makeMutations (expressContext, userId, isAdmin, fetchOne) {

rejectGroupRelationshipInvite: (root, { groupRelationshipInviteId }) => rejectGroupRelationshipInvite(userId, groupRelationshipInviteId),

removeWidgetFromMenu: (root, { contextWidgetId }) =>
removeWidgetFromMenu({ userId, contextWidgetId }),

removeMember: (root, { personId, groupId }) =>
removeMember(userId, personId, groupId),

Expand All @@ -482,6 +493,9 @@ export function makeMutations (expressContext, userId, isAdmin, fetchOne) {
removeSkillToLearn: (root, { id, name }) => removeSkillToLearn(userId, id || name),
removeSuggestedSkillFromGroup: (root, { groupId, id, name }) => removeSuggestedSkillFromGroup(userId, groupId, id || name),

reorderContextWidget: (root, { contextWidgetId, order }) =>
reorderContextWidget({ userId, contextWidgetId, order }),

reorderPostInCollection: (root, { collectionId, postId, newOrderIndex }) =>
reorderPostInCollection(userId, collectionId, postId, newOrderIndex),

Expand All @@ -508,6 +522,9 @@ export function makeMutations (expressContext, userId, isAdmin, fetchOne) {
unlinkAccount: (root, { provider }) =>
unlinkAccount(userId, provider),

updateContextWidget: (root, { contextWidgetId, data }) =>
updateContextWidget({ userId, contextWidgetId, data }),

updateGroupResponsibility: (root, { groupId, responsibilityId, title, description }) =>
updateGroupResponsibility({ userId, groupId, responsibilityId, title, description }),

Expand Down
37 changes: 37 additions & 0 deletions apps/backend/api/graphql/makeModels.js
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,42 @@ export default function makeModels (userId, isAdmin, apiClient) {
fetchMany: () => CommonRole.fetchAll()
},

ContextWidget: {
model: ContextWidget,
attributes: [
'id',
'title',
'type',
'order',
'visibility',
'view',
'icon',
'created_at',
'updated_at',
'highlightNumber',
'secondaryNumber'
],
relations: [
{ group: { alias: 'ownerGroup' } },
{ parent: { alias: 'parentWidget' } },
{ children: { alias: 'childWidgets', querySet: true } },
'viewGroup',
'viewPost',
'customView',
'viewUser',
'viewChat'
],
fetchMany: ({ groupId, includeUnordered }) => {
return ContextWidget.collection().query(q => {
q.where({ group_id: groupId })
if (!includeUnordered) {
q.whereNotNull('order')
}
q.orderBy('order', 'asc')
})
}
},

Me: {
model: User,
attributes: [
Expand Down Expand Up @@ -440,6 +476,7 @@ export default function makeModels (userId, isAdmin, apiClient) {
{ activeMembers: { querySet: true } },
{ agreements: { querySet: true } },
{ childGroups: { querySet: true } },
{ contextWidgets: { querySet: true } },
{ customViews: { querySet: true } },
{ groupRelationshipInvitesFrom: { querySet: true } },
{ groupRelationshipInvitesTo: { querySet: true } },
Expand Down
130 changes: 130 additions & 0 deletions apps/backend/api/graphql/mutations/context_widgets.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
const { GraphQLYogaError } = require('@graphql-yoga/node')
import convertGraphqlData from './convertGraphqlData'


// What are the mutations?
// - create
// - update
// - reorder
// - remove from menu

export async function createContextWidget({ userId, groupId, data }) {
if (!userId) throw new GraphQLYogaError('No userId passed into function')
if (!groupId) throw new GraphQLYogaError('No groupId passed into function')
const convertedData = convertGraphqlData(data)

const responsibilities = await Responsibility.fetchForUserAndGroupAsStrings(userId, groupId)
if (!responsibilities.includes(Responsibility.constants.RESP_ADMINISTRATION)) {
throw new GraphQLYogaError("You don't have permission to create context widgets for this group")
}

// Ensure only one view reference is set
const viewFields = ['view_group_id', 'view_post_id', 'custom_view_id', 'view_user_id', 'view_chat_id', 'view']
const setViewFields = viewFields.filter(field => convertedData[field] != null)
if (setViewFields.length > 1) {
throw new GraphQLYogaError('Only one view reference can be set')
}

return ContextWidget.create({
...convertedData,
group_id: groupId
})
.catch(err => {
throw new GraphQLYogaError(`Creation of context widget failed: ${err.message}`)
})
}

export async function updateContextWidget({ userId, contextWidgetId, data }) {
if (!userId) throw new GraphQLYogaError('No userId passed into function')
if (!contextWidgetId) throw new GraphQLYogaError('No context widget id passed into function')
const convertedData = convertGraphqlData(data)
const widget = await ContextWidget.where({ id: contextWidgetId }).fetch()
if (!widget) throw new GraphQLYogaError('Context widget not found')

const groupId = widget.get('group_id')
const responsibilities = await Responsibility.fetchForUserAndGroupAsStrings(userId, groupId)
if (!responsibilities.includes(Responsibility.constants.RESP_ADMINISTRATION)) {
throw new GraphQLYogaError("You don't have permission to update context widgets for this group")
}
// Ensure only one view reference is set
const viewFields = Object.values(ContextWidget.ViewFields)
const newViewFields = viewFields.filter(field => convertedData[field] != null)
if (newViewFields.length > 1) {
throw new GraphQLYogaError('Only one view reference can be set')
}

return ContextWidget.update({ id: contextWidgetId, data: convertedData })
.catch(err => {
throw new GraphQLYogaError(`Update of context widget failed: ${err.message}`)
})
}

export async function reorderContextWidget({ userId, contextWidgetId, order }) {
if (!userId) throw new GraphQLYogaError('No userId passed into function')
if (!contextWidgetId) throw new GraphQLYogaError('No context widget id passed into function')

const widget = await ContextWidget.where({ id: contextWidgetId }).fetch()
if (!widget) throw new GraphQLYogaError('Context widget not found')

const groupId = widget.get('group_id')
const responsibilities = await Responsibility.fetchForUserAndGroupAsStrings(userId, groupId)
if (!responsibilities.includes(Responsibility.constants.RESP_ADMINISTRATION)) {
throw new GraphQLYogaError("You don't have permission to reorder context widgets for this group")
}

return ContextWidget.reorder({
id: contextWidgetId,
order
})
.catch(err => {
throw new GraphQLYogaError(`Reordering of context widget failed: ${err.message}`)
})
}


export async function removeWidgetFromMenu({ userId, contextWidgetId }) {
if (!userId) throw new GraphQLYogaError('No userId passed into function')
if (!contextWidgetId) throw new GraphQLYogaError('No context widget id passed into function')

const widget = await ContextWidget.where({ id: contextWidgetId }).fetch()
if (!widget) throw new GraphQLYogaError('Context widget not found')

const groupId = widget.get('group_id')
const responsibilities = await Responsibility.fetchForUserAndGroupAsStrings(userId, groupId)
if (!responsibilities.includes(Responsibility.constants.RESP_ADMINISTRATION)) {
throw new GraphQLYogaError("You don't have permission to modify context widgets for this group")
}

return ContextWidget.removeFromMenu({id: contextWidgetId})
.catch(err => {
throw new GraphQLYogaError(`Removing widget from menu failed: ${err.message}`)
})
}

export async function transitionGroupToNewMenu({ userId, groupId }) {
if (!userId) throw new GraphQLYogaError('No userId passed into function')
if (!groupId) throw new GraphQLYogaError('No groupId passed into function')

// Look up the group
const group = await Group.where({ id: groupId }).fetch()
if (!group) throw new GraphQLYogaError('Group not found')

// Check if user has admin permissions
const responsibilities = await Responsibility.fetchForUserAndGroupAsStrings(userId, groupId)
if (!responsibilities.includes(Responsibility.constants.RESP_ADMINISTRATION)) {
throw new GraphQLYogaError("You don't have permission to modify this group's menu")
}

try {
const existingWidgets = await ContextWidget.where({ group_id: groupId }).fetch()

if (!existingWidgets) {
await group.setupContextWidgets()
}

await group.transitionToNewMenu()
return group
} catch (err) {
throw new GraphQLYogaError(`Failed to transition group to new menu: ${err.message}`)
}
}
Loading