refactor: refactoring Team-Collections with reordering in self-host (HBE-150) (#34)
* chore: removed firebase module as a dependency from team-collection module * chore: modified team-collection resolver file to use input-args types * chore: modified getTeamOfCollection service method and resolver * chore: modified getParentOfCollection service method in team-collection module * chore: modified getChildrenOfCollection service method in team-collection module * chore: added new fields to TeamCollection model in prisma schema file * chore: modified getCollection service method and resolver in team-collection module * chore: modified createCollection service method and resolver in team-collection module * chore: created cast helper function to resolve issue with creation mutation in team-collection * chore: modified teamCollectionRemoved subscription return types * chore: removed return types from subscriptions in team-collection module * chore: removed all instances of getTeamCollections service method in team-collection module * feat: added mutation to handle moving collections and supporting subscriptions * feat: added mutation to re-ordering team-collection order * chore: added teacher comments to both collection modules * test: added test cases for getTeamOfCollection service method * test: added test cases for getParentOfCollection service method * test: added test cases for getChildrenOfCollection service method * test: added test cases for getTeamRootCollections service method * test: added test cases for getCollection service method * test: added test cases for createCollection service method * chore: renamed renameCollection to renameUserCollection in UserCollection module * test: added test cases for renameCollection service method * test: added test cases for deleteCollection service method * test: added test cases for moveCollection service method * test: added test cases for updateCollectionOrder service method * chore: added import and export to JSON mutations to team-collection module * chore: created replaceCollectionsWithJSON mutation in team-collection module * chore: moved the mutation and service method of importCollectionFromFirestore to the end of file * chore: added helper comments to all import,export functions * chore: exportCollectionsToJSON service method orders collections and requests in ascending order * chore: added test cases for importCollectionsFromJSON service method * chore: added ToDo to write test cases for exportCollectionsToJSON * chore: removed prisma migration folder * chore: completed all changes requested in inital PR review * chore: completed all changes requested in second PR review * chore: completed all changes requested in third PR review
This commit is contained in:
0
packages/hoppscotch-backend/cross-env
Normal file
0
packages/hoppscotch-backend/cross-env
Normal file
0
packages/hoppscotch-backend/eslint
Normal file
0
packages/hoppscotch-backend/eslint
Normal file
@@ -41,14 +41,17 @@ model TeamInvitation {
|
|||||||
}
|
}
|
||||||
|
|
||||||
model TeamCollection {
|
model TeamCollection {
|
||||||
id String @id @default(cuid())
|
id String @id @default(cuid())
|
||||||
parentID String?
|
parentID String?
|
||||||
parent TeamCollection? @relation("TeamCollectionChildParent", fields: [parentID], references: [id])
|
parent TeamCollection? @relation("TeamCollectionChildParent", fields: [parentID], references: [id])
|
||||||
children TeamCollection[] @relation("TeamCollectionChildParent")
|
children TeamCollection[] @relation("TeamCollectionChildParent")
|
||||||
requests TeamRequest[]
|
requests TeamRequest[]
|
||||||
teamID String
|
teamID String
|
||||||
team Team @relation(fields: [teamID], references: [id], onDelete: Cascade)
|
team Team @relation(fields: [teamID], references: [id], onDelete: Cascade)
|
||||||
title String
|
title String
|
||||||
|
orderIndex Int
|
||||||
|
createdOn DateTime @default(now()) @db.Timestamp(3)
|
||||||
|
updatedOn DateTime @updatedAt @db.Timestamp(3)
|
||||||
}
|
}
|
||||||
|
|
||||||
model TeamRequest {
|
model TeamRequest {
|
||||||
@@ -59,6 +62,9 @@ model TeamRequest {
|
|||||||
team Team @relation(fields: [teamID], references: [id], onDelete: Cascade)
|
team Team @relation(fields: [teamID], references: [id], onDelete: Cascade)
|
||||||
title String
|
title String
|
||||||
request Json
|
request Json
|
||||||
|
orderIndex Int
|
||||||
|
createdOn DateTime @default(now()) @db.Timestamp(3)
|
||||||
|
updatedOn DateTime @updatedAt @db.Timestamp(3)
|
||||||
}
|
}
|
||||||
|
|
||||||
model Shortcode {
|
model Shortcode {
|
||||||
|
|||||||
@@ -0,0 +1,5 @@
|
|||||||
|
import { Injectable } from '@nestjs/common';
|
||||||
|
import { AuthGuard } from '@nestjs/passport';
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class MultiAuthGuard extends AuthGuard(['google1', 'google2']) {}
|
||||||
@@ -54,7 +54,8 @@ export const USER_COLLECTION_NOT_FOUND = 'user_collection/not_found' as const;
|
|||||||
* Tried to reorder user request but failed
|
* Tried to reorder user request but failed
|
||||||
* (UserRequestService)
|
* (UserRequestService)
|
||||||
*/
|
*/
|
||||||
export const USER_REQUEST_CREATION_FAILED = 'user_request/creation_failed' as const;
|
export const USER_REQUEST_CREATION_FAILED =
|
||||||
|
'user_request/creation_failed' as const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tried to do an action on a user request but user request is not matched with user collection
|
* Tried to do an action on a user request but user request is not matched with user collection
|
||||||
@@ -72,7 +73,8 @@ export const USER_REQUEST_NOT_FOUND = 'user_request/not_found' as const;
|
|||||||
* Tried to reorder user request but failed
|
* Tried to reorder user request but failed
|
||||||
* (UserRequestService)
|
* (UserRequestService)
|
||||||
*/
|
*/
|
||||||
export const USER_REQUEST_REORDERING_FAILED = 'user_request/reordering_failed' as const;
|
export const USER_REQUEST_REORDERING_FAILED =
|
||||||
|
'user_request/reordering_failed' as const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tried to perform action on a team which they are not a member of
|
* Tried to perform action on a team which they are not a member of
|
||||||
@@ -104,6 +106,58 @@ export const TEAM_USER_NO_FB_SYNCDATA = 'team/user_no_fb_syncdata';
|
|||||||
*/
|
*/
|
||||||
export const TEAM_FB_COLL_PATH_RESOLVE_FAIL = 'team/fb_coll_path_resolve_fail';
|
export const TEAM_FB_COLL_PATH_RESOLVE_FAIL = 'team/fb_coll_path_resolve_fail';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Could not find the team in the database
|
||||||
|
* (TeamCollectionService)
|
||||||
|
*/
|
||||||
|
export const TEAM_COLL_NOT_FOUND = 'team_coll/collection_not_found';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Cannot make parent collection a child of a collection that a child of itself
|
||||||
|
* (TeamCollectionService)
|
||||||
|
*/
|
||||||
|
export const TEAM_COLL_IS_PARENT_COLL = 'team_coll/collection_is_parent_coll';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Target and Parent collections are not from the same team
|
||||||
|
* (TeamCollectionService)
|
||||||
|
*/
|
||||||
|
export const TEAM_COLL_NOT_SAME_TEAM = 'team_coll/collections_not_same_team';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Target and Parent collections are the same
|
||||||
|
* (TeamCollectionService)
|
||||||
|
*/
|
||||||
|
export const TEAM_COLL_DEST_SAME =
|
||||||
|
'team_coll/target_and_destination_collection_are_same';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Collection is already a root collection
|
||||||
|
* (TeamCollectionService)
|
||||||
|
*/
|
||||||
|
export const TEAM_COL_ALREADY_ROOT =
|
||||||
|
'team_coll/target_collection_is_already_root_collection';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Collections have different parents
|
||||||
|
* (TeamCollectionService)
|
||||||
|
*/
|
||||||
|
export const TEAM_COL_NOT_SAME_PARENT =
|
||||||
|
'team_coll/team_collections_have_different_parents';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Collection and next Collection are the same
|
||||||
|
* (TeamCollectionService)
|
||||||
|
*/
|
||||||
|
export const TEAM_COL_SAME_NEXT_COLL =
|
||||||
|
'team_coll/collection_and_next_collection_are_same';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Team Collection Re-Ordering Failed
|
||||||
|
* (TeamCollectionService)
|
||||||
|
*/
|
||||||
|
export const TEAM_COL_REORDERING_FAILED = 'team_coll/reordering_failed';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tried to update the team to a state it doesn't have any owners
|
* Tried to update the team to a state it doesn't have any owners
|
||||||
* (TeamService)
|
* (TeamService)
|
||||||
@@ -140,6 +194,12 @@ export const TEAM_COLL_SHORT_TITLE = 'team_coll/short_title';
|
|||||||
*/
|
*/
|
||||||
export const TEAM_COLL_INVALID_JSON = 'team_coll/invalid_json';
|
export const TEAM_COLL_INVALID_JSON = 'team_coll/invalid_json';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The Team Collection does not belong to the team
|
||||||
|
* (TeamCollectionService)
|
||||||
|
*/
|
||||||
|
export const TEAM_NOT_OWNER = 'team_coll/team_not_owner' as const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tried to perform action on a request that doesn't accept their member role level
|
* Tried to perform action on a request that doesn't accept their member role level
|
||||||
* (GqlRequestTeamMemberGuard)
|
* (GqlRequestTeamMemberGuard)
|
||||||
|
|||||||
@@ -5,7 +5,10 @@ import { UserEnvironment } from '../user-environment/user-environments.model';
|
|||||||
import { UserHistory } from '../user-history/user-history.model';
|
import { UserHistory } from '../user-history/user-history.model';
|
||||||
import { TeamMember } from 'src/team/team.model';
|
import { TeamMember } from 'src/team/team.model';
|
||||||
import { TeamEnvironment } from 'src/team-environments/team-environments.model';
|
import { TeamEnvironment } from 'src/team-environments/team-environments.model';
|
||||||
import { TeamCollection } from 'src/team-collection/team-collection.model';
|
import {
|
||||||
|
CollectionReorderData,
|
||||||
|
TeamCollection,
|
||||||
|
} from 'src/team-collection/team-collection.model';
|
||||||
import { TeamRequest } from 'src/team-request/team-request.model';
|
import { TeamRequest } from 'src/team-request/team-request.model';
|
||||||
import { TeamInvitation } from 'src/team-invitation/team-invitation.model';
|
import { TeamInvitation } from 'src/team-invitation/team-invitation.model';
|
||||||
import { UserCollection } from '@prisma/client';
|
import { UserCollection } from '@prisma/client';
|
||||||
@@ -42,11 +45,11 @@ export type TopicDef = {
|
|||||||
topic: `team_environment/${string}/${'created' | 'updated' | 'deleted'}`
|
topic: `team_environment/${string}/${'created' | 'updated' | 'deleted'}`
|
||||||
]: TeamEnvironment;
|
]: TeamEnvironment;
|
||||||
[
|
[
|
||||||
topic: `team_coll/${string}/${
|
topic: `team_coll/${string}/${'coll_added' | 'coll_updated'}`
|
||||||
| 'coll_added'
|
|
||||||
| 'coll_updated'
|
|
||||||
| 'coll_removed'}`
|
|
||||||
]: TeamCollection;
|
]: TeamCollection;
|
||||||
|
[topic: `team_coll/${string}/${'coll_removed'}`]: string;
|
||||||
|
[topic: `team_coll/${string}/${'coll_moved'}`]: TeamCollection;
|
||||||
|
[topic: `team_coll/${string}/${'coll_order_updated'}`]: CollectionReorderData;
|
||||||
[topic: `user_history/${string}/deleted_many`]: number;
|
[topic: `user_history/${string}/deleted_many`]: number;
|
||||||
[topic: `team_req/${string}/${'req_created' | 'req_updated'}`]: TeamRequest;
|
[topic: `team_req/${string}/${'req_created' | 'req_updated'}`]: TeamRequest;
|
||||||
[topic: `team_req/${string}/req_deleted`]: string;
|
[topic: `team_req/${string}/req_deleted`]: string;
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ import {
|
|||||||
TEAM_INVALID_COLL_ID,
|
TEAM_INVALID_COLL_ID,
|
||||||
TEAM_REQ_NOT_MEMBER,
|
TEAM_REQ_NOT_MEMBER,
|
||||||
} from 'src/errors';
|
} from 'src/errors';
|
||||||
|
import * as E from 'fp-ts/Either';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class GqlCollectionTeamMemberGuard implements CanActivate {
|
export class GqlCollectionTeamMemberGuard implements CanActivate {
|
||||||
@@ -29,6 +30,7 @@ export class GqlCollectionTeamMemberGuard implements CanActivate {
|
|||||||
if (!requireRoles) throw new Error(BUG_TEAM_NO_REQUIRE_TEAM_ROLE);
|
if (!requireRoles) throw new Error(BUG_TEAM_NO_REQUIRE_TEAM_ROLE);
|
||||||
|
|
||||||
const gqlExecCtx = GqlExecutionContext.create(context);
|
const gqlExecCtx = GqlExecutionContext.create(context);
|
||||||
|
|
||||||
const { user } = gqlExecCtx.getContext().req;
|
const { user } = gqlExecCtx.getContext().req;
|
||||||
if (user == undefined) throw new Error(BUG_AUTH_NO_USER_CTX);
|
if (user == undefined) throw new Error(BUG_AUTH_NO_USER_CTX);
|
||||||
|
|
||||||
@@ -38,10 +40,10 @@ export class GqlCollectionTeamMemberGuard implements CanActivate {
|
|||||||
const collection = await this.teamCollectionService.getCollection(
|
const collection = await this.teamCollectionService.getCollection(
|
||||||
collectionID,
|
collectionID,
|
||||||
);
|
);
|
||||||
if (!collection) throw new Error(TEAM_INVALID_COLL_ID);
|
if (E.isLeft(collection)) throw new Error(TEAM_INVALID_COLL_ID);
|
||||||
|
|
||||||
const member = await this.teamService.getTeamMember(
|
const member = await this.teamService.getTeamMember(
|
||||||
collection.teamID,
|
collection.right.teamID,
|
||||||
user.uid,
|
user.uid,
|
||||||
);
|
);
|
||||||
if (!member) throw new Error(TEAM_REQ_NOT_MEMBER);
|
if (!member) throw new Error(TEAM_REQ_NOT_MEMBER);
|
||||||
|
|||||||
@@ -0,0 +1,100 @@
|
|||||||
|
import { ArgsType, Field, ID } from '@nestjs/graphql';
|
||||||
|
import { PaginationArgs } from 'src/types/input-types.args';
|
||||||
|
|
||||||
|
@ArgsType()
|
||||||
|
export class GetRootTeamCollectionsArgs extends PaginationArgs {
|
||||||
|
@Field(() => ID, { name: 'teamID', description: 'ID of the team' })
|
||||||
|
teamID: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
@ArgsType()
|
||||||
|
export class CreateRootTeamCollectionArgs {
|
||||||
|
@Field(() => ID, { name: 'teamID', description: 'ID of the team' })
|
||||||
|
teamID: string;
|
||||||
|
|
||||||
|
@Field({ name: 'title', description: 'Title of the new collection' })
|
||||||
|
title: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
@ArgsType()
|
||||||
|
export class CreateChildTeamCollectionArgs {
|
||||||
|
@Field(() => ID, {
|
||||||
|
name: 'collectionID',
|
||||||
|
description: 'ID of the parent to the new collection',
|
||||||
|
})
|
||||||
|
collectionID: string;
|
||||||
|
|
||||||
|
@Field({ name: 'childTitle', description: 'Title of the new collection' })
|
||||||
|
childTitle: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
@ArgsType()
|
||||||
|
export class RenameTeamCollectionArgs {
|
||||||
|
@Field(() => ID, {
|
||||||
|
name: 'collectionID',
|
||||||
|
description: 'ID of the collection',
|
||||||
|
})
|
||||||
|
collectionID: string;
|
||||||
|
|
||||||
|
@Field({
|
||||||
|
name: 'newTitle',
|
||||||
|
description: 'The updated title of the collection',
|
||||||
|
})
|
||||||
|
newTitle: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
@ArgsType()
|
||||||
|
export class MoveTeamCollectionArgs {
|
||||||
|
@Field(() => ID, {
|
||||||
|
name: 'parentCollectionID',
|
||||||
|
description: 'ID of the parent to the new collection',
|
||||||
|
nullable: true,
|
||||||
|
})
|
||||||
|
parentCollectionID: string;
|
||||||
|
|
||||||
|
@Field(() => ID, {
|
||||||
|
name: 'collectionID',
|
||||||
|
description: 'ID of the collection',
|
||||||
|
})
|
||||||
|
collectionID: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
@ArgsType()
|
||||||
|
export class UpdateTeamCollectionOrderArgs {
|
||||||
|
@Field(() => ID, {
|
||||||
|
name: 'collectionID',
|
||||||
|
description: 'ID of the collection',
|
||||||
|
})
|
||||||
|
collectionID: string;
|
||||||
|
|
||||||
|
@Field(() => ID, {
|
||||||
|
name: 'destCollID',
|
||||||
|
description:
|
||||||
|
'ID of the collection that comes after the updated collection in its new position',
|
||||||
|
nullable: true,
|
||||||
|
})
|
||||||
|
destCollID: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
@ArgsType()
|
||||||
|
export class ReplaceTeamCollectionArgs {
|
||||||
|
@Field(() => ID, {
|
||||||
|
name: 'teamID',
|
||||||
|
description: 'Id of the team to add to',
|
||||||
|
})
|
||||||
|
teamID: string;
|
||||||
|
|
||||||
|
@Field({
|
||||||
|
name: 'jsonString',
|
||||||
|
description: 'JSON string to replace with',
|
||||||
|
})
|
||||||
|
jsonString: string;
|
||||||
|
|
||||||
|
@Field(() => ID, {
|
||||||
|
name: 'parentCollectionID',
|
||||||
|
description:
|
||||||
|
'ID to the collection to which to import to (null if to import to the root of team)',
|
||||||
|
nullable: true,
|
||||||
|
})
|
||||||
|
parentCollectionID?: string;
|
||||||
|
}
|
||||||
@@ -12,6 +12,25 @@ export class TeamCollection {
|
|||||||
})
|
})
|
||||||
title: string;
|
title: string;
|
||||||
|
|
||||||
parentID: string | null;
|
@Field(() => ID, {
|
||||||
|
description: 'ID of the collection',
|
||||||
|
nullable: true,
|
||||||
|
})
|
||||||
|
parentID: string;
|
||||||
teamID: string;
|
teamID: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ObjectType()
|
||||||
|
export class CollectionReorderData {
|
||||||
|
@Field({
|
||||||
|
description: 'Team Collection being moved',
|
||||||
|
})
|
||||||
|
collection: TeamCollection;
|
||||||
|
|
||||||
|
@Field({
|
||||||
|
description:
|
||||||
|
'Team Collection succeeding the collection being moved in its new position',
|
||||||
|
nullable: true,
|
||||||
|
})
|
||||||
|
nextCollection?: TeamCollection;
|
||||||
|
}
|
||||||
|
|||||||
@@ -5,17 +5,10 @@ import { TeamCollectionResolver } from './team-collection.resolver';
|
|||||||
import { GqlCollectionTeamMemberGuard } from './guards/gql-collection-team-member.guard';
|
import { GqlCollectionTeamMemberGuard } from './guards/gql-collection-team-member.guard';
|
||||||
import { TeamModule } from '../team/team.module';
|
import { TeamModule } from '../team/team.module';
|
||||||
import { UserModule } from '../user/user.module';
|
import { UserModule } from '../user/user.module';
|
||||||
// import { FirebaseModule } from '../firebase/firebase.module';
|
|
||||||
import { PubSubModule } from '../pubsub/pubsub.module';
|
import { PubSubModule } from '../pubsub/pubsub.module';
|
||||||
|
|
||||||
@Module({
|
@Module({
|
||||||
imports: [
|
imports: [PrismaModule, TeamModule, UserModule, PubSubModule],
|
||||||
PrismaModule,
|
|
||||||
// FirebaseModule,
|
|
||||||
TeamModule,
|
|
||||||
UserModule,
|
|
||||||
PubSubModule,
|
|
||||||
],
|
|
||||||
providers: [
|
providers: [
|
||||||
TeamCollectionService,
|
TeamCollectionService,
|
||||||
TeamCollectionResolver,
|
TeamCollectionResolver,
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import {
|
|||||||
Subscription,
|
Subscription,
|
||||||
ID,
|
ID,
|
||||||
} from '@nestjs/graphql';
|
} from '@nestjs/graphql';
|
||||||
import { TeamCollection } from './team-collection.model';
|
import { CollectionReorderData, TeamCollection } from './team-collection.model';
|
||||||
import { Team, TeamMemberRole } from '../team/team.model';
|
import { Team, TeamMemberRole } from '../team/team.model';
|
||||||
import { TeamCollectionService } from './team-collection.service';
|
import { TeamCollectionService } from './team-collection.service';
|
||||||
import { GqlAuthGuard } from '../guards/gql-auth.guard';
|
import { GqlAuthGuard } from '../guards/gql-auth.guard';
|
||||||
@@ -17,6 +17,18 @@ import { UseGuards } from '@nestjs/common';
|
|||||||
import { RequiresTeamRole } from '../team/decorators/requires-team-role.decorator';
|
import { RequiresTeamRole } from '../team/decorators/requires-team-role.decorator';
|
||||||
import { GqlCollectionTeamMemberGuard } from './guards/gql-collection-team-member.guard';
|
import { GqlCollectionTeamMemberGuard } from './guards/gql-collection-team-member.guard';
|
||||||
import { PubSubService } from 'src/pubsub/pubsub.service';
|
import { PubSubService } from 'src/pubsub/pubsub.service';
|
||||||
|
import { PaginationArgs } from 'src/types/input-types.args';
|
||||||
|
import {
|
||||||
|
CreateChildTeamCollectionArgs,
|
||||||
|
CreateRootTeamCollectionArgs,
|
||||||
|
GetRootTeamCollectionsArgs,
|
||||||
|
MoveTeamCollectionArgs,
|
||||||
|
RenameTeamCollectionArgs,
|
||||||
|
ReplaceTeamCollectionArgs,
|
||||||
|
UpdateTeamCollectionOrderArgs,
|
||||||
|
} from './input-type.args';
|
||||||
|
import * as E from 'fp-ts/Either';
|
||||||
|
import { throwErr } from 'src/utils';
|
||||||
|
|
||||||
@Resolver(() => TeamCollection)
|
@Resolver(() => TeamCollection)
|
||||||
export class TeamCollectionResolver {
|
export class TeamCollectionResolver {
|
||||||
@@ -30,58 +42,43 @@ export class TeamCollectionResolver {
|
|||||||
description: 'Team the collection belongs to',
|
description: 'Team the collection belongs to',
|
||||||
complexity: 5,
|
complexity: 5,
|
||||||
})
|
})
|
||||||
team(@Parent() collection: TeamCollection): Promise<Team> {
|
async team(@Parent() collection: TeamCollection) {
|
||||||
return this.teamCollectionService.getTeamOfCollection(collection.id);
|
const team = await this.teamCollectionService.getTeamOfCollection(
|
||||||
|
collection.id,
|
||||||
|
);
|
||||||
|
if (E.isLeft(team)) throwErr(team.left);
|
||||||
|
return team.right;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ResolveField(() => TeamCollection, {
|
@ResolveField(() => TeamCollection, {
|
||||||
description:
|
description: 'Return the parent Team Collection (null if root )',
|
||||||
'The collection who is the parent of this collection (null if this is root collection)',
|
|
||||||
nullable: true,
|
nullable: true,
|
||||||
complexity: 3,
|
complexity: 3,
|
||||||
})
|
})
|
||||||
parent(@Parent() collection: TeamCollection): Promise<TeamCollection | null> {
|
async parent(@Parent() collection: TeamCollection) {
|
||||||
return this.teamCollectionService.getParentOfCollection(collection.id);
|
return this.teamCollectionService.getParentOfCollection(collection.id);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ResolveField(() => [TeamCollection], {
|
@ResolveField(() => [TeamCollection], {
|
||||||
description: 'List of children collection',
|
description: 'List of children Team Collections',
|
||||||
complexity: 3,
|
complexity: 3,
|
||||||
})
|
})
|
||||||
children(
|
async children(
|
||||||
@Parent() collection: TeamCollection,
|
@Parent() collection: TeamCollection,
|
||||||
@Args({
|
@Args() args: PaginationArgs,
|
||||||
name: 'cursor',
|
) {
|
||||||
nullable: true,
|
|
||||||
description: 'ID of the last returned collection (for pagination)',
|
|
||||||
})
|
|
||||||
cursor?: string,
|
|
||||||
): Promise<TeamCollection[]> {
|
|
||||||
return this.teamCollectionService.getChildrenOfCollection(
|
return this.teamCollectionService.getChildrenOfCollection(
|
||||||
collection.id,
|
collection.id,
|
||||||
cursor ?? null,
|
args.cursor,
|
||||||
|
args.take,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Queries
|
// Queries
|
||||||
// @Query(() => String, {
|
|
||||||
// description:
|
|
||||||
// 'Returns the JSON string giving the collections and their contents of the team',
|
|
||||||
// })
|
|
||||||
// @UseGuards(GqlAuthGuard, GqlTeamMemberGuard)
|
|
||||||
// @RequiresTeamRole(
|
|
||||||
// TeamMemberRole.VIEWER,
|
|
||||||
// TeamMemberRole.EDITOR,
|
|
||||||
// TeamMemberRole.OWNER,
|
|
||||||
// )
|
|
||||||
// exportCollectionsToJSON(
|
|
||||||
// @Args({ name: 'teamID', description: 'ID of the team', type: () => ID }) teamID: string,
|
|
||||||
// ): Promise<string> {
|
|
||||||
// return this.teamCollectionService.exportCollectionsToJSON(teamID);
|
|
||||||
// }
|
|
||||||
|
|
||||||
@Query(() => [TeamCollection], {
|
@Query(() => String, {
|
||||||
description: 'Returns the collections of the team',
|
description:
|
||||||
|
'Returns the JSON string giving the collections and their contents of the team',
|
||||||
})
|
})
|
||||||
@UseGuards(GqlAuthGuard, GqlTeamMemberGuard)
|
@UseGuards(GqlAuthGuard, GqlTeamMemberGuard)
|
||||||
@RequiresTeamRole(
|
@RequiresTeamRole(
|
||||||
@@ -89,27 +86,20 @@ export class TeamCollectionResolver {
|
|||||||
TeamMemberRole.EDITOR,
|
TeamMemberRole.EDITOR,
|
||||||
TeamMemberRole.OWNER,
|
TeamMemberRole.OWNER,
|
||||||
)
|
)
|
||||||
rootCollectionsOfTeam(
|
async exportCollectionsToJSON(
|
||||||
@Args({ name: 'teamID', description: 'ID of the team', type: () => ID })
|
@Args({ name: 'teamID', description: 'ID of the team', type: () => ID })
|
||||||
teamID: string,
|
teamID: string,
|
||||||
@Args({
|
) {
|
||||||
name: 'cursor',
|
const jsonString = await this.teamCollectionService.exportCollectionsToJSON(
|
||||||
nullable: true,
|
|
||||||
type: () => ID,
|
|
||||||
description: 'ID of the last returned collection (for pagination)',
|
|
||||||
})
|
|
||||||
cursor?: string,
|
|
||||||
): Promise<TeamCollection[]> {
|
|
||||||
return this.teamCollectionService.getTeamRootCollections(
|
|
||||||
teamID,
|
teamID,
|
||||||
cursor ?? null,
|
|
||||||
);
|
);
|
||||||
|
|
||||||
|
if (E.isLeft(jsonString)) throwErr(jsonString.left as string);
|
||||||
|
return jsonString.right;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Query(() => [TeamCollection], {
|
@Query(() => [TeamCollection], {
|
||||||
description: 'Returns the collections of the team',
|
description: 'Returns the collections of a team',
|
||||||
deprecationReason:
|
|
||||||
'Deprecated because of no practical use. Use `rootCollectionsOfTeam` instead.',
|
|
||||||
})
|
})
|
||||||
@UseGuards(GqlAuthGuard, GqlTeamMemberGuard)
|
@UseGuards(GqlAuthGuard, GqlTeamMemberGuard)
|
||||||
@RequiresTeamRole(
|
@RequiresTeamRole(
|
||||||
@@ -117,25 +107,16 @@ export class TeamCollectionResolver {
|
|||||||
TeamMemberRole.EDITOR,
|
TeamMemberRole.EDITOR,
|
||||||
TeamMemberRole.OWNER,
|
TeamMemberRole.OWNER,
|
||||||
)
|
)
|
||||||
collectionsOfTeam(
|
async rootCollectionsOfTeam(@Args() args: GetRootTeamCollectionsArgs) {
|
||||||
@Args({ name: 'teamID', description: 'ID of the team', type: () => ID })
|
return this.teamCollectionService.getTeamRootCollections(
|
||||||
teamID: string,
|
args.teamID,
|
||||||
@Args({
|
args.cursor,
|
||||||
name: 'cursor',
|
args.take,
|
||||||
type: () => ID,
|
|
||||||
nullable: true,
|
|
||||||
description: 'ID of the last returned collection (for pagination)',
|
|
||||||
})
|
|
||||||
cursor?: string,
|
|
||||||
): Promise<TeamCollection[]> {
|
|
||||||
return this.teamCollectionService.getTeamCollections(
|
|
||||||
teamID,
|
|
||||||
cursor ?? null,
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Query(() => TeamCollection, {
|
@Query(() => TeamCollection, {
|
||||||
description: 'Get a collection with the given ID or null (if not exists)',
|
description: 'Get a Team Collection with ID or null (if not exists)',
|
||||||
nullable: true,
|
nullable: true,
|
||||||
})
|
})
|
||||||
@UseGuards(GqlAuthGuard, GqlCollectionTeamMemberGuard)
|
@UseGuards(GqlAuthGuard, GqlCollectionTeamMemberGuard)
|
||||||
@@ -144,15 +125,20 @@ export class TeamCollectionResolver {
|
|||||||
TeamMemberRole.EDITOR,
|
TeamMemberRole.EDITOR,
|
||||||
TeamMemberRole.OWNER,
|
TeamMemberRole.OWNER,
|
||||||
)
|
)
|
||||||
collection(
|
async collection(
|
||||||
@Args({
|
@Args({
|
||||||
name: 'collectionID',
|
name: 'collectionID',
|
||||||
description: 'ID of the collection',
|
description: 'ID of the collection',
|
||||||
type: () => ID,
|
type: () => ID,
|
||||||
})
|
})
|
||||||
collectionID: string,
|
collectionID: string,
|
||||||
): Promise<TeamCollection | null> {
|
) {
|
||||||
return this.teamCollectionService.getCollection(collectionID);
|
const teamCollections = await this.teamCollectionService.getCollection(
|
||||||
|
collectionID,
|
||||||
|
);
|
||||||
|
|
||||||
|
if (E.isLeft(teamCollections)) throwErr(teamCollections.left);
|
||||||
|
return teamCollections.right;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Mutations
|
// Mutations
|
||||||
@@ -162,13 +148,264 @@ export class TeamCollectionResolver {
|
|||||||
})
|
})
|
||||||
@UseGuards(GqlAuthGuard, GqlTeamMemberGuard)
|
@UseGuards(GqlAuthGuard, GqlTeamMemberGuard)
|
||||||
@RequiresTeamRole(TeamMemberRole.OWNER, TeamMemberRole.EDITOR)
|
@RequiresTeamRole(TeamMemberRole.OWNER, TeamMemberRole.EDITOR)
|
||||||
createRootCollection(
|
async createRootCollection(@Args() args: CreateRootTeamCollectionArgs) {
|
||||||
@Args({ name: 'teamID', description: 'ID of the team', type: () => ID })
|
const teamCollection = await this.teamCollectionService.createCollection(
|
||||||
|
args.teamID,
|
||||||
|
args.title,
|
||||||
|
null,
|
||||||
|
);
|
||||||
|
|
||||||
|
if (E.isLeft(teamCollection)) throwErr(teamCollection.left);
|
||||||
|
return teamCollection.right;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Mutation(() => Boolean, {
|
||||||
|
description: 'Import collections from JSON string to the specified Team',
|
||||||
|
})
|
||||||
|
@UseGuards(GqlAuthGuard, GqlTeamMemberGuard)
|
||||||
|
@RequiresTeamRole(TeamMemberRole.OWNER, TeamMemberRole.EDITOR)
|
||||||
|
async importCollectionsFromJSON(
|
||||||
|
@Args({
|
||||||
|
name: 'teamID',
|
||||||
|
type: () => ID,
|
||||||
|
description: 'Id of the team to add to',
|
||||||
|
})
|
||||||
teamID: string,
|
teamID: string,
|
||||||
@Args({ name: 'title', description: 'Title of the new collection' })
|
@Args({
|
||||||
title: string,
|
name: 'jsonString',
|
||||||
): Promise<TeamCollection> {
|
description: 'JSON string to import',
|
||||||
return this.teamCollectionService.createCollection(teamID, title, null);
|
})
|
||||||
|
jsonString: string,
|
||||||
|
@Args({
|
||||||
|
name: 'parentCollectionID',
|
||||||
|
type: () => ID,
|
||||||
|
description:
|
||||||
|
'ID to the collection to which to import to (null if to import to the root of team)',
|
||||||
|
nullable: true,
|
||||||
|
})
|
||||||
|
parentCollectionID?: string,
|
||||||
|
): Promise<boolean> {
|
||||||
|
const importedCollection =
|
||||||
|
await this.teamCollectionService.importCollectionsFromJSON(
|
||||||
|
jsonString,
|
||||||
|
teamID,
|
||||||
|
parentCollectionID ?? null,
|
||||||
|
);
|
||||||
|
if (E.isLeft(importedCollection)) throwErr(importedCollection.left);
|
||||||
|
return importedCollection.right;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Mutation(() => Boolean, {
|
||||||
|
description:
|
||||||
|
'Replace existing collections of a specific team with collections in JSON string',
|
||||||
|
})
|
||||||
|
@UseGuards(GqlAuthGuard, GqlTeamMemberGuard)
|
||||||
|
@RequiresTeamRole(TeamMemberRole.OWNER, TeamMemberRole.EDITOR)
|
||||||
|
async replaceCollectionsWithJSON(@Args() args: ReplaceTeamCollectionArgs) {
|
||||||
|
const teamCollection =
|
||||||
|
await this.teamCollectionService.replaceCollectionsWithJSON(
|
||||||
|
args.jsonString,
|
||||||
|
args.teamID,
|
||||||
|
args.parentCollectionID ?? null,
|
||||||
|
);
|
||||||
|
|
||||||
|
if (E.isLeft(teamCollection)) throwErr(teamCollection.left);
|
||||||
|
return teamCollection.right;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Mutation(() => TeamCollection, {
|
||||||
|
description: 'Create a collection that has a parent collection',
|
||||||
|
})
|
||||||
|
@UseGuards(GqlAuthGuard, GqlCollectionTeamMemberGuard)
|
||||||
|
@RequiresTeamRole(TeamMemberRole.OWNER, TeamMemberRole.EDITOR)
|
||||||
|
async createChildCollection(@Args() args: CreateChildTeamCollectionArgs) {
|
||||||
|
const team = await this.teamCollectionService.getTeamOfCollection(
|
||||||
|
args.collectionID,
|
||||||
|
);
|
||||||
|
if (E.isLeft(team)) throwErr(team.left);
|
||||||
|
|
||||||
|
const teamCollection = await this.teamCollectionService.createCollection(
|
||||||
|
team.right.id,
|
||||||
|
args.childTitle,
|
||||||
|
args.collectionID,
|
||||||
|
);
|
||||||
|
|
||||||
|
if (E.isLeft(teamCollection)) throwErr(teamCollection.left);
|
||||||
|
return teamCollection.right;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Mutation(() => TeamCollection, {
|
||||||
|
description: 'Rename a collection',
|
||||||
|
})
|
||||||
|
@UseGuards(GqlAuthGuard, GqlCollectionTeamMemberGuard)
|
||||||
|
@RequiresTeamRole(TeamMemberRole.OWNER, TeamMemberRole.EDITOR)
|
||||||
|
async renameCollection(@Args() args: RenameTeamCollectionArgs) {
|
||||||
|
const updatedTeamCollection =
|
||||||
|
await this.teamCollectionService.renameCollection(
|
||||||
|
args.collectionID,
|
||||||
|
args.newTitle,
|
||||||
|
);
|
||||||
|
|
||||||
|
if (E.isLeft(updatedTeamCollection)) throwErr(updatedTeamCollection.left);
|
||||||
|
return updatedTeamCollection.right;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Mutation(() => Boolean, {
|
||||||
|
description: 'Delete a collection',
|
||||||
|
})
|
||||||
|
@UseGuards(GqlAuthGuard, GqlCollectionTeamMemberGuard)
|
||||||
|
@RequiresTeamRole(TeamMemberRole.OWNER, TeamMemberRole.EDITOR)
|
||||||
|
async deleteCollection(
|
||||||
|
@Args({
|
||||||
|
name: 'collectionID',
|
||||||
|
description: 'ID of the collection',
|
||||||
|
type: () => ID,
|
||||||
|
})
|
||||||
|
collectionID: string,
|
||||||
|
) {
|
||||||
|
const result = await this.teamCollectionService.deleteCollection(
|
||||||
|
collectionID,
|
||||||
|
);
|
||||||
|
|
||||||
|
if (E.isLeft(result)) throwErr(result.left);
|
||||||
|
return result.right;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Mutation(() => TeamCollection, {
|
||||||
|
description:
|
||||||
|
'Move a collection into a new parent collection or the root of the team',
|
||||||
|
})
|
||||||
|
@UseGuards(GqlAuthGuard, GqlCollectionTeamMemberGuard)
|
||||||
|
@RequiresTeamRole(TeamMemberRole.OWNER, TeamMemberRole.EDITOR)
|
||||||
|
async moveCollection(@Args() args: MoveTeamCollectionArgs) {
|
||||||
|
const res = await this.teamCollectionService.moveCollection(
|
||||||
|
args.collectionID,
|
||||||
|
args.parentCollectionID,
|
||||||
|
);
|
||||||
|
if (E.isLeft(res)) throwErr(res.left);
|
||||||
|
return res.right;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Mutation(() => Boolean, {
|
||||||
|
description: 'Update the order of collections',
|
||||||
|
})
|
||||||
|
@UseGuards(GqlAuthGuard, GqlCollectionTeamMemberGuard)
|
||||||
|
@RequiresTeamRole(TeamMemberRole.OWNER, TeamMemberRole.EDITOR)
|
||||||
|
async updateCollectionOrder(@Args() args: UpdateTeamCollectionOrderArgs) {
|
||||||
|
const request = await this.teamCollectionService.updateCollectionOrder(
|
||||||
|
args.collectionID,
|
||||||
|
args.destCollID,
|
||||||
|
);
|
||||||
|
if (E.isLeft(request)) throwErr(request.left);
|
||||||
|
return request.right;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Subscriptions
|
||||||
|
|
||||||
|
@Subscription(() => TeamCollection, {
|
||||||
|
description:
|
||||||
|
'Listen to when a collection has been added to a team. The emitted value is the team added',
|
||||||
|
resolve: (value) => value,
|
||||||
|
})
|
||||||
|
@RequiresTeamRole(
|
||||||
|
TeamMemberRole.OWNER,
|
||||||
|
TeamMemberRole.EDITOR,
|
||||||
|
TeamMemberRole.VIEWER,
|
||||||
|
)
|
||||||
|
@UseGuards(GqlAuthGuard, GqlTeamMemberGuard)
|
||||||
|
teamCollectionAdded(
|
||||||
|
@Args({
|
||||||
|
name: 'teamID',
|
||||||
|
description: 'ID of the team to listen to',
|
||||||
|
type: () => ID,
|
||||||
|
})
|
||||||
|
teamID: string,
|
||||||
|
) {
|
||||||
|
return this.pubsub.asyncIterator(`team_coll/${teamID}/coll_added`);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Subscription(() => TeamCollection, {
|
||||||
|
description: 'Listen to when a collection has been updated.',
|
||||||
|
resolve: (value) => value,
|
||||||
|
})
|
||||||
|
@RequiresTeamRole(
|
||||||
|
TeamMemberRole.OWNER,
|
||||||
|
TeamMemberRole.EDITOR,
|
||||||
|
TeamMemberRole.VIEWER,
|
||||||
|
)
|
||||||
|
@UseGuards(GqlAuthGuard, GqlTeamMemberGuard)
|
||||||
|
teamCollectionUpdated(
|
||||||
|
@Args({
|
||||||
|
name: 'teamID',
|
||||||
|
description: 'ID of the team to listen to',
|
||||||
|
type: () => ID,
|
||||||
|
})
|
||||||
|
teamID: string,
|
||||||
|
) {
|
||||||
|
return this.pubsub.asyncIterator(`team_coll/${teamID}/coll_updated`);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Subscription(() => ID, {
|
||||||
|
description: 'Listen to when a collection has been removed',
|
||||||
|
resolve: (value) => value,
|
||||||
|
})
|
||||||
|
@RequiresTeamRole(
|
||||||
|
TeamMemberRole.OWNER,
|
||||||
|
TeamMemberRole.EDITOR,
|
||||||
|
TeamMemberRole.VIEWER,
|
||||||
|
)
|
||||||
|
@UseGuards(GqlAuthGuard, GqlTeamMemberGuard)
|
||||||
|
teamCollectionRemoved(
|
||||||
|
@Args({
|
||||||
|
name: 'teamID',
|
||||||
|
description: 'ID of the team to listen to',
|
||||||
|
type: () => ID,
|
||||||
|
})
|
||||||
|
teamID: string,
|
||||||
|
) {
|
||||||
|
return this.pubsub.asyncIterator(`team_coll/${teamID}/coll_removed`);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Subscription(() => TeamCollection, {
|
||||||
|
description: 'Listen to when a collection has been moved',
|
||||||
|
resolve: (value) => value,
|
||||||
|
})
|
||||||
|
@RequiresTeamRole(
|
||||||
|
TeamMemberRole.OWNER,
|
||||||
|
TeamMemberRole.EDITOR,
|
||||||
|
TeamMemberRole.VIEWER,
|
||||||
|
)
|
||||||
|
@UseGuards(GqlAuthGuard, GqlTeamMemberGuard)
|
||||||
|
teamCollectionMoved(
|
||||||
|
@Args({
|
||||||
|
name: 'teamID',
|
||||||
|
description: 'ID of the team to listen to',
|
||||||
|
type: () => ID,
|
||||||
|
})
|
||||||
|
teamID: string,
|
||||||
|
) {
|
||||||
|
return this.pubsub.asyncIterator(`team_coll/${teamID}/coll_moved`);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Subscription(() => CollectionReorderData, {
|
||||||
|
description: 'Listen to when a collections position has changed',
|
||||||
|
resolve: (value) => value,
|
||||||
|
})
|
||||||
|
@RequiresTeamRole(
|
||||||
|
TeamMemberRole.OWNER,
|
||||||
|
TeamMemberRole.EDITOR,
|
||||||
|
TeamMemberRole.VIEWER,
|
||||||
|
)
|
||||||
|
@UseGuards(GqlAuthGuard, GqlTeamMemberGuard)
|
||||||
|
collectionOrderUpdated(
|
||||||
|
@Args({
|
||||||
|
name: 'teamID',
|
||||||
|
description: 'ID of the team to listen to',
|
||||||
|
type: () => ID,
|
||||||
|
})
|
||||||
|
teamID: string,
|
||||||
|
) {
|
||||||
|
return this.pubsub.asyncIterator(`team_coll/${teamID}/coll_order_updated`);
|
||||||
}
|
}
|
||||||
|
|
||||||
// @Mutation(() => TeamCollection, {
|
// @Mutation(() => TeamCollection, {
|
||||||
@@ -214,204 +451,4 @@ export class TeamCollectionResolver {
|
|||||||
// );
|
// );
|
||||||
// }
|
// }
|
||||||
// }
|
// }
|
||||||
|
|
||||||
// @Mutation(() => Boolean, {
|
|
||||||
// description: 'Import collections from JSON string to the specified Team',
|
|
||||||
// })
|
|
||||||
// @UseGuards(GqlAuthGuard, GqlTeamMemberGuard)
|
|
||||||
// @RequiresTeamRole(TeamMemberRole.OWNER, TeamMemberRole.EDITOR)
|
|
||||||
// async importCollectionsFromJSON(
|
|
||||||
// @Args({
|
|
||||||
// name: 'teamID',
|
|
||||||
// type: () => ID,
|
|
||||||
// description: 'Id of the team to add to',
|
|
||||||
// })
|
|
||||||
// teamID: string,
|
|
||||||
// @Args({
|
|
||||||
// name: 'jsonString',
|
|
||||||
// description: 'JSON string to import',
|
|
||||||
// })
|
|
||||||
// jsonString: string,
|
|
||||||
// @Args({
|
|
||||||
// name: 'parentCollectionID',
|
|
||||||
// type: () => ID,
|
|
||||||
// description:
|
|
||||||
// 'ID to the collection to which to import to (null if to import to the root of team)',
|
|
||||||
// nullable: true,
|
|
||||||
// })
|
|
||||||
// parentCollectionID?: string,
|
|
||||||
// ): Promise<boolean> {
|
|
||||||
// await this.teamCollectionService.importCollectionsFromJSON(
|
|
||||||
// jsonString,
|
|
||||||
// teamID,
|
|
||||||
// parentCollectionID ?? null,
|
|
||||||
// );
|
|
||||||
|
|
||||||
// return true;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// @Mutation(() => Boolean, {
|
|
||||||
// description:
|
|
||||||
// 'Replace existing collections of a specific team with collections in JSON string',
|
|
||||||
// })
|
|
||||||
// @UseGuards(GqlAuthGuard, GqlTeamMemberGuard)
|
|
||||||
// @RequiresTeamRole(TeamMemberRole.OWNER, TeamMemberRole.EDITOR)
|
|
||||||
// async replaceCollectionsWithJSON(
|
|
||||||
// @Args({
|
|
||||||
// name: 'teamID',
|
|
||||||
// type: () => ID,
|
|
||||||
// description: 'Id of the team to add to',
|
|
||||||
// })
|
|
||||||
// teamID: string,
|
|
||||||
// @Args({
|
|
||||||
// name: 'jsonString',
|
|
||||||
// description: 'JSON string to replace with',
|
|
||||||
// })
|
|
||||||
// jsonString: string,
|
|
||||||
// @Args({
|
|
||||||
// name: 'parentCollectionID',
|
|
||||||
// type: () => ID,
|
|
||||||
// description:
|
|
||||||
// 'ID to the collection to which to import to (null if to import to the root of team)',
|
|
||||||
// nullable: true,
|
|
||||||
// })
|
|
||||||
// parentCollectionID?: string,
|
|
||||||
// ): Promise<boolean> {
|
|
||||||
// await this.teamCollectionService.replaceCollectionsWithJSON(
|
|
||||||
// jsonString,
|
|
||||||
// teamID,
|
|
||||||
// parentCollectionID ?? null,
|
|
||||||
// );
|
|
||||||
|
|
||||||
// return true;
|
|
||||||
// }
|
|
||||||
|
|
||||||
@Mutation(() => TeamCollection, {
|
|
||||||
description: 'Create a collection that has a parent collection',
|
|
||||||
})
|
|
||||||
@UseGuards(GqlAuthGuard, GqlCollectionTeamMemberGuard)
|
|
||||||
@RequiresTeamRole(TeamMemberRole.OWNER, TeamMemberRole.EDITOR)
|
|
||||||
async createChildCollection(
|
|
||||||
@Args({
|
|
||||||
name: 'collectionID',
|
|
||||||
type: () => ID,
|
|
||||||
description: 'ID of the parent to the new collection',
|
|
||||||
})
|
|
||||||
collectionID: string,
|
|
||||||
@Args({ name: 'childTitle', description: 'Title of the new collection' })
|
|
||||||
childTitle: string,
|
|
||||||
): Promise<TeamCollection> {
|
|
||||||
const team = await this.teamCollectionService.getTeamOfCollection(
|
|
||||||
collectionID,
|
|
||||||
);
|
|
||||||
return await this.teamCollectionService.createCollection(
|
|
||||||
team.id,
|
|
||||||
childTitle,
|
|
||||||
collectionID,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Mutation(() => TeamCollection, {
|
|
||||||
description: 'Rename a collection',
|
|
||||||
})
|
|
||||||
@UseGuards(GqlAuthGuard, GqlCollectionTeamMemberGuard)
|
|
||||||
@RequiresTeamRole(TeamMemberRole.OWNER, TeamMemberRole.EDITOR)
|
|
||||||
renameCollection(
|
|
||||||
@Args({
|
|
||||||
name: 'collectionID',
|
|
||||||
description: 'ID of the collection',
|
|
||||||
type: () => ID,
|
|
||||||
})
|
|
||||||
collectionID: string,
|
|
||||||
@Args({
|
|
||||||
name: 'newTitle',
|
|
||||||
description: 'The updated title of the collection',
|
|
||||||
})
|
|
||||||
newTitle: string,
|
|
||||||
): Promise<TeamCollection> {
|
|
||||||
return this.teamCollectionService.renameCollection(collectionID, newTitle);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Mutation(() => Boolean, {
|
|
||||||
description: 'Delete a collection',
|
|
||||||
})
|
|
||||||
@UseGuards(GqlAuthGuard, GqlCollectionTeamMemberGuard)
|
|
||||||
@RequiresTeamRole(TeamMemberRole.OWNER, TeamMemberRole.EDITOR)
|
|
||||||
async deleteCollection(
|
|
||||||
@Args({
|
|
||||||
name: 'collectionID',
|
|
||||||
description: 'ID of the collection',
|
|
||||||
type: () => ID,
|
|
||||||
})
|
|
||||||
collectionID: string,
|
|
||||||
): Promise<boolean> {
|
|
||||||
this.teamCollectionService.deleteCollection(collectionID);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Subscriptions
|
|
||||||
@Subscription(() => TeamCollection, {
|
|
||||||
description:
|
|
||||||
'Listen to when a collection has been added to a team. The emitted value is the team added',
|
|
||||||
resolve: (value) => value,
|
|
||||||
})
|
|
||||||
@RequiresTeamRole(
|
|
||||||
TeamMemberRole.OWNER,
|
|
||||||
TeamMemberRole.EDITOR,
|
|
||||||
TeamMemberRole.VIEWER,
|
|
||||||
)
|
|
||||||
@UseGuards(GqlAuthGuard, GqlTeamMemberGuard)
|
|
||||||
teamCollectionAdded(
|
|
||||||
@Args({
|
|
||||||
name: 'teamID',
|
|
||||||
description: 'ID of the team to listen to',
|
|
||||||
type: () => ID,
|
|
||||||
})
|
|
||||||
teamID: string,
|
|
||||||
): AsyncIterator<TeamCollection> {
|
|
||||||
return this.pubsub.asyncIterator(`team_coll/${teamID}/coll_added`);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Subscription(() => TeamCollection, {
|
|
||||||
description: 'Listen to when a collection has been updated.',
|
|
||||||
resolve: (value) => value,
|
|
||||||
})
|
|
||||||
@RequiresTeamRole(
|
|
||||||
TeamMemberRole.OWNER,
|
|
||||||
TeamMemberRole.EDITOR,
|
|
||||||
TeamMemberRole.VIEWER,
|
|
||||||
)
|
|
||||||
@UseGuards(GqlAuthGuard, GqlTeamMemberGuard)
|
|
||||||
teamCollectionUpdated(
|
|
||||||
@Args({
|
|
||||||
name: 'teamID',
|
|
||||||
description: 'ID of the team to listen to',
|
|
||||||
type: () => ID,
|
|
||||||
})
|
|
||||||
teamID: string,
|
|
||||||
): AsyncIterator<TeamCollection> {
|
|
||||||
return this.pubsub.asyncIterator(`team_coll/${teamID}/coll_updated`);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Subscription(() => ID, {
|
|
||||||
description: 'Listen to when a collection has been removed',
|
|
||||||
resolve: (value) => value,
|
|
||||||
})
|
|
||||||
@RequiresTeamRole(
|
|
||||||
TeamMemberRole.OWNER,
|
|
||||||
TeamMemberRole.EDITOR,
|
|
||||||
TeamMemberRole.VIEWER,
|
|
||||||
)
|
|
||||||
@UseGuards(GqlAuthGuard, GqlTeamMemberGuard)
|
|
||||||
teamCollectionRemoved(
|
|
||||||
@Args({
|
|
||||||
name: 'teamID',
|
|
||||||
description: 'ID of the team to listen to',
|
|
||||||
type: () => ID,
|
|
||||||
})
|
|
||||||
teamID: string,
|
|
||||||
): AsyncIterator<TeamCollection> {
|
|
||||||
return this.pubsub.asyncIterator(`team_coll/${teamID}/coll_removed`);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -43,13 +43,13 @@ export class TeamRequestResolver {
|
|||||||
return this.teamRequestService.getTeamOfRequest(req);
|
return this.teamRequestService.getTeamOfRequest(req);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ResolveField(() => TeamCollection, {
|
// @ResolveField(() => TeamCollection, {
|
||||||
description: 'Collection the request belongs to',
|
// description: 'Collection the request belongs to',
|
||||||
complexity: 3,
|
// complexity: 3,
|
||||||
})
|
// })
|
||||||
collection(@Parent() req: TeamRequest): Promise<TeamCollection> {
|
// collection(@Parent() req: TeamRequest): Promise<TeamCollection> {
|
||||||
return this.teamRequestService.getCollectionOfRequest(req);
|
// return this.teamRequestService.getCollectionOfRequest(req);
|
||||||
}
|
// }
|
||||||
|
|
||||||
// Query
|
// Query
|
||||||
@Query(() => [TeamRequest], {
|
@Query(() => [TeamRequest], {
|
||||||
@@ -126,29 +126,29 @@ export class TeamRequestResolver {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Mutation
|
// // Mutation
|
||||||
@Mutation(() => TeamRequest, {
|
// @Mutation(() => TeamRequest, {
|
||||||
description: 'Create a request in the given collection.',
|
// description: 'Create a request in the given collection.',
|
||||||
})
|
// })
|
||||||
@UseGuards(GqlAuthGuard, GqlCollectionTeamMemberGuard)
|
// @UseGuards(GqlAuthGuard, GqlCollectionTeamMemberGuard)
|
||||||
@RequiresTeamRole(TeamMemberRole.EDITOR, TeamMemberRole.OWNER)
|
// @RequiresTeamRole(TeamMemberRole.EDITOR, TeamMemberRole.OWNER)
|
||||||
createRequestInCollection(
|
// createRequestInCollection(
|
||||||
@Args({
|
// @Args({
|
||||||
name: 'collectionID',
|
// name: 'collectionID',
|
||||||
description: 'ID of the collection',
|
// description: 'ID of the collection',
|
||||||
type: () => ID,
|
// type: () => ID,
|
||||||
})
|
// })
|
||||||
collectionID: string,
|
// collectionID: string,
|
||||||
@Args({
|
// @Args({
|
||||||
name: 'data',
|
// name: 'data',
|
||||||
type: () => CreateTeamRequestInput,
|
// type: () => CreateTeamRequestInput,
|
||||||
description:
|
// description:
|
||||||
'The request data (stringified JSON of Hoppscotch request object)',
|
// 'The request data (stringified JSON of Hoppscotch request object)',
|
||||||
})
|
// })
|
||||||
data: CreateTeamRequestInput,
|
// data: CreateTeamRequestInput,
|
||||||
): Promise<TeamRequest> {
|
// ): Promise<TeamRequest> {
|
||||||
return this.teamRequestService.createTeamRequest(collectionID, data);
|
// return this.teamRequestService.createTeamRequest(collectionID, data);
|
||||||
}
|
// }
|
||||||
|
|
||||||
@Mutation(() => TeamRequest, {
|
@Mutation(() => TeamRequest, {
|
||||||
description: 'Update a request with the given ID',
|
description: 'Update a request with the given ID',
|
||||||
@@ -190,30 +190,30 @@ export class TeamRequestResolver {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Mutation(() => TeamRequest, {
|
// @Mutation(() => TeamRequest, {
|
||||||
description: 'Move a request to the given collection',
|
// description: 'Move a request to the given collection',
|
||||||
})
|
// })
|
||||||
@UseGuards(GqlAuthGuard, GqlRequestTeamMemberGuard)
|
// @UseGuards(GqlAuthGuard, GqlRequestTeamMemberGuard)
|
||||||
@RequiresTeamRole(TeamMemberRole.EDITOR, TeamMemberRole.OWNER)
|
// @RequiresTeamRole(TeamMemberRole.EDITOR, TeamMemberRole.OWNER)
|
||||||
moveRequest(
|
// moveRequest(
|
||||||
@Args({
|
// @Args({
|
||||||
name: 'requestID',
|
// name: 'requestID',
|
||||||
description: 'ID of the request to move',
|
// description: 'ID of the request to move',
|
||||||
type: () => ID,
|
// type: () => ID,
|
||||||
})
|
// })
|
||||||
requestID: string,
|
// requestID: string,
|
||||||
@Args({
|
// @Args({
|
||||||
name: 'destCollID',
|
// name: 'destCollID',
|
||||||
description: 'ID of the collection to move the request to',
|
// description: 'ID of the collection to move the request to',
|
||||||
type: () => ID,
|
// type: () => ID,
|
||||||
})
|
// })
|
||||||
destCollID: string,
|
// destCollID: string,
|
||||||
): Promise<TeamRequest> {
|
// ): Promise<TeamRequest> {
|
||||||
return pipe(
|
// return pipe(
|
||||||
this.teamRequestService.moveRequest(requestID, destCollID),
|
// this.teamRequestService.moveRequest(requestID, destCollID),
|
||||||
TE.getOrElse((e) => throwErr(e)),
|
// TE.getOrElse((e) => throwErr(e)),
|
||||||
)();
|
// )();
|
||||||
}
|
// }
|
||||||
|
|
||||||
// Subscriptions
|
// Subscriptions
|
||||||
@Subscription(() => TeamRequest, {
|
@Subscription(() => TeamRequest, {
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ import { PubSubService } from 'src/pubsub/pubsub.service';
|
|||||||
import { throwErr } from 'src/utils';
|
import { throwErr } from 'src/utils';
|
||||||
import { pipe } from 'fp-ts/function';
|
import { pipe } from 'fp-ts/function';
|
||||||
import * as TO from 'fp-ts/TaskOption';
|
import * as TO from 'fp-ts/TaskOption';
|
||||||
import * as TE from 'fp-ts/TaskEither';
|
import * as E from 'fp-ts/Either';
|
||||||
import { Prisma } from '@prisma/client';
|
import { Prisma } from '@prisma/client';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
@@ -127,43 +127,41 @@ export class TeamRequestService {
|
|||||||
this.pubsub.publish(`team_req/${req.teamID}/req_deleted`, requestID);
|
this.pubsub.publish(`team_req/${req.teamID}/req_deleted`, requestID);
|
||||||
}
|
}
|
||||||
|
|
||||||
async createTeamRequest(
|
// async createTeamRequest(collectionID: string, input: CreateTeamRequestInput) {
|
||||||
collectionID: string,
|
// const team = await this.teamCollectionService.getTeamOfCollection(
|
||||||
input: CreateTeamRequestInput,
|
// collectionID,
|
||||||
): Promise<TeamRequest> {
|
// );
|
||||||
const team = await this.teamCollectionService.getTeamOfCollection(
|
// if (E.isLeft(team)) return [];
|
||||||
collectionID,
|
|
||||||
);
|
|
||||||
|
|
||||||
const data = await this.prisma.teamRequest.create({
|
// const data = await this.prisma.teamRequest.create({
|
||||||
data: {
|
// data: {
|
||||||
team: {
|
// team: {
|
||||||
connect: {
|
// connect: {
|
||||||
id: team.id,
|
// id: team.right.id,
|
||||||
},
|
// },
|
||||||
},
|
// },
|
||||||
request: JSON.parse(input.request),
|
// request: JSON.parse(input.request),
|
||||||
title: input.title,
|
// title: input.title,
|
||||||
collection: {
|
// collection: {
|
||||||
connect: {
|
// connect: {
|
||||||
id: collectionID,
|
// id: collectionID,
|
||||||
},
|
// },
|
||||||
},
|
// },
|
||||||
},
|
// },
|
||||||
});
|
// });
|
||||||
|
|
||||||
const result = {
|
// const result = {
|
||||||
id: data.id,
|
// id: data.id,
|
||||||
collectionID: data.collectionID,
|
// collectionID: data.collectionID,
|
||||||
title: data.title,
|
// title: data.title,
|
||||||
request: JSON.stringify(data.request),
|
// request: JSON.stringify(data.request),
|
||||||
teamID: data.teamID,
|
// teamID: data.teamID,
|
||||||
};
|
// };
|
||||||
|
|
||||||
this.pubsub.publish(`team_req/${result.teamID}/req_created`, result);
|
// this.pubsub.publish(`team_req/${result.teamID}/req_created`, result);
|
||||||
|
|
||||||
return result;
|
// return result;
|
||||||
}
|
// }
|
||||||
|
|
||||||
async getRequestsInCollection(
|
async getRequestsInCollection(
|
||||||
collectionID: string,
|
collectionID: string,
|
||||||
@@ -242,12 +240,12 @@ export class TeamRequestService {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
async getCollectionOfRequest(req: TeamRequest): Promise<TeamCollection> {
|
// async getCollectionOfRequest(req: TeamRequest): Promise<TeamCollection> {
|
||||||
return (
|
// return (
|
||||||
(await this.teamCollectionService.getCollection(req.collectionID)) ??
|
// (await this.teamCollectionService.getCollection(req.collectionID)) ??
|
||||||
throwErr(TEAM_INVALID_COLL_ID)
|
// throwErr(TEAM_INVALID_COLL_ID)
|
||||||
);
|
// );
|
||||||
}
|
// }
|
||||||
|
|
||||||
async getTeamOfRequestFromID(reqID: string): Promise<Team> {
|
async getTeamOfRequestFromID(reqID: string): Promise<Team> {
|
||||||
const req =
|
const req =
|
||||||
@@ -263,69 +261,69 @@ export class TeamRequestService {
|
|||||||
return req.team;
|
return req.team;
|
||||||
}
|
}
|
||||||
|
|
||||||
moveRequest(reqID: string, destinationCollID: string) {
|
// moveRequest(reqID: string, destinationCollID: string) {
|
||||||
return pipe(
|
// return pipe(
|
||||||
TE.Do,
|
// TE.Do,
|
||||||
|
|
||||||
// Check if the request exists
|
// // Check if the request exists
|
||||||
TE.bind('request', () =>
|
// TE.bind('request', () =>
|
||||||
pipe(
|
// pipe(
|
||||||
this.getRequestTO(reqID),
|
// this.getRequestTO(reqID),
|
||||||
TE.fromTaskOption(() => TEAM_REQ_NOT_FOUND),
|
// TE.fromTaskOption(() => TEAM_REQ_NOT_FOUND),
|
||||||
),
|
// ),
|
||||||
),
|
// ),
|
||||||
|
|
||||||
// Check if the destination collection exists (or null)
|
// // Check if the destination collection exists (or null)
|
||||||
TE.bindW('targetCollection', () =>
|
// TE.bindW('targetCollection', () =>
|
||||||
pipe(
|
// pipe(
|
||||||
this.teamCollectionService.getCollectionTO(destinationCollID),
|
// this.teamCollectionService.getCollectionTO(destinationCollID),
|
||||||
TE.fromTaskOption(() => TEAM_REQ_INVALID_TARGET_COLL_ID),
|
// TE.fromTaskOption(() => TEAM_REQ_INVALID_TARGET_COLL_ID),
|
||||||
),
|
// ),
|
||||||
),
|
// ),
|
||||||
|
|
||||||
// Block operation if target collection is not part of the same team
|
// // Block operation if target collection is not part of the same team
|
||||||
// as the request
|
// // as the request
|
||||||
TE.chainW(
|
// TE.chainW(
|
||||||
TE.fromPredicate(
|
// TE.fromPredicate(
|
||||||
({ request, targetCollection }) =>
|
// ({ request, targetCollection }) =>
|
||||||
request.teamID === targetCollection.teamID,
|
// request.teamID === targetCollection.teamID,
|
||||||
() => TEAM_REQ_INVALID_TARGET_COLL_ID,
|
// () => TEAM_REQ_INVALID_TARGET_COLL_ID,
|
||||||
),
|
// ),
|
||||||
),
|
// ),
|
||||||
|
|
||||||
// Update the collection
|
// // Update the collection
|
||||||
TE.chain(({ request, targetCollection }) =>
|
// TE.chain(({ request, targetCollection }) =>
|
||||||
TE.fromTask(() =>
|
// TE.fromTask(() =>
|
||||||
this.prisma.teamRequest.update({
|
// this.prisma.teamRequest.update({
|
||||||
where: {
|
// where: {
|
||||||
id: request.id,
|
// id: request.id,
|
||||||
},
|
// },
|
||||||
data: {
|
// data: {
|
||||||
collectionID: targetCollection.id,
|
// collectionID: targetCollection.id,
|
||||||
},
|
// },
|
||||||
}),
|
// }),
|
||||||
),
|
// ),
|
||||||
),
|
// ),
|
||||||
|
|
||||||
// Generate TeamRequest model object
|
// // Generate TeamRequest model object
|
||||||
TE.map(
|
// TE.map(
|
||||||
(request) =>
|
// (request) =>
|
||||||
<TeamRequest>{
|
// <TeamRequest>{
|
||||||
id: request.id,
|
// id: request.id,
|
||||||
collectionID: request.collectionID,
|
// collectionID: request.collectionID,
|
||||||
request: JSON.stringify(request.request),
|
// request: JSON.stringify(request.request),
|
||||||
teamID: request.teamID,
|
// teamID: request.teamID,
|
||||||
title: request.title,
|
// title: request.title,
|
||||||
},
|
// },
|
||||||
),
|
// ),
|
||||||
|
|
||||||
// Update on PubSub
|
// // Update on PubSub
|
||||||
TE.chainFirst((req) => {
|
// TE.chainFirst((req) => {
|
||||||
this.pubsub.publish(`team_req/${req.teamID}/req_deleted`, req.id);
|
// this.pubsub.publish(`team_req/${req.teamID}/req_deleted`, req.id);
|
||||||
this.pubsub.publish(`team_req/${req.teamID}/req_created`, req);
|
// this.pubsub.publish(`team_req/${req.teamID}/req_created`, req);
|
||||||
|
|
||||||
return TE.of({}); // We don't care about the return type
|
// return TE.of({}); // We don't care about the return type
|
||||||
}),
|
// }),
|
||||||
);
|
// );
|
||||||
}
|
// }
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,7 @@
|
|||||||
|
import { Prisma } from '@prisma/client';
|
||||||
|
|
||||||
|
export interface CollectionFolder {
|
||||||
|
folders: CollectionFolder[];
|
||||||
|
requests: any[];
|
||||||
|
name: string;
|
||||||
|
}
|
||||||
@@ -18,7 +18,6 @@ import {
|
|||||||
UserCollection,
|
UserCollection,
|
||||||
UserCollectionReorderData,
|
UserCollectionReorderData,
|
||||||
} from './user-collections.model';
|
} from './user-collections.model';
|
||||||
import * as E from 'fp-ts/Either';
|
|
||||||
import { throwErr } from 'src/utils';
|
import { throwErr } from 'src/utils';
|
||||||
import { User } from 'src/user/user.model';
|
import { User } from 'src/user/user.model';
|
||||||
import { PaginationArgs } from 'src/types/input-types.args';
|
import { PaginationArgs } from 'src/types/input-types.args';
|
||||||
@@ -30,6 +29,7 @@ import {
|
|||||||
UpdateUserCollectionArgs,
|
UpdateUserCollectionArgs,
|
||||||
} from './input-type.args';
|
} from './input-type.args';
|
||||||
import { ReqType } from 'src/types/RequestTypes';
|
import { ReqType } from 'src/types/RequestTypes';
|
||||||
|
import * as E from 'fp-ts/Either';
|
||||||
|
|
||||||
@Resolver(() => UserCollection)
|
@Resolver(() => UserCollection)
|
||||||
export class UserCollectionResolver {
|
export class UserCollectionResolver {
|
||||||
@@ -230,7 +230,7 @@ export class UserCollectionResolver {
|
|||||||
@Args() args: RenameUserCollectionsArgs,
|
@Args() args: RenameUserCollectionsArgs,
|
||||||
) {
|
) {
|
||||||
const updatedUserCollection =
|
const updatedUserCollection =
|
||||||
await this.userCollectionService.renameCollection(
|
await this.userCollectionService.renameUserCollection(
|
||||||
args.newTitle,
|
args.newTitle,
|
||||||
args.userCollectionID,
|
args.userCollectionID,
|
||||||
user.uid,
|
user.uid,
|
||||||
|
|||||||
@@ -692,9 +692,9 @@ describe('createUserCollection', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('renameCollection', () => {
|
describe('renameUserCollection', () => {
|
||||||
test('should throw USER_COLL_SHORT_TITLE when title is less than 3 characters', async () => {
|
test('should throw USER_COLL_SHORT_TITLE when title is less than 3 characters', async () => {
|
||||||
const result = await userCollectionService.renameCollection(
|
const result = await userCollectionService.renameUserCollection(
|
||||||
'',
|
'',
|
||||||
rootRESTUserCollection.id,
|
rootRESTUserCollection.id,
|
||||||
user.uid,
|
user.uid,
|
||||||
@@ -707,7 +707,7 @@ describe('renameCollection', () => {
|
|||||||
'NotFoundError',
|
'NotFoundError',
|
||||||
);
|
);
|
||||||
|
|
||||||
const result = await userCollectionService.renameCollection(
|
const result = await userCollectionService.renameUserCollection(
|
||||||
'validTitle',
|
'validTitle',
|
||||||
rootRESTUserCollection.id,
|
rootRESTUserCollection.id,
|
||||||
'op09',
|
'op09',
|
||||||
@@ -725,7 +725,7 @@ describe('renameCollection', () => {
|
|||||||
title: 'NewTitle',
|
title: 'NewTitle',
|
||||||
});
|
});
|
||||||
|
|
||||||
const result = await userCollectionService.renameCollection(
|
const result = await userCollectionService.renameUserCollection(
|
||||||
'NewTitle',
|
'NewTitle',
|
||||||
rootRESTUserCollection.id,
|
rootRESTUserCollection.id,
|
||||||
user.uid,
|
user.uid,
|
||||||
@@ -743,7 +743,7 @@ describe('renameCollection', () => {
|
|||||||
|
|
||||||
mockPrisma.userCollection.update.mockRejectedValueOnce('RecordNotFound');
|
mockPrisma.userCollection.update.mockRejectedValueOnce('RecordNotFound');
|
||||||
|
|
||||||
const result = await userCollectionService.renameCollection(
|
const result = await userCollectionService.renameUserCollection(
|
||||||
'NewTitle',
|
'NewTitle',
|
||||||
'invalidID',
|
'invalidID',
|
||||||
user.uid,
|
user.uid,
|
||||||
@@ -761,7 +761,7 @@ describe('renameCollection', () => {
|
|||||||
title: 'NewTitle',
|
title: 'NewTitle',
|
||||||
});
|
});
|
||||||
|
|
||||||
const result = await userCollectionService.renameCollection(
|
const result = await userCollectionService.renameUserCollection(
|
||||||
'NewTitle',
|
'NewTitle',
|
||||||
rootRESTUserCollection.id,
|
rootRESTUserCollection.id,
|
||||||
user.uid,
|
user.uid,
|
||||||
|
|||||||
@@ -28,6 +28,11 @@ export class UserCollectionService {
|
|||||||
private readonly pubsub: PubSubService,
|
private readonly pubsub: PubSubService,
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Typecast a database UserCollection to a UserCollection model
|
||||||
|
* @param userCollection database UserCollection
|
||||||
|
* @returns UserCollection model
|
||||||
|
*/
|
||||||
private cast(collection: UserCollection) {
|
private cast(collection: UserCollection) {
|
||||||
return <UserCollectionModel>{
|
return <UserCollectionModel>{
|
||||||
...collection,
|
...collection,
|
||||||
@@ -35,6 +40,13 @@ export class UserCollectionService {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the count of child collections present for a given collectionID
|
||||||
|
* * The count returned is highest OrderIndex + 1
|
||||||
|
*
|
||||||
|
* @param collectionID The Collection ID
|
||||||
|
* @returns Number of Child Collections
|
||||||
|
*/
|
||||||
private async getChildCollectionsCount(collectionID: string) {
|
private async getChildCollectionsCount(collectionID: string) {
|
||||||
const childCollectionCount = await this.prisma.userCollection.findMany({
|
const childCollectionCount = await this.prisma.userCollection.findMany({
|
||||||
where: { parentID: collectionID },
|
where: { parentID: collectionID },
|
||||||
@@ -46,6 +58,13 @@ export class UserCollectionService {
|
|||||||
return childCollectionCount[0].orderIndex;
|
return childCollectionCount[0].orderIndex;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the count of root collections present for a given userUID
|
||||||
|
* * The count returned is highest OrderIndex + 1
|
||||||
|
*
|
||||||
|
* @param userID The User UID
|
||||||
|
* @returns Number of Root Collections
|
||||||
|
*/
|
||||||
private async getRootCollectionsCount(userID: string) {
|
private async getRootCollectionsCount(userID: string) {
|
||||||
const rootCollectionCount = await this.prisma.userCollection.findMany({
|
const rootCollectionCount = await this.prisma.userCollection.findMany({
|
||||||
where: { userUid: userID, parentID: null },
|
where: { userUid: userID, parentID: null },
|
||||||
@@ -57,6 +76,13 @@ export class UserCollectionService {
|
|||||||
return rootCollectionCount[0].orderIndex;
|
return rootCollectionCount[0].orderIndex;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check to see if Collection belongs to User
|
||||||
|
*
|
||||||
|
* @param collectionID The collection ID
|
||||||
|
* @param userID The User ID
|
||||||
|
* @returns An Option of a Boolean
|
||||||
|
*/
|
||||||
private async isOwnerCheck(collectionID: string, userID: string) {
|
private async isOwnerCheck(collectionID: string, userID: string) {
|
||||||
try {
|
try {
|
||||||
await this.prisma.userCollection.findFirstOrThrow({
|
await this.prisma.userCollection.findFirstOrThrow({
|
||||||
@@ -72,6 +98,12 @@ export class UserCollectionService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get User of given Collection ID
|
||||||
|
*
|
||||||
|
* @param collectionID The collection ID
|
||||||
|
* @returns User of given Collection ID
|
||||||
|
*/
|
||||||
async getUserOfCollection(collectionID: string) {
|
async getUserOfCollection(collectionID: string) {
|
||||||
try {
|
try {
|
||||||
const userCollection = await this.prisma.userCollection.findUniqueOrThrow(
|
const userCollection = await this.prisma.userCollection.findUniqueOrThrow(
|
||||||
@@ -90,6 +122,12 @@ export class UserCollectionService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get parent of given Collection ID
|
||||||
|
*
|
||||||
|
* @param collectionID The collection ID
|
||||||
|
* @returns Parent UserCollection of given Collection ID
|
||||||
|
*/
|
||||||
async getParentOfUserCollection(collectionID: string) {
|
async getParentOfUserCollection(collectionID: string) {
|
||||||
const { parent } = await this.prisma.userCollection.findUnique({
|
const { parent } = await this.prisma.userCollection.findUnique({
|
||||||
where: {
|
where: {
|
||||||
@@ -103,6 +141,15 @@ export class UserCollectionService {
|
|||||||
return parent;
|
return parent;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get child collections of given Collection ID
|
||||||
|
*
|
||||||
|
* @param collectionID The collection ID
|
||||||
|
* @param cursor collectionID for pagination
|
||||||
|
* @param take Number of items we want returned
|
||||||
|
* @param type Type of UserCollection
|
||||||
|
* @returns A list of child collections
|
||||||
|
*/
|
||||||
async getChildrenOfUserCollection(
|
async getChildrenOfUserCollection(
|
||||||
collectionID: string,
|
collectionID: string,
|
||||||
cursor: string | null,
|
cursor: string | null,
|
||||||
@@ -123,6 +170,12 @@ export class UserCollectionService {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get collection details
|
||||||
|
*
|
||||||
|
* @param collectionID The collection ID
|
||||||
|
* @returns An Either of the Collection details
|
||||||
|
*/
|
||||||
async getUserCollection(collectionID: string) {
|
async getUserCollection(collectionID: string) {
|
||||||
try {
|
try {
|
||||||
const userCollection = await this.prisma.userCollection.findUniqueOrThrow(
|
const userCollection = await this.prisma.userCollection.findUniqueOrThrow(
|
||||||
@@ -138,6 +191,15 @@ export class UserCollectionService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new UserCollection
|
||||||
|
*
|
||||||
|
* @param user The User object
|
||||||
|
* @param title The title of new UserCollection
|
||||||
|
* @param parentUserCollectionID The parent collectionID (null if root collection)
|
||||||
|
* @param type Type of Collection we want to create (REST/GQL)
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
async createUserCollection(
|
async createUserCollection(
|
||||||
user: AuthUser,
|
user: AuthUser,
|
||||||
title: string,
|
title: string,
|
||||||
@@ -147,6 +209,7 @@ export class UserCollectionService {
|
|||||||
const isTitleValid = isValidLength(title, 3);
|
const isTitleValid = isValidLength(title, 3);
|
||||||
if (!isTitleValid) return E.left(USER_COLL_SHORT_TITLE);
|
if (!isTitleValid) return E.left(USER_COLL_SHORT_TITLE);
|
||||||
|
|
||||||
|
// Check to see if parentUserCollectionID belongs to this User
|
||||||
if (parentUserCollectionID !== null) {
|
if (parentUserCollectionID !== null) {
|
||||||
const isOwner = await this.isOwnerCheck(parentUserCollectionID, user.uid);
|
const isOwner = await this.isOwnerCheck(parentUserCollectionID, user.uid);
|
||||||
if (O.isNone(isOwner)) return E.left(USER_NOT_OWNER);
|
if (O.isNone(isOwner)) return E.left(USER_NOT_OWNER);
|
||||||
@@ -181,6 +244,14 @@ export class UserCollectionService {
|
|||||||
return E.right(userCollection);
|
return E.right(userCollection);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param user The User Object
|
||||||
|
* @param cursor collectionID for pagination
|
||||||
|
* @param take Number of items we want returned
|
||||||
|
* @param type Type of UserCollection
|
||||||
|
* @returns A list of root UserCollections
|
||||||
|
*/
|
||||||
async getUserRootCollections(
|
async getUserRootCollections(
|
||||||
user: AuthUser,
|
user: AuthUser,
|
||||||
cursor: string | null,
|
cursor: string | null,
|
||||||
@@ -202,6 +273,15 @@ export class UserCollectionService {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param user The User Object
|
||||||
|
* @param userCollectionID The User UID
|
||||||
|
* @param cursor collectionID for pagination
|
||||||
|
* @param take Number of items we want returned
|
||||||
|
* @param type Type of UserCollection
|
||||||
|
* @returns A list of child UserCollections
|
||||||
|
*/
|
||||||
async getUserChildCollections(
|
async getUserChildCollections(
|
||||||
user: AuthUser,
|
user: AuthUser,
|
||||||
userCollectionID: string,
|
userCollectionID: string,
|
||||||
@@ -221,7 +301,15 @@ export class UserCollectionService {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async renameCollection(
|
/**
|
||||||
|
* Update the title of a UserCollection
|
||||||
|
*
|
||||||
|
* @param newTitle The new title of collection
|
||||||
|
* @param userCollectionID The Collection Id
|
||||||
|
* @param userID The User UID
|
||||||
|
* @returns An Either of the updated UserCollection
|
||||||
|
*/
|
||||||
|
async renameUserCollection(
|
||||||
newTitle: string,
|
newTitle: string,
|
||||||
userCollectionID: string,
|
userCollectionID: string,
|
||||||
userID: string,
|
userID: string,
|
||||||
@@ -254,6 +342,12 @@ export class UserCollectionService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Delete a UserCollection from the DB
|
||||||
|
*
|
||||||
|
* @param collectionID The Collection Id
|
||||||
|
* @returns The deleted UserCollection
|
||||||
|
*/
|
||||||
private async removeUserCollection(collectionID: string) {
|
private async removeUserCollection(collectionID: string) {
|
||||||
try {
|
try {
|
||||||
const deletedUserCollection = await this.prisma.userCollection.delete({
|
const deletedUserCollection = await this.prisma.userCollection.delete({
|
||||||
@@ -268,6 +362,12 @@ export class UserCollectionService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Delete child collection and requests of a UserCollection
|
||||||
|
*
|
||||||
|
* @param collectionID The Collection Id
|
||||||
|
* @returns A Boolean of deletion status
|
||||||
|
*/
|
||||||
private async deleteCollectionData(collection: UserCollection) {
|
private async deleteCollectionData(collection: UserCollection) {
|
||||||
// Get all child collections in collectionID
|
// Get all child collections in collectionID
|
||||||
const childCollectionList = await this.prisma.userCollection.findMany({
|
const childCollectionList = await this.prisma.userCollection.findMany({
|
||||||
@@ -312,6 +412,13 @@ export class UserCollectionService {
|
|||||||
return E.right(true);
|
return E.right(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Delete a UserCollection
|
||||||
|
*
|
||||||
|
* @param collectionID The Collection Id
|
||||||
|
* @param userID The User UID
|
||||||
|
* @returns An Either of Boolean of deletion status
|
||||||
|
*/
|
||||||
async deleteUserCollection(collectionID: string, userID: string) {
|
async deleteUserCollection(collectionID: string, userID: string) {
|
||||||
// Get collection details of collectionID
|
// Get collection details of collectionID
|
||||||
const collection = await this.getUserCollection(collectionID);
|
const collection = await this.getUserCollection(collectionID);
|
||||||
@@ -327,6 +434,13 @@ export class UserCollectionService {
|
|||||||
return E.right(true);
|
return E.right(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Change parentID of UserCollection's
|
||||||
|
*
|
||||||
|
* @param collectionID The collection ID
|
||||||
|
* @param parentCollectionID The new parent's collection ID or change to root collection
|
||||||
|
* @returns If successful return an Either of true
|
||||||
|
*/
|
||||||
private async changeParent(
|
private async changeParent(
|
||||||
collection: UserCollection,
|
collection: UserCollection,
|
||||||
parentCollectionID: string | null,
|
parentCollectionID: string | null,
|
||||||
@@ -358,6 +472,13 @@ export class UserCollectionService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if collection is parent of destCollection
|
||||||
|
*
|
||||||
|
* @param collection The ID of collection being moved
|
||||||
|
* @param destCollection The ID of collection into which we are moving target collection into
|
||||||
|
* @returns An Option of boolean, is parent or not
|
||||||
|
*/
|
||||||
private async isParent(
|
private async isParent(
|
||||||
collection: UserCollection,
|
collection: UserCollection,
|
||||||
destCollection: UserCollection,
|
destCollection: UserCollection,
|
||||||
@@ -385,6 +506,14 @@ export class UserCollectionService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update the OrderIndex of all collections in given parentID
|
||||||
|
*
|
||||||
|
* @param parentID The Parent collectionID
|
||||||
|
* @param orderIndexCondition Condition to decide what collections will be updated
|
||||||
|
* @param dataCondition Increment/Decrement OrderIndex condition
|
||||||
|
* @returns A Collection with updated OrderIndexes
|
||||||
|
*/
|
||||||
private async updateOrderIndex(
|
private async updateOrderIndex(
|
||||||
parentID: string,
|
parentID: string,
|
||||||
orderIndexCondition: Prisma.IntFilter,
|
orderIndexCondition: Prisma.IntFilter,
|
||||||
@@ -401,6 +530,14 @@ export class UserCollectionService {
|
|||||||
return updatedUserCollection;
|
return updatedUserCollection;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Move UserCollection into root or another collection
|
||||||
|
*
|
||||||
|
* @param userCollectionID The ID of collection being moved
|
||||||
|
* @param destCollectionID The ID of collection the target collection is being moved into or move target collection to root
|
||||||
|
* @param userID The User UID
|
||||||
|
* @returns An Either of the moved UserCollection
|
||||||
|
*/
|
||||||
async moveUserCollection(
|
async moveUserCollection(
|
||||||
userCollectionID: string,
|
userCollectionID: string,
|
||||||
destCollectionID: string | null,
|
destCollectionID: string | null,
|
||||||
@@ -490,12 +627,26 @@ export class UserCollectionService {
|
|||||||
return E.right(updatedCollection.right);
|
return E.right(updatedCollection.right);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Find the number of child collections present in collectionID
|
||||||
|
*
|
||||||
|
* @param collectionID The Collection ID
|
||||||
|
* @returns Number of collections
|
||||||
|
*/
|
||||||
getCollectionCount(collectionID: string): Promise<number> {
|
getCollectionCount(collectionID: string): Promise<number> {
|
||||||
return this.prisma.userCollection.count({
|
return this.prisma.userCollection.count({
|
||||||
where: { parentID: collectionID },
|
where: { parentID: collectionID },
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update order of root or child collectionID's
|
||||||
|
*
|
||||||
|
* @param collectionID The ID of collection being re-ordered
|
||||||
|
* @param nextCollectionID The ID of collection that is after the moved collection in its new position
|
||||||
|
* @param userID The User UID
|
||||||
|
* @returns If successful return an Either of true
|
||||||
|
*/
|
||||||
async updateUserCollectionOrder(
|
async updateUserCollectionOrder(
|
||||||
collectionID: string,
|
collectionID: string,
|
||||||
nextCollectionID: string | null,
|
nextCollectionID: string | null,
|
||||||
|
|||||||
Reference in New Issue
Block a user