Update groups API
This commit is contained in:
parent
2ee067c072
commit
5af92a7d81
|
@ -54,6 +54,10 @@ Returns the authenticated user.
|
||||||
|
|
||||||
Gets all groups, in no particular order.
|
Gets all groups, in no particular order.
|
||||||
|
|
||||||
|
Parameters:
|
||||||
|
- `availableToUserId`: Optional. if specified, only groups that the user can
|
||||||
|
join and groups they've already joined will be returned.
|
||||||
|
|
||||||
Requires no authorization.
|
Requires no authorization.
|
||||||
|
|
||||||
### `GET /v0/groups/[slug]`
|
### `GET /v0/groups/[slug]`
|
||||||
|
@ -62,12 +66,18 @@ Gets a group by its slug.
|
||||||
|
|
||||||
Requires no authorization.
|
Requires no authorization.
|
||||||
|
|
||||||
### `GET /v0/groups/by-id/[id]`
|
### `GET /v0/group/by-id/[id]`
|
||||||
|
|
||||||
Gets a group by its unique ID.
|
Gets a group by its unique ID.
|
||||||
|
|
||||||
Requires no authorization.
|
Requires no authorization.
|
||||||
|
|
||||||
|
### `GET /v0/group/by-id/[id]/markets`
|
||||||
|
|
||||||
|
Gets a group's markets by its unique ID.
|
||||||
|
|
||||||
|
Requires no authorization.
|
||||||
|
|
||||||
### `GET /v0/markets`
|
### `GET /v0/markets`
|
||||||
|
|
||||||
Lists all markets, ordered by creation date descending.
|
Lists all markets, ordered by creation date descending.
|
||||||
|
|
|
@ -11,7 +11,7 @@ import {
|
||||||
updateDoc,
|
updateDoc,
|
||||||
where,
|
where,
|
||||||
} from 'firebase/firestore'
|
} from 'firebase/firestore'
|
||||||
import { uniq } from 'lodash'
|
import { uniq, uniqBy } from 'lodash'
|
||||||
import { Group, GROUP_CHAT_SLUG, GroupLink } from 'common/group'
|
import { Group, GROUP_CHAT_SLUG, GroupLink } from 'common/group'
|
||||||
import {
|
import {
|
||||||
coll,
|
coll,
|
||||||
|
@ -21,7 +21,7 @@ import {
|
||||||
listenForValues,
|
listenForValues,
|
||||||
} from './utils'
|
} from './utils'
|
||||||
import { Contract } from 'common/contract'
|
import { Contract } from 'common/contract'
|
||||||
import { updateContract } from 'web/lib/firebase/contracts'
|
import { getContractFromId, updateContract } from 'web/lib/firebase/contracts'
|
||||||
import { db } from 'web/lib/firebase/init'
|
import { db } from 'web/lib/firebase/init'
|
||||||
import { filterDefined } from 'common/util/array'
|
import { filterDefined } from 'common/util/array'
|
||||||
import { getUser } from 'web/lib/firebase/users'
|
import { getUser } from 'web/lib/firebase/users'
|
||||||
|
@ -31,6 +31,9 @@ export const groupMembers = (groupId: string) =>
|
||||||
collection(groups, groupId, 'groupMembers')
|
collection(groups, groupId, 'groupMembers')
|
||||||
export const groupContracts = (groupId: string) =>
|
export const groupContracts = (groupId: string) =>
|
||||||
collection(groups, groupId, 'groupContracts')
|
collection(groups, groupId, 'groupContracts')
|
||||||
|
const openGroupsQuery = query(groups, where('anyoneCanJoin', '==', true))
|
||||||
|
const memberGroupsQuery = (userId: string) =>
|
||||||
|
query(collectionGroup(db, 'groupMembers'), where('userId', '==', userId))
|
||||||
|
|
||||||
export function groupPath(
|
export function groupPath(
|
||||||
groupSlug: string,
|
groupSlug: string,
|
||||||
|
@ -78,23 +81,24 @@ export function listenForGroupContractDocs(
|
||||||
return listenForValues(groupContracts(groupId), setContractDocs)
|
return listenForValues(groupContracts(groupId), setContractDocs)
|
||||||
}
|
}
|
||||||
|
|
||||||
export function listenForOpenGroups(setGroups: (groups: Group[]) => void) {
|
export async function listGroupContracts(groupId: string) {
|
||||||
return listenForValues(
|
const contractDocs = await getValues<{
|
||||||
query(groups, where('anyoneCanJoin', '==', true)),
|
contractId: string
|
||||||
setGroups
|
createdTime: number
|
||||||
|
}>(groupContracts(groupId))
|
||||||
|
return Promise.all(
|
||||||
|
contractDocs.map((doc) => getContractFromId(doc.contractId))
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function listenForOpenGroups(setGroups: (groups: Group[]) => void) {
|
||||||
|
return listenForValues(openGroupsQuery, setGroups)
|
||||||
|
}
|
||||||
|
|
||||||
export function getGroup(groupId: string) {
|
export function getGroup(groupId: string) {
|
||||||
return getValue<Group>(doc(groups, groupId))
|
return getValue<Group>(doc(groups, groupId))
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getGroupContracts(groupId: string) {
|
|
||||||
return getValues<{ contractId: string; createdTime: number }>(
|
|
||||||
groupContracts(groupId)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function getGroupBySlug(slug: string) {
|
export async function getGroupBySlug(slug: string) {
|
||||||
const q = query(groups, where('slug', '==', slug))
|
const q = query(groups, where('slug', '==', slug))
|
||||||
const docs = (await getDocs(q)).docs
|
const docs = (await getDocs(q)).docs
|
||||||
|
@ -112,10 +116,7 @@ export function listenForMemberGroupIds(
|
||||||
userId: string,
|
userId: string,
|
||||||
setGroupIds: (groupIds: string[]) => void
|
setGroupIds: (groupIds: string[]) => void
|
||||||
) {
|
) {
|
||||||
const q = query(
|
const q = memberGroupsQuery(userId)
|
||||||
collectionGroup(db, 'groupMembers'),
|
|
||||||
where('userId', '==', userId)
|
|
||||||
)
|
|
||||||
return onSnapshot(q, { includeMetadataChanges: true }, (snapshot) => {
|
return onSnapshot(q, { includeMetadataChanges: true }, (snapshot) => {
|
||||||
if (snapshot.metadata.fromCache) return
|
if (snapshot.metadata.fromCache) return
|
||||||
|
|
||||||
|
@ -136,6 +137,24 @@ export function listenForMemberGroups(
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function listAvailableGroups(userId: string) {
|
||||||
|
const [openGroups, memberGroupSnapshot] = await Promise.all([
|
||||||
|
getValues<Group>(openGroupsQuery),
|
||||||
|
getDocs(memberGroupsQuery(userId)),
|
||||||
|
])
|
||||||
|
const memberGroups = filterDefined(
|
||||||
|
await Promise.all(
|
||||||
|
memberGroupSnapshot.docs.map((doc) => {
|
||||||
|
return doc.ref.parent.parent?.id
|
||||||
|
? getGroup(doc.ref.parent.parent?.id)
|
||||||
|
: null
|
||||||
|
})
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
return uniqBy([...openGroups, ...memberGroups], (g) => g.id)
|
||||||
|
}
|
||||||
|
|
||||||
export async function addUserToGroupViaId(groupId: string, userId: string) {
|
export async function addUserToGroupViaId(groupId: string, userId: string) {
|
||||||
// get group to get the member ids
|
// get group to get the member ids
|
||||||
const group = await getGroup(groupId)
|
const group = await getGroup(groupId)
|
||||||
|
|
18
web/pages/api/v0/group/by-id/[id]/markets.ts
Normal file
18
web/pages/api/v0/group/by-id/[id]/markets.ts
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
import { NextApiRequest, NextApiResponse } from 'next'
|
||||||
|
import { applyCorsHeaders, CORS_UNRESTRICTED } from 'web/lib/api/cors'
|
||||||
|
import { listGroupContracts } from 'web/lib/firebase/groups'
|
||||||
|
|
||||||
|
export default async function handler(
|
||||||
|
req: NextApiRequest,
|
||||||
|
res: NextApiResponse
|
||||||
|
) {
|
||||||
|
await applyCorsHeaders(req, res, CORS_UNRESTRICTED)
|
||||||
|
const { id } = req.query
|
||||||
|
const contracts = await listGroupContracts(id as string)
|
||||||
|
if (!contracts) {
|
||||||
|
res.status(404).json({ error: 'Group not found' })
|
||||||
|
return
|
||||||
|
}
|
||||||
|
res.setHeader('Cache-Control', 'no-cache')
|
||||||
|
return res.status(200).json(contracts)
|
||||||
|
}
|
|
@ -1,14 +1,42 @@
|
||||||
import type { NextApiRequest, NextApiResponse } from 'next'
|
import type { NextApiRequest, NextApiResponse } from 'next'
|
||||||
import { listAllGroups } from 'web/lib/firebase/groups'
|
import { listAllGroups, listAvailableGroups } from 'web/lib/firebase/groups'
|
||||||
import { applyCorsHeaders, CORS_UNRESTRICTED } from 'web/lib/api/cors'
|
import { applyCorsHeaders, CORS_UNRESTRICTED } from 'web/lib/api/cors'
|
||||||
|
import { z } from 'zod'
|
||||||
|
import { validate } from 'web/pages/api/v0/_validate'
|
||||||
|
import { ValidationError } from 'web/pages/api/v0/_types'
|
||||||
|
|
||||||
type Data = any[]
|
const queryParams = z
|
||||||
|
.object({
|
||||||
|
availableToUserId: z.string().optional(),
|
||||||
|
})
|
||||||
|
.strict()
|
||||||
|
|
||||||
export default async function handler(
|
export default async function handler(
|
||||||
req: NextApiRequest,
|
req: NextApiRequest,
|
||||||
res: NextApiResponse<Data>
|
res: NextApiResponse
|
||||||
) {
|
) {
|
||||||
await applyCorsHeaders(req, res, CORS_UNRESTRICTED)
|
await applyCorsHeaders(req, res, CORS_UNRESTRICTED)
|
||||||
|
let params: z.infer<typeof queryParams>
|
||||||
|
try {
|
||||||
|
params = validate(queryParams, req.query)
|
||||||
|
} catch (e) {
|
||||||
|
if (e instanceof ValidationError) {
|
||||||
|
return res.status(400).json(e)
|
||||||
|
}
|
||||||
|
console.error(`Unknown error during validation: ${e}`)
|
||||||
|
return res.status(500).json({ error: 'Unknown error during validation' })
|
||||||
|
}
|
||||||
|
|
||||||
|
const { availableToUserId } = params
|
||||||
|
|
||||||
|
// TODO: should we check if the user is a real user?
|
||||||
|
if (availableToUserId) {
|
||||||
|
const groups = await listAvailableGroups(availableToUserId)
|
||||||
|
res.setHeader('Cache-Control', 'max-age=0')
|
||||||
|
res.status(200).json(groups)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
const groups = await listAllGroups()
|
const groups = await listAllGroups()
|
||||||
res.setHeader('Cache-Control', 'max-age=0')
|
res.setHeader('Cache-Control', 'max-age=0')
|
||||||
res.status(200).json(groups)
|
res.status(200).json(groups)
|
||||||
|
|
Loading…
Reference in New Issue
Block a user