Skip to content

Commit

Permalink
chore(rethinkdb): TimelineEvent: Phase 1 (#9871)
Browse files Browse the repository at this point in the history
Signed-off-by: Matt Krick <matt.krick@gmail.com>
  • Loading branch information
mattkrick committed Jun 26, 2024
1 parent 0300ce5 commit c6a028b
Show file tree
Hide file tree
Showing 16 changed files with 121 additions and 110 deletions.
2 changes: 1 addition & 1 deletion packages/client/components/SelectMeetingDropdownItem.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ const SelectMeetingDropdownItem = (props: Props) => {
history.push(`/meet/${meetingId}`)
}
//FIXME 6062: change to React.ComponentType
const IconOrSVG = meetingTypeToIcon[meetingType]
const IconOrSVG = meetingTypeToIcon[meetingType]!
const meetingPhase = getMeetingPhase(phases)
const meetingPhaseLabel = (meetingPhase && phaseLabelLookup[meetingPhase.phaseType]) || 'Complete'

Expand Down
4 changes: 2 additions & 2 deletions packages/server/dataloader/customLoaderMakers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -318,7 +318,7 @@ export const meetingSettingsByType = (parent: RootDataLoader) => {
keys.forEach((key) => {
const {meetingType} = key
types[meetingType] = types[meetingType] || []
types[meetingType].push(key.teamId)
types[meetingType]!.push(key.teamId)
})
const entries = Object.entries(types) as [MeetingTypeEnum, string[]][]
const resultsByType = await Promise.all(
Expand Down Expand Up @@ -422,7 +422,7 @@ export const meetingTemplatesByType = (parent: RootDataLoader) => {
keys.forEach((key) => {
const {meetingType} = key
types[meetingType] = types[meetingType] || []
types[meetingType].push(key.teamId)
types[meetingType]!.push(key.teamId)
})
const entries = Object.entries(types) as [MeetingTypeEnum, string[]][]
const resultsByType = await Promise.all(
Expand Down
11 changes: 10 additions & 1 deletion packages/server/graphql/mutations/archiveTimelineEvent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import TimelineEventCheckinComplete from 'parabol-server/database/types/Timeline
import TimelineEventRetroComplete from 'parabol-server/database/types/TimelineEventRetroComplete'
import getRethink from '../../database/rethinkDriver'
import {TimelineEventEnum} from '../../database/types/TimelineEvent'
import getKysely from '../../postgres/getKysely'
import {getUserId, isTeamMember} from '../../utils/authorization'
import publish from '../../utils/publish'
import standardError from '../../utils/standardError'
Expand Down Expand Up @@ -57,7 +58,15 @@ const archiveTimelineEvent = {
.get('timelineEventsByMeetingId')
.load(meetingId)
const eventIds = meetingTimelineEvents.map(({id}) => id)
await r.table('TimelineEvent').getAll(r.args(eventIds)).update({isActive: false}).run()
const pg = getKysely()
await Promise.all([
pg
.updateTable('TimelineEvent')
.set({isActive: false})
.where('id', 'in', eventIds)
.execute(),
r.table('TimelineEvent').getAll(r.args(eventIds)).update({isActive: false}).run()
])
meetingTimelineEvents.map((event) => {
const {id: timelineEventId, userId} = event
publish(
Expand Down
7 changes: 6 additions & 1 deletion packages/server/graphql/mutations/endCheckIn.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import MeetingAction from '../../database/types/MeetingAction'
import Task from '../../database/types/Task'
import TimelineEventCheckinComplete from '../../database/types/TimelineEventCheckinComplete'
import generateUID from '../../generateUID'
import getKysely from '../../postgres/getKysely'
import archiveTasksForDB from '../../safeMutations/archiveTasksForDB'
import removeSuggestedAction from '../../safeMutations/removeSuggestedAction'
import {Logger} from '../../utils/Logger'
Expand Down Expand Up @@ -244,7 +245,11 @@ export default {
})
)
const timelineEventId = events[0]!.id
await r.table('TimelineEvent').insert(events).run()
const pg = getKysely()
await Promise.all([
pg.insertInto('TimelineEvent').values(events).execute(),
r.table('TimelineEvent').insert(events).run()
])
if (team.isOnboardTeam) {
const teamLeadUserId = await r
.table('TeamMember')
Expand Down
7 changes: 6 additions & 1 deletion packages/server/graphql/mutations/endSprintPoker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import getRethink from '../../database/rethinkDriver'
import Meeting from '../../database/types/Meeting'
import MeetingPoker from '../../database/types/MeetingPoker'
import TimelineEventPokerComplete from '../../database/types/TimelineEventPokerComplete'
import getKysely from '../../postgres/getKysely'
import {Logger} from '../../utils/Logger'
import {analytics} from '../../utils/analytics/analytics'
import {getUserId, isSuperUser, isTeamMember} from '../../utils/authorization'
Expand Down Expand Up @@ -127,7 +128,11 @@ export default {
meetingId
})
)
await r.table('TimelineEvent').insert(events).run()
const pg = getKysely()
await Promise.all([
pg.insertInto('TimelineEvent').values(events).execute(),
r.table('TimelineEvent').insert(events).run()
])

const data = {
meetingId,
Expand Down
21 changes: 15 additions & 6 deletions packages/server/graphql/mutations/helpers/bootstrapNewUser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ import SuggestedActionTryTheDemo from '../../../database/types/SuggestedActionTr
import TimelineEventJoinedParabol from '../../../database/types/TimelineEventJoinedParabol'
import User from '../../../database/types/User'
import generateUID from '../../../generateUID'
import getKysely from '../../../postgres/getKysely'
import getUsersbyDomain from '../../../postgres/queries/getUsersByDomain'
import insertUser from '../../../postgres/queries/insertUser'
import IUser from '../../../postgres/types/IUser'
import acceptTeamInvitation from '../../../safeMutations/acceptTeamInvitation'
import {analytics} from '../../../utils/analytics/analytics'
Expand Down Expand Up @@ -57,13 +57,22 @@ const bootstrapNewUser = async (
const hasSAMLURL = !!(await getSAMLURLFromEmail(email, dataLoader, false))
const isQualifiedForAutoJoin = (isVerified || hasSAMLURL) && isCompanyDomain
const orgIds = organizations.map(({id}) => id)

const pg = getKysely()
const [teamsWithAutoJoinRes] = await Promise.all([
isQualifiedForAutoJoin ? dataLoader.get('autoJoinTeamsByOrgId').loadMany(orgIds) : [],
insertUser({...newUser, isPatient0, featureFlags: experimentalFlags}),
r({
event: r.table('TimelineEvent').insert(joinEvent)
}).run()
pg
.with('User', (qc) =>
qc.insertInto('User').values({
...newUser,
isPatient0,
featureFlags: experimentalFlags,
identities: newUser.identities.map((identity) => JSON.stringify(identity))
})
)
.insertInto('TimelineEvent')
.values(joinEvent)
.execute(),
r.table('TimelineEvent').insert(joinEvent).run()
])

// Identify the user so user properties are set before any events are sent
Expand Down
11 changes: 7 additions & 4 deletions packages/server/graphql/mutations/helpers/createTeamAndLeader.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,8 @@ import MeetingSettingsPoker from '../../../database/types/MeetingSettingsPoker'
import MeetingSettingsRetrospective from '../../../database/types/MeetingSettingsRetrospective'
import Team from '../../../database/types/Team'
import TimelineEventCreatedTeam from '../../../database/types/TimelineEventCreatedTeam'
import getPg from '../../../postgres/getPg'
import {insertTeamQuery} from '../../../postgres/queries/generated/insertTeamQuery'
import getKysely from '../../../postgres/getKysely'
import IUser from '../../../postgres/types/IUser'
import catchAndLog from '../../../postgres/utils/catchAndLog'
import addTeamIdToTMS from '../../../safeMutations/addTeamIdToTMS'
import insertNewTeamMember from '../../../safeMutations/insertNewTeamMember'

Expand Down Expand Up @@ -38,8 +36,13 @@ export default async function createTeamAndLeader(user: IUser, newTeam: ValidNew
orgId
})

const pg = getKysely()
await Promise.all([
catchAndLog(() => insertTeamQuery.run(verifiedTeam, getPg())),
pg
.with('Team', (qc) => qc.insertInto('Team').values(verifiedTeam))
.insertInto('TimelineEvent')
.values(timelineEvent)
.execute(),
// add meeting settings
r.table('MeetingSettings').insert(meetingSettings).run(),
// denormalize common fields to team member
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ export const MSTeamsNotificationHelper: NotificationIntegrationHelper<MSTeamsNot
const card = new AdaptiveCards.AdaptiveCard()
card.version = new AdaptiveCards.Version(1.2, 0)

const meetingTitle = meetingTypeTitleLookup[meeting.meetingType](meeting.name)
const meetingTitle = meetingTypeTitleLookup[meeting.meetingType]!(meeting.name)
const titleTextBlock = GenerateACMeetingTitle(meetingTitle)
card.addItem(titleTextBlock)

Expand All @@ -104,7 +104,7 @@ export const MSTeamsNotificationHelper: NotificationIntegrationHelper<MSTeamsNot
const meetingLinkColumn = new AdaptiveCards.Column()
meetingLinkColumn.width = 'stretch'
const joinMeetingActionSet = new AdaptiveCards.ActionSet()
const joinMeetingAction = MeetingActionLookup[meeting.meetingType](meetingUrl)
const joinMeetingAction = MeetingActionLookup[meeting.meetingType]!(meetingUrl)
joinMeetingActionSet.addAction(joinMeetingAction)
meetingLinkColumn.addItem(joinMeetingActionSet)
meetingLinkColumnSet.addColumn(meetingLinkColumn)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,7 @@ const MattermostNotificationHelper: NotificationIntegrationHelper<MattermostNoti
}
const options = {searchParams}
const meetingUrl = makeAppURL(appOrigin, `meet/${meeting.id}`, options)
const notification = makeStartMeetingNotificationLookup[meeting.meetingType](
const notification = makeStartMeetingNotificationLookup[meeting.meetingType]!(
team,
meeting,
meetingUrl
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -352,7 +352,7 @@ export const SlackSingleChannelNotifier: NotificationIntegrationHelper<SlackNoti
}
const options = {searchParams}
const meetingUrl = makeAppURL(appOrigin, `meet/${meeting.id}`, options)
const {title, blocks} = makeStartMeetingNotificationLookup[meeting.meetingType](
const {title, blocks} = makeStartMeetingNotificationLookup[meeting.meetingType]!(
team,
meeting,
meetingUrl
Expand Down Expand Up @@ -388,7 +388,7 @@ export const SlackSingleChannelNotifier: NotificationIntegrationHelper<SlackNoti
}
const options = {searchParams}
const meetingUrl = makeAppURL(appOrigin, `meet/${meeting.id}`, options)
const {blocks} = makeStartMeetingNotificationLookup[meeting.meetingType](
const {blocks} = makeStartMeetingNotificationLookup[meeting.meetingType]!(
team,
meeting,
meetingUrl
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import getRethink from '../../../database/rethinkDriver'
import {RDatum} from '../../../database/stricterR'
import MeetingRetrospective from '../../../database/types/MeetingRetrospective'
import TimelineEventRetroComplete from '../../../database/types/TimelineEventRetroComplete'
import getKysely from '../../../postgres/getKysely'
import removeSuggestedAction from '../../../safeMutations/removeSuggestedAction'
import {Logger} from '../../../utils/Logger'
import RecallAIServerManager from '../../../utils/RecallAIServerManager'
Expand Down Expand Up @@ -163,7 +164,11 @@ const safeEndRetrospective = async ({
})
)
const timelineEventId = events[0]!.id
await r.table('TimelineEvent').insert(events).run()
const pg = getKysely()
await Promise.all([
pg.insertInto('TimelineEvent').values(events).execute(),
r.table('TimelineEvent').insert(events).run()
])

if (team.isOnboardTeam) {
const teamLeadUserId = await r
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import {checkTeamsLimit} from '../../../billing/helpers/teamLimitsCheck'
import getRethink, {ParabolR} from '../../../database/rethinkDriver'
import MeetingTeamPrompt from '../../../database/types/MeetingTeamPrompt'
import TimelineEventTeamPromptComplete from '../../../database/types/TimelineEventTeamPromptComplete'
import getKysely from '../../../postgres/getKysely'
import {getTeamPromptResponsesByMeetingId} from '../../../postgres/queries/getTeamPromptResponsesByMeetingIds'
import {Logger} from '../../../utils/Logger'
import {analytics} from '../../../utils/analytics/analytics'
Expand Down Expand Up @@ -102,7 +103,11 @@ const safeEndTeamPrompt = async ({
})
)
const timelineEventId = events[0]!.id
await r.table('TimelineEvent').insert(events).run()
const pg = getKysely()
await Promise.all([
pg.insertInto('TimelineEvent').values(events).execute(),
r.table('TimelineEvent').insert(events).run()
])
summarizeTeamPrompt(meeting, context)
analytics.teamPromptEnd(completedTeamPrompt, meetingMembers, responses, dataLoader)
checkTeamsLimit(team.orgId, dataLoader)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import {Client} from 'pg'
import getPgConfig from '../getPgConfig'

export async function up() {
const client = new Client(getPgConfig())
await client.connect()
// teamId, orgId, meetingId
await client.query(`
DO $$
BEGIN
IF NOT EXISTS (SELECT 1 FROM pg_type WHERE typname = 'TimelineEventEnum') THEN
CREATE TYPE "TimelineEventEnum" AS ENUM (
'TEAM_PROMPT_COMPLETE',
'POKER_COMPLETE',
'actionComplete',
'createdTeam',
'joinedParabol',
'retroComplete'
);
END IF;
CREATE TABLE IF NOT EXISTS "TimelineEvent" (
"id" VARCHAR(100) PRIMARY KEY,
"createdAt" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW(),
"interactionCount" SMALLINT NOT NULL DEFAULT 0,
"seenCount" SMALLINT NOT NULL DEFAULT 0,
"type" "TimelineEventEnum" NOT NULL,
"userId" VARCHAR(100) NOT NULL,
"teamId" VARCHAR(100),
"orgId" VARCHAR(100),
"meetingId" VARCHAR(100),
"isActive" BOOLEAN NOT NULL DEFAULT TRUE,
CONSTRAINT "fk_userId"
FOREIGN KEY("userId")
REFERENCES "User"("id")
ON DELETE CASCADE,
CONSTRAINT "fk_teamId"
FOREIGN KEY("teamId")
REFERENCES "Team"("id")
ON DELETE CASCADE
);
CREATE INDEX IF NOT EXISTS "idx_TimelineEvent_userId_createdAt" ON "TimelineEvent"("userId", "createdAt") WHERE "isActive" = TRUE;
CREATE INDEX IF NOT EXISTS "idx_TimelineEvent_meetingId" ON "TimelineEvent"("meetingId");
END $$;
`)
await client.end()
}

export async function down() {
const client = new Client(getPgConfig())
await client.connect()
await client.query(`
DROP TABLE "TimelineEvent";
DROP TYPE "TimelineEventEnum";
` /* Do undo magic */)
await client.end()
}
21 changes: 0 additions & 21 deletions packages/server/postgres/queries/insertUser.ts

This file was deleted.

30 changes: 0 additions & 30 deletions packages/server/postgres/queries/src/insertTeamQuery.sql

This file was deleted.

36 changes: 0 additions & 36 deletions packages/server/postgres/queries/src/insertUserQuery.sql

This file was deleted.

0 comments on commit c6a028b

Please sign in to comment.