Skip to content
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

jyg-UID2-1736 Pretends sharing with DPS when allow_sites is null #200

Closed
Show file tree
Hide file tree
Changes from 3 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
8 changes: 8 additions & 0 deletions src/api/entities/AuditTrail.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { Model } from 'objection';

import { ClientType } from '../services/adminServiceHelpers';
import { BaseModel } from './BaseModel';
import { ModelObjectOpt } from './ModelObjectOpt';

Expand All @@ -11,13 +12,15 @@ export enum AuditAction {

export enum AuditTrailEvents {
UpdateSharingPermissions = 'UpdateSharingPermissions',
UpdateSharingTypes = 'UpdateSharingTypes',
ApproveAccount = 'ApproveAccount',
ManageKeyPair = 'ManageKeyPair',
}

export type AuditTrailEventData =
| UpdateSharingPermissionEventData
| ApproveAccountEventData
| UpdateSharingTypesEventData
| ManageKeyPairEventData;

export type UpdateSharingPermissionEventData = {
Expand All @@ -26,6 +29,11 @@ export type UpdateSharingPermissionEventData = {
sharingPermissions: number[];
};

export type UpdateSharingTypesEventData = {
siteId: number;
allowedTypes: ClientType[];
};

export type ApproveAccountEventData = {
siteId: number;
oldName?: string;
Expand Down
53 changes: 39 additions & 14 deletions src/api/routers/participantsRouter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import {
insertApproveAccountAuditTrail,
insertKeyPairAuditTrails,
insertSharingAuditTrails,
insertSharingTypesAuditTrail,
updateAuditTrailToProceed,
} from '../services/auditTrailService';
import { assignClientRoleToUser, createNewUser, sendInviteEmail } from '../services/kcUsersService';
Expand All @@ -29,6 +30,7 @@ import {
ParticipantRequest,
sendNewParticipantEmail,
sendParticipantApprovedEmail,
UpdateSharingTypes,
} from '../services/participantsService';
import {
createUserInPortal,
Expand Down Expand Up @@ -211,14 +213,8 @@ export function createParticipantsRouter() {
}
);

const sharingRelationParser = z.object({
const sharingSitesParser = z.object({
newParticipantSites: z.array(z.number()),
newTypes: z.array(ClientTypeEnum),
});

const keyPairParser = z.object({
name: z.string(),
disabled: z.boolean(),
});

participantsRouter.post(
Expand All @@ -228,7 +224,7 @@ export function createParticipantsRouter() {
if (!participant?.siteId) {
return res.status(400).send('Site id is not set');
}
const { newParticipantSites, newTypes } = sharingRelationParser.parse(req.body);
const { newParticipantSites } = sharingSitesParser.parse(req.body);
const currentUser = await findUserByEmail(req.auth?.payload?.email as string);
const auditTrail = await insertSharingAuditTrails(
participant,
Expand All @@ -240,15 +236,19 @@ export function createParticipantsRouter() {

const sharingParticipants = await addSharingParticipants(
participant.siteId,
newParticipantSites,
newTypes
newParticipantSites
);

await updateAuditTrailToProceed(auditTrail.id);
return res.status(200).json(sharingParticipants);
}
);

const keyPairParser = z.object({
name: z.string(),
disabled: z.boolean(),
});

participantsRouter.post(
'/:participantId/keyPair/add',
async (req: ParticipantRequest, res: Response) => {
Expand Down Expand Up @@ -287,9 +287,8 @@ export function createParticipantsRouter() {
}
);

const removeSharingRelationParser = z.object({
const removeSharingSitesParser = z.object({
sharingSitesToRemove: z.array(z.number()),
types: z.array(ClientTypeEnum),
});

participantsRouter.post(
Expand All @@ -299,7 +298,7 @@ export function createParticipantsRouter() {
if (!participant?.siteId) {
return res.status(400).send('Site id is not set');
}
const { sharingSitesToRemove, types } = removeSharingRelationParser.parse(req.body);
const { sharingSitesToRemove } = removeSharingSitesParser.parse(req.body);
const currentUser = await findUserByEmail(req.auth?.payload?.email as string);
const auditTrail = await insertSharingAuditTrails(
participant,
Expand All @@ -311,10 +310,36 @@ export function createParticipantsRouter() {

const sharingParticipants = await deleteSharingParticipants(
participant.siteId,
sharingSitesToRemove,
sharingSitesToRemove
);

await updateAuditTrailToProceed(auditTrail.id);

return res.status(200).json(sharingParticipants);
}
);

const sharingTypesParser = z.object({
types: z.array(ClientTypeEnum),
});
participantsRouter.post(
'/:participantId/sharingPermission/shareWithTypes',
async (req: ParticipantRequest, res: Response) => {
const { participant } = req;
if (!participant?.siteId) {
return res.status(400).send('Site id is not set');
}
const { types } = sharingTypesParser.parse(req.body);
const currentUser = await findUserByEmail(req.auth?.payload?.email as string);
const auditTrail = await insertSharingTypesAuditTrail(
participant,
currentUser!.id,
currentUser!.email,
types
);

const sharingParticipants = await UpdateSharingTypes(participant.siteId, types);

await updateAuditTrailToProceed(auditTrail.id);

return res.status(200).json(sharingParticipants);
Expand Down
2 changes: 1 addition & 1 deletion src/api/services/adminServiceHelpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ export type SiteDTO = {
};

export type SharingListResponse = {
allowed_sites: number[];
allowed_sites: number[] | null;
allowed_types: ClientType[];
hash: number;
};
Expand Down
28 changes: 28 additions & 0 deletions src/api/services/auditTrailService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import {
} from '../entities/AuditTrail';
import { Participant, ParticipantApprovalPartial } from '../entities/Participant';
import { getLoggers } from '../helpers/loggingHelpers';
import { ClientType } from './adminServiceHelpers';
import { findUserByEmail } from './usersService';

const arraysHaveSameElements = (a: unknown[], b: unknown[]): boolean => {
Expand Down Expand Up @@ -52,6 +53,33 @@ export const insertSharingAuditTrails = async (
}
};

export const insertSharingTypesAuditTrail = async (
participant: Participant,
userId: number,
userEmail: string,
types: ClientType[]
) => {
try {
const sharingAuditTrail: Omit<AuditTrailDTO, 'id'> = {
participantId: participant.id,
userId,
userEmail,
event: AuditTrailEvents.UpdateSharingTypes,
eventData: {
siteId: participant.siteId!,
allowedTypes: types,
},
succeeded: false,
};

return await AuditTrail.query().insert(sharingAuditTrail);
} catch (error) {
const [logger] = getLoggers();
logger.error(`Audit trails inserted failed: ${error}`);
throw error;
}
};

export const insertKeyPairAuditTrails = async (
participant: Participant,
userId: number,
Expand Down
34 changes: 26 additions & 8 deletions src/api/services/participantsService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -75,30 +75,48 @@ export const getParticipantsBySiteIds = async (siteIds: number[]) => {

export const addSharingParticipants = async (
participantSiteId: number,
siteIds: number[],
types: ClientType[]
siteIds: number[]
): Promise<SharingListResponse> => {
const sharingListResponse = await getSharingList(participantSiteId);
const newSharingSet = new Set([...sharingListResponse.allowed_sites, ...siteIds]);
const existingSharedSites = sharingListResponse.allowed_sites ?? [];
const newSharingSet = new Set([...existingSharedSites, ...siteIds]);
const response = await updateSharingList(
participantSiteId,
sharingListResponse.hash,
[...newSharingSet],
types
Array.from(newSharingSet),
sharingListResponse.allowed_types
);
return response;
};

export const deleteSharingParticipants = async (
participantSiteId: number,
siteIds: number[],
types: ClientType[]
siteIds: number[]
): Promise<SharingListResponse> => {
const sharingListResponse = await getSharingList(participantSiteId);
if (!sharingListResponse.allowed_sites) throw Error('The site is not shared with any sites');
jingyi-gao-ttd marked this conversation as resolved.
Show resolved Hide resolved
const newSharingList = sharingListResponse.allowed_sites.filter(
(siteId) => !siteIds.includes(siteId)
);
return updateSharingList(participantSiteId, sharingListResponse.hash, newSharingList, types);
return updateSharingList(
participantSiteId,
sharingListResponse.hash,
newSharingList,
sharingListResponse.allowed_types
);
};

export const UpdateSharingTypes = async (
participantSiteId: number,
types: ClientType[]
): Promise<SharingListResponse> => {
const sharingListResponse = await getSharingList(participantSiteId);
return updateSharingList(
participantSiteId,
sharingListResponse.hash,
sharingListResponse.allowed_sites ?? [],
types
);
};

export const sendParticipantApprovedEmail = async (users: User[]) => {
Expand Down
2 changes: 1 addition & 1 deletion src/web/screens/home.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ function Home() {
try {
const sharingList = await GetSharingList();
// TODO include the sites from allowed_types in the count
setSharingPermissionsCount(sharingList.allowed_sites.length);
setSharingPermissionsCount((sharingList.allowed_sites ?? []).length);
} catch (e: unknown) {
log.error(e);
setHasError(true);
Expand Down
37 changes: 21 additions & 16 deletions src/web/screens/sharingPermissions.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import {
CompleteRecommendations,
DeleteSharingParticipants,
GetSharingList,
UpdateSharingTypes,
} from '../services/participant';
import { preloadAllSitesList, preloadAvailableSiteList } from '../services/site';
import { PortalRoute } from './routeUtils';
Expand All @@ -21,13 +22,13 @@ import './sharingPermissions.scss';
function SharingPermissions() {
const [showStatusPopup, setShowStatusPopup] = useState(false);
const { participant, setParticipant } = useContext(ParticipantContext);
const [sharedSiteIds, setSharedSiteIds] = useState<number[]>([]);
const [sharedSiteIds, setSharedSiteIds] = useState<number[] | null>([]);
const [sharedTypes, setSharedTypes] = useState<ClientType[]>([]);
const [statusPopup, setStatusPopup] = useState<StatusNotificationType>();

const handleSaveSharingType = async (selectedTypes: ClientType[]) => {
try {
const response = await AddSharingParticipants(participant!.id, sharedSiteIds, selectedTypes);
const response = await UpdateSharingTypes(participant!.id, selectedTypes);
setStatusPopup({
type: 'Success',
message: `${
Expand All @@ -37,6 +38,7 @@ function SharingPermissions() {
} saved to Your Sharing Permissions`,
});
setSharedTypes(response.allowed_types ?? []);
if (!sharedSiteIds) setSharedSiteIds(response.allowed_sites);
if (!participant?.completedRecommendations) {
const updatedParticipant = await CompleteRecommendations(participant!.id);
setParticipant(updatedParticipant);
Expand All @@ -53,7 +55,7 @@ function SharingPermissions() {

const handleAddSharingSite = async (selectedSiteIds: number[]) => {
try {
const response = await AddSharingParticipants(participant!.id, selectedSiteIds, sharedTypes);
const response = await AddSharingParticipants(participant!.id, selectedSiteIds);
setStatusPopup({
type: 'Success',
message: `${
Expand All @@ -73,11 +75,7 @@ function SharingPermissions() {

const handleDeleteSharingSite = async (siteIdsToDelete: number[]) => {
try {
const response = await DeleteSharingParticipants(
participant!.id,
siteIdsToDelete,
sharedTypes
);
const response = await DeleteSharingParticipants(participant!.id, siteIdsToDelete);
setStatusPopup({
type: 'Success',
message: `${siteIdsToDelete.length} sharing ${
Expand Down Expand Up @@ -105,6 +103,19 @@ function SharingPermissions() {
loadSharingList();
}, [loadSharingList]);

const renderSharingPermissionTable = () => {
if (!participant?.completedRecommendations) return;
const tableSharedSiteIds = sharedSiteIds ?? [];
const tableSharedTypes = sharedSiteIds === null ? ['DSP' as ClientType] : sharedTypes;
jingyi-gao-ttd marked this conversation as resolved.
Show resolved Hide resolved
return (
<SharingPermissionsTable
sharedSiteIds={tableSharedSiteIds}
sharedTypes={tableSharedTypes}
onDeleteSharingPermission={handleDeleteSharingSite}
/>
);
};

return (
<div className='sharingPermissions'>
<h1>Sharing Permissions</h1>
Expand All @@ -124,16 +135,10 @@ function SharingPermissions() {
<Collapsible title='Search and Add Permissions' defaultOpen>
<SearchAndAddParticipants
onSharingPermissionsAdded={handleAddSharingSite}
sharedSiteIds={sharedSiteIds}
sharedSiteIds={sharedSiteIds ?? []}
/>
</Collapsible>
{(participant?.completedRecommendations || sharedSiteIds.length > 0) && (
<SharingPermissionsTable
sharedSiteIds={sharedSiteIds}
sharedTypes={sharedTypes}
onDeleteSharingPermission={handleDeleteSharingSite}
/>
)}
{renderSharingPermissionTable()}
</div>

{statusPopup && (
Expand Down
Loading