chore(activitystream): refactor getStreamActivity

This commit is contained in:
Alessandro Magionami
2024-09-23 15:40:49 +02:00
parent 59872015fa
commit 6920bb1f0c
14 changed files with 110 additions and 57 deletions
@@ -52,7 +52,7 @@ export type Activity = {
export type ActivityCollection = {
__typename?: 'ActivityCollection';
cursor?: Maybe<Scalars['String']['output']>;
items?: Maybe<Array<Maybe<Activity>>>;
items: Array<Activity>;
totalCount: Scalars['Int']['output'];
};
@@ -3867,6 +3867,8 @@ export type Workspace = {
createdAt: Scalars['DateTime']['output'];
/** Selected fallback when `logo` not set */
defaultLogoIndex: Scalars['Int']['output'];
/** The default role workspace members will receive for workspace projects. */
defaultProjectRole: Scalars['String']['output'];
description?: Maybe<Scalars['String']['output']>;
/** Enable/Disable discovery of the workspace */
discoverabilityEnabled: Scalars['Boolean']['output'];
@@ -4153,6 +4155,7 @@ export type WorkspaceTeamFilter = {
export type WorkspaceUpdateInput = {
defaultLogoIndex?: InputMaybe<Scalars['Int']['input']>;
defaultProjectRole?: InputMaybe<Scalars['String']['input']>;
description?: InputMaybe<Scalars['String']['input']>;
discoverabilityEnabled?: InputMaybe<Scalars['Boolean']['input']>;
domainBasedMembershipProtectionEnabled?: InputMaybe<Scalars['Boolean']['input']>;
@@ -7190,6 +7193,7 @@ export type WorkspaceFieldArgs = {
billing: {},
createdAt: {},
defaultLogoIndex: {},
defaultProjectRole: {},
description: {},
discoverabilityEnabled: {},
domainBasedMembershipProtectionEnabled: {},
@@ -121,7 +121,7 @@ extend type Commit {
type ActivityCollection {
totalCount: Int!
cursor: String
items: [Activity]
items: [Activity!]!
}
type Activity {
+1
View File
@@ -68,6 +68,7 @@ generates:
BlobMetadata: '@/modules/blobstorage/domain/types#BlobStorageItem'
ServerWorkspacesInfo: '@/modules/core/helpers/graphTypes#GraphQLEmptyReturn'
ProjectRole: '@/modules/workspacesCore/helpers/graphTypes#ProjectRoleGraphQLReturn '
ActivityCollection: '@/modules/activitystream/helpers/graphTypes#ActivityCollectionGraphQLReturn'
modules/cross-server-sync/graph/generated/graphql.ts:
plugins:
- 'typescript'
@@ -1,4 +1,8 @@
import { StreamScopeActivity } from '@/modules/activitystream/helpers/types'
import { StreamActionType } from '@/modules/activitystream/domain/types'
import {
StreamActivityRecord,
StreamScopeActivity
} from '@/modules/activitystream/helpers/types'
export type GetActivity = (
streamId: string,
@@ -16,3 +20,12 @@ export type GetActiveUserStreams = (
streamIds: string[]
}[]
>
export type GetStreamActivity = (args: {
streamId: string
actionType: StreamActionType
after?: Date
before?: Date
cursor?: Date
limit?: number
}) => Promise<{ items: StreamActivityRecord[]; cursor: string | null }>
@@ -0,0 +1,4 @@
import { ActionTypes } from '@/modules/activitystream/helpers/types'
export type StreamActionType =
(typeof ActionTypes.Stream)[keyof (typeof ActionTypes)['Stream']]
@@ -0,0 +1,7 @@
import { BaseError } from '@/modules/shared/errors'
export class InvalidActionTypeError extends BaseError {
static defaultMessage = 'Invalid action type'
static code = 'INVALID_ACTION_TYPE'
static statusCode = 400
}
@@ -0,0 +1,37 @@
import { db } from '@/db/knex'
import { ActionTypes } from '@/modules/activitystream/helpers/types'
import { getStreamActivityFactory } from '@/modules/activitystream/repositories'
import { getActivityCountByStreamId } from '@/modules/activitystream/services'
import { Resolvers } from '@/modules/core/graph/generated/graphql'
import { InvalidActionTypeError } from '@/modules/activitystream/errors/activityStream'
import { StreamActionType } from '@/modules/activitystream/domain/types'
export = {
Stream: {
async activity(parent, args) {
if (
args.actionType &&
!Object.values(ActionTypes.Stream).includes(args.actionType as StreamActionType)
) {
throw new InvalidActionTypeError()
}
const { items, cursor } = await getStreamActivityFactory({ db })({
streamId: parent.id,
actionType: (args.actionType as StreamActionType) ?? undefined,
after: args.after ?? undefined,
before: args.before ?? undefined,
cursor: args.cursor ?? undefined,
limit: args.limit ?? undefined
})
const totalCount = await getActivityCountByStreamId({
streamId: parent.id,
actionType: args.actionType ?? undefined,
after: args.after ?? undefined,
before: args.before ?? undefined
})
return { items, cursor, totalCount }
}
}
} as Resolvers
@@ -2,11 +2,9 @@
const { md5 } = require('@/modules/shared/helpers/cryptoHelper')
const {
getUserActivity,
getStreamActivity,
getResourceActivity,
getUserTimeline,
getActivityCountByResourceId,
getActivityCountByStreamId,
getActivityCountByUserId,
getTimelineCount
} = require('../../services/index')
@@ -67,26 +65,6 @@ module.exports = {
return await userTimelineQueryCore(parent, args)
}
},
Stream: {
async activity(parent, args) {
const { items, cursor } = await getStreamActivity({
streamId: parent.id,
actionType: args.actionType,
after: args.after,
before: args.before,
cursor: args.cursor,
limit: args.limit
})
const totalCount = await getActivityCountByStreamId({
streamId: parent.id,
actionType: args.actionType,
after: args.after,
before: args.before
})
return { items, cursor, totalCount }
}
},
Branch: {
async activity(parent, args) {
@@ -0,0 +1,6 @@
import { StreamActivityRecord } from '@/modules/activitystream/helpers/types'
import { ActivityCollection } from '@/modules/core/graph/generated/graphql'
export type ActivityCollectionGraphQLReturn = Omit<ActivityCollection, 'items'> & {
items: StreamActivityRecord[]
}
@@ -1,5 +1,8 @@
import knex from '@/db/knex'
import { GetActiveUserStreams } from '@/modules/activitystream/domain/operations'
import {
GetActiveUserStreams,
GetStreamActivity
} from '@/modules/activitystream/domain/operations'
import {
StreamActivityRecord,
StreamScopeActivity
@@ -54,3 +57,25 @@ export const getActiveUserStreamsFactory =
.whereNot('server_acl.role', '=', Roles.Server.ArchivedUser)
return (await query) as Awaited<ReturnType<GetActiveUserStreams>>
}
export const getStreamActivityFactory =
({ db }: { db: Knex }): GetStreamActivity =>
async ({ streamId, actionType, after, before, cursor, limit }) => {
if (!limit) {
limit = 200
}
const dbQuery = tables.streamActivity(db).where({ streamId })
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
}
}
@@ -64,26 +64,6 @@ module.exports = {
}
},
async getStreamActivity({ streamId, actionType, after, before, cursor, limit }) {
if (!limit) {
limit = 200
}
const dbQuery = StreamActivity().where({ streamId })
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
}
},
async getUserActivity({ userId, actionType, after, before, cursor, limit }) {
if (!limit) {
limit = 200
@@ -9,6 +9,7 @@ import { WorkspaceGraphQLReturn, WorkspaceBillingGraphQLReturn, WorkspaceMutatio
import { WebhookGraphQLReturn } from '@/modules/webhooks/helpers/graphTypes';
import { SmartTextEditorValueSchema } from '@/modules/core/services/richTextEditorService';
import { BlobStorageItem } from '@/modules/blobstorage/domain/types';
import { ActivityCollectionGraphQLReturn } from '@/modules/activitystream/helpers/graphTypes';
import { GraphQLContext } from '@/modules/shared/helpers/typeHelper';
export type Maybe<T> = T | null;
export type InputMaybe<T> = Maybe<T>;
@@ -64,7 +65,7 @@ export type Activity = {
export type ActivityCollection = {
__typename?: 'ActivityCollection';
cursor?: Maybe<Scalars['String']['output']>;
items?: Maybe<Array<Maybe<Activity>>>;
items: Array<Activity>;
totalCount: Scalars['Int']['output'];
};
@@ -4172,7 +4173,6 @@ export type WorkspaceTeamFilter = {
export type WorkspaceUpdateInput = {
defaultLogoIndex?: InputMaybe<Scalars['Int']['input']>;
/** stream:reviewer | stream:contributor */
defaultProjectRole?: InputMaybe<Scalars['String']['input']>;
description?: InputMaybe<Scalars['String']['input']>;
discoverabilityEnabled?: InputMaybe<Scalars['Boolean']['input']>;
@@ -4264,7 +4264,7 @@ export type DirectiveResolverFn<TResult = {}, TParent = {}, TContext = {}, TArgs
export type ResolversTypes = {
ActiveUserMutations: ResolverTypeWrapper<MutationsObjectGraphQLReturn>;
Activity: ResolverTypeWrapper<Activity>;
ActivityCollection: ResolverTypeWrapper<ActivityCollection>;
ActivityCollection: ResolverTypeWrapper<ActivityCollectionGraphQLReturn>;
AddDomainToWorkspaceInput: AddDomainToWorkspaceInput;
AdminInviteList: ResolverTypeWrapper<Omit<AdminInviteList, 'items'> & { items: Array<ResolversTypes['ServerInvite']> }>;
AdminQueries: ResolverTypeWrapper<GraphQLEmptyReturn>;
@@ -4308,7 +4308,7 @@ export type ResolversTypes = {
BlobMetadata: ResolverTypeWrapper<BlobStorageItem>;
BlobMetadataCollection: ResolverTypeWrapper<Omit<BlobMetadataCollection, 'items'> & { items?: Maybe<Array<ResolversTypes['BlobMetadata']>> }>;
Boolean: ResolverTypeWrapper<Scalars['Boolean']['output']>;
Branch: ResolverTypeWrapper<Omit<Branch, 'author' | 'commits'> & { author?: Maybe<ResolversTypes['User']>, commits?: Maybe<ResolversTypes['CommitCollection']> }>;
Branch: ResolverTypeWrapper<Omit<Branch, 'activity' | 'author' | 'commits'> & { activity?: Maybe<ResolversTypes['ActivityCollection']>, author?: Maybe<ResolversTypes['User']>, commits?: Maybe<ResolversTypes['CommitCollection']> }>;
BranchCollection: ResolverTypeWrapper<Omit<BranchCollection, 'items'> & { items?: Maybe<Array<ResolversTypes['Branch']>> }>;
BranchCreateInput: BranchCreateInput;
BranchDeleteInput: BranchDeleteInput;
@@ -4526,7 +4526,7 @@ export type ResolversTypes = {
export type ResolversParentTypes = {
ActiveUserMutations: MutationsObjectGraphQLReturn;
Activity: Activity;
ActivityCollection: ActivityCollection;
ActivityCollection: ActivityCollectionGraphQLReturn;
AddDomainToWorkspaceInput: AddDomainToWorkspaceInput;
AdminInviteList: Omit<AdminInviteList, 'items'> & { items: Array<ResolversParentTypes['ServerInvite']> };
AdminQueries: GraphQLEmptyReturn;
@@ -4567,7 +4567,7 @@ export type ResolversParentTypes = {
BlobMetadata: BlobStorageItem;
BlobMetadataCollection: Omit<BlobMetadataCollection, 'items'> & { items?: Maybe<Array<ResolversParentTypes['BlobMetadata']>> };
Boolean: Scalars['Boolean']['output'];
Branch: Omit<Branch, 'author' | 'commits'> & { author?: Maybe<ResolversParentTypes['User']>, commits?: Maybe<ResolversParentTypes['CommitCollection']> };
Branch: Omit<Branch, 'activity' | 'author' | 'commits'> & { activity?: Maybe<ResolversParentTypes['ActivityCollection']>, author?: Maybe<ResolversParentTypes['User']>, commits?: Maybe<ResolversParentTypes['CommitCollection']> };
BranchCollection: Omit<BranchCollection, 'items'> & { items?: Maybe<Array<ResolversParentTypes['Branch']>> };
BranchCreateInput: BranchCreateInput;
BranchDeleteInput: BranchDeleteInput;
@@ -4817,7 +4817,7 @@ export type ActivityResolvers<ContextType = GraphQLContext, ParentType extends R
export type ActivityCollectionResolvers<ContextType = GraphQLContext, ParentType extends ResolversParentTypes['ActivityCollection'] = ResolversParentTypes['ActivityCollection']> = {
cursor?: Resolver<Maybe<ResolversTypes['String']>, ParentType, ContextType>;
items?: Resolver<Maybe<Array<Maybe<ResolversTypes['Activity']>>>, ParentType, ContextType>;
items?: Resolver<Array<ResolversTypes['Activity']>, ParentType, ContextType>;
totalCount?: Resolver<ResolversTypes['Int'], ParentType, ContextType>;
__isTypeOf?: IsTypeOfResolverFn<ParentType, ContextType>;
};
@@ -50,7 +50,7 @@ export type Activity = {
export type ActivityCollection = {
__typename?: 'ActivityCollection';
cursor?: Maybe<Scalars['String']['output']>;
items?: Maybe<Array<Maybe<Activity>>>;
items: Array<Activity>;
totalCount: Scalars['Int']['output'];
};
@@ -4158,7 +4158,6 @@ export type WorkspaceTeamFilter = {
export type WorkspaceUpdateInput = {
defaultLogoIndex?: InputMaybe<Scalars['Int']['input']>;
/** stream:reviewer | stream:contributor */
defaultProjectRole?: InputMaybe<Scalars['String']['input']>;
description?: InputMaybe<Scalars['String']['input']>;
discoverabilityEnabled?: InputMaybe<Scalars['Boolean']['input']>;
@@ -51,7 +51,7 @@ export type Activity = {
export type ActivityCollection = {
__typename?: 'ActivityCollection';
cursor?: Maybe<Scalars['String']['output']>;
items?: Maybe<Array<Maybe<Activity>>>;
items: Array<Activity>;
totalCount: Scalars['Int']['output'];
};
@@ -4159,7 +4159,6 @@ export type WorkspaceTeamFilter = {
export type WorkspaceUpdateInput = {
defaultLogoIndex?: InputMaybe<Scalars['Int']['input']>;
/** stream:reviewer | stream:contributor */
defaultProjectRole?: InputMaybe<Scalars['String']['input']>;
description?: InputMaybe<Scalars['String']['input']>;
discoverabilityEnabled?: InputMaybe<Scalars['Boolean']['input']>;