Dwayne Harris 5 years ago
parent
commit
8dccc477bd
  1. 14
      src/lib/collections.ts
  2. 87
      src/plugins/api/groups.ts
  3. 2
      src/schemas.ts

14
src/lib/collections.ts

@ -4,13 +4,13 @@ import uniq from 'lodash/uniq'
import { DatabaseItem } from '../types'
import { containerFor, createQuerySpec, queryItems } from './database'
import { User, UserSubscription, UserBlock } from '../types/collections'
import { User, UserSubscription, UserBlock, UserItemType } from '../types/collections'
export async function getUsers(client: CosmosClient, ids: string[], logger?: Logger): Promise<User[]> {
return await queryItems<User>({
container: containerFor(client, 'Users'),
query: createQuerySpec(
'SELECT u.id, u.name, u.imageUrl, u.coverImageUrl, u.group, u.created FROM Users u WHERE ARRAY_CONTAINS(@ids, u.id)',
`SELECT u.id, u.name, u.imageUrl, u.coverImageUrl, u['group'], u.created FROM Users u WHERE ARRAY_CONTAINS(@ids, u.id)`,
{
ids: uniq(ids),
}
@ -20,7 +20,7 @@ export async function getUsers(client: CosmosClient, ids: string[], logger?: Log
}
export async function getUsersFromItems<T extends DatabaseItem>(client: CosmosClient, items: T[], logger?: Logger): Promise<User[]> {
return await getUsers(client, items.map(i => i.id))
return await getUsers(client, items.map(i => i.id), logger)
}
export async function getApprovedSubscriptions(client: CosmosClient, from: string, to: string, logger?: Logger): Promise<UserSubscription[]> {
@ -30,9 +30,9 @@ export async function getApprovedSubscriptions(client: CosmosClient, from: strin
`SELECT u.id FROM Users u WHERE
u.subscriberId = @to
u.pk = @from AND
u.t = 'subscription' AND
u.t = @type AND
u.pending = false`,
{ from, to }
{ from, to, type: UserItemType.Subscription }
),
logger,
})
@ -44,9 +44,9 @@ export async function getUserBlocks(client: CosmosClient, from: string, to: stri
query: createQuerySpec(
`SELECT u.id FROM Users u WHERE
u.pk = @from
AND u.t = 'block'
AND u.t = @type
AND ARRAY_CONTAINS(@to, u.blockedId)`,
{ from, to }
{ from, to, type: UserItemType.Block }
),
logger,
})

87
src/plugins/api/groups.ts

@ -12,8 +12,9 @@ import merge from 'lodash/merge'
import { Server, IncomingMessage, ServerResponse } from 'http'
import { MIN_ID_LENGTH, MAX_NAME_LENGTH, GROUP_LISTING_PARTITION_KEY } from '../../constants'
import { errorSchema, groupListingSchema } from '../../schemas'
import { errorSchema, groupListingSchema, userSchema } from '../../schemas'
import { unauthorizedError, badRequestError, notFoundError, serverError } from '../../lib/errors'
import { getUsers } from '../../lib/collections'
import { containerFor, createQuerySpec, queryItems, getItem, normalize } from '../../lib/database'
import {
@ -489,12 +490,12 @@ function listRoute(server: FastifyInstance<Server, IncomingMessage, ServerRespon
let registrationString = ''
if (registration) {
registrationString = `AND d.registration = ${registration}`
registrationString = `AND d.registration = '${registration}'`
}
const container = containerFor(server.database.client, 'GroupDirectory')
const { resources: groups, requestCharge, continuation: newContinuation } = await container.items.query<GroupListing>(
`SELECT * FROM GroupDirectory d WHERE d.pk = ${GROUP_LISTING_PARTITION_KEY} ${registrationString} ORDER BY d.${sort}`,
`SELECT * FROM GroupDirectory d WHERE d.pk = '${GROUP_LISTING_PARTITION_KEY}' ${registrationString} ORDER BY d.${sort}`,
{
maxItemCount: 40,
continuation,
@ -510,6 +511,85 @@ function listRoute(server: FastifyInstance<Server, IncomingMessage, ServerRespon
})
}
function membersRoute(server: FastifyInstance<Server, IncomingMessage, ServerResponse>) {
interface Query {
type?: string
continuation?: string
}
const options: RouteShorthandOptions = {
schema: {
querystring: {
type: 'object',
properties: {
type: {
type: 'string',
enum: ['admin', 'moderator', 'member'],
},
continuation: { type: 'string' },
},
},
response: {
200: {
type: 'object',
properties: {
members: {
type: 'array',
items: userSchema,
},
continuation: { type: 'string' },
}
},
400: errorSchema,
}
},
}
server.get<Query, DefaultParams, DefaultHeaders, DefaultBody>('/api/group/:id/members', options, async (request, reply) => {
if (!server.database) return serverError(reply)
const groupContainer = containerFor(server.database.client, 'Groups')
const group = await getItem<Group>({
container: groupContainer,
id: request.params.id,
logger: request.log
})
if (!group) return notFoundError(reply)
const { type, continuation } = request.query
let typeString = ''
if (type) {
typeString = `AND g.membership = '${type}'`
}
const container = containerFor(server.database.client, 'Groups')
const { resources: memberships, requestCharge, continuation: newContinuation } = await container.items.query<GroupMembership>(
`SELECT g.userId, g.membership FROM Groups g WHERE g.pk = '${group.id}' AND g.t = '${GroupItemType.Membership}' ${typeString} ORDER BY g.created DESC`,
{
maxItemCount: 100,
continuation,
}
).fetchAll()
request.log.trace('Query: %d', requestCharge)
const users = await getUsers(server.database.client, memberships.map(membership => membership.userId), request.log)
return {
members: users.map(user => {
const m = memberships.find(membership => membership.userId === user.id)
return {
...user,
membership: m ? m.membership : undefined,
}
}),
continuation: newContinuation,
}
})
}
const plugin: Plugin<Server, IncomingMessage, ServerResponse, PluginOptions> = async server => {
availabilityRoute(server)
createRoute(server)
@ -518,6 +598,7 @@ const plugin: Plugin<Server, IncomingMessage, ServerResponse, PluginOptions> = a
unblockRoute(server)
activateRoute(server)
listRoute(server)
membersRoute(server)
}
export default plugin

2
src/schemas.ts

@ -39,7 +39,9 @@ export const userSchema: JSONSchema = {
},
},
created: { type: 'number' },
subscription: { type: 'string' },
membership: { type: 'string' },
},
}

Loading…
Cancel
Save