Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat/add org intivitation #107

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@
"watch": "yarn build && ./node_modules/.bin/tsc --build --watch",
"lint": "eslint \"./*.json\" \"packages/*/src/**/*.{ts,js,json}\" --fix",
"test": "jest --testTimeout 30000",
"test:one": "jest --testTimeout 30000 packages/nestjs-invitation/src/services/invitation.service.spec.ts",
"test:one": "jest --testTimeout 30000 packages/nestjs-org/src/listeners/invitation-accepted-listener.spec.ts",
"prepare": "husky install && yarn clean && yarn build",
"test:watch": "jest --watch",
"test:cov": "jest --coverage",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ import { MailerModule, MailerService } from '@nestjs-modules/mailer';

import { InvitationModule } from '../invitation.module';
import { InvitationGetUserEventAsync } from '../events/invitation-get-user.event';

import { InvitationEntityFixture } from './invitation/entities/invitation.entity.fixture';
import { InvitationAcceptedEventAsync } from '../events/invitation-accepted.event';
import { UserOtpEntityFixture } from './user/entities/user-otp-entity.fixture';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,12 @@ import { INestApplication } from '@nestjs/common';
import { UserFactory } from '@concepta/nestjs-user/src/seeding';
import { ConfigService, ConfigType } from '@nestjs/config';
import { OtpService } from '@concepta/nestjs-otp';
import { OtpInterface, UserInterface } from '@concepta/ts-common';
import {
INVITATION_MODULE_CATEGORY_ORG_KEY,
INVITATION_MODULE_CATEGORY_USER_KEY,
OtpInterface,
UserInterface,
} from '@concepta/ts-common';
import { EmailService } from '@concepta/nestjs-email';
import { SeedingSource } from '@concepta/typeorm-seeding';
import { getDataSourceToken } from '@nestjs/typeorm';
Expand All @@ -17,19 +22,19 @@ import { invitationDefaultConfig } from '../config/invitation-default.config';
import { InvitationFactory } from '../invitation.factory';
import { InvitationEntityInterface } from '../interfaces/invitation.entity.interface';
import { InvitationSettingsInterface } from '../interfaces/invitation-settings.interface';

import { AppModuleFixture } from '../__fixtures__/app.module.fixture';
import { InvitationEntityFixture } from '../__fixtures__/invitation/entities/invitation.entity.fixture';
import { UserEntityFixture } from '../__fixtures__/user/entities/user-entity.fixture';

describe('InvitationController (e2e)', () => {
const category = 'invitation';
const userCategory = INVITATION_MODULE_CATEGORY_USER_KEY;
const orgCategory = INVITATION_MODULE_CATEGORY_ORG_KEY;
const payload = { moreData: 'foo' };

let app: INestApplication;
let invitationFactory: InvitationFactory;
let seedingSource: SeedingSource;
let user: UserEntityFixture;
let invitation: InvitationEntityInterface;
let otpService: OtpService;
let configService: ConfigService;
let config: ConfigType<typeof invitationDefaultConfig>;
Expand Down Expand Up @@ -60,33 +65,84 @@ describe('InvitationController (e2e)', () => {
seedingSource,
});

const invitationFactory = new InvitationFactory({
invitationFactory = new InvitationFactory({
entity: InvitationEntityFixture,
seedingSource,
});

user = await userFactory.create();
invitation = await invitationFactory.create({ category, user });
});

afterEach(async () => {
jest.clearAllMocks();
return app ? await app.close() : undefined;
});

describe('Type: org', () => {
let invitation: InvitationEntityInterface;

beforeEach(async () => {
invitation = await invitationFactory.create({
category: orgCategory,
user,
});
});

it('POST invitation', async () => {
await createInvite(app, {
email: user.email,
category: orgCategory,
payload,
});
});

it('PATCH invitation-acceptance', async () => {
const { code } = invitation;

const otp = await createOtp(config, otpService, user, orgCategory);

const { passcode } = otp;

await supertest(app.getHttpServer())
.patch(`/invitation-acceptance/${code}`)
.send({
passcode,
payload: { newPassword: 'hOdv2A2h%' },
} as InvitationAcceptInviteDto)
.expect(200);
});
});

describe('Type: user', () => {
let invitation: InvitationEntityInterface;

beforeEach(async () => {
invitation = await invitationFactory.create({
category: userCategory,
user,
});
});

it('POST invitation', async () => {
await createInvite({ email: user.email, category, payload });
await createInvite(app, {
email: user.email,
category: userCategory,
payload,
});
});

it('POST invitation (create new user)', async () => {
await createInvite({ email: '[email protected]', category, payload });
await createInvite(app, {
email: '[email protected]',
category: userCategory,
payload,
});
});

it('POST invitation reattempt', async () => {
const invitationDto = await createInvite({
const invitationDto = await createInvite(app, {
email: '[email protected]',
category,
category: userCategory,
payload,
});

Expand All @@ -98,7 +154,7 @@ describe('InvitationController (e2e)', () => {
it('PATCH invitation-acceptance', async () => {
const { code } = invitation;

const otp = await createOtp(config, otpService, user, category);
const otp = await createOtp(config, otpService, user, userCategory);

const { passcode } = otp;

Expand All @@ -114,7 +170,7 @@ describe('InvitationController (e2e)', () => {
it('GET invitation-acceptance', async () => {
const { code } = invitation;

const otp = await createOtp(config, otpService, user, category);
const otp = await createOtp(config, otpService, user, userCategory);

const { passcode } = otp;

Expand All @@ -126,12 +182,12 @@ describe('InvitationController (e2e)', () => {
it('GET invitation', async () => {
const invitationCreateDto = {
email: user.email,
category,
category: userCategory,
payload,
} as InvitationCreateDto;
const invite1 = await createInvite(invitationCreateDto);
const invite2 = await createInvite(invitationCreateDto);
const invite3 = await createInvite(invitationCreateDto);
const invite1 = await createInvite(app, invitationCreateDto);
const invite2 = await createInvite(app, invitationCreateDto);
const invite3 = await createInvite(app, invitationCreateDto);

const response = await supertest(app.getHttpServer())
.get(`/invitation?s={"email": "${invitationCreateDto.email}"}`)
Expand All @@ -147,9 +203,9 @@ describe('InvitationController (e2e)', () => {
});

it('GET invitation/:id', async () => {
const invitation = await createInvite({
const invitation = await createInvite(app, {
email: user.email,
category,
category: userCategory,
payload,
});

Expand All @@ -163,9 +219,9 @@ describe('InvitationController (e2e)', () => {
});

it('DELETE invitation/:id', async () => {
const invitation = await createInvite({
const invitation = await createInvite(app, {
email: user.email,
category,
category: userCategory,
payload,
});

Expand All @@ -177,20 +233,21 @@ describe('InvitationController (e2e)', () => {
.get(`/invitation/${invitation.id}`)
.expect(404);
});

const createInvite = async (
invitationCreateDto: InvitationCreateDto,
): Promise<InvitationDto> => {
const response = await supertest(app.getHttpServer())
.post('/invitation')
.send(invitationCreateDto)
.expect(201);

return response.body as InvitationDto;
};
});
});

const createInvite = async (
app: INestApplication,
invitationCreateDto: InvitationCreateDto,
): Promise<InvitationDto> => {
const response = await supertest(app.getHttpServer())
.post('/invitation')
.send(invitationCreateDto)
.expect(201);

return response.body as InvitationDto;
};

const createOtp = async (
config: ConfigType<typeof invitationDefaultConfig>,
otpService: OtpService,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,7 @@ export class InvitationController
email,
category,
code: randomUUID(),
constraints: payload,
});

if (user !== undefined && invite !== undefined) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,9 @@ import {
import { AuditPostgresEmbed } from '@concepta/typeorm-common';

import { InvitationEntityInterface } from '../interfaces/invitation.entity.interface';
import { LiteralObject } from '@nestjs/common';

//TODO check this entity later
// TODO check this entity later
export abstract class InvitationPostgresEntity
implements InvitationEntityInterface
{
Expand All @@ -31,5 +32,8 @@ export abstract class InvitationPostgresEntity
@Column()
category!: string;

@Column({ type: 'jsonb' })
constraints?: LiteralObject;

user!: ReferenceIdInterface;
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import {
import { AuditSqlLiteEmbed } from '@concepta/typeorm-common';

import { InvitationEntityInterface } from '../interfaces/invitation.entity.interface';
import { LiteralObject } from '@nestjs/common';

//TODO check this entity later
export abstract class InvitationSqliteEntity
Expand All @@ -31,5 +32,8 @@ export abstract class InvitationSqliteEntity
@Column()
category!: string;

@Column({ type: 'simple-json', nullable: true })
constraints?: LiteralObject;

user!: ReferenceIdInterface;
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
import { Test, TestingModule } from '@nestjs/testing';
import { INestApplication } from '@nestjs/common';
import { getDataSourceToken } from '@nestjs/typeorm';
import { OtpInterface, UserInterface } from '@concepta/ts-common';
import {
INVITATION_MODULE_CATEGORY_USER_KEY,
OtpInterface,
UserInterface,
} from '@concepta/ts-common';
import { UserEntityInterface } from '@concepta/nestjs-user';
import { OtpService } from '@concepta/nestjs-otp';
import { UserFactory } from '@concepta/nestjs-user/src/seeding';
Expand All @@ -10,18 +14,16 @@ import { EmailService } from '@concepta/nestjs-email';
import { EventDispatchService } from '@concepta/nestjs-event';

import { INVITATION_MODULE_SETTINGS_TOKEN } from '../invitation.constants';

import { InvitationFactory } from '../invitation.factory';
import { InvitationSettingsInterface } from '../interfaces/invitation-settings.interface';
import { InvitationEntityInterface } from '../interfaces/invitation.entity.interface';
import { InvitationAcceptanceService } from './invitation-acceptance.service';

import { AppModuleFixture } from '../__fixtures__/app.module.fixture';
import { InvitationEntityFixture } from '../__fixtures__/invitation/entities/invitation.entity.fixture';
import { UserEntityFixture } from '../__fixtures__/user/entities/user-entity.fixture';

describe(InvitationAcceptanceService, () => {
const category = 'invitation';
const category = INVITATION_MODULE_CATEGORY_USER_KEY;

let spyEmailService: jest.SpyInstance;
let spyEventDispatchService: jest.SpyInstance;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ export class InvitationAcceptanceService extends BaseService<InvitationEntityInt
queryOptions?: QueryOptionsInterface,
): Promise<boolean> {
const invitationAcceptedEventAsync = new InvitationAcceptedEventAsync({
...invitationDto,
invitation: invitationDto,
data: payload,
queryOptions,
});
Expand All @@ -109,7 +109,7 @@ export class InvitationAcceptanceService extends BaseService<InvitationEntityInt
invitationAcceptedEventAsync,
);

return eventResult.some((it) => it === true);
return eventResult.every((it) => it === true);
}

async sendEmail(email: string): Promise<void> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,27 +2,25 @@ import { Repository } from 'typeorm';
import { Test, TestingModule } from '@nestjs/testing';
import { INestApplication } from '@nestjs/common';
import { getDataSourceToken } from '@nestjs/typeorm';

import { UserEntityInterface } from '@concepta/nestjs-user';
import { OtpService } from '@concepta/nestjs-otp';
import { EmailService } from '@concepta/nestjs-email';
import { UserFactory } from '@concepta/nestjs-user/src/seeding';
import { SeedingSource } from '@concepta/typeorm-seeding';
import { getDynamicRepositoryToken } from '@concepta/nestjs-typeorm-ext';
import { INVITATION_MODULE_CATEGORY_USER_KEY } from '@concepta/ts-common';

import { INVITATION_MODULE_INVITATION_ENTITY_KEY } from '../invitation.constants';

import { InvitationFactory } from '../invitation.factory';
import { InvitationSendService } from './invitation-send.service';
import { InvitationRevocationService } from './invitation-revocation.service';
import { InvitationEntityInterface } from '../interfaces/invitation.entity.interface';

import { AppModuleFixture } from '../__fixtures__/app.module.fixture';
import { InvitationEntityFixture } from '../__fixtures__/invitation/entities/invitation.entity.fixture';
import { UserEntityFixture } from '../__fixtures__/user/entities/user-entity.fixture';

describe(InvitationRevocationService, () => {
const category = 'invitation';
const category = INVITATION_MODULE_CATEGORY_USER_KEY;

let spyEmailService: jest.SpyInstance;

Expand Down
Loading