Commit 54b5f434 authored by Revant Nandgaonkar's avatar Revant Nandgaonkar

chore(communication-server): OAuth2 Client Module

Merge branch 'oauth2-client-module' into 'develop'

See merge request castlecraft/building-blocks!288
parents f5cbecbf babde4a2
......@@ -2,8 +2,8 @@ import { ConfigService } from '../config/config.service';
import { MongoConnectionOptions } from 'typeorm/driver/mongodb/MongoConnectionOptions';
import { TokenCache } from '../auth/entities/token-cache/token-cache.entity';
import { EmailAccount } from '../email/entities/email-account/email-account.entity';
import { SocialKey } from '../oauth2-client/entities/social-key/social-key.entity';
import { SocialToken } from '../oauth2-client/entities/social-token/social-token.entity';
import { OAuth2Provider } from '../oauth2-client/entities/oauth2-provider/oauth2-provider.entity';
import { OAuth2Token } from '../oauth2-client/entities/oauth2-token/oauth2-token.entity';
import { SMSGateway } from '../smsmessage/entities/sms-gateway/sms-gateway.entity';
import { ServerSettings } from '../system-settings/entities/server-settings/server-settings.entity';
import { QueueLog } from '../system-settings/entities/queue-log/queue-log.entity';
......@@ -23,8 +23,8 @@ export const TYPEORM_CONNECTION: MongoConnectionOptions = {
entities: [
TokenCache,
EmailAccount,
SocialKey,
SocialToken,
OAuth2Provider,
OAuth2Token,
SMSGateway,
ServerSettings,
QueueLog,
......
import { Oauth2ProviderAggregateService } from './oauth2-provider-aggregate/oauth2-provider-aggregate.service';
export const OAuth2ClientAggregates = [Oauth2ProviderAggregateService];
import { Test, TestingModule } from '@nestjs/testing';
import { Oauth2ProviderAggregateService } from './oauth2-provider-aggregate.service';
describe('Oauth2ProviderAggregateService', () => {
let service: Oauth2ProviderAggregateService;
beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
providers: [
{
provide: Oauth2ProviderAggregateService,
useValue: {},
},
],
}).compile();
service = module.get<Oauth2ProviderAggregateService>(
Oauth2ProviderAggregateService,
);
});
it('should be defined', () => {
expect(service).toBeDefined();
});
});
import { Injectable, NotFoundException } from '@nestjs/common';
import { AggregateRoot } from '@nestjs/cqrs';
import { OAuth2ProviderDto } from '../../policies/oauth2-provider-dto/oauth2-provider.dto';
import { OAuth2ProviderAddedEvent } from '../../events/oauth2-provider-added/oauth2-provider-added.event';
import { OAuth2ProviderRemovedEvent } from '../../events/oauth2-provider-removed/oauth2-provider-removed.event';
import { OAuth2ProviderService } from '../../entities/oauth2-provider/oauth2-provider.service';
import { OAuth2Provider } from '../../entities/oauth2-provider/oauth2-provider.entity';
@Injectable()
export class Oauth2ProviderAggregateService extends AggregateRoot {
constructor(private readonly oauth2Provider: OAuth2ProviderService) {
super();
}
async addProvider(payload: OAuth2ProviderDto) {
const provider = Object.assign(new OAuth2Provider(), payload);
this.apply(new OAuth2ProviderAddedEvent(provider));
}
async removeProvider(uuid: string) {
const provider = await this.oauth2Provider.findOne({ uuid });
if (!provider) throw new NotFoundException({ uuid });
this.apply(new OAuth2ProviderRemovedEvent(provider));
}
async retrieveProvider(uuid: string) {
const provider = await this.oauth2Provider.findOne({ uuid });
if (!provider) throw new NotFoundException({ uuid });
return provider;
}
async updateProvider(uuid: string, payload: OAuth2ProviderDto) {
const provider = await this.oauth2Provider.findOne({ uuid });
if (!provider) throw new NotFoundException({ uuid });
const updatedProvider = Object.assign(provider, payload);
this.apply(new OAuth2ProviderAddedEvent(updatedProvider));
}
async list(offset: number, limit: number, search?: string, sort?: string) {
return this.oauth2Provider.list(offset, limit);
}
}
import { ICommand } from '@nestjs/cqrs';
import { OAuth2ProviderDto } from '../../policies/oauth2-provider-dto/oauth2-provider.dto';
export class AddOAuth2ProviderCommand implements ICommand {
constructor(public readonly payload: OAuth2ProviderDto) {}
}
import { CommandHandler, ICommandHandler, EventPublisher } from '@nestjs/cqrs';
import { AddOAuth2ProviderCommand } from './add-oauth2-provider.command';
import { Oauth2ProviderAggregateService } from '../../aggregates/oauth2-provider-aggregate/oauth2-provider-aggregate.service';
@CommandHandler(AddOAuth2ProviderCommand)
export class AddOAuth2ProviderHandler
implements ICommandHandler<AddOAuth2ProviderCommand> {
constructor(
private publisher: EventPublisher,
private manager: Oauth2ProviderAggregateService,
) {}
async execute(command: AddOAuth2ProviderCommand) {
const { payload } = command;
const aggregate = this.publisher.mergeObjectContext(this.manager);
await aggregate.addProvider(payload);
aggregate.commit();
}
}
import { AddOAuth2ProviderHandler } from './add-oauth2-provider/add-oauth2-provider.handler';
import { RemoveOAuth2ProviderHandler } from './remove-oauth2-provider/remove-oauth2-provider.handler';
import { UpdateOAuth2ProviderHandler } from './update-oauth2-provider/update-oauth2-provider.handler';
export const OAuth2ClientCommandHandlers = [
AddOAuth2ProviderHandler,
RemoveOAuth2ProviderHandler,
UpdateOAuth2ProviderHandler,
];
import { ICommand } from '@nestjs/cqrs';
export class RemoveOAuth2ProviderCommand implements ICommand {
constructor(
public readonly providerUuid: string,
public readonly actorUuid: string,
) {}
}
import { CommandHandler, ICommandHandler, EventPublisher } from '@nestjs/cqrs';
import { RemoveOAuth2ProviderCommand } from './remove-oauth2-provider.command';
import { Oauth2ProviderAggregateService } from '../../aggregates/oauth2-provider-aggregate/oauth2-provider-aggregate.service';
@CommandHandler(RemoveOAuth2ProviderCommand)
export class RemoveOAuth2ProviderHandler
implements ICommandHandler<RemoveOAuth2ProviderCommand> {
constructor(
private publisher: EventPublisher,
private manager: Oauth2ProviderAggregateService,
) {}
async execute(command: RemoveOAuth2ProviderCommand) {
// TODO: record actorUuid from command
const { providerUuid } = command;
const aggregate = this.publisher.mergeObjectContext(this.manager);
await aggregate.removeProvider(providerUuid);
aggregate.commit();
}
}
import { ICommand } from '@nestjs/cqrs';
import { OAuth2ProviderDto } from '../../policies/oauth2-provider-dto/oauth2-provider.dto';
export class UpdateOAuth2ProviderCommand implements ICommand {
constructor(
public readonly providerUuid: string,
public readonly payload: OAuth2ProviderDto,
) {}
}
import { CommandHandler, ICommandHandler, EventPublisher } from '@nestjs/cqrs';
import { UpdateOAuth2ProviderCommand } from './update-oauth2-provider.command';
import { Oauth2ProviderAggregateService } from '../../aggregates/oauth2-provider-aggregate/oauth2-provider-aggregate.service';
@CommandHandler(UpdateOAuth2ProviderCommand)
export class UpdateOAuth2ProviderHandler
implements ICommandHandler<UpdateOAuth2ProviderCommand> {
constructor(
private publisher: EventPublisher,
private manager: Oauth2ProviderAggregateService,
) {}
async execute(command: UpdateOAuth2ProviderCommand) {
const { providerUuid, payload } = command;
const aggregate = this.publisher.mergeObjectContext(this.manager);
await aggregate.updateProvider(providerUuid, payload);
aggregate.commit();
}
}
import { Test, TestingModule } from '@nestjs/testing';
import { HttpService } from '@nestjs/common';
import { QueryBus, CommandBus } from '@nestjs/cqrs';
import { Reflector } from '@nestjs/core';
import { Oauth2ProviderController } from './oauth2-provider.controller';
import { TokenGuard } from '../../../auth/guards/token.guard';
import { RoleGuard } from '../../../auth/guards/role.guard';
import { ServerSettingsService } from '../../../system-settings/entities/server-settings/server-settings.service';
import { TokenCacheService } from '../../../auth/entities/token-cache/token-cache.service';
describe('Oauth2Provider Controller', () => {
let controller: Oauth2ProviderController;
beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
providers: [
{ provide: CommandBus, useValue: {} },
{ provide: QueryBus, useValue: {} },
{ provide: Reflector, useValue: {} },
{ provide: HttpService, useValue: {} },
{ provide: ServerSettingsService, useValue: {} },
{ provide: TokenCacheService, useValue: {} },
],
controllers: [Oauth2ProviderController],
})
.overrideGuard(TokenGuard)
.useValue({})
.overrideGuard(RoleGuard)
.useValue({})
.compile();
controller = module.get<Oauth2ProviderController>(Oauth2ProviderController);
});
it('should be defined', () => {
expect(controller).toBeDefined();
});
});
import {
Controller,
Post,
Get,
Body,
Param,
Req,
UseGuards,
Query,
UsePipes,
ValidationPipe,
} from '@nestjs/common';
import { CommandBus, QueryBus } from '@nestjs/cqrs';
import { OAuth2ProviderDto } from '../../policies/oauth2-provider-dto/oauth2-provider.dto';
import { AddOAuth2ProviderCommand } from '../../commands/add-oauth2-provider/add-oauth2-provider.command';
import { RemoveOAuth2ProviderCommand } from '../../commands/remove-oauth2-provider/remove-oauth2-provider.command';
import { TokenGuard } from '../../../auth/guards/token.guard';
import { RoleGuard } from '../../../auth/guards/role.guard';
import { Roles } from '../../../auth/decorators/roles.decorator';
import { ADMINISTRATOR } from '../../../constants/app-strings';
import { UpdateOAuth2ProviderCommand } from '../../commands/update-oauth2-provider/update-oauth2-provider.command';
import { ListOAuth2ProviderQuery } from '../../queries/list-oauth2-providers/list-oauth2-providers.query';
import { RetrieveOAuth2ProviderQuery } from '../../queries/retrieve-oauth2-provider/retrieve-oauth2-provider.query';
@Controller('oauth2_provider')
export class Oauth2ProviderController {
constructor(
private readonly commandBus: CommandBus,
private readonly queryBus: QueryBus,
) {}
@Post('v1/add_provider')
@Roles(ADMINISTRATOR)
@UseGuards(TokenGuard, RoleGuard)
@UsePipes(ValidationPipe)
async addProvider(@Body() payload: OAuth2ProviderDto) {
return await this.commandBus.execute(new AddOAuth2ProviderCommand(payload));
}
@Post('v1/remove_provider/:uuid')
@Roles(ADMINISTRATOR)
@UseGuards(TokenGuard, RoleGuard)
async removeProvider(@Param('uuid') uuid, @Req() req) {
const user = req.token.sub;
return await this.commandBus.execute(
new RemoveOAuth2ProviderCommand(uuid, user),
);
}
@Post('v1/update_provider/:uuid')
@Roles(ADMINISTRATOR)
@UseGuards(TokenGuard, RoleGuard)
@UsePipes(ValidationPipe)
async updateProvider(
@Param('uuid') uuid,
@Body() payload: OAuth2ProviderDto,
) {
return await this.commandBus.execute(
new UpdateOAuth2ProviderCommand(uuid, payload),
);
}
@Get('v1/retrieve_provider/:uuid')
@UseGuards(TokenGuard)
async retrieveProvider(@Param('uuid') uuid) {
return await this.queryBus.execute(new RetrieveOAuth2ProviderQuery(uuid));
}
@Get('v1/list')
@UseGuards(TokenGuard)
async list(
@Query('offset') offset: number,
@Query('limit') limit: number,
@Query('search') search?: string,
@Query('sort') sort?: string,
) {
return await this.queryBus.execute(
new ListOAuth2ProviderQuery(offset, limit, search, sort),
);
}
}
import { OAuth2ProviderService } from './oauth2-provider/oauth2-provider.service';
import { OAuth2TokenService } from './oauth2-token/oauth2-token.service';
export const OAuth2ClientEntityProviders = [
OAuth2ProviderService,
OAuth2TokenService,
];
......@@ -2,7 +2,7 @@ import { Column, Entity, BaseEntity, ObjectID, ObjectIdColumn } from 'typeorm';
import * as uuidv4 from 'uuid/v4';
@Entity()
export class SocialKey extends BaseEntity {
export class OAuth2Provider extends BaseEntity {
@ObjectIdColumn()
_id: ObjectID;
......
import { Test, TestingModule } from '@nestjs/testing';
import { getRepositoryToken } from '@nestjs/typeorm';
import { SocialKey } from './social-key.entity';
import { SocialKeyService } from './social-key.service';
import { OAuth2Provider } from './oauth2-provider.entity';
import { OAuth2ProviderService } from './oauth2-provider.service';
describe('Social Key', () => {
let service: SocialKeyService;
describe('OAuth2ProviderService', () => {
let service: OAuth2ProviderService;
beforeAll(async () => {
const module: TestingModule = await Test.createTestingModule({
providers: [
SocialKeyService,
OAuth2ProviderService,
{
provide: getRepositoryToken(SocialKey),
provide: getRepositoryToken(OAuth2Provider),
useValue: {}, // provide mock values
},
],
}).compile();
service = module.get<SocialKeyService>(SocialKeyService);
service = module.get<OAuth2ProviderService>(OAuth2ProviderService);
});
it('should be defined', () => {
expect(service).toBeDefined();
......
import { Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { MongoRepository } from 'typeorm';
import { OAuth2Provider } from './oauth2-provider.entity';
@Injectable()
export class OAuth2ProviderService {
constructor(
@InjectRepository(OAuth2Provider)
private readonly oauth2ProviderRepository: MongoRepository<OAuth2Provider>,
) {}
async save(params) {
return await this.oauth2ProviderRepository.save(params);
}
async find(): Promise<OAuth2Provider[]> {
return await this.oauth2ProviderRepository.find();
}
async findOne(params) {
return await this.oauth2ProviderRepository.findOne(params);
}
async update(query, params) {
return await this.oauth2ProviderRepository.update(query, params);
}
async count() {
return await this.oauth2ProviderRepository.count();
}
async list(skip: number, take: number) {
const providers = await this.oauth2ProviderRepository.find({ skip, take });
return {
docs: providers,
length: await this.oauth2ProviderRepository.count(),
offset: skip,
};
}
}
......@@ -2,13 +2,13 @@ import { Entity, BaseEntity, ObjectIdColumn, Column, ObjectID } from 'typeorm';
import * as uuidv4 from 'uuid/v4';
@Entity()
export class SocialToken extends BaseEntity {
export class OAuth2Token extends BaseEntity {
@ObjectIdColumn()
_id: ObjectID;
@Column()
uuid: string;
@Column()
socialKey: string; // uuid of Social Key
oauth2Provider: string; // uuid of Social Key
@Column()
user: string; // uuid of request user;
@Column()
......
import { Test, TestingModule } from '@nestjs/testing';
import { OAuth2TokenService } from './oauth2-token.service';
import { getRepositoryToken } from '@nestjs/typeorm';
import { OAuth2Token } from './oauth2-token.entity';
describe('Oauth2TokenService', () => {
let service: OAuth2TokenService;
beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
providers: [
OAuth2TokenService,
{ provide: getRepositoryToken(OAuth2Token), useValue: {} },
],
}).compile();
service = module.get<OAuth2TokenService>(OAuth2TokenService);
});
it('should be defined', () => {
expect(service).toBeDefined();
});
});
import { Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { MongoRepository } from 'typeorm';
import { SocialKey } from './social-key.entity';
import { OAuth2Token } from './oauth2-token.entity';
@Injectable()
export class SocialKeyService {
export class OAuth2TokenService {
constructor(
@InjectRepository(SocialKey)
private readonly socialKeyRepository: MongoRepository<SocialKey>,
@InjectRepository(OAuth2Token)
private readonly oauth2TokenRepository: MongoRepository<OAuth2Token>,
) {}
async save(params) {
return await this.socialKeyRepository.save(params);
return await this.oauth2TokenRepository.save(params);
}
async find(): Promise<SocialKey[]> {
return await this.socialKeyRepository.find();
async find(): Promise<OAuth2Token[]> {
return await this.oauth2TokenRepository.find();
}
async findOne(params) {
return await this.socialKeyRepository.findOne(params);
return await this.oauth2TokenRepository.findOne(params);
}
async update(query, params) {
return await this.socialKeyRepository.update(query, params);
return await this.oauth2TokenRepository.update(query, params);
}
async count() {
return await this.socialKeyRepository.count();
return await this.oauth2TokenRepository.count();
}
async paginate(skip: number, take: number) {
return await this.socialKeyRepository.find({ skip, take });
return await this.oauth2TokenRepository.find({ skip, take });
}
}
import { OAuth2ProviderAddedHandler } from './oauth2-provider-added/oauth2-provider-added.handler';
import { OAuth2ProviderRemovedHandler } from './oauth2-provider-removed/oauth2-provider-removed.handler';
import { OAuth2ProviderUpdatedHandler } from './oauth2-provider-updated/oauth2-provider-updated.handler';
export const OAuth2ClientEventHandlers = [
OAuth2ProviderAddedHandler,
OAuth2ProviderRemovedHandler,
OAuth2ProviderUpdatedHandler,
];
import { IEvent } from '@nestjs/cqrs';
import { OAuth2Provider } from '../../entities/oauth2-provider/oauth2-provider.entity';
export class OAuth2ProviderAddedEvent implements IEvent {
constructor(public readonly provider: OAuth2Provider) {}
}
import { Test } from '@nestjs/testing';
import { CqrsModule, EventBus } from '@nestjs/cqrs';
import { OAuth2ProviderAddedHandler } from './oauth2-provider-added.handler';
import { OAuth2ProviderAddedEvent } from './oauth2-provider-added.event';
import { OAuth2Provider } from '../../entities/oauth2-provider/oauth2-provider.entity';
describe('Event: OAuth2ProviderAddedHandler', () => {
let eventBus$: EventBus;
let eventHandler: OAuth2ProviderAddedHandler;
const mockProvider = new OAuth2Provider();
beforeEach(async () => {
const module = await Test.createTestingModule({
imports: [CqrsModule],
providers: [
OAuth2ProviderAddedHandler,
{
provide: EventBus,
useFactory: () => jest.fn(),
},
],
}).compile();
eventBus$ = module.get<EventBus>(EventBus);
eventHandler = module.get<OAuth2ProviderAddedHandler>(
OAuth2ProviderAddedHandler,
);
});
it('should be defined', () => {
expect(eventBus$).toBeDefined();
expect(eventHandler).toBeDefined();
});
it('should save OAuth2Provider', async () => {
eventBus$.publish = jest.fn(() => {});
mockProvider.save = jest.fn(() => Promise.resolve(mockProvider));
await eventHandler.handle(new OAuth2ProviderAddedEvent(mockProvider));
expect(mockProvider.save).toHaveBeenCalledTimes(1);
});
});
import { EventsHandler, IEventHandler } from '@nestjs/cqrs';
import { OAuth2ProviderAddedEvent } from './oauth2-provider-added.event';
@EventsHandler(OAuth2ProviderAddedEvent)
export class OAuth2ProviderAddedHandler
implements IEventHandler<OAuth2ProviderAddedEvent> {
handle(event: OAuth2ProviderAddedEvent) {
const { provider } = event;
provider
.save()
.then(success => {})
.catch(error => {});
}
}
import { IEvent } from '@nestjs/cqrs';
import { OAuth2Provider } from '../../entities/oauth2-provider/oauth2-provider.entity';
export class OAuth2ProviderRemovedEvent implements IEvent {
constructor(public readonly provider: OAuth2Provider) {}
}
import { Test } from '@nestjs/testing';
import { CqrsModule, EventBus } from '@nestjs/cqrs';
import { OAuth2Provider } from '../../entities/oauth2-provider/oauth2-provider.entity';
import { OAuth2ProviderRemovedHandler } from './oauth2-provider-removed.handler';
import { OAuth2ProviderRemovedEvent } from './oauth2-provider-removed.event';
describe('Event: OAuth2ProviderRemovedHandler', () => {
let eventBus$: EventBus;
let eventHandler: OAuth2ProviderRemovedHandler;