forked from geolba/tethys.backend
Arno Kaimbacher
49bd96ee77
- **AdminuserController.ts**: enable editing `first_name` and `last_name` for user creation and updates - **MimetypeController.ts**: add creation support for mimetypes with selectable extensions - **Models**: add `Mimetype` model (mime_type.ts); add `SnakeCaseNamingStrategy` for User model - **Validators**: - **updateDatasetValidator**: increase title length to 255 and description length to 2500 - **User Validators**: refine `createUserValidator` and `updateUserValidator` to include `first_name` and `last_name` - **vanilla_error_reporter**: improve error reporting for wildcard fields - **SKOS Query**: refine keyword request in `SearchCategoryAutocomplete.vue` - **UI Enhancements**: - improve icon design in wizard (Wizard.vue) - add components for mimetype creation (Create.vue and button in Index.vue) - **Routes**: update `routes.ts` to include new AdonisJS routes
342 lines
15 KiB
TypeScript
342 lines
15 KiB
TypeScript
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(2500),
|
|
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()
|
|
.isUniquePerson({ table: 'persons', column: 'email', idField: 'id' }),
|
|
first_name: vine.string().trim().minLength(3).maxLength(255),
|
|
last_name: vine.string().trim().minLength(3).maxLength(255),
|
|
}),
|
|
)
|
|
.minLength(1)
|
|
.distinct('email'),
|
|
contributors: vine
|
|
.array(
|
|
vine.object({
|
|
email: vine
|
|
.string()
|
|
.trim()
|
|
.maxLength(255)
|
|
.email()
|
|
.normalizeEmail()
|
|
.isUniquePerson({ table: 'persons', column: 'email', idField: 'id' }),
|
|
first_name: vine.string().trim().minLength(3).maxLength(255),
|
|
last_name: vine.string().trim().minLength(3).maxLength(255),
|
|
pivot_contributor_type: vine.enum(Object.keys(ContributorTypes)),
|
|
}),
|
|
)
|
|
.distinct('email')
|
|
.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().positive().optional(),
|
|
elevation_min: vine.number().positive().optional().requiredIfExists('elevation_max'),
|
|
elevation_max: vine.number().positive().optional().requiredIfExists('elevation_min'),
|
|
// type: vine.enum(Object.values(DescriptionTypes)),
|
|
depth_absolut: vine.number().negative().optional(),
|
|
depth_min: vine.number().negative().optional().requiredIfExists('depth_max'),
|
|
depth_max: vine.number().negative().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
|
|
.myfile({
|
|
size: '512mb',
|
|
extnames: extensions,
|
|
})
|
|
.filenameLength({ clientNameSizeLimit: 100 })
|
|
.fileScan({ removeInfected: true }),
|
|
)
|
|
.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(2500),
|
|
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()
|
|
.isUniquePerson({ table: 'persons', column: 'email', idField: 'id' }),
|
|
first_name: vine.string().trim().minLength(3).maxLength(255),
|
|
last_name: vine.string().trim().minLength(3).maxLength(255),
|
|
}),
|
|
)
|
|
.minLength(1)
|
|
.distinct('email'),
|
|
contributors: vine
|
|
.array(
|
|
vine.object({
|
|
email: vine
|
|
.string()
|
|
.trim()
|
|
.maxLength(255)
|
|
.email()
|
|
.normalizeEmail()
|
|
.isUniquePerson({ table: 'persons', column: 'email', idField: 'id' }),
|
|
first_name: vine.string().trim().minLength(3).maxLength(255),
|
|
last_name: vine.string().trim().minLength(3).maxLength(255),
|
|
pivot_contributor_type: vine.enum(Object.keys(ContributorTypes)),
|
|
}),
|
|
)
|
|
.distinct('email')
|
|
.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().positive().optional(),
|
|
elevation_min: vine.number().positive().optional().requiredIfExists('elevation_max'),
|
|
elevation_max: vine.number().positive().optional().requiredIfExists('elevation_min'),
|
|
// type: vine.enum(Object.values(DescriptionTypes)),
|
|
depth_absolut: vine.number().negative().optional(),
|
|
depth_min: vine.number().negative().optional().requiredIfExists('depth_max'),
|
|
depth_max: vine.number().negative().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.myfile({
|
|
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.maxLength': 'Main Title must be less than {{ max }} 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.maxLength': 'Main Abstract must be less than {{ max }} 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',
|
|
'authors.distinct': 'The {{ field }} array must have unique values based on the {{ fields }} attribute.',
|
|
'authors.*.email.isUnique': 'the email of the new creator already exists in the database',
|
|
'contributors.*.pivot_contributor_type.required': 'contributor type is required, if defined',
|
|
'contributors.distinct': 'The {{ field }} array must have unique values based on the {{ fields }} attribute.',
|
|
|
|
'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;
|