Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12,216 changes: 11,157 additions & 1,059 deletions package-lock.json

Large diffs are not rendered by default.

10 changes: 5 additions & 5 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
"private": true,
"version": "1.0.0",
"scripts": {
"build-ts": "tsc",
"build-ts": "tsc -p tsconfig.prod.json",
"build": "npm run build-ts && npm run lint",
"dev": "cross-env NODE_ENV=dev ts-node-dev --ignore-watch node_modules --inspect=0.0.0.0:9267 ./src/api/server.ts",
"lint": "tsc --noEmit && eslint \"**/*.{js,ts}\" --quiet --fix",
Expand All @@ -30,16 +30,16 @@
"@types/lusca": "^1.6.1",
"@types/node": "^13.13.4",
"@types/supertest": "^2.0.9",
"@typescript-eslint/eslint-plugin": "^2.31.0",
"@typescript-eslint/parser": "^2.31.0",
"@typescript-eslint/eslint-plugin": "^5.13.0",
"@typescript-eslint/parser": "^5.13.0",
"cross-env": "^7.0.2",
"errorhandler": "^1.5.1",
"eslint": "^6.8.0",
"eslint": "^8.10.0",
"jest": "^26.0.0",
"nodemon": "^2.0.3",
"supertest": "^4.0.2",
"ts-jest": "^25.4.0",
"ts-node-dev": "^1.0.0-pre.44",
"typescript": "^3.8.3"
"typescript": "^3.9.10"
}
}
15 changes: 15 additions & 0 deletions src/api/app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,18 @@ import bodyParser from "body-parser";
import compression from "compression";
import express from "express";
import lusca from "lusca";
import { InMemoryEventBus } from "../contexts/core/InMemoryEventBus";

// Controllers (route handlers)
import * as healthController from "./controllers/health";
import { registerGenialyRouter } from "./genially/genially.router";
import { registerCounterGenialysRouter } from "./geniallyCounter/geniallysCounter.route";
import { registerSubscribersGeniallysCounter } from "./geniallyCounter/subcribersDomainEvents";

// Create EventBus in memory
const eventBus = new InMemoryEventBus();
// Register Subscribers in applications
registerSubscribersGeniallysCounter(eventBus);

// Create Express server
const app = express();
Expand All @@ -20,4 +29,10 @@ app.use(lusca.xssProtection(true));
// Primary app routes
app.get("/", healthController.check);

// Routes of Genially
app.use("/api", registerGenialyRouter(eventBus));

// Routes of Counter Geniallys
app.use("/api", registerCounterGenialysRouter());

export default app;
16 changes: 16 additions & 0 deletions src/api/genially/controllers/DeleteGeniallyController.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { Request, Response } from "express";
import DeleteGeniallyService from "../../../contexts/core/genially/application/DeleteGeniallyService";

export class DeleteGeniallyController {
constructor(private deleteService: DeleteGeniallyService) {}

public async execute(req: Request, res: Response) {
try {
const { id } = req.params;
await this.deleteService.execute(id);
res.status(200).send("deleted successful");
} catch (error) {
res.status(500).send({ error: error.message });
}
}
}
24 changes: 24 additions & 0 deletions src/api/genially/controllers/GeniallyPostController.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import { Request, Response } from "express";
import CreateGeniallyService from "../../../contexts/core/genially/application/CreateGeniallyService";

export class GeniallyPostController {
constructor(private createGeniallyService: CreateGeniallyService) {}

public async execute(req: Request, res: Response) {
try {
const { id } = req.params;
const { name, description } = req.body;
const genially = await this.createGeniallyService.execute({
id,
name,
description,
});

res
.status(201)
.json({ id, name, description, createAt: genially.createdAt });
} catch (error) {
res.status(500).json({ error: error.message });
}
}
}
17 changes: 17 additions & 0 deletions src/api/genially/controllers/RenameGeniallyController.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { Request, Response } from "express";
import RenameGeniallyService from "../../../contexts/core/genially/application/RenameGeniallyService";

export class RenameGeniallyController {
constructor(private renameService: RenameGeniallyService) {}

public async execute(req: Request, res: Response) {
try {
const { id } = req.params;
const { name } = req.body;
await this.renameService.execute(id, name);
res.status(200).send("rename successful");
} catch (error) {
res.status(500).send({ error: error.message });
}
}
}
41 changes: 41 additions & 0 deletions src/api/genially/genially.router.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import { Request, Response, Router } from "express";
import CreateGeniallyService from "../../contexts/core/genially/application/CreateGeniallyService";
import DeleteGeniallyService from "../../contexts/core/genially/application/DeleteGeniallyService";
import RenameGeniallyService from "../../contexts/core/genially/application/RenameGeniallyService";
import InMemoryGeniallyRepository from "../../contexts/core/genially/infrastructure/InMemoryGeniallyRepository";
import { InMemoryEventBus } from "../../contexts/core/InMemoryEventBus";
import { DeleteGeniallyController } from "./controllers/DeleteGeniallyController";
import { GeniallyPostController } from "./controllers/GeniallyPostController";
import { RenameGeniallyController } from "./controllers/RenameGeniallyController";

export function registerGenialyRouter(eventBus: InMemoryEventBus): Router {
const geniallyRouter = Router();

const geniallyRepository = new InMemoryGeniallyRepository();

//Create Genially Router
const createGeniallyService = new CreateGeniallyService(
geniallyRepository,
eventBus
);
const genialyPostControler = new GeniallyPostController(
createGeniallyService
);
geniallyRouter.post("/genially/:id", (req: Request, res: Response) =>
genialyPostControler.execute(req, res)
);

const deleteGeniallyService = new DeleteGeniallyService(geniallyRepository);
const deleteControler = new DeleteGeniallyController(deleteGeniallyService);
geniallyRouter.delete("/genially/:id", (req: Request, res: Response) =>
deleteControler.execute(req, res)
);

const renameGeniallyService = new RenameGeniallyService(geniallyRepository);
const renameControler = new RenameGeniallyController(renameGeniallyService);
geniallyRouter.put("/genially/rename/:id", (req: Request, res: Response) =>
renameControler.execute(req, res)
);

return geniallyRouter;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { Request, Response } from "express";
import { SearchGeniallysCounterService } from "../../../contexts/core/geniallysCounter/application/SearchGeniallysCounterService";

export class GeniallysCounterGetController {
constructor(private searchCounterService: SearchGeniallysCounterService) {}

public async execute(req: Request, res: Response) {
try {
const counter = await this.searchCounterService.execute();
res.status(200).json({ totalGeniallys: counter });
} catch (error) {
res.status(400).json({ errorMesagge: error.message });
}
}
}
18 changes: 18 additions & 0 deletions src/api/geniallyCounter/geniallysCounter.route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { Request, Response, Router } from "express";
import { SearchGeniallysCounterService } from "../../contexts/core/geniallysCounter/application/SearchGeniallysCounterService";
import { GeniallysCounterGetController } from "./controller/GeniallysCounterGetController";
import { geniallysCounterRepository } from "./subcribersDomainEvents";

export function registerCounterGenialysRouter(): Router {
const counterRouter = Router();

//Create Counter Genially Router
const counterController = new GeniallysCounterGetController(
new SearchGeniallysCounterService(geniallysCounterRepository)
);
counterRouter.get("/counter-geniallys/", (req: Request, res: Response) =>
counterController.execute(req, res)
);

return counterRouter;
}
19 changes: 19 additions & 0 deletions src/api/geniallyCounter/subcribersDomainEvents.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { IncrementGeniallysCounter } from "../../contexts/core/geniallysCounter/application/IncrementGeniallysCounter";
import { IncrementGeniallyWhenGenialyCreated } from "../../contexts/core/geniallysCounter/application/IncrementGeniallyWhenGenialyCreated";
import { InMemoryGeniallysCounterRepository } from "../../contexts/core/geniallysCounter/infrastructure/InMemoryGeniallysCounterRepository";
import { InMemoryEventBus } from "../../contexts/core/InMemoryEventBus";

export const geniallysCounterRepository =
new InMemoryGeniallysCounterRepository();

export function registerSubscribersGeniallysCounter(
eventBus: InMemoryEventBus
): void {
const incrementCounterGeniallyService = new IncrementGeniallysCounter(
geniallysCounterRepository
);
const incrementGeniallysCounterSubscriber =
new IncrementGeniallyWhenGenialyCreated(incrementCounterGeniallyService);

eventBus.addSubscribers([incrementGeniallysCounterSubscriber]);
}
10 changes: 10 additions & 0 deletions src/contexts/core/DomainEvent.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
export class DomainEvent {
readonly eventName: string;
readonly ocurredOn: Date;
readonly eventCreatorEntityId: string;
constructor(name: string, entityCreatorId: string, ocurredOn?: Date) {
this.eventName = name;
this.ocurredOn = ocurredOn || new Date();
this.eventCreatorEntityId = entityCreatorId;
}
}
31 changes: 31 additions & 0 deletions src/contexts/core/InMemoryEventBus.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { DomainEvent } from "./DomainEvent";
import { Subscriber } from "./Subscriber";

export type EventName = string;

export class InMemoryEventBus {
private subscribersMap: Map<EventName, Subscriber[]> = new Map();

public async publishEvent(event: DomainEvent): Promise<void> {
const subscribersInBus = this.subscribersMap.get(event.eventName);
if (subscribersInBus) {
subscribersInBus.map((subscriber) => subscriber.executeService(event));
}
}

public addSubscribers(subcribers: Subscriber[]): void {
subcribers.map((subscriber) => this.registerSuncriber(subscriber));
}

private registerSuncriber(subscriber: Subscriber): void {
const eventsNames = subscriber.subscribedTo();
for (const name of eventsNames) {
//
if (this.subscribersMap.has(name)) {
this.subscribersMap.get(name).push(subscriber);
} else {
this.subscribersMap.set(name, [subscriber]);
}
}
}
}
7 changes: 7 additions & 0 deletions src/contexts/core/Subscriber.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { DomainEvent } from "./DomainEvent";
import { EventName } from "./InMemoryEventBus";

export interface Subscriber {
subscribedTo(): EventName[];
executeService(event: DomainEvent): Promise<void>;
}
16 changes: 14 additions & 2 deletions src/contexts/core/genially/application/CreateGeniallyService.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
import { InMemoryEventBus } from "../../InMemoryEventBus";
import Genially from "../domain/Genially";
import { GeniallyCreatedDomainEvent } from "../domain/GeniallyCreatedDomainEvent";
import { GeniallyDescription } from "../domain/GeniallyDescription";
import { GeniallyName } from "../domain/GeniallyName";
import GeniallyRepository from "../domain/GeniallyRepository";

type CreateGeniallyServiceRequest = {
Expand All @@ -8,15 +12,23 @@ type CreateGeniallyServiceRequest = {
};

export default class CreateGeniallyService {
constructor(private repository: GeniallyRepository) {}
constructor(
private repository: GeniallyRepository,
private eventBus: InMemoryEventBus
) {}

public async execute(req: CreateGeniallyServiceRequest): Promise<Genially> {
const { id, name, description } = req;

const genially = new Genially(id, name, description);
const genially = new Genially(
id,
new GeniallyName(name),
new GeniallyDescription(description)
);

await this.repository.save(genially);

this.eventBus.publishEvent(new GeniallyCreatedDomainEvent(genially.id));
return genially;
}
}
14 changes: 12 additions & 2 deletions src/contexts/core/genially/application/DeleteGeniallyService.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,17 @@
import Genially from "../domain/Genially";
import GeniallyNotExist from "../domain/GeniallyNotExist";
import GeniallyRepository from "../domain/GeniallyRepository";

export default class DeleteGeniallyService {
public async execute(): Promise<Genially> {
return undefined;
constructor(private repository: GeniallyRepository) {}

public async execute(id: string): Promise<Genially> {
const genially = await this.repository.find(id);
if (!genially) {
throw new GeniallyNotExist(id);
}
genially.deleteFromDate(new Date());
await this.repository.save(genially);
return genially;
}
}
15 changes: 13 additions & 2 deletions src/contexts/core/genially/application/RenameGeniallyService.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,18 @@
import Genially from "../domain/Genially";
import { GeniallyName } from "../domain/GeniallyName";
import GeniallyNotExist from "../domain/GeniallyNotExist";
import GeniallyRepository from "../domain/GeniallyRepository";

export default class RenameGeniallyService {
public async execute(): Promise<Genially> {
return undefined;
constructor(private repository: GeniallyRepository) {}

public async execute(id: string, newName: string): Promise<Genially> {
const genially = await this.repository.find(id);
if (!genially) {
throw new GeniallyNotExist(id);
}
genially.rename(new GeniallyName(newName));
await this.repository.save(genially);
return genially;
}
}
13 changes: 13 additions & 0 deletions src/contexts/core/genially/domain/Errors.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
export class GeniallyNameInvalid extends Error {
constructor(name: string) {
super(`name invalid :"${name}" su longitud debe ser de 3 a 20 caracteres`);
}
}

export class GeniallyDescriptionInvalid extends Error {
constructor(description: string) {
super(
`Description invalid :"${description}" su longitud debe ser de maximo 125 caracteres`
);
}
}
Loading