Skip to content

feat: Control plane #6

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

Open
wants to merge 8 commits into
base: main
Choose a base branch
from
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
2 changes: 2 additions & 0 deletions src/services/control-plane/adapters/drivens/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export * from './repo-querier-local-adapter';
export * from './repo-querier-stub-adapter';
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { userManagerProxy, userPermissionManagerProxy } from "../../../repository/app/composition-root";
import { RepoUser } from "../../../repository/app/schemas";
import { Permissions } from "../../app/schemas/auth";
import { ForRepoQuerying } from "../../ports/drivens";

export class RepoQuerierLocalAdapter implements ForRepoQuerying {
async getUser(email: string): Promise<RepoUser> {
const user = userManagerProxy.getInternalUser(email)

return user;
}

async getPermissions(userId: string): Promise<Permissions> {
const userPermissions = await userPermissionManagerProxy.getUserPermissions(userId)

return {
admin: userPermissions.admin,
user: userPermissions.user
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { RepoUser } from "../../../repository/app/schemas";
import { UserPermissions } from "../../app/schemas/auth";
import { ForRepoQuerying } from "../../ports/drivens";

export class RepoQuerierStubAdapter implements ForRepoQuerying {
async getUser(_email: string): Promise<RepoUser> {
return {
id: "1",
name: "John Doe",
email: "john@gmail.com",
password: "123",
};
}

async getPermissions(_userId: string): Promise<UserPermissions> {
return Promise.resolve({ id: "1", userId: "1", admin: true, user: true });
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { ControlPlane } from "../../app/control-plane";
import { AuthDetails, Permissions } from "../../app/schemas/auth";
import { ForManagingAuthentication } from "../../ports/drivers";

export class AuthManagerProxyAdapter implements ForManagingAuthentication {
constructor(private readonly controlPlane: ControlPlane) {}

async getAuthDetails(email: string, password: string): Promise<AuthDetails> {
return this.controlPlane.getAuthDetails(email, password);
}

async getPermissions(userId: string): Promise<Permissions> {
return this.controlPlane.getPermissions(userId);
}
}
1 change: 1 addition & 0 deletions src/services/control-plane/adapters/drivers/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './auth-manager-proxy-adapter';
14 changes: 14 additions & 0 deletions src/services/control-plane/app/composition-root.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { RepoQuerierStubAdapter } from "../adapters/drivens";
import { AuthManagerProxyAdapter } from "../adapters/drivers";
import { ControlPlane } from "./control-plane";

const compositionMock = () => {
const repoQuerierstub = new RepoQuerierStubAdapter();
const controlPlane = new ControlPlane(repoQuerierstub);

const authManagerProxy = new AuthManagerProxyAdapter(controlPlane);

return { authManagerProxy };
};

export const { authManagerProxy } = compositionMock();
39 changes: 39 additions & 0 deletions src/services/control-plane/app/control-plane.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import { beforeEach, describe, expect, it } from "vitest";
import { RepoQuerierStubAdapter } from "../adapters/drivens";
import { ControlPlane } from "./control-plane";

describe("ControlPlane", () => {
const repoQuerierstub = new RepoQuerierStubAdapter();
let controlPlane = new ControlPlane(repoQuerierstub);

beforeEach(() => {
controlPlane = new ControlPlane(repoQuerierstub);
});

it.concurrent("should get auth details", async () => {
// GIVEN
const mockEmail = "john@gmail.com";
const mockPassword = "123";

const resultExpected = { token: "token", refreshToken: "refreshToken" };

// WHEN
const result = await controlPlane.getAuthDetails(mockEmail, mockPassword);

// THEN
expect(result).toEqual(resultExpected);
});

it.concurrent("should get permissions", async () => {
// GIVEN
const mockUserId = "1";

const resultExpected = { admin: true, user: true };

// WHEN
const result = await controlPlane.getPermissions(mockUserId);

// THEN
expect(result).toEqual(resultExpected);
});
});
38 changes: 38 additions & 0 deletions src/services/control-plane/app/control-plane.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import { RepoUser } from "../../repository/app/schemas";
import { ForRepoQuerying } from "../ports/drivens/for-repo-querying";
import { ForManagingAuthentication } from "../ports/drivers";
import { AuthDetails, Permissions } from "./schemas/auth";

export class ControlPlane implements ForManagingAuthentication {
constructor(
private readonly repoQuerier: ForRepoQuerying,
) {}

async getAuthDetails(email: string, password: string): Promise<AuthDetails> {
let user: RepoUser

try {
user = await this.repoQuerier.getUser(email);
} catch (error) {
// acá podría hacer una validación según el tipo de error
throw new Error("Wrong email");
}

if (password !== user.password) {
throw new Error("Wrong password");
}

return { token: "token", refreshToken: "refreshToken" };
}

async getPermissions(userId: string): Promise<Permissions> {
const userPermissions = await this.repoQuerier.getPermissions(userId);

const permissions = {
admin: userPermissions.admin,
user: userPermissions.user,
};

return permissions;
}
}
16 changes: 16 additions & 0 deletions src/services/control-plane/app/schemas/auth.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
export interface UserPermissions {
id: string;
userId: string;
admin: boolean;
user: boolean;
}

export interface AuthDetails {
token: string;
refreshToken: string;
}

export interface Permissions {
admin: boolean;
user: boolean;
}
7 changes: 7 additions & 0 deletions src/services/control-plane/ports/drivens/for-repo-querying.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { RepoUser } from "../../../repository/app/schemas";
import { Permissions } from "../../app/schemas/auth";

export interface ForRepoQuerying {
getUser(email: string): Promise<RepoUser>;
getPermissions(userId: string): Promise<Permissions>;
}
1 change: 1 addition & 0 deletions src/services/control-plane/ports/drivens/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from "./for-repo-querying";
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import { AuthDetails, Permissions } from "../../app/schemas/auth";

export interface ForManagingAuthentication {
getAuthDetails(email: string, password: string): Promise<AuthDetails>;
getPermissions(userId: string): Promise<Permissions>;
}
1 change: 1 addition & 0 deletions src/services/control-plane/ports/drivers/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from "./for-managing-authentication";
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ export class ControlAuthenticatorStub implements ForControlAuthenticating {
return Promise.resolve(authDetailsMock);
}

getPermissions(_email: string, _password: string): Promise<Permissions> {
getPermissions(_userId: string): Promise<Permissions> {
return Promise.resolve(permissionsMock);
}
}
3 changes: 2 additions & 1 deletion src/services/dashboard-api/adapters/drivens/index.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
export * from './control-authenticator-stub-adapter';
export * from './repo-querier-stub-adapter';
export * from './repo-querier-local-adapter';
export * from './repo-querier-stub-adapter';
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { userManagerProxy } from "../../../repository/app/composition-root";
import { ExternalUser } from "../../../repository/app/schemas";
import { User } from "../../app/schemas";
import { ForRepoQuerying } from "../../ports/drivens";

export class RepoQuerierLocalAdapter implements ForRepoQuerying {
async getUser(email: string): Promise<ExternalUser> {
return await userManagerProxy.getUser(email)
}

async createUser(user: User): Promise<ExternalUser> {
return await userManagerProxy.createUser(user)
}
}
7 changes: 4 additions & 3 deletions src/services/dashboard-api/app/composition-root.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import {
authTRPCAdapter,
} from "../adapters/drivers";
import { initTRPC } from "@trpc/server";
import { RepoQuerierLocalAdapter } from "../adapters/drivens";

const compositionMock = () => {
// DRIVENS
Expand All @@ -29,7 +30,7 @@ const compositionMock = () => {
};

export const { authenticatorProxyAdapter } = compositionMock();
/*
/*
const registerMock = {
name: "John",
email: "jhon@gmail.com",
Expand All @@ -42,12 +43,12 @@ authenticatorProxyAdapter.register(registerMock);
export const localTRPCCompose = () => {
// DRIVENS
const controlAuthenticatorStub = new ControlAuthenticatorStub();
const repoQuerierStub = new RepoQuerierStub();
const repoQuerierLocal = new RepoQuerierLocalAdapter();

// APP
const dashboardApiMock = new DashboardApi(
controlAuthenticatorStub,
repoQuerierStub
repoQuerierLocal
);

// TRPC INSTANCE
Expand Down
10 changes: 4 additions & 6 deletions src/services/dashboard-api/app/dashboard-api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,10 @@ export class DashboardApi implements ForAuthenticating {
email,
password
);
const permissions = await this.controlAuthenticator.getPermissions(
email,
password
);
const user = await this.repoQuerier.getUser(email);

const permissions = await this.controlAuthenticator.getPermissions(user.id);

const result = {
...user,
...authDetails,
Expand All @@ -37,8 +36,7 @@ export class DashboardApi implements ForAuthenticating {
user.password
);
const permissions = await this.controlAuthenticator.getPermissions(
user.email,
user.password
newUser.id
);

const result = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,5 @@ import { AuthDetails, Permissions } from "../../app/schemas";

export interface ForControlAuthenticating {
getAuthDetails(email: string, password: string): Promise<AuthDetails>;
getPermissions(email: string, password: string): Promise<Permissions>;
getPermissions(userId: string): Promise<Permissions>;
}
1 change: 1 addition & 0 deletions src/services/repository/adapters/drivers/index.ts
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
export * from './user-manager-proxy';
export * from './user-permission-manager-proxy';
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Repository } from "../../app/repository";
import { ExternalUser, User } from "../../app/schemas";
import { ExternalUser, Permissions, RepoUser, User, UserPermission } from "../../app/schemas";
import { ForManagingUser } from "../../ports/drivers";

export class UserManagerProxy implements ForManagingUser {
Expand All @@ -12,4 +12,8 @@ export class UserManagerProxy implements ForManagingUser {
async createUser(user: User): Promise<ExternalUser> {
return this.repository.createUser(user);
}

async getInternalUser(email: string): Promise<RepoUser> {
return this.repository.getInternalUser(email);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { Repository } from "../../app/repository";
import { Permissions, UserPermission } from "../../app/schemas";
import { UserPermissionRepository } from "../../app/user-permission-repository";
import { ForManagingPermission } from "../../ports/drivers/for-managing-permission";

export class UserPermissionManagerProxy implements ForManagingPermission {
constructor(private readonly repository: UserPermissionRepository) {}

async getUserPermissions(userId: string): Promise<UserPermission> {
return this.repository.getUserPermissions(userId)
}

async createUserPermissions(userId: string, permissions: Permissions): Promise<UserPermission> {
return this.repository.createUserPermissions(userId, permissions)
}
}
8 changes: 8 additions & 0 deletions src/services/repository/app/composition-root.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,22 @@
import { LoggerStubAdapter } from "../adapters/drivens";
import { UserPermissionManagerProxy } from "../adapters/drivers";
import { UserManagerProxy } from "./../adapters/drivers/user-manager-proxy";
import { Repository } from "./repository";
import { UserPermissionRepository } from "./user-permission-repository";

export const compositionMock = () => {
const monitorStub = new LoggerStubAdapter();
const repositoryMock = new Repository(monitorStub);

const userManagerProxy = new UserManagerProxy(repositoryMock);

const userPermissionRepositoryMock = new UserPermissionRepository(monitorStub)
const userPermissionManagerProxy = new UserPermissionManagerProxy(userPermissionRepositoryMock);

return {
userManagerProxy,
userPermissionManagerProxy
};
};

export const { userManagerProxy, userPermissionManagerProxy } = compositionMock();
18 changes: 18 additions & 0 deletions src/services/repository/app/repository.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -93,4 +93,22 @@ describe("Repository", () => {
//THEN
expect(result).toEqual(expectedResult);
});

it.concurrent("should get internal user", async () => {
// GIVEN
const mockedEmail = "samuelcito@gmail.com";

const expectedResult = {
id: "1",
name: "Samuel",
email: "samuelcito@gmail.com",
password: 'password'
};

// WHEN
const result = await repositoryMock.getInternalUser(mockedEmail);

// THEN
expect(result).toEqual(expectedResult);
});
});
Loading