-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
iuliandanea
committed
Nov 28, 2024
1 parent
a783d7c
commit bf65dab
Showing
13 changed files
with
539 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
folder: | ||
description: > | ||
Folder object | ||
type: object | ||
required: | ||
- folderId | ||
- archiveNumber | ||
- archiveId | ||
- displayDate | ||
- displayEndDate | ||
properties: | ||
folderId: | ||
type: string | ||
archiveNumber: | ||
type: string | ||
archiveId: | ||
type: string | ||
displayDate: | ||
type: string | ||
format: date-time | ||
displayEndDate: | ||
type: string | ||
format: date-time |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
folder/{id}: | ||
patch: | ||
parameters: | ||
- name: id | ||
in: path | ||
required: true | ||
schema: | ||
type: integer | ||
summary: Update a folder | ||
security: | ||
- bearerHttpAuthentication: [] | ||
operationId: patch-folder | ||
requestBody: | ||
content: | ||
application/json: | ||
schema: | ||
type: object | ||
properties: | ||
archiveNumber: | ||
type: string | ||
displayDate: | ||
type: string | ||
format: date-time | ||
responses: | ||
"200": | ||
description: The updated folder | ||
content: | ||
application/json: | ||
schema: | ||
type: object | ||
properties: | ||
data: | ||
$ref: "../models/folder.yaml#/folder" | ||
"400": | ||
$ref: "../../shared/errors.yaml#/400" | ||
"500": | ||
$ref: "../../shared/errors.yaml#/500" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,128 @@ | ||
import type { Request, NextFunction } from "express"; | ||
import { logger } from "@stela/logger"; | ||
import request from "supertest"; | ||
import { app } from "../app"; | ||
import { db } from "../database"; | ||
import { | ||
extractUserEmailFromAuthToken, | ||
verifyUserAuthentication, | ||
} from "../middleware"; | ||
|
||
jest.mock("../database"); | ||
jest.mock("../middleware"); | ||
jest.mock("@stela/logger"); | ||
|
||
const setupDatabase = async (): Promise<void> => { | ||
await db.sql("fixtures.create_test_folders"); | ||
}; | ||
|
||
const clearDatabase = async (): Promise<void> => { | ||
await db.query( | ||
`TRUNCATE | ||
folder CASCADE` | ||
); | ||
}; | ||
|
||
describe("patch folder", () => { | ||
const agent = request(app); | ||
|
||
beforeEach(async () => { | ||
(verifyUserAuthentication as jest.Mock).mockImplementation( | ||
async ( | ||
req: Request< | ||
unknown, | ||
unknown, | ||
{ userSubjectFromAuthToken?: string; emailFromAuthToken?: string } | ||
>, | ||
__, | ||
next: NextFunction | ||
) => { | ||
req.body.emailFromAuthToken = "test+1@permanent.org"; | ||
req.body.userSubjectFromAuthToken = | ||
"b5461dc2-1eb0-450e-b710-fef7b2cafe1e"; | ||
|
||
next(); | ||
} | ||
); | ||
await clearDatabase(); | ||
await setupDatabase(); | ||
}); | ||
|
||
afterEach(async () => { | ||
await clearDatabase(); | ||
jest.restoreAllMocks(); | ||
jest.clearAllMocks(); | ||
}); | ||
|
||
test("expect an empty query to cause a 400 error", async () => { | ||
await agent.patch("/api/v2/folder/1").send({}).expect(400); | ||
}); | ||
|
||
test("expect non existent record to cause a 404 error", async () => { | ||
await agent | ||
.patch("/api/v2/folder/111111111") | ||
.send({ displayDate: "2024-09-26T15:09:52.000Z" }) | ||
.expect(404); | ||
}); | ||
|
||
test("expect request to have an email from auth token if an auth token exists", async () => { | ||
(extractUserEmailFromAuthToken as jest.Mock).mockImplementation( | ||
(req: Request, __, next: NextFunction) => { | ||
(req.body as { emailFromAuthToken: string }).emailFromAuthToken = | ||
"not an email"; | ||
next(); | ||
} | ||
); | ||
|
||
await agent.patch("/api/v2/folder/1").expect(400); | ||
}); | ||
|
||
test("expect displayDate is updated", async () => { | ||
await agent.patch("/api/v2/folder/1").send({ displayDate: '2024-09-26T15:09:52' }).expect(200); | ||
|
||
const result = await db.query( | ||
"SELECT to_char(displaydt, 'YYYY-MM-DD HH24:MI:SS') as displaydt FROM folder WHERE folderid = :folderId", | ||
{ | ||
folderId: 1, | ||
} | ||
); | ||
|
||
expect(result.rows[0]).toEqual({ displaydt: '2024-09-26 15:09:52' }); | ||
}); | ||
|
||
test("expect displayDate is updated when set to null", async () => { | ||
await agent | ||
.patch("/api/v2/folder/1") | ||
.send({ displayDate: null }) | ||
.expect(200); | ||
|
||
const result = await db.query( | ||
"SELECT displaydt FROM folder WHERE folderid = :folderId", | ||
{ | ||
folderId: 1, | ||
} | ||
); | ||
|
||
expect(result.rows[0]).toStrictEqual({ displaydt: null }); | ||
}); | ||
|
||
test("expect 400 error if display date is wrong type", async () => { | ||
await agent | ||
.patch("/api/v2/folder/1") | ||
.send({ | ||
displayDate: false, | ||
}) | ||
.expect(400); | ||
}); | ||
|
||
test("expect to log error and return 500 if database update fails", async () => { | ||
const testError = new Error("test error"); | ||
jest.spyOn(db, "sql").mockImplementation(async () => { | ||
throw testError; | ||
}); | ||
|
||
await agent.patch("/api/v2/folder/1").send({ displayDate: "2024-09-26T15:09:52.000Z" }).expect(500); | ||
|
||
expect(logger.error).toHaveBeenCalledWith(testError); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
import { | ||
Router, | ||
type Request, | ||
type Response, | ||
type NextFunction, | ||
} from "express"; | ||
import { verifyUserAuthentication } from "../middleware"; | ||
import { getFolderById, patchFolder } from "./service"; | ||
import { | ||
validatePatchFolderRequest, | ||
validateFolderRequest, | ||
} from "./validators"; | ||
import { isValidationError } from "../validators/validator_util"; | ||
|
||
export const folderController = Router(); | ||
|
||
folderController.patch( | ||
"/:folderId", | ||
verifyUserAuthentication, | ||
async (req: Request, res: Response, next: NextFunction) => { | ||
try { | ||
validateFolderRequest(req.params); | ||
validatePatchFolderRequest(req.body); | ||
const folderId = await patchFolder(req.params.folderId, req.body); | ||
const folder = await getFolderById({ | ||
folderId, | ||
}); | ||
|
||
res.status(200).send({ data: folder }); | ||
} catch (err) { | ||
if (isValidationError(err)) { | ||
res.status(400).json({ error: err.message }); | ||
return; | ||
} | ||
next(err); | ||
} | ||
} | ||
); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
import type { PatchFolderRequest, FolderColumnsForUpdate } from "./models"; | ||
|
||
export function requestFieldsToDatabaseFields( | ||
request: PatchFolderRequest, | ||
folderId: string | ||
): FolderColumnsForUpdate { | ||
return { | ||
archivenbr: request.archiveNumber, | ||
archiveid: request.archiveId, | ||
displaydt: request.displayDate, | ||
displayenddt: request.displayEndDate, | ||
folderId, | ||
}; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
export { folderController } from "./controller"; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,107 @@ | ||
export interface Folder { | ||
folderId: string; | ||
archiveNumber: string; | ||
archiveId: string; | ||
displayName: string; | ||
downloadName?: string; | ||
downloadNameOk?: boolean; | ||
displayDate?: string; | ||
displayEndDate?: string; | ||
timeZoneId?: bigint; | ||
note?: string; | ||
description?: string; | ||
special?: string; | ||
sort?: string; | ||
locationId?: bigint; | ||
view?: string; | ||
viewProperty?: string; | ||
thumbArchiveNumber?: string; | ||
imageRatio?: number; | ||
thumbStatus?: string; | ||
thumbUrl200?: string; | ||
thumbUrl500?: string; | ||
thumbUrl1000?: string; | ||
thumbUrl2000?: string; | ||
status: FolderStatus; | ||
type: FolderType; | ||
publicAt: string; | ||
createdAt: string; | ||
updatedAt?: string; | ||
thumbnail256?: string; | ||
thumbnail256CloudPath?: string; | ||
} | ||
|
||
export interface FolderRow { | ||
folderId: string; | ||
archiveNumber: string; | ||
archiveId: string; | ||
displayName: string; | ||
downloadName?: string; | ||
downloadNameOk?: boolean; | ||
displayDate?: string; | ||
displayEndDate?: string; | ||
timeZoneId?: bigint; | ||
note?: string; | ||
description?: string; | ||
special?: string; | ||
sort?: string; | ||
locationId?: bigint; | ||
view?: string; | ||
viewProperty?: string; | ||
thumbArchiveNumber?: string; | ||
imageRatio?: number; | ||
thumbStatus?: string; | ||
thumbUrl200?: string; | ||
thumbUrl500?: string; | ||
thumbUrl1000?: string; | ||
thumbUrl2000?: string; | ||
status: FolderStatus; | ||
type: FolderType; | ||
publicAt: string; | ||
createdAt: string; | ||
updatedAt?: string; | ||
thumbnail256?: string; | ||
thumbnail256CloudPath?: string; | ||
} | ||
|
||
export interface FolderColumnsForUpdate { | ||
folderId: string; | ||
archivenbr: string; | ||
archiveid: bigint; | ||
displaydt: string; | ||
displayenddt: string; | ||
} | ||
|
||
export interface PatchFolderRequest { | ||
emailFromAuthToken: string; | ||
archiveNumber: string; | ||
archiveId: bigint; | ||
displayDate: string; | ||
displayEndDate: string; | ||
} | ||
|
||
export enum FolderStatus { | ||
Deleted = "status.generic.deleted", | ||
Error = "status.generic.error", | ||
ManualReview = "status.generic.manual_review", | ||
Ok = "status.generic.ok", | ||
Copying = "status.folder.copying", | ||
Moving = "status.folder.moving", | ||
New = "status.folder.new", | ||
ThumbnailGenerating = "status.folder.genthumb", | ||
ThumbnailBroken = "status.folder.broken_thumbnail", | ||
NoThumbnailCandidates = "status.folder.no_thumbnail_candidates", | ||
Nested = "status.folder.nested", | ||
Empty = "status.folder.empty", | ||
} | ||
|
||
export enum FolderType { | ||
App = "type.folder.app", | ||
Private = "type.folder.private", | ||
Public = "type.folder.public", | ||
Share = "type.folder.share", | ||
RootApp = "type.folder.root.app", | ||
RootPrivate = "type.folder.root.private", | ||
RootPublic = "type.folder.root.public", | ||
RootRoot = "type.folder.root.root", | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
SELECT | ||
folder.folderid AS "folderId", | ||
folder.archivenbr AS "archiveNumber", | ||
folder.archiveid AS "archiveId", | ||
folder.displaydt AS "displayDate", | ||
folder.displayenddt AS "displayEndDate" | ||
FROM | ||
folder | ||
WHERE folder.folderid = :folderId |
Oops, something went wrong.