From 2439317408ac2f17473c02ccac0931502a39cf79 Mon Sep 17 00:00:00 2001 From: Marshall Polaris Date: Sat, 20 Aug 2022 13:32:12 -0700 Subject: [PATCH] Convert tags to groups on demand (#784) * Fix stuff to not prematurely initialize Firebase when imported * Add script to convert a tag to a group with the same contracts --- functions/src/api.ts | 11 ++-- functions/src/create-group.ts | 6 +- functions/src/scripts/convert-tag-to-group.ts | 66 +++++++++++++++++++ 3 files changed, 73 insertions(+), 10 deletions(-) create mode 100644 functions/src/scripts/convert-tag-to-group.ts diff --git a/functions/src/api.ts b/functions/src/api.ts index e9a488c2..7440f16a 100644 --- a/functions/src/api.ts +++ b/functions/src/api.ts @@ -23,13 +23,8 @@ type JwtCredentials = { kind: 'jwt'; data: admin.auth.DecodedIdToken } type KeyCredentials = { kind: 'key'; data: string } type Credentials = JwtCredentials | KeyCredentials -const auth = admin.auth() -const firestore = admin.firestore() -const privateUsers = firestore.collection( - 'private-users' -) as admin.firestore.CollectionReference - export const parseCredentials = async (req: Request): Promise => { + const auth = admin.auth() const authHeader = req.get('Authorization') if (!authHeader) { throw new APIError(403, 'Missing Authorization header.') @@ -57,6 +52,8 @@ export const parseCredentials = async (req: Request): Promise => { } export const lookupUser = async (creds: Credentials): Promise => { + const firestore = admin.firestore() + const privateUsers = firestore.collection('private-users') switch (creds.kind) { case 'jwt': { if (typeof creds.data.user_id !== 'string') { @@ -70,7 +67,7 @@ export const lookupUser = async (creds: Credentials): Promise => { if (privateUserQ.empty) { throw new APIError(403, `No private user exists with API key ${key}.`) } - const privateUser = privateUserQ.docs[0].data() + const privateUser = privateUserQ.docs[0].data() as PrivateUser return { uid: privateUser.id, creds: { privateUser, ...creds } } } default: diff --git a/functions/src/create-group.ts b/functions/src/create-group.ts index a9626916..71c6bd64 100644 --- a/functions/src/create-group.ts +++ b/functions/src/create-group.ts @@ -21,6 +21,7 @@ const bodySchema = z.object({ }) export const creategroup = newEndpoint({}, async (req, auth) => { + const firestore = admin.firestore() const { name, about, memberIds, anyoneCanJoin } = validate( bodySchema, req.body @@ -67,7 +68,7 @@ export const creategroup = newEndpoint({}, async (req, auth) => { return { status: 'success', group: group } }) -const getSlug = async (name: string) => { +export const getSlug = async (name: string) => { const proposedSlug = slugify(name) const preexistingGroup = await getGroupFromSlug(proposedSlug) @@ -75,9 +76,8 @@ const getSlug = async (name: string) => { return preexistingGroup ? proposedSlug + '-' + randomString() : proposedSlug } -const firestore = admin.firestore() - export async function getGroupFromSlug(slug: string) { + const firestore = admin.firestore() const snap = await firestore .collection('groups') .where('slug', '==', slug) diff --git a/functions/src/scripts/convert-tag-to-group.ts b/functions/src/scripts/convert-tag-to-group.ts new file mode 100644 index 00000000..48f14e27 --- /dev/null +++ b/functions/src/scripts/convert-tag-to-group.ts @@ -0,0 +1,66 @@ +// Takes a tag and makes a new group with all the contracts in it. + +import * as admin from 'firebase-admin' +import { initAdmin } from './script-init' +import { isProd, log } from '../utils' +import { getSlug } from '../create-group' +import { Group } from '../../../common/group' + +const getTaggedContractIds = async (tag: string) => { + const firestore = admin.firestore() + const results = await firestore + .collection('contracts') + .where('lowercaseTags', 'array-contains', tag.toLowerCase()) + .get() + return results.docs.map((d) => d.id) +} + +const createGroup = async ( + name: string, + about: string, + contractIds: string[] +) => { + const firestore = admin.firestore() + const creatorId = isProd() + ? 'IPTOzEqrpkWmEzh6hwvAyY9PqFb2' + : '94YYTk1AFWfbWMpfYcvnnwI1veP2' + + const slug = await getSlug(name) + const groupRef = firestore.collection('groups').doc() + const now = Date.now() + const group: Group = { + id: groupRef.id, + creatorId, + slug, + name, + about, + createdTime: now, + mostRecentActivityTime: now, + contractIds: contractIds, + anyoneCanJoin: true, + memberIds: [], + } + return await groupRef.create(group) +} + +const convertTagToGroup = async (tag: string, groupName: string) => { + log(`Looking up contract IDs with tag ${tag}...`) + const contractIds = await getTaggedContractIds(tag) + log(`${contractIds.length} contracts found.`) + if (contractIds.length > 0) { + log(`Creating group ${groupName}...`) + const about = `Contracts that used to be tagged ${tag}.` + const result = await createGroup(groupName, about, contractIds) + log(`Done. Group: `, result) + } +} + +if (require.main === module) { + initAdmin() + const args = process.argv.slice(2) + if (args.length != 2) { + console.log('Usage: convert-tag-to-group [tag] [group-name]') + } else { + convertTagToGroup(args[0], args[1]).catch((e) => console.error(e)) + } +}