Compare commits
2 Commits
feat/subpa
...
feat/migra
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
fe1d7005b5 | ||
|
|
f5d2e4f11f |
14
.vscode/extensions.json
vendored
14
.vscode/extensions.json
vendored
@@ -1,14 +0,0 @@
|
|||||||
{
|
|
||||||
"recommendations": [
|
|
||||||
"antfu.iconify",
|
|
||||||
"vue.volar",
|
|
||||||
"esbenp.prettier-vscode",
|
|
||||||
"dbaeumer.vscode-eslint",
|
|
||||||
"editorconfig.editorconfig",
|
|
||||||
"csstools.postcss",
|
|
||||||
"folke.vscode-monorepo-workspace"
|
|
||||||
],
|
|
||||||
"unwantedRecommendations": [
|
|
||||||
"octref.vetur"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@@ -50,7 +50,7 @@ execSync(`npx import-meta-env -x build.env -e build.env -p "/site/**/*"`)
|
|||||||
fs.rmSync("build.env")
|
fs.rmSync("build.env")
|
||||||
|
|
||||||
const caddyProcess = runChildProcessWithPrefix("caddy", ["run", "--config", "/etc/caddy/Caddyfile", "--adapter", "caddyfile"], "App/Admin Dashboard Caddy")
|
const caddyProcess = runChildProcessWithPrefix("caddy", ["run", "--config", "/etc/caddy/Caddyfile", "--adapter", "caddyfile"], "App/Admin Dashboard Caddy")
|
||||||
const backendProcess = runChildProcessWithPrefix("pnpm", ["run", "start:prod"], "Backend Server")
|
const backendProcess = runChildProcessWithPrefix("pnpm", ["run", "start:migrate:prod"], "Backend Server")
|
||||||
|
|
||||||
caddyProcess.on("exit", (code) => {
|
caddyProcess.on("exit", (code) => {
|
||||||
console.log(`Exiting process because Caddy Server exited with code ${code}`)
|
console.log(`Exiting process because Caddy Server exited with code ${code}`)
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ FROM builder AS dev
|
|||||||
|
|
||||||
ENV PRODUCTION="false"
|
ENV PRODUCTION="false"
|
||||||
|
|
||||||
CMD ["pnpm", "run", "start:dev"]
|
CMD ["pnpm", "run", "start:migrate:dev"]
|
||||||
|
|
||||||
EXPOSE 3170
|
EXPOSE 3170
|
||||||
|
|
||||||
@@ -32,7 +32,7 @@ FROM builder AS prod
|
|||||||
|
|
||||||
ENV PRODUCTION="true"
|
ENV PRODUCTION="true"
|
||||||
|
|
||||||
CMD ["pnpm", "run", "start:prod"]
|
CMD ["pnpm", "run", "start:migrate:prod"]
|
||||||
|
|
||||||
EXPOSE 3170
|
EXPOSE 3170
|
||||||
|
|
||||||
|
|||||||
@@ -14,6 +14,9 @@
|
|||||||
"start:dev": "nest start --watch",
|
"start:dev": "nest start --watch",
|
||||||
"start:debug": "nest start --debug --watch",
|
"start:debug": "nest start --debug --watch",
|
||||||
"start:prod": "node dist/main",
|
"start:prod": "node dist/main",
|
||||||
|
"start:migrate:dev": "prisma migrate deploy && npm run start:dev",
|
||||||
|
"start:migrate:debug": "prisma migrate deploy && npm run start:debug",
|
||||||
|
"start:migrate:prod": "prisma migrate deploy && npm run start:prod",
|
||||||
"lint": "eslint \"{src,apps,libs,test}/**/*.ts\" --fix",
|
"lint": "eslint \"{src,apps,libs,test}/**/*.ts\" --fix",
|
||||||
"test": "jest",
|
"test": "jest",
|
||||||
"postinstall": "prisma generate && pnpm run generate-gql-sdl",
|
"postinstall": "prisma generate && pnpm run generate-gql-sdl",
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ import { TeamEnvironmentsModule } from '../team-environments/team-environments.m
|
|||||||
import { TeamCollectionModule } from '../team-collection/team-collection.module';
|
import { TeamCollectionModule } from '../team-collection/team-collection.module';
|
||||||
import { TeamRequestModule } from '../team-request/team-request.module';
|
import { TeamRequestModule } from '../team-request/team-request.module';
|
||||||
import { InfraResolver } from './infra.resolver';
|
import { InfraResolver } from './infra.resolver';
|
||||||
|
import { ShortcodeModule } from 'src/shortcode/shortcode.module';
|
||||||
|
|
||||||
@Module({
|
@Module({
|
||||||
imports: [
|
imports: [
|
||||||
@@ -23,6 +24,7 @@ import { InfraResolver } from './infra.resolver';
|
|||||||
TeamEnvironmentsModule,
|
TeamEnvironmentsModule,
|
||||||
TeamCollectionModule,
|
TeamCollectionModule,
|
||||||
TeamRequestModule,
|
TeamRequestModule,
|
||||||
|
ShortcodeModule,
|
||||||
],
|
],
|
||||||
providers: [InfraResolver, AdminResolver, AdminService],
|
providers: [InfraResolver, AdminResolver, AdminService],
|
||||||
exports: [AdminService],
|
exports: [AdminService],
|
||||||
|
|||||||
@@ -443,6 +443,23 @@ export class AdminResolver {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Mutation(() => Boolean, {
|
||||||
|
description: 'Revoke Shortcode by ID',
|
||||||
|
})
|
||||||
|
@UseGuards(GqlAuthGuard, GqlAdminGuard)
|
||||||
|
async revokeShortcodeByAdmin(
|
||||||
|
@Args({
|
||||||
|
name: 'code',
|
||||||
|
description: 'The shortcode to delete',
|
||||||
|
type: () => ID,
|
||||||
|
})
|
||||||
|
code: string,
|
||||||
|
): Promise<boolean> {
|
||||||
|
const res = await this.adminService.deleteShortcode(code);
|
||||||
|
if (E.isLeft(res)) throwErr(res.left);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
/* Subscriptions */
|
/* Subscriptions */
|
||||||
|
|
||||||
@Subscription(() => InvitedUser, {
|
@Subscription(() => InvitedUser, {
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ import {
|
|||||||
INVALID_EMAIL,
|
INVALID_EMAIL,
|
||||||
USER_ALREADY_INVITED,
|
USER_ALREADY_INVITED,
|
||||||
} from '../errors';
|
} from '../errors';
|
||||||
|
import { ShortcodeService } from 'src/shortcode/shortcode.service';
|
||||||
|
|
||||||
const mockPrisma = mockDeep<PrismaService>();
|
const mockPrisma = mockDeep<PrismaService>();
|
||||||
const mockPubSub = mockDeep<PubSubService>();
|
const mockPubSub = mockDeep<PubSubService>();
|
||||||
@@ -25,6 +26,7 @@ const mockTeamRequestService = mockDeep<TeamRequestService>();
|
|||||||
const mockTeamInvitationService = mockDeep<TeamInvitationService>();
|
const mockTeamInvitationService = mockDeep<TeamInvitationService>();
|
||||||
const mockTeamCollectionService = mockDeep<TeamCollectionService>();
|
const mockTeamCollectionService = mockDeep<TeamCollectionService>();
|
||||||
const mockMailerService = mockDeep<MailerService>();
|
const mockMailerService = mockDeep<MailerService>();
|
||||||
|
const mockShortcodeService = mockDeep<ShortcodeService>();
|
||||||
|
|
||||||
const adminService = new AdminService(
|
const adminService = new AdminService(
|
||||||
mockUserService,
|
mockUserService,
|
||||||
@@ -36,6 +38,7 @@ const adminService = new AdminService(
|
|||||||
mockPubSub as any,
|
mockPubSub as any,
|
||||||
mockPrisma as any,
|
mockPrisma as any,
|
||||||
mockMailerService,
|
mockMailerService,
|
||||||
|
mockShortcodeService,
|
||||||
);
|
);
|
||||||
|
|
||||||
const invitedUsers: InvitedUsers[] = [
|
const invitedUsers: InvitedUsers[] = [
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ import { TeamRequestService } from '../team-request/team-request.service';
|
|||||||
import { TeamEnvironmentsService } from '../team-environments/team-environments.service';
|
import { TeamEnvironmentsService } from '../team-environments/team-environments.service';
|
||||||
import { TeamInvitationService } from '../team-invitation/team-invitation.service';
|
import { TeamInvitationService } from '../team-invitation/team-invitation.service';
|
||||||
import { TeamMemberRole } from '../team/team.model';
|
import { TeamMemberRole } from '../team/team.model';
|
||||||
|
import { ShortcodeService } from 'src/shortcode/shortcode.service';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class AdminService {
|
export class AdminService {
|
||||||
@@ -37,6 +38,7 @@ export class AdminService {
|
|||||||
private readonly pubsub: PubSubService,
|
private readonly pubsub: PubSubService,
|
||||||
private readonly prisma: PrismaService,
|
private readonly prisma: PrismaService,
|
||||||
private readonly mailerService: MailerService,
|
private readonly mailerService: MailerService,
|
||||||
|
private readonly shortcodeService: ShortcodeService,
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -432,4 +434,35 @@ export class AdminService {
|
|||||||
|
|
||||||
return E.right(teamInvite.right);
|
return E.right(teamInvite.right);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fetch all created ShortCodes
|
||||||
|
*
|
||||||
|
* @param args Pagination arguments
|
||||||
|
* @param userEmail User email
|
||||||
|
* @returns ShortcodeWithUserEmail
|
||||||
|
*/
|
||||||
|
async fetchAllShortcodes(
|
||||||
|
cursorID: string,
|
||||||
|
take: number,
|
||||||
|
userEmail: string = null,
|
||||||
|
) {
|
||||||
|
return this.shortcodeService.fetchAllShortcodes(
|
||||||
|
{ cursor: cursorID, take },
|
||||||
|
userEmail,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Delete a Shortcode
|
||||||
|
*
|
||||||
|
* @param shortcodeID ID of Shortcode being deleted
|
||||||
|
* @returns Boolean on successful deletion
|
||||||
|
*/
|
||||||
|
async deleteShortcode(shortcodeID: string) {
|
||||||
|
const result = await this.shortcodeService.deleteShortcode(shortcodeID);
|
||||||
|
|
||||||
|
if (E.isLeft(result)) return E.left(result.left);
|
||||||
|
return E.right(result.right);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ import { InvitedUser } from './invited-user.model';
|
|||||||
import { Team } from 'src/team/team.model';
|
import { Team } from 'src/team/team.model';
|
||||||
import { TeamInvitation } from 'src/team-invitation/team-invitation.model';
|
import { TeamInvitation } from 'src/team-invitation/team-invitation.model';
|
||||||
import { GqlAdmin } from './decorators/gql-admin.decorator';
|
import { GqlAdmin } from './decorators/gql-admin.decorator';
|
||||||
|
import { ShortcodeWithUserEmail } from 'src/shortcode/shortcode.model';
|
||||||
|
|
||||||
@UseGuards(GqlThrottlerGuard)
|
@UseGuards(GqlThrottlerGuard)
|
||||||
@Resolver(() => Infra)
|
@Resolver(() => Infra)
|
||||||
@@ -202,4 +203,23 @@ export class InfraResolver {
|
|||||||
async teamRequestsCount() {
|
async teamRequestsCount() {
|
||||||
return this.adminService.getTeamRequestsCount();
|
return this.adminService.getTeamRequestsCount();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ResolveField(() => [ShortcodeWithUserEmail], {
|
||||||
|
description: 'Returns a list of all the shortcodes in the infra',
|
||||||
|
})
|
||||||
|
async allShortcodes(
|
||||||
|
@Args() args: PaginationArgs,
|
||||||
|
@Args({
|
||||||
|
name: 'userEmail',
|
||||||
|
nullable: true,
|
||||||
|
description: 'Users email to filter shortcodes by',
|
||||||
|
})
|
||||||
|
userEmail: string,
|
||||||
|
) {
|
||||||
|
return await this.adminService.fetchAllShortcodes(
|
||||||
|
args.cursor,
|
||||||
|
args.take,
|
||||||
|
userEmail,
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import { Field, ID, ObjectType } from '@nestjs/graphql';
|
import { Field, ID, ObjectType } from '@nestjs/graphql';
|
||||||
|
import { User } from 'src/user/user.model';
|
||||||
|
|
||||||
@ObjectType()
|
@ObjectType()
|
||||||
export class Shortcode {
|
export class Shortcode {
|
||||||
@@ -23,3 +24,46 @@ export class Shortcode {
|
|||||||
})
|
})
|
||||||
createdOn: Date;
|
createdOn: Date;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ObjectType()
|
||||||
|
export class ShortcodeCreator {
|
||||||
|
@Field({
|
||||||
|
description: 'Uid of user who created the shortcode',
|
||||||
|
})
|
||||||
|
uid: string;
|
||||||
|
|
||||||
|
@Field({
|
||||||
|
description: 'Email of user who created the shortcode',
|
||||||
|
})
|
||||||
|
email: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
@ObjectType()
|
||||||
|
export class ShortcodeWithUserEmail {
|
||||||
|
@Field(() => ID, {
|
||||||
|
description: 'The 12 digit alphanumeric code',
|
||||||
|
})
|
||||||
|
id: string;
|
||||||
|
|
||||||
|
@Field({
|
||||||
|
description: 'JSON string representing the request data',
|
||||||
|
})
|
||||||
|
request: string;
|
||||||
|
|
||||||
|
@Field({
|
||||||
|
description: 'JSON string representing the properties for an embed',
|
||||||
|
nullable: true,
|
||||||
|
})
|
||||||
|
properties: string;
|
||||||
|
|
||||||
|
@Field({
|
||||||
|
description: 'Timestamp of when the Shortcode was created',
|
||||||
|
})
|
||||||
|
createdOn: Date;
|
||||||
|
|
||||||
|
@Field({
|
||||||
|
description: 'Details of user who created the shortcode',
|
||||||
|
nullable: true,
|
||||||
|
})
|
||||||
|
creator: ShortcodeCreator;
|
||||||
|
}
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import {
|
|||||||
} from '@nestjs/graphql';
|
} from '@nestjs/graphql';
|
||||||
import * as E from 'fp-ts/Either';
|
import * as E from 'fp-ts/Either';
|
||||||
import { UseGuards } from '@nestjs/common';
|
import { UseGuards } from '@nestjs/common';
|
||||||
import { Shortcode } from './shortcode.model';
|
import { Shortcode, ShortcodeWithUserEmail } from './shortcode.model';
|
||||||
import { ShortcodeService } from './shortcode.service';
|
import { ShortcodeService } from './shortcode.service';
|
||||||
import { throwErr } from 'src/utils';
|
import { throwErr } from 'src/utils';
|
||||||
import { GqlUser } from 'src/decorators/gql-user.decorator';
|
import { GqlUser } from 'src/decorators/gql-user.decorator';
|
||||||
@@ -19,6 +19,7 @@ import { AuthUser } from '../types/AuthUser';
|
|||||||
import { PaginationArgs } from 'src/types/input-types.args';
|
import { PaginationArgs } from 'src/types/input-types.args';
|
||||||
import { GqlThrottlerGuard } from 'src/guards/gql-throttler.guard';
|
import { GqlThrottlerGuard } from 'src/guards/gql-throttler.guard';
|
||||||
import { SkipThrottle } from '@nestjs/throttler';
|
import { SkipThrottle } from '@nestjs/throttler';
|
||||||
|
import { GqlAdminGuard } from 'src/admin/guards/gql-admin.guard';
|
||||||
|
|
||||||
@UseGuards(GqlThrottlerGuard)
|
@UseGuards(GqlThrottlerGuard)
|
||||||
@Resolver(() => Shortcode)
|
@Resolver(() => Shortcode)
|
||||||
@@ -121,7 +122,7 @@ export class ShortcodeResolver {
|
|||||||
@Args({
|
@Args({
|
||||||
name: 'code',
|
name: 'code',
|
||||||
type: () => ID,
|
type: () => ID,
|
||||||
description: 'The shortcode to resolve',
|
description: 'The shortcode to remove',
|
||||||
})
|
})
|
||||||
code: string,
|
code: string,
|
||||||
) {
|
) {
|
||||||
|
|||||||
@@ -1,12 +1,13 @@
|
|||||||
import { mockDeep, mockReset } from 'jest-mock-extended';
|
import { mockDeep, mockReset } from 'jest-mock-extended';
|
||||||
import { PrismaService } from '../prisma/prisma.service';
|
import { PrismaService } from '../prisma/prisma.service';
|
||||||
import {
|
import {
|
||||||
|
INVALID_EMAIL,
|
||||||
SHORTCODE_INVALID_PROPERTIES_JSON,
|
SHORTCODE_INVALID_PROPERTIES_JSON,
|
||||||
SHORTCODE_INVALID_REQUEST_JSON,
|
SHORTCODE_INVALID_REQUEST_JSON,
|
||||||
SHORTCODE_NOT_FOUND,
|
SHORTCODE_NOT_FOUND,
|
||||||
SHORTCODE_PROPERTIES_NOT_FOUND,
|
SHORTCODE_PROPERTIES_NOT_FOUND,
|
||||||
} from 'src/errors';
|
} from 'src/errors';
|
||||||
import { Shortcode } from './shortcode.model';
|
import { Shortcode, ShortcodeWithUserEmail } from './shortcode.model';
|
||||||
import { ShortcodeService } from './shortcode.service';
|
import { ShortcodeService } from './shortcode.service';
|
||||||
import { UserService } from 'src/user/user.service';
|
import { UserService } from 'src/user/user.service';
|
||||||
import { AuthUser } from 'src/types/AuthUser';
|
import { AuthUser } from 'src/types/AuthUser';
|
||||||
@@ -97,6 +98,35 @@ const shortcodes = [
|
|||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
|
const shortcodesWithUserEmail = [
|
||||||
|
{
|
||||||
|
id: 'blablabla',
|
||||||
|
request: {
|
||||||
|
hello: 'there',
|
||||||
|
},
|
||||||
|
embedProperties: {
|
||||||
|
foo: 'bar',
|
||||||
|
},
|
||||||
|
creatorUid: user.uid,
|
||||||
|
createdOn: new Date(),
|
||||||
|
updatedOn: createdOn,
|
||||||
|
User: user,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'blablabla1',
|
||||||
|
request: {
|
||||||
|
hello: 'there',
|
||||||
|
},
|
||||||
|
embedProperties: {
|
||||||
|
foo: 'bar',
|
||||||
|
},
|
||||||
|
creatorUid: user.uid,
|
||||||
|
createdOn: new Date(),
|
||||||
|
updatedOn: createdOn,
|
||||||
|
User: user,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
describe('ShortcodeService', () => {
|
describe('ShortcodeService', () => {
|
||||||
describe('getShortCode', () => {
|
describe('getShortCode', () => {
|
||||||
test('should return a valid Shortcode with valid Shortcode ID', async () => {
|
test('should return a valid Shortcode with valid Shortcode ID', async () => {
|
||||||
@@ -441,4 +471,99 @@ describe('ShortcodeService', () => {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('deleteShortcode', () => {
|
||||||
|
test('should return true on successful deletion of Shortcode with valid inputs', async () => {
|
||||||
|
mockPrisma.shortcode.delete.mockResolvedValueOnce(mockEmbed);
|
||||||
|
|
||||||
|
const result = await shortcodeService.deleteShortcode(mockEmbed.id);
|
||||||
|
expect(result).toEqualRight(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should return SHORTCODE_NOT_FOUND error when Shortcode is invalid', async () => {
|
||||||
|
mockPrisma.shortcode.delete.mockRejectedValue('RecordNotFound');
|
||||||
|
|
||||||
|
expect(shortcodeService.deleteShortcode('invalid')).resolves.toEqualLeft(
|
||||||
|
SHORTCODE_NOT_FOUND,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('fetchAllShortcodes', () => {
|
||||||
|
test('should return list of Shortcodes with valid inputs and no cursor', async () => {
|
||||||
|
mockPrisma.shortcode.findMany.mockResolvedValueOnce(
|
||||||
|
shortcodesWithUserEmail,
|
||||||
|
);
|
||||||
|
|
||||||
|
const result = await shortcodeService.fetchAllShortcodes(
|
||||||
|
{
|
||||||
|
cursor: null,
|
||||||
|
take: 10,
|
||||||
|
},
|
||||||
|
user.email,
|
||||||
|
);
|
||||||
|
expect(result).toEqual(<ShortcodeWithUserEmail[]>[
|
||||||
|
{
|
||||||
|
id: shortcodes[0].id,
|
||||||
|
request: JSON.stringify(shortcodes[0].request),
|
||||||
|
properties: JSON.stringify(shortcodes[0].embedProperties),
|
||||||
|
createdOn: shortcodes[0].createdOn,
|
||||||
|
creator: {
|
||||||
|
uid: user.uid,
|
||||||
|
email: user.email,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: shortcodes[1].id,
|
||||||
|
request: JSON.stringify(shortcodes[1].request),
|
||||||
|
properties: JSON.stringify(shortcodes[1].embedProperties),
|
||||||
|
createdOn: shortcodes[1].createdOn,
|
||||||
|
creator: {
|
||||||
|
uid: user.uid,
|
||||||
|
email: user.email,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should return list of Shortcode with valid inputs and cursor', async () => {
|
||||||
|
mockPrisma.shortcode.findMany.mockResolvedValue([
|
||||||
|
shortcodesWithUserEmail[1],
|
||||||
|
]);
|
||||||
|
|
||||||
|
const result = await shortcodeService.fetchAllShortcodes(
|
||||||
|
{
|
||||||
|
cursor: 'blablabla',
|
||||||
|
take: 10,
|
||||||
|
},
|
||||||
|
user.email,
|
||||||
|
);
|
||||||
|
expect(result).toEqual(<ShortcodeWithUserEmail[]>[
|
||||||
|
{
|
||||||
|
id: shortcodes[1].id,
|
||||||
|
request: JSON.stringify(shortcodes[1].request),
|
||||||
|
properties: JSON.stringify(shortcodes[1].embedProperties),
|
||||||
|
createdOn: shortcodes[1].createdOn,
|
||||||
|
creator: {
|
||||||
|
uid: user.uid,
|
||||||
|
email: user.email,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should return an empty array for an invalid cursor', async () => {
|
||||||
|
mockPrisma.shortcode.findMany.mockResolvedValue([]);
|
||||||
|
|
||||||
|
const result = await shortcodeService.fetchAllShortcodes(
|
||||||
|
{
|
||||||
|
cursor: 'invalidcursor',
|
||||||
|
take: 10,
|
||||||
|
},
|
||||||
|
user.email,
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(result).toHaveLength(0);
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ import {
|
|||||||
SHORTCODE_PROPERTIES_NOT_FOUND,
|
SHORTCODE_PROPERTIES_NOT_FOUND,
|
||||||
} from 'src/errors';
|
} from 'src/errors';
|
||||||
import { UserDataHandler } from 'src/user/user.data.handler';
|
import { UserDataHandler } from 'src/user/user.data.handler';
|
||||||
import { Shortcode } from './shortcode.model';
|
import { Shortcode, ShortcodeWithUserEmail } from './shortcode.model';
|
||||||
import { Shortcode as DBShortCode } from '@prisma/client';
|
import { Shortcode as DBShortCode } from '@prisma/client';
|
||||||
import { PubSubService } from 'src/pubsub/pubsub.service';
|
import { PubSubService } from 'src/pubsub/pubsub.service';
|
||||||
import { UserService } from 'src/user/user.service';
|
import { UserService } from 'src/user/user.service';
|
||||||
@@ -180,7 +180,7 @@ export class ShortcodeService implements UserDataHandler, OnModuleInit {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Delete a ShortCode
|
* Delete a ShortCode created by User of uid
|
||||||
*
|
*
|
||||||
* @param shortcode ShortCode
|
* @param shortcode ShortCode
|
||||||
* @param uid User Uid
|
* @param uid User Uid
|
||||||
@@ -223,6 +223,26 @@ export class ShortcodeService implements UserDataHandler, OnModuleInit {
|
|||||||
return deletedShortCodes.count;
|
return deletedShortCodes.count;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Delete a Shortcode
|
||||||
|
*
|
||||||
|
* @param shortcodeID ID of Shortcode being deleted
|
||||||
|
* @returns Boolean on successful deletion
|
||||||
|
*/
|
||||||
|
async deleteShortcode(shortcodeID: string) {
|
||||||
|
try {
|
||||||
|
await this.prisma.shortcode.delete({
|
||||||
|
where: {
|
||||||
|
id: shortcodeID,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
return E.right(true);
|
||||||
|
} catch (error) {
|
||||||
|
return E.left(SHORTCODE_NOT_FOUND);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Update a created Shortcode
|
* Update a created Shortcode
|
||||||
* @param shortcodeID Shortcode ID
|
* @param shortcodeID Shortcode ID
|
||||||
@@ -263,4 +283,57 @@ export class ShortcodeService implements UserDataHandler, OnModuleInit {
|
|||||||
return E.left(SHORTCODE_NOT_FOUND);
|
return E.left(SHORTCODE_NOT_FOUND);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fetch all created ShortCodes
|
||||||
|
*
|
||||||
|
* @param args Pagination arguments
|
||||||
|
* @param userEmail User email
|
||||||
|
* @returns ShortcodeWithUserEmail
|
||||||
|
*/
|
||||||
|
async fetchAllShortcodes(
|
||||||
|
args: PaginationArgs,
|
||||||
|
userEmail: string | null = null,
|
||||||
|
) {
|
||||||
|
const shortCodes = await this.prisma.shortcode.findMany({
|
||||||
|
where: userEmail
|
||||||
|
? {
|
||||||
|
User: {
|
||||||
|
email: userEmail,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
: undefined,
|
||||||
|
orderBy: {
|
||||||
|
createdOn: 'desc',
|
||||||
|
},
|
||||||
|
skip: args.cursor ? 1 : 0,
|
||||||
|
take: args.take,
|
||||||
|
cursor: args.cursor ? { id: args.cursor } : undefined,
|
||||||
|
include: {
|
||||||
|
User: true,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const fetchedShortCodes: ShortcodeWithUserEmail[] = shortCodes.map(
|
||||||
|
(code) => {
|
||||||
|
return <ShortcodeWithUserEmail>{
|
||||||
|
id: code.id,
|
||||||
|
request: JSON.stringify(code.request),
|
||||||
|
properties:
|
||||||
|
code.embedProperties != null
|
||||||
|
? JSON.stringify(code.embedProperties)
|
||||||
|
: null,
|
||||||
|
createdOn: code.createdOn,
|
||||||
|
creator: code.User
|
||||||
|
? {
|
||||||
|
uid: code.User.uid,
|
||||||
|
email: code.User.email,
|
||||||
|
}
|
||||||
|
: null,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
return fetchedShortCodes;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ ENV PRODUCTION="true"
|
|||||||
ENV PORT=3170
|
ENV PORT=3170
|
||||||
ENV APP_PORT=${PORT}
|
ENV APP_PORT=${PORT}
|
||||||
ENV DB_URL=${DATABASE_URL}
|
ENV DB_URL=${DATABASE_URL}
|
||||||
CMD ["pnpm", "run", "start:prod"]
|
CMD ["pnpm", "run", "start:migrate:prod"]
|
||||||
EXPOSE 3170
|
EXPOSE 3170
|
||||||
|
|
||||||
FROM base_builder as fe_builder
|
FROM base_builder as fe_builder
|
||||||
|
|||||||
Reference in New Issue
Block a user