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

chore(rethinkdb): TeamMember: Phase 3 #10003

Merged
merged 21 commits into from
Jul 24, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
eab30fb
write to PG
mattkrick Jul 15, 2024
650c396
chore: use dataloader in more cases
mattkrick Jul 16, 2024
d2a6388
use CTEs for a single write to PG
mattkrick Jul 16, 2024
344b7af
re-add rethinkdb mutation
mattkrick Jul 17, 2024
c136bb9
fix removeTemMember
mattkrick Jul 17, 2024
2b98ce0
combine calls to pg into 1 cte
mattkrick Jul 17, 2024
36e6f8f
fix tsc error
mattkrick Jul 17, 2024
eb30b1b
Merge branch 'master' into chore/teamMember-phase1
mattkrick Jul 17, 2024
288ea95
Merge branch 'master' into chore/teamMember-phase1
mattkrick Jul 17, 2024
d8ea1a4
chore: migrate existing TeamMembers to pg
mattkrick Jul 17, 2024
b611237
remove RethinkDB.TeamMember
mattkrick Jul 17, 2024
5fa485f
make picture non null
mattkrick Jul 17, 2024
21de99f
Merge branch 'chore/teamMember-phase1' into chore/teamMember-phase2
mattkrick Jul 17, 2024
c1947d9
Merge branch 'chore/teamMember-phase2' into chore/teamMember-phase3
mattkrick Jul 17, 2024
e0218c8
Merge branch 'master' into chore/teamMember-phase3
mattkrick Jul 18, 2024
f563d14
Merge branch 'master' into chore/teamMember-phase2
mattkrick Jul 19, 2024
41f0631
Merge branch 'master' into chore/teamMember-phase2
mattkrick Jul 19, 2024
2fa57ba
fix: don't destroy pg pool until teardown in tests
mattkrick Jul 19, 2024
90c1c5c
Merge branch 'chore/teamMember-phase2' into chore/teamMember-phase3
mattkrick Jul 19, 2024
89154f0
Merge branch 'master' into chore/teamMember-phase3
mattkrick Jul 23, 2024
9655589
fix: nonnull to return payloads
mattkrick Jul 24, 2024
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
4 changes: 2 additions & 2 deletions codegen.json
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@
"NotifyTaskInvolves": "../../database/types/NotificationTaskInvolves#default",
"NotifyTeamArchived": "../../database/types/NotificationTeamArchived#default",
"Organization": "./types/Organization#OrganizationSource",
"OrganizationUser": "../../postgres/types/index#OrganizationUser",
"OrganizationUser": "../../postgres/types/index#OrganizationUser as OrganizationUserDB",
"PokerMeeting": "../../database/types/MeetingPoker#default as MeetingPoker",
"PokerMeetingMember": "../../database/types/MeetingPokerMeetingMember#default as PokerMeetingMemberDB",
"PokerTemplate": "../../database/types/PokerTemplate#default as PokerTemplateDB",
Expand Down Expand Up @@ -145,7 +145,7 @@
"TeamHealthPhase": "./types/TeamHealthPhase#TeamHealthPhaseSource",
"TeamHealthStage": "./types/TeamHealthStage#TeamHealthStageSource",
"TeamInvitation": "../../database/types/TeamInvitation#default",
"TeamMember": "../../database/types/TeamMember#default as TeamMemberDB",
"TeamMember": "../../postgres/types/index#TeamMember as TeamMember",
"TeamMemberIntegrationAuthWebhook": "../../postgres/queries/getTeamMemberIntegrationAuth#TeamMemberIntegrationAuth",
"TeamMemberIntegrationAuthOAuth1": "../../postgres/queries/getTeamMemberIntegrationAuth#TeamMemberIntegrationAuth",
"TeamMemberIntegrationAuthOAuth2": "../../postgres/queries/getTeamMemberIntegrationAuth#TeamMemberIntegrationAuth",
Expand Down
5 changes: 0 additions & 5 deletions packages/server/database/rethinkDriver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ import {MasterPool, r} from 'rethinkdb-ts'
import SlackAuth from '../database/types/SlackAuth'
import SlackNotification from '../database/types/SlackNotification'
import TeamInvitation from '../database/types/TeamInvitation'
import TeamMember from '../database/types/TeamMember'
import {AnyMeeting, AnyMeetingSettings, AnyMeetingTeamMember} from '../postgres/types/Meeting'
import {ScheduledJobUnion} from '../types/custom'
import getRethinkConfig from './getRethinkConfig'
Expand Down Expand Up @@ -156,10 +155,6 @@ export type RethinkSchema = {
type: TeamInvitation
index: 'email' | 'teamId' | 'token'
}
TeamMember: {
type: TeamMember
index: 'teamId' | 'userId'
}
TemplateDimension: {
type: TemplateDimension
index: 'teamId' | 'templateId' | 'scaleId'
Expand Down
55 changes: 0 additions & 55 deletions packages/server/database/types/TeamMember.ts

This file was deleted.

17 changes: 17 additions & 0 deletions packages/server/dataloader/foreignKeyLoaderMakers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,23 @@ export const teamsByOrgIds = foreignKeyLoaderMaker('teams', 'orgId', (orgIds) =>
selectTeams().where('orgId', 'in', orgIds).where('isArchived', '=', false).execute()
)

export const teamMembersByTeamId = foreignKeyLoaderMaker('teamMembers', 'teamId', (teamIds) =>
getKysely()
.selectFrom('TeamMember')
.selectAll()
.where('teamId', 'in', teamIds)
.where('isNotRemoved', '=', true)
.execute()
)

export const teamMembersByUserId = foreignKeyLoaderMaker('teamMembers', 'userId', (userIds) =>
getKysely()
.selectFrom('TeamMember')
.selectAll()
.where('userId', 'in', userIds)
.where('isNotRemoved', '=', true)
.execute()
)
export const discussionsByMeetingId = foreignKeyLoaderMaker(
'discussions',
'meetingId',
Expand Down
4 changes: 4 additions & 0 deletions packages/server/dataloader/primaryKeyLoaderMakers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -146,3 +146,7 @@ export const saml = primaryKeyLoaderMaker((ids: readonly string[]) => {
export const organizationUsers = primaryKeyLoaderMaker((ids: readonly string[]) => {
return getKysely().selectFrom('OrganizationUser').selectAll().where('id', 'in', ids).execute()
})

export const teamMembers = primaryKeyLoaderMaker((ids: readonly string[]) => {
return getKysely().selectFrom('TeamMember').selectAll().where('id', 'in', ids).execute()
})
28 changes: 0 additions & 28 deletions packages/server/dataloader/rethinkForeignKeyLoaderMakers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -221,31 +221,3 @@ export const teamInvitationsByTeamId = new RethinkForeignKeyLoaderMaker(
.run()
}
)

export const teamMembersByTeamId = new RethinkForeignKeyLoaderMaker(
'teamMembers',
'teamId',
async (teamIds) => {
// tasksByUserId is expensive since we have to look up each team to check the team archive status
const r = await getRethink()
return r
.table('TeamMember')
.getAll(r.args(teamIds), {index: 'teamId'})
.filter({isNotRemoved: true})
.run()
}
)

export const teamMembersByUserId = new RethinkForeignKeyLoaderMaker(
'teamMembers',
'userId',
async (userIds) => {
// tasksByUserId is expensive since we have to look up each team to check the team archive status
const r = await getRethink()
return r
.table('TeamMember')
.getAll(r.args(userIds), {index: 'userId'})
.filter({isNotRemoved: true})
.run()
}
)
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,5 @@ export const slackAuths = new RethinkPrimaryKeyLoaderMaker('SlackAuth')
export const slackNotifications = new RethinkPrimaryKeyLoaderMaker('SlackNotification')
export const suggestedActions = new RethinkPrimaryKeyLoaderMaker('SuggestedAction')
export const tasks = new RethinkPrimaryKeyLoaderMaker('Task')
export const teamMembers = new RethinkPrimaryKeyLoaderMaker('TeamMember')
export const teamInvitations = new RethinkPrimaryKeyLoaderMaker('TeamInvitation')
export const templateDimensions = new RethinkPrimaryKeyLoaderMaker('TemplateDimension')
10 changes: 6 additions & 4 deletions packages/server/graphql/mutations/archiveTeam.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
import {GraphQLID, GraphQLNonNull, GraphQLObjectType} from 'graphql'
import {SubscriptionChannel} from 'parabol-client/types/constEnums'
import TeamMemberId from '../../../client/shared/gqlIds/TeamMemberId'
import {maybeRemoveRestrictions} from '../../billing/helpers/teamLimitsCheck'
import getRethink from '../../database/rethinkDriver'
import NotificationTeamArchived from '../../database/types/NotificationTeamArchived'
import removeMeetingTemplatesForTeam from '../../postgres/queries/removeMeetingTemplatesForTeam'
import safeArchiveTeam from '../../safeMutations/safeArchiveTeam'
import {analytics} from '../../utils/analytics/analytics'
import {getUserId, isSuperUser, isTeamLead, isUserOrgAdmin} from '../../utils/authorization'
import {getUserId, isSuperUser, isUserOrgAdmin} from '../../utils/authorization'
import publish from '../../utils/publish'
import standardError from '../../utils/standardError'
import {GQLContext} from '../graphql'
Expand Down Expand Up @@ -35,13 +36,14 @@ export default {

// AUTH
const viewerId = getUserId(authToken)
const [teamLead, viewer, teamToArchive] = await Promise.all([
isTeamLead(viewerId, teamId, dataLoader),
const [teamMember, viewer, teamToArchive] = await Promise.all([
dataLoader.get('teamMembers').load(TeamMemberId.join(teamId, viewerId)),
dataLoader.get('users').loadNonNull(viewerId),
dataLoader.get('teams').loadNonNull(teamId)
])
const isTeamLead = teamMember?.isLead
const isOrgAdmin = await isUserOrgAdmin(viewerId, teamToArchive.orgId, dataLoader)
if (!teamLead && !isSuperUser(authToken) && !isOrgAdmin) {
if (!isTeamLead && !isSuperUser(authToken) && !isOrgAdmin) {
return standardError(new Error('Not team lead or org admin'), {userId: viewerId})
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ import TimelineEventCreatedTeam from '../../../database/types/TimelineEventCreat
import {DataLoaderInstance} from '../../../dataloader/RootDataLoader'
import getKysely from '../../../postgres/getKysely'
import IUser from '../../../postgres/types/IUser'
import insertNewTeamMember from '../../../safeMutations/insertNewTeamMember'

interface ValidNewTeam {
id: string
Expand Down Expand Up @@ -68,9 +67,7 @@ export default async function createTeamAndLeader(
.values(timelineEvent)
.execute(),
// add meeting settings
r.table('MeetingSettings').insert(meetingSettings).run(),
// denormalize common fields to team member
insertNewTeamMember(user, teamId, dataLoader)
r.table('MeetingSettings').insert(meetingSettings).run()
])
dataLoader.clearAll(['teams', 'users', 'teamMembers', 'timelineEvents', 'meetingSettings'])
}
12 changes: 1 addition & 11 deletions packages/server/graphql/mutations/helpers/removeTeamMember.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,18 +47,12 @@ const removeTeamMember = async (
r.table('Task').getAll(teamId, {index: 'teamId'}).delete()
])
} else if (isLead) {
// assign new leader, remove old leader flag
await pg
.updateTable('TeamMember')
.set(({not}) => ({isLead: not('isLead')}))
.where('id', 'in', [teamMemberId, teamLeader.id])
.execute()
// assign new leader, remove old leader flag
await r({
newTeamLead: r.table('TeamMember').get(teamLeader.id).update({
isLead: true
}),
oldTeamLead: r.table('TeamMember').get(teamMemberId).update({isLead: false})
}).run()
}

await pg
Expand All @@ -68,10 +62,6 @@ const removeTeamMember = async (
.execute()
// assign active tasks to the team lead
const {integratedTasksToArchive, reassignedTasks} = await r({
teamMember: r.table('TeamMember').get(teamMemberId).update({
isNotRemoved: false,
updatedAt: now
}),
integratedTasksToArchive: r
.table('Task')
.getAll(userId, {index: 'userId'})
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import Meeting from '../../../database/types/Meeting'
import MeetingMember from '../../../database/types/MeetingMember'
import TeamMember from '../../../database/types/TeamMember'
import {TeamMember} from '../../../postgres/types'
import {analytics} from '../../../utils/analytics/analytics'
import {DataLoaderWorker} from '../../graphql'

Expand Down
4 changes: 2 additions & 2 deletions packages/server/graphql/mutations/joinMeeting.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,11 @@ import Meeting from '../../database/types/Meeting'
import MeetingRetrospective from '../../database/types/MeetingRetrospective'
import PokerMeetingMember from '../../database/types/PokerMeetingMember'
import RetroMeetingMember from '../../database/types/RetroMeetingMember'
import TeamMember from '../../database/types/TeamMember'
import TeamPromptMeetingMember from '../../database/types/TeamPromptMeetingMember'
import TeamPromptResponseStage from '../../database/types/TeamPromptResponseStage'
import UpdatesStage from '../../database/types/UpdatesStage'
import insertDiscussions from '../../postgres/queries/insertDiscussions'
import {TeamMember} from '../../postgres/types'
import {analytics} from '../../utils/analytics/analytics'
import {getUserId, isTeamMember} from '../../utils/authorization'
import getPhase from '../../utils/getPhase'
Expand Down Expand Up @@ -82,7 +82,7 @@ const joinMeeting = {
return {error: {message: 'Not on the team'}}
}
const teamMemberId = toTeamMemberId(teamId, viewerId)
const teamMember = await dataLoader.get('teamMembers').load(teamMemberId)
const teamMember = await dataLoader.get('teamMembers').loadNonNull(teamMemberId)
const meetingMember = createMeetingMember(meeting, teamMember)
const {errors} = await r.table('MeetingMember').insert(meetingMember).run()
// if this is called concurrently, only 1 will be error free
Expand Down
10 changes: 0 additions & 10 deletions packages/server/graphql/mutations/promoteToTeamLead.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import {GraphQLID, GraphQLNonNull} from 'graphql'
import {SubscriptionChannel} from 'parabol-client/types/constEnums'
import TeamMemberId from '../../../client/shared/gqlIds/TeamMemberId'
import getRethink from '../../database/rethinkDriver'
import getKysely from '../../postgres/getKysely'
import {getUserId, isSuperUser, isUserOrgAdmin} from '../../utils/authorization'
import publish from '../../utils/publish'
Expand All @@ -27,7 +26,6 @@ export default {
{teamId, userId}: {teamId: string; userId: string},
{authToken, dataLoader, socketId: mutatorId}: GQLContext
) {
const r = await getRethink()
const pg = getKysely()
const operationId = dataLoader.share()
const subOptions = {mutatorId, operationId}
Expand Down Expand Up @@ -61,14 +59,6 @@ export default {
.where('id', 'in', [oldLeadTeamMemberId, promoteeOnTeam.id])
.execute()
dataLoader.clearAll('teamMembers')
await r({
teamLead: r.table('TeamMember').get(oldLeadTeamMemberId).update({
isLead: false
}),
promotee: r.table('TeamMember').get(promoteeOnTeam.id).update({
isLead: true
})
}).run()

const data = {teamId, oldLeaderId: oldLeadTeamMemberId, newLeaderId: promoteeOnTeam.id}
publish(SubscriptionChannel.TEAM, teamId, 'PromoteToTeamLeadPayload', data, subOptions)
Expand Down
8 changes: 5 additions & 3 deletions packages/server/graphql/mutations/removeTeamMember.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import {GraphQLID, GraphQLNonNull, GraphQLObjectType} from 'graphql'
import {SubscriptionChannel} from 'parabol-client/types/constEnums'
import fromTeamMemberId from 'parabol-client/utils/relay/fromTeamMemberId'
import {getUserId, isTeamLead, isUserOrgAdmin} from '../../utils/authorization'
import TeamMemberId from '../../../client/shared/gqlIds/TeamMemberId'
import {getUserId, isUserOrgAdmin} from '../../utils/authorization'
import publish from '../../utils/publish'
import standardError from '../../utils/standardError'
import {GQLContext} from '../graphql'
Expand Down Expand Up @@ -31,10 +32,11 @@ export default {
const viewerId = getUserId(authToken)
const {userId, teamId} = fromTeamMemberId(teamMemberId)
const team = await dataLoader.get('teams').loadNonNull(teamId)
const [isOrgAdmin, isViewerTeamLead] = await Promise.all([
const [isOrgAdmin, teamMember] = await Promise.all([
isUserOrgAdmin(viewerId, team.orgId, dataLoader),
isTeamLead(viewerId, teamId, dataLoader)
dataLoader.get('teamMembers').loadNonNull(TeamMemberId.join(teamId, viewerId))
])
const isViewerTeamLead = teamMember?.isLead
const isSelf = viewerId === userId
if (!isSelf) {
if (!isOrgAdmin && !isViewerTeamLead) {
Expand Down
7 changes: 1 addition & 6 deletions packages/server/graphql/mutations/setPokerSpectate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,6 @@ const setPokerSpectate = {
const r = await getRethink()
const pg = getKysely()
const viewerId = getUserId(authToken)
const now = new Date()
const operationId = dataLoader.share()
const subOptions = {mutatorId, operationId}

Expand Down Expand Up @@ -68,11 +67,7 @@ const setPokerSpectate = {
.where('id', '=', teamMemberId)
.execute()
await r({
meetingMember: r.table('MeetingMember').get(meetingMemberId).update({isSpectating}),
teamMember: r
.table('TeamMember')
.get(teamMemberId)
.update({isSpectatingPoker: isSpectating, updatedAt: now})
meetingMember: r.table('MeetingMember').get(meetingMemberId).update({isSpectating})
}).run()
dataLoader.clearAll('teamMembers')
// mutate the dataLoader cache
Expand Down
2 changes: 1 addition & 1 deletion packages/server/graphql/mutations/startSprintPoker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,7 @@ export default {
}

const teamMemberId = toTeamMemberId(teamId, viewerId)
const teamMember = await dataLoader.get('teamMembers').load(teamMemberId)
const teamMember = await dataLoader.get('teamMembers').loadNonNull(teamMemberId)
const {isSpectatingPoker} = teamMember
const updates = {
lastMeetingType: meetingType
Expand Down
15 changes: 0 additions & 15 deletions packages/server/graphql/mutations/toggleTeamDrawer.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
import {GraphQLID, GraphQLNonNull} from 'graphql'
import getRethink from '../../database/rethinkDriver'
import {RValue} from '../../database/stricterR'
import getKysely from '../../postgres/getKysely'
import {getUserId, isTeamMember} from '../../utils/authorization'
import standardError from '../../utils/standardError'
Expand All @@ -27,7 +25,6 @@ const toggleTeamDrawer = {
{teamId, teamDrawerType}: {teamId: string; teamDrawerType: TeamDrawer | null},
{authToken}: GQLContext
) => {
const r = await getRethink()
const pg = getKysely()
const viewerId = getUserId(authToken)

Expand All @@ -47,18 +44,6 @@ const toggleTeamDrawer = {
}))
.where('id', '=', viewerTeamMemberId)
.execute()
await r
.table('TeamMember')
.get(viewerTeamMemberId)
.update((teamMember: RValue) => ({
openDrawer: r.branch(
teamMember('openDrawer').default(null).eq(teamDrawerType),
null,
teamDrawerType
)
}))
.run()

return {teamMemberId: viewerTeamMemberId}
}
}
Expand Down
Loading
Loading