Skip to content

Commit

Permalink
add routes definition for admin getUsers, and finish front implementa…
Browse files Browse the repository at this point in the history
…tion of httpAdminGateway
  • Loading branch information
JeromeBu committed Oct 8, 2024
1 parent ee33dc4 commit 57375de
Show file tree
Hide file tree
Showing 12 changed files with 101 additions and 56 deletions.
24 changes: 16 additions & 8 deletions front/src/core-logic/adapters/AdminGateway/HttpAdminGateway.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Observable, from, of, throwError } from "rxjs";
import { Observable, from } from "rxjs";
import {
AdminRoutes,
ApiConsumer,
Expand All @@ -7,23 +7,23 @@ import {
EstablishmentBatchReport,
FormEstablishmentBatchDto,
GetDashboardParams,
GetUsersFilters,
InclusionConnectJwt,
InclusionConnectedUser,
RejectIcUserRoleForAgencyParams,
RemoveAgencyUserParams,
SetFeatureFlagParam,
UserInList,
UserParamsForAgency,
WithUserFilters,
createApiConsumerParamsFromApiConsumer,
User,
} from "shared";
import { HttpClient } from "shared-routes";
import {
logBodyAndThrow,
otherwiseThrow,
throwBadRequestWithExplicitMessage,
} from "src/core-logic/adapters/otherwiseThrow";
import { UserFilters } from "src/core-logic/domain/admin/listUsers/listUsers.slice";
import { AdminGateway } from "src/core-logic/ports/AdminGateway";
import { P, match } from "ts-pattern";

Expand Down Expand Up @@ -246,10 +246,18 @@ export class HttpAdminGateway implements AdminGateway {
}

public listUsers$(
_params: UserFilters,
_token: InclusionConnectJwt,
): Observable<User[]> {
throw new Error("yolo");
// return of([]);
filters: GetUsersFilters,
token: InclusionConnectJwt,
): Observable<UserInList[]> {
return from(
this.httpClient
.getUsers({ headers: { authorization: token }, queryParams: filters })
.then((response) =>
match(response)
.with({ status: 200 }, ({ body }) => body)
.with({ status: 401 }, logBodyAndThrow)
.otherwise(otherwiseThrow),
),
);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,15 @@ import {
EstablishmentBatchReport,
FormEstablishmentBatchDto,
GetDashboardParams,
GetUsersFilters,
InclusionConnectJwt,
InclusionConnectedUser,
NotificationsByKind,
RejectIcUserRoleForAgencyParams,
RemoveAgencyUserParams,
UserInList,
UserParamsForAgency,
User,
} from "shared";
import { UserFilters } from "src/core-logic/domain/admin/listUsers/listUsers.slice";
import { AdminGateway } from "src/core-logic/ports/AdminGateway";

const simulatedAgencyDtos: AgencyRight[] = [
Expand Down Expand Up @@ -194,25 +194,24 @@ export class SimulatedAdminGateway implements AdminGateway {
}

public listUsers$(
{ emailContains }: UserFilters,
{ emailContains }: GetUsersFilters,
_token: string,
): Observable<User[]> {
): Observable<UserInList[]> {
return of(
simulatedUsers.filter((user) =>
user.email.includes(emailContains),
),
simulatedUsers.filter((user) => user.email.includes(emailContains)),
);
}
}

const simulatedUsers: User[] = [
const simulatedUsers: UserInList[] = [
{
id: "fake-user-id-1",
email: "[email protected]",
firstName: "Jerome",
lastName: "Yolo",
externalId: "external-id-1",
createdAt: new Date().toISOString(),
numberOfAgencies: 10,
},
{
id: "fake-user-id-2",
Expand All @@ -221,6 +220,7 @@ const simulatedUsers: User[] = [
lastName: "Lala",
externalId: "external-id-1",
createdAt: new Date().toISOString(),
numberOfAgencies: 3,
},
];

Expand Down
11 changes: 7 additions & 4 deletions front/src/core-logic/adapters/AdminGateway/TestAdminGateway.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,16 @@ import {
DashboardUrlAndName,
EstablishmentBatchReport,
FormEstablishmentBatchDto,
GetUsersFilters,
InclusionConnectJwt,
InclusionConnectedUser,
NotificationsByKind,
RejectIcUserRoleForAgencyParams,
RemoveAgencyUserParams,
SetFeatureFlagParam,
UserInList,
UserParamsForAgency,
User,
} from "shared";
import { type UserFilters } from "src/core-logic/domain/admin/listUsers/listUsers.slice";
import { AdminGateway } from "src/core-logic/ports/AdminGateway";

export class TestAdminGateway implements AdminGateway {
Expand Down Expand Up @@ -50,7 +50,7 @@ export class TestAdminGateway implements AdminGateway {

public createUserForAgencyResponse$ = new Subject<InclusionConnectedUser>();

public listUsersResponse$ = new Subject<User[]>();
public listUsersResponse$ = new Subject<UserInList[]>();

public updateFeatureFlags$ = (
params: SetFeatureFlagParam,
Expand Down Expand Up @@ -118,7 +118,10 @@ export class TestAdminGateway implements AdminGateway {
return this.removeUserFromAgencyResponse$;
}

public listUsers$(_params: UserFilters, _token: string): Observable<User[]> {
public listUsers$(
_params: GetUsersFilters,
_token: string,
): Observable<UserInList[]> {
return this.listUsersResponse$;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,7 @@ const fetchUsersEpic: ListUserActionEpic = (
switchMap((action) =>
adminGateway.listUsers$(action.payload, getAdminToken(state$.value)),
),
map((action) => {
console.log("reached here : ", action);
return listUsersSlice.actions.fetchUsersSucceeded(action);
}),
map((action) => listUsersSlice.actions.fetchUsersSucceeded(action)),
);

const triggerFetchOnQueryChangeEpic: ListUserActionEpic = (
Expand Down
14 changes: 5 additions & 9 deletions front/src/core-logic/domain/admin/listUsers/listUsers.slice.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { createSlice, PayloadAction } from "@reduxjs/toolkit";
import { User } from "shared";
import { PayloadAction, createSlice } from "@reduxjs/toolkit";
import type { GetUsersFilters, UserInList } from "shared";

type UsersState = {
users: User[];
users: UserInList[];
isFetching: boolean;
query: string;
};
Expand All @@ -13,21 +13,17 @@ export const listUsersInitialState: UsersState = {
query: "",
};

export type UserFilters = {
emailContains: string;
};

export const listUsersSlice = createSlice({
name: "listUsers",
initialState: listUsersInitialState,
reducers: {
queryUpdated: (state, action: PayloadAction<string>) => {
state.query = action.payload;
},
fetchUsersRequested: (state, _action: PayloadAction<UserFilters>) => {
fetchUsersRequested: (state, _action: PayloadAction<GetUsersFilters>) => {
state.isFetching = true;
},
fetchUsersSucceeded: (state, action: PayloadAction<User[]>) => {
fetchUsersSucceeded: (state, action: PayloadAction<UserInList[]>) => {
state.users = action.payload;
state.isFetching = false;
},
Expand Down
13 changes: 7 additions & 6 deletions front/src/core-logic/domain/admin/listUsers/listUsers.test.ts
Original file line number Diff line number Diff line change
@@ -1,19 +1,20 @@
import { expectToEqual, User } from "shared";
import { UserInList, expectToEqual } from "shared";
import { listUsersSelectors } from "src/core-logic/domain/admin/listUsers/listUsers.selectors";
import { listUsersSlice } from "src/core-logic/domain/admin/listUsers/listUsers.slice";
import {
createTestStore,
TestDependencies,
createTestStore,
} from "src/core-logic/storeConfig/createTestStore";
import { ReduxStore } from "src/core-logic/storeConfig/store";

const someUser: User = {
const someUser: UserInList = {
id: "some-user-id",
email: "[email protected]",
firstName: "Yo",
lastName: "Lo",
externalId: "external-123",
createdAt: new Date().toISOString(),
numberOfAgencies: 2,
};

describe("Admin Users slice", () => {
Expand Down Expand Up @@ -50,15 +51,15 @@ describe("Admin Users slice", () => {
const query = "my query";
store.dispatch(listUsersSlice.actions.queryUpdated(query));
expectToEqual(listUsersSelectors.isFetching(store.getState()), false);
fastForwardObservables()
fastForwardObservables();
expectToEqual(listUsersSelectors.isFetching(store.getState()), true);

feedWithUsers([someUser]);
expectToEqual(listUsersSelectors.isFetching(store.getState()), false);
expectToEqual(listUsersSelectors.users(store.getState()), [someUser]);
})
});

const feedWithUsers = (users: User[]) => {
const feedWithUsers = (users: UserInList[]) => {
dependencies.adminGateway.listUsersResponse$.next(users);
};

Expand Down
8 changes: 4 additions & 4 deletions front/src/core-logic/ports/AdminGateway.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,17 +6,17 @@ import {
EstablishmentBatchReport,
FormEstablishmentBatchDto,
GetDashboardParams,
GetUsersFilters,
InclusionConnectJwt,
InclusionConnectedUser,
NotificationsByKind,
RejectIcUserRoleForAgencyParams,
RemoveAgencyUserParams,
SetFeatureFlagParam,
UserInList,
UserParamsForAgency,
WithUserFilters,
User,
} from "shared";
import { UserFilters } from "src/core-logic/domain/admin/listUsers/listUsers.slice";

export interface AdminGateway {
addEstablishmentBatch$: (
Expand Down Expand Up @@ -70,7 +70,7 @@ export interface AdminGateway {
): Observable<ApiConsumerJwt | undefined>;

listUsers$(
params: UserFilters,
params: GetUsersFilters,
token: InclusionConnectJwt,
): Observable<User[]>;
): Observable<UserInList[]>;
}
4 changes: 4 additions & 0 deletions shared/src/admin/admin.dto.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,3 +58,7 @@ export type UpdateAgencyStatusParamsWithoutId =
status: Extract<ActiveOrRejectedStatus, "rejected">;
rejectionJustification: string;
};

export type GetUsersFilters = {
emailContains: string;
};
16 changes: 15 additions & 1 deletion shared/src/admin/admin.routes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,14 @@ import {
} from "../formEstablishment/FormEstablishment.schema";
import { withAuthorizationHeaders } from "../headers";
import { httpErrorSchema } from "../httpClient/httpErrors.schema";
import { inclusionConnectedUserSchema } from "../inclusionConnectedAllowed/inclusionConnectedAllowed.schema";
import {
inclusionConnectedUserSchema,
userInListSchema,
} from "../inclusionConnectedAllowed/inclusionConnectedAllowed.schema";
import { notificationsByKindSchema } from "../notifications/notifications.schema";
import { expressEmptyResponseBody } from "../zodUtils";
import {
getUsersFiltersSchema,
rejectIcUserRoleForAgencyParamsSchema,
userParamsForAgencySchema,
withUserFiltersSchema,
Expand Down Expand Up @@ -140,4 +144,14 @@ export const adminRoutes = defineRoutes({
401: httpErrorSchema,
},
}),
getUsers: defineRoute({
method: "get",
url: "/admin/users",
...withAuthorizationHeaders,
queryParamsSchema: getUsersFiltersSchema,
responses: {
200: z.array(userInListSchema),
401: httpErrorSchema,
},
}),
});
5 changes: 5 additions & 0 deletions shared/src/admin/admin.schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import {
import { siretSchema } from "../siret/siret.schema";
import { zStringMinLength1 } from "../zodUtils";
import {
GetUsersFilters,
ManageConventionAdminForm,
ManageEstablishmentAdminForm,
RejectIcUserRoleForAgencyParams,
Expand Down Expand Up @@ -58,3 +59,7 @@ export const manageEstablishmentAdminFormSchema: z.Schema<ManageEstablishmentAdm
z.object({
siret: siretSchema,
});

export const getUsersFiltersSchema: z.Schema<GetUsersFilters> = z.object({
emailContains: z.string(),
});
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,10 @@ export type User = {
createdAt: DateTimeIsoString;
};

export type UserInList = User & {
numberOfAgencies: number;
};

type WithAgencyRights = {
agencyRights: AgencyRight[];
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,9 @@ import { zStringCanBeEmpty, zStringMinLength1 } from "../zodUtils";
import {
AgencyRight,
InclusionConnectedUser,
User,
UserId,
UserInList,
WithAgencyDashboards,
WithDiscussionId,
WithEstablishmentDashboards,
Expand Down Expand Up @@ -58,19 +60,30 @@ const dashboardsSchema: z.Schema<
}),
});

export const inclusionConnectedUserSchema: z.Schema<InclusionConnectedUser> =
const userSchema: z.Schema<User> = z.object({
id: userIdSchema,
email: emailSchema,
createdAt: dateTimeIsoStringSchema,
firstName: zStringCanBeEmpty,
lastName: zStringCanBeEmpty,
externalId: zStringCanBeEmpty.or(z.null()),
});

export const userInListSchema: z.Schema<UserInList> = userSchema.and(
z.object({
id: userIdSchema,
email: emailSchema,
createdAt: dateTimeIsoStringSchema,
agencyRights: z.array(agencyRightSchema),
firstName: zStringCanBeEmpty,
lastName: zStringCanBeEmpty,
externalId: zStringCanBeEmpty.or(z.null()),
dashboards: dashboardsSchema,
establishments: z.array(withEstablishmentSiretAndName).optional(),
isBackofficeAdmin: z.boolean().optional(),
});
numberOfAgencies: z.number(),
}),
);

export const inclusionConnectedUserSchema: z.Schema<InclusionConnectedUser> =
userSchema.and(
z.object({
agencyRights: z.array(agencyRightSchema),
dashboards: dashboardsSchema,
establishments: z.array(withEstablishmentSiretAndName).optional(),
isBackofficeAdmin: z.boolean().optional(),
}),
);

export type WithIdToken = {
idToken: IdToken;
Expand Down

0 comments on commit 57375de

Please sign in to comment.