-
Notifications
You must be signed in to change notification settings - Fork 0
refactor: consume file types, add doc string and merge image upload handling #839
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
Open
fingertips18
wants to merge
5
commits into
main
Choose a base branch
from
refactor/file-integration
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
5 commits
Select commit
Hold shift + click to select a range
7dbe120
refactor: consume file types, add doc string and merge image upload h…
fingertips18 d69e20a
Correct image source, validation, and control flow
fingertips18 bc2f348
Prevent invalid requests and orphaned data
fingertips18 9ec2010
Resolve unsafe cast before validation
fingertips18 1902e4b
Resolve file handler test issue
fingertips18 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Some comments aren't visible on the classic Files Changed page.
There are no files selected for viewing
This file contains hidden or 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 hidden or 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 hidden or 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 hidden or 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 hidden or 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,169 @@ | ||
| import { ensureDate, ensureNumber, ensureString } from '.'; | ||
|
|
||
| export const FileRole = { | ||
| image: 'image', | ||
| } as const; | ||
|
|
||
| export type File = { | ||
| id: string; | ||
| parentTable: string; | ||
| parentID: string; | ||
| role: (typeof FileRole)[keyof typeof FileRole]; | ||
| name: string; | ||
| url: string; | ||
| type: string; | ||
| size: number; | ||
| createdAt: Date; | ||
| updatedAt: Date; | ||
| }; | ||
|
|
||
| /** | ||
| * Validates that a value is a valid file role. | ||
| * | ||
| * @param value - The value to validate as a file role | ||
| * @returns The validated file role value | ||
| * @throws {Error} If the value is not a string or is not a valid file role | ||
| */ | ||
| function ensureRole(value: unknown): 'image' { | ||
| const roleString = ensureString({ | ||
| value, | ||
| name: 'role', | ||
| }); | ||
|
|
||
| if ( | ||
| !Object.values(FileRole).includes( | ||
| roleString as (typeof FileRole)[keyof typeof FileRole], | ||
| ) | ||
| ) { | ||
| throw new Error(`Invalid file role: ${roleString}`); | ||
| } | ||
|
|
||
| return roleString as (typeof FileRole)[keyof typeof FileRole]; | ||
| } | ||
|
|
||
| /** | ||
| * Maps a DTO object to a File domain object. | ||
| * | ||
| * @param dto - The data transfer object to map | ||
| * @returns The mapped File domain object with validated properties | ||
| * @throws {Error} If the DTO is not a valid object or contains invalid properties | ||
| */ | ||
| export function mapFile(dto: unknown): File { | ||
| if (typeof dto !== 'object' || dto === null) { | ||
| throw new Error('Invalid file DTO'); | ||
| } | ||
|
|
||
| const d = dto as Record<string, unknown>; | ||
|
|
||
| return { | ||
| id: ensureString({ value: d.id, name: 'id' }), | ||
| parentTable: ensureString({ value: d.parent_table, name: 'parent_table' }), | ||
| parentID: ensureString({ value: d.parent_id, name: 'parent_id' }), | ||
| role: ensureRole(d.role), | ||
| name: ensureString({ value: d.name, name: 'name' }), | ||
| url: ensureString({ value: d.url, name: 'url' }), | ||
| type: ensureString({ value: d.type, name: 'type' }), | ||
| size: ensureNumber({ value: d.size, name: 'size' }), | ||
| createdAt: ensureDate({ value: d.created_at, name: 'created_at' }), | ||
| updatedAt: ensureDate({ value: d.updated_at, name: 'updated_at' }), | ||
| }; | ||
| } | ||
|
|
||
| /** | ||
| * Converts a File domain object to a JSON-serializable format. | ||
| * | ||
| * @param file - The File domain object to convert | ||
| * @returns A record with snake_case keys suitable for API serialization, excluding undefined values | ||
| */ | ||
| export function toJSONFile(file: Partial<File>): Record<string, unknown> { | ||
| const result: Record<string, unknown> = { | ||
| id: file.id, | ||
| parent_table: file.parentTable, | ||
| parent_id: file.parentID, | ||
| role: file.role, | ||
| name: file.name, | ||
| url: file.url, | ||
| type: file.type, | ||
| size: file.size, | ||
| created_at: file.createdAt ? file.createdAt.toISOString() : undefined, | ||
| updated_at: file.updatedAt ? file.updatedAt.toISOString() : undefined, | ||
| }; | ||
|
|
||
| // Filter out undefined values | ||
| return Object.fromEntries( | ||
| Object.entries(result).filter(([, v]) => v !== undefined), | ||
| ); | ||
| } | ||
|
|
||
| // -------------------- UPLOADTHING types below -------------------- | ||
|
|
||
| /** | ||
| * Represents a file that has been successfully uploaded via UploadThing. | ||
| */ | ||
| export type FileUpload = { | ||
| key: string; | ||
| fileName: string; | ||
| fileType: string; | ||
| fileURL: string; | ||
| contentDisposition: string; | ||
| pollingJWT: string; | ||
| pollingURL: string; | ||
| customId?: string; | ||
| URL: string; | ||
| fields: Record<string, string>; | ||
| }; | ||
|
|
||
| /** | ||
| * Validates and converts an unknown value to a fields object with string values. | ||
| * | ||
| * @param value - The value to validate and convert as fields | ||
| * @returns An object with string values | ||
| * @throws {Error} If any field value is not a string | ||
| * @throws {Error} If the value is not a valid object | ||
| */ | ||
| function ensureFields(value: unknown): { [k: string]: string } { | ||
| if (!value || typeof value !== 'object') { | ||
| throw new Error("Expected property 'fields' to be an object"); | ||
| } | ||
|
|
||
| return Object.fromEntries( | ||
| Object.entries(value).map(([k, v]) => [ | ||
| k, | ||
| ensureString({ value: v, name: k }), | ||
| ]), | ||
| ); | ||
| } | ||
|
|
||
| /** | ||
| * Maps a DTO object to a FileUpload domain object. | ||
| * | ||
| * @param dto - The data transfer object to map | ||
| * @returns The mapped FileUpload domain object with validated properties | ||
| * @throws {Error} If the DTO is not a valid object or contains invalid properties | ||
| */ | ||
| export function mapFileUpload(dto: unknown): FileUpload { | ||
| if (typeof dto !== 'object' || dto === null) { | ||
| throw new Error('Invalid file DTO'); | ||
| } | ||
|
|
||
| const d = dto as Record<string, unknown>; | ||
|
|
||
| return { | ||
| key: ensureString({ value: d.key, name: 'key' }), | ||
| fileName: ensureString({ value: d.file_name, name: 'file_name' }), | ||
| fileType: ensureString({ value: d.file_type, name: 'file_type' }), | ||
| fileURL: ensureString({ value: d.file_url, name: 'file_url' }), | ||
| contentDisposition: ensureString({ | ||
| value: d.content_disposition, | ||
| name: 'content_disposition', | ||
| }), | ||
| pollingJWT: ensureString({ value: d.polling_jwt, name: 'polling_jwt' }), | ||
| pollingURL: ensureString({ value: d.polling_url, name: 'polling_url' }), | ||
| customId: | ||
| d.custom_id != null | ||
| ? ensureString({ value: d.custom_id, name: 'custom_id' }) | ||
| : undefined, | ||
| URL: ensureString({ value: d.url, name: 'url' }), | ||
| fields: ensureFields(d.fields), | ||
| }; | ||
| } | ||
This file was deleted.
Oops, something went wrong.
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.