60f68b178d
* Fold type, fold page, query for fold contracts * Tsconfig: target esnext, nounused locals: false * Store tags in field on contract. Script to update contract tags * Show tags on fold page * Load all fold comments server-side to serve better feed * Fix the annoying firebase already initialized error! * Add links to /edit and /leaderboards for fold * Page with list of folds * UI for creating a fold * Create a fold * Edit fold page
82 lines
2.0 KiB
TypeScript
82 lines
2.0 KiB
TypeScript
import * as functions from 'firebase-functions'
|
|
import * as admin from 'firebase-admin'
|
|
import * as _ from 'lodash'
|
|
|
|
import { getUser } from './utils'
|
|
import { Contract } from '../../common/contract'
|
|
import { slugify } from '../../common/util/slugify'
|
|
import { randomString } from '../../common/util/random'
|
|
import { Fold } from '../../common/fold'
|
|
|
|
export const createFold = functions.runWith({ minInstances: 1 }).https.onCall(
|
|
async (
|
|
data: {
|
|
name: string
|
|
tags: string[]
|
|
},
|
|
context
|
|
) => {
|
|
const userId = context?.auth?.uid
|
|
if (!userId) return { status: 'error', message: 'Not authorized' }
|
|
|
|
const creator = await getUser(userId)
|
|
if (!creator) return { status: 'error', message: 'User not found' }
|
|
|
|
const { name, tags } = data
|
|
|
|
if (!name || typeof name !== 'string')
|
|
return { status: 'error', message: 'Name must be a non-empty string' }
|
|
|
|
if (!_.isArray(tags))
|
|
return { status: 'error', message: 'Tags must be an array of strings' }
|
|
|
|
console.log(
|
|
'creating fold for',
|
|
creator.username,
|
|
'named',
|
|
name,
|
|
'on',
|
|
tags
|
|
)
|
|
|
|
const slug = await getSlug(name)
|
|
|
|
const foldRef = firestore.collection('folds').doc()
|
|
|
|
const fold: Fold = {
|
|
id: foldRef.id,
|
|
curatorId: userId,
|
|
slug,
|
|
name,
|
|
tags,
|
|
createdTime: Date.now(),
|
|
contractIds: [],
|
|
excludedContractIds: [],
|
|
excludedCreatorIds: [],
|
|
}
|
|
|
|
await foldRef.create(fold)
|
|
|
|
return { status: 'success', fold }
|
|
}
|
|
)
|
|
|
|
const getSlug = async (name: string) => {
|
|
const proposedSlug = slugify(name)
|
|
|
|
const preexistingFold = await getFoldFromSlug(proposedSlug)
|
|
|
|
return preexistingFold ? proposedSlug + '-' + randomString() : proposedSlug
|
|
}
|
|
|
|
const firestore = admin.firestore()
|
|
|
|
export async function getFoldFromSlug(slug: string) {
|
|
const snap = await firestore
|
|
.collection('folds')
|
|
.where('slug', '==', slug)
|
|
.get()
|
|
|
|
return snap.empty ? undefined : (snap.docs[0].data() as Contract)
|
|
}
|