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
This commit is contained in:
Marshall Polaris 2022-08-20 13:32:12 -07:00 committed by GitHub
parent f4ebb2b504
commit 2439317408
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 73 additions and 10 deletions

View File

@ -23,13 +23,8 @@ type JwtCredentials = { kind: 'jwt'; data: admin.auth.DecodedIdToken }
type KeyCredentials = { kind: 'key'; data: string } type KeyCredentials = { kind: 'key'; data: string }
type Credentials = JwtCredentials | KeyCredentials type Credentials = JwtCredentials | KeyCredentials
const auth = admin.auth()
const firestore = admin.firestore()
const privateUsers = firestore.collection(
'private-users'
) as admin.firestore.CollectionReference<PrivateUser>
export const parseCredentials = async (req: Request): Promise<Credentials> => { export const parseCredentials = async (req: Request): Promise<Credentials> => {
const auth = admin.auth()
const authHeader = req.get('Authorization') const authHeader = req.get('Authorization')
if (!authHeader) { if (!authHeader) {
throw new APIError(403, 'Missing Authorization header.') throw new APIError(403, 'Missing Authorization header.')
@ -57,6 +52,8 @@ export const parseCredentials = async (req: Request): Promise<Credentials> => {
} }
export const lookupUser = async (creds: Credentials): Promise<AuthedUser> => { export const lookupUser = async (creds: Credentials): Promise<AuthedUser> => {
const firestore = admin.firestore()
const privateUsers = firestore.collection('private-users')
switch (creds.kind) { switch (creds.kind) {
case 'jwt': { case 'jwt': {
if (typeof creds.data.user_id !== 'string') { if (typeof creds.data.user_id !== 'string') {
@ -70,7 +67,7 @@ export const lookupUser = async (creds: Credentials): Promise<AuthedUser> => {
if (privateUserQ.empty) { if (privateUserQ.empty) {
throw new APIError(403, `No private user exists with API key ${key}.`) 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 } } return { uid: privateUser.id, creds: { privateUser, ...creds } }
} }
default: default:

View File

@ -21,6 +21,7 @@ const bodySchema = z.object({
}) })
export const creategroup = newEndpoint({}, async (req, auth) => { export const creategroup = newEndpoint({}, async (req, auth) => {
const firestore = admin.firestore()
const { name, about, memberIds, anyoneCanJoin } = validate( const { name, about, memberIds, anyoneCanJoin } = validate(
bodySchema, bodySchema,
req.body req.body
@ -67,7 +68,7 @@ export const creategroup = newEndpoint({}, async (req, auth) => {
return { status: 'success', group: group } return { status: 'success', group: group }
}) })
const getSlug = async (name: string) => { export const getSlug = async (name: string) => {
const proposedSlug = slugify(name) const proposedSlug = slugify(name)
const preexistingGroup = await getGroupFromSlug(proposedSlug) const preexistingGroup = await getGroupFromSlug(proposedSlug)
@ -75,9 +76,8 @@ const getSlug = async (name: string) => {
return preexistingGroup ? proposedSlug + '-' + randomString() : proposedSlug return preexistingGroup ? proposedSlug + '-' + randomString() : proposedSlug
} }
const firestore = admin.firestore()
export async function getGroupFromSlug(slug: string) { export async function getGroupFromSlug(slug: string) {
const firestore = admin.firestore()
const snap = await firestore const snap = await firestore
.collection('groups') .collection('groups')
.where('slug', '==', slug) .where('slug', '==', slug)

View File

@ -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))
}
}