chore(activitystream): refactor getUserActivity
This commit is contained in:
@@ -114,3 +114,22 @@ export type GetResourceActivity = ({
|
||||
cursor: string | null
|
||||
items: StreamActivityRecord[]
|
||||
}>
|
||||
|
||||
export type GetUserActivity = ({
|
||||
userId,
|
||||
actionType,
|
||||
before,
|
||||
after,
|
||||
cursor,
|
||||
limit
|
||||
}: {
|
||||
userId: string
|
||||
actionType: StreamActionType
|
||||
after?: Date
|
||||
before?: Date
|
||||
cursor?: Date
|
||||
limit?: number
|
||||
}) => Promise<{
|
||||
cursor: string | null
|
||||
items: StreamActivityRecord[]
|
||||
}>
|
||||
|
||||
@@ -1,84 +0,0 @@
|
||||
'use strict'
|
||||
const { md5 } = require('@/modules/shared/helpers/cryptoHelper')
|
||||
const { getUserActivity } = require('../../services/index')
|
||||
const {
|
||||
getActivityCountByUserIdFactory,
|
||||
getTimelineCountFactory,
|
||||
getUserTimelineFactory
|
||||
} = require('@/modules/activitystream/repositories')
|
||||
const { db } = require('@/db/knex')
|
||||
|
||||
const userActivityQueryCore = async (parent, args) => {
|
||||
const { items, cursor } = await getUserActivity({
|
||||
userId: parent.id,
|
||||
actionType: args.actionType,
|
||||
after: args.after,
|
||||
before: args.before,
|
||||
cursor: args.cursor,
|
||||
limit: args.limit
|
||||
})
|
||||
const totalCount = await getActivityCountByUserIdFactory({ db })({
|
||||
userId: parent.id,
|
||||
actionType: args.actionType,
|
||||
after: args.after,
|
||||
before: args.before
|
||||
})
|
||||
|
||||
return { items, cursor, totalCount }
|
||||
}
|
||||
|
||||
const userTimelineQueryCore = async (parent, args) => {
|
||||
const { items, cursor } = await getUserTimelineFactory({ db })({
|
||||
userId: parent.id,
|
||||
after: args.after,
|
||||
before: args.before,
|
||||
cursor: args.cursor,
|
||||
limit: args.limit
|
||||
})
|
||||
const totalCount = await getTimelineCountFactory({ db })({
|
||||
userId: parent.id,
|
||||
after: args.after,
|
||||
before: args.before
|
||||
})
|
||||
|
||||
return { items, cursor, totalCount }
|
||||
}
|
||||
|
||||
/** @type {import('@/modules/core/graph/generated/graphql').Resolvers} */
|
||||
module.exports = {
|
||||
LimitedUser: {
|
||||
async activity(parent, args) {
|
||||
return await userActivityQueryCore(parent, args)
|
||||
},
|
||||
|
||||
async timeline(parent, args) {
|
||||
return await userTimelineQueryCore(parent, args)
|
||||
}
|
||||
},
|
||||
User: {
|
||||
async activity(parent, args) {
|
||||
return await userActivityQueryCore(parent, args)
|
||||
},
|
||||
|
||||
async timeline(parent, args) {
|
||||
return await userTimelineQueryCore(parent, args)
|
||||
}
|
||||
},
|
||||
Activity: {
|
||||
/**
|
||||
* We need a unique ID to be able to properly cache stuff on the clientside
|
||||
*/
|
||||
id(parent) {
|
||||
if (!parent) return null
|
||||
const { streamId, resourceId, userId, time } = parent
|
||||
const plainIdentity = JSON.stringify({
|
||||
streamId,
|
||||
resourceId,
|
||||
userId,
|
||||
time
|
||||
})
|
||||
|
||||
return md5(plainIdentity)
|
||||
}
|
||||
}
|
||||
}
|
||||
+91
-1
@@ -3,14 +3,87 @@ import { ActionTypes } from '@/modules/activitystream/helpers/types'
|
||||
import {
|
||||
getActivityCountByResourceIdFactory,
|
||||
getActivityCountByStreamIdFactory,
|
||||
getActivityCountByUserIdFactory,
|
||||
getResourceActivityFactory,
|
||||
getStreamActivityFactory
|
||||
getStreamActivityFactory,
|
||||
getTimelineCountFactory,
|
||||
getUserActivityFactory,
|
||||
getUserTimelineFactory
|
||||
} from '@/modules/activitystream/repositories'
|
||||
import { Resolvers } from '@/modules/core/graph/generated/graphql'
|
||||
import { InvalidActionTypeError } from '@/modules/activitystream/errors/activityStream'
|
||||
import { StreamActionType } from '@/modules/activitystream/domain/types'
|
||||
import { md5 } from '@/modules/shared/helpers/cryptoHelper'
|
||||
|
||||
type ActivityPaginatedArgs = {
|
||||
actionType?: string | null
|
||||
after?: Date | null
|
||||
before?: Date | null
|
||||
cursor?: Date | null
|
||||
limit?: number // This field is required because the type-defs defines it as required
|
||||
}
|
||||
|
||||
const userActivityQueryCore = async (
|
||||
parent: { id: string },
|
||||
args: ActivityPaginatedArgs
|
||||
) => {
|
||||
const { items, cursor } = await getUserActivityFactory({ db })({
|
||||
userId: parent.id,
|
||||
actionType: (args.actionType as StreamActionType) ?? undefined,
|
||||
after: args.after ?? undefined,
|
||||
before: args.before ?? undefined,
|
||||
cursor: args.cursor ?? undefined,
|
||||
limit: args.limit
|
||||
})
|
||||
const totalCount = await getActivityCountByUserIdFactory({ db })({
|
||||
userId: parent.id,
|
||||
actionType: (args.actionType as StreamActionType) ?? undefined,
|
||||
after: args.after ?? undefined,
|
||||
before: args.before ?? undefined
|
||||
})
|
||||
|
||||
return { items, cursor, totalCount }
|
||||
}
|
||||
|
||||
const userTimelineQueryCore = async (
|
||||
parent: { id: string },
|
||||
args: ActivityPaginatedArgs
|
||||
) => {
|
||||
const { items, cursor } = await getUserTimelineFactory({ db })({
|
||||
userId: parent.id,
|
||||
after: args.after ?? undefined,
|
||||
before: args.before ?? undefined,
|
||||
cursor: args.cursor ?? undefined,
|
||||
limit: args.limit
|
||||
})
|
||||
const totalCount = await getTimelineCountFactory({ db })({
|
||||
userId: parent.id,
|
||||
after: args.after ?? undefined,
|
||||
before: args.before ?? undefined
|
||||
})
|
||||
|
||||
return { items, cursor, totalCount }
|
||||
}
|
||||
|
||||
export = {
|
||||
LimitedUser: {
|
||||
async activity(parent, args) {
|
||||
return await userActivityQueryCore(parent, args)
|
||||
},
|
||||
|
||||
async timeline(parent, args) {
|
||||
return await userTimelineQueryCore(parent, args)
|
||||
}
|
||||
},
|
||||
User: {
|
||||
async activity(parent, args) {
|
||||
return await userActivityQueryCore(parent, args)
|
||||
},
|
||||
|
||||
async timeline(parent, args) {
|
||||
return await userTimelineQueryCore(parent, args)
|
||||
}
|
||||
},
|
||||
Stream: {
|
||||
async activity(parent, args) {
|
||||
if (
|
||||
@@ -79,5 +152,22 @@ export = {
|
||||
|
||||
return { items, cursor, totalCount }
|
||||
}
|
||||
},
|
||||
Activity: {
|
||||
/**
|
||||
* We need a unique ID to be able to properly cache stuff on the clientside
|
||||
*/
|
||||
id(parent) {
|
||||
if (!parent) return null
|
||||
const { streamId, resourceId, userId, time } = parent
|
||||
const plainIdentity = JSON.stringify({
|
||||
streamId,
|
||||
resourceId,
|
||||
userId,
|
||||
time
|
||||
})
|
||||
|
||||
return md5(plainIdentity)
|
||||
}
|
||||
}
|
||||
} as Resolvers
|
||||
@@ -7,6 +7,7 @@ import {
|
||||
GetResourceActivity,
|
||||
GetStreamActivity,
|
||||
GetTimelineCount,
|
||||
GetUserActivity,
|
||||
GetUserTimeline
|
||||
} from '@/modules/activitystream/domain/operations'
|
||||
import {
|
||||
@@ -191,3 +192,24 @@ export const getResourceActivityFactory =
|
||||
cursor: results.length > 0 ? results[results.length - 1].time.toISOString() : null
|
||||
}
|
||||
}
|
||||
|
||||
export const getUserActivityFactory =
|
||||
({ db }: { db: Knex }): GetUserActivity =>
|
||||
async ({ userId, actionType, after, before, cursor, limit }) => {
|
||||
if (!limit) {
|
||||
limit = 200
|
||||
}
|
||||
|
||||
const dbQuery = tables.streamActivity(db).where({ userId })
|
||||
if (actionType) dbQuery.andWhere({ actionType })
|
||||
if (after) dbQuery.andWhere('time', '>', after)
|
||||
if (before) dbQuery.andWhere('time', '<', before)
|
||||
if (cursor) dbQuery.andWhere('time', '<', cursor)
|
||||
dbQuery.orderBy('time', 'desc').limit(limit)
|
||||
|
||||
const results = await dbQuery.select('*')
|
||||
return {
|
||||
items: results,
|
||||
cursor: results.length > 0 ? results[results.length - 1].time.toISOString() : null
|
||||
}
|
||||
}
|
||||
|
||||
@@ -61,24 +61,5 @@ module.exports = {
|
||||
{ trx }
|
||||
)
|
||||
}
|
||||
},
|
||||
|
||||
async getUserActivity({ userId, actionType, after, before, cursor, limit }) {
|
||||
if (!limit) {
|
||||
limit = 200
|
||||
}
|
||||
|
||||
const dbQuery = StreamActivity().where({ userId })
|
||||
if (actionType) dbQuery.andWhere({ actionType })
|
||||
if (after) dbQuery.andWhere('time', '>', after)
|
||||
if (before) dbQuery.andWhere('time', '<', before)
|
||||
if (cursor) dbQuery.andWhere('time', '<', cursor)
|
||||
dbQuery.orderBy('time', 'desc').limit(limit)
|
||||
|
||||
const results = await dbQuery.select('*')
|
||||
return {
|
||||
items: results,
|
||||
cursor: results.length > 0 ? results[results.length - 1].time.toISOString() : null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,7 +4,6 @@ const expect = require('chai').expect
|
||||
const { createUser } = require('../../core/services/users')
|
||||
const { createPersonalAccessToken } = require('../../core/services/tokens')
|
||||
const { createObject } = require('../../core/services/objects')
|
||||
const { getUserActivity } = require('../services')
|
||||
|
||||
const { beforeEachContext, initializeTestServer } = require('@/test/hooks')
|
||||
const { noErrors } = require('@/test/helpers')
|
||||
@@ -12,6 +11,10 @@ const {
|
||||
addOrUpdateStreamCollaborator
|
||||
} = require('@/modules/core/services/streams/streamAccessService')
|
||||
const { Roles, Scopes } = require('@speckle/shared')
|
||||
const { getUserActivityFactory } = require('@/modules/activitystream/repositories')
|
||||
const { db } = require('@/db/knex')
|
||||
|
||||
const getUserActivity = getUserActivityFactory({ db })
|
||||
|
||||
let sendRequest
|
||||
|
||||
|
||||
Reference in New Issue
Block a user