feat: Update .gitignore and refine TypeScript configuration; clean up commented code and enhance dataset validation; npm updates
Some checks failed
CI / container-job (push) Failing after 35s

- Updated .gitignore to include new patterns
- Refined TypeScript configuration for better performance and readability
- Cleaned up commented code in several files
- Enhanced dataset validation logic
- Updated npm dependencies to the latest versions
This commit is contained in:
Kaimbacher 2025-01-29 11:26:21 +01:00
parent a5e0a36327
commit 8d47a58d29
22 changed files with 1315 additions and 4273 deletions

1
.gitignore vendored
View file

@ -7,3 +7,4 @@ coverage
tmp
docker-compose.yml
.env.test
public/assets

6
ace.js
View file

@ -15,10 +15,10 @@
/**
* Register hook to process TypeScript files using ts-node
*/
import { register } from 'node:module'
register('ts-node/esm', import.meta.url)
import { register } from 'node:module';
register('ts-node/esm', import.meta.url);
/**
* Import ace console entrypoint
*/
await import('./bin/console.js')
await import('./bin/console.js');

View file

@ -276,7 +276,7 @@ export default class DatasetsController {
validateSMTP: false,
});
const validRecipientEmail: boolean = validationResult.valid;
let emailStatusMessage = '';
// let emailStatusMessage = '';
if (sendMail == true) {
if (dataset.editor.email && validRecipientEmail) {
@ -289,7 +289,7 @@ export default class DatasetsController {
<p>Best regards,<br>Your Tethys reviewer: ${authUser.login}</p>
`);
});
emailStatusMessage = ` A rejection email was successfully sent to ${dataset.editor.email}.`;
// emailStatusMessage = ` A rejection email was successfully sent to ${dataset.editor.email}.`;
} catch (error) {
logger.error(error);
return response
@ -297,7 +297,7 @@ export default class DatasetsController {
.toRoute('reviewer.dataset.list');
}
} else {
emailStatusMessage = ` However, the email could not be sent because the editor's email address (${dataset.editor.email}) is not valid.`;
// emailStatusMessage = ` However, the email could not be sent because the editor's email address (${dataset.editor.email}) is not valid.`;
}
}

View file

@ -1193,7 +1193,7 @@ export default class DatasetController {
throw error;
} else if (error instanceof Exception) {
// General exception handling
return response.flash('errors', { error: error.message }).redirect().back();
return response.flash('errors', error.message).redirect().back();
} else {
session.flash({ error: 'An error occurred while deleting the dataset.' });
return response.redirect().back();

View file

@ -273,7 +273,7 @@ export const updateDatasetValidator = vine.compile(
references: vine
.array(
vine.object({
value: vine.string().trim().minLength(3).maxLength(255),
value: vine.string().trim().minLength(3).maxLength(255).validateReference({ typeField: 'type' }),
type: vine.enum(Object.values(ReferenceIdentifierTypes)),
relation: vine.enum(Object.values(RelationTypes)),
label: vine.string().trim().minLength(2).maxLength(255),

View file

@ -142,7 +142,7 @@ export class VanillaErrorReporter implements ErrorReporterContract {
// }
this.hasErrors = true;
var test = field.getFieldPath();
// var test = field.getFieldPath();
// this.errors.push(error);
// if (this.errors[error.field]) {

View file

@ -47,7 +47,7 @@ const databaseConfig = defineConfig({
migrations: {
naturalSort: true,
},
healthCheck: false,
// healthCheck: false,
debug: false,
pool: { min: 1, max: 100 },
},

View file

@ -12,7 +12,7 @@ const mailConfig = defineConfig({
mailers: {
smtp: transports.smtp({
socketTimeout: 5000,// Overall timeout (5 seconds)
// socketTimeout: 5000,// Overall timeout (5 seconds)
host: env.get('SMTP_HOST', ''),
port: env.get('SMTP_PORT'),
secure: false,
@ -30,10 +30,10 @@ const mailConfig = defineConfig({
}, */
}),
resend: transports.resend({
key: env.get('RESEND_API_KEY'),
baseUrl: 'https://api.resend.com',
}),
// resend: transports.resend({
// key: env.get('RESEND_API_KEY'),
// baseUrl: 'https://api.resend.com',
// }),
},
});

View file

@ -6,7 +6,7 @@
*/
import env from '#start/env';
import app from '@adonisjs/core/services/app';
// import app from '@adonisjs/core/services/app';
import { defineConfig, stores } from '@adonisjs/session';
const sessionConfig = defineConfig({

5289
package-lock.json generated

File diff suppressed because it is too large Load diff

View file

@ -15,28 +15,29 @@
"format-check": "prettier --check ./**/*.{ts,js}",
"test": "node ace test"
},
"eslintIgnore": [
"build"
],
"eslintConfig": {
"ignorePatterns": [
"build"
]
},
"alias": {
"vue": "./node_modules/vue/dist/vue.esm-bundler.js"
},
"devDependencies": {
"@adonisjs/assembler": "^7.1.1",
"@adonisjs/tsconfig": "^1.2.1",
"@adonisjs/tsconfig": "^1.4.0",
"@babel/core": "^7.20.12",
"@babel/plugin-proposal-class-properties": "^7.18.6",
"@babel/plugin-proposal-decorators": "^7.20.13",
"@babel/plugin-transform-runtime": "^7.19.6",
"@babel/preset-env": "^7.20.2",
"@babel/preset-typescript": "^7.18.6",
"@japa/api-client": "^2.0.3",
"@japa/assert": "^3.0.0",
"@japa/plugin-adonisjs": "^3.0.0",
"@japa/runner": "^3.1.1",
"@japa/assert": "^4.0.1",
"@japa/plugin-adonisjs": "^4.0.0",
"@japa/runner": "^4.2.0",
"@mdi/js": "^7.1.96",
"@poppinss/utils": "^6.7.2",
"@swc/core": "^1.4.2",
"@swc/core": "^1.10.1",
"@symfony/webpack-encore": "^5.0.1",
"@tailwindcss/forms": "^0.5.2",
"@types/bcryptjs": "^2.4.6",
@ -44,7 +45,7 @@
"@types/escape-html": "^1.0.4",
"@types/leaflet": "^1.9.3",
"@types/luxon": "^3.4.2",
"@types/node": "^22.5.5",
"@types/node": "^22.10.2",
"@types/proxy-addr": "^2.0.0",
"@types/qrcode": "^1.5.5",
"@types/source-map-support": "^0.5.6",
@ -60,14 +61,14 @@
"eslint-plugin-prettier": "^5.0.0-alpha.2",
"numeral": "^2.0.6",
"pinia": "^2.0.30",
"pino-pretty": "^11.2.2",
"pino-pretty": "^13.0.0",
"postcss-loader": "^8.1.1",
"prettier": "^3.0.0",
"prettier": "^3.4.2",
"supertest": "^6.3.3",
"tailwindcss": "^3.2.4",
"ts-loader": "^9.4.2",
"ts-node": "^10.9.2",
"typescript": "^5.1.3",
"typescript": "~5.7",
"vue": "^3.4.26",
"vue-facing-decorator": "^3.0.0",
"vue-loader": "^17.0.1",
@ -75,26 +76,29 @@
"xslt3": "^2.5.0"
},
"dependencies": {
"@adonisjs/auth": "^9.1.1",
"@adonisjs/core": "^6.3.1",
"@adonisjs/auth": "^9.2.4",
"@adonisjs/core": "^6.17.0",
"@adonisjs/cors": "^2.2.1",
"@adonisjs/drive": "^2.3.0",
"@adonisjs/drive": "^3.2.0",
"@adonisjs/encore": "^1.0.0",
"@adonisjs/inertia": "^1.0.0-7",
"@adonisjs/lucid": "^21.1.0",
"@adonisjs/inertia": "^2.1.3",
"@adonisjs/lucid": "^21.5.1",
"@adonisjs/mail": "^9.2.2",
"@adonisjs/redis": "^9.1.0",
"@adonisjs/session": "^7.1.1",
"@adonisjs/session": "^7.5.0",
"@adonisjs/shield": "^8.1.1",
"@adonisjs/static": "^1.1.1",
"@adonisjs/vite": "^4.0.0",
"@eidellev/adonis-stardust": "^3.0.0",
"@fontsource/archivo-black": "^5.0.1",
"@fontsource/inter": "^5.0.1",
"@inertiajs/inertia": "^0.11.1",
"@inertiajs/vue3": "^1.0.0",
"@inertiajs/vue3": "^2.0.3",
"@opensearch-project/opensearch": "^2.4.0",
"@phc/format": "^1.0.0",
"@vinejs/vine": "^2.0.0",
"@poppinss/manager": "^5.0.2",
"@vinejs/vine": "^3.0.0",
"axios": "^1.7.9",
"bcrypt": "^5.1.1",
"bcryptjs": "^2.4.3",
"clamscan": "^2.1.2",

View file

@ -69,7 +69,7 @@ export default class MailProvider {
const mailConfigProvider = this.app.config.get('mail');
const config = await configProvider.resolve<any>(this.app, mailConfigProvider);
const iwas = await config.mailers.smtp();
await config.mailers.smtp();
// iwas.config.host = 'hhhost';
// this.app.config.set('mail.mailers.smtp.host', 'xhost');
// const iwas = await config.mailers.smtp();

View file

@ -5,7 +5,7 @@
|*/
import type { ApplicationService } from '@adonisjs/core/types';
import vine, { BaseLiteralType, Vine } from '@vinejs/vine';
import type { Validation, FieldContext, FieldOptions } from '@vinejs/vine/types';
import type { FieldContext, FieldOptions } from '@vinejs/vine/types';
// import type { MultipartFile, FileValidationOptions } from '@adonisjs/bodyparser/types';
import type { MultipartFile } from '@adonisjs/core/bodyparser';
import type { FileValidationOptions } from '@adonisjs/core/types/bodyparser';
@ -28,8 +28,7 @@ declare module '@vinejs/vine' {
* Extend HTTP request class
*/
declare module '@adonisjs/core/http' {
interface Request extends RequestValidator {
}
interface Request extends RequestValidator {}
}
/**
@ -48,7 +47,7 @@ export async function getEnabledExtensions() {
.flat();
return extensions;
};
}
/**
* VineJS validation rule that validates the file to be an
* instance of BodyParser MultipartFile class.
@ -82,8 +81,8 @@ const isMultipartFile = vine.createRule(async (file: MultipartFile | unknown, op
if (validatedFile.allowedExtensions === undefined && validationOptions.extnames) {
validatedFile.allowedExtensions = await getEnabledExtensions();
}
/**
* wieder löschen
/**
* wieder löschen
* Set extensions when it's defined in the options and missing
* on the file instance
*/
@ -111,14 +110,16 @@ export class VineMultipartFile extends BaseLiteralType<MultipartFile, MultipartF
// extnames: (18) ['gpkg', 'htm', 'html', 'csv', 'txt', 'asc', 'c', 'cc', 'h', 'srt', 'tiff', 'pdf', 'png', 'zip', 'jpg', 'jpeg', 'jpe', 'xlsx']
// size: '512mb'
public constructor(validationOptions?: FileRuleValidationOptions, options?: FieldOptions, validations?: Validation<any>[]) {
// public constructor(validationOptions?: FileRuleValidationOptions, options?: FieldOptions, validations?: Validation<any>[]) {
public constructor(validationOptions?: FileRuleValidationOptions, options?: FieldOptions) {
// super(options, validations);
super(options, [isMultipartFile(validationOptions || {})]);
this.validationOptions = validationOptions;
}
public clone(): any {
return new VineMultipartFile(this.validationOptions, this.cloneOptions(), this.cloneValidations());
// return new VineMultipartFile(this.validationOptions, this.cloneOptions(), this.cloneValidations());
return new VineMultipartFile(this.validationOptions, this.cloneOptions());
}
}
@ -153,9 +154,8 @@ export default class VinejsProvider {
* data for the current request using VineJS validators
*/
Request.macro('validateUsing', function (...args) {
return new RequestValidator(this.ctx).validateUsing(...args);
});
return new RequestValidator(this.ctx).validateUsing(...args);
});
}
/**

View file

@ -20,7 +20,7 @@
import AuthLayout from '@/Layouts/Auth.vue';
import { reactive } from 'vue';
import { useForm } from '@inertiajs/vue3';
import { Inertia } from '@inertiajs/inertia';
// import { Inertia } from '@inertiajs/inertia';
// import { NButton, NInput } from 'naive-ui';
// import { useForm } from '@inertiajs/inertia-vue3'
import FormInput from '@/Components/FormInput.vue';
@ -45,7 +45,7 @@ export default {
});
const submit = async () => {
await Inertia.post('/app/register', form);
// await Inertia.post('/app/register', form);
};
return { form, submit };

View file

@ -72,9 +72,19 @@ createInertiaApp({
.use(EmitterPlugin);
// .component('inertia-link', Link)
// Listen for navigation event to handle layout changes
// window.addEventListener('inertia:navigate', () => {
// layoutService.isAsideMobileExpanded = false;
// layoutService.isAsideLgActive = false;
// });
asyncPlugin.install('settings').then(() => {
app.mount(el);
});
},
});

View file

@ -15,5 +15,5 @@
},
},
"include": ["./**/*.ts", "./**/*.vue"],
"exclude": ["./utils/*.js"],
"exclude": ["./utils/*.js", "./utils/Timer.js", "./utils/focusTrap.js"],
}

View file

@ -1,16 +1,15 @@
/**
* Get the first day of the week
*
* @return {number}
*/
export function getFirstDay(): number {
if (typeof window.firstDay === 'undefined') {
console.warn('No firstDay found')
return 1
}
if (typeof window.firstDay === 'undefined') {
console.warn('No firstDay found');
return 1;
}
return window.firstDay
return window.firstDay;
}
/**
@ -19,20 +18,12 @@ export function getFirstDay(): number {
* @return {string[]}
*/
export function getDayNames(): string[] {
if (typeof window.dayNames === 'undefined') {
console.warn('No dayNames found')
return [
'Sunday',
'Monday',
'Tuesday',
'Wednesday',
'Thursday',
'Friday',
'Saturday',
]
}
if (typeof window.dayNames === 'undefined') {
console.warn('No dayNames found');
return ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'];
}
return window.dayNames
return window.dayNames;
}
/**
@ -41,12 +32,12 @@ export function getDayNames(): string[] {
* @return {string[]}
*/
export function getDayNamesShort(): string[] {
if (typeof window.dayNamesShort === 'undefined') {
console.warn('No dayNamesShort found')
return ['Sun.', 'Mon.', 'Tue.', 'Wed.', 'Thu.', 'Fri.', 'Sat.']
}
if (typeof window.dayNamesShort === 'undefined') {
console.warn('No dayNamesShort found');
return ['Sun.', 'Mon.', 'Tue.', 'Wed.', 'Thu.', 'Fri.', 'Sat.'];
}
return window.dayNamesShort
return window.dayNamesShort;
}
/**
@ -55,12 +46,12 @@ export function getDayNamesShort(): string[] {
* @return {string[]}
*/
export function getDayNamesMin(): string[] {
if (typeof window.dayNamesMin === 'undefined') {
console.warn('No dayNamesMin found')
return ['Su', 'Mo', 'Tu', 'We', 'Th', 'Fr', 'Sa']
}
if (typeof window.dayNamesMin === 'undefined') {
console.warn('No dayNamesMin found');
return ['Su', 'Mo', 'Tu', 'We', 'Th', 'Fr', 'Sa'];
}
return window.dayNamesMin
return window.dayNamesMin;
}
/**
@ -69,25 +60,12 @@ export function getDayNamesMin(): string[] {
* @return {string[]}
*/
export function getMonthNames(): string[] {
if (typeof window.monthNames === 'undefined') {
console.warn('No monthNames found')
return [
'January',
'February',
'March',
'April',
'May',
'June',
'July',
'August',
'September',
'October',
'November',
'December',
]
}
if (typeof window.monthNames === 'undefined') {
console.warn('No monthNames found');
return ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'];
}
return window.monthNames
return window.monthNames;
}
/**
@ -96,23 +74,10 @@ export function getMonthNames(): string[] {
* @return {string[]}
*/
export function getMonthNamesShort(): string[] {
if (typeof window.monthNamesShort === 'undefined') {
console.warn('No monthNamesShort found')
return [
'Jan.',
'Feb.',
'Mar.',
'Apr.',
'May.',
'Jun.',
'Jul.',
'Aug.',
'Sep.',
'Oct.',
'Nov.',
'Dec.',
]
}
if (typeof window.monthNamesShort === 'undefined') {
console.warn('No monthNamesShort found');
return ['Jan.', 'Feb.', 'Mar.', 'Apr.', 'May.', 'Jun.', 'Jul.', 'Aug.', 'Sep.', 'Oct.', 'Nov.', 'Dec.'];
}
return window.monthNamesShort
return window.monthNamesShort;
}

View file

@ -79,7 +79,7 @@ router.group(() => {
}).as('register.show');
router.post('/register', async ({ request, response }: HttpContext) => {
const data = await request.validateUsing(authValidator);
await request.validateUsing(authValidator);
return response.redirect().toRoute('app.index');
}).as('register.store');
}).prefix('apps').as('apps').use(middleware.auth());

View file

@ -25,6 +25,7 @@ type Options = {
clientNameSizeLimit: number;
};
// async function allowedMimetypeExtensions(file: VineMultipartFile | unknown, options: Options | unknown, field: FieldContext) {
async function allowedMimetypeExtensions(file: VineMultipartFile | unknown, options: Options | unknown, field: FieldContext) {
// if (typeof value !== 'string' && typeof value != 'number') {
// return;

View file

@ -3,37 +3,16 @@
| Preloaded File - node ace make:preload rules/fileScan
|--------------------------------------------------------------------------
|*/
import { FieldContext } from '@vinejs/vine/types';
import vine, { errors } from '@vinejs/vine';
// import { VineString } from '@vinejs/vine';
import { VineMultipartFile, isBodyParserFile } from '#providers/vinejs_provider';
import type { MultipartFile } from '@adonisjs/core/bodyparser';
import ClamScan from 'clamscan';
/**
* Options accepted by the unique rule
*/
// type Options = {
// mainLanguageField: string;
// typeField: string;
// };
type Options = {
// size: string | number;
// extnames: string[];
removeInfected: boolean;
// debugMode?: boolean;
// scanRecursively?: boolean;
host?: string;
port?: number;
// clamdscan: {
// active: boolean;
// host: string;
// port: number;
// multiscan: boolean;
// };
// preference: string;
};
async function fileScan(file: VineMultipartFile | unknown, options: Options, field: FieldContext) {
@ -46,40 +25,45 @@ async function fileScan(file: VineMultipartFile | unknown, options: Options, fie
const validatedFile = file as MultipartFile;
try {
await scanFileForViruses(validatedFile.tmpPath, options.host, options.port); //, 'gitea.lan', 3310);
// await this.scanFileForViruses("/tmp/testfile.txt");
await scanFileForViruses(validatedFile.tmpPath, options);
} catch (error) {
// If the file is infected or there's an error scanning the file, throw a validation exception
// throw error;
field.report(`Upload error. Code: ${error.code} message: ${error.messages.uploadError}`, 'fileScan', field);
}
}
async function scanFileForViruses(filePath: string | undefined, host?: string, port?: number): Promise<void> {
// const clamscan = await (new ClamScan().init());
async function scanFileForViruses(filePath: string | undefined, options: Options): Promise<void> {
if (!filePath) {
throw new errors.E_VALIDATION_ERROR({ uploadError: 'File path is undefined!' });
}
const opts: ClamScan.Options = {
removeInfected: true, // If true, removes infected files
debugMode: false, // Whether or not to log info/debug/error msgs to the console
removeInfected: options.removeInfected, // If true, removes infected files
debugMode: false, // If true, deep scan folders recursively
scanRecursively: true, // If true, deep scan folders recursively
clamdscan: {
active: true, // If true, this module will consider using the clamdscan binary
host,
port,
host: options.host,
port: options.port,
multiscan: true, // Scan using all available cores! Yay!
},
preference: 'clamdscan', // If clamdscan is found and active, it will be used by default
};
const clamscan = await new ClamScan().init(opts);
return new Promise(async (resolve, reject) => {
try {
const clamscan = await new ClamScan().init(opts);
// You can re-use the `clamscan` object as many times as you want
// const version = await clamscan.getVersion();
// console.log(`ClamAV Version: ${version}`);
const { file, isInfected, viruses } = await clamscan.isInfected(filePath);
const result = await clamscan.isInfected(filePath);
if (!result || typeof result.isInfected === 'undefined') {
reject(new errors.E_VALIDATION_ERROR({ uploadError: 'Unexpected response from virus scan!' }));
return;
}
const { file, isInfected, viruses } = result;
if (isInfected) {
console.log(`${file} is infected with ${viruses}!`);
// reject(new ValidationException(true, { 'upload error': `File ${file} is infected!` }));
reject(new errors.E_VALIDATION_ERROR({ uploadError: `File ${file} is infected!` }));
console.log(`${file} is infected with ${viruses}!`); // reject(new ValidationException(true, { 'upload error': `File ${file} is infected!` }));
reject(new errors.E_VALIDATION_ERROR({ uploadError: `File ${file} is infected with ${viruses}!` }));
} else {
resolve();
}

View file

@ -1,7 +1,7 @@
import { FieldContext } from '@vinejs/vine/types';
import vine from '@vinejs/vine';
import { VineString } from '@vinejs/vine';
import axios, { AxiosInstance } from 'axios';
import axios from 'axios';
import { ReferenceIdentifierTypes } from '#contracts/enums';
type Options = {
@ -11,7 +11,7 @@ type Options = {
// Function to check if DOI exists using the DOI API
async function checkDoiExists(doi: string): Promise<boolean> {
try {
const response = await axios.get(`${doi}`);
const response = await axios.default.get(`${doi}`);
return response.status === 200; // If status is 200, DOI is valid
} catch (error) {
return false; // If request fails, DOI does not exist
@ -21,7 +21,7 @@ async function checkDoiExists(doi: string): Promise<boolean> {
// Function to check if ISBN exists using the Open Library API
async function checkIsbnExists(isbn: string): Promise<boolean> {
try {
const response = await axios.get(`https://isbnsearch.org/isbn/${isbn}`);
const response = await axios.default.get(`https://isbnsearch.org/isbn/${isbn}`);
return response.data && response.status == 200; // If title is returned, ISBN is valid
} catch (error) {
return false; // If request fails, ISBN does not exist

View file

@ -51,7 +51,7 @@ test.group('ReferenceValidation', () => {
vine.object({
reference: vine.string().validateReference({ typeField: 'type' }),
type: vine.enum(Object.values(ReferenceIdentifierTypes)),
})
}),
);
const data = {
@ -71,7 +71,7 @@ test.group('ReferenceValidation', () => {
vine.object({
reference: vine.string().validateReference({ typeField: 'type' }),
type: vine.enum(Object.values(ReferenceIdentifierTypes)),
})
}),
);
const data = {
@ -95,7 +95,7 @@ test.group('ReferenceValidation', () => {
vine.object({
reference: vine.string().validateReference({ typeField: 'type' }),
type: vine.enum(Object.values(ReferenceIdentifierTypes)),
})
}),
);
const data = {
@ -116,7 +116,7 @@ test.group('ReferenceValidation', () => {
vine.object({
reference: vine.string().validateReference({ typeField: 'type' }),
type: vine.enum(Object.values(ReferenceIdentifierTypes)),
})
}),
);
const data = {
@ -137,7 +137,7 @@ test.group('ReferenceValidation', () => {
vine.object({
reference: vine.string().validateReference({ typeField: 'type' }),
type: vine.enum(Object.values(ReferenceIdentifierTypes)),
})
}),
);
const data = {
@ -158,7 +158,7 @@ test.group('ReferenceValidation', () => {
vine.object({
reference: vine.string().validateReference({ typeField: 'type' }),
type: vine.enum(Object.values(ReferenceIdentifierTypes)),
})
}),
);
const data = {
@ -179,7 +179,7 @@ test.group('ReferenceValidation', () => {
vine.object({
reference: vine.string().validateReference({ typeField: 'type' }),
type: vine.enum(Object.values(ReferenceIdentifierTypes)),
})
}),
);
const data = {