Skip to content

Commit

Permalink
api: list did feature rucio#226
Browse files Browse the repository at this point in the history
  • Loading branch information
maany committed Jun 22, 2023
1 parent f1a262c commit 1e917e6
Show file tree
Hide file tree
Showing 4 changed files with 180 additions and 22 deletions.
19 changes: 2 additions & 17 deletions src/lib/infrastructure/ioc/container-config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,12 +37,6 @@ import SwitchAccountInputPort from "@/lib/core/port/primary/switch-account-input
import SwitchAccountUseCase from "@/lib/core/use-case/switch-account-usecase";
import SwitchAccountController, { ISwitchAccountController } from "../controller/switch-account-controller";
import SwitchAccountPresenter from "../presenter/switch-account-presenter";
import { ListDIDsInputPort } from "@/lib/core/port/primary/list-dids-ports";
import ListDIDsUseCase from "@/lib/core/use-case/list-dids-usecase";
import ListDIDsController, { ListDIDsControllerParameters } from "../controller/list-dids-controller";
import ListDIDsPresenter from "../presenter/list-dids-presenter";
import { ListDIDsRequest } from "@/lib/core/usecase-models/list-dids-usecase-models";
import { BaseController } from "@/lib/sdk/controller";
import { loadFeatures } from "@/lib/sdk/ioc-helpers";


Expand All @@ -56,6 +50,8 @@ appContainer.bind<DIDGatewayOutputPort>(GATEWAYS.DID).to(RucioDIDGateway);
appContainer.bind<EnvConfigGatewayOutputPort>(GATEWAYS.ENV_CONFIG).to(EnvConfigGateway);
appContainer.bind<StreamGatewayOutputPort>(GATEWAYS.STREAM).to(StreamingGateway).inRequestScope();

loadFeatures(appContainer)

appContainer.bind<UserPassLoginInputPort>(INPUT_PORT.USERPASS_LOGIN).to(UserPassLoginUseCase).inRequestScope();
appContainer.bind<IUserPassLoginController>(CONTROLLERS.USERPASS_LOGIN).to(UserPassLoginController);
appContainer.bind<interfaces.Factory<UserPassLoginInputPort>>(USECASE_FACTORY.USERPASS_LOGIN).toFactory<UserPassLoginUseCase, [IronSession, NextApiResponse]>((context: interfaces.Context) =>
Expand All @@ -66,17 +62,6 @@ appContainer.bind<interfaces.Factory<UserPassLoginInputPort>>(USECASE_FACTORY.US
}
);

appContainer.bind<ListDIDsInputPort>(INPUT_PORT.LIST_DIDS).to(ListDIDsUseCase).inRequestScope();
appContainer.bind<BaseController<ListDIDsControllerParameters ,ListDIDsRequest>>(CONTROLLERS.LIST_DIDS).to(ListDIDsController);
appContainer.bind<interfaces.Factory<ListDIDsInputPort>>(USECASE_FACTORY.LIST_DIDS).toFactory<ListDIDsUseCase, [NextApiResponse]>((context: interfaces.Context) =>
(response: NextApiResponse) => {
const rucioDIDGateway: DIDGatewayOutputPort = appContainer.get(GATEWAYS.DID)
return new ListDIDsUseCase(new ListDIDsPresenter(response), rucioDIDGateway);
}
);

loadFeatures(appContainer)

appContainer.bind<SetX509LoginSessionInputPort>(INPUT_PORT.SET_X509_LOGIN_SESSION).to(SetX509LoginSessionUseCase).inRequestScope();
appContainer.bind<ISetX509LoginSessionController>(CONTROLLERS.SET_X509_LOGIN_SESSION).to(SetX509LoginSessionController);
appContainer.bind<interfaces.Factory<SetX509LoginSessionInputPort>>(USECASE_FACTORY.SET_X509_LOGIN_SESSION).toFactory<SetX509LoginSessionUseCase, [IronSession, NextApiResponse]>((context: interfaces.Context) =>
Expand Down
42 changes: 42 additions & 0 deletions src/lib/infrastructure/ioc/features/list-dids-feature.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import DIDGatewayOutputPort from "@/lib/core/port/secondary/did-gateway-output-port";
import { ListDIDsError, ListDIDsRequest, ListDIDsResponse } from "@/lib/core/usecase-models/list-dids-usecase-models";
import { ListDIDsControllerParameters } from "@/lib/infrastructure/controller/list-dids-controller";
import { ListDIDsViewModel } from "@/lib/infrastructure/data/view-model/list-did";
import { BaseStreamableFeature, IOCSymbols } from "@/lib/sdk/ioc-helpers";
import GATEWAYS from "@/lib/infrastructure/ioc/ioc-symbols-gateway";
import CONTROLLERS from "@/lib/infrastructure/ioc/ioc-symbols-controllers";
import INPUT_PORT from "@/lib/infrastructure/ioc/ioc-symbols-input-port";
import USECASE_FACTORY from "@/lib/infrastructure/ioc/ioc-symbols-usecase-factory";
import { Container } from "inversify";
import ListDIDsController from "@/lib/infrastructure/controller/list-dids-controller";
import ListDIDsUseCase from "@/lib/core/use-case/list-dids-usecase";
import ListDIDsPresenter from "../../presenter/list-dids-presenter";


export default class ListDidsFeature extends BaseStreamableFeature<
ListDIDsControllerParameters,
ListDIDsRequest,
ListDIDsResponse,
ListDIDsError,
ListDIDsViewModel> {
constructor( appContainer: Container ) {
const didGateway = appContainer.get<DIDGatewayOutputPort>(GATEWAYS.DID)
const symbols: IOCSymbols = {
CONTROLLER: CONTROLLERS.LIST_DIDS,
USECASE_FACTORY: USECASE_FACTORY.LIST_DIDS,
INPUT_PORT: INPUT_PORT.LIST_DIDS,
}
super(
appContainer,
ListDIDsController,
ListDIDsUseCase,
[
didGateway,
],
ListDIDsPresenter,
false,
symbols
)
}

}
107 changes: 102 additions & 5 deletions src/lib/sdk/ioc-helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,12 @@ import { IronSession } from 'iron-session';
import { NextApiResponse } from 'next';
import path from 'path';
import { BaseController, TParameters } from './controller';
import { BasePresenter } from './presenter';
import type { BaseInputPort, BaseOutputPort } from './primary-ports';
import { BasePresenter, BaseStreamingPresenter } from './presenter';
import type { BaseInputPort, BaseOutputPort, BaseStreamingOutputPort } from './primary-ports';
import { TUseCase } from './usecase';
import TUseCaseFactory from './usecase-factory';
import { BaseResponseModel } from './usecase-models';
import { BaseViewModel } from './view-models';

/**
* An object that contains symbols for the different types of dependencies in an IoC container.
Expand Down Expand Up @@ -125,6 +127,100 @@ TControllerParams extends TParameters,
}
}

/**
* A base class for streamable features in a web application.
* @template TControllerParams The type of the parameters for the controller.
* @template TRequestModel The type of the request model for the use case.
* @template TResponseModel The type of the response model for the use case.
* @template TErrorModel The type of the error model for the use case.
* @template TViewModel The type of the view model for the presenter.
*/
export class BaseStreamableFeature<
TControllerParams extends TParameters,
TRequestModel,
TResponseModel extends BaseResponseModel,
TErrorModel,
TViewModel extends BaseViewModel,
> {
/**
* Creates a new instance of the `BaseStreamableFeature` class.
* @param appContainer The IoC container for the application.
* @param Controller The controller class for the feature.
* @param UseCase The use case class for the feature.
* @param useCaseContructorArgs The arguments to pass to the use case constructor.
* @param Presenter The presenter class for the feature.
* @param passSessionToPresenter Whether to pass the session to the presenter.
* @param symbols An object that contains symbols for the different types of dependencies in the IoC container.
*/
constructor(
appContainer: Container,
Controller: new (useCaseFactory: TUseCaseFactory<TRequestModel>) => BaseController<TControllerParams, TRequestModel>,
UseCase: new (presenter: BaseStreamingOutputPort<TResponseModel, TErrorModel>, ...args: any[]) => TUseCase<TRequestModel>,
useCaseContructorArgs: any[] = [],
Presenter: new (response: NextApiResponse, session?: IronSession) => BaseStreamingPresenter<TResponseModel, TViewModel, TErrorModel>,
passSessionToPresenter: boolean = false,
symbols: IOCSymbols,
) {
this.createIOCBindings<TControllerParams, TRequestModel, TResponseModel, TErrorModel, TViewModel>(
appContainer,
Controller,
UseCase,
useCaseContructorArgs,
Presenter,
passSessionToPresenter,
symbols,
)
}

/**
* Creates the IoC bindings for the streamable feature.
* @param appContainer The IoC container for the application.
* @param Controller The controller class for the feature.
* @param UseCase The use case class for the feature.
* @param useCaseContructorArgs The arguments to pass to the use case constructor.
* @param Presenter The presenter class for the feature.
* @param passSessionToPresenter Whether to pass the session to the presenter.
* @param symbols An object that contains symbols for the different types of dependencies in the IoC container.
*/
createIOCBindings<
TControllerParams extends TParameters,
TRequestModel,
TResponseModel extends BaseResponseModel,
TErrorModel,
TViewModel extends BaseViewModel,
>(
appContainer: Container,
Controller: new (useCaseFactory: TUseCaseFactory<TRequestModel>) => BaseController<TControllerParams, TRequestModel>,
UseCase: new (presenter: BaseStreamingOutputPort<TResponseModel, TErrorModel>, ...args: any[]) => TUseCase<TRequestModel>,
useCaseContructorArgs: any[] = [],
Presenter: new (response: NextApiResponse, session?: IronSession) => BaseStreamingPresenter<TResponseModel, TViewModel, TErrorModel>,
passSessionToPresenter: boolean = false,
symbols: IOCSymbols,
) {
const symbolInputPort = symbols.INPUT_PORT
const symbolController = symbols.CONTROLLER
const symbolUseCaseFactory = symbols.USECASE_FACTORY

appContainer.bind<BaseInputPort<TRequestModel>>(symbolInputPort).to(UseCase).inRequestScope();
appContainer.bind<BaseController<TControllerParams, TRequestModel>>(symbolController).to(Controller).inRequestScope();

if(passSessionToPresenter){
appContainer.bind<interfaces.Factory<TUseCase<TRequestModel>>>(symbolUseCaseFactory).toFactory<TUseCase<TRequestModel>, [response: NextApiResponse, session: IronSession]>((context: interfaces.Context) =>
(response: NextApiResponse, session: IronSession) => {
const presenter = new Presenter(response, session);
return new UseCase(presenter, ...useCaseContructorArgs);
}
);
} else {
appContainer.bind<interfaces.Factory<TUseCase<TRequestModel>>>(symbolUseCaseFactory).toFactory<TUseCase<TRequestModel>, [response: NextApiResponse]>((context: interfaces.Context) =>
(response: NextApiResponse) => {
const presenter = new Presenter(response);
return new UseCase(presenter, ...useCaseContructorArgs);
});
}
}
}

/**
* Loads features from the features directory into the IoC Container.
* @param appContainer The IoC container for the application.
Expand All @@ -144,9 +240,10 @@ export async function loadFeatures(appContainer: Container, featuresDir?: string
if (!featureClass) {
throw new Error(`Feature ${featureName} has no default export`)
}
// if default export is not a subclass of BaseFeature, throw error
if (!(featureClass.prototype instanceof BaseFeature)) {
throw new Error(`Feature ${featureName} is not a subclass of BaseFeature`)
// if default export is not a subclass of BaseFeature or BaseStreambleFeature, throw error
if (!(featureClass.prototype instanceof BaseFeature) &&
!(featureClass.prototype instanceof BaseStreamableFeature)) {
throw new Error(`Feature ${featureName} is not a subclass of BaseFeature or BaseStreamableFeature`)
}
// if constructor signature of default export is not new (appContainer: Container) => BaseFeature, throw error
if (featureClass.length !== 1) {
Expand Down
34 changes: 34 additions & 0 deletions src/pages/api/dids.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import appContainer from "@/lib/infrastructure/ioc/container-config";
import CONTROLLERS from "@/lib/infrastructure/ioc/ioc-symbols-controllers";
import { BaseController } from "@/lib/sdk/controller";
import { NextApiRequest, NextApiResponse } from "next";
import { ListDIDsControllerParameters } from "@/lib/infrastructure/controller/list-dids-controller";
import { withAuthenticatedSessionRoute } from "@/lib/infrastructure/auth/session-utils";

async function listDIDs(req: NextApiRequest, res: NextApiResponse, rucioAuthToken: string) {
if(req.method === 'GET') {
res.status(405).json({ error: 'Method Not Allowed' })
return
}
const { query, type } = req.body
if(!query) {
res.status(400).json({ error: 'Missing query parameter' })
return
}
if(!type) {
res.status(400).json({ error: 'Missing type parameter' })
return
}

const controller = appContainer.get<BaseController<ListDIDsControllerParameters, void>>(CONTROLLERS.LIST_DIDS)
const controllerParameters: ListDIDsControllerParameters = {
response: res,
query: query,
type: type,
rucioAuthToken: rucioAuthToken
}

await controller.execute(controllerParameters)
}

export default withAuthenticatedSessionRoute(listDIDs)

0 comments on commit 1e917e6

Please sign in to comment.