- replaced validation library @adonisjs/validator with @vinejs/vine (performance)
Some checks failed
CI Pipeline / japa-tests (push) Failing after 56s
Some checks failed
CI Pipeline / japa-tests (push) Failing after 56s
- npm updates
This commit is contained in:
parent
08c2edca3b
commit
ec17d79cf2
47
adonisrc.ts
47
adonisrc.ts
|
@ -25,15 +25,9 @@ export default defineConfig({
|
||||||
preloads: [
|
preloads: [
|
||||||
() => import('./start/routes.js'),
|
() => import('./start/routes.js'),
|
||||||
() => import('./start/kernel.js'),
|
() => import('./start/kernel.js'),
|
||||||
// {
|
() => import('#start/validator'),
|
||||||
// file: () => import('./start/inertia.js'),
|
() => import('#start/rules/unique'),
|
||||||
// environment: ["web"],
|
() => import('#start/rules/translated_language')
|
||||||
// },
|
|
||||||
// () => import('#start/events'),
|
|
||||||
// {
|
|
||||||
// file: () => import('./start/validator.js'),
|
|
||||||
// environment: ["web"],
|
|
||||||
// }
|
|
||||||
],
|
],
|
||||||
/*
|
/*
|
||||||
|--------------------------------------------------------------------------
|
|--------------------------------------------------------------------------
|
||||||
|
@ -68,8 +62,9 @@ export default defineConfig({
|
||||||
() => import('#providers/stardust_provider'),
|
() => import('#providers/stardust_provider'),
|
||||||
() => import('#providers/query_builder_provider'),
|
() => import('#providers/query_builder_provider'),
|
||||||
() => import('#providers/token_worker_provider'),
|
() => import('#providers/token_worker_provider'),
|
||||||
() => import('#providers/validator_provider'),
|
// () => import('#providers/validator_provider'),
|
||||||
() => import('#providers/drive/provider/drive_provider')
|
() => import('#providers/drive/provider/drive_provider'),
|
||||||
|
() => import('@adonisjs/core/providers/vinejs_provider')
|
||||||
],
|
],
|
||||||
metaFiles: [
|
metaFiles: [
|
||||||
{
|
{
|
||||||
|
@ -90,21 +85,21 @@ export default defineConfig({
|
||||||
| and add additional suites.
|
| and add additional suites.
|
||||||
|
|
|
|
||||||
*/
|
*/
|
||||||
tests: {
|
tests: {
|
||||||
suites: [
|
suites: [
|
||||||
{
|
{
|
||||||
files: ['tests/unit/**/*.spec(.ts|.js)'],
|
files: ['tests/unit/**/*.spec(.ts|.js)'],
|
||||||
name: 'unit',
|
name: 'unit',
|
||||||
timeout: 2000,
|
timeout: 2000,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
files: ['tests/functional/**/*.spec(.ts|.js)'],
|
files: ['tests/functional/**/*.spec(.ts|.js)'],
|
||||||
name: 'functional',
|
name: 'functional',
|
||||||
timeout: 30000,
|
timeout: 30000,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
forceExit: false,
|
forceExit: false,
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,15 +1,13 @@
|
||||||
import type { HttpContext } from '@adonisjs/core/http';
|
import type { HttpContext } from '@adonisjs/core/http';
|
||||||
import User from '#models/user';
|
import User from '#models/user';
|
||||||
import Role from '#models/role';
|
import Role from '#models/role';
|
||||||
import { ModelQueryBuilderContract } from "@adonisjs/lucid/types/model";
|
import { ModelQueryBuilderContract } from '@adonisjs/lucid/types/model';
|
||||||
import CreateUserValidator from '#validators/create_user_validator';
|
import { createUserValidator, updateUserValidator } from '#validators/user';
|
||||||
import UpdateUserValidator from '#validators/update_user_validator';
|
|
||||||
// import { schema, rules } from '@ioc:Adonis/Core/Validator';
|
// import { schema, rules } from '@ioc:Adonis/Core/Validator';
|
||||||
// import Hash from '@ioc:Adonis/Core/Hash';
|
// import Hash from '@ioc:Adonis/Core/Hash';
|
||||||
// import { schema, rules } from '@ioc:Adonis/Core/Validator';
|
// import { schema, rules } from '@ioc:Adonis/Core/Validator';
|
||||||
|
|
||||||
export default class AdminuserController {
|
export default class AdminuserController {
|
||||||
|
|
||||||
public async index({ auth, request, inertia }: HttpContext) {
|
public async index({ auth, request, inertia }: HttpContext) {
|
||||||
const page = request.input('page', 1);
|
const page = request.input('page', 1);
|
||||||
// const limit = 10
|
// const limit = 10
|
||||||
|
@ -48,7 +46,7 @@ export default class AdminuserController {
|
||||||
// .preload('focusInterests')
|
// .preload('focusInterests')
|
||||||
// .preload('role')
|
// .preload('role')
|
||||||
.paginate(page, 5);
|
.paginate(page, 5);
|
||||||
|
|
||||||
// var test = request.all();
|
// var test = request.all();
|
||||||
|
|
||||||
return inertia.render('Admin/User/Index', {
|
return inertia.render('Admin/User/Index', {
|
||||||
|
@ -79,7 +77,8 @@ export default class AdminuserController {
|
||||||
// node ace make:validator CreateUser
|
// node ace make:validator CreateUser
|
||||||
try {
|
try {
|
||||||
// Step 2 - Validate request body against the schema
|
// Step 2 - Validate request body against the schema
|
||||||
await request.validate(CreateUserValidator);
|
// await request.validate(CreateUserValidator);
|
||||||
|
await request.validateUsing(createUserValidator);
|
||||||
// console.log({ payload });
|
// console.log({ payload });
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
// Step 3 - Handle errors
|
// Step 3 - Handle errors
|
||||||
|
@ -94,7 +93,7 @@ export default class AdminuserController {
|
||||||
}
|
}
|
||||||
|
|
||||||
session.flash('message', 'User has been created successfully');
|
session.flash('message', 'User has been created successfully');
|
||||||
return response.redirect().toRoute('user.index');
|
return response.redirect().toRoute('settings.user.index');
|
||||||
}
|
}
|
||||||
|
|
||||||
public async show({ request, inertia }: HttpContext) {
|
public async show({ request, inertia }: HttpContext) {
|
||||||
|
@ -133,7 +132,11 @@ export default class AdminuserController {
|
||||||
const user = await User.query().where('id', id).firstOrFail();
|
const user = await User.query().where('id', id).firstOrFail();
|
||||||
|
|
||||||
// validate update form
|
// validate update form
|
||||||
await request.validate(UpdateUserValidator);
|
await request.validateUsing(updateUserValidator, {
|
||||||
|
meta: {
|
||||||
|
userId: user.id,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
// password is optional
|
// password is optional
|
||||||
let input;
|
let input;
|
||||||
|
@ -160,7 +163,7 @@ export default class AdminuserController {
|
||||||
await user.delete();
|
await user.delete();
|
||||||
|
|
||||||
session.flash('message', `User ${user.login} has been deleted.`);
|
session.flash('message', `User ${user.login} has been deleted.`);
|
||||||
return response.redirect().toRoute('user.index');
|
return response.redirect().toRoute('settings.user.index');
|
||||||
}
|
}
|
||||||
|
|
||||||
// private async syncRoles(userId: number, roleIds: Array<number>) {
|
// private async syncRoles(userId: number, roleIds: Array<number>) {
|
||||||
|
|
|
@ -1,9 +1,8 @@
|
||||||
import type { HttpContext } from '@adonisjs/core/http';
|
import type { HttpContext } from '@adonisjs/core/http';
|
||||||
import Role from '#models/role';
|
import Role from '#models/role';
|
||||||
import Permission from '#models/permission';
|
import Permission from '#models/permission';
|
||||||
import CreateRoleValidator from '#validators/create_role_validator';
|
import { createRoleValidator, updateRoleValidator } from '#validators/role';
|
||||||
import UpdateRoleValidator from '#validators/update_role_validator';
|
import type { ModelQueryBuilderContract } from '@adonisjs/lucid/types/model';
|
||||||
import type { ModelQueryBuilderContract } from "@adonisjs/lucid/types/model";
|
|
||||||
|
|
||||||
// import { schema, rules } from '@ioc:Adonis/Core/Validator';
|
// import { schema, rules } from '@ioc:Adonis/Core/Validator';
|
||||||
|
|
||||||
|
@ -59,7 +58,8 @@ export default class RoleController {
|
||||||
// node ace make:validator CreateUser
|
// node ace make:validator CreateUser
|
||||||
try {
|
try {
|
||||||
// Step 2 - Validate request body against the schema
|
// Step 2 - Validate request body against the schema
|
||||||
await request.validate(CreateRoleValidator);
|
// await request.validate(CreateRoleValidator);
|
||||||
|
await request.validateUsing(createRoleValidator);
|
||||||
// await request.validate({ schema: roleSchema });
|
// await request.validate({ schema: roleSchema });
|
||||||
// console.log({ payload });
|
// console.log({ payload });
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
@ -76,7 +76,7 @@ export default class RoleController {
|
||||||
}
|
}
|
||||||
|
|
||||||
session.flash('message', `Role ${role.name} has been created successfully`);
|
session.flash('message', `Role ${role.name} has been created successfully`);
|
||||||
return response.redirect().toRoute('role.index');
|
return response.redirect().toRoute('settings.role.index');
|
||||||
}
|
}
|
||||||
|
|
||||||
public async show({ request, inertia }: HttpContext) {
|
public async show({ request, inertia }: HttpContext) {
|
||||||
|
@ -115,7 +115,12 @@ export default class RoleController {
|
||||||
const role = await Role.query().where('id', id).firstOrFail();
|
const role = await Role.query().where('id', id).firstOrFail();
|
||||||
|
|
||||||
// validate update form
|
// validate update form
|
||||||
await request.validate(UpdateRoleValidator);
|
// await request.validate(UpdateRoleValidator);
|
||||||
|
await request.validateUsing(updateRoleValidator, {
|
||||||
|
meta: {
|
||||||
|
roleId: role.id,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
// password is optional
|
// password is optional
|
||||||
|
|
||||||
|
@ -138,6 +143,6 @@ export default class RoleController {
|
||||||
await role.delete();
|
await role.delete();
|
||||||
|
|
||||||
session.flash('message', `Role ${role.name} has been deleted.`);
|
session.flash('message', `Role ${role.name} has been deleted.`);
|
||||||
return response.redirect().toRoute('role.index');
|
return response.redirect().toRoute('settings.role.index');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,7 @@ import type { HttpContext } from '@adonisjs/core/http';
|
||||||
import User from '#models/user';
|
import User from '#models/user';
|
||||||
// import Hash from '@ioc:Adonis/Core/Hash';
|
// import Hash from '@ioc:Adonis/Core/Hash';
|
||||||
// import InvalidCredentialException from 'App/Exceptions/InvalidCredentialException';
|
// import InvalidCredentialException from 'App/Exceptions/InvalidCredentialException';
|
||||||
import AuthValidator from '#validators/auth_validator';
|
import { authValidator } from '#validators/auth';
|
||||||
|
|
||||||
import TwoFactorAuthProvider from '#app/services/TwoFactorAuthProvider';
|
import TwoFactorAuthProvider from '#app/services/TwoFactorAuthProvider';
|
||||||
// import { Authenticator } from '@adonisjs/auth';
|
// import { Authenticator } from '@adonisjs/auth';
|
||||||
|
@ -18,7 +18,8 @@ export default class AuthController {
|
||||||
// console.log({
|
// console.log({
|
||||||
// registerBody: request.body(),
|
// registerBody: request.body(),
|
||||||
// });
|
// });
|
||||||
await request.validate(AuthValidator);
|
// await request.validate(AuthValidator);
|
||||||
|
await request.validateUsing(authValidator);
|
||||||
|
|
||||||
// const plainPassword = await request.input('password');
|
// const plainPassword = await request.input('password');
|
||||||
// const email = await request.input('email');
|
// const email = await request.input('email');
|
||||||
|
|
|
@ -3,7 +3,8 @@ import User from '#models/user';
|
||||||
// import { RenderResponse } from '@ioc:EidelLev/Inertia';
|
// import { RenderResponse } from '@ioc:EidelLev/Inertia';
|
||||||
import TwoFactorAuthProvider from '#app/services/TwoFactorAuthProvider';
|
import TwoFactorAuthProvider from '#app/services/TwoFactorAuthProvider';
|
||||||
import hash from '@adonisjs/core/services/hash';
|
import hash from '@adonisjs/core/services/hash';
|
||||||
import { schema, rules } from '@adonisjs/validator';
|
// import { schema, rules } from '@adonisjs/validator';
|
||||||
|
import vine, { SimpleMessagesProvider } from '@vinejs/vine';
|
||||||
|
|
||||||
// Here we are generating secret and recovery codes for the user that’s enabling 2FA and storing them to our database.
|
// Here we are generating secret and recovery codes for the user that’s enabling 2FA and storing them to our database.
|
||||||
export default class UserController {
|
export default class UserController {
|
||||||
|
@ -26,13 +27,23 @@ export default class UserController {
|
||||||
}
|
}
|
||||||
|
|
||||||
public async accountInfoStore({ auth, request, response, session }: HttpContext) {
|
public async accountInfoStore({ auth, request, response, session }: HttpContext) {
|
||||||
const passwordSchema = schema.create({
|
// const passwordSchema = schema.create({
|
||||||
old_password: schema.string({ trim: true }, [rules.required()]),
|
// old_password: schema.string({ trim: true }, [rules.required()]),
|
||||||
new_password: schema.string({ trim: true }, [rules.minLength(8), rules.maxLength(255), rules.confirmed('confirm_password')]),
|
// new_password: schema.string({ trim: true }, [rules.minLength(8), rules.maxLength(255), rules.confirmed('confirm_password')]),
|
||||||
confirm_password: schema.string({ trim: true }, [rules.required()]),
|
// confirm_password: schema.string({ trim: true }, [rules.required()]),
|
||||||
|
// });
|
||||||
|
const passwordSchema = vine.object({
|
||||||
|
// first step
|
||||||
|
old_password: vine
|
||||||
|
.string()
|
||||||
|
.trim()
|
||||||
|
.regex(/^[a-zA-Z0-9]+$/),
|
||||||
|
new_password: vine.string().confirmed({ confirmationField: 'confirm_password' }).trim().minLength(8).maxLength(255),
|
||||||
});
|
});
|
||||||
try {
|
try {
|
||||||
await request.validate({ schema: passwordSchema });
|
// await request.validate({ schema: passwordSchema });
|
||||||
|
const validator = vine.compile(passwordSchema);
|
||||||
|
await request.validateUsing(validator);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
// return response.badRequest(error.messages);
|
// return response.badRequest(error.messages);
|
||||||
throw error;
|
throw error;
|
||||||
|
@ -58,7 +69,7 @@ export default class UserController {
|
||||||
|
|
||||||
// return response.status(200).send({ message: 'Password updated successfully.' });
|
// return response.status(200).send({ message: 'Password updated successfully.' });
|
||||||
session.flash({ message: 'Password updated successfully.' });
|
session.flash({ message: 'Password updated successfully.' });
|
||||||
return response.redirect().toRoute('settings.user.index');
|
return response.redirect().toRoute('settings.user');
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
// return response.status(500).send({ message: 'Internal server error.' });
|
// return response.status(500).send({ message: 'Internal server error.' });
|
||||||
return response.flash('warning', `Invalid server state. Internal server error.`).redirect().back();
|
return response.flash('warning', `Invalid server state. Internal server error.`).redirect().back();
|
||||||
|
|
|
@ -8,7 +8,6 @@ import { XMLBuilder } from 'xmlbuilder2/lib/interfaces.js';
|
||||||
import { create } from 'xmlbuilder2';
|
import { create } from 'xmlbuilder2';
|
||||||
import { readFileSync } from 'fs';
|
import { readFileSync } from 'fs';
|
||||||
import SaxonJS from 'saxon-js';
|
import SaxonJS from 'saxon-js';
|
||||||
import { schema } from '@adonisjs/validator';
|
|
||||||
import { DateTime } from 'luxon';
|
import { DateTime } from 'luxon';
|
||||||
import Index from '#app/Library/Utils/Index';
|
import Index from '#app/Library/Utils/Index';
|
||||||
import { getDomain } from '#app/utils/utility-functions';
|
import { getDomain } from '#app/utils/utility-functions';
|
||||||
|
@ -17,14 +16,14 @@ import DoiClientException from '#app/exceptions/DoiClientException';
|
||||||
import logger from '@adonisjs/core/services/logger';
|
import logger from '@adonisjs/core/services/logger';
|
||||||
import { HttpException } from 'node-exceptions';
|
import { HttpException } from 'node-exceptions';
|
||||||
import { ModelQueryBuilderContract } from "@adonisjs/lucid/types/model";
|
import { ModelQueryBuilderContract } from "@adonisjs/lucid/types/model";
|
||||||
import { CustomMessages } from "@adonisjs/validator/types";
|
import vine, { SimpleMessagesProvider } from '@vinejs/vine';
|
||||||
|
|
||||||
// Create a new instance of the client
|
// Create a new instance of the client
|
||||||
const client = new Client({ node: 'http://localhost:9200' }); // replace with your OpenSearch endpoint
|
const client = new Client({ node: 'http://localhost:9200' }); // replace with your OpenSearch endpoint
|
||||||
|
|
||||||
export default class DatasetsController {
|
export default class DatasetsController {
|
||||||
private proc;
|
private proc;
|
||||||
public messages: CustomMessages = {
|
public messages = {
|
||||||
// 'required': '{{ field }} is required',
|
// 'required': '{{ field }} is required',
|
||||||
// 'licenses.minLength': 'at least {{ options.minLength }} permission must be defined',
|
// 'licenses.minLength': 'at least {{ options.minLength }} permission must be defined',
|
||||||
'reviewer_id.required': 'reviewer_id must be defined',
|
'reviewer_id.required': 'reviewer_id must be defined',
|
||||||
|
@ -184,11 +183,13 @@ export default class DatasetsController {
|
||||||
}
|
}
|
||||||
|
|
||||||
public async approveUpdate({ request, response }: HttpContext) {
|
public async approveUpdate({ request, response }: HttpContext) {
|
||||||
const approveDatasetSchema = schema.create({
|
const approveDatasetSchema = vine.object({
|
||||||
reviewer_id: schema.number(),
|
reviewer_id: vine.number(),
|
||||||
});
|
});
|
||||||
try {
|
try {
|
||||||
await request.validate({ schema: approveDatasetSchema, messages: this.messages });
|
// await request.validate({ schema: approveDatasetSchema, messages: this.messages });
|
||||||
|
const validator = vine.compile(approveDatasetSchema);
|
||||||
|
await request.validateUsing(validator, { messagesProvider: new SimpleMessagesProvider(this.messages) });
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
// return response.badRequest(error.messages);
|
// return response.badRequest(error.messages);
|
||||||
throw error;
|
throw error;
|
||||||
|
@ -252,13 +253,14 @@ export default class DatasetsController {
|
||||||
}
|
}
|
||||||
|
|
||||||
public async publishUpdate({ request, response }: HttpContext) {
|
public async publishUpdate({ request, response }: HttpContext) {
|
||||||
const publishDatasetSchema = schema.create({
|
const publishDatasetSchema = vine.object({
|
||||||
publisher_name: schema.string({ trim: true }),
|
publisher_name: vine.string().alphaNumeric().trim(),
|
||||||
});
|
});
|
||||||
try {
|
try {
|
||||||
await request.validate({ schema: publishDatasetSchema, messages: this.messages });
|
// await request.validate({ schema: publishDatasetSchema, messages: this.messages });
|
||||||
|
const validator = vine.compile(publishDatasetSchema);
|
||||||
|
await request.validateUsing(validator, { messagesProvider: new SimpleMessagesProvider(this.messages) });
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
// return response.badRequest(error.messages);
|
|
||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
const id = request.param('id');
|
const id = request.param('id');
|
||||||
|
|
|
@ -4,8 +4,8 @@ import Dataset from '#models/dataset';
|
||||||
import Field from '#app/Library/Field';
|
import Field from '#app/Library/Field';
|
||||||
import BaseModel from '#models/base_model';
|
import BaseModel from '#models/base_model';
|
||||||
import { DateTime } from 'luxon';
|
import { DateTime } from 'luxon';
|
||||||
import { schema, rules } from '@adonisjs/validator';
|
|
||||||
import { ModelQueryBuilderContract } from "@adonisjs/lucid/types/model";
|
import { ModelQueryBuilderContract } from "@adonisjs/lucid/types/model";
|
||||||
|
import vine from '@vinejs/vine';
|
||||||
|
|
||||||
interface Dictionary {
|
interface Dictionary {
|
||||||
[index: string]: string;
|
[index: string]: string;
|
||||||
|
@ -227,13 +227,19 @@ export default class DatasetsController {
|
||||||
})
|
})
|
||||||
.firstOrFail();
|
.firstOrFail();
|
||||||
|
|
||||||
const newSchema = schema.create({
|
// const newSchema = schema.create({
|
||||||
server_state: schema.string({ trim: true }),
|
// server_state: schema.string({ trim: true }),
|
||||||
reject_reviewer_note: schema.string({ trim: true }, [rules.minLength(10), rules.maxLength(500)]),
|
// reject_reviewer_note: schema.string({ trim: true }, [rules.minLength(10), rules.maxLength(500)]),
|
||||||
|
// });
|
||||||
|
const newSchema = vine.object({
|
||||||
|
server_state: vine.string().trim(),
|
||||||
|
reject_reviewer_note: vine.string().trim().minLength(10).maxLength(500),
|
||||||
});
|
});
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await request.validate({ schema: newSchema });
|
// await request.validate({ schema: newSchema });
|
||||||
|
const validator = vine.compile(newSchema);
|
||||||
|
await request.validateUsing(validator);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
// return response.badRequest(error.messages);
|
// return response.badRequest(error.messages);
|
||||||
throw error;
|
throw error;
|
||||||
|
|
|
@ -8,15 +8,14 @@ import Description from '#models/description';
|
||||||
import Language from '#models/language';
|
import Language from '#models/language';
|
||||||
import Coverage from '#models/coverage';
|
import Coverage from '#models/coverage';
|
||||||
import Collection from '#models/collection';
|
import Collection from '#models/collection';
|
||||||
import { schema, rules } from '@adonisjs/validator';
|
|
||||||
import { CustomMessages } from '@adonisjs/validator/types';
|
|
||||||
import dayjs from 'dayjs';
|
import dayjs from 'dayjs';
|
||||||
import Person from '#models/person';
|
import Person from '#models/person';
|
||||||
import db from '@adonisjs/lucid/services/db';
|
import db from '@adonisjs/lucid/services/db';
|
||||||
import { TransactionClientContract } from '@adonisjs/lucid/types/database';
|
import { TransactionClientContract } from '@adonisjs/lucid/types/database';
|
||||||
import Subject from '#models/subject';
|
import Subject from '#models/subject';
|
||||||
import CreateDatasetValidator from '#validators/create_dataset_validator';
|
// import CreateDatasetValidator from '#validators/create_dataset_validator';
|
||||||
import UpdateDatasetValidator from '#validators/update_dataset_validator';
|
import { createDatasetValidator, updateDatasetValidator } from '#validators/dataset';
|
||||||
|
// import UpdateDatasetValidator from '#validators/update_dataset_validator';
|
||||||
import {
|
import {
|
||||||
TitleTypes,
|
TitleTypes,
|
||||||
DescriptionTypes,
|
DescriptionTypes,
|
||||||
|
@ -32,7 +31,7 @@ import DatasetReference from '#models/dataset_reference';
|
||||||
import { cuid } from '@adonisjs/core/helpers';
|
import { cuid } from '@adonisjs/core/helpers';
|
||||||
import File from '#models/file';
|
import File from '#models/file';
|
||||||
import ClamScan from 'clamscan';
|
import ClamScan from 'clamscan';
|
||||||
import { ValidationException } from '@adonisjs/validator';
|
// import { ValidationException } from '@adonisjs/validator';
|
||||||
// import Drive from '@ioc:Adonis/Core/Drive';
|
// import Drive from '@ioc:Adonis/Core/Drive';
|
||||||
import drive from '#services/drive';
|
import drive from '#services/drive';
|
||||||
import { Exception } from '@adonisjs/core/exceptions';
|
import { Exception } from '@adonisjs/core/exceptions';
|
||||||
|
@ -41,6 +40,7 @@ import * as crypto from 'crypto';
|
||||||
interface Dictionary {
|
interface Dictionary {
|
||||||
[index: string]: string;
|
[index: string]: string;
|
||||||
}
|
}
|
||||||
|
import vine, { SimpleMessagesProvider, errors } from '@vinejs/vine';
|
||||||
|
|
||||||
export default class DatasetController {
|
export default class DatasetController {
|
||||||
public async index({ auth, request, inertia }: HttpContext) {
|
public async index({ auth, request, inertia }: HttpContext) {
|
||||||
|
@ -125,8 +125,6 @@ export default class DatasetController {
|
||||||
// mixedtype: 'Mixed Type',
|
// mixedtype: 'Mixed Type',
|
||||||
// vocabulary: 'Vocabulary',
|
// vocabulary: 'Vocabulary',
|
||||||
// };
|
// };
|
||||||
|
|
||||||
// const languages = await Database.from('languages').select('*').where('active', true);
|
|
||||||
return inertia.render('Submitter/Dataset/Create', {
|
return inertia.render('Submitter/Dataset/Create', {
|
||||||
licenses: licenses,
|
licenses: licenses,
|
||||||
doctypes: DatasetTypes,
|
doctypes: DatasetTypes,
|
||||||
|
@ -146,75 +144,98 @@ export default class DatasetController {
|
||||||
}
|
}
|
||||||
|
|
||||||
public async firstStep({ request, response }: HttpContext) {
|
public async firstStep({ request, response }: HttpContext) {
|
||||||
const newDatasetSchema = schema.create({
|
// const newDatasetSchema = schema.create({
|
||||||
language: schema.string({ trim: true }, [
|
// language: schema.string({ trim: true }, [
|
||||||
rules.regex(/^[a-zA-Z0-9-_]+$/), //Must be alphanumeric with hyphens or underscores
|
// rules.regex(/^[a-zA-Z0-9-_]+$/), //Must be alphanumeric with hyphens or underscores
|
||||||
]),
|
// ]),
|
||||||
licenses: schema.array([rules.minLength(1)]).members(schema.number()), // define at least one license for the new dataset
|
// licenses: schema.array([rules.minLength(1)]).members(schema.number()), // define at least one license for the new dataset
|
||||||
rights: schema.string([rules.equalTo('true')]),
|
// rights: schema.string([rules.equalTo('true')]),
|
||||||
|
// });
|
||||||
|
const newDatasetSchema = vine.object({
|
||||||
|
// first step
|
||||||
|
language: vine
|
||||||
|
.string()
|
||||||
|
.trim()
|
||||||
|
.regex(/^[a-zA-Z0-9]+$/),
|
||||||
|
licenses: vine.array(vine.number()).minLength(1), // define at least one license for the new dataset
|
||||||
|
rights: vine.string().in(['true']),
|
||||||
});
|
});
|
||||||
|
|
||||||
// await request.validate({ schema: newDatasetSchema, messages: this.messages });
|
// await request.validate({ schema: newDatasetSchema, messages: this.messages });
|
||||||
try {
|
try {
|
||||||
// Step 2 - Validate request body against the schema
|
// Step 2 - Validate request body against the schema
|
||||||
|
// await request.validate({ schema: newDatasetSchema, messages: this.messages });
|
||||||
await request.validate({ schema: newDatasetSchema, messages: this.messages });
|
const validator = vine.compile(newDatasetSchema);
|
||||||
// console.log({ payload });
|
await request.validateUsing(validator, { messagesProvider: new SimpleMessagesProvider(this.messages) });
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
// Step 3 - Handle errors
|
// Step 3 - Handle errors
|
||||||
// return response.badRequest(error.messages);
|
|
||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
return response.redirect().back();
|
return response.redirect().back();
|
||||||
}
|
}
|
||||||
|
|
||||||
public async secondStep({ request, response }: HttpContext) {
|
public async secondStep({ request, response }: HttpContext) {
|
||||||
const newDatasetSchema = schema.create({
|
const newDatasetSchema = vine.object({
|
||||||
// first step
|
// first step
|
||||||
language: schema.string({ trim: true }, [
|
language: vine
|
||||||
rules.regex(/^[a-zA-Z0-9-_]+$/), //Must be alphanumeric with hyphens or underscores
|
.string()
|
||||||
]),
|
.trim()
|
||||||
licenses: schema.array([rules.minLength(1)]).members(schema.number()), // define at least one license for the new dataset
|
.regex(/^[a-zA-Z0-9]+$/),
|
||||||
rights: schema.string([rules.equalTo('true')]),
|
licenses: vine.array(vine.number()).minLength(1), // define at least one license for the new dataset
|
||||||
|
rights: vine.string().in(['true']),
|
||||||
// second step
|
// second step
|
||||||
type: schema.string({ trim: true }, [rules.minLength(3), rules.maxLength(255)]),
|
type: vine.string().trim().minLength(3).maxLength(255),
|
||||||
creating_corporation: schema.string({ trim: true }, [rules.minLength(3), rules.maxLength(255)]),
|
creating_corporation: vine.string().trim().minLength(3).maxLength(255),
|
||||||
titles: schema.array([rules.minLength(1)]).members(
|
titles: vine
|
||||||
schema.object().members({
|
.array(
|
||||||
value: schema.string({ trim: true }, [rules.minLength(3), rules.maxLength(255)]),
|
vine.object({
|
||||||
type: schema.enum(Object.values(TitleTypes)),
|
value: vine.string().trim().minLength(3).maxLength(255),
|
||||||
language: schema.string({ trim: true }, [
|
type: vine.enum(Object.values(TitleTypes)),
|
||||||
rules.minLength(2),
|
language: vine
|
||||||
rules.maxLength(255),
|
.string()
|
||||||
rules.translatedLanguage('/language', 'type'),
|
.trim()
|
||||||
]),
|
.minLength(2)
|
||||||
}),
|
.maxLength(255)
|
||||||
),
|
.translatedLanguage({ mainLanguageField: 'language', typeField: 'type' }),
|
||||||
descriptions: schema.array([rules.minLength(1)]).members(
|
}),
|
||||||
schema.object().members({
|
)
|
||||||
value: schema.string({ trim: true }, [rules.minLength(3), rules.maxLength(255)]),
|
.minLength(1),
|
||||||
type: schema.enum(Object.values(DescriptionTypes)),
|
descriptions: vine
|
||||||
language: schema.string({ trim: true }, [
|
.array(
|
||||||
rules.minLength(2),
|
vine.object({
|
||||||
rules.maxLength(255),
|
value: vine.string().trim().minLength(3).maxLength(255),
|
||||||
rules.translatedLanguage('/language', 'type'),
|
type: vine.enum(Object.values(DescriptionTypes)),
|
||||||
]),
|
language: vine
|
||||||
}),
|
.string()
|
||||||
),
|
.trim()
|
||||||
authors: schema.array([rules.minLength(1)]).members(schema.object().members({ email: schema.string({ trim: true }) })),
|
.minLength(2)
|
||||||
contributors: schema.array.optional().members(
|
.maxLength(255)
|
||||||
schema.object().members({
|
.translatedLanguage({ mainLanguageField: 'language', typeField: 'type' }),
|
||||||
email: schema.string({ trim: true }),
|
}),
|
||||||
pivot_contributor_type: schema.enum(Object.keys(ContributorTypes)),
|
)
|
||||||
}),
|
.minLength(1),
|
||||||
),
|
authors: vine
|
||||||
// project_id: schema.number(),
|
.array(
|
||||||
|
vine.object({
|
||||||
|
email: vine.string().trim().maxLength(255).email().normalizeEmail(),
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
.minLength(1),
|
||||||
|
contributors: vine
|
||||||
|
.array(
|
||||||
|
vine.object({
|
||||||
|
email: vine.string().trim().maxLength(255).email().normalizeEmail(),
|
||||||
|
pivot_contributor_type: vine.enum(Object.keys(ContributorTypes)),
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
.optional(),
|
||||||
|
project_id: vine.number().optional(),
|
||||||
});
|
});
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Step 2 - Validate request body against the schema
|
// Step 2 - Validate request body against the schema
|
||||||
await request.validate({ schema: newDatasetSchema, messages: this.messages });
|
// await request.validate({ schema: newDatasetSchema, messages: this.messages });
|
||||||
// console.log({ payload });
|
const validator = vine.compile(newDatasetSchema);
|
||||||
|
await request.validateUsing(validator, { messagesProvider: new SimpleMessagesProvider(this.messages) });
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
// Step 3 - Handle errors
|
// Step 3 - Handle errors
|
||||||
// return response.badRequest(error.messages);
|
// return response.badRequest(error.messages);
|
||||||
|
@ -224,84 +245,112 @@ export default class DatasetController {
|
||||||
}
|
}
|
||||||
|
|
||||||
public async thirdStep({ request, response }: HttpContext) {
|
public async thirdStep({ request, response }: HttpContext) {
|
||||||
const newDatasetSchema = schema.create({
|
const newDatasetSchema = vine.object({
|
||||||
// first step
|
// first step
|
||||||
language: schema.string({ trim: true }, [
|
language: vine
|
||||||
rules.regex(/^[a-zA-Z0-9-_]+$/), //Must be alphanumeric with hyphens or underscores
|
.string()
|
||||||
]),
|
.trim()
|
||||||
licenses: schema.array([rules.minLength(1)]).members(schema.number()), // define at least one license for the new dataset
|
.regex(/^[a-zA-Z0-9]+$/),
|
||||||
rights: schema.string([rules.equalTo('true')]),
|
licenses: vine.array(vine.number()).minLength(1), // define at least one license for the new dataset
|
||||||
|
rights: vine.string().in(['true']),
|
||||||
// second step
|
// second step
|
||||||
type: schema.string({ trim: true }, [rules.minLength(3), rules.maxLength(255)]),
|
type: vine.string().trim().minLength(3).maxLength(255),
|
||||||
creating_corporation: schema.string({ trim: true }, [rules.minLength(3), rules.maxLength(255)]),
|
creating_corporation: vine.string().trim().minLength(3).maxLength(255),
|
||||||
titles: schema.array([rules.minLength(1)]).members(
|
titles: vine
|
||||||
schema.object().members({
|
.array(
|
||||||
value: schema.string({ trim: true }, [rules.minLength(3), rules.maxLength(255)]),
|
vine.object({
|
||||||
type: schema.enum(Object.values(TitleTypes)),
|
value: vine.string().trim().minLength(3).maxLength(255),
|
||||||
language: schema.string({ trim: true }, [
|
type: vine.enum(Object.values(TitleTypes)),
|
||||||
rules.minLength(2),
|
language: vine
|
||||||
rules.maxLength(255),
|
.string()
|
||||||
rules.translatedLanguage('/language', 'type'),
|
.trim()
|
||||||
]),
|
.minLength(2)
|
||||||
}),
|
.maxLength(255)
|
||||||
),
|
.translatedLanguage({ mainLanguageField: 'language', typeField: 'type' }),
|
||||||
descriptions: schema.array([rules.minLength(1)]).members(
|
}),
|
||||||
schema.object().members({
|
)
|
||||||
value: schema.string({ trim: true }, [rules.minLength(3), rules.maxLength(255)]),
|
.minLength(1),
|
||||||
type: schema.enum(Object.values(DescriptionTypes)),
|
descriptions: vine
|
||||||
language: schema.string({ trim: true }, [
|
.array(
|
||||||
rules.minLength(2),
|
vine.object({
|
||||||
rules.maxLength(255),
|
value: vine.string().trim().minLength(3).maxLength(255),
|
||||||
rules.translatedLanguage('/language', 'type'),
|
type: vine.enum(Object.values(DescriptionTypes)),
|
||||||
]),
|
language: vine
|
||||||
}),
|
.string()
|
||||||
),
|
.trim()
|
||||||
authors: schema.array([rules.minLength(1)]).members(schema.object().members({ email: schema.string({ trim: true }) })),
|
.minLength(2)
|
||||||
contributors: schema.array.optional().members(
|
.maxLength(255)
|
||||||
schema.object().members({
|
.translatedLanguage({ mainLanguageField: 'language', typeField: 'type' }),
|
||||||
email: schema.string({ trim: true }),
|
}),
|
||||||
pivot_contributor_type: schema.enum(Object.keys(ContributorTypes)),
|
)
|
||||||
}),
|
.minLength(1),
|
||||||
),
|
authors: vine
|
||||||
|
.array(
|
||||||
|
vine.object({
|
||||||
|
email: vine.string().trim().maxLength(255).email().normalizeEmail(),
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
.minLength(1),
|
||||||
|
contributors: vine
|
||||||
|
.array(
|
||||||
|
vine.object({
|
||||||
|
email: vine.string().trim().maxLength(255).email().normalizeEmail(),
|
||||||
|
pivot_contributor_type: vine.enum(Object.keys(ContributorTypes)),
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
.optional(),
|
||||||
// third step
|
// third step
|
||||||
project_id: schema.number.optional(),
|
project_id: vine.number().optional(),
|
||||||
embargo_date: schema.date.optional({ format: 'yyyy-MM-dd' }, [rules.after(10, 'days')]),
|
// embargo_date: schema.date.optional({ format: 'yyyy-MM-dd' }, [rules.after(10, 'days')]),
|
||||||
coverage: schema.object().members({
|
embargo_date: vine
|
||||||
x_min: schema.number(),
|
.date({
|
||||||
x_max: schema.number(),
|
formats: ['YYYY-MM-DD'],
|
||||||
y_min: schema.number(),
|
})
|
||||||
y_max: schema.number(),
|
.afterOrEqual((_field) => {
|
||||||
elevation_absolut: schema.number.optional(),
|
return dayjs().add(10, 'day').format('YYYY-MM-DD');
|
||||||
elevation_min: schema.number.optional([rules.requiredIfExists('elevation_max')]),
|
})
|
||||||
elevation_max: schema.number.optional([rules.requiredIfExists('elevation_min')]),
|
.optional(),
|
||||||
depth_absolut: schema.number.optional(),
|
coverage: vine.object({
|
||||||
depth_min: schema.number.optional([rules.requiredIfExists('depth_max')]),
|
x_min: vine.number(),
|
||||||
depth_max: schema.number.optional([rules.requiredIfExists('depth_min')]),
|
x_max: vine.number(),
|
||||||
|
y_min: vine.number(),
|
||||||
|
y_max: vine.number(),
|
||||||
|
elevation_absolut: vine.number().optional(),
|
||||||
|
elevation_min: vine.number().optional().requiredIfExists('elevation_max'),
|
||||||
|
elevation_max: vine.number().optional().requiredIfExists('elevation_min'),
|
||||||
|
// type: vine.enum(Object.values(DescriptionTypes)),
|
||||||
|
depth_absolut: vine.number().optional(),
|
||||||
|
depth_min: vine.number().optional().requiredIfExists('depth_max'),
|
||||||
|
depth_max: vine.number().optional().requiredIfExists('depth_min'),
|
||||||
}),
|
}),
|
||||||
references: schema.array.optional([rules.uniqueArray('value')]).members(
|
references: vine
|
||||||
schema.object().members({
|
.array(
|
||||||
value: schema.string({ trim: true }, [rules.minLength(3), rules.maxLength(255)]),
|
vine.object({
|
||||||
type: schema.enum(Object.values(ReferenceIdentifierTypes)),
|
value: vine.string().trim().minLength(3).maxLength(255),
|
||||||
relation: schema.enum(Object.values(RelationTypes)),
|
type: vine.enum(Object.values(ReferenceIdentifierTypes)),
|
||||||
label: schema.string({ trim: true }, [rules.minLength(2), rules.maxLength(255)]),
|
relation: vine.enum(Object.values(RelationTypes)),
|
||||||
}),
|
label: vine.string().trim().minLength(2).maxLength(255),
|
||||||
),
|
}),
|
||||||
subjects: schema.array([rules.minLength(3), rules.uniqueArray('value')]).members(
|
)
|
||||||
schema.object().members({
|
.optional(),
|
||||||
value: schema.string({ trim: true }, [
|
subjects: vine
|
||||||
rules.minLength(3),
|
.array(
|
||||||
rules.maxLength(255),
|
vine.object({
|
||||||
// rules.unique({ table: 'dataset_subjects', column: 'value' }),
|
value: vine.string().trim().minLength(3).maxLength(255),
|
||||||
]),
|
// pivot_contributor_type: vine.enum(Object.keys(ContributorTypes)),
|
||||||
// type: schema.enum(Object.values(TitleTypes)),
|
language: vine.string().trim().minLength(2).maxLength(255),
|
||||||
language: schema.string({ trim: true }, [rules.minLength(2), rules.maxLength(255)]),
|
}),
|
||||||
}),
|
)
|
||||||
),
|
.minLength(3)
|
||||||
|
.distinct('value')
|
||||||
|
.optional(),
|
||||||
});
|
});
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Step 2 - Validate request body against the schema
|
// Step 3 - Validate request body against the schema
|
||||||
await request.validate({ schema: newDatasetSchema, messages: this.messages });
|
// await request.validate({ schema: newDatasetSchema, messages: this.messages });
|
||||||
|
const validator = vine.compile(newDatasetSchema);
|
||||||
|
await request.validateUsing(validator, { messagesProvider: new SimpleMessagesProvider(this.messages) });
|
||||||
// console.log({ payload });
|
// console.log({ payload });
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
// Step 3 - Handle errors
|
// Step 3 - Handle errors
|
||||||
|
@ -316,7 +365,8 @@ export default class DatasetController {
|
||||||
try {
|
try {
|
||||||
// Step 2 - Validate request body against the schema
|
// Step 2 - Validate request body against the schema
|
||||||
// await request.validate({ schema: newDatasetSchema, messages: this.messages });
|
// await request.validate({ schema: newDatasetSchema, messages: this.messages });
|
||||||
await request.validate(CreateDatasetValidator);
|
// await request.validate(CreateDatasetValidator);
|
||||||
|
await request.validateUsing(createDatasetValidator);
|
||||||
// console.log({ payload });
|
// console.log({ payload });
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
// Step 3 - Handle errors
|
// Step 3 - Handle errors
|
||||||
|
@ -505,13 +555,15 @@ export default class DatasetController {
|
||||||
const { file, isInfected, viruses } = await clamscan.isInfected(filePath);
|
const { file, isInfected, viruses } = await clamscan.isInfected(filePath);
|
||||||
if (isInfected) {
|
if (isInfected) {
|
||||||
console.log(`${file} is infected with ${viruses}!`);
|
console.log(`${file} is infected with ${viruses}!`);
|
||||||
reject(new ValidationException(true, { 'upload error': `File ${file} is infected!` }));
|
// reject(new ValidationException(true, { 'upload error': `File ${file} is infected!` }));
|
||||||
|
reject(new errors.E_VALIDATION_ERROR({ 'upload error': `File ${file} is infected!` }));
|
||||||
} else {
|
} else {
|
||||||
resolve();
|
resolve();
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
// If there's an error scanning the file, throw a validation exception
|
// If there's an error scanning the file, throw a validation exception
|
||||||
reject(new ValidationException(true, { 'upload error': `${error.message}` }));
|
// reject(new ValidationException(true, { 'upload error': `${error.message}` }));
|
||||||
|
reject(new errors.E_VALIDATION_ERROR({ 'upload error': `${error.message}!` }));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -553,24 +605,24 @@ export default class DatasetController {
|
||||||
return pivotAttributes;
|
return pivotAttributes;
|
||||||
}
|
}
|
||||||
|
|
||||||
public messages: CustomMessages = {
|
public messages = {
|
||||||
'minLength': '{{ field }} must be at least {{ options.minLength }} characters long',
|
'minLength': '{{ field }} must be at least {{ min }} characters long',
|
||||||
'maxLength': '{{ field }} must be less then {{ options.maxLength }} characters long',
|
'maxLength': '{{ field }} must be less then {{ max }} characters long',
|
||||||
'required': '{{ field }} is required',
|
'required': '{{ field }} is required',
|
||||||
'unique': '{{ field }} must be unique, and this value is already taken',
|
'unique': '{{ field }} must be unique, and this value is already taken',
|
||||||
// 'confirmed': '{{ field }} is not correct',
|
// 'confirmed': '{{ field }} is not correct',
|
||||||
'licenses.minLength': 'at least {{ options.minLength }} permission must be defined',
|
'licenses.minLength': 'at least {{ min }} permission must be defined',
|
||||||
'licenses.*.number': 'Define roles as valid numbers',
|
'licenses.*.number': 'Define roles as valid numbers',
|
||||||
'rights.equalTo': 'you must agree to continue',
|
'rights.in': 'you must agree to continue',
|
||||||
|
|
||||||
'titles.0.value.minLength': 'Main Title must be at least {{ options.minLength }} characters long',
|
'titles.0.value.minLength': 'Main Title must be at least {{ min }} characters long',
|
||||||
'titles.0.value.required': 'Main Title is required',
|
'titles.0.value.required': 'Main Title is required',
|
||||||
'titles.*.value.required': 'Additional title is required, if defined',
|
'titles.*.value.required': 'Additional title is required, if defined',
|
||||||
'titles.*.type.required': 'Additional title type is required',
|
'titles.*.type.required': 'Additional title type is required',
|
||||||
'titles.*.language.required': 'Additional title language is required',
|
'titles.*.language.required': 'Additional title language is required',
|
||||||
'titles.*.language.translatedLanguage': 'The language of the translated title must be different from the language of the dataset',
|
'titles.*.language.translatedLanguage': 'The language of the translated title must be different from the language of the dataset',
|
||||||
|
|
||||||
'descriptions.0.value.minLength': 'Main Abstract must be at least {{ options.minLength }} characters long',
|
'descriptions.0.value.minLength': 'Main Abstract must be at least {{ min }} characters long',
|
||||||
'descriptions.0.value.required': 'Main Abstract is required',
|
'descriptions.0.value.required': 'Main Abstract is required',
|
||||||
'descriptions.*.value.required': 'Additional description is required, if defined',
|
'descriptions.*.value.required': 'Additional description is required, if defined',
|
||||||
'descriptions.*.type.required': 'Additional description type is required',
|
'descriptions.*.type.required': 'Additional description type is required',
|
||||||
|
@ -578,26 +630,26 @@ export default class DatasetController {
|
||||||
'descriptions.*.language.translatedLanguage':
|
'descriptions.*.language.translatedLanguage':
|
||||||
'The language of the translated description must be different from the language of the dataset',
|
'The language of the translated description must be different from the language of the dataset',
|
||||||
|
|
||||||
'authors.minLength': 'at least {{ options.minLength }} author must be defined',
|
'authors.array.minLength': 'at least {{ min }} author must be defined',
|
||||||
'contributors.*.pivot_contributor_type.required': 'contributor type is required, if defined',
|
'contributors.*.pivot_contributor_type.required': 'contributor type is required, if defined',
|
||||||
|
|
||||||
'after': `{{ field }} must be older than ${dayjs().add(10, 'day')}`,
|
'after': `{{ field }} must be older than ${dayjs().add(10, 'day')}`,
|
||||||
|
|
||||||
'subjects.minLength': 'at least {{ options.minLength }} keywords must be defined',
|
'subjects.array.minLength': 'at least {{ min }} keywords must be defined',
|
||||||
'subjects.uniqueArray': 'The {{ options.array }} array must have unique values based on the {{ options.field }} attribute.',
|
|
||||||
'subjects.*.value.required': 'keyword value is required',
|
'subjects.*.value.required': 'keyword value is required',
|
||||||
'subjects.*.value.minLength': 'keyword value must be at least {{ options.minLength }} characters long',
|
'subjects.*.value.minLength': 'keyword value must be at least {{ min }} characters long',
|
||||||
'subjects.*.type.required': 'keyword type is required',
|
'subjects.*.type.required': 'keyword type is required',
|
||||||
'subjects.*.language.required': 'language of keyword is required',
|
'subjects.*.language.required': 'language of keyword is required',
|
||||||
|
'subjects.distinct': 'The {{ field }} array must have unique values based on the {{ fields }} attribute.',
|
||||||
|
|
||||||
'references.*.value.required': 'Additional reference value is required, if defined',
|
'references.*.value.required': 'Additional reference value is required, if defined',
|
||||||
'references.*.type.required': 'Additional reference identifier type is required',
|
'references.*.type.required': 'Additional reference identifier type is required',
|
||||||
'references.*.relation.required': 'Additional reference relation type is required',
|
'references.*.relation.required': 'Additional reference relation type is required',
|
||||||
'references.*.label.required': 'Additional reference label is required',
|
'references.*.label.required': 'Additional reference label is required',
|
||||||
|
|
||||||
'files.minLength': 'At least {{ options.minLength }} file upload is required.',
|
'files.array.minLength': 'At least {{ min }} file upload is required.',
|
||||||
'files.*.size': 'file size is to big',
|
'files.*.size': 'file size is to big',
|
||||||
'files.extnames': 'file extension is not supported',
|
'files.*.extnames': 'file extension is not supported',
|
||||||
};
|
};
|
||||||
|
|
||||||
// public async release({ params, view }) {
|
// public async release({ params, view }) {
|
||||||
|
@ -654,16 +706,18 @@ export default class DatasetController {
|
||||||
const preferredReviewerEmail = request.input('preferred_reviewer_email');
|
const preferredReviewerEmail = request.input('preferred_reviewer_email');
|
||||||
|
|
||||||
if (preferation === 'yes_preferation') {
|
if (preferation === 'yes_preferation') {
|
||||||
const newSchema = schema.create({
|
const newSchema = vine.object({
|
||||||
preferred_reviewer: schema.string({ trim: true }, [rules.minLength(3), rules.maxLength(255)]),
|
preferred_reviewer: vine.string().alphaNumeric().trim().minLength(3).maxLength(255),
|
||||||
preferred_reviewer_email: schema.string([rules.email()]),
|
preferred_reviewer_email: vine.string().maxLength(255).email().normalizeEmail(),
|
||||||
});
|
});
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await request.validate({
|
// await request.validate({
|
||||||
schema: newSchema,
|
// schema: newSchema,
|
||||||
// reporter: validator.reporters.vanilla,
|
// // reporter: validator.reporters.vanilla,
|
||||||
});
|
// });
|
||||||
|
const validator = vine.compile(newSchema);
|
||||||
|
await request.validateUsing(validator);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
// return response.badRequest(error.messages);
|
// return response.badRequest(error.messages);
|
||||||
throw error;
|
throw error;
|
||||||
|
@ -799,8 +853,8 @@ export default class DatasetController {
|
||||||
|
|
||||||
public async update({ request, response, session }: HttpContext) {
|
public async update({ request, response, session }: HttpContext) {
|
||||||
try {
|
try {
|
||||||
// await request.validate({ schema: newDatasetSchema, messages: this.messages });
|
// await request.validate(UpdateDatasetValidator);
|
||||||
await request.validate(UpdateDatasetValidator);
|
await request.validateUsing(updateDatasetValidator);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
// - Handle errors
|
// - Handle errors
|
||||||
// return response.badRequest(error.messages);
|
// return response.badRequest(error.messages);
|
||||||
|
@ -1068,7 +1122,7 @@ export default class DatasetController {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
if (error instanceof ValidationException) {
|
if (error instanceof errors.E_VALIDATION_ERROR) {
|
||||||
// Validation exception handling
|
// Validation exception handling
|
||||||
throw error;
|
throw error;
|
||||||
} else if (error instanceof Exception) {
|
} else if (error instanceof Exception) {
|
||||||
|
|
34
app/models/mime_type.ts
Normal file
34
app/models/mime_type.ts
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
import { column, SnakeCaseNamingStrategy } from '@adonisjs/lucid/orm';
|
||||||
|
import BaseModel from './base_model.js';
|
||||||
|
|
||||||
|
export default class MimeType extends BaseModel {
|
||||||
|
public static namingStrategy = new SnakeCaseNamingStrategy();
|
||||||
|
public static primaryKey = 'id';
|
||||||
|
public static table = 'mime_types';
|
||||||
|
public static fillable: string[] = ['name', 'file_extension', 'enabled'];
|
||||||
|
|
||||||
|
@column({
|
||||||
|
isPrimary: true,
|
||||||
|
})
|
||||||
|
public id: number;
|
||||||
|
|
||||||
|
@column({})
|
||||||
|
public name: string;
|
||||||
|
|
||||||
|
@column({})
|
||||||
|
public file_extension: string;
|
||||||
|
|
||||||
|
@column({})
|
||||||
|
public enabled: boolean;
|
||||||
|
|
||||||
|
@column({})
|
||||||
|
public visible_frontdoor: boolean;
|
||||||
|
|
||||||
|
|
||||||
|
public visible_oai: boolean;
|
||||||
|
|
||||||
|
// @hasMany(() => Collection, {
|
||||||
|
// foreignKey: 'role_id',
|
||||||
|
// })
|
||||||
|
// public collections: HasMany<typeof Collection>;
|
||||||
|
}
|
20
app/validators/auth.ts
Normal file
20
app/validators/auth.ts
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
import vine from '@vinejs/vine';
|
||||||
|
|
||||||
|
// public schema = schema.create({
|
||||||
|
// email: schema.string({ trim: true }, [
|
||||||
|
// rules.email(),
|
||||||
|
// // rules.unique({ table: 'accounts', column: 'email' })
|
||||||
|
// ]),
|
||||||
|
// password: schema.string({}, [rules.minLength(6)]),
|
||||||
|
// });
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Validates the role's creation action
|
||||||
|
* node ace make:validator role
|
||||||
|
*/
|
||||||
|
export const authValidator = vine.compile(
|
||||||
|
vine.object({
|
||||||
|
email: vine.string().maxLength(255).email().normalizeEmail(),
|
||||||
|
password: vine.string().trim().minLength(6),
|
||||||
|
}),
|
||||||
|
);
|
|
@ -1,47 +0,0 @@
|
||||||
import { schema, rules } from '@adonisjs/validator';
|
|
||||||
import type { HttpContext } from '@adonisjs/core/http';
|
|
||||||
import { CustomMessages } from "@adonisjs/validator/types";
|
|
||||||
|
|
||||||
export default class AuthValidator {
|
|
||||||
constructor(protected ctx: HttpContext) {}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Define schema to validate the "shape", "type", "formatting" and "integrity" of data.
|
|
||||||
*
|
|
||||||
* For example:
|
|
||||||
* 1. The username must be of data type string. But then also, it should
|
|
||||||
* not contain special characters or numbers.
|
|
||||||
* ```
|
|
||||||
* schema.string({}, [ rules.alpha() ])
|
|
||||||
* ```
|
|
||||||
*
|
|
||||||
* 2. The email must be of data type string, formatted as a valid
|
|
||||||
* email. But also, not used by any other user.
|
|
||||||
* ```
|
|
||||||
* schema.string({}, [
|
|
||||||
* rules.email(),
|
|
||||||
* rules.unique({ table: 'users', column: 'email' }),
|
|
||||||
* ])
|
|
||||||
* ```
|
|
||||||
*/
|
|
||||||
public schema = schema.create({
|
|
||||||
email: schema.string({ trim: true }, [
|
|
||||||
rules.email(),
|
|
||||||
// rules.unique({ table: 'accounts', column: 'email' })
|
|
||||||
]),
|
|
||||||
password: schema.string({}, [rules.minLength(6)]),
|
|
||||||
});
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Custom messages for validation failures. You can make use of dot notation `(.)`
|
|
||||||
* for targeting nested fields and array expressions `(*)` for targeting all
|
|
||||||
* children of an array. For example:
|
|
||||||
*
|
|
||||||
* {
|
|
||||||
* 'profile.username.required': 'Username is required',
|
|
||||||
* 'scores.*.number': 'Define scores as valid numbers'
|
|
||||||
* }
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
public messages: CustomMessages = {};
|
|
||||||
}
|
|
|
@ -1,179 +0,0 @@
|
||||||
import { schema, rules } from '@adonisjs/validator';
|
|
||||||
import type { HttpContext } from '@adonisjs/core/http';
|
|
||||||
import dayjs from 'dayjs';
|
|
||||||
import { TitleTypes, DescriptionTypes, RelationTypes, ReferenceIdentifierTypes, ContributorTypes } from '#contracts/enums';
|
|
||||||
import { CustomMessages } from "@adonisjs/validator/types";
|
|
||||||
|
|
||||||
export default class CreateDatasetValidator {
|
|
||||||
constructor(protected ctx: HttpContext) {}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Define schema to validate the "shape", "type", "formatting" and "integrity" of data.
|
|
||||||
*
|
|
||||||
* For example:
|
|
||||||
* 1. The username must be of data type string. But then also, it should
|
|
||||||
* not contain special characters or numbers.
|
|
||||||
* ```
|
|
||||||
* schema.string({}, [ rules.alpha() ])
|
|
||||||
* ```
|
|
||||||
*
|
|
||||||
* 2. The email must be of data type string, formatted as a valid
|
|
||||||
* email. But also, not used by any other user.
|
|
||||||
* ```
|
|
||||||
* schema.string({}, [
|
|
||||||
* rules.email(),
|
|
||||||
* rules.unique({ table: 'users', column: 'email' }),
|
|
||||||
* ])
|
|
||||||
* ```
|
|
||||||
*/
|
|
||||||
public schema = schema.create({
|
|
||||||
// first step
|
|
||||||
language: schema.string({ trim: true }, [
|
|
||||||
rules.regex(/^[a-zA-Z0-9-_]+$/), //Must be alphanumeric with hyphens or underscores
|
|
||||||
]),
|
|
||||||
licenses: schema.array([rules.minLength(1)]).members(schema.number()), // define at least one license for the new dataset
|
|
||||||
rights: schema.string([rules.equalTo('true')]),
|
|
||||||
// second step
|
|
||||||
type: schema.string({ trim: true }, [rules.minLength(3), rules.maxLength(255)]),
|
|
||||||
creating_corporation: schema.string({ trim: true }, [rules.minLength(3), rules.maxLength(255)]),
|
|
||||||
titles: schema.array([rules.minLength(1)]).members(
|
|
||||||
schema.object().members({
|
|
||||||
value: schema.string({ trim: true }, [rules.minLength(3), rules.maxLength(255)]),
|
|
||||||
type: schema.enum(Object.values(TitleTypes)),
|
|
||||||
language: schema.string({ trim: true }, [
|
|
||||||
rules.minLength(2),
|
|
||||||
rules.maxLength(255),
|
|
||||||
rules.translatedLanguage('/language', 'type'),
|
|
||||||
]),
|
|
||||||
}),
|
|
||||||
),
|
|
||||||
descriptions: schema.array([rules.minLength(1)]).members(
|
|
||||||
schema.object().members({
|
|
||||||
value: schema.string({ trim: true }, [rules.minLength(3), rules.maxLength(255)]),
|
|
||||||
type: schema.enum(Object.values(DescriptionTypes)),
|
|
||||||
language: schema.string({ trim: true }, [
|
|
||||||
rules.minLength(2),
|
|
||||||
rules.maxLength(255),
|
|
||||||
rules.translatedLanguage('/language', 'type'),
|
|
||||||
]),
|
|
||||||
}),
|
|
||||||
),
|
|
||||||
authors: schema.array([rules.minLength(1)]).members(schema.object().members({ email: schema.string({ trim: true }) })),
|
|
||||||
contributors: schema.array.optional().members(
|
|
||||||
schema.object().members({
|
|
||||||
email: schema.string({ trim: true }),
|
|
||||||
pivot_contributor_type: schema.enum(Object.keys(ContributorTypes)),
|
|
||||||
}),
|
|
||||||
),
|
|
||||||
// third step
|
|
||||||
project_id: schema.number.optional(),
|
|
||||||
embargo_date: schema.date.optional({ format: 'yyyy-MM-dd' }, [rules.after(10, 'days')]),
|
|
||||||
coverage: schema.object().members({
|
|
||||||
x_min: schema.number(),
|
|
||||||
x_max: schema.number(),
|
|
||||||
y_min: schema.number(),
|
|
||||||
y_max: schema.number(),
|
|
||||||
elevation_absolut: schema.number.optional(),
|
|
||||||
elevation_min: schema.number.optional([rules.requiredIfExists('elevation_max')]),
|
|
||||||
elevation_max: schema.number.optional([rules.requiredIfExists('elevation_min')]),
|
|
||||||
depth_absolut: schema.number.optional(),
|
|
||||||
depth_min: schema.number.optional([rules.requiredIfExists('depth_max')]),
|
|
||||||
depth_max: schema.number.optional([rules.requiredIfExists('depth_min')]),
|
|
||||||
}),
|
|
||||||
references: schema.array.optional([rules.uniqueArray('value')]).members(
|
|
||||||
schema.object().members({
|
|
||||||
value: schema.string({ trim: true }, [rules.minLength(3), rules.maxLength(255)]),
|
|
||||||
type: schema.enum(Object.values(ReferenceIdentifierTypes)),
|
|
||||||
relation: schema.enum(Object.values(RelationTypes)),
|
|
||||||
label: schema.string({ trim: true }, [rules.minLength(2), rules.maxLength(255)]),
|
|
||||||
}),
|
|
||||||
),
|
|
||||||
subjects: schema.array([rules.minLength(3), rules.uniqueArray('value')]).members(
|
|
||||||
schema.object().members({
|
|
||||||
value: schema.string({ trim: true }, [
|
|
||||||
rules.minLength(3),
|
|
||||||
rules.maxLength(255),
|
|
||||||
// rules.unique({ table: 'dataset_subjects', column: 'value' }),
|
|
||||||
]),
|
|
||||||
// type: schema.enum(Object.values(TitleTypes)),
|
|
||||||
language: schema.string({ trim: true }, [rules.minLength(2), rules.maxLength(255)]),
|
|
||||||
}),
|
|
||||||
),
|
|
||||||
// file: schema.file({
|
|
||||||
// size: '100mb',
|
|
||||||
// extnames: ['jpg', 'gif', 'png'],
|
|
||||||
// }),
|
|
||||||
files: schema.array([rules.minLength(1)]).members(
|
|
||||||
schema.file({
|
|
||||||
size: '512mb',
|
|
||||||
extnames: ['jpg', 'gif', 'png', 'tif', 'pdf', 'zip', 'fgb', 'nc', 'qml', 'ovr', 'gpkg', 'gml', 'gpx', 'kml', 'kmz', 'json'],
|
|
||||||
}),
|
|
||||||
),
|
|
||||||
// upload: schema.object().members({
|
|
||||||
// label: schema.string({ trim: true }, [rules.maxLength(255)]),
|
|
||||||
|
|
||||||
// // label: schema.string({ trim: true }, [
|
|
||||||
// // // rules.minLength(3),
|
|
||||||
// // // rules.maxLength(255),
|
|
||||||
// // ]),
|
|
||||||
// }),
|
|
||||||
});
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Custom messages for validation failures. You can make use of dot notation `(.)`
|
|
||||||
* for targeting nested fields and array expressions `(*)` for targeting all
|
|
||||||
* children of an array. For example:
|
|
||||||
*
|
|
||||||
* {
|
|
||||||
* 'profile.username.required': 'Username is required',
|
|
||||||
* 'scores.*.number': 'Define scores as valid numbers'
|
|
||||||
* }
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
public messages: CustomMessages = {
|
|
||||||
'minLength': '{{ field }} must be at least {{ options.minLength }} characters long',
|
|
||||||
'maxLength': '{{ field }} must be less then {{ options.maxLength }} characters long',
|
|
||||||
'required': '{{ field }} is required',
|
|
||||||
'unique': '{{ field }} must be unique, and this value is already taken',
|
|
||||||
// 'confirmed': '{{ field }} is not correct',
|
|
||||||
'licenses.minLength': 'at least {{ options.minLength }} licenses must be defined',
|
|
||||||
'licenses.*.number': 'Define licences as valid numbers',
|
|
||||||
'rights.equalTo': 'you must agree to continue',
|
|
||||||
|
|
||||||
'titles.0.value.minLength': 'Main Title must be at least {{ options.minLength }} characters long',
|
|
||||||
'titles.0.value.required': 'Main Title is required',
|
|
||||||
'titles.*.value.required': 'Additional title is required, if defined',
|
|
||||||
'titles.*.type.required': 'Additional title type is required',
|
|
||||||
'titles.*.language.required': 'Additional title language is required',
|
|
||||||
'titles.*.language.translatedLanguage': 'The language of the translated title must be different from the language of the dataset',
|
|
||||||
|
|
||||||
'descriptions.0.value.minLength': 'Main Abstract must be at least {{ options.minLength }} characters long',
|
|
||||||
'descriptions.0.value.required': 'Main Abstract is required',
|
|
||||||
'descriptions.*.value.required': 'Additional description is required, if defined',
|
|
||||||
'descriptions.*.type.required': 'Additional description type is required',
|
|
||||||
'descriptions.*.language.required': 'Additional description language is required',
|
|
||||||
'descriptions.*.language.translatedLanguage':
|
|
||||||
'The language of the translated description must be different from the language of the dataset',
|
|
||||||
|
|
||||||
'authors.minLength': 'at least {{ options.minLength }} author must be defined',
|
|
||||||
'contributors.*.pivot_contributor_type.required': 'contributor type is required, if defined',
|
|
||||||
|
|
||||||
'after': `{{ field }} must be older than ${dayjs().add(10, 'day')}`,
|
|
||||||
|
|
||||||
'subjects.minLength': 'at least {{ options.minLength }} keywords must be defined',
|
|
||||||
'subjects.uniqueArray': 'The {{ options.array }} array must have unique values based on the {{ options.field }} attribute.',
|
|
||||||
'subjects.*.value.required': 'keyword value is required',
|
|
||||||
'subjects.*.value.minLength': 'keyword value must be at least {{ options.minLength }} characters long',
|
|
||||||
'subjects.*.type.required': 'keyword type is required',
|
|
||||||
'subjects.*.language.required': 'language of keyword is required',
|
|
||||||
|
|
||||||
'references.*.value.required': 'Additional reference value is required, if defined',
|
|
||||||
'references.*.type.required': 'Additional reference identifier type is required',
|
|
||||||
'references.*.relation.required': 'Additional reference relation type is required',
|
|
||||||
'references.*.label.required': 'Additional reference label is required',
|
|
||||||
|
|
||||||
'files.minLength': 'At least {{ options.minLength }} file upload is required.',
|
|
||||||
'files.*.size': 'file size is to big',
|
|
||||||
'files.extnames': 'file extension is not supported',
|
|
||||||
};
|
|
||||||
}
|
|
|
@ -1,70 +0,0 @@
|
||||||
import { schema, rules } from '@adonisjs/validator';
|
|
||||||
import type { HttpContext } from '@adonisjs/core/http';
|
|
||||||
import { CustomMessages } from "@adonisjs/validator/types";
|
|
||||||
|
|
||||||
export default class CreateRoleValidator {
|
|
||||||
constructor(protected ctx: HttpContext) {}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Define schema to validate the "shape", "type", "formatting" and "integrity" of data.
|
|
||||||
*
|
|
||||||
* For example:
|
|
||||||
* 1. The username must be of data type string. But then also, it should
|
|
||||||
* not contain special characters or numbers.
|
|
||||||
* ```
|
|
||||||
* schema.string({}, [ rules.alpha() ])
|
|
||||||
* ```
|
|
||||||
*
|
|
||||||
* 2. The email must be of data type string, formatted as a valid
|
|
||||||
* email. But also, not used by any other user.
|
|
||||||
* ```
|
|
||||||
* schema.string({}, [
|
|
||||||
* rules.email(),
|
|
||||||
* rules.unique({ table: 'users', column: 'email' }),
|
|
||||||
* ])
|
|
||||||
* ```
|
|
||||||
*/
|
|
||||||
public schema = schema.create({
|
|
||||||
name: schema.string({ trim: true }, [
|
|
||||||
rules.minLength(3),
|
|
||||||
rules.maxLength(255),
|
|
||||||
rules.unique({ table: 'roles', column: 'name' }),
|
|
||||||
rules.regex(/^[a-zA-Z0-9-_]+$/), //Must be alphanumeric with hyphens or underscores
|
|
||||||
]),
|
|
||||||
display_name: schema.string.optional({ trim: true }, [
|
|
||||||
rules.minLength(3),
|
|
||||||
rules.maxLength(255),
|
|
||||||
rules.unique({ table: 'roles', column: 'name' }),
|
|
||||||
rules.regex(/^[a-zA-Z0-9-_]+$/), //Must be alphanumeric with hyphens or underscores
|
|
||||||
]),
|
|
||||||
description: schema.string.optional({}, [rules.minLength(3), rules.maxLength(255)]),
|
|
||||||
permissions: schema.array([rules.minLength(1)]).members(schema.number()), // define at least one role for the new role
|
|
||||||
});
|
|
||||||
|
|
||||||
// emails: schema
|
|
||||||
// .array([rules.minLength(1)])
|
|
||||||
// .members(
|
|
||||||
// schema.object().members({ email: schema.string({}, [rules.email()]) })
|
|
||||||
// ),
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Custom messages for validation failures. You can make use of dot notation `(.)`
|
|
||||||
* for targeting nested fields and array expressions `(*)` for targeting all
|
|
||||||
* children of an array. For example:
|
|
||||||
*
|
|
||||||
* {
|
|
||||||
* 'profile.username.required': 'Username is required',
|
|
||||||
* 'scores.*.number': 'Define scores as valid numbers'
|
|
||||||
* }
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
public messages: CustomMessages = {
|
|
||||||
'minLength': '{{ field }} must be at least {{ options.minLength }} characters long',
|
|
||||||
'maxLength': '{{ field }} must be less then {{ options.maxLength }} characters long',
|
|
||||||
'required': '{{ field }} is required',
|
|
||||||
'unique': '{{ field }} must be unique, and this value is already taken',
|
|
||||||
'confirmed': '{{ field }} is not correct',
|
|
||||||
'permissions.minLength': 'at least {{ options.minLength }} permission must be defined',
|
|
||||||
'permissions.*.number': 'Define roles as valid numbers',
|
|
||||||
};
|
|
||||||
}
|
|
|
@ -1,65 +0,0 @@
|
||||||
import { schema, rules } from '@adonisjs/validator';
|
|
||||||
import type { HttpContext } from '@adonisjs/core/http';
|
|
||||||
import { CustomMessages } from "@adonisjs/validator/types";
|
|
||||||
|
|
||||||
export default class CreateUserValidator {
|
|
||||||
constructor(protected ctx: HttpContext) {}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Define schema to validate the "shape", "type", "formatting" and "integrity" of data.
|
|
||||||
*
|
|
||||||
* For example:
|
|
||||||
* 1. The username must be of data type string. But then also, it should
|
|
||||||
* not contain special characters or numbers.
|
|
||||||
* ```
|
|
||||||
* schema.string({}, [ rules.alpha() ])
|
|
||||||
* ```
|
|
||||||
*
|
|
||||||
* 2. The email must be of data type string, formatted as a valid
|
|
||||||
* email. But also, not used by any other user.
|
|
||||||
* ```
|
|
||||||
* schema.string({}, [
|
|
||||||
* rules.email(),
|
|
||||||
* rules.unique({ table: 'users', column: 'email' }),
|
|
||||||
* ])
|
|
||||||
* ```
|
|
||||||
*/
|
|
||||||
public schema = schema.create({
|
|
||||||
login: schema.string({ trim: true }, [
|
|
||||||
rules.minLength(3),
|
|
||||||
rules.maxLength(50),
|
|
||||||
rules.unique({ table: 'accounts', column: 'login' }),
|
|
||||||
rules.regex(/^[a-zA-Z0-9-_]+$/), //Must be alphanumeric with hyphens or underscores
|
|
||||||
]),
|
|
||||||
email: schema.string({}, [rules.email(), rules.unique({ table: 'accounts', column: 'email' })]),
|
|
||||||
password: schema.string([rules.confirmed(), rules.minLength(6)]),
|
|
||||||
roles: schema.array([rules.minLength(1)]).members(schema.number()), // define at least one role for the new user
|
|
||||||
});
|
|
||||||
|
|
||||||
// emails: schema
|
|
||||||
// .array([rules.minLength(1)])
|
|
||||||
// .members(
|
|
||||||
// schema.object().members({ email: schema.string({}, [rules.email()]) })
|
|
||||||
// ),
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Custom messages for validation failures. You can make use of dot notation `(.)`
|
|
||||||
* for targeting nested fields and array expressions `(*)` for targeting all
|
|
||||||
* children of an array. For example:
|
|
||||||
*
|
|
||||||
* {
|
|
||||||
* 'profile.username.required': 'Username is required',
|
|
||||||
* 'scores.*.number': 'Define scores as valid numbers'
|
|
||||||
* }
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
public messages: CustomMessages = {
|
|
||||||
'minLength': '{{ field }} must be at least {{ options.minLength }} characters long',
|
|
||||||
'maxLength': '{{ field }} must be less then {{ options.maxLength }} characters long',
|
|
||||||
'required': '{{ field }} is required',
|
|
||||||
'unique': '{{ field }} must be unique, and this value is already taken',
|
|
||||||
'confirmed': '{{ field }} is not correct',
|
|
||||||
'roles.minLength': 'at least {{ options.minLength }} role must be defined',
|
|
||||||
'roles.*.number': 'Define roles as valid numbers',
|
|
||||||
};
|
|
||||||
}
|
|
296
app/validators/dataset.ts
Normal file
296
app/validators/dataset.ts
Normal file
|
@ -0,0 +1,296 @@
|
||||||
|
import vine, { SimpleMessagesProvider } from '@vinejs/vine';
|
||||||
|
import { TitleTypes, DescriptionTypes, ContributorTypes, ReferenceIdentifierTypes, RelationTypes } from '#contracts/enums';
|
||||||
|
import dayjs from 'dayjs';
|
||||||
|
import MimeType from '#models/mime_type';
|
||||||
|
|
||||||
|
const enabledExtensions = await MimeType.query().select('file_extension').where('enabled', true).exec();
|
||||||
|
const extensions = enabledExtensions.map((extension)=> {
|
||||||
|
return extension.file_extension.split('|')
|
||||||
|
}).flat();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Validates the dataset's creation action
|
||||||
|
* node ace make:validator dataset
|
||||||
|
*/
|
||||||
|
export const createDatasetValidator = vine.compile(
|
||||||
|
vine.object({
|
||||||
|
// first step
|
||||||
|
language: vine
|
||||||
|
.string()
|
||||||
|
.trim()
|
||||||
|
.regex(/^[a-zA-Z0-9]+$/),
|
||||||
|
licenses: vine.array(vine.number()).minLength(1), // define at least one license for the new dataset
|
||||||
|
rights: vine.string().in(['true']),
|
||||||
|
// second step
|
||||||
|
type: vine.string().trim().minLength(3).maxLength(255),
|
||||||
|
creating_corporation: vine.string().trim().minLength(3).maxLength(255),
|
||||||
|
titles: vine
|
||||||
|
.array(
|
||||||
|
vine.object({
|
||||||
|
value: vine.string().trim().minLength(3).maxLength(255),
|
||||||
|
type: vine.enum(Object.values(TitleTypes)),
|
||||||
|
language: vine
|
||||||
|
.string()
|
||||||
|
.trim()
|
||||||
|
.minLength(2)
|
||||||
|
.maxLength(255)
|
||||||
|
.translatedLanguage({ mainLanguageField: 'language', typeField: 'type' }),
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
.minLength(1),
|
||||||
|
descriptions: vine
|
||||||
|
.array(
|
||||||
|
vine.object({
|
||||||
|
value: vine.string().trim().minLength(3).maxLength(255),
|
||||||
|
type: vine.enum(Object.values(DescriptionTypes)),
|
||||||
|
language: vine
|
||||||
|
.string()
|
||||||
|
.trim()
|
||||||
|
.minLength(2)
|
||||||
|
.maxLength(255)
|
||||||
|
.translatedLanguage({ mainLanguageField: 'language', typeField: 'type' }),
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
.minLength(1),
|
||||||
|
authors: vine
|
||||||
|
.array(
|
||||||
|
vine.object({
|
||||||
|
email: vine.string().trim().maxLength(255).email().normalizeEmail(),
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
.minLength(1),
|
||||||
|
contributors: vine
|
||||||
|
.array(
|
||||||
|
vine.object({
|
||||||
|
email: vine.string().trim().maxLength(255).email().normalizeEmail(),
|
||||||
|
pivot_contributor_type: vine.enum(Object.keys(ContributorTypes)),
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
.optional(),
|
||||||
|
// third step
|
||||||
|
project_id: vine.number().optional(),
|
||||||
|
// embargo_date: schema.date.optional({ format: 'yyyy-MM-dd' }, [rules.after(10, 'days')]),
|
||||||
|
embargo_date: vine
|
||||||
|
.date({
|
||||||
|
formats: ['YYYY-MM-DD'],
|
||||||
|
})
|
||||||
|
.afterOrEqual((_field) => {
|
||||||
|
return dayjs().add(10, 'day').format('YYYY-MM-DD');
|
||||||
|
})
|
||||||
|
.optional(),
|
||||||
|
coverage: vine.object({
|
||||||
|
x_min: vine.number(),
|
||||||
|
x_max: vine.number(),
|
||||||
|
y_min: vine.number(),
|
||||||
|
y_max: vine.number(),
|
||||||
|
elevation_absolut: vine.number().optional(),
|
||||||
|
elevation_min: vine.number().optional().requiredIfExists('elevation_max'),
|
||||||
|
elevation_max: vine.number().optional().requiredIfExists('elevation_min'),
|
||||||
|
// type: vine.enum(Object.values(DescriptionTypes)),
|
||||||
|
depth_absolut: vine.number().optional(),
|
||||||
|
depth_min: vine.number().optional().requiredIfExists('depth_max'),
|
||||||
|
depth_max: vine.number().optional().requiredIfExists('depth_min'),
|
||||||
|
}),
|
||||||
|
references: vine
|
||||||
|
.array(
|
||||||
|
vine.object({
|
||||||
|
value: vine.string().trim().minLength(3).maxLength(255),
|
||||||
|
type: vine.enum(Object.values(ReferenceIdentifierTypes)),
|
||||||
|
relation: vine.enum(Object.values(RelationTypes)),
|
||||||
|
label: vine.string().trim().minLength(2).maxLength(255),
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
.optional(),
|
||||||
|
subjects: vine
|
||||||
|
.array(
|
||||||
|
vine.object({
|
||||||
|
value: vine.string().trim().minLength(3).maxLength(255),
|
||||||
|
// pivot_contributor_type: vine.enum(Object.keys(ContributorTypes)),
|
||||||
|
language: vine.string().trim().minLength(2).maxLength(255),
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
.minLength(3)
|
||||||
|
.distinct('value'),
|
||||||
|
// last step
|
||||||
|
files: vine
|
||||||
|
.array(
|
||||||
|
vine.file({
|
||||||
|
size: '512mb',
|
||||||
|
extnames: extensions,
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
.minLength(1),
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Validates the dataset's update action
|
||||||
|
*/
|
||||||
|
export const updateDatasetValidator = vine.compile(
|
||||||
|
vine.object({
|
||||||
|
// first step
|
||||||
|
language: vine
|
||||||
|
.string()
|
||||||
|
.trim()
|
||||||
|
.regex(/^[a-zA-Z0-9]+$/),
|
||||||
|
licenses: vine.array(vine.number()).minLength(1), // define at least one license for the new dataset
|
||||||
|
rights: vine.string().in(['true']),
|
||||||
|
// second step
|
||||||
|
type: vine.string().trim().minLength(3).maxLength(255),
|
||||||
|
creating_corporation: vine.string().trim().minLength(3).maxLength(255),
|
||||||
|
titles: vine
|
||||||
|
.array(
|
||||||
|
vine.object({
|
||||||
|
value: vine.string().trim().minLength(3).maxLength(255),
|
||||||
|
type: vine.enum(Object.values(TitleTypes)),
|
||||||
|
language: vine
|
||||||
|
.string()
|
||||||
|
.trim()
|
||||||
|
.minLength(2)
|
||||||
|
.maxLength(255)
|
||||||
|
.translatedLanguage({ mainLanguageField: 'language', typeField: 'type' }),
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
.minLength(1),
|
||||||
|
descriptions: vine
|
||||||
|
.array(
|
||||||
|
vine.object({
|
||||||
|
value: vine.string().trim().minLength(3).maxLength(255),
|
||||||
|
type: vine.enum(Object.values(DescriptionTypes)),
|
||||||
|
language: vine
|
||||||
|
.string()
|
||||||
|
.trim()
|
||||||
|
.minLength(2)
|
||||||
|
.maxLength(255)
|
||||||
|
.translatedLanguage({ mainLanguageField: 'language', typeField: 'type' }),
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
.minLength(1),
|
||||||
|
authors: vine
|
||||||
|
.array(
|
||||||
|
vine.object({
|
||||||
|
email: vine.string().trim().maxLength(255).email().normalizeEmail(),
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
.minLength(1),
|
||||||
|
contributors: vine
|
||||||
|
.array(
|
||||||
|
vine.object({
|
||||||
|
email: vine.string().trim().maxLength(255).email().normalizeEmail(),
|
||||||
|
pivot_contributor_type: vine.enum(Object.keys(ContributorTypes)),
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
.optional(),
|
||||||
|
// third step
|
||||||
|
project_id: vine.number().optional(),
|
||||||
|
// embargo_date: schema.date.optional({ format: 'yyyy-MM-dd' }, [rules.after(10, 'days')]),
|
||||||
|
embargo_date: vine
|
||||||
|
.date({
|
||||||
|
formats: ['YYYY-MM-DD'],
|
||||||
|
})
|
||||||
|
.afterOrEqual((_field) => {
|
||||||
|
return dayjs().add(10, 'day').format('YYYY-MM-DD');
|
||||||
|
})
|
||||||
|
.optional(),
|
||||||
|
coverage: vine.object({
|
||||||
|
x_min: vine.number(),
|
||||||
|
x_max: vine.number(),
|
||||||
|
y_min: vine.number(),
|
||||||
|
y_max: vine.number(),
|
||||||
|
elevation_absolut: vine.number().optional(),
|
||||||
|
elevation_min: vine.number().optional().requiredIfExists('elevation_max'),
|
||||||
|
elevation_max: vine.number().optional().requiredIfExists('elevation_min'),
|
||||||
|
// type: vine.enum(Object.values(DescriptionTypes)),
|
||||||
|
depth_absolut: vine.number().optional(),
|
||||||
|
depth_min: vine.number().optional().requiredIfExists('depth_max'),
|
||||||
|
depth_max: vine.number().optional().requiredIfExists('depth_min'),
|
||||||
|
}),
|
||||||
|
references: vine
|
||||||
|
.array(
|
||||||
|
vine.object({
|
||||||
|
value: vine.string().trim().minLength(3).maxLength(255),
|
||||||
|
type: vine.enum(Object.values(ReferenceIdentifierTypes)),
|
||||||
|
relation: vine.enum(Object.values(RelationTypes)),
|
||||||
|
label: vine.string().trim().minLength(2).maxLength(255),
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
.optional(),
|
||||||
|
subjects: vine
|
||||||
|
.array(
|
||||||
|
vine.object({
|
||||||
|
value: vine.string().trim().minLength(3).maxLength(255),
|
||||||
|
// pivot_contributor_type: vine.enum(Object.keys(ContributorTypes)),
|
||||||
|
language: vine.string().trim().minLength(2).maxLength(255),
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
.minLength(3)
|
||||||
|
.distinct('value'),
|
||||||
|
// last step
|
||||||
|
files: vine
|
||||||
|
.array(
|
||||||
|
vine.file({
|
||||||
|
size: '512mb',
|
||||||
|
extnames: extensions,
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
// .minLength(1),
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
|
// files: schema.array([rules.minLength(1)]).members(
|
||||||
|
// schema.file({
|
||||||
|
// size: '512mb',
|
||||||
|
// extnames: ['jpg', 'gif', 'png', 'tif', 'pdf', 'zip', 'fgb', 'nc', 'qml', 'ovr', 'gpkg', 'gml', 'gpx', 'kml', 'kmz', 'json'],
|
||||||
|
// }),
|
||||||
|
// ),
|
||||||
|
|
||||||
|
let messagesProvider = new SimpleMessagesProvider({
|
||||||
|
'minLength': '{{ field }} must be at least {{ min }} characters long',
|
||||||
|
'maxLength': '{{ field }} must be less then {{ max }} characters long',
|
||||||
|
'required': '{{ field }} is required',
|
||||||
|
'unique': '{{ field }} must be unique, and this value is already taken',
|
||||||
|
// 'confirmed': '{{ field }} is not correct',
|
||||||
|
'licenses.minLength': 'at least {{ min }} permission must be defined',
|
||||||
|
'licenses.*.number': 'Define roles as valid numbers',
|
||||||
|
'rights.in': 'you must agree to continue',
|
||||||
|
|
||||||
|
'titles.0.value.minLength': 'Main Title must be at least {{ min }} characters long',
|
||||||
|
'titles.0.value.required': 'Main Title is required',
|
||||||
|
'titles.*.value.required': 'Additional title is required, if defined',
|
||||||
|
'titles.*.type.required': 'Additional title type is required',
|
||||||
|
'titles.*.language.required': 'Additional title language is required',
|
||||||
|
'titles.*.language.translatedLanguage': 'The language of the translated title must be different from the language of the dataset',
|
||||||
|
|
||||||
|
'descriptions.0.value.minLength': 'Main Abstract must be at least {{ min }} characters long',
|
||||||
|
'descriptions.0.value.required': 'Main Abstract is required',
|
||||||
|
'descriptions.*.value.required': 'Additional description is required, if defined',
|
||||||
|
'descriptions.*.type.required': 'Additional description type is required',
|
||||||
|
'descriptions.*.language.required': 'Additional description language is required',
|
||||||
|
'descriptions.*.language.translatedLanguage':
|
||||||
|
'The language of the translated description must be different from the language of the dataset',
|
||||||
|
|
||||||
|
'authors.array.minLength': 'at least {{ min }} author must be defined',
|
||||||
|
'contributors.*.pivot_contributor_type.required': 'contributor type is required, if defined',
|
||||||
|
|
||||||
|
'after': `{{ field }} must be older than ${dayjs().add(10, 'day')}`,
|
||||||
|
|
||||||
|
'subjects.array.minLength': 'at least {{ min }} keywords must be defined',
|
||||||
|
'subjects.*.value.required': 'keyword value is required',
|
||||||
|
'subjects.*.value.minLength': 'keyword value must be at least {{ min }} characters long',
|
||||||
|
'subjects.*.type.required': 'keyword type is required',
|
||||||
|
'subjects.*.language.required': 'language of keyword is required',
|
||||||
|
'subjects.distinct': 'The {{ field }} array must have unique values based on the {{ fields }} attribute.',
|
||||||
|
|
||||||
|
'references.*.value.required': 'Additional reference value is required, if defined',
|
||||||
|
'references.*.type.required': 'Additional reference identifier type is required',
|
||||||
|
'references.*.relation.required': 'Additional reference relation type is required',
|
||||||
|
'references.*.label.required': 'Additional reference label is required',
|
||||||
|
|
||||||
|
'files.array.minLength': 'At least {{ min }} file upload is required.',
|
||||||
|
'files.*.size': 'file size is to big',
|
||||||
|
'files.*.extnames': 'file extension is not supported',
|
||||||
|
});
|
||||||
|
|
||||||
|
createDatasetValidator.messagesProvider = messagesProvider;
|
||||||
|
updateDatasetValidator.messagesProvider = messagesProvider;
|
||||||
|
// export default createDatasetValidator;
|
64
app/validators/role.ts
Normal file
64
app/validators/role.ts
Normal file
|
@ -0,0 +1,64 @@
|
||||||
|
import vine, { SimpleMessagesProvider } from '@vinejs/vine';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Validates the role's creation action
|
||||||
|
* node ace make:validator role
|
||||||
|
*/
|
||||||
|
export const createRoleValidator = vine.compile(
|
||||||
|
vine.object({
|
||||||
|
name: vine
|
||||||
|
.string()
|
||||||
|
.isUnique({ table: 'roles', column: 'name' })
|
||||||
|
.trim()
|
||||||
|
.minLength(3)
|
||||||
|
.maxLength(255)
|
||||||
|
.regex(/^[a-zA-Z0-9]+$/), //Must be alphanumeric with hyphens or underscores
|
||||||
|
display_name: vine
|
||||||
|
.string()
|
||||||
|
.isUnique({ table: 'roles', column: 'display_name' })
|
||||||
|
.trim()
|
||||||
|
.minLength(3)
|
||||||
|
.maxLength(255)
|
||||||
|
.regex(/^[a-zA-Z0-9]+$/),
|
||||||
|
description: vine.string().trim().escape().minLength(3).maxLength(255).optional(),
|
||||||
|
permissions: vine.array(vine.number()).minLength(1), // define at least one permission for the new role
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
|
export const updateRoleValidator = vine.withMetaData<{ roleId: number }>().compile(
|
||||||
|
vine.object({
|
||||||
|
name: vine
|
||||||
|
.string()
|
||||||
|
// .unique(async (db, value, field) => {
|
||||||
|
// const result = await db.from('roles').select('id').whereNot('id', field.meta.roleId).where('name', value).first();
|
||||||
|
// return result.length ? false : true;
|
||||||
|
// })
|
||||||
|
.isUnique({
|
||||||
|
table: 'roles',
|
||||||
|
column: 'name',
|
||||||
|
whereNot: (field) => field.meta.roleId,
|
||||||
|
})
|
||||||
|
.trim()
|
||||||
|
.minLength(3)
|
||||||
|
.maxLength(255),
|
||||||
|
|
||||||
|
description: vine.string().trim().escape().minLength(3).maxLength(255).optional(),
|
||||||
|
permissions: vine.array(vine.number()).minLength(1), // define at least one permission for the new role
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
|
let messagesProvider = new SimpleMessagesProvider({
|
||||||
|
// Applicable for all fields
|
||||||
|
'required': 'The {{ field }} field is required',
|
||||||
|
'unique': '{{ field }} must be unique, and this value is already taken',
|
||||||
|
'string': 'The value of {{ field }} field must be a string',
|
||||||
|
'email': 'The value is not a valid email address',
|
||||||
|
|
||||||
|
// 'contacts.0.email.required': 'The primary email of the contact is required',
|
||||||
|
// 'contacts.*.email.required': 'Contact email is required',
|
||||||
|
'permissions.minLength': 'at least {{ options.minLength }} permission must be defined',
|
||||||
|
'permissions.*.number': 'Define permissions as valid numbers',
|
||||||
|
});
|
||||||
|
|
||||||
|
createRoleValidator.messagesProvider = messagesProvider;
|
||||||
|
updateRoleValidator.messagesProvider = messagesProvider;
|
|
@ -1,180 +0,0 @@
|
||||||
import { schema, rules } from '@adonisjs/validator';
|
|
||||||
import type { HttpContext } from '@adonisjs/core/http';
|
|
||||||
import dayjs from 'dayjs';
|
|
||||||
import { TitleTypes, DescriptionTypes, RelationTypes, ReferenceIdentifierTypes, ContributorTypes } from '#contracts/enums';
|
|
||||||
import { CustomMessages } from "@adonisjs/validator/types";
|
|
||||||
|
|
||||||
export default class UpdateDatasetValidator {
|
|
||||||
constructor(protected ctx: HttpContext) {}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Define schema to validate the "shape", "type", "formatting" and "integrity" of data.
|
|
||||||
*
|
|
||||||
* For example:
|
|
||||||
* 1. The username must be of data type string. But then also, it should
|
|
||||||
* not contain special characters or numbers.
|
|
||||||
* ```
|
|
||||||
* schema.string({}, [ rules.alpha() ])
|
|
||||||
* ```
|
|
||||||
*
|
|
||||||
* 2. The email must be of data type string, formatted as a valid
|
|
||||||
* email. But also, not used by any other user.
|
|
||||||
* ```
|
|
||||||
* schema.string({}, [
|
|
||||||
* rules.email(),
|
|
||||||
* rules.unique({ table: 'users', column: 'email' }),
|
|
||||||
* ])
|
|
||||||
* ```
|
|
||||||
*/
|
|
||||||
public schema = schema.create({
|
|
||||||
// first step
|
|
||||||
language: schema.string({ trim: true }, [
|
|
||||||
rules.regex(/^[a-zA-Z0-9-_]+$/), //Must be alphanumeric with hyphens or underscores
|
|
||||||
]),
|
|
||||||
licenses: schema.array([rules.minLength(1)]).members(schema.number()), // define at least one license for the new dataset
|
|
||||||
rights: schema.string([rules.equalTo('true')]),
|
|
||||||
// second step
|
|
||||||
type: schema.string({ trim: true }, [rules.minLength(3), rules.maxLength(255)]),
|
|
||||||
creating_corporation: schema.string({ trim: true }, [rules.minLength(3), rules.maxLength(255)]),
|
|
||||||
titles: schema.array([rules.minLength(1)]).members(
|
|
||||||
schema.object().members({
|
|
||||||
value: schema.string({ trim: true }, [rules.minLength(3), rules.maxLength(255)]),
|
|
||||||
type: schema.enum(Object.values(TitleTypes)),
|
|
||||||
language: schema.string({ trim: true }, [
|
|
||||||
rules.minLength(2),
|
|
||||||
rules.maxLength(255),
|
|
||||||
rules.translatedLanguage('/language', 'type'),
|
|
||||||
]),
|
|
||||||
}),
|
|
||||||
),
|
|
||||||
descriptions: schema.array([rules.minLength(1)]).members(
|
|
||||||
schema.object().members({
|
|
||||||
value: schema.string({ trim: true }, [rules.minLength(3), rules.maxLength(255)]),
|
|
||||||
type: schema.enum(Object.values(DescriptionTypes)),
|
|
||||||
language: schema.string({ trim: true }, [
|
|
||||||
rules.minLength(2),
|
|
||||||
rules.maxLength(255),
|
|
||||||
rules.translatedLanguage('/language', 'type'),
|
|
||||||
]),
|
|
||||||
}),
|
|
||||||
),
|
|
||||||
authors: schema.array([rules.minLength(1)]).members(schema.object().members({ email: schema.string({ trim: true }) })),
|
|
||||||
contributors: schema.array.optional().members(
|
|
||||||
schema.object().members({
|
|
||||||
email: schema.string({ trim: true }),
|
|
||||||
pivot_contributor_type: schema.enum(Object.keys(ContributorTypes)),
|
|
||||||
}),
|
|
||||||
),
|
|
||||||
// third step
|
|
||||||
project_id: schema.number.optional(),
|
|
||||||
embargo_date: schema.date.optional({ format: 'yyyy-MM-dd' }, [rules.after(10, 'days')]),
|
|
||||||
coverage: schema.object().members({
|
|
||||||
x_min: schema.number(),
|
|
||||||
x_max: schema.number(),
|
|
||||||
y_min: schema.number(),
|
|
||||||
y_max: schema.number(),
|
|
||||||
elevation_absolut: schema.number.optional(),
|
|
||||||
elevation_min: schema.number.optional([rules.requiredIfExists('elevation_max')]),
|
|
||||||
elevation_max: schema.number.optional([rules.requiredIfExists('elevation_min')]),
|
|
||||||
depth_absolut: schema.number.optional(),
|
|
||||||
depth_min: schema.number.optional([rules.requiredIfExists('depth_max')]),
|
|
||||||
depth_max: schema.number.optional([rules.requiredIfExists('depth_min')]),
|
|
||||||
}),
|
|
||||||
references: schema.array.optional([rules.uniqueArray('value')]).members(
|
|
||||||
schema.object().members({
|
|
||||||
value: schema.string({ trim: true }, [rules.minLength(3), rules.maxLength(255)]),
|
|
||||||
type: schema.enum(Object.values(ReferenceIdentifierTypes)),
|
|
||||||
relation: schema.enum(Object.values(RelationTypes)),
|
|
||||||
label: schema.string({ trim: true }, [rules.minLength(2), rules.maxLength(255)]),
|
|
||||||
}),
|
|
||||||
),
|
|
||||||
subjects: schema.array([rules.minLength(3), rules.uniqueArray('value')]).members(
|
|
||||||
schema.object().members({
|
|
||||||
value: schema.string({ trim: true }, [
|
|
||||||
rules.minLength(3),
|
|
||||||
rules.maxLength(255),
|
|
||||||
// rules.unique({ table: 'dataset_subjects', column: 'value' }),
|
|
||||||
]),
|
|
||||||
// type: schema.enum(Object.values(TitleTypes)),
|
|
||||||
language: schema.string({ trim: true }, [rules.minLength(2), rules.maxLength(255)]),
|
|
||||||
}),
|
|
||||||
),
|
|
||||||
// file: schema.file({
|
|
||||||
// size: '100mb',
|
|
||||||
// extnames: ['jpg', 'gif', 'png'],
|
|
||||||
// }),
|
|
||||||
files: schema.array.optional().members(
|
|
||||||
schema.file({
|
|
||||||
size: '100mb',
|
|
||||||
extnames: ['jpg', 'gif', 'png', 'tif', 'pdf'],
|
|
||||||
}),
|
|
||||||
)
|
|
||||||
|
|
||||||
// upload: schema.object().members({
|
|
||||||
// label: schema.string({ trim: true }, [rules.maxLength(255)]),
|
|
||||||
|
|
||||||
// // label: schema.string({ trim: true }, [
|
|
||||||
// // // rules.minLength(3),
|
|
||||||
// // // rules.maxLength(255),
|
|
||||||
// // ]),
|
|
||||||
// }),
|
|
||||||
});
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Custom messages for validation failures. You can make use of dot notation `(.)`
|
|
||||||
* for targeting nested fields and array expressions `(*)` for targeting all
|
|
||||||
* children of an array. For example:
|
|
||||||
*
|
|
||||||
* {
|
|
||||||
* 'profile.username.required': 'Username is required',
|
|
||||||
* 'scores.*.number': 'Define scores as valid numbers'
|
|
||||||
* }
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
public messages: CustomMessages = {
|
|
||||||
'minLength': '{{ field }} must be at least {{ options.minLength }} characters long',
|
|
||||||
'maxLength': '{{ field }} must be less then {{ options.maxLength }} characters long',
|
|
||||||
'required': '{{ field }} is required',
|
|
||||||
'unique': '{{ field }} must be unique, and this value is already taken',
|
|
||||||
// 'confirmed': '{{ field }} is not correct',
|
|
||||||
'licenses.minLength': 'at least {{ options.minLength }} licenses must be defined',
|
|
||||||
'licenses.*.number': 'Define licences as valid numbers',
|
|
||||||
'rights.equalTo': 'you must agree to continue',
|
|
||||||
|
|
||||||
'titles.0.value.minLength': 'Main Title must be at least {{ options.minLength }} characters long',
|
|
||||||
'titles.0.value.required': 'Main Title is required',
|
|
||||||
'titles.*.value.required': 'Additional title is required, if defined',
|
|
||||||
'titles.*.type.required': 'Additional title type is required',
|
|
||||||
'titles.*.language.required': 'Additional title language is required',
|
|
||||||
'titles.*.language.translatedLanguage': 'The language of the translated title must be different from the language of the dataset',
|
|
||||||
|
|
||||||
'descriptions.0.value.minLength': 'Main Abstract must be at least {{ options.minLength }} characters long',
|
|
||||||
'descriptions.0.value.required': 'Main Abstract is required',
|
|
||||||
'descriptions.*.value.required': 'Additional description is required, if defined',
|
|
||||||
'descriptions.*.type.required': 'Additional description type is required',
|
|
||||||
'descriptions.*.language.required': 'Additional description language is required',
|
|
||||||
'descriptions.*.language.translatedLanguage':
|
|
||||||
'The language of the translated description must be different from the language of the dataset',
|
|
||||||
|
|
||||||
'authors.minLength': 'at least {{ options.minLength }} author must be defined',
|
|
||||||
'contributors.*.pivot_contributor_type.required': 'contributor type is required, if defined',
|
|
||||||
|
|
||||||
'after': `{{ field }} must be older than ${dayjs().add(10, 'day')}`,
|
|
||||||
|
|
||||||
'subjects.minLength': 'at least {{ options.minLength }} keywords must be defined',
|
|
||||||
'subjects.uniqueArray': 'The {{ options.array }} array must have unique values based on the {{ options.field }} attribute.',
|
|
||||||
'subjects.*.value.required': 'keyword value is required',
|
|
||||||
'subjects.*.value.minLength': 'keyword value must be at least {{ options.minLength }} characters long',
|
|
||||||
'subjects.*.type.required': 'keyword type is required',
|
|
||||||
'subjects.*.language.required': 'language of keyword is required',
|
|
||||||
|
|
||||||
'references.*.value.required': 'Additional reference value is required, if defined',
|
|
||||||
'references.*.type.required': 'Additional reference identifier type is required',
|
|
||||||
'references.*.relation.required': 'Additional reference relation type is required',
|
|
||||||
'references.*.label.required': 'Additional reference label is required',
|
|
||||||
|
|
||||||
'files.minLength': 'At least {{ options.minLength }} file upload is required.',
|
|
||||||
'files.*.size': 'file size is to big',
|
|
||||||
'files.extnames': 'file extension is not supported',
|
|
||||||
};
|
|
||||||
}
|
|
|
@ -1,99 +0,0 @@
|
||||||
import { schema, rules } from '@adonisjs/validator';
|
|
||||||
import type { HttpContext } from '@adonisjs/core/http';
|
|
||||||
import { CustomMessages } from "@adonisjs/validator/types";
|
|
||||||
|
|
||||||
// import { Request } from '@adonisjs/core/build/standalone';
|
|
||||||
|
|
||||||
export default class UpdateRoleValidator {
|
|
||||||
protected ctx: HttpContext;
|
|
||||||
public schema;
|
|
||||||
|
|
||||||
constructor(ctx: HttpContext) {
|
|
||||||
this.ctx = ctx;
|
|
||||||
this.schema = this.createSchema();
|
|
||||||
}
|
|
||||||
|
|
||||||
// public get schema() {
|
|
||||||
// return this._schema;
|
|
||||||
// }
|
|
||||||
|
|
||||||
private createSchema() {
|
|
||||||
return schema.create({
|
|
||||||
name: schema.string({ trim: true }, [
|
|
||||||
rules.minLength(3),
|
|
||||||
rules.maxLength(50),
|
|
||||||
rules.unique({
|
|
||||||
table: 'roles',
|
|
||||||
column: 'name',
|
|
||||||
whereNot: { id: this.ctx?.params.id },
|
|
||||||
}),
|
|
||||||
rules.regex(/^[a-zA-Z0-9-_]+$/),
|
|
||||||
//Must be alphanumeric with hyphens or underscores
|
|
||||||
]),
|
|
||||||
description: schema.string.optional({}, [rules.minLength(3), rules.maxLength(255)]),
|
|
||||||
permissions: schema.array([rules.minLength(1)]).members(schema.number()), // define at least one permission for the new role
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Define schema to validate the "shape", "type", "formatting" and "integrity" of data.
|
|
||||||
*
|
|
||||||
* For example:
|
|
||||||
* 1. The username must be of data type string. But then also, it should
|
|
||||||
* not contain special characters or numbers.
|
|
||||||
* ```
|
|
||||||
* schema.string({}, [ rules.alpha() ])
|
|
||||||
* ```
|
|
||||||
*
|
|
||||||
* 2. The email must be of data type string, formatted as a valid
|
|
||||||
* email. But also, not used by any other user.
|
|
||||||
* ```
|
|
||||||
* schema.string({}, [
|
|
||||||
* rules.email(),
|
|
||||||
* rules.unique({ table: 'users', column: 'email' }),
|
|
||||||
* ])
|
|
||||||
* ```
|
|
||||||
*/
|
|
||||||
|
|
||||||
// public refs = schema.refs({
|
|
||||||
// id: this.ctx.params.id
|
|
||||||
// })
|
|
||||||
|
|
||||||
// public schema = schema.create({
|
|
||||||
// login: schema.string({ trim: true }, [
|
|
||||||
// rules.minLength(3),
|
|
||||||
// rules.maxLength(50),
|
|
||||||
// rules.unique({
|
|
||||||
// table: 'accounts',
|
|
||||||
// column: 'login',
|
|
||||||
// // whereNot: { id: this.refs.id }
|
|
||||||
// whereNot: { id: this.ctx?.params.id },
|
|
||||||
// }),
|
|
||||||
// // rules.regex(/^[a-zA-Z0-9-_]+$/),
|
|
||||||
// //Must be alphanumeric with hyphens or underscores
|
|
||||||
// ]),
|
|
||||||
// email: schema.string({}, [rules.email(), rules.unique({ table: 'accounts', column: 'email' })]),
|
|
||||||
// password: schema.string.optional([rules.confirmed(), rules.minLength(6)]),
|
|
||||||
// roles: schema.array([rules.minLength(1)]).members(schema.number()), // define at least one role for the new user
|
|
||||||
// });
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Custom messages for validation failures. You can make use of dot notation `(.)`
|
|
||||||
* for targeting nested fields and array expressions `(*)` for targeting all
|
|
||||||
* children of an array. For example:
|
|
||||||
*
|
|
||||||
* {
|
|
||||||
* 'profile.username.required': 'Username is required',
|
|
||||||
* 'scores.*.number': 'Define scores as valid numbers'
|
|
||||||
* }
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
public messages: CustomMessages = {
|
|
||||||
'minLength': '{{ field }} must be at least {{ options.minLength }} characters long',
|
|
||||||
'maxLength': '{{ field }} must be less then {{ options.maxLength }} characters long',
|
|
||||||
'required': '{{ field }} is required',
|
|
||||||
'unique': '{{ field }} must be unique, and this value is already taken',
|
|
||||||
'permissions.minLength': 'at least {{ options.minLength }} permission must be defined',
|
|
||||||
'permissions.*.number': 'Define permissions as valid numbers',
|
|
||||||
};
|
|
||||||
}
|
|
|
@ -1,105 +0,0 @@
|
||||||
import { schema, rules } from '@adonisjs/validator';
|
|
||||||
import type { HttpContext } from '@adonisjs/core/http';
|
|
||||||
import { CustomMessages } from "@adonisjs/validator/types";
|
|
||||||
|
|
||||||
// import { Request } from '@adonisjs/core/build/standalone';
|
|
||||||
|
|
||||||
export default class UpdateUserValidator {
|
|
||||||
protected ctx: HttpContext;
|
|
||||||
public schema;
|
|
||||||
|
|
||||||
constructor(ctx: HttpContext) {
|
|
||||||
this.ctx = ctx;
|
|
||||||
this.schema = this.createSchema();
|
|
||||||
}
|
|
||||||
|
|
||||||
// public get schema() {
|
|
||||||
// return this._schema;
|
|
||||||
// }
|
|
||||||
|
|
||||||
private createSchema() {
|
|
||||||
return schema.create({
|
|
||||||
login: schema.string({ trim: true }, [
|
|
||||||
rules.minLength(3),
|
|
||||||
rules.maxLength(50),
|
|
||||||
rules.unique({
|
|
||||||
table: 'accounts',
|
|
||||||
column: 'login',
|
|
||||||
// whereNot: { id: this.refs.id }
|
|
||||||
whereNot: { id: this.ctx?.params.id },
|
|
||||||
}),
|
|
||||||
// rules.regex(/^[a-zA-Z0-9-_]+$/),
|
|
||||||
//Must be alphanumeric with hyphens or underscores
|
|
||||||
]),
|
|
||||||
email: schema.string({}, [
|
|
||||||
rules.email(),
|
|
||||||
rules.unique({ table: 'accounts', column: 'email', whereNot: { id: this.ctx?.params.id } }),
|
|
||||||
]),
|
|
||||||
password: schema.string.optional([rules.confirmed(), rules.minLength(6)]),
|
|
||||||
roles: schema.array.optional([rules.minLength(1)]).members(schema.number()), // define at least one role for the new user
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Define schema to validate the "shape", "type", "formatting" and "integrity" of data.
|
|
||||||
*
|
|
||||||
* For example:
|
|
||||||
* 1. The username must be of data type string. But then also, it should
|
|
||||||
* not contain special characters or numbers.
|
|
||||||
* ```
|
|
||||||
* schema.string({}, [ rules.alpha() ])
|
|
||||||
* ```
|
|
||||||
*
|
|
||||||
* 2. The email must be of data type string, formatted as a valid
|
|
||||||
* email. But also, not used by any other user.
|
|
||||||
* ```
|
|
||||||
* schema.string({}, [
|
|
||||||
* rules.email(),
|
|
||||||
* rules.unique({ table: 'users', column: 'email' }),
|
|
||||||
* ])
|
|
||||||
* ```
|
|
||||||
*/
|
|
||||||
|
|
||||||
// public refs = schema.refs({
|
|
||||||
// id: this.ctx.params.id
|
|
||||||
// })
|
|
||||||
|
|
||||||
// public schema = schema.create({
|
|
||||||
// login: schema.string({ trim: true }, [
|
|
||||||
// rules.minLength(3),
|
|
||||||
// rules.maxLength(50),
|
|
||||||
// rules.unique({
|
|
||||||
// table: 'accounts',
|
|
||||||
// column: 'login',
|
|
||||||
// // whereNot: { id: this.refs.id }
|
|
||||||
// whereNot: { id: this.ctx?.params.id },
|
|
||||||
// }),
|
|
||||||
// // rules.regex(/^[a-zA-Z0-9-_]+$/),
|
|
||||||
// //Must be alphanumeric with hyphens or underscores
|
|
||||||
// ]),
|
|
||||||
// email: schema.string({}, [rules.email(), rules.unique({ table: 'accounts', column: 'email' })]),
|
|
||||||
// password: schema.string.optional([rules.confirmed(), rules.minLength(6)]),
|
|
||||||
// roles: schema.array([rules.minLength(1)]).members(schema.number()), // define at least one role for the new user
|
|
||||||
// });
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Custom messages for validation failures. You can make use of dot notation `(.)`
|
|
||||||
* for targeting nested fields and array expressions `(*)` for targeting all
|
|
||||||
* children of an array. For example:
|
|
||||||
*
|
|
||||||
* {
|
|
||||||
* 'profile.username.required': 'Username is required',
|
|
||||||
* 'scores.*.number': 'Define scores as valid numbers'
|
|
||||||
* }
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
public messages: CustomMessages = {
|
|
||||||
'minLength': '{{ field }} must be at least {{ options.minLength }} characters long',
|
|
||||||
'maxLength': '{{ field }} must be less then {{ options.maxLength }} characters long',
|
|
||||||
'required': '{{ field }} is required',
|
|
||||||
'unique': '{{ field }} must be unique, and this value is already taken',
|
|
||||||
'confirmed': '{{ field }} is not correct',
|
|
||||||
'roles.minLength': 'at least {{ options.minLength }} role must be defined',
|
|
||||||
'roles.*.number': 'Define roles as valid numbers',
|
|
||||||
};
|
|
||||||
}
|
|
60
app/validators/user.ts
Normal file
60
app/validators/user.ts
Normal file
|
@ -0,0 +1,60 @@
|
||||||
|
import vine, { SimpleMessagesProvider } from '@vinejs/vine';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Validates the role's creation action
|
||||||
|
* node ace make:validator user
|
||||||
|
*/
|
||||||
|
export const createUserValidator = vine.compile(
|
||||||
|
vine.object({
|
||||||
|
login: vine
|
||||||
|
.string()
|
||||||
|
.trim()
|
||||||
|
.minLength(3)
|
||||||
|
.maxLength(20)
|
||||||
|
.isUnique({ table: 'accounts', column: 'login' })
|
||||||
|
.regex(/^[a-zA-Z0-9]+$/), //Must be alphanumeric with hyphens or underscores
|
||||||
|
email: vine.string().maxLength(255).email().normalizeEmail().isUnique({ table: 'accounts', column: 'email' }),
|
||||||
|
password: vine.string().confirmed().trim().minLength(3).maxLength(60),
|
||||||
|
roles: vine.array(vine.number()).minLength(1), // define at least one role for the new user
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Validates the role's update action
|
||||||
|
* node ace make:validator user
|
||||||
|
*/
|
||||||
|
export const updateUserValidator = vine.withMetaData<{ userId: number }>().compile(
|
||||||
|
vine.object({
|
||||||
|
login: vine
|
||||||
|
.string()
|
||||||
|
.trim()
|
||||||
|
.minLength(3)
|
||||||
|
.maxLength(20)
|
||||||
|
.isUnique({ table: 'accounts', column: 'login', whereNot: (field) => field.meta.userId })
|
||||||
|
.regex(/^[a-zA-Z0-9]+$/), //Must be alphanumeric with hyphens or underscores
|
||||||
|
email: vine
|
||||||
|
.string()
|
||||||
|
.maxLength(255)
|
||||||
|
.email()
|
||||||
|
.normalizeEmail()
|
||||||
|
.isUnique({ table: 'accounts', column: 'email', whereNot: (field) => field.meta.userId }),
|
||||||
|
password: vine.string().confirmed().trim().minLength(3).maxLength(60),
|
||||||
|
roles: vine.array(vine.number()).minLength(1), // define at least one role for the new user
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
|
let messagesProvider = new SimpleMessagesProvider({
|
||||||
|
// Applicable for all fields
|
||||||
|
'required': 'The {{ field }} field is required',
|
||||||
|
'unique': '{{ field }} must be unique, and this value is already taken',
|
||||||
|
'string': 'The value of {{ field }} field must be a string',
|
||||||
|
'email': 'The value is not a valid email address',
|
||||||
|
'minLength': '{{ field }} must be at least {{ options.minLength }} characters long',
|
||||||
|
'maxLength': '{{ field }} must be less then {{ options.maxLength }} characters long',
|
||||||
|
'confirmed': 'Oops! The confirmation of {{ field }} is not correct. Please double-check and ensure they match.',
|
||||||
|
'roles.minLength': 'at least {{ options.minLength }} role must be defined',
|
||||||
|
'roles.*.number': 'Define roles as valid numbers',
|
||||||
|
});
|
||||||
|
|
||||||
|
createUserValidator.messagesProvider = messagesProvider;
|
||||||
|
updateUserValidator.messagesProvider = messagesProvider;
|
169
app/validators/vanilla_error_reporter.ts
Normal file
169
app/validators/vanilla_error_reporter.ts
Normal file
|
@ -0,0 +1,169 @@
|
||||||
|
// import { ValidationError } from '../errors/validation_error.js';
|
||||||
|
import { errors } from '@vinejs/vine';
|
||||||
|
import type { ErrorReporterContract, FieldContext } from '@vinejs/vine/types';
|
||||||
|
import string from '@poppinss/utils/string';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Shape of the Vanilla error node
|
||||||
|
*/
|
||||||
|
export type VanillaErrorNode = {
|
||||||
|
[field: string]: string[];
|
||||||
|
};
|
||||||
|
export interface MessagesBagContract {
|
||||||
|
get(pointer: string, rule: string, message: string, arrayExpressionPointer?: string, args?: any): string;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Message bag exposes the API to pull the most appropriate message for a
|
||||||
|
* given validation failure.
|
||||||
|
*/
|
||||||
|
export class MessagesBag implements MessagesBagContract {
|
||||||
|
messages;
|
||||||
|
wildCardCallback;
|
||||||
|
constructor(messages: string[]) {
|
||||||
|
this.messages = messages;
|
||||||
|
this.wildCardCallback = typeof this.messages['*'] === 'function' ? this.messages['*'] : undefined;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Transform message by replace placeholders with runtime values
|
||||||
|
*/
|
||||||
|
transform(message: any, rule: string, pointer: string, args: any) {
|
||||||
|
/**
|
||||||
|
* No interpolation required
|
||||||
|
*/
|
||||||
|
if (!message.includes('{{')) {
|
||||||
|
return message;
|
||||||
|
}
|
||||||
|
return string.interpolate(message, { rule, field: pointer, options: args || {} });
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Returns the most appropriate message for the validation failure.
|
||||||
|
*/
|
||||||
|
get(pointer: string, rule: string, message: string, arrayExpressionPointer: string, args: any) {
|
||||||
|
let validationMessage = this.messages[`${pointer}.${rule}`];
|
||||||
|
/**
|
||||||
|
* Fetch message for the array expression pointer if it exists
|
||||||
|
*/
|
||||||
|
if (!validationMessage && arrayExpressionPointer) {
|
||||||
|
validationMessage = this.messages[`${arrayExpressionPointer}.${rule}`];
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Fallback to the message for the rule
|
||||||
|
*/
|
||||||
|
if (!validationMessage) {
|
||||||
|
validationMessage = this.messages[rule];
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Transform and return message. The wildcard callback is invoked when custom message
|
||||||
|
* is not defined
|
||||||
|
*/
|
||||||
|
return validationMessage
|
||||||
|
? this.transform(validationMessage, rule, pointer, args)
|
||||||
|
: this.wildCardCallback
|
||||||
|
? this.wildCardCallback(pointer, rule, arrayExpressionPointer, args)
|
||||||
|
: message;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Shape of the error message collected by the SimpleErrorReporter
|
||||||
|
*/
|
||||||
|
// type SimpleError = {
|
||||||
|
// message: string;
|
||||||
|
// field: string;
|
||||||
|
// rule: string;
|
||||||
|
// index?: number;
|
||||||
|
// meta?: Record<string, any>;
|
||||||
|
// };
|
||||||
|
/**
|
||||||
|
* Simple error reporter collects error messages as an array of object.
|
||||||
|
* Each object has following properties.
|
||||||
|
*
|
||||||
|
* - message: string
|
||||||
|
* - field: string
|
||||||
|
* - rule: string
|
||||||
|
* - index?: number (in case of an array member)
|
||||||
|
* - args?: Record<string, any>
|
||||||
|
*/
|
||||||
|
export class VanillaErrorReporter implements ErrorReporterContract {
|
||||||
|
private messages;
|
||||||
|
// private bail;
|
||||||
|
/**
|
||||||
|
* Boolean to know one or more errors have been reported
|
||||||
|
*/
|
||||||
|
hasErrors: boolean = false;
|
||||||
|
/**
|
||||||
|
* Collection of errors
|
||||||
|
*/
|
||||||
|
// errors: SimpleError[] = [];
|
||||||
|
errors = {};
|
||||||
|
/**
|
||||||
|
* Report an error.
|
||||||
|
*/
|
||||||
|
|
||||||
|
// constructor(messages: MessagesBagContract) {
|
||||||
|
// this.messages = messages;
|
||||||
|
// }
|
||||||
|
|
||||||
|
report(message: string, rule: string, field: FieldContext, meta?: Record<string, any> | undefined): void {
|
||||||
|
// const error: SimpleError = {
|
||||||
|
// message,
|
||||||
|
// rule,
|
||||||
|
// field: field.getFieldPath()
|
||||||
|
// };
|
||||||
|
// if (meta) {
|
||||||
|
// error.meta = meta;
|
||||||
|
// }
|
||||||
|
// if (field.isArrayMember) {
|
||||||
|
// error.index = field.name as number;
|
||||||
|
// }
|
||||||
|
// this.errors.push(error);
|
||||||
|
this.hasErrors = true;
|
||||||
|
const error = {
|
||||||
|
message,
|
||||||
|
rule,
|
||||||
|
field: field.getFieldPath(),
|
||||||
|
};
|
||||||
|
// field: 'titles.0.value'
|
||||||
|
// message: 'Main Title is required'
|
||||||
|
// rule: 'required' "required"
|
||||||
|
if (meta) {
|
||||||
|
error.meta = meta;
|
||||||
|
}
|
||||||
|
// if (field.isArrayMember) {
|
||||||
|
// error.index = field.name;
|
||||||
|
// }
|
||||||
|
this.hasErrors = true;
|
||||||
|
// this.errors.push(error);
|
||||||
|
if (this.errors[error.field]) {
|
||||||
|
this.errors[error.field]?.push(message);
|
||||||
|
} else {
|
||||||
|
this.errors[error.field] = [message];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Collecting errors as per the JSONAPI spec
|
||||||
|
*/
|
||||||
|
// this.errors.push({
|
||||||
|
// code: rule,
|
||||||
|
// detail: message,
|
||||||
|
// source: {
|
||||||
|
// pointer: field.wildCardPath,
|
||||||
|
// },
|
||||||
|
// ...(meta ? { meta } : {}),
|
||||||
|
// });
|
||||||
|
|
||||||
|
// let pointer: string = field.wildCardPath as string; //'display_name'
|
||||||
|
// // if (field.isArrayMember) {
|
||||||
|
// // this.errors[pointer] = field.name;
|
||||||
|
// // }
|
||||||
|
// this.errors[pointer] = this.errors[pointer] || [];
|
||||||
|
// // this.errors[pointer].push(message);
|
||||||
|
// this.errors[pointer].push(this.messages.get(pointer, rule, message, arrayExpressionPointer, args));
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Returns an instance of the validation error
|
||||||
|
*/
|
||||||
|
createError() {
|
||||||
|
return new errors.E_VALIDATION_ERROR(this.errors);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
export {};
|
970
package-lock.json
generated
970
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
|
@ -37,7 +37,7 @@
|
||||||
"@mdi/js": "^7.1.96",
|
"@mdi/js": "^7.1.96",
|
||||||
"@poppinss/utils": "^6.7.2",
|
"@poppinss/utils": "^6.7.2",
|
||||||
"@swc/core": "^1.4.2",
|
"@swc/core": "^1.4.2",
|
||||||
"@symfony/webpack-encore": "^4.5.0",
|
"@symfony/webpack-encore": "^4.6.1",
|
||||||
"@tailwindcss/forms": "^0.5.2",
|
"@tailwindcss/forms": "^0.5.2",
|
||||||
"@types/bcryptjs": "^2.4.6",
|
"@types/bcryptjs": "^2.4.6",
|
||||||
"@types/clamscan": "^2.0.4",
|
"@types/clamscan": "^2.0.4",
|
||||||
|
@ -53,15 +53,14 @@
|
||||||
"babel-preset-typescript-vue3": "^2.0.17",
|
"babel-preset-typescript-vue3": "^2.0.17",
|
||||||
"chart.js": "^4.2.0",
|
"chart.js": "^4.2.0",
|
||||||
"dotenv-webpack": "^8.0.1",
|
"dotenv-webpack": "^8.0.1",
|
||||||
"eslint": "^8.32.0",
|
"eslint": "^8.57.0",
|
||||||
"eslint-config-prettier": "^9.0.0",
|
"eslint-config-prettier": "^9.0.0",
|
||||||
"eslint-plugin-adonis": "^2.1.1",
|
"eslint-plugin-adonis": "^2.1.1",
|
||||||
"eslint-plugin-prettier": "^5.0.0-alpha.2",
|
"eslint-plugin-prettier": "^5.0.0-alpha.2",
|
||||||
"naive-ui": "^2.35.0",
|
|
||||||
"numeral": "^2.0.6",
|
"numeral": "^2.0.6",
|
||||||
"pinia": "^2.0.30",
|
"pinia": "^2.0.30",
|
||||||
"pino-pretty": "^11.0.0",
|
"pino-pretty": "^11.0.0",
|
||||||
"postcss-loader": "^7.3.0",
|
"postcss-loader": "^7.3.4",
|
||||||
"prettier": "^3.0.0",
|
"prettier": "^3.0.0",
|
||||||
"supertest": "^6.3.3",
|
"supertest": "^6.3.3",
|
||||||
"tailwindcss": "^3.2.4",
|
"tailwindcss": "^3.2.4",
|
||||||
|
@ -85,7 +84,6 @@
|
||||||
"@adonisjs/session": "^7.1.1",
|
"@adonisjs/session": "^7.1.1",
|
||||||
"@adonisjs/shield": "^8.1.1",
|
"@adonisjs/shield": "^8.1.1",
|
||||||
"@adonisjs/static": "^1.1.1",
|
"@adonisjs/static": "^1.1.1",
|
||||||
"@adonisjs/validator": "^13.0.2",
|
|
||||||
"@eidellev/adonis-stardust": "^3.0.0",
|
"@eidellev/adonis-stardust": "^3.0.0",
|
||||||
"@fontsource/archivo-black": "^5.0.1",
|
"@fontsource/archivo-black": "^5.0.1",
|
||||||
"@fontsource/inter": "^5.0.1",
|
"@fontsource/inter": "^5.0.1",
|
||||||
|
@ -93,6 +91,7 @@
|
||||||
"@inertiajs/vue3": "^1.0.0",
|
"@inertiajs/vue3": "^1.0.0",
|
||||||
"@opensearch-project/opensearch": "^2.4.0",
|
"@opensearch-project/opensearch": "^2.4.0",
|
||||||
"@phc/format": "^1.0.0",
|
"@phc/format": "^1.0.0",
|
||||||
|
"@vinejs/vine": "^2.0.0",
|
||||||
"bcrypt": "^5.1.1",
|
"bcrypt": "^5.1.1",
|
||||||
"bcryptjs": "^2.4.3",
|
"bcryptjs": "^2.4.3",
|
||||||
"clamscan": "^2.1.2",
|
"clamscan": "^2.1.2",
|
||||||
|
|
|
@ -88,6 +88,10 @@ const submit = async () => {
|
||||||
<FormField label="Permissions" wrap-body>
|
<FormField label="Permissions" wrap-body>
|
||||||
<FormCheckRadioGroup v-model="form.permissions" name="permissions" is-column :options="props.permissions" />
|
<FormCheckRadioGroup v-model="form.permissions" name="permissions" is-column :options="props.permissions" />
|
||||||
</FormField>
|
</FormField>
|
||||||
|
<div class="text-red-400 text-sm" v-if="form.errors.permissions && Array.isArray(form.errors.permissions)">
|
||||||
|
<!-- {{ errors.password_confirmation }} -->
|
||||||
|
{{ form.errors.permissions.join(', ') }}
|
||||||
|
</div>
|
||||||
|
|
||||||
<template #footer>
|
<template #footer>
|
||||||
<BaseButtons>
|
<BaseButtons>
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
// import { Head, Link, useForm, usePage } from '@inertiajs/inertia-vue3';
|
// import { Head, Link, useForm, usePage } from '@inertiajs/inertia-vue3';
|
||||||
import { Head, Link, useForm, usePage } from '@inertiajs/vue3';
|
import { Head, Link, useForm, usePage } from '@inertiajs/vue3';
|
||||||
import { ComputedRef } from 'vue';
|
import { ComputedRef } from 'vue';
|
||||||
import { mdiAccountKey, mdiPlus, mdiSquareEditOutline, mdiAlertBoxOutline } from '@mdi/js';
|
import { mdiAccountKey, mdiPlus, mdiSquareEditOutline, mdiAlertBoxOutline, mdiTrashCan } from '@mdi/js';
|
||||||
import { computed } from 'vue';
|
import { computed } from 'vue';
|
||||||
import LayoutAuthenticated from '@/Layouts/LayoutAuthenticated.vue';
|
import LayoutAuthenticated from '@/Layouts/LayoutAuthenticated.vue';
|
||||||
import SectionMain from '@/Components/SectionMain.vue';
|
import SectionMain from '@/Components/SectionMain.vue';
|
||||||
|
@ -49,13 +49,13 @@ const form = useForm({
|
||||||
search: props.filters.search,
|
search: props.filters.search,
|
||||||
});
|
});
|
||||||
|
|
||||||
// const formDelete = useForm({});
|
const formDelete = useForm({});
|
||||||
// async function destroy(id) {
|
// async function destroy(id) {
|
||||||
// const destroy = async (id) => {
|
const destroy = async (id: number) => {
|
||||||
// if (confirm('Are you sure you want to delete?')) {
|
if (confirm('Are you sure you want to delete?')) {
|
||||||
// await formDelete.delete(stardust.route('settings.user.destroy', [id]));
|
await formDelete.delete(stardust.route('settings.user.destroy', [id]));
|
||||||
// }
|
}
|
||||||
// };
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
@ -131,7 +131,7 @@ const form = useForm({
|
||||||
:icon="mdiSquareEditOutline"
|
:icon="mdiSquareEditOutline"
|
||||||
small
|
small
|
||||||
/>
|
/>
|
||||||
<!-- <BaseButton v-if="can.delete" color="danger" :icon="mdiTrashCan" small @click="destroy(user.id)" /> -->
|
<BaseButton v-if="can.delete" color="danger" :icon="mdiTrashCan" small @click="destroy(user.id)" />
|
||||||
</BaseButtons>
|
</BaseButtons>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
|
|
@ -24,7 +24,8 @@ import router from '@adonisjs/core/services/router';
|
||||||
import type { HttpContext } from '@adonisjs/core/http';
|
import type { HttpContext } from '@adonisjs/core/http';
|
||||||
|
|
||||||
// import Inertia from '@ioc:EidelLev/Inertia';
|
// import Inertia from '@ioc:EidelLev/Inertia';
|
||||||
import AuthValidator from '#validators/auth_validator';
|
// import AuthValidator from '#validators/auth_validator';
|
||||||
|
import { authValidator } from '#validators/auth';
|
||||||
// import HealthCheck from '@ioc:Adonis/Core/HealthCheck';
|
// import HealthCheck from '@ioc:Adonis/Core/HealthCheck';
|
||||||
import User from '#models/user';
|
import User from '#models/user';
|
||||||
import AuthController from '#controllers/Http/Auth/AuthController';
|
import AuthController from '#controllers/Http/Auth/AuthController';
|
||||||
|
@ -101,7 +102,7 @@ router.group(() => {
|
||||||
registerBody: request.body(),
|
registerBody: request.body(),
|
||||||
});
|
});
|
||||||
|
|
||||||
const data = await request.validate(AuthValidator);
|
const data = await request.validateUsing(authValidator);
|
||||||
console.log({ data });
|
console.log({ data });
|
||||||
|
|
||||||
return response.redirect().toRoute('app.index');
|
return response.redirect().toRoute('app.index');
|
||||||
|
@ -140,10 +141,10 @@ router.group(() => {
|
||||||
.as('user.update')
|
.as('user.update')
|
||||||
.where('id', router.matchers.number())
|
.where('id', router.matchers.number())
|
||||||
.use(middleware.can(['user-edit']));
|
.use(middleware.can(['user-edit']));
|
||||||
// // Route.delete('/user/:id', [AdminuserController, 'destroy'])
|
router.delete('/user/:id', [AdminuserController, 'destroy'])
|
||||||
// // .as('user.destroy')
|
.as('user.destroy')
|
||||||
// // .where('id', Route.matchers.number())
|
.where('id', router.matchers.number())
|
||||||
// // .use(middleware.can(['user-delete']));
|
.use(middleware.can(['user-delete']));
|
||||||
// // Route.resource('user', 'AdminuserController');
|
// // Route.resource('user', 'AdminuserController');
|
||||||
|
|
||||||
router.get('/role', [RoleController, 'index']).as('role.index').use(middleware.can(['user-list']));
|
router.get('/role', [RoleController, 'index']).as('role.index').use(middleware.can(['user-list']));
|
||||||
|
|
48
start/rules/translated_language.ts
Normal file
48
start/rules/translated_language.ts
Normal file
|
@ -0,0 +1,48 @@
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Preloaded File - node ace make:preload rules/translatedLanguage
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|*/
|
||||||
|
|
||||||
|
import { FieldContext } from '@vinejs/vine/types';
|
||||||
|
import vine from '@vinejs/vine';
|
||||||
|
import { VineString } from '@vinejs/vine';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Options accepted by the unique rule
|
||||||
|
*/
|
||||||
|
type Options = {
|
||||||
|
mainLanguageField: string;
|
||||||
|
typeField: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
async function translatedLanguage(value: unknown, options: Options, field: FieldContext) {
|
||||||
|
if (typeof value !== 'string' && typeof value != 'number') {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// const type = validator.helpers.getFieldValue(typeField, root, tip); //'type' = 'Translated'
|
||||||
|
const typeValue = vine.helpers.getNestedValue(options.typeField, field); //'Main' or 'Translated'
|
||||||
|
|
||||||
|
// const mainLanguage = validator.helpers.getFieldValue(mainLanguageField, root, tip);
|
||||||
|
const mainLanguage = field.data[options.mainLanguageField]; // 'en' or 'de'
|
||||||
|
|
||||||
|
if (typeValue === 'Translated') {
|
||||||
|
if (value === mainLanguage) {
|
||||||
|
// report thattranlated language field is same as main language field of dataset
|
||||||
|
field.report('The tranlated {{ field }} hast the same language seted as dataset language', 'translatedLanguage', field);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const translatedLanguageRule = vine.createRule(translatedLanguage);
|
||||||
|
|
||||||
|
declare module '@vinejs/vine' {
|
||||||
|
interface VineString {
|
||||||
|
translatedLanguage(options: Options): this;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
VineString.macro('translatedLanguage', function (this: VineString, options: Options) {
|
||||||
|
return this.use(translatedLanguageRule(options));
|
||||||
|
});
|
60
start/rules/unique.ts
Normal file
60
start/rules/unique.ts
Normal file
|
@ -0,0 +1,60 @@
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Preloaded File - node ace make:preload rules/unique
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|*/
|
||||||
|
|
||||||
|
import { FieldContext } from '@vinejs/vine/types';
|
||||||
|
import db from '@adonisjs/lucid/services/db';
|
||||||
|
import vine from '@vinejs/vine';
|
||||||
|
import { VineString, VineNumber } from '@vinejs/vine';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Options accepted by the unique rule
|
||||||
|
*/
|
||||||
|
type Options = {
|
||||||
|
table: string;
|
||||||
|
column: string;
|
||||||
|
whereNot?: ((field: FieldContext) => string);
|
||||||
|
};
|
||||||
|
|
||||||
|
async function isUnique(value: unknown, options: Options, field: FieldContext) {
|
||||||
|
if (typeof value !== 'string' && typeof value != 'number') {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let ignoreId: string | undefined;
|
||||||
|
if (options.whereNot) {
|
||||||
|
ignoreId = options.whereNot(field);
|
||||||
|
}
|
||||||
|
|
||||||
|
const builder = db.from(options.table).select(options.column).where(options.column, value);
|
||||||
|
if (ignoreId) {
|
||||||
|
builder.whereNot('id', '=', ignoreId);
|
||||||
|
}
|
||||||
|
const result = await builder.first();
|
||||||
|
if (result) {
|
||||||
|
// report that value is NOT unique
|
||||||
|
field.report('The {{ field }} field is not unique', 'isUnique', field);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const isUniqueRule = vine.createRule(isUnique);
|
||||||
|
|
||||||
|
|
||||||
|
declare module '@vinejs/vine' {
|
||||||
|
interface VineString {
|
||||||
|
isUnique(options: Options): this;
|
||||||
|
}
|
||||||
|
interface VineNumber {
|
||||||
|
isUnique(options: Options): this;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
VineString.macro('isUnique', function (this: VineString, options: Options) {
|
||||||
|
return this.use(isUniqueRule(options));
|
||||||
|
});
|
||||||
|
VineNumber.macro('isUnique', function (this: VineNumber, options: Options) {
|
||||||
|
return this.use(isUniqueRule(options));
|
||||||
|
});
|
|
@ -1,6 +1,6 @@
|
||||||
/*
|
/*
|
||||||
|--------------------------------------------------------------------------
|
|--------------------------------------------------------------------------
|
||||||
| Preloaded File
|
| Preloaded File - node ace make:preload validator
|
||||||
|--------------------------------------------------------------------------
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
|
||||||
| Any code written inside this file will be executed during the application
|
| Any code written inside this file will be executed during the application
|
||||||
|
@ -8,133 +8,71 @@
|
||||||
https://issuehunt.io/r/adonisjs/validator/issues/84
|
https://issuehunt.io/r/adonisjs/validator/issues/84
|
||||||
|
|
|
|
||||||
*/
|
*/
|
||||||
// import { string } from '@ioc:Adonis/Core/Helpers';
|
import vine from '@vinejs/vine';
|
||||||
import { validator } from '@adonisjs/validator';
|
// import { FieldContext } from '@vinejs/vine/types';
|
||||||
|
// import db from '@adonisjs/lucid/services/db';
|
||||||
|
import { VanillaErrorReporter } from '#validators/vanilla_error_reporter';
|
||||||
|
// import { SimpleErrorReporter } from '@vinejs/vine';
|
||||||
|
|
||||||
validator.rule('uniqueArray', (dataArray, [field], { pointer, arrayExpressionPointer, errorReporter }) => {
|
|
||||||
const array = dataArray; //validator.helpers.getFieldValue(data, field, tip);
|
|
||||||
|
|
||||||
if (!Array.isArray(array)) {
|
|
||||||
throw new Error(`The ${pointer} must be an array.`);
|
|
||||||
}
|
|
||||||
|
|
||||||
const uniqueValues = new Set();
|
// vine.messagesProvider = new SimpleMessagesProvider({
|
||||||
for (let i = 0; i < array.length; i++) {
|
// // Applicable for all fields
|
||||||
const item = array[i];
|
// 'required': 'The {{ field }} field is required',
|
||||||
const attributeValue = item[field]; // Extract the attribute value for uniqueness check
|
// 'string': 'The value of {{ field }} field must be a string',
|
||||||
|
// 'email': 'The value is not a valid email address',
|
||||||
|
|
||||||
|
// // 'contacts.0.email.required': 'The primary email of the contact is required',
|
||||||
|
// // 'contacts.*.email.required': 'Contact email is required',
|
||||||
|
// 'permissions.minLength': 'at least {{ options.minLength }} permission must be defined',
|
||||||
|
// 'permissions.*.number': 'Define permissions as valid numbers',
|
||||||
|
// })
|
||||||
|
vine.errorReporter = () => new VanillaErrorReporter();
|
||||||
|
|
||||||
|
|
||||||
if (uniqueValues.has(attributeValue)) {
|
// /**
|
||||||
// throw new Error(`The ${field} array contains duplicate values for the ${field} attribute.`)
|
// * Options accepted by the unique rule
|
||||||
errorReporter.report(
|
// */
|
||||||
pointer,
|
// type Options = {
|
||||||
'uniqueArray', // Keep an eye on this
|
// table: string;
|
||||||
`The ${pointer} array contains duplicate values for the ${field} attribute.`,
|
// column: string;
|
||||||
arrayExpressionPointer,
|
// };
|
||||||
{ field, array: pointer },
|
|
||||||
);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
uniqueValues.add(attributeValue);
|
// /**
|
||||||
}
|
// * Implementation
|
||||||
});
|
// */
|
||||||
|
// async function unique(value: unknown, options: Options, field: FieldContext) {
|
||||||
|
// /**
|
||||||
|
// * We do not want to deal with non-string
|
||||||
|
// * values. The "string" rule will handle the
|
||||||
|
// * the validation.
|
||||||
|
// */
|
||||||
|
// if (typeof value !== 'string') {
|
||||||
|
// return;
|
||||||
|
// }
|
||||||
|
|
||||||
validator.rule(
|
// const builder = await db
|
||||||
'translatedLanguage',
|
// .from(options.table)
|
||||||
(value, [mainLanguageField, typeField], { root, tip, pointer, arrayExpressionPointer, errorReporter }) => {
|
// .select(options.column)
|
||||||
if (typeof value !== 'string') {
|
// .where(options.column, value).first();
|
||||||
return;
|
// const row = await builder.first();
|
||||||
}
|
|
||||||
// const fieldValue = validator. getValue(data, field)
|
|
||||||
// this should return the "category_id" value present in "root", but i got undefined
|
|
||||||
const mainLanguage = validator.helpers.getFieldValue(mainLanguageField, root, tip);
|
|
||||||
const type = validator.helpers.getFieldValue(typeField, root, tip);
|
|
||||||
|
|
||||||
if (type && type === 'Translated') {
|
// if (row) {
|
||||||
if (value === mainLanguage) {
|
// field.report('The {{ field }} field is not unique', 'unique', field);
|
||||||
errorReporter.report(
|
// }
|
||||||
pointer,
|
// }
|
||||||
'translatedLanguage', // Keep an eye on this
|
|
||||||
'translatedLanguage validation failed',
|
|
||||||
arrayExpressionPointer,
|
|
||||||
{ mainLanguage },
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// if (value !== string.camelCase(value)) {
|
// /**
|
||||||
// options.errorReporter.report(
|
// * Converting a function to a VineJS rule
|
||||||
// options.pointer,
|
// */
|
||||||
// 'camelCase',
|
// export const uniqueRule = vine.createRule(unique);
|
||||||
// 'camelCase validation failed',
|
|
||||||
// options.arrayExpressionPointer
|
|
||||||
// );
|
|
||||||
// }
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
validator.rule('fileExtension', async (value, [extensions], { pointer, arrayExpressionPointer, errorReporter }) => {
|
// VineString.macro('unique', function (this: VineString, options: Options) {
|
||||||
const allowedExtensions = extensions.map((ext: string) => ext.toLowerCase());
|
// return this.use(uniqueRule(options));
|
||||||
const uploadedFile = value;
|
|
||||||
|
|
||||||
if (!uploadedFile) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const extension = uploadedFile.extname.toLowerCase().replace('.', '');
|
|
||||||
|
|
||||||
if (!allowedExtensions.includes(extension)) {
|
|
||||||
errorReporter.report(
|
|
||||||
pointer,
|
|
||||||
'fileExtension',
|
|
||||||
'Invalid file extension. Only {{ extensions }} files are allowed.',
|
|
||||||
arrayExpressionPointer,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// validator.rule(
|
|
||||||
// 'clamavScan',
|
|
||||||
// (value, [field], { root, tip, pointer, arrayExpressionPointer, errorReporter }) => {
|
|
||||||
// if (typeof value !== 'object') {
|
|
||||||
// return;
|
|
||||||
// }
|
|
||||||
// const uploadedFile = validator.helpers.getFieldValue(field, root, tip);
|
|
||||||
// // return rules.file({}, [
|
|
||||||
// // async (file) => {
|
|
||||||
// // const clamdhost = process.env['CLAMD_HOST'] ?? '127.0.0.1';
|
|
||||||
// // const clamdport = Number(process.env['CLAMD_PORT']) ?? '3310';
|
|
||||||
// // try {
|
|
||||||
// // var isInfected = await scanFileForViruses(file.tmpPath, clamdhost, clamdport);
|
|
||||||
// // } catch (error) {
|
|
||||||
// // throw new Error(`${pointer}: ${error.message}`);
|
|
||||||
// // }
|
|
||||||
// // },
|
|
||||||
// // ]);
|
|
||||||
// });
|
// });
|
||||||
|
|
||||||
// async function scanFileForViruses(filePath, host, port): Promise<boolean> {
|
// // declare module '@vinejs/vine' {
|
||||||
// // const clamscan = await (new ClamScan().init());
|
// // interface VineString {
|
||||||
// const opts: ClamScan.Options = {
|
// // unique(options: Options): this;
|
||||||
// preference: 'clamdscan',
|
// // }
|
||||||
// clamdscan: {
|
// // }
|
||||||
// active: true,
|
|
||||||
// host,
|
|
||||||
// port,
|
|
||||||
// multiscan: true,
|
|
||||||
// },
|
|
||||||
// };
|
|
||||||
// const clamscan = await new ClamScan().init(opts);
|
|
||||||
|
|
||||||
// return new Promise((resolve, reject) => {
|
|
||||||
// clamscan.isInfected(filePath, (err, file, isInfected: boolean) => {
|
|
||||||
// if (err) {
|
|
||||||
// reject(err);
|
|
||||||
// } else if (isInfected) {
|
|
||||||
// reject(new Error(`File ${file} is infected!`));
|
|
||||||
// } else {
|
|
||||||
// resolve(isInfected);
|
|
||||||
// }
|
|
||||||
// });
|
|
||||||
// });
|
|
||||||
// }
|
|
||||||
|
|
140
start/validator_old.ts
Normal file
140
start/validator_old.ts
Normal file
|
@ -0,0 +1,140 @@
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Preloaded File
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| Any code written inside this file will be executed during the application
|
||||||
|
| boot.
|
||||||
|
https://issuehunt.io/r/adonisjs/validator/issues/84
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
// import { string } from '@ioc:Adonis/Core/Helpers';
|
||||||
|
import { validator } from '@adonisjs/validator';
|
||||||
|
|
||||||
|
validator.rule('uniqueArray', (dataArray, [field], { pointer, arrayExpressionPointer, errorReporter }) => {
|
||||||
|
const array = dataArray; //validator.helpers.getFieldValue(data, field, tip);
|
||||||
|
|
||||||
|
if (!Array.isArray(array)) {
|
||||||
|
throw new Error(`The ${pointer} must be an array.`);
|
||||||
|
}
|
||||||
|
|
||||||
|
const uniqueValues = new Set();
|
||||||
|
for (let i = 0; i < array.length; i++) {
|
||||||
|
const item = array[i];
|
||||||
|
const attributeValue = item[field]; // Extract the attribute value for uniqueness check
|
||||||
|
|
||||||
|
if (uniqueValues.has(attributeValue)) {
|
||||||
|
// throw new Error(`The ${field} array contains duplicate values for the ${field} attribute.`)
|
||||||
|
errorReporter.report(
|
||||||
|
pointer,
|
||||||
|
'uniqueArray', // Keep an eye on this
|
||||||
|
`The ${pointer} array contains duplicate values for the ${field} attribute.`,
|
||||||
|
arrayExpressionPointer,
|
||||||
|
{ field, array: pointer },
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
uniqueValues.add(attributeValue);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
validator.rule(
|
||||||
|
'translatedLanguage',
|
||||||
|
(value, [mainLanguageField, typeField], { root, tip, pointer, arrayExpressionPointer, errorReporter }) => {
|
||||||
|
if (typeof value !== 'string') {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// const fieldValue = validator. getValue(data, field)
|
||||||
|
// this should return the "category_id" value present in "root", but i got undefined
|
||||||
|
const mainLanguage = validator.helpers.getFieldValue(mainLanguageField, root, tip);
|
||||||
|
const type = validator.helpers.getFieldValue(typeField, root, tip);
|
||||||
|
|
||||||
|
if (type && type === 'Translated') {
|
||||||
|
if (value === mainLanguage) {
|
||||||
|
errorReporter.report(
|
||||||
|
pointer,
|
||||||
|
'translatedLanguage', // Keep an eye on this
|
||||||
|
'translatedLanguage validation failed',
|
||||||
|
arrayExpressionPointer,
|
||||||
|
{ mainLanguage },
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// if (value !== string.camelCase(value)) {
|
||||||
|
// options.errorReporter.report(
|
||||||
|
// options.pointer,
|
||||||
|
// 'camelCase',
|
||||||
|
// 'camelCase validation failed',
|
||||||
|
// options.arrayExpressionPointer
|
||||||
|
// );
|
||||||
|
// }
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
validator.rule('fileExtension', async (value, [extensions], { pointer, arrayExpressionPointer, errorReporter }) => {
|
||||||
|
const allowedExtensions = extensions.map((ext: string) => ext.toLowerCase());
|
||||||
|
const uploadedFile = value;
|
||||||
|
|
||||||
|
if (!uploadedFile) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const extension = uploadedFile.extname.toLowerCase().replace('.', '');
|
||||||
|
|
||||||
|
if (!allowedExtensions.includes(extension)) {
|
||||||
|
errorReporter.report(
|
||||||
|
pointer,
|
||||||
|
'fileExtension',
|
||||||
|
'Invalid file extension. Only {{ extensions }} files are allowed.',
|
||||||
|
arrayExpressionPointer,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// validator.rule(
|
||||||
|
// 'clamavScan',
|
||||||
|
// (value, [field], { root, tip, pointer, arrayExpressionPointer, errorReporter }) => {
|
||||||
|
// if (typeof value !== 'object') {
|
||||||
|
// return;
|
||||||
|
// }
|
||||||
|
// const uploadedFile = validator.helpers.getFieldValue(field, root, tip);
|
||||||
|
// // return rules.file({}, [
|
||||||
|
// // async (file) => {
|
||||||
|
// // const clamdhost = process.env['CLAMD_HOST'] ?? '127.0.0.1';
|
||||||
|
// // const clamdport = Number(process.env['CLAMD_PORT']) ?? '3310';
|
||||||
|
// // try {
|
||||||
|
// // var isInfected = await scanFileForViruses(file.tmpPath, clamdhost, clamdport);
|
||||||
|
// // } catch (error) {
|
||||||
|
// // throw new Error(`${pointer}: ${error.message}`);
|
||||||
|
// // }
|
||||||
|
// // },
|
||||||
|
// // ]);
|
||||||
|
// });
|
||||||
|
|
||||||
|
// async function scanFileForViruses(filePath, host, port): Promise<boolean> {
|
||||||
|
// // const clamscan = await (new ClamScan().init());
|
||||||
|
// const opts: ClamScan.Options = {
|
||||||
|
// preference: 'clamdscan',
|
||||||
|
// clamdscan: {
|
||||||
|
// active: true,
|
||||||
|
// host,
|
||||||
|
// port,
|
||||||
|
// multiscan: true,
|
||||||
|
// },
|
||||||
|
// };
|
||||||
|
// const clamscan = await new ClamScan().init(opts);
|
||||||
|
|
||||||
|
// return new Promise((resolve, reject) => {
|
||||||
|
// clamscan.isInfected(filePath, (err, file, isInfected: boolean) => {
|
||||||
|
// if (err) {
|
||||||
|
// reject(err);
|
||||||
|
// } else if (isInfected) {
|
||||||
|
// reject(new Error(`File ${file} is infected!`));
|
||||||
|
// } else {
|
||||||
|
// resolve(isInfected);
|
||||||
|
// }
|
||||||
|
// });
|
||||||
|
// });
|
||||||
|
// }
|
|
@ -73,7 +73,7 @@
|
||||||
},
|
},
|
||||||
"types": [
|
"types": [
|
||||||
// "@eidellev/inertia-adonisjs",
|
// "@eidellev/inertia-adonisjs",
|
||||||
"naive-ui/volar"
|
// "naive-ui/volar"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user