feat: Add alternate mimetype support, enhance validation for alternate mimetypes, and improve script loading performance
All checks were successful
CI / container-job (push) Successful in 36s

- mime_type.ts: Added a new column `public alternate_mimetype: string;`
- MimetypeController.ts: Extended validation and storage logic to accommodate the new `alternate_mimetype` attribute
- adonisrc.ts: Integrated new validation rule to validate user-provided mimetypes
- vite.ts: Set `defer: true` for script attributes to improve loading performance
- update_1_to_mime_types.ts: Added migration for the new `alternate_mimetype` column in the database
- UI improvements: Updated components such as AsideMenuLayer.vue, FormCheckRadioGroup.vue, MimeTypeInput.vue, NavBar.vue (lime-green background), NavBarMenu.vue, SectionBannerStarOnGitea.vue, Admin/mimetype/Create.vue, Admin/mimetype/Delete.vue, Admin/mimetype/Index.vue
- allowed_extensions_mimetype.ts: Enhanced rule to also check for alternate mimetypes
- referenceValidation.ts: Improved validation to allow only ISBNs with a '-' delimiter
- package-lock.json: Updated npm dependencie
This commit is contained in:
Kaimbacher 2025-02-13 15:49:09 +01:00
parent 4c5a8f5a42
commit a3031169ca
20 changed files with 719 additions and 704 deletions

View file

@ -14,10 +14,6 @@ import MimeType from '#models/mime_type';
/**
* Options accepted by the unique rule
*/
// type Options = {
// mainLanguageField: string;
// typeField: string;
// };
type Options = {
// size: string | number;
// extnames: string[];
@ -26,13 +22,8 @@ type Options = {
allowedMimeTypes: string[];
};
// async function allowedMimetypeExtensions(file: VineMultipartFile | unknown, options: Options | unknown, field: FieldContext) {
async function allowedMimetypeExtensions(file: VineMultipartFile | unknown, options: Options, field: FieldContext) {
// if (typeof value !== 'string' && typeof value != 'number') {
// return;
// }
if (!isBodyParserFile(file)) {
return;
}
@ -41,10 +32,18 @@ async function allowedMimetypeExtensions(file: VineMultipartFile | unknown, opti
const fileExtension = validatedFile?.extname?.toLocaleLowerCase() as string; // Get file extension from the file
// validate if file extension is allowed in combination with mimetype
const mimeRecord = await MimeType.query().select('file_extension').where('name', mimeType).andWhere('enabled', true).first();
let mimeRecord = await MimeType.query().select('file_extension').where('name', mimeType).andWhere('enabled', true).first();
if (!mimeRecord) {
const allowedMimetypes = await MimeType.query().select('name').where('enabled', true)
mimeRecord = await MimeType.query()
.select('file_extension')
.whereRaw("? = ANY (string_to_array(alternate_mimetype, '|'))", [mimeType])
.andWhere('enabled', true)
.first();
}
if (!mimeRecord) {
const allowedMimetypes = await MimeType.query().select('name').where('enabled', true);
// Transform allowed MIME types to a concatenated string
const allowedMimetypesString = allowedMimetypes.map((mime) => mime.name).join(', ');
// throw new Error('Invalid MIME type');

View file

@ -76,7 +76,8 @@ async function validateReference(value: unknown, options: Options, field: FieldC
}
}
} else if (type === ReferenceIdentifierTypes.ISBN) {
if (!/^(?=(?:[^0-9]*[0-9]){10}(?:(?:[^0-9]*[0-9]){3})?$)[\d-]+$/.test(value)) {
const isbnRegex = /^(?:\d{1,5}-\d{1,7}-\d{1,7}-[\dX]$|97[89]-\d{1,5}-\d{1,7}-\d{1,7}-\d)$/;
if (!isbnRegex.test(value)) {
field.report('The {{ field }} must be a valid ISBN', 'validateReference', field);
} else {
try {

View file

@ -0,0 +1,29 @@
import { FieldContext } from '@vinejs/vine/types';
import vine from '@vinejs/vine';
import { VineString } from '@vinejs/vine';
async function isValidMimetype(value: unknown, options: unknown, field: FieldContext) {
if (typeof value !== 'string') {
return;
}
// Regex pattern to match valid mimetypes (e.g., "application/json", "text/html")
const mimetypePattern = /^[a-zA-Z0-9!#$&^_.+-]+\/[a-zA-Z0-9!#$&^_.+-]+$/;
if (!mimetypePattern.test(value)) {
field.report('The given value is not a valid mimetype', 'isValidMimetype', field);
}
}
export const isValidMimetypeRule = vine.createRule(isValidMimetype);
declare module '@vinejs/vine' {
interface VineString {
isValidMimetype(): this;
}
}
VineString.macro('isValidMimetype', function (this: VineString) {
return this.use(isValidMimetypeRule());
});