manifold/functions/src/create-group.ts

88 lines
2.2 KiB
TypeScript
Raw Normal View History

import * as admin from 'firebase-admin'
import { getUser } from './utils'
import { Contract } from '../../common/contract'
import { slugify } from '../../common/util/slugify'
import { randomString } from '../../common/util/random'
import {
Group,
MAX_ABOUT_LENGTH,
MAX_GROUP_NAME_LENGTH,
MAX_ID_LENGTH,
} from '../../common/group'
import { APIError, newEndpoint, validate } from '../../functions/src/api'
import { z } from 'zod'
const bodySchema = z.object({
name: z.string().min(1).max(MAX_GROUP_NAME_LENGTH),
memberIds: z.array(z.string().min(1).max(MAX_ID_LENGTH)),
anyoneCanJoin: z.boolean(),
about: z.string().min(1).max(MAX_ABOUT_LENGTH).optional(),
})
export const creategroup = newEndpoint({}, async (req, auth) => {
const { name, about, memberIds, anyoneCanJoin } = validate(
bodySchema,
req.body
)
const creator = await getUser(auth.uid)
if (!creator)
throw new APIError(400, 'No user exists with the authenticated user ID.')
// Add creator id to member ids for convenience
if (!memberIds.includes(creator.id)) memberIds.push(creator.id)
console.log(
'creating group for',
creator.username,
'named',
name,
'about',
about,
'other member ids',
memberIds
)
const slug = await getSlug(name)
const groupRef = firestore.collection('groups').doc()
const group: Group = {
id: groupRef.id,
creatorId: creator.id,
slug,
name,
about: about ?? '',
createdTime: Date.now(),
mostRecentActivityTime: Date.now(),
// TODO: allow users to add contract ids on group creation
contractIds: [],
anyoneCanJoin,
memberIds,
}
await groupRef.create(group)
return { status: 'success', group: group }
})
const getSlug = async (name: string) => {
const proposedSlug = slugify(name)
const preexistingGroup = await getGroupFromSlug(proposedSlug)
return preexistingGroup ? proposedSlug + '-' + randomString() : proposedSlug
}
const firestore = admin.firestore()
export async function getGroupFromSlug(slug: string) {
const snap = await firestore
.collection('groups')
.where('slug', '==', slug)
.get()
return snap.empty ? undefined : (snap.docs[0].data() as Contract)
}