feat: completed addition of new data field in TeamCollection

This commit is contained in:
Balu Babu
2023-12-01 12:59:34 +05:30
parent 85c42da31c
commit f13d00465d
7 changed files with 162 additions and 15 deletions

View File

@@ -111,7 +111,7 @@ services:
build:
dockerfile: packages/hoppscotch-backend/Dockerfile
context: .
target: prod
target: dev
env_file:
- ./.env
restart: always
@@ -121,7 +121,7 @@ services:
- PORT=3000
volumes:
# Uncomment the line below when modifying code. Only applicable when using the "dev" target.
# - ./packages/hoppscotch-backend/:/usr/src/app
- ./packages/hoppscotch-backend/:/usr/src/app
- /usr/src/app/node_modules/
depends_on:
hoppscotch-db:

View File

@@ -254,6 +254,13 @@ export const TEAM_COLL_INVALID_JSON = 'team_coll/invalid_json';
*/
export const TEAM_NOT_OWNER = 'team_coll/team_not_owner' as const;
/**
* The Team Collection data is not valid
* (TeamCollectionService)
*/
export const TEAM_COLL_DATA_INVALID =
'team_coll/team_coll_data_invalid' as const;
/**
* Tried to perform an action on a request that doesn't accept their member role level
* (GqlRequestTeamMemberGuard)

View File

@@ -14,6 +14,12 @@ export class CreateRootTeamCollectionArgs {
@Field({ name: 'title', description: 'Title of the new collection' })
title: string;
@Field({
name: 'data',
description: 'JSON string representing the collection data',
})
data: string;
}
@ArgsType()
@@ -26,6 +32,12 @@ export class CreateChildTeamCollectionArgs {
@Field({ name: 'childTitle', description: 'Title of the new collection' })
childTitle: string;
@Field({
name: 'data',
description: 'JSON string representing the collection data',
})
data: string;
}
@ArgsType()
@@ -33,12 +45,14 @@ export class RenameTeamCollectionArgs {
@Field(() => ID, {
name: 'collectionID',
description: 'ID of the collection',
deprecationReason: 'Switch to updateTeamCollection mutation instead',
})
collectionID: string;
@Field({
name: 'newTitle',
description: 'The updated title of the collection',
deprecationReason: 'Switch to updateTeamCollection mutation instead',
})
newTitle: string;
}
@@ -98,3 +112,25 @@ export class ReplaceTeamCollectionArgs {
})
parentCollectionID?: string;
}
@ArgsType()
export class UpdateTeamCollectionArgs {
@Field(() => ID, {
name: 'collectionID',
description: 'ID of the collection',
})
collectionID: string;
@Field({
name: 'newTitle',
description: 'The updated title of the collection',
nullable: true,
})
newTitle: string;
@Field({
name: 'data',
description: 'JSON string representing the collection data',
})
data: string;
}

View File

@@ -12,6 +12,12 @@ export class TeamCollection {
})
title: string;
@Field({
description: 'JSON string representing the collection data',
nullable: true,
})
data: string;
@Field(() => ID, {
description: 'ID of the collection',
nullable: true,

View File

@@ -25,6 +25,7 @@ import {
MoveTeamCollectionArgs,
RenameTeamCollectionArgs,
ReplaceTeamCollectionArgs,
UpdateTeamCollectionArgs,
UpdateTeamCollectionOrderArgs,
} from './input-type.args';
import * as E from 'fp-ts/Either';
@@ -141,7 +142,14 @@ export class TeamCollectionResolver {
);
if (E.isLeft(teamCollections)) throwErr(teamCollections.left);
return teamCollections.right;
return <TeamCollection>{
id: teamCollections.right.id,
title: teamCollections.right.title,
parentID: teamCollections.right.parentID,
data: !teamCollections.right.data
? null
: JSON.stringify(teamCollections.right.data),
};
}
// Mutations
@@ -155,6 +163,7 @@ export class TeamCollectionResolver {
const teamCollection = await this.teamCollectionService.createCollection(
args.teamID,
args.title,
args.data,
null,
);
@@ -230,6 +239,7 @@ export class TeamCollectionResolver {
const teamCollection = await this.teamCollectionService.createCollection(
team.right.id,
args.childTitle,
args.data,
args.collectionID,
);
@@ -239,6 +249,7 @@ export class TeamCollectionResolver {
@Mutation(() => TeamCollection, {
description: 'Rename a collection',
deprecationReason: 'Switch to updateTeamCollection mutation instead',
})
@UseGuards(GqlAuthGuard, GqlCollectionTeamMemberGuard)
@RequiresTeamRole(TeamMemberRole.OWNER, TeamMemberRole.EDITOR)
@@ -303,6 +314,23 @@ export class TeamCollectionResolver {
return request.right;
}
@Mutation(() => TeamCollection, {
description: 'Update Team Collection details',
})
@UseGuards(GqlAuthGuard, GqlCollectionTeamMemberGuard)
@RequiresTeamRole(TeamMemberRole.OWNER, TeamMemberRole.EDITOR)
async updateTeamCollection(@Args() args: UpdateTeamCollectionArgs) {
const updatedTeamCollection =
await this.teamCollectionService.updateTeamCollection(
args.collectionID,
args.data,
args.newTitle,
);
if (E.isLeft(updatedTeamCollection)) throwErr(updatedTeamCollection.left);
return updatedTeamCollection.right;
}
// Subscriptions
@Subscription(() => TeamCollection, {

View File

@@ -13,6 +13,7 @@ import {
TEAM_COLL_IS_PARENT_COLL,
TEAM_COL_SAME_NEXT_COLL,
TEAM_COL_REORDERING_FAILED,
TEAM_COLL_DATA_INVALID,
} from '../errors';
import { PubSubService } from '../pubsub/pubsub.service';
import { isValidLength } from 'src/utils';
@@ -69,6 +70,7 @@ export class TeamCollectionService {
this.generatePrismaQueryObjForFBCollFolder(f, teamID, index + 1),
),
},
data: folder.data ?? undefined,
};
}
@@ -118,6 +120,7 @@ export class TeamCollectionService {
name: collection.right.title,
folders: childrenCollectionObjects,
requests: requests.map((x) => x.request),
data: JSON.stringify(collection.right.data),
};
return E.right(result);
@@ -199,7 +202,7 @@ export class TeamCollectionService {
);
teamCollections.forEach((x) =>
this.pubsub.publish(`team_coll/${destTeamID}/coll_added`, x),
this.pubsub.publish(`team_coll/${destTeamID}/coll_added`, this.cast(x)),
);
return E.right(true);
@@ -269,7 +272,7 @@ export class TeamCollectionService {
);
teamCollections.forEach((x) =>
this.pubsub.publish(`team_coll/${destTeamID}/coll_added`, x),
this.pubsub.publish(`team_coll/${destTeamID}/coll_added`, this.cast(x)),
);
return E.right(true);
@@ -277,11 +280,17 @@ export class TeamCollectionService {
/**
* Typecast a database TeamCollection to a TeamCollection model
*
* @param teamCollection database TeamCollection
* @returns TeamCollection model
*/
private cast(teamCollection: DBTeamCollection): TeamCollection {
return <TeamCollection>{ ...teamCollection };
return <TeamCollection>{
id: teamCollection.id,
title: teamCollection.title,
parentID: teamCollection.parentID,
data: !teamCollection.data ? null : JSON.stringify(teamCollection.data),
};
}
/**
@@ -324,7 +333,7 @@ export class TeamCollectionService {
});
if (!teamCollection) return null;
return teamCollection.parent;
return !teamCollection.parent ? null : this.cast(teamCollection.parent);
}
/**
@@ -335,12 +344,12 @@ export class TeamCollectionService {
* @param take Number of items we want returned
* @returns A list of child collections
*/
getChildrenOfCollection(
async getChildrenOfCollection(
collectionID: string,
cursor: string | null,
take: number,
) {
return this.prisma.teamCollection.findMany({
const res = await this.prisma.teamCollection.findMany({
where: {
parentID: collectionID,
},
@@ -351,6 +360,12 @@ export class TeamCollectionService {
skip: cursor ? 1 : 0,
cursor: cursor ? { id: cursor } : undefined,
});
const childCollections = res.map((teamCollection) =>
this.cast(teamCollection),
);
return childCollections;
}
/**
@@ -366,7 +381,7 @@ export class TeamCollectionService {
cursor: string | null,
take: number,
) {
return this.prisma.teamCollection.findMany({
const res = await this.prisma.teamCollection.findMany({
where: {
teamID,
parentID: null,
@@ -378,6 +393,12 @@ export class TeamCollectionService {
skip: cursor ? 1 : 0,
cursor: cursor ? { id: cursor } : undefined,
});
const teamCollections = res.map((teamCollection) =>
this.cast(teamCollection),
);
return teamCollections;
}
/**
@@ -470,6 +491,7 @@ export class TeamCollectionService {
async createCollection(
teamID: string,
title: string,
data: string,
parentTeamCollectionID: string | null,
) {
const isTitleValid = isValidLength(title, this.TITLE_LENGTH);
@@ -481,6 +503,9 @@ export class TeamCollectionService {
if (O.isNone(isOwner)) return E.left(TEAM_NOT_OWNER);
}
const collectionData = stringToJson(data);
if (E.isLeft(collectionData)) return E.left(TEAM_COLL_DATA_INVALID);
const isParent = parentTeamCollectionID
? {
connect: {
@@ -498,18 +523,23 @@ export class TeamCollectionService {
},
},
parent: isParent,
data: collectionData.right,
orderIndex: !parentTeamCollectionID
? (await this.getRootCollectionsCount(teamID)) + 1
: (await this.getChildCollectionsCount(parentTeamCollectionID)) + 1,
},
});
this.pubsub.publish(`team_coll/${teamID}/coll_added`, teamCollection);
this.pubsub.publish(
`team_coll/${teamID}/coll_added`,
this.cast(teamCollection),
);
return E.right(this.cast(teamCollection));
}
/**
* @deprecated Use updateTeamCollection method instead
* Update the title of a TeamCollection
*
* @param collectionID The Collection ID
@@ -532,10 +562,10 @@ export class TeamCollectionService {
this.pubsub.publish(
`team_coll/${updatedTeamCollection.teamID}/coll_updated`,
updatedTeamCollection,
this.cast(updatedTeamCollection),
);
return E.right(updatedTeamCollection);
return E.right(this.cast(updatedTeamCollection));
} catch (error) {
return E.left(TEAM_COLL_NOT_FOUND);
}
@@ -694,8 +724,8 @@ export class TeamCollectionService {
* @returns An Option of boolean, is parent or not
*/
private async isParent(
collection: TeamCollection,
destCollection: TeamCollection,
collection: DBTeamCollection,
destCollection: DBTeamCollection,
): Promise<O.Option<boolean>> {
//* Recursively check if collection is a parent by going up the tree of child-parent collections until we reach a root collection i.e parentID === null
//* Valid condition, isParent returns false
@@ -971,4 +1001,43 @@ export class TeamCollectionService {
const teamCollectionsCount = this.prisma.teamCollection.count();
return teamCollectionsCount;
}
/**
* Update Team Collection details
*
* @param collectionID Collection ID
* @param collectionData new header data in a JSONified string form
* @param newTitle New title of the collection
* @returns Updated TeamCollection
*/
async updateTeamCollection(
collectionID: string,
collectionData: string,
newTitle: string = null,
) {
try {
if (collectionData) {
const jsonReq = stringToJson(collectionData);
if (E.isLeft(jsonReq)) return E.left(TEAM_COLL_DATA_INVALID);
collectionData = jsonReq.right;
}
const updatedTeamCollection = await this.prisma.teamCollection.update({
where: { id: collectionID },
data: {
data: collectionData,
title: newTitle ?? undefined,
},
});
this.pubsub.publish(
`team_coll/${updatedTeamCollection.teamID}/coll_updated`,
this.cast(updatedTeamCollection),
);
return E.right(this.cast(updatedTeamCollection));
} catch (e) {
return E.left(TEAM_COLL_NOT_FOUND);
}
}
}

View File

@@ -3,4 +3,5 @@ export interface CollectionFolder {
folders: CollectionFolder[];
requests: any[];
name: string;
data?: string;
}