Skip to content

Commit

Permalink
feat: add manager usergroups
Browse files Browse the repository at this point in the history
  • Loading branch information
rutmanz committed Sep 19, 2024
1 parent c0d1457 commit 780514b
Show file tree
Hide file tree
Showing 5 changed files with 124 additions and 83 deletions.
31 changes: 16 additions & 15 deletions prisma/schema.prisma
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,13 @@ model Account {
}

model Department {
id String @id @db.VarChar(50)
name String @db.VarChar(100)
slack_group String? @db.VarChar(50)
createdAt DateTime @default(now()) @db.Timestamptz(6)
updatedAt DateTime @updatedAt @db.Timestamptz(6)
Certs Cert[]
id String @id @db.VarChar(50)
name String @db.VarChar(100)
slack_group String? @db.VarChar(50)
manager_slack_group String? @db.VarChar(50)
createdAt DateTime @default(now()) @db.Timestamptz(6)
updatedAt DateTime @updatedAt @db.Timestamptz(6)
Certs Cert[]
Members DepartmentAssociation[]
Expand Down Expand Up @@ -112,16 +113,16 @@ model Meetings {
}

model Member {
email String @id @db.VarChar(50)
first_name String @db.VarChar(50)
full_name String @db.VarChar(100)
email String @id @db.VarChar(50)
first_name String @db.VarChar(50)
full_name String @db.VarChar(100)
use_slack_photo Boolean
slack_id String? @unique @db.VarChar(15)
slack_photo String? @db.VarChar(255)
slack_photo_small String? @db.VarChar(255)
fallback_photo String? @db.VarChar(255)
is_primary_team Boolean @default(true)
active Boolean @default(true)
slack_id String? @unique @db.VarChar(15)
slack_photo String? @db.VarChar(255)
slack_photo_small String? @db.VarChar(255)
fallback_photo String? @db.VarChar(255)
is_primary_team Boolean @default(true)
active Boolean @default(true)
createdAt DateTime @default(now()) @db.Timestamptz(6)
updatedAt DateTime @updatedAt @db.Timestamptz(6)
Expand Down
29 changes: 29 additions & 0 deletions src/lib/cert_operations.ts
Original file line number Diff line number Diff line change
Expand Up @@ -78,3 +78,32 @@ export async function createCertRequest(giver: Prisma.MemberWhereUniqueInput, re
})
return { success: true }
}

export async function getManagers() {
const departments = await prisma.department.findMany({
include: {
Certs: {
where: {
isManager: true
},
select: {
Instances: {
select: {
Member: {
select: {
email: true,
slack_id: true
}
}
}
}
}
}
}
})

return departments.map((dept) => ({
dept,
managers: dept.Certs.flatMap((cert) => cert.Instances.map((instance) => instance.Member.slack_id).filter((v) => v != null))
}))
}
46 changes: 10 additions & 36 deletions src/slack/handlers/actions/checkin.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { Blocks, Elements, Message } from 'slack-block-builder'
import { Blocks, Message } from 'slack-block-builder'
import { getManagers } from '~lib/cert_operations'
import config from '~lib/config'
import logger from '~lib/logger'
import prisma from '~lib/prisma'
import { formatList } from '~slack/lib/messages'
import { EventMiddleware } from '~slack/lib/types'

Expand All @@ -14,52 +14,26 @@ export const handleAppMentioned: EventMiddleware<'app_mention'> = async ({ event
})
const user = await client.auth.test()

const departments = await prisma.department.findMany({
select: {
name: true,
Certs: {
where: {
isManager: true
},
select: {
Instances: {
select: {
Member: {
select: {
email: true,
slack_id: true
}
}
}
}
}
}
}
})

const dept_managers = departments.map((dept) => ({
name: dept.name,
managers: dept.Certs.flatMap((cert) => cert.Instances.map((instance) => instance.Member.slack_id).filter((v) => v != null))
}))
const dept_managers = await getManagers()

for (const dept of dept_managers) {
if (dept.managers.length == 0) {
logger.warn('No manager slack ids for dept ' + dept.name)
for (const manager_dept of dept_managers) {
if (manager_dept.managers.length == 0) {
logger.warn('No manager slack ids for dept ' + manager_dept.dept.name)
continue
}
const dm = await client.conversations.open({
users: [...config.slack.users.copres, ...dept.managers].join(',')
users: [...config.slack.users.copres, ...manager_dept.managers].join(',')
})
if (dm.channel?.id == null) {
logger.warn('No group dm for dept ' + dept.name)
logger.warn('No group dm for dept ' + manager_dept.dept.name)
continue
}
const text = event.text.replace('<@' + user.user_id! + '>', formatList(dept.managers.map((id) => '<@' + id + '>')))
const text = event.text.replace('<@' + user.user_id! + '>', formatList(manager_dept.managers.map((id) => '<@' + id + '>')))
await client.chat.postMessage({
channel: dm.channel!.id!,
text,
blocks: Message()
.blocks(Blocks.Section().text(text), Blocks.Context().elements('Copresident Checkin for ' + dept.name))
.blocks(Blocks.Section().text(text), Blocks.Context().elements('Copresident Checkin for ' + manager_dept.dept.name))
.buildToObject().blocks
})
}
Expand Down
4 changes: 3 additions & 1 deletion src/tasks/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,9 @@ export function scheduleTasks() {

tasks['Sync Sheet'] = scheduleTask(updateSheet, 60 * 5, isProd, 0)
tasks['Announce Certs'] = scheduleTask(announceNewCerts, 60 * 60, isProd, 60) // Just in case the cert announcement isn't automatically run on changes
tasks['Sync Usergroups'] = scheduleTask(updateSlackUsergroups, 60 * 60, isProd, 2 * 60)
if (isProd) { // This task affects workspace-wide groups, should not be run while testing if in the same workspace
tasks['Sync Usergroups'] = scheduleTask(updateSlackUsergroups, 60 * 60, isProd, 2 * 60)
}
tasks['Link Fallback Photos'] = createTaskFunc(syncFallbackPhotos)
tasks['Logout All'] = scheduleCronTask(createTaskFunc(logoutAll), '0 0 * * *')

Expand Down
97 changes: 66 additions & 31 deletions src/tasks/slack_groups.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import prisma from '~lib/prisma'
import logger from '~lib/logger'
import { profile_client } from '~slack/lib/profile'
import { slack_client } from '~slack'
import { getManagers } from '~lib/cert_operations'

let timeout: NodeJS.Timeout

Expand All @@ -12,65 +13,99 @@ export function scheduleUpdateSlackUsergroups() {
timeout = setTimeout(updateSlackUsergroups, 1000 * 30)
}
}

export async function updateSlackUsergroups() {
if (profile_client == null) {
return
}
const usergroups_list = await slack_client.usergroups.list({ include_disabled: true })
const usergroups = new Map(usergroups_list.usergroups!.map((g) => [g.id!, g]))
const departments = await prisma.department.findMany({ include: { Members: { select: { Member: { select: { slack_id: true } } } } } })
for (const department of departments) {
const handle = department.name.toLowerCase().replace(' ', '-') + '-dept'
const existing = usergroups.get(department.slack_group ?? '')
if (department.slack_group == null || existing == null) {
const resp = await profile_client.usergroups
const syncUsergroup = async (data: { department_id: string; group_id: string | null; title: string; handle: string; member_ids: string[] }) => {
const existing = usergroups.get(data.group_id ?? '')
let returnValue: { group_id: string; isNew: boolean }
if (data.group_id == null || existing == null) {
const resp = await profile_client!.usergroups
.create({
name: department.name,
handle
name: data.title,
handle: data.handle
})
.catch((e) => {
return { usergroup: null, error: e }
})
if (resp.error != null) {
logger.error({ error: resp.error, department: department.id, handle: department.name.toLowerCase().replace(' ', '-') }, 'Could not create usergroup')
continue
logger.error({ error: resp.error, department: data.department_id, handle: data.handle }, 'Could not create usergroup')
return
} else {
await prisma.department.update({
where: { id: department.id },
data: {
slack_group: resp.usergroup!.id
}
})
department.slack_group = resp.usergroup!.id!
data.group_id = resp.usergroup!.id!
returnValue = { group_id: resp.usergroup!.id!, isNew: true }
}
} else {
if (existing.name != department.name || existing.handle != handle) {
await profile_client.usergroups.update({
usergroup: department.slack_group,
name: department.name,
handle
if (existing.name != data.title || existing.handle != data.handle) {
await profile_client!.usergroups.update({
usergroup: data.group_id,
name: data.title,
handle: data.handle
})
}
returnValue = { group_id: data.group_id, isNew: false }
}

const members = department.Members.filter((m) => m.Member.slack_id != null).map((m) => m.Member.slack_id!)
if (members.length == 0 && existing != null) {
if (data.member_ids.length == 0 && existing != null) {
// If it's already disabled, don't disable it again
if (!existing.date_delete) {
await profile_client.usergroups.disable({
usergroup: department.slack_group
await profile_client!.usergroups.disable({
usergroup: data.group_id
})
}
}
if (members.length > 0) {

if (data.member_ids.length > 0) {
if (existing?.date_delete) {
await profile_client.usergroups.enable({
usergroup: department.slack_group
await profile_client!.usergroups.enable({
usergroup: data.group_id
})
}
await profile_client.usergroups.users.update({
usergroup: department.slack_group,
users: members.join(',')
await profile_client!.usergroups.users.update({
usergroup: data.group_id,
users: data.member_ids.join(',')
})
}

return returnValue
}
for (const department of departments) {
const res = await syncUsergroup({
department_id: department.id,
group_id: department.slack_group,
title: department.name,
handle: department.name.toLowerCase().replace(' ', '-') + '-dept',
member_ids: department.Members.filter((m) => m.Member.slack_id != null).map((m) => m.Member.slack_id!)
})
if (res?.isNew) {
await prisma.department.update({
where: { id: department.id },
data: {
slack_group: res.group_id
}
})
}
}
for (const manager_department of await getManagers()) {
const department = manager_department.dept
const res = await syncUsergroup({
department_id: department.id,
group_id: department.manager_slack_group,
title: department.name + ' Managers',
handle: department.name.toLowerCase().replace(' ', '-') + '-managers',
member_ids: manager_department.managers
})
if (res?.isNew) {
await prisma.department.update({
where: { id: department.id },
data: {
manager_slack_group: res.group_id
}
})
}
}
Expand Down

0 comments on commit 780514b

Please sign in to comment.