Skip to content

Commit

Permalink
fix: Fetch announcement with the edit button is clicked (#724)
Browse files Browse the repository at this point in the history
  • Loading branch information
goemen authored Sep 5, 2024
1 parent ae02c20 commit 848bb6f
Show file tree
Hide file tree
Showing 8 changed files with 161 additions and 11 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -53,12 +53,13 @@ import { useAnnouncementSelectionStore } from '../../store/modules/announcementS
import { ref } from 'vue';
import { NotificationService } from '../../services/notificationService';
import { useRouter } from 'vue-router';
import { Announcement } from '../../types/announcements';
const router = useRouter();
const announcementSelectionStore = useAnnouncementSelectionStore();
const { announcement } = defineProps<{
announcement: any;
const props = defineProps<{
announcement: Announcement;
}>();
const announcementSearchStore = useAnnouncementSearchStore();
Expand Down Expand Up @@ -116,8 +117,18 @@ async function unpublishAnnouncement(announcementId: string) {
}
}
const editAnnouncement = () => {
announcementSelectionStore.setAnnouncement(announcement);
router.push('/edit-announcement');
const editAnnouncement = async () => {
const { announcement_id } = props.announcement;
try {
const announcement = await ApiService.getAnnouncement(announcement_id);
announcementSelectionStore.setAnnouncement(announcement);
router.push(`/edit-announcement`);
} catch (e) {
console.error(e);
NotificationService.pushNotificationError(
'Error',
'An error occurred while trying to load the announcement.',
);
}
};
</script>
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { createVuetify } from 'vuetify';
import * as components from 'vuetify/components';
import * as directives from 'vuetify/directives';
import ApiService from '../../../services/apiService';
import { NotificationService } from '../../../services/notificationService';
import { Announcement } from '../../../types/announcements';
import AnnouncementActions from '../AnnouncementActions.vue';

Expand Down Expand Up @@ -143,4 +144,36 @@ describe('AnnouncementActions', () => {
});
});
});

describe('edit announcement', () => {
it('sets the announcement to edit mode', async () => {
const apiSpy = vi
.spyOn(ApiService, 'getAnnouncement')
.mockImplementation(() => {
return Promise.resolve(mockDraftAnnouncement as any);
});
await wrapper.vm.editAnnouncement();

expect(apiSpy).toHaveBeenCalledWith(
mockDraftAnnouncement.announcement_id,
);
});

describe('when the announcement is not successfully retrieved', () => {
it('shows an error message', async () => {
vi.spyOn(ApiService, 'getAnnouncement').mockImplementation(() => {
return Promise.reject();
});

const errorSnackbarSpy = vi.spyOn(
NotificationService,
'pushNotificationError',
);

await wrapper.vm.editAnnouncement();

expect(errorSnackbarSpy).toHaveBeenCalled();
});
});
});
});
28 changes: 28 additions & 0 deletions admin-frontend/src/services/__tests__/apiService.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -527,6 +527,34 @@ describe('ApiService', () => {
});
});

describe('getAnnouncement', () => {
it('returns an announcement', async () => {
const mockBackendResponse = { title: 'test' };
const mockAxiosResponse = {
data: mockBackendResponse,
};
vi.spyOn(ApiService.apiAxios, 'get').mockResolvedValueOnce(
mockAxiosResponse,
);

const resp = await ApiService.getAnnouncement('1');
expect(resp).toEqual(mockBackendResponse);
});

describe('when the data are not successfully retrieved from the backend', () => {
it('returns a rejected promise', async () => {
const mockAxiosError = new AxiosError();
vi.spyOn(ApiService.apiAxios, 'get').mockRejectedValueOnce(
mockAxiosError,
);

await expect(ApiService.getAnnouncement('1')).rejects.toEqual(
mockAxiosError,
);
});
});
});

describe('clamavScanFile', () => {
describe('when the given file is valid', () => {
it('returns a response', async () => {
Expand Down
20 changes: 20 additions & 0 deletions admin-frontend/src/services/apiService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {
UserInvite,
} from '../types';
import {
Announcement,
AnnouncementFilterType,
AnnouncementFormValue,
AnnouncementSortType,
Expand Down Expand Up @@ -337,6 +338,25 @@ export default {
}
},

async getAnnouncement(id: string) {
try {
const { data } = await apiAxios.get<
Announcement & {
announcement_resource: {
resource_type: string;
display_name: string;
resource_url: string;
attachment_file_id: string;
}[];
}
>(`${ApiRoutes.ANNOUNCEMENTS}/${id}`);
return data;
} catch (e) {
console.log(`Failed to get announcement from API - ${e}`);
throw e;
}
},

/**
* Download a list of reports in csv format. This method also causes
* the browser to save the resulting file.
Expand Down
20 changes: 20 additions & 0 deletions backend/src/v1/routes/announcement-routes.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,15 @@ const mockGetAnnouncements = jest.fn().mockResolvedValue({
const mockPatchAnnouncements = jest.fn();
const mockCreateAnnouncement = jest.fn();
const mockUpdateAnnouncement = jest.fn();
const mockGetAnnouncementById = jest.fn();
jest.mock('../services/announcements-service', () => ({
getAnnouncements: (...args) => {
return mockGetAnnouncements(...args);
},
patchAnnouncements: (...args) => mockPatchAnnouncements(...args),
createAnnouncement: (...args) => mockCreateAnnouncement(...args),
updateAnnouncement: (...args) => mockUpdateAnnouncement(...args),
getAnnouncementById: (...args) => mockGetAnnouncementById(...args),
}));

jest.mock('../middlewares/authorization/authenticate-admin', () => ({
Expand Down Expand Up @@ -431,4 +433,22 @@ describe('announcement-routes', () => {
});
});
});

describe('GET /:id - get announcement by id', () => {
it('should return 200', async () => {
const response = await request(app).get('/123');
expect(response.status).toBe(200);
expect(mockGetAnnouncementById).toHaveBeenCalledWith("123");
});

describe('when service throws error', () => {
it('should return 400', async () => {
mockGetAnnouncementById.mockRejectedValue(new Error('Invalid request'));
const response = await request(app).get('/123');

expect(response.status).toBe(400);
expect(response.body.error).toBeDefined();
});
});
})
});
13 changes: 12 additions & 1 deletion backend/src/v1/routes/announcement-routes.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Router } from 'express';
import { Request, Router } from 'express';
import formData from 'express-form-data';
import os from 'os';
import { APP_ANNOUNCEMENTS_FOLDER } from '../../constants/admin';
Expand All @@ -9,6 +9,7 @@ import { useUpload } from '../middlewares/storage/upload';
import { useValidate } from '../middlewares/validations';
import {
createAnnouncement,
getAnnouncementById,
getAnnouncements,
patchAnnouncements,
updateAnnouncement,
Expand Down Expand Up @@ -137,4 +138,14 @@ router.put(
},
);

router.get('/:id', authenticateAdmin(), async (req: Request, res) => {
try {
const announcement = await getAnnouncementById(req.params.id);
return res.json(announcement);
} catch (error) {
logger.error(error);
res.status(400).json({ message: 'Invalid request', error });
}
});

export default router;
17 changes: 14 additions & 3 deletions backend/src/v1/services/announcements-service.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ jest.mock('../prisma/prisma-client', () => ({
count: jest.fn().mockResolvedValue(2),
updateMany: (...args) => mockUpdateMany(...args),
create: (...args) => mockCreateAnnouncement(...args),
findUniqueOrThrow: (...args) => mockFindUniqueOrThrow(...args),
},
announcement_history: {
create: (...args) => mockHistoryCreate(...args),
Expand Down Expand Up @@ -832,7 +833,7 @@ describe('AnnouncementsService', () => {
});
});

it('should default to undefined dates', async () => {
it('should default to null dates', async () => {
mockFindUniqueOrThrow.mockResolvedValue({
id: 'announcement-id',
announcement_resource: [],
Expand All @@ -855,8 +856,8 @@ describe('AnnouncementsService', () => {
expect.objectContaining({
where: { announcement_id: 'announcement-id' },
data: expect.objectContaining({
expires_on: undefined,
published_on: undefined,
expires_on: null,
published_on: null,
}),
}),
);
Expand Down Expand Up @@ -912,4 +913,14 @@ describe('AnnouncementsService', () => {
});
});
});

describe('getAnnouncementById', () => {
it('should return announcement by id', async () => {
await AnnouncementService.getAnnouncementById('1');
expect(mockFindUniqueOrThrow).toHaveBeenCalledWith({
where: { announcement_id: '1' },
include: { announcement_resource: true },
});
});
});
});
20 changes: 18 additions & 2 deletions backend/src/v1/services/announcements-service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,22 @@ export const getAnnouncements = async (
};
};

/**
* Get announcement by id
* @param id
* @returns
*/
export const getAnnouncementById = async (id: string): Promise<announcement> => {
return prisma.announcement.findUniqueOrThrow({
where: {
announcement_id: id,
},
include: {
announcement_resource: true,
},
});
}

/**
* Patch announcements by ids.
* This method also copies the original record into the announcement history table.
Expand Down Expand Up @@ -411,8 +427,8 @@ export const updateAnnouncement = async (
},
published_on: !isEmpty(input.published_on)
? input.published_on
: undefined,
expires_on: !isEmpty(input.expires_on) ? input.expires_on : undefined,
: null,
expires_on: !isEmpty(input.expires_on) ? input.expires_on : null,
admin_user_announcement_updated_byToadmin_user: {
connect: { admin_user_id: currentUserId },
},
Expand Down

0 comments on commit 848bb6f

Please sign in to comment.