Compare commits
7 commits
master
...
feat/check
Author | SHA1 | Date | |
---|---|---|---|
a41b091214 | |||
a3031169ca | |||
4c5a8f5a42 | |||
8d47a58d29 | |||
a5e0a36327 | |||
c0496be51b | |||
2c4f51be68 |
77 changed files with 3493 additions and 9364 deletions
|
@ -17,4 +17,6 @@ REDIS_PORT=6379
|
|||
REDIS_PASSWORD=
|
||||
SMTP_HOST=
|
||||
SMTP_PORT=
|
||||
RESEND_API_KEY=
|
||||
RESEND_API_KEY=
|
||||
OPENSEARCH_HOST=http://localhost
|
||||
OPENSEARCH_CORE=tethys-records
|
78
.gitea/workflows/checkReferenceType.yaml
Normal file
78
.gitea/workflows/checkReferenceType.yaml
Normal file
|
@ -0,0 +1,78 @@
|
|||
# This is a Gitea Actions workflow configuration file for running CI tests on the `feat/checkReferenceType` branch.
|
||||
# The workflow is named "CI" and runs on the latest Ubuntu environment using a Node.js 20 Docker container.
|
||||
# It sets up a PostgreSQL service with specified environment variables and health checks.
|
||||
# The workflow includes the following steps:
|
||||
# 1. Checkout the repository using the actions/checkout@v3 action.
|
||||
# 2. Install Node.js dependencies using `npm ci`.
|
||||
# 3. Create a `.env.test` file by copying from `.env.example`.
|
||||
# 4. Set up environment variables in the `.env.test` file, including database connection details and other app-specific settings.
|
||||
# 5. Run functional tests using the `node ace test functional --groups "ReferenceValidation"` command.
|
||||
name: CI
|
||||
run-name: Running tests for checkReferenceType branch
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- feat/checkReferenceType
|
||||
|
||||
jobs:
|
||||
container-job:
|
||||
runs-on: ubuntu-latest
|
||||
# Docker Hub image that `container-job` executes in
|
||||
container: node:20-bullseye
|
||||
|
||||
services:
|
||||
# Label used to access the service container
|
||||
postgres:
|
||||
image: postgres:latest
|
||||
env:
|
||||
POSTGRES_USER: alice
|
||||
POSTGRES_PASSWORD: ${{ secrets.POSTGRES_PASSWORD }}
|
||||
POSTGRES_DB: tethys_dev
|
||||
# ports:
|
||||
# - 5432:5432
|
||||
options: |
|
||||
--health-cmd pg_isready
|
||||
--health-interval 10s
|
||||
--health-timeout 5s
|
||||
--health-retries 5
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v3
|
||||
|
||||
# - name: Set up Node.js
|
||||
# uses: actions/setup-node@v2
|
||||
# with:
|
||||
# node-version: '20'
|
||||
|
||||
- name: Install dependencies
|
||||
run: npm ci
|
||||
|
||||
- name: Create .env.test file
|
||||
run: cp .env.example .env.test
|
||||
|
||||
- name: Set up environment variables
|
||||
run: |
|
||||
echo "DB_CONNECTION=pg" >> .env.test
|
||||
echo "PG_HOST=postgres" >> .env.test
|
||||
echo "PG_PORT=5432" >> .env.test
|
||||
echo "PG_USER=alice" >> .env.test
|
||||
echo "PG_PASSWORD=${{ secrets.POSTGRES_PASSWORD }}" >> .env.test
|
||||
echo "PG_DB_NAME=tethys_dev" >> .env.test
|
||||
echo "NODE_ENV=test" >> .env.test
|
||||
echo "ASSETS_DRIVER=fake" >> .env.test
|
||||
echo "SESSION_DRIVER=memory" >> .env.test
|
||||
echo "HASH_DRIVER=bcrypt" >> .env.test
|
||||
echo "HOST=127.0.0.1" >> .env.test
|
||||
echo "PORT=3333" >> .env.test
|
||||
echo "APP_NAME=TethysCloud" >> .env.test
|
||||
echo "APP_URL=http://${HOST}:${PORT}" >> .env.test
|
||||
echo "CACHE_VIEWS=false" >> .env.test
|
||||
echo "APP_KEY=pfi5N2ACN4tMJ5d8d8BPHfh3FEuvleej" >> .env.test
|
||||
echo "DRIVE_DISK=local" >> .env.test
|
||||
echo "OAI_LIST_SIZE=200" >> .env.test
|
||||
echo "OPENSEARCH_HOST=${{ secrets.OPENSEARCH_HOST }}" >> .env.test
|
||||
echo "OPENSEARCH_CORE=tethys-records" >> .env.test
|
||||
|
||||
- name: Run tests
|
||||
run: node ace test functional --groups "ReferenceValidation"
|
|
@ -4,7 +4,13 @@
|
|||
name: CI Pipeline
|
||||
run-name: ${{ github.actor }} is running CI pipeline
|
||||
# trigger build when pushing, or when creating a pull request
|
||||
on: [push, pull_request]
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
pull_request:
|
||||
branches:
|
||||
- master
|
||||
|
||||
jobs:
|
||||
# Label of the container job
|
||||
|
@ -12,7 +18,7 @@ jobs:
|
|||
# run build on latest ubuntu
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
container: node:18-bullseye
|
||||
container: node:20-bullseye
|
||||
|
||||
services:
|
||||
mydb:
|
||||
|
@ -70,6 +76,7 @@ jobs:
|
|||
&& echo "CACHE_VIEWS=false" >> .env.test
|
||||
&& echo "APP_KEY=pfi5N2ACN4tMJ5d8d8BPHfh3FEuvleej" >> .env.test
|
||||
&& echo "DRIVE_DISK=local" >> .env.test
|
||||
&& echo "OAI_LIST_SIZE=200" >> .env.test
|
||||
|
||||
# finally run the tests
|
||||
# - run: npm test
|
||||
|
@ -95,3 +102,4 @@ jobs:
|
|||
# uses: coverallsapp/github-action@master
|
||||
# with:
|
||||
# github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
|
|
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -7,3 +7,4 @@ coverage
|
|||
tmp
|
||||
docker-compose.yml
|
||||
.env.test
|
||||
public/assets
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
################## First Stage - Creating base #########################
|
||||
|
||||
# Created a variable to hold our node base image
|
||||
ARG NODE_IMAGE=node:20-bookworm-slim
|
||||
ARG NODE_IMAGE=node:22-bookworm-slim
|
||||
|
||||
FROM $NODE_IMAGE AS base
|
||||
# Install dumb-init and ClamAV, and perform ClamAV database update
|
||||
|
|
7
ace.js
7
ace.js
|
@ -15,10 +15,11 @@
|
|||
/**
|
||||
* Register hook to process TypeScript files using ts-node
|
||||
*/
|
||||
import { register } from 'node:module'
|
||||
register('ts-node/esm', import.meta.url)
|
||||
// import { register } from 'node:module';
|
||||
// register('ts-node/esm', import.meta.url);
|
||||
import 'ts-node-maintained/register/esm';
|
||||
|
||||
/**
|
||||
* Import ace console entrypoint
|
||||
*/
|
||||
await import('./bin/console.js')
|
||||
await import('./bin/console.js');
|
||||
|
|
167
adonisrc.ts
167
adonisrc.ts
|
@ -1,7 +1,7 @@
|
|||
import { defineConfig } from '@adonisjs/core/app'
|
||||
import { defineConfig } from '@adonisjs/core/app';
|
||||
|
||||
export default defineConfig({
|
||||
/*
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Commands
|
||||
|--------------------------------------------------------------------------
|
||||
|
@ -10,12 +10,11 @@ export default defineConfig({
|
|||
| will be scanned automatically from the "./commands" directory.
|
||||
|
||||
*/
|
||||
commands: [
|
||||
() => import('@adonisjs/core/commands'),
|
||||
() => import('@adonisjs/lucid/commands'),
|
||||
() => import('@adonisjs/mail/commands')
|
||||
],
|
||||
/*
|
||||
commands: [
|
||||
() => import('@adonisjs/core/commands'),
|
||||
() => import('@adonisjs/lucid/commands'),
|
||||
() => import('@adonisjs/mail/commands')],
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Preloads
|
||||
|--------------------------------------------------------------------------
|
||||
|
@ -23,19 +22,21 @@ export default defineConfig({
|
|||
| List of modules to import before starting the application.
|
||||
|
|
||||
*/
|
||||
preloads: [
|
||||
() => import('./start/routes.js'),
|
||||
() => import('./start/kernel.js'),
|
||||
() => import('#start/validator'),
|
||||
() => import('#start/rules/unique'),
|
||||
() => import('#start/rules/translated_language'),
|
||||
() => import('#start/rules/unique_person'),
|
||||
() => import('#start/rules/file_length'),
|
||||
() => import('#start/rules/file_scan'),
|
||||
() => import('#start/rules/allowed_extensions_mimetypes'),
|
||||
() => import('#start/rules/dependent_array_min_length')
|
||||
],
|
||||
/*
|
||||
preloads: [
|
||||
() => import('./start/routes.js'),
|
||||
() => import('./start/kernel.js'),
|
||||
() => import('#start/validator'),
|
||||
() => import('#start/rules/unique'),
|
||||
() => import('#start/rules/translated_language'),
|
||||
() => import('#start/rules/unique_person'),
|
||||
() => import('#start/rules/file_length'),
|
||||
() => import('#start/rules/file_scan'),
|
||||
() => import('#start/rules/allowed_extensions_mimetypes'),
|
||||
() => import('#start/rules/dependent_array_min_length'),
|
||||
() => import('#start/rules/referenceValidation'),
|
||||
() => import('#start/rules/valid_mimetype'),
|
||||
],
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Service providers
|
||||
|--------------------------------------------------------------------------
|
||||
|
@ -44,48 +45,48 @@ export default defineConfig({
|
|||
| application
|
||||
|
|
||||
*/
|
||||
providers: [
|
||||
// () => import('./providers/AppProvider.js'),
|
||||
() => import('@adonisjs/core/providers/app_provider'),
|
||||
() => import('@adonisjs/core/providers/hash_provider'),
|
||||
{
|
||||
file: () => import('@adonisjs/core/providers/repl_provider'),
|
||||
environment: ['repl', 'test'],
|
||||
},
|
||||
() => import('@adonisjs/session/session_provider'),
|
||||
() => import('@adonisjs/core/providers/edge_provider'),
|
||||
() => import('@adonisjs/shield/shield_provider'),
|
||||
// () => import('@eidellev/inertia-adonisjs'),
|
||||
// () => import('@adonisjs/inertia/inertia_provider'),
|
||||
() => import('#providers/app_provider'),
|
||||
() => import('#providers/inertia_provider'),
|
||||
() => import('@adonisjs/lucid/database_provider'),
|
||||
() => import('@adonisjs/auth/auth_provider'),
|
||||
// () => import('@eidellev/adonis-stardust'),
|
||||
() => import('@adonisjs/redis/redis_provider'),
|
||||
() => import('@adonisjs/encore/encore_provider'),
|
||||
() => import('@adonisjs/static/static_provider'),
|
||||
() => import('#providers/stardust_provider'),
|
||||
() => import('#providers/query_builder_provider'),
|
||||
() => import('#providers/token_worker_provider'),
|
||||
// () => import('#providers/validator_provider'),
|
||||
() => import('#providers/drive/provider/drive_provider'),
|
||||
// () => import('@adonisjs/core/providers/vinejs_provider'),
|
||||
() => import('#providers/vinejs_provider'),
|
||||
() => import('@adonisjs/mail/mail_provider')
|
||||
// () => import('#providers/mail_provider'),
|
||||
],
|
||||
metaFiles: [
|
||||
{
|
||||
pattern: 'public/**',
|
||||
reloadServer: false,
|
||||
},
|
||||
{
|
||||
pattern: 'resources/views/**/*.edge',
|
||||
reloadServer: false,
|
||||
},
|
||||
],
|
||||
/*
|
||||
providers: [
|
||||
// () => import('./providers/AppProvider.js'),
|
||||
() => import('@adonisjs/core/providers/app_provider'),
|
||||
() => import('@adonisjs/core/providers/hash_provider'),
|
||||
{
|
||||
file: () => import('@adonisjs/core/providers/repl_provider'),
|
||||
environment: ['repl', 'test'],
|
||||
},
|
||||
() => import('@adonisjs/session/session_provider'),
|
||||
() => import('@adonisjs/core/providers/edge_provider'),
|
||||
() => import('@adonisjs/shield/shield_provider'),
|
||||
// () => import('@eidellev/inertia-adonisjs'),
|
||||
// () => import('@adonisjs/inertia/inertia_provider'),
|
||||
() => import('#providers/app_provider'),
|
||||
() => import('#providers/inertia_provider'),
|
||||
() => import('@adonisjs/lucid/database_provider'),
|
||||
() => import('@adonisjs/auth/auth_provider'),
|
||||
// () => import('@eidellev/adonis-stardust'),
|
||||
() => import('@adonisjs/redis/redis_provider'),
|
||||
// () => import('@adonisjs/encore/encore_provider'),
|
||||
() => import('@adonisjs/static/static_provider'),
|
||||
() => import('#providers/stardust_provider'),
|
||||
() => import('#providers/query_builder_provider'),
|
||||
() => import('#providers/token_worker_provider'),
|
||||
// () => import('#providers/validator_provider'),
|
||||
() => import('#providers/drive/provider/drive_provider'),
|
||||
// () => import('@adonisjs/core/providers/vinejs_provider'),
|
||||
() => import('#providers/vinejs_provider'),
|
||||
() => import('@adonisjs/mail/mail_provider'),
|
||||
() => import('@adonisjs/vite/vite_provider'),
|
||||
],
|
||||
metaFiles: [
|
||||
{
|
||||
pattern: 'public/**',
|
||||
reloadServer: false,
|
||||
},
|
||||
{
|
||||
pattern: 'resources/views/**/*.edge',
|
||||
reloadServer: false,
|
||||
},
|
||||
],
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Tests
|
||||
|--------------------------------------------------------------------------
|
||||
|
@ -94,22 +95,24 @@ export default defineConfig({
|
|||
| and add additional suites.
|
||||
|
|
||||
*/
|
||||
tests: {
|
||||
suites: [
|
||||
{
|
||||
files: ['tests/unit/**/*.spec(.ts|.js)'],
|
||||
name: 'unit',
|
||||
timeout: 2000,
|
||||
},
|
||||
{
|
||||
files: ['tests/functional/**/*.spec(.ts|.js)'],
|
||||
name: 'functional',
|
||||
timeout: 30000,
|
||||
},
|
||||
],
|
||||
forceExit: false,
|
||||
},
|
||||
|
||||
|
||||
|
||||
})
|
||||
tests: {
|
||||
suites: [
|
||||
{
|
||||
files: ['tests/unit/**/*.spec(.ts|.js)'],
|
||||
name: 'unit',
|
||||
timeout: 2000,
|
||||
},
|
||||
{
|
||||
files: ['tests/functional/**/*.spec(.ts|.js)'],
|
||||
name: 'functional',
|
||||
timeout: 30000,
|
||||
},
|
||||
],
|
||||
forceExit: false,
|
||||
},
|
||||
assetsBundler: false,
|
||||
hooks: {
|
||||
onBuildStarting: [() => import('@adonisjs/vite/build_hook')],
|
||||
},
|
||||
// assetsBundler: false
|
||||
});
|
||||
|
|
|
@ -25,6 +25,7 @@ export default class MimetypeController {
|
|||
const newDatasetSchema = vine.object({
|
||||
name: vine.string().trim().isUnique({ table: 'mime_types', column: 'name' }),
|
||||
file_extension: vine.array(vine.string()).minLength(1), // define at least one extension for the new mimetype
|
||||
alternate_mimetype: vine.array(vine.string().isValidMimetype()).distinct().optional(), // define alias mimetypes
|
||||
enabled: vine.boolean(),
|
||||
});
|
||||
// await request.validate({ schema: newDatasetSchema, messages: this.messages });
|
||||
|
@ -32,18 +33,22 @@ export default class MimetypeController {
|
|||
// Step 2 - Validate request body against the schema
|
||||
// await request.validate({ schema: newDatasetSchema, messages: this.messages });
|
||||
const validator = vine.compile(newDatasetSchema);
|
||||
validator.messagesProvider = new SimpleMessagesProvider(this.messages);
|
||||
await request.validateUsing(validator);
|
||||
validator.messagesProvider = new SimpleMessagesProvider(this.messages);
|
||||
await request.validateUsing(validator, { messagesProvider: new SimpleMessagesProvider(this.messages) });
|
||||
} catch (error) {
|
||||
// Step 3 - Handle errors
|
||||
// return response.badRequest(error.messages);
|
||||
throw error;
|
||||
}
|
||||
const input = request.only(['name', 'enabled', 'file_extension']);
|
||||
const input = request.only(['name', 'enabled', 'file_extension', 'alternate_mimetype']);
|
||||
// Concatenate the file_extensions array into a string with '|' as the separator
|
||||
if (Array.isArray(input.file_extension)) {
|
||||
input.file_extension = input.file_extension.join('|');
|
||||
}
|
||||
// Concatenate the alias_mimetype array into a string with '|' as the separator
|
||||
if (Array.isArray(input.alternate_mimetype)) {
|
||||
input.alternate_mimetype = input.alternate_mimetype.join('|');
|
||||
}
|
||||
await MimeType.create(input);
|
||||
// if (request.input('roles')) {
|
||||
// const roles: Array<number> = request.input('roles');
|
||||
|
|
|
@ -276,7 +276,7 @@ export default class DatasetsController {
|
|||
validateSMTP: false,
|
||||
});
|
||||
const validRecipientEmail: boolean = validationResult.valid;
|
||||
let emailStatusMessage = '';
|
||||
// let emailStatusMessage = '';
|
||||
|
||||
if (sendMail == true) {
|
||||
if (dataset.editor.email && validRecipientEmail) {
|
||||
|
@ -289,7 +289,7 @@ export default class DatasetsController {
|
|||
<p>Best regards,<br>Your Tethys reviewer: ${authUser.login}</p>
|
||||
`);
|
||||
});
|
||||
emailStatusMessage = ` A rejection email was successfully sent to ${dataset.editor.email}.`;
|
||||
// emailStatusMessage = ` A rejection email was successfully sent to ${dataset.editor.email}.`;
|
||||
} catch (error) {
|
||||
logger.error(error);
|
||||
return response
|
||||
|
@ -297,7 +297,7 @@ export default class DatasetsController {
|
|||
.toRoute('reviewer.dataset.list');
|
||||
}
|
||||
} else {
|
||||
emailStatusMessage = ` However, the email could not be sent because the editor's email address (${dataset.editor.email}) is not valid.`;
|
||||
// emailStatusMessage = ` However, the email could not be sent because the editor's email address (${dataset.editor.email}) is not valid.`;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -363,7 +363,8 @@ export default class DatasetController {
|
|||
references: vine
|
||||
.array(
|
||||
vine.object({
|
||||
value: vine.string().trim().minLength(3).maxLength(255),
|
||||
// value: vine.string().trim().minLength(3).maxLength(255),
|
||||
value: vine.string().trim().minLength(3).maxLength(255).validateReference({ typeField: 'type' }),
|
||||
type: vine.enum(Object.values(ReferenceIdentifierTypes)),
|
||||
relation: vine.enum(Object.values(RelationTypes)),
|
||||
label: vine.string().trim().minLength(2).maxLength(255),
|
||||
|
@ -1192,7 +1193,7 @@ export default class DatasetController {
|
|||
throw error;
|
||||
} else if (error instanceof Exception) {
|
||||
// General exception handling
|
||||
return response.flash('errors', { error: error.message }).redirect().back();
|
||||
return response.flash('errors', error.message).redirect().back();
|
||||
} else {
|
||||
session.flash({ error: 'An error occurred while deleting the dataset.' });
|
||||
return response.redirect().back();
|
||||
|
|
|
@ -6,7 +6,7 @@ import DoiClientException from '#app/exceptions/DoiClientException';
|
|||
import { StatusCodes } from 'http-status-codes';
|
||||
import logger from '@adonisjs/core/services/logger';
|
||||
import { AxiosResponse } from 'axios';
|
||||
import axios from 'axios';
|
||||
import { default as axios } from 'axios';
|
||||
|
||||
export class DoiClient implements DoiClientContract {
|
||||
public username: string;
|
||||
|
@ -50,7 +50,7 @@ export class DoiClient implements DoiClientContract {
|
|||
'Content-Type': 'application/xml;charset=UTF-8',
|
||||
};
|
||||
try {
|
||||
const metadataResponse = await axios.default.put(`${this.serviceUrl}/metadata/${doiValue}`, xmlMeta, { auth, headers });
|
||||
const metadataResponse = await axios.put(`${this.serviceUrl}/metadata/${doiValue}`, xmlMeta, { auth, headers });
|
||||
|
||||
// Response Codes
|
||||
// 201 Created: operation successful
|
||||
|
@ -65,7 +65,7 @@ export class DoiClient implements DoiClientContract {
|
|||
throw new DoiClientException(metadataResponse.status, message);
|
||||
}
|
||||
|
||||
const doiResponse = await axios.default.put(`${this.serviceUrl}/doi/${doiValue}`, `doi=${doiValue}\nurl=${landingPageUrl}`, {
|
||||
const doiResponse = await axios.put(`${this.serviceUrl}/doi/${doiValue}`, `doi=${doiValue}\nurl=${landingPageUrl}`, {
|
||||
auth,
|
||||
headers,
|
||||
});
|
||||
|
|
|
@ -3,7 +3,6 @@ import { column, hasMany, belongsTo, SnakeCaseNamingStrategy, computed } from '@
|
|||
import HashValue from './hash_value.js';
|
||||
import Dataset from './dataset.js';
|
||||
import BaseModel from './base_model.js';
|
||||
// import { Buffer } from 'buffer';
|
||||
import * as fs from 'fs';
|
||||
import crypto from 'crypto';
|
||||
// import Drive from '@ioc:Adonis/Core/Drive';
|
||||
|
|
|
@ -16,9 +16,14 @@ export default class MimeType extends BaseModel {
|
|||
@column({})
|
||||
public name: string;
|
||||
|
||||
// 1 : n file_extensions are separated by '|' in the database
|
||||
@column({})
|
||||
public file_extension: string;
|
||||
|
||||
// 1 : n alternate_mimetype are separated by '|' in the database
|
||||
@column({})
|
||||
public alternate_mimetype: string;
|
||||
|
||||
@column({})
|
||||
public enabled: boolean;
|
||||
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
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();
|
||||
|
@ -125,7 +126,7 @@ export const createDatasetValidator = vine.compile(
|
|||
references: vine
|
||||
.array(
|
||||
vine.object({
|
||||
value: vine.string().trim().minLength(3).maxLength(255),
|
||||
value: vine.string().trim().minLength(3).maxLength(255).validateReference({ typeField: 'type' }),
|
||||
type: vine.enum(Object.values(ReferenceIdentifierTypes)),
|
||||
relation: vine.enum(Object.values(RelationTypes)),
|
||||
label: vine.string().trim().minLength(2).maxLength(255),
|
||||
|
@ -272,7 +273,7 @@ export const updateDatasetValidator = vine.compile(
|
|||
references: vine
|
||||
.array(
|
||||
vine.object({
|
||||
value: vine.string().trim().minLength(3).maxLength(255),
|
||||
value: vine.string().trim().minLength(3).maxLength(255).validateReference({ typeField: 'type' }),
|
||||
type: vine.enum(Object.values(ReferenceIdentifierTypes)),
|
||||
relation: vine.enum(Object.values(RelationTypes)),
|
||||
label: vine.string().trim().minLength(2).maxLength(255),
|
||||
|
|
|
@ -142,7 +142,7 @@ export class VanillaErrorReporter implements ErrorReporterContract {
|
|||
// }
|
||||
this.hasErrors = true;
|
||||
|
||||
var test = field.getFieldPath();
|
||||
// var test = field.getFieldPath();
|
||||
|
||||
// this.errors.push(error);
|
||||
// if (this.errors[error.field]) {
|
||||
|
|
|
@ -47,7 +47,7 @@ const databaseConfig = defineConfig({
|
|||
migrations: {
|
||||
naturalSort: true,
|
||||
},
|
||||
healthCheck: false,
|
||||
// healthCheck: false,
|
||||
debug: false,
|
||||
pool: { min: 1, max: 100 },
|
||||
},
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
import { defineConfig } from '@adonisjs/inertia';
|
||||
import type { HttpContext } from '@adonisjs/core/http';
|
||||
import type { InferSharedProps } from '@adonisjs/inertia/types'
|
||||
|
||||
export default defineConfig({
|
||||
const inertiaConfig = defineConfig({
|
||||
/**
|
||||
* Path to the Edge view that will be used as the root view for Inertia responses
|
||||
*/
|
||||
|
@ -52,6 +53,12 @@ export default defineConfig({
|
|||
},
|
||||
});
|
||||
|
||||
export default inertiaConfig
|
||||
|
||||
declare module '@adonisjs/inertia/types' {
|
||||
export interface SharedProps extends InferSharedProps<typeof inertiaConfig> {}
|
||||
}
|
||||
|
||||
// import { InertiaConfig } from '@ioc:EidelLev/Inertia';
|
||||
|
||||
// /*
|
||||
|
|
|
@ -12,7 +12,7 @@ const mailConfig = defineConfig({
|
|||
mailers: {
|
||||
|
||||
smtp: transports.smtp({
|
||||
socketTimeout: 5000,// Overall timeout (5 seconds)
|
||||
// socketTimeout: 5000,// Overall timeout (5 seconds)
|
||||
host: env.get('SMTP_HOST', ''),
|
||||
port: env.get('SMTP_PORT'),
|
||||
secure: false,
|
||||
|
@ -30,10 +30,10 @@ const mailConfig = defineConfig({
|
|||
}, */
|
||||
}),
|
||||
|
||||
resend: transports.resend({
|
||||
key: env.get('RESEND_API_KEY'),
|
||||
baseUrl: 'https://api.resend.com',
|
||||
}),
|
||||
// resend: transports.resend({
|
||||
// key: env.get('RESEND_API_KEY'),
|
||||
// baseUrl: 'https://api.resend.com',
|
||||
// }),
|
||||
},
|
||||
});
|
||||
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
*/
|
||||
|
||||
import env from '#start/env';
|
||||
import app from '@adonisjs/core/services/app';
|
||||
// import app from '@adonisjs/core/services/app';
|
||||
import { defineConfig, stores } from '@adonisjs/session';
|
||||
|
||||
const sessionConfig = defineConfig({
|
||||
|
|
32
config/vite.ts
Normal file
32
config/vite.ts
Normal file
|
@ -0,0 +1,32 @@
|
|||
import { defineConfig } from '@adonisjs/vite';
|
||||
|
||||
const viteBackendConfig = defineConfig({
|
||||
/**
|
||||
* The output of vite will be written inside this
|
||||
* directory. The path should be relative from
|
||||
* the application root.
|
||||
*/
|
||||
buildDirectory: 'public/assets',
|
||||
|
||||
/**
|
||||
* The path to the manifest file generated by the
|
||||
* "vite build" command.
|
||||
*/
|
||||
manifestFile: 'public/assets/.vite/manifest.json',
|
||||
|
||||
/**
|
||||
* Feel free to change the value of the "assetsUrl" to
|
||||
* point to a CDN in production.
|
||||
*/
|
||||
assetsUrl: '/assets',
|
||||
|
||||
/**
|
||||
* Add defer attribute to scripts for better performance.
|
||||
*/
|
||||
scriptAttributes: {
|
||||
defer: true,
|
||||
},
|
||||
|
||||
});
|
||||
|
||||
export default viteBackendConfig;
|
18
database/migrations/update_1_to_mime_types.ts
Normal file
18
database/migrations/update_1_to_mime_types.ts
Normal file
|
@ -0,0 +1,18 @@
|
|||
import { BaseSchema } from "@adonisjs/lucid/schema";
|
||||
|
||||
export default class AddAlternateMimetypeToMimeTypes extends BaseSchema {
|
||||
protected tableName = 'mime_types';
|
||||
|
||||
public async up () {
|
||||
this.schema.alterTable(this.tableName, (table) => {
|
||||
table.string('alternate_mimetype').nullable();
|
||||
});
|
||||
}
|
||||
|
||||
public async down () {
|
||||
this.schema.alterTable(this.tableName, (table) => {
|
||||
table.dropColumn('alternate_mimetype');
|
||||
});
|
||||
}
|
||||
}
|
||||
// ALTER TABLE "mime_types" ADD COLUMN "alternate_mimetype" VARCHAR(255) NULL
|
10056
package-lock.json
generated
10056
package-lock.json
generated
File diff suppressed because it is too large
Load diff
76
package.json
76
package.json
|
@ -4,7 +4,8 @@
|
|||
"private": true,
|
||||
"scripts": {
|
||||
"type-check": "tsc --noEmit",
|
||||
"dev": "node ace serve --watch",
|
||||
"dev": "node ace serve",
|
||||
"devInspect": "node ace serve --watch --node-args='--inspect'",
|
||||
"compress:xslt": "./node_modules/xslt3/xslt3.js -xsl:public/assets2/datasetxml2oai-pmh.xslt -export:public/assets2/datasetxml2oai.sef.json -t -nogo '-ns:##html5'",
|
||||
"compress:solr": "./node_modules/xslt3/xslt3.js -xsl:public/assets2/solr.xslt -export:public/assets2/solr.sef.json -t -nogo '-ns:##html5'",
|
||||
"compress:doi": "./node_modules/xslt3/xslt3.js -xsl:public/assets2/doi_datacite.xslt -export:public/assets2/doi_datacite.sef.json -t -nogo '-ns:##html5'",
|
||||
|
@ -15,59 +16,57 @@
|
|||
"format-check": "prettier --check ./**/*.{ts,js}",
|
||||
"test": "node ace test"
|
||||
},
|
||||
"eslintIgnore": [
|
||||
"build"
|
||||
],
|
||||
"eslintConfig": {
|
||||
"ignorePatterns": [
|
||||
"build"
|
||||
]
|
||||
},
|
||||
"alias": {
|
||||
"vue": "./node_modules/vue/dist/vue.esm-bundler.js"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@adonisjs/assembler": "^7.1.1",
|
||||
"@adonisjs/tsconfig": "^1.2.1",
|
||||
"@babel/core": "^7.20.12",
|
||||
"@babel/plugin-proposal-class-properties": "^7.18.6",
|
||||
"@babel/plugin-proposal-decorators": "^7.20.13",
|
||||
"@babel/plugin-transform-runtime": "^7.19.6",
|
||||
"@babel/preset-env": "^7.20.2",
|
||||
"@babel/preset-typescript": "^7.18.6",
|
||||
"@japa/api-client": "^2.0.3",
|
||||
"@japa/assert": "^3.0.0",
|
||||
"@japa/plugin-adonisjs": "^3.0.0",
|
||||
"@japa/runner": "^3.1.1",
|
||||
"@adonisjs/tsconfig": "^1.4.0",
|
||||
"@japa/assert": "^4.0.1",
|
||||
"@japa/plugin-adonisjs": "^4.0.0",
|
||||
"@japa/runner": "^4.2.0",
|
||||
"@mdi/js": "^7.1.96",
|
||||
"@poppinss/utils": "^6.7.2",
|
||||
"@swc/core": "^1.4.2",
|
||||
"@symfony/webpack-encore": "^5.0.1",
|
||||
"@swc/wasm": "^1.10.14",
|
||||
"@tailwindcss/forms": "^0.5.2",
|
||||
"@types/bcryptjs": "^2.4.6",
|
||||
"@types/clamscan": "^2.0.4",
|
||||
"@types/escape-html": "^1.0.4",
|
||||
"@types/fs-extra": "^11.0.4",
|
||||
"@types/leaflet": "^1.9.3",
|
||||
"@types/luxon": "^3.4.2",
|
||||
"@types/node": "^22.5.5",
|
||||
"@types/node": "^22.10.2",
|
||||
"@types/proxy-addr": "^2.0.0",
|
||||
"@types/qrcode": "^1.5.5",
|
||||
"@types/source-map-support": "^0.5.6",
|
||||
"@types/sprintf-js": "^1.1.4",
|
||||
"@types/supertest": "^6.0.2",
|
||||
"@vitejs/plugin-vue": "^5.2.1",
|
||||
"autoprefixer": "^10.4.13",
|
||||
"babel-preset-typescript-vue3": "^2.0.17",
|
||||
"chart.js": "^4.2.0",
|
||||
"dotenv-webpack": "^8.0.1",
|
||||
"eslint": "^8.57.1",
|
||||
"eslint-config-prettier": "^9.0.0",
|
||||
"eslint-config-prettier": "^10.0.1",
|
||||
"eslint-plugin-adonis": "^2.1.1",
|
||||
"eslint-plugin-prettier": "^5.0.0-alpha.2",
|
||||
"hot-hook": "^0.4.0",
|
||||
"numeral": "^2.0.6",
|
||||
"pinia": "^2.0.30",
|
||||
"pino-pretty": "^11.2.2",
|
||||
"pino-pretty": "^13.0.0",
|
||||
"postcss-loader": "^8.1.1",
|
||||
"prettier": "^3.0.0",
|
||||
"prettier": "^3.4.2",
|
||||
"supertest": "^6.3.3",
|
||||
"tailwindcss": "^3.2.4",
|
||||
"tailwindcss": "^3.4.17",
|
||||
"ts-loader": "^9.4.2",
|
||||
"ts-node": "^10.9.2",
|
||||
"typescript": "^5.1.3",
|
||||
"ts-node-maintained": "^10.9.5",
|
||||
"typescript": "~5.7",
|
||||
"vite": "^6.0.11",
|
||||
"vue": "^3.4.26",
|
||||
"vue-facing-decorator": "^3.0.0",
|
||||
"vue-loader": "^17.0.1",
|
||||
|
@ -75,30 +74,31 @@
|
|||
"xslt3": "^2.5.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"@adonisjs/auth": "^9.1.1",
|
||||
"@adonisjs/core": "^6.3.1",
|
||||
"@adonisjs/auth": "^9.2.4",
|
||||
"@adonisjs/core": "^6.17.0",
|
||||
"@adonisjs/cors": "^2.2.1",
|
||||
"@adonisjs/drive": "^2.3.0",
|
||||
"@adonisjs/encore": "^1.0.0",
|
||||
"@adonisjs/inertia": "^1.0.0-7",
|
||||
"@adonisjs/lucid": "^21.1.0",
|
||||
"@adonisjs/drive": "^3.2.0",
|
||||
"@adonisjs/inertia": "^2.1.3",
|
||||
"@adonisjs/lucid": "^21.5.1",
|
||||
"@adonisjs/mail": "^9.2.2",
|
||||
"@adonisjs/redis": "^9.1.0",
|
||||
"@adonisjs/session": "^7.1.1",
|
||||
"@adonisjs/session": "^7.5.0",
|
||||
"@adonisjs/shield": "^8.1.1",
|
||||
"@adonisjs/static": "^1.1.1",
|
||||
"@adonisjs/vite": "^4.0.0",
|
||||
"@eidellev/adonis-stardust": "^3.0.0",
|
||||
"@fontsource/archivo-black": "^5.0.1",
|
||||
"@fontsource/inter": "^5.0.1",
|
||||
"@inertiajs/inertia": "^0.11.1",
|
||||
"@inertiajs/vue3": "^1.0.0",
|
||||
"@opensearch-project/opensearch": "^2.4.0",
|
||||
"@inertiajs/vue3": "^2.0.3",
|
||||
"@opensearch-project/opensearch": "^3.2.0",
|
||||
"@phc/format": "^1.0.0",
|
||||
"@vinejs/vine": "^2.0.0",
|
||||
"@poppinss/manager": "^5.0.2",
|
||||
"@vinejs/vine": "^3.0.0",
|
||||
"axios": "^1.7.9",
|
||||
"bcrypt": "^5.1.1",
|
||||
"bcryptjs": "^2.4.3",
|
||||
"clamscan": "^2.1.2",
|
||||
"crypto": "^1.0.1",
|
||||
"dayjs": "^1.11.7",
|
||||
"deep-email-validator": "^0.1.21",
|
||||
"edge.js": "^6.0.1",
|
||||
|
@ -121,6 +121,12 @@
|
|||
"vuedraggable": "^4.1.0",
|
||||
"xmlbuilder2": "^3.1.1"
|
||||
},
|
||||
"hotHook": {
|
||||
"boundaries": [
|
||||
"./app/Controllers/**/*.ts",
|
||||
"./app/middleware/*.ts"
|
||||
]
|
||||
},
|
||||
"type": "module",
|
||||
"imports": {
|
||||
"#controllers/*": "./app/Controllers/*.js",
|
||||
|
|
|
@ -1,7 +1,10 @@
|
|||
module.exports = {
|
||||
plugins: {
|
||||
// 'postcss-import': {},
|
||||
'tailwindcss/nesting': {},
|
||||
// 'postcss-nesting': {},
|
||||
'tailwindcss/nesting': {},
|
||||
// "@tailwindcss/postcss": {},
|
||||
// tailwindcss: {},
|
||||
tailwindcss: {},
|
||||
autoprefixer: {},
|
||||
},
|
||||
|
|
|
@ -69,7 +69,7 @@ export default class MailProvider {
|
|||
const mailConfigProvider = this.app.config.get('mail');
|
||||
const config = await configProvider.resolve<any>(this.app, mailConfigProvider);
|
||||
|
||||
const iwas = await config.mailers.smtp();
|
||||
await config.mailers.smtp();
|
||||
// iwas.config.host = 'hhhost';
|
||||
// this.app.config.set('mail.mailers.smtp.host', 'xhost');
|
||||
// const iwas = await config.mailers.smtp();
|
||||
|
|
|
@ -63,6 +63,15 @@ export default class QueryBuilderProvider {
|
|||
|
||||
public register() {
|
||||
// Register your own bindings
|
||||
// const ModelQueryBuilder = this.app.container.bind('@adonisjs/lucid/orm/ModelQueryBuilder');
|
||||
|
||||
// ModelQueryBuilder.macro('whereTrue', function (columnName: string) {
|
||||
// return this.where(columnName, true);
|
||||
// });
|
||||
|
||||
// ModelQueryBuilder.macro('whereFalse', function (columnName: string) {
|
||||
// return this.where(columnName, false);
|
||||
// });
|
||||
}
|
||||
|
||||
public async boot() {
|
||||
|
@ -73,15 +82,14 @@ export default class QueryBuilderProvider {
|
|||
// let rolesPluck = {};
|
||||
let rolesPluck: { [key: number]: any } = {};
|
||||
const result = await this.exec();
|
||||
result.forEach((user, index) => {
|
||||
let idc;
|
||||
result.forEach((user: { [key: string]: any }, index: number) => {
|
||||
let idc: number;
|
||||
if (!id) {
|
||||
idc = index;
|
||||
} else {
|
||||
idc = user[id];
|
||||
}
|
||||
const value = user[valueColumn];
|
||||
// rolesPluck[idc] = user.name;
|
||||
const value: any = user[valueColumn];
|
||||
rolesPluck[idc] = value;
|
||||
});
|
||||
return rolesPluck;
|
||||
|
|
|
@ -4,14 +4,15 @@
|
|||
|--------------------------------------------------------------------------
|
||||
|*/
|
||||
import type { ApplicationService } from '@adonisjs/core/types';
|
||||
import vine, { BaseLiteralType, Vine } from '@vinejs/vine';
|
||||
import type { Validation, FieldContext, FieldOptions } from '@vinejs/vine/types';
|
||||
import vine, { symbols, BaseLiteralType, Vine } from '@vinejs/vine';
|
||||
import type { FieldContext, FieldOptions } from '@vinejs/vine/types';
|
||||
// import type { MultipartFile, FileValidationOptions } from '@adonisjs/bodyparser/types';
|
||||
import type { MultipartFile } from '@adonisjs/core/bodyparser';
|
||||
import type { FileValidationOptions } from '@adonisjs/core/types/bodyparser';
|
||||
import { Request, RequestValidator } from '@adonisjs/core/http';
|
||||
import MimeType from '#models/mime_type';
|
||||
|
||||
|
||||
/**
|
||||
* Validation options accepted by the "file" rule
|
||||
*/
|
||||
|
@ -28,8 +29,7 @@ declare module '@vinejs/vine' {
|
|||
* Extend HTTP request class
|
||||
*/
|
||||
declare module '@adonisjs/core/http' {
|
||||
interface Request extends RequestValidator {
|
||||
}
|
||||
interface Request extends RequestValidator {}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -48,7 +48,7 @@ export async function getEnabledExtensions() {
|
|||
.flat();
|
||||
|
||||
return extensions;
|
||||
};
|
||||
}
|
||||
/**
|
||||
* VineJS validation rule that validates the file to be an
|
||||
* instance of BodyParser MultipartFile class.
|
||||
|
@ -82,8 +82,8 @@ const isMultipartFile = vine.createRule(async (file: MultipartFile | unknown, op
|
|||
if (validatedFile.allowedExtensions === undefined && validationOptions.extnames) {
|
||||
validatedFile.allowedExtensions = await getEnabledExtensions();
|
||||
}
|
||||
/**
|
||||
* wieder löschen
|
||||
/**
|
||||
* wieder löschen
|
||||
* Set extensions when it's defined in the options and missing
|
||||
* on the file instance
|
||||
*/
|
||||
|
@ -102,7 +102,20 @@ const isMultipartFile = vine.createRule(async (file: MultipartFile | unknown, op
|
|||
});
|
||||
});
|
||||
|
||||
const MULTIPART_FILE: typeof symbols.SUBTYPE = symbols.SUBTYPE;
|
||||
|
||||
export class VineMultipartFile extends BaseLiteralType<MultipartFile, MultipartFile, MultipartFile> {
|
||||
|
||||
[MULTIPART_FILE]: string;
|
||||
// constructor(validationOptions?: FileRuleValidationOptions, options?: FieldOptions) {
|
||||
// super(options, [isMultipartFile(validationOptions || {})]);
|
||||
// this.validationOptions = validationOptions;
|
||||
// this.#private = true;
|
||||
// }
|
||||
|
||||
// clone(): this {
|
||||
// return new VineMultipartFile(this.validationOptions, this.cloneOptions()) as this;
|
||||
// }
|
||||
// #private;
|
||||
// constructor(validationOptions?: FileRuleValidationOptions, options?: FieldOptions, validations?: Validation<any>[]);
|
||||
// clone(): this;
|
||||
|
@ -111,14 +124,16 @@ export class VineMultipartFile extends BaseLiteralType<MultipartFile, MultipartF
|
|||
// extnames: (18) ['gpkg', 'htm', 'html', 'csv', 'txt', 'asc', 'c', 'cc', 'h', 'srt', 'tiff', 'pdf', 'png', 'zip', 'jpg', 'jpeg', 'jpe', 'xlsx']
|
||||
// size: '512mb'
|
||||
|
||||
public constructor(validationOptions?: FileRuleValidationOptions, options?: FieldOptions, validations?: Validation<any>[]) {
|
||||
// public constructor(validationOptions?: FileRuleValidationOptions, options?: FieldOptions, validations?: Validation<any>[]) {
|
||||
public constructor(validationOptions?: FileRuleValidationOptions, options?: FieldOptions) {
|
||||
// super(options, validations);
|
||||
super(options, [isMultipartFile(validationOptions || {})]);
|
||||
this.validationOptions = validationOptions;
|
||||
}
|
||||
|
||||
public clone(): any {
|
||||
return new VineMultipartFile(this.validationOptions, this.cloneOptions(), this.cloneValidations());
|
||||
// return new VineMultipartFile(this.validationOptions, this.cloneOptions(), this.cloneValidations());
|
||||
return new VineMultipartFile(this.validationOptions, this.cloneOptions());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -152,10 +167,12 @@ export default class VinejsProvider {
|
|||
* The validate method can be used to validate the request
|
||||
* data for the current request using VineJS validators
|
||||
*/
|
||||
Request.macro('validateUsing', function (...args) {
|
||||
return new RequestValidator(this.ctx).validateUsing(...args);
|
||||
});
|
||||
|
||||
Request.macro('validateUsing', function (this: Request, ...args) {
|
||||
if (!this.ctx) {
|
||||
throw new Error('HttpContext is not available');
|
||||
}
|
||||
return new RequestValidator(this.ctx).validateUsing(...args);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -1,12 +0,0 @@
|
|||
{
|
||||
"entrypoints": {
|
||||
"app": {
|
||||
"css": [
|
||||
"http://localhost:8080/assets/app.css"
|
||||
],
|
||||
"js": [
|
||||
"http://localhost:8080/assets/app.js"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,103 +0,0 @@
|
|||
{
|
||||
"assets/app.css": "http://localhost:8080/assets/app.css",
|
||||
"assets/app.js": "http://localhost:8080/assets/app.js",
|
||||
"assets/resources_js_apps_settings_l18n_de_js.js": "http://localhost:8080/assets/resources_js_apps_settings_l18n_de_js.js",
|
||||
"assets/resources_js_apps_settings_l18n_en_js.js": "http://localhost:8080/assets/resources_js_apps_settings_l18n_en_js.js",
|
||||
"assets/resources_js_Pages_Admin_License_Index_vue.js": "http://localhost:8080/assets/resources_js_Pages_Admin_License_Index_vue.js",
|
||||
"assets/resources_js_Pages_Admin_Mimetype_Create_vue.js": "http://localhost:8080/assets/resources_js_Pages_Admin_Mimetype_Create_vue.js",
|
||||
"assets/resources_js_Pages_Admin_Mimetype_Delete_vue.js": "http://localhost:8080/assets/resources_js_Pages_Admin_Mimetype_Delete_vue.js",
|
||||
"assets/resources_js_Pages_Admin_Mimetype_Index_vue.js": "http://localhost:8080/assets/resources_js_Pages_Admin_Mimetype_Index_vue.js",
|
||||
"assets/resources_js_Pages_Admin_Permission_Create_vue.js": "http://localhost:8080/assets/resources_js_Pages_Admin_Permission_Create_vue.js",
|
||||
"assets/resources_js_Pages_Admin_Permission_Edit_vue.js": "http://localhost:8080/assets/resources_js_Pages_Admin_Permission_Edit_vue.js",
|
||||
"assets/resources_js_Pages_Admin_Permission_Index_vue.js": "http://localhost:8080/assets/resources_js_Pages_Admin_Permission_Index_vue.js",
|
||||
"assets/resources_js_Pages_Admin_Permission_Show_vue.js": "http://localhost:8080/assets/resources_js_Pages_Admin_Permission_Show_vue.js",
|
||||
"assets/resources_js_Pages_Admin_Role_Create_vue.js": "http://localhost:8080/assets/resources_js_Pages_Admin_Role_Create_vue.js",
|
||||
"assets/resources_js_Pages_Admin_Role_Edit_vue.js": "http://localhost:8080/assets/resources_js_Pages_Admin_Role_Edit_vue.js",
|
||||
"assets/resources_js_Pages_Admin_Role_Index_vue.js": "http://localhost:8080/assets/resources_js_Pages_Admin_Role_Index_vue.js",
|
||||
"assets/resources_js_Pages_Admin_Role_Show_vue.js": "http://localhost:8080/assets/resources_js_Pages_Admin_Role_Show_vue.js",
|
||||
"assets/resources_js_Pages_Admin_Settings_vue-resources_js_utils_toast_css.css": "http://localhost:8080/assets/resources_js_Pages_Admin_Settings_vue-resources_js_utils_toast_css.css",
|
||||
"assets/resources_js_Pages_Admin_Settings_vue-resources_js_utils_toast_css.js": "http://localhost:8080/assets/resources_js_Pages_Admin_Settings_vue-resources_js_utils_toast_css.js",
|
||||
"assets/resources_js_Pages_Admin_User_Create_vue-resources_js_Components_SimplePasswordMeter_password-f3312a.css": "http://localhost:8080/assets/resources_js_Pages_Admin_User_Create_vue-resources_js_Components_SimplePasswordMeter_password-f3312a.css",
|
||||
"assets/resources_js_Pages_Admin_User_Create_vue-resources_js_Components_SimplePasswordMeter_password-f3312a.js": "http://localhost:8080/assets/resources_js_Pages_Admin_User_Create_vue-resources_js_Components_SimplePasswordMeter_password-f3312a.js",
|
||||
"assets/resources_js_Pages_Admin_User_Edit_vue-resources_js_Components_SimplePasswordMeter_password-m-6dc207.css": "http://localhost:8080/assets/resources_js_Pages_Admin_User_Edit_vue-resources_js_Components_SimplePasswordMeter_password-m-6dc207.css",
|
||||
"assets/resources_js_Pages_Admin_User_Edit_vue-resources_js_Components_SimplePasswordMeter_password-m-6dc207.js": "http://localhost:8080/assets/resources_js_Pages_Admin_User_Edit_vue-resources_js_Components_SimplePasswordMeter_password-m-6dc207.js",
|
||||
"assets/resources_js_Pages_Admin_User_Index_vue.js": "http://localhost:8080/assets/resources_js_Pages_Admin_User_Index_vue.js",
|
||||
"assets/resources_js_Pages_Admin_User_Show_vue.js": "http://localhost:8080/assets/resources_js_Pages_Admin_User_Show_vue.js",
|
||||
"assets/resources_js_Pages_App_vue.js": "http://localhost:8080/assets/resources_js_Pages_App_vue.js",
|
||||
"assets/resources_js_Pages_Auth_AccountInfo_vue-resources_js_utils_toast_css-resources_js_Components_-06c7b5.css": "http://localhost:8080/assets/resources_js_Pages_Auth_AccountInfo_vue-resources_js_utils_toast_css-resources_js_Components_-06c7b5.css",
|
||||
"assets/resources_js_Pages_Auth_AccountInfo_vue-resources_js_utils_toast_css-resources_js_Components_-06c7b5.js": "http://localhost:8080/assets/resources_js_Pages_Auth_AccountInfo_vue-resources_js_utils_toast_css-resources_js_Components_-06c7b5.js",
|
||||
"assets/resources_js_Pages_Auth_Login_vue.js": "http://localhost:8080/assets/resources_js_Pages_Auth_Login_vue.js",
|
||||
"assets/resources_js_Pages_Auth_Register_vue.js": "http://localhost:8080/assets/resources_js_Pages_Auth_Register_vue.js",
|
||||
"assets/resources_js_Pages_Dashboard_vue.js": "http://localhost:8080/assets/resources_js_Pages_Dashboard_vue.js",
|
||||
"assets/resources_js_Pages_Editor_Dataset_Approve_vue.js": "http://localhost:8080/assets/resources_js_Pages_Editor_Dataset_Approve_vue.js",
|
||||
"assets/resources_js_Pages_Editor_Dataset_Doi_vue.js": "http://localhost:8080/assets/resources_js_Pages_Editor_Dataset_Doi_vue.js",
|
||||
"assets/resources_js_Pages_Editor_Dataset_Index_vue.js": "http://localhost:8080/assets/resources_js_Pages_Editor_Dataset_Index_vue.js",
|
||||
"assets/resources_js_Pages_Editor_Dataset_Publish_vue.js": "http://localhost:8080/assets/resources_js_Pages_Editor_Dataset_Publish_vue.js",
|
||||
"assets/resources_js_Pages_Editor_Dataset_Receive_vue.js": "http://localhost:8080/assets/resources_js_Pages_Editor_Dataset_Receive_vue.js",
|
||||
"assets/resources_js_Pages_Editor_Dataset_Reject_vue.js": "http://localhost:8080/assets/resources_js_Pages_Editor_Dataset_Reject_vue.js",
|
||||
"assets/resources_js_Pages_Error_vue.js": "http://localhost:8080/assets/resources_js_Pages_Error_vue.js",
|
||||
"assets/resources_js_Pages_Errors_ServerError_vue.js": "http://localhost:8080/assets/resources_js_Pages_Errors_ServerError_vue.js",
|
||||
"assets/resources_js_Pages_Errors_not_found_vue.js": "http://localhost:8080/assets/resources_js_Pages_Errors_not_found_vue.js",
|
||||
"assets/resources_js_Pages_Map_vue-resources_js_Components_Map_draw_component_vue-resources_js_Compon-b0925c.css": "http://localhost:8080/assets/resources_js_Pages_Map_vue-resources_js_Components_Map_draw_component_vue-resources_js_Compon-b0925c.css",
|
||||
"assets/resources_js_Pages_Map_vue-resources_js_Components_Map_draw_component_vue-resources_js_Compon-b0925c.js": "http://localhost:8080/assets/resources_js_Pages_Map_vue-resources_js_Components_Map_draw_component_vue-resources_js_Compon-b0925c.js",
|
||||
"assets/resources_js_Pages_ProfileView_vue.js": "http://localhost:8080/assets/resources_js_Pages_ProfileView_vue.js",
|
||||
"assets/resources_js_Pages_Reviewer_Dataset_Index_vue.js": "http://localhost:8080/assets/resources_js_Pages_Reviewer_Dataset_Index_vue.js",
|
||||
"assets/resources_js_Pages_Reviewer_Dataset_Reject_vue.js": "http://localhost:8080/assets/resources_js_Pages_Reviewer_Dataset_Reject_vue.js",
|
||||
"assets/resources_js_Pages_Reviewer_Dataset_Review_vue.js": "http://localhost:8080/assets/resources_js_Pages_Reviewer_Dataset_Review_vue.js",
|
||||
"assets/resources_js_Pages_Submitter_Dataset_Category_vue.css": "http://localhost:8080/assets/resources_js_Pages_Submitter_Dataset_Category_vue.css",
|
||||
"assets/resources_js_Pages_Submitter_Dataset_Category_vue.js": "http://localhost:8080/assets/resources_js_Pages_Submitter_Dataset_Category_vue.js",
|
||||
"assets/resources_js_Pages_Submitter_Dataset_Create_vue-resources_js_utils_toast_css-resources_js_Com-03a898.css": "http://localhost:8080/assets/resources_js_Pages_Submitter_Dataset_Create_vue-resources_js_utils_toast_css-resources_js_Com-03a898.css",
|
||||
"assets/resources_js_Pages_Submitter_Dataset_Create_vue-resources_js_utils_toast_css-resources_js_Com-03a898.js": "http://localhost:8080/assets/resources_js_Pages_Submitter_Dataset_Create_vue-resources_js_utils_toast_css-resources_js_Com-03a898.js",
|
||||
"assets/resources_js_Pages_Submitter_Dataset_Delete_vue.js": "http://localhost:8080/assets/resources_js_Pages_Submitter_Dataset_Delete_vue.js",
|
||||
"assets/resources_js_Pages_Submitter_Dataset_Edit_vue-resources_js_utils_toast_css-resources_js_Compo-a37b65.css": "http://localhost:8080/assets/resources_js_Pages_Submitter_Dataset_Edit_vue-resources_js_utils_toast_css-resources_js_Compo-a37b65.css",
|
||||
"assets/resources_js_Pages_Submitter_Dataset_Edit_vue-resources_js_utils_toast_css-resources_js_Compo-a37b65.js": "http://localhost:8080/assets/resources_js_Pages_Submitter_Dataset_Edit_vue-resources_js_utils_toast_css-resources_js_Compo-a37b65.js",
|
||||
"assets/resources_js_Pages_Submitter_Dataset_Index_vue.css": "http://localhost:8080/assets/resources_js_Pages_Submitter_Dataset_Index_vue.css",
|
||||
"assets/resources_js_Pages_Submitter_Dataset_Index_vue.js": "http://localhost:8080/assets/resources_js_Pages_Submitter_Dataset_Index_vue.js",
|
||||
"assets/resources_js_Pages_Submitter_Dataset_Release_vue.js": "http://localhost:8080/assets/resources_js_Pages_Submitter_Dataset_Release_vue.js",
|
||||
"assets/resources_js_Pages_Submitter_Person_Index_vue.js": "http://localhost:8080/assets/resources_js_Pages_Submitter_Person_Index_vue.js",
|
||||
"assets/resources_js_Pages_register-view_register-view-component_vue.js": "http://localhost:8080/assets/resources_js_Pages_register-view_register-view-component_vue.js",
|
||||
"assets/vendors-node_modules_mdi_js_mdi_js-node_modules_vue-loader_dist_exportHelper_js.js": "http://localhost:8080/assets/vendors-node_modules_mdi_js_mdi_js-node_modules_vue-loader_dist_exportHelper_js.js",
|
||||
"assets/vendors-node_modules_focus-trap_dist_focus-trap_esm_js-node_modules_notiwind_dist_index_esm_js.js": "http://localhost:8080/assets/vendors-node_modules_focus-trap_dist_focus-trap_esm_js-node_modules_notiwind_dist_index_esm_js.js",
|
||||
"assets/vendors-node_modules_vue-facing-decorator_dist_esm_utils_js.js": "http://localhost:8080/assets/vendors-node_modules_vue-facing-decorator_dist_esm_utils_js.js",
|
||||
"assets/vendors-node_modules_toastify-js_src_toastify_js.js": "http://localhost:8080/assets/vendors-node_modules_toastify-js_src_toastify_js.js",
|
||||
"assets/vendors-node_modules_leaflet_dist_leaflet-src_js-node_modules_leaflet_src_control_Control_Att-adabdc.js": "http://localhost:8080/assets/vendors-node_modules_leaflet_dist_leaflet-src_js-node_modules_leaflet_src_control_Control_Att-adabdc.js",
|
||||
"assets/vendors-node_modules_buffer_index_js-node_modules_vuedraggable_dist_vuedraggable_umd_js.js": "http://localhost:8080/assets/vendors-node_modules_buffer_index_js-node_modules_vuedraggable_dist_vuedraggable_umd_js.js",
|
||||
"assets/vendors-node_modules_mime_dist_src_index_js.js": "http://localhost:8080/assets/vendors-node_modules_mime_dist_src_index_js.js",
|
||||
"assets/vendors-node_modules_numeral_numeral_js-node_modules_chart_js_dist_chart_js.js": "http://localhost:8080/assets/vendors-node_modules_numeral_numeral_js-node_modules_chart_js_dist_chart_js.js",
|
||||
"assets/resources_js_Components_BaseButton_vue.js": "http://localhost:8080/assets/resources_js_Components_BaseButton_vue.js",
|
||||
"assets/resources_js_Stores_main_ts-resources_js_Components_BaseDivider_vue-resources_js_Components_C-b45805.js": "http://localhost:8080/assets/resources_js_Stores_main_ts-resources_js_Components_BaseDivider_vue-resources_js_Components_C-b45805.js",
|
||||
"assets/resources_js_Layouts_LayoutAuthenticated_vue.css": "http://localhost:8080/assets/resources_js_Layouts_LayoutAuthenticated_vue.css",
|
||||
"assets/resources_js_Layouts_LayoutAuthenticated_vue.js": "http://localhost:8080/assets/resources_js_Layouts_LayoutAuthenticated_vue.js",
|
||||
"assets/resources_js_Components_BaseButtons_vue-resources_js_Components_FormControl_vue-resources_js_-d830d6.js": "http://localhost:8080/assets/resources_js_Components_BaseButtons_vue-resources_js_Components_FormControl_vue-resources_js_-d830d6.js",
|
||||
"assets/resources_js_Components_Admin_Pagination_vue-resources_js_Components_BaseButtons_vue-resource-6f3a70.js": "http://localhost:8080/assets/resources_js_Components_Admin_Pagination_vue-resources_js_Components_BaseButtons_vue-resource-6f3a70.js",
|
||||
"assets/resources_js_utils_toast_ts-resources_js_Components_NotificationBar_vue.js": "http://localhost:8080/assets/resources_js_utils_toast_ts-resources_js_Components_NotificationBar_vue.js",
|
||||
"assets/resources_js_Components_Map_draw_component_vue-resources_js_Components_Map_zoom_component_vue-058bcc.js": "http://localhost:8080/assets/resources_js_Components_Map_draw_component_vue-resources_js_Components_Map_zoom_component_vue-058bcc.js",
|
||||
"assets/resources_js_Components_SectionMain_vue-resources_js_Components_SectionTitleLineWithButton_vu-764dfe.js": "http://localhost:8080/assets/resources_js_Components_SectionMain_vue-resources_js_Components_SectionTitleLineWithButton_vu-764dfe.js",
|
||||
"assets/resources_js_Components_BaseButtons_vue-resources_js_Components_NotificationBar_vue-resources-7e06d8.js": "http://localhost:8080/assets/resources_js_Components_BaseButtons_vue-resources_js_Components_NotificationBar_vue-resources-7e06d8.js",
|
||||
"assets/resources_js_Components_Admin_Sort_vue-resources_js_Components_SectionTitleLineWithButton_vue.js": "http://localhost:8080/assets/resources_js_Components_Admin_Sort_vue-resources_js_Components_SectionTitleLineWithButton_vue.js",
|
||||
"assets/resources_js_Components_CardBoxModal_vue.js": "http://localhost:8080/assets/resources_js_Components_CardBoxModal_vue.js",
|
||||
"assets/resources_js_Components_FileUpload_vue-resources_js_Components_FormCheckRadioGroup_vue-resour-25e686.js": "http://localhost:8080/assets/resources_js_Components_FileUpload_vue-resources_js_Components_FormCheckRadioGroup_vue-resour-25e686.js",
|
||||
"assets/fonts/inter-latin-ext-400-normal.woff": "http://localhost:8080/assets/fonts/inter-latin-ext-400-normal.1c20f7dc.woff",
|
||||
"assets/fonts/inter-latin-400-normal.woff": "http://localhost:8080/assets/fonts/inter-latin-400-normal.b0c8fe9d.woff",
|
||||
"assets/fonts/inter-latin-ext-400-normal.woff2": "http://localhost:8080/assets/fonts/inter-latin-ext-400-normal.3d10c85f.woff2",
|
||||
"assets/fonts/inter-latin-400-normal.woff2": "http://localhost:8080/assets/fonts/inter-latin-400-normal.9698cc7d.woff2",
|
||||
"assets/fonts/archivo-black-latin-400-normal.woff2": "http://localhost:8080/assets/fonts/archivo-black-latin-400-normal.fc847a1f.woff2",
|
||||
"assets/fonts/archivo-black-latin-ext-400-normal.woff2": "http://localhost:8080/assets/fonts/archivo-black-latin-ext-400-normal.21761451.woff2",
|
||||
"assets/fonts/inter-cyrillic-ext-400-normal.woff": "http://localhost:8080/assets/fonts/inter-cyrillic-ext-400-normal.e8945162.woff",
|
||||
"assets/fonts/archivo-black-latin-400-normal.woff": "http://localhost:8080/assets/fonts/archivo-black-latin-400-normal.58a301a6.woff",
|
||||
"assets/fonts/inter-cyrillic-ext-400-normal.woff2": "http://localhost:8080/assets/fonts/inter-cyrillic-ext-400-normal.fd1478dc.woff2",
|
||||
"assets/fonts/inter-cyrillic-400-normal.woff": "http://localhost:8080/assets/fonts/inter-cyrillic-400-normal.e2841352.woff",
|
||||
"assets/fonts/inter-greek-400-normal.woff": "http://localhost:8080/assets/fonts/inter-greek-400-normal.a42da273.woff",
|
||||
"assets/fonts/archivo-black-latin-ext-400-normal.woff": "http://localhost:8080/assets/fonts/archivo-black-latin-ext-400-normal.5ab5ba92.woff",
|
||||
"assets/fonts/inter-greek-400-normal.woff2": "http://localhost:8080/assets/fonts/inter-greek-400-normal.a8de720a.woff2",
|
||||
"assets/fonts/inter-cyrillic-400-normal.woff2": "http://localhost:8080/assets/fonts/inter-cyrillic-400-normal.cb04b2ee.woff2",
|
||||
"assets/fonts/inter-greek-ext-400-normal.woff": "http://localhost:8080/assets/fonts/inter-greek-ext-400-normal.b9e1e894.woff",
|
||||
"assets/fonts/inter-vietnamese-400-normal.woff": "http://localhost:8080/assets/fonts/inter-vietnamese-400-normal.96f8adc7.woff",
|
||||
"assets/fonts/inter-greek-ext-400-normal.woff2": "http://localhost:8080/assets/fonts/inter-greek-ext-400-normal.f2fa0d9e.woff2",
|
||||
"assets/fonts/inter-vietnamese-400-normal.woff2": "http://localhost:8080/assets/fonts/inter-vietnamese-400-normal.44c9df13.woff2",
|
||||
"assets/images/marker-icon.png": "http://localhost:8080/assets/images/marker-icon.2b3e1faf.png",
|
||||
"assets/images/layers-2x.png": "http://localhost:8080/assets/images/layers-2x.8f2c4d11.png",
|
||||
"assets/images/layers.png": "http://localhost:8080/assets/images/layers.416d9136.png",
|
||||
"assets/images/Close.svg": "http://localhost:8080/assets/images/Close.e4887675.svg",
|
||||
"assets/vendors-node_modules_vue-facing-decorator_dist_esm_index_js-node_modules_vue-facing-decorator-818045.js": "http://localhost:8080/assets/vendors-node_modules_vue-facing-decorator_dist_esm_index_js-node_modules_vue-facing-decorator-818045.js"
|
||||
}
|
|
@ -1,19 +1,20 @@
|
|||
/* @import url('https://fonts.googleapis.com/css2?family=Poppins:wght@400;500&display=swap'); */
|
||||
/* @import url('https://fonts.googleapis.com/css?family=Roboto:400,400i,600,700'); */
|
||||
|
||||
@tailwind base;
|
||||
@tailwind components;
|
||||
@tailwind utilities;
|
||||
|
||||
@import '_checkbox-radio-switch.css';
|
||||
@import '_progress.css';
|
||||
@import '_scrollbars.css';
|
||||
@import '_table.css';
|
||||
|
||||
@import '~leaflet/dist/leaflet.css';
|
||||
/* @import '~leaflet/dist/leaflet.css'; */
|
||||
@import '~/leaflet/dist/leaflet.css';
|
||||
@import '@fontsource/inter/index.css';
|
||||
@import '@fontsource/archivo-black/index.css';
|
||||
|
||||
|
||||
@tailwind base;
|
||||
@tailwind components;
|
||||
@tailwind utilities;
|
||||
:root {
|
||||
--color-main-background: #ffffff;
|
||||
--color-main-background-rgb: 255,255,255;
|
||||
|
|
|
@ -36,13 +36,24 @@ const logoutItemClick = async () => {
|
|||
await router.post(stardust.route('logout'));
|
||||
};
|
||||
|
||||
const menuClick = (event, item) => {
|
||||
interface MenuItem {
|
||||
name: string;
|
||||
label: string;
|
||||
icon: string;
|
||||
color: string;
|
||||
link: string;
|
||||
}
|
||||
|
||||
const menuClick = (event: Event, item: MenuItem) => {
|
||||
emit('menu-click', event, item);
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<aside id="aside" class="lg:py-2 lg:pl-2 w-60 fixed flex z-40 top-0 h-screen transition-position overflow-hidden">
|
||||
<aside
|
||||
id="aside"
|
||||
class="lg:pb-2 lg:pl-2 w-60 fixed flex z-40 top-0 lg:top-16 h-screen lg:h-[calc(100vh-64px)] transition-position overflow-hidden"
|
||||
>
|
||||
<div :class="styleStore.asideStyle" class="lg:rounded-xl flex-1 flex flex-col overflow-hidden dark:bg-slate-900">
|
||||
<div :class="styleStore.asideBrandStyle" class="flex flex-row h-14 items-center justify-between dark:bg-slate-900">
|
||||
<div class="text-center flex-1 lg:text-left lg:pl-6 xl:text-center xl:pl-0">
|
||||
|
|
|
@ -198,7 +198,7 @@ import DeleteIcon from '@/Components/Icons/Delete.vue';
|
|||
import RefreshIcon from '@/Components/Icons/Refresh.vue';
|
||||
// import { Page, PageProps, Errors, ErrorBag } from '@inertiajs/inertia';
|
||||
import Draggable from 'vuedraggable';
|
||||
import { Buffer } from 'buffer';
|
||||
// import { Buffer } from 'buffer';
|
||||
import { TethysFile } from '@/Dataset';
|
||||
|
||||
// lastModified: 1691759507591
|
||||
|
@ -445,18 +445,19 @@ class FileUploadComponent extends Vue {
|
|||
let localUrl: string = '';
|
||||
if (file instanceof File) {
|
||||
localUrl = URL.createObjectURL(file as Blob);
|
||||
} else if (file.fileData) {
|
||||
// const blob = new Blob([file.fileData]);
|
||||
// localUrl = URL.createObjectURL(blob);
|
||||
const parsed = JSON.parse(file.fileData);
|
||||
file.fileData = '';
|
||||
// retrieve the original buffer of data
|
||||
const buff = Buffer.from(parsed.blob, 'base64');
|
||||
const blob = new Blob([buff], { type: 'application/octet-stream' });
|
||||
// file.blob = blob;
|
||||
localUrl = URL.createObjectURL(blob);
|
||||
file.fileSrc = localUrl;
|
||||
}
|
||||
}
|
||||
// else if (file.fileData) {
|
||||
// // const blob = new Blob([file.fileData]);
|
||||
// // localUrl = URL.createObjectURL(blob);
|
||||
// const parsed = JSON.parse(file.fileData);
|
||||
// file.fileData = '';
|
||||
// // retrieve the original buffer of data
|
||||
// const buff = Buffer.from(parsed.blob, 'base64');
|
||||
// const blob = new Blob([buff], { type: 'application/octet-stream' });
|
||||
// // file.blob = blob;
|
||||
// localUrl = URL.createObjectURL(blob);
|
||||
// file.fileSrc = localUrl;
|
||||
// }
|
||||
|
||||
// setTimeout(() => {
|
||||
// URL.revokeObjectURL(localUrl);
|
||||
|
|
|
@ -1,10 +1,22 @@
|
|||
<script setup lang="ts">
|
||||
import { computed } from 'vue';
|
||||
import { computed, ref } from 'vue';
|
||||
import FormCheckRadio from '@/Components/FormCheckRadio.vue';
|
||||
import BaseButton from '@/Components/BaseButton.vue';
|
||||
import FormControl from '@/Components/FormControl.vue';
|
||||
import { mdiPlusCircle } from '@mdi/js';
|
||||
const props = defineProps({
|
||||
options: {
|
||||
type: Object,
|
||||
default: () => {},
|
||||
default: () => { },
|
||||
},
|
||||
allowManualAdding: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
manualAddingPlaceholder: {
|
||||
type: String,
|
||||
default: 'Add manually',
|
||||
required: false,
|
||||
},
|
||||
name: {
|
||||
type: String,
|
||||
|
@ -55,6 +67,29 @@ const computedValue = computed({
|
|||
const hasIdAttribute = (obj: any): obj is { id: any } => {
|
||||
return typeof obj === 'object' && 'id' in obj;
|
||||
};
|
||||
|
||||
const newOption = ref<string>('');
|
||||
const addOption = () => {
|
||||
if (newOption.value && !props.options[newOption.value]) {
|
||||
props.options[newOption.value] = newOption.value;
|
||||
newOption.value = '';
|
||||
}
|
||||
};
|
||||
|
||||
const inputElClass = computed(() => {
|
||||
const base = [
|
||||
'px-3 py-2 max-w-full focus:ring focus:outline-none border-gray-700 rounded w-full',
|
||||
'dark:placeholder-gray-400',
|
||||
'h-12',
|
||||
'border',
|
||||
'bg-transparent'
|
||||
// props.isReadOnly ? 'bg-gray-50 dark:bg-slate-600' : 'bg-white dark:bg-slate-800',
|
||||
];
|
||||
// if (props.icon) {
|
||||
// base.push('pl-10');
|
||||
// }
|
||||
return base;
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
@ -63,15 +98,17 @@ const hasIdAttribute = (obj: any): obj is { id: any } => {
|
|||
<!-- :label="value" -->
|
||||
<!-- :input-value="value.id"
|
||||
:label="value.name" -->
|
||||
<FormCheckRadio
|
||||
v-for="(value, key) in options"
|
||||
:key="key"
|
||||
v-model="computedValue"
|
||||
:type="type"
|
||||
:name="name"
|
||||
:input-value="key"
|
||||
:label="value"
|
||||
:class="componentClass"
|
||||
/>
|
||||
<div v-if="allowManualAdding && type === 'checkbox'" class="flex items-center mt-2 mb-2 relative">
|
||||
<input v-model="newOption" :placeholder="manualAddingPlaceholder" :class="inputElClass"
|
||||
@keydown.prevent.enter="addOption" />
|
||||
<svg v-show="newOption.length >= 2" @click.prevent="addOption" xmlns="http://www.w3.org/2000/svg"
|
||||
class="w-6 h-6 absolute right-2 top-1/2 transform -translate-y-1/2 cursor-pointer text-gray-500"
|
||||
viewBox="0 0 24 24" fill="currentColor">
|
||||
<path
|
||||
d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm1 17h-2v-6H5v-2h6V5h2v6h6v2h-6v6z" />
|
||||
</svg>
|
||||
</div>
|
||||
<FormCheckRadio v-for="(value, key) in options" :key="key" v-model="computedValue" :type="type" :name="name"
|
||||
:input-value="key" :label="value" :class="componentClass" />
|
||||
</div>
|
||||
</template>
|
||||
|
|
|
@ -268,7 +268,7 @@ export default class DrawControlComponent extends Vue {
|
|||
position: absolute;
|
||||
left: 10px;
|
||||
top: 100px;
|
||||
z-index: 999;
|
||||
z-index: 40;
|
||||
}
|
||||
|
||||
.btn-group-vertical button {
|
||||
|
|
|
@ -372,6 +372,9 @@ export default class MapComponent extends Vue {
|
|||
margin-top: 0.5em;
|
||||
}
|
||||
|
||||
.leaflet-container .leaflet-pane {
|
||||
z-index: 30!important;
|
||||
}
|
||||
/* .leaflet-pane {
|
||||
z-index: 30;
|
||||
} */
|
||||
|
|
|
@ -100,7 +100,7 @@ export default class ZoomControlComponent extends Vue {
|
|||
position: absolute;
|
||||
left: 10px;
|
||||
top: 10px;
|
||||
z-index: 999;
|
||||
z-index: 40;
|
||||
}
|
||||
|
||||
.btn-group-vertical button {
|
||||
|
|
138
resources/js/Components/MimetypeInput.vue
Normal file
138
resources/js/Components/MimetypeInput.vue
Normal file
|
@ -0,0 +1,138 @@
|
|||
<template>
|
||||
<div class="relative mb-4">
|
||||
<!-- <label for="mimetype-input" class="block text-sm font-medium text-gray-700">Search for Mimetypes</label> -->
|
||||
<input id="mimetype-input" v-model="newExtension" type="text" placeholder="Enter Mimetype Name"
|
||||
class="block w-full border border-gray-300 rounded-lg px-4 py-2 focus:ring-blue-500 focus:border-blue-500"
|
||||
:class="inputElClass" @input="handleInputChange" @keydown.down="onArrowDown" @keydown.up="onArrowUp"
|
||||
@keydown.prevent.enter="onEnter">
|
||||
</input>
|
||||
<svg class="w-4 h-4 absolute left-2.5 top-3.5" v-show="newExtension.length < 2"
|
||||
xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
|
||||
d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z" />
|
||||
</svg>
|
||||
<svg class="w-4 h-4 absolute left-2.5 top-3.5" v-show="newExtension.length >= 2"
|
||||
xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor"
|
||||
@click="clearInput">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M6 18L18 6M6 6l12 12" />
|
||||
</svg>
|
||||
|
||||
<ul v-if="showDropdown && filteredMimetypes.length"
|
||||
class="bg-white dark:bg-slate-800 w-full mt-2 max-h-28 overflow-y-auto scroll-smooth">
|
||||
<li v-for="(mimeType, index) in filteredMimetypes" :key="index" @click="selectResult(mimeType)"
|
||||
class="pl-8 pr-2 py-1 border-b-2 border-gray-100 relative cursor-pointer hover:bg-blue-500 hover:text-white"
|
||||
:class="{
|
||||
'bg-blue-500 text-white': selectedIndex === index,
|
||||
'bg-white text-gray-900': selectedIndex !== index
|
||||
}" :ref="(el) => {
|
||||
if (ul) {
|
||||
ul[index] = el as HTMLLIElement;
|
||||
}
|
||||
}">
|
||||
<svg class="absolute w-4 h-4 left-2 top-2" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20"
|
||||
fill="currentColor">
|
||||
<path fill-rule="evenodd"
|
||||
d="M12.293 5.293a1 1 0 011.414 0l4 4a1 1 0 010 1.414l-4 4a1 1 0 01-1.414-1.414L14.586 11H3a1 1 0 110-2h11.586l-2.293-2.293a1 1 0 010-1.414z"
|
||||
clip-rule="evenodd" />
|
||||
</svg>
|
||||
<span>{{ mimeType }}</span>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref, Ref, watch, computed } from 'vue';
|
||||
// import mime from 'mime';
|
||||
|
||||
const emit = defineEmits(['onSelectResult', 'onClearInput'])
|
||||
|
||||
const props = defineProps({
|
||||
borderless: Boolean,
|
||||
transparent: Boolean,
|
||||
mimeTypes: {
|
||||
type: Array as () => string[],
|
||||
required: true
|
||||
},
|
||||
// form: Object,
|
||||
// isValidMimeType: Function,
|
||||
});
|
||||
|
||||
const newExtension = ref('');
|
||||
const showDropdown = ref(false);
|
||||
const filteredMimetypes = ref<string[]>([]);
|
||||
const selectedIndex: Ref<number> = ref(0);
|
||||
const ul: Ref<HTMLLIElement[] | null> = ref<HTMLLIElement[]>([]);
|
||||
|
||||
watch(selectedIndex, (selectedIndex: number) => {
|
||||
if (selectedIndex != null && ul.value != null) {
|
||||
const currentElement: HTMLLIElement = ul.value[selectedIndex];
|
||||
currentElement &&
|
||||
currentElement?.scrollIntoView({
|
||||
behavior: 'smooth',
|
||||
block: 'nearest',
|
||||
inline: 'start',
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
const inputElClass = computed(() => {
|
||||
const base = [
|
||||
'block p-2.5 w-full z-20 text-sm text-gray-900 bg-gray-50 rounded-r-lg',
|
||||
'dark:placeholder-gray-400 dark:text-white dark:focus:border-blue-500',
|
||||
'h-12',
|
||||
props.borderless ? 'border-0' : 'border',
|
||||
props.transparent ? 'bg-transparent' : 'bg-white dark:bg-slate-800',
|
||||
];
|
||||
base.push('pl-10');
|
||||
return base;
|
||||
});
|
||||
|
||||
const handleInputChange = (e: Event) => {
|
||||
const target = <HTMLInputElement>e.target;
|
||||
newExtension.value = target.value;
|
||||
|
||||
if (newExtension.value.length >= 2) {
|
||||
showDropdown.value = true;
|
||||
filteredMimetypes.value = props.mimeTypes.filter(mimeType =>
|
||||
mimeType.toLowerCase().includes(newExtension.value.toLowerCase())
|
||||
);
|
||||
} else {
|
||||
showDropdown.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
const selectResult = (mimeType: string) => {
|
||||
showDropdown.value = false;
|
||||
newExtension.value = '';
|
||||
selectedIndex.value = -1;
|
||||
emit('onSelectResult', mimeType);
|
||||
};
|
||||
|
||||
const clearInput = () => {
|
||||
newExtension.value = '';
|
||||
showDropdown.value = false;
|
||||
// props.form.name = '';
|
||||
// props.resetFileExtensions();
|
||||
emit('onClearInput');
|
||||
};
|
||||
|
||||
const onArrowDown = () => {
|
||||
if (filteredMimetypes.value.length > 0) {
|
||||
selectedIndex.value = selectedIndex.value === filteredMimetypes.value.length - 1 ? 0 : selectedIndex.value + 1;
|
||||
}
|
||||
};
|
||||
|
||||
const onArrowUp = () => {
|
||||
if (filteredMimetypes.value.length > 0) {
|
||||
selectedIndex.value = selectedIndex.value == 0 || selectedIndex.value == -1 ? filteredMimetypes.value.length - 1 : selectedIndex.value - 1;
|
||||
}
|
||||
};
|
||||
|
||||
const onEnter = () => {
|
||||
if (Array.isArray(filteredMimetypes.value) && filteredMimetypes.value.length && selectedIndex.value !== -1 && selectedIndex.value < filteredMimetypes.value.length) {
|
||||
const mimeType = filteredMimetypes.value[selectedIndex.value];
|
||||
selectResult(mimeType);
|
||||
}
|
||||
};
|
||||
</script>
|
|
@ -72,7 +72,7 @@ const menuNavBarToggle = () => {
|
|||
const menuOpenLg = () => {
|
||||
layoutStore.isAsideLgActive = true;
|
||||
};
|
||||
const userHasRoles = (roleNames): boolean => {
|
||||
const userHasRoles = (roleNames: Array<string>): boolean => {
|
||||
return user.value.roles.some(role => roleNames.includes(role.name));
|
||||
};
|
||||
|
||||
|
@ -95,7 +95,7 @@ const showAbout = async () => {
|
|||
</script>
|
||||
|
||||
<template>
|
||||
<nav class="text-base top-0 left-0 right-0 fixed bg-gray-50 h-14 z-40 w-screen transition-position lg:w-auto dark:bg-slate-800"
|
||||
<nav class="text-base top-0 left-0 right-0 fixed bg-lime h-14 z-50 w-screen transition-position lg:w-auto dark:bg-slate-800"
|
||||
:class="{ 'xl:pl-60': props.showBurger == true }">
|
||||
<FirstrunWizard ref="about"></FirstrunWizard>
|
||||
<div class="flex lg:items-stretch" :class="containerMaxW">
|
||||
|
@ -122,10 +122,10 @@ const showAbout = async () => {
|
|||
<BaseIcon :path="isMenuNavBarActive ? mdiClose : mdiDotsVertical" size="24" />
|
||||
</NavBarItem>
|
||||
</div>
|
||||
<div class="absolute w-screen top-14 left-0 bg-gray-50 shadow lg:w-auto lg:items-stretch lg:flex lg:grow lg:static lg:border-b-0 lg:overflow-visible lg:shadow-none dark:bg-slate-800"
|
||||
<div class="fixed w-screen top-14 left-0 shadow lg:w-auto lg:items-stretch lg:flex lg:grow lg:static lg:border-b-0 lg:overflow-visible lg:shadow-none dark:bg-slate-800"
|
||||
:class="[isMenuNavBarActive ? 'block' : 'hidden']">
|
||||
<div
|
||||
class="max-h-screen-menu overflow-y-auto lg:overflow-visible lg:flex lg:items-stretch lg:justify-end lg:ml-auto">
|
||||
class="bg-white lg:bg-lime dark:bg-transparent max-h-screen-menu overflow-y-auto lg:overflow-visible lg:flex lg:items-stretch lg:justify-end lg:ml-auto">
|
||||
|
||||
<!-- help menu -->
|
||||
<NavBarMenu>
|
||||
|
@ -186,7 +186,7 @@ const showAbout = async () => {
|
|||
<NavBarItem is-desktop-icon-only @click.prevent="toggleLightDark">
|
||||
<NavBarItemLabel v-bind:icon="mdiThemeLightDark" label="Light/Dark" is-desktop-icon-only />
|
||||
</NavBarItem>
|
||||
<NavBarItem href="https://gitea.geologie.ac.at/geolba/tethys" target="_blank" is-desktop-icon-only>
|
||||
<NavBarItem href="https://gitea.geosphere.at/geolba/tethys.backend" target="_blank" is-desktop-icon-only>
|
||||
<NavBarItemLabel v-bind:icon="mdiGithub" label="GitHub" is-desktop-icon-only />
|
||||
</NavBarItem>
|
||||
<NavBarItem is-desktop-icon-only @click="showAbout">
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
<script setup>
|
||||
<script lang="ts" setup>
|
||||
import { StyleService } from '@/Stores/style.service';
|
||||
import { computed, ref, onMounted, onBeforeUnmount } from 'vue';
|
||||
import { mdiChevronUp, mdiChevronDown } from '@mdi/js';
|
||||
|
@ -15,10 +15,10 @@ const toggle = () => {
|
|||
isDropdownActive.value = !isDropdownActive.value;
|
||||
};
|
||||
|
||||
const root = ref(null);
|
||||
const root = ref(NavBarItem);
|
||||
|
||||
const forceClose = (event) => {
|
||||
if (!root.value.$el.contains(event.target)) {
|
||||
const forceClose = (event: MouseEvent) => {
|
||||
if (!root.value?.$el.contains(event.target)) {
|
||||
isDropdownActive.value = false;
|
||||
}
|
||||
};
|
||||
|
|
|
@ -5,9 +5,9 @@ import SectionBanner from '@/Components/SectionBanner.vue';
|
|||
</script>
|
||||
<template>
|
||||
<SectionBanner bg="greenBlue">
|
||||
<h1 class="text-3xl text-white mb-6">Like the project? Please star on <b>Gitea</b>!</h1>
|
||||
<h1 class="text-3xl text-white mb-6">Like the project? Please star on <b>GeoSphere Git Repository</b>!</h1>
|
||||
<div>
|
||||
<BaseButton href="https://gitea.geologie.ac.at/geolba/tethys" :icon="mdiGithub" label="Gitea" target="_blank" rounded-full />
|
||||
<BaseButton href="https://gitea.geosphere.at/geolba/tethys.backend" :icon="mdiGithub" label="Forgejo" target="_blank" rounded-full />
|
||||
</div>
|
||||
</SectionBanner>
|
||||
</template>
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<script lang="ts" setup>
|
||||
import { ref, watch, computed, Ref, reactive } from 'vue';
|
||||
import { ref, reactive } from 'vue';
|
||||
import { Head, useForm } from '@inertiajs/vue3';
|
||||
import { mdiAccountKey, mdiArrowLeftBoldOutline } from '@mdi/js';
|
||||
import { mdiAccountKey, mdiArrowLeftBoldOutline, mdiTrashCan, mdiImageText, mdiPlus } from '@mdi/js';
|
||||
import LayoutAuthenticated from '@/Layouts/LayoutAuthenticated.vue';
|
||||
import SectionMain from '@/Components/SectionMain.vue';
|
||||
import SectionTitleLineWithButton from '@/Components/SectionTitleLineWithButton.vue';
|
||||
|
@ -10,115 +10,97 @@ import BaseDivider from '@/Components/BaseDivider.vue';
|
|||
import BaseButton from '@/Components/BaseButton.vue';
|
||||
import BaseButtons from '@/Components/BaseButtons.vue';
|
||||
import { stardust } from '@eidellev/adonis-stardust/client';
|
||||
import mime from 'mime';
|
||||
import FormField from '@/Components/FormField.vue';
|
||||
import FormControl from '@/Components/FormControl.vue';
|
||||
import standardTypes from 'mime/types/standard.js';
|
||||
import otherTypes from 'mime/types/other.js';
|
||||
import FormCheckRadioGroup from '@/Components/FormCheckRadioGroup.vue';
|
||||
import MimetypeInput from '@/Components/MimetypeInput.vue';
|
||||
|
||||
const props = defineProps({
|
||||
permissions: {
|
||||
type: Object,
|
||||
default: () => ({}),
|
||||
},
|
||||
defineProps({
|
||||
borderless: Boolean,
|
||||
transparent: Boolean,
|
||||
ctrlKFocus: Boolean,
|
||||
});
|
||||
|
||||
const customTypes: { [key: string]: string[] } = {
|
||||
'application/vnd.opengeospatial.geopackage+sqlite3': ['gpkg'],
|
||||
'text/plain': ['txt', 'asc', 'c', 'cc', 'h', 'srt'],
|
||||
};
|
||||
|
||||
const isReadOnly: boolean = true;
|
||||
const standardMimeTypes = Object.keys(standardTypes);
|
||||
const otherMimeTypes = Object.keys(otherTypes);
|
||||
const mimeTypes = [...standardMimeTypes, ...otherMimeTypes];
|
||||
// const standardMimeTypes = Object.keys(standardTypes);
|
||||
// const otherMimeTypes = Object.keys(otherTypes);
|
||||
// const customMimeTypes = Object.keys(customTypes);
|
||||
const mimeTypesMap = new Map<string, string[]>();
|
||||
|
||||
Object.entries(standardTypes).forEach(([mimeType, extensions]) => {
|
||||
mimeTypesMap.set(mimeType, extensions);
|
||||
});
|
||||
|
||||
Object.entries(otherTypes).forEach(([mimeType, extensions]) => {
|
||||
mimeTypesMap.set(mimeType, extensions);
|
||||
});
|
||||
|
||||
Object.entries(customTypes).forEach(([mimeType, extensions]) => {
|
||||
mimeTypesMap.set(mimeType, extensions);
|
||||
});
|
||||
|
||||
const mimeTypes = Array.from(mimeTypesMap.keys());
|
||||
|
||||
const file_extensions = reactive<Record<string, string>>({});
|
||||
interface FormData {
|
||||
name: string;
|
||||
file_extension: string[];
|
||||
alternate_mimetype: string[];
|
||||
enabled: boolean;
|
||||
[key: string]: string | string[] | boolean;
|
||||
}
|
||||
const form = useForm<FormData>({
|
||||
name: '',
|
||||
file_extension: [],
|
||||
alternate_mimetype: [],
|
||||
enabled: true,
|
||||
});
|
||||
|
||||
const filteredMimetypes = ref<string[]>([]); // Stores the filtered MIME types for the dropdown
|
||||
const showDropdown = ref(false); // Controls the visibility of the autocomplete dropdown
|
||||
const selectedIndex: Ref<number> = ref(0); // Track selected MIME type in the dropdown
|
||||
const ul: Ref<HTMLLIElement[] | null> = ref<HTMLLIElement[]>([]);
|
||||
const newExtension: Ref = ref(''); //reactive([] as Array<string>);
|
||||
const mimetypeError = ref<string | null>(null);
|
||||
|
||||
watch(selectedIndex, (selectedIndex: number) => {
|
||||
if (selectedIndex != null && ul.value != null) {
|
||||
const currentElement: HTMLLIElement = ul.value[selectedIndex];
|
||||
currentElement &&
|
||||
currentElement?.scrollIntoView({
|
||||
behavior: 'smooth',
|
||||
block: 'nearest',
|
||||
inline: 'start',
|
||||
});
|
||||
}
|
||||
});
|
||||
const addAlternateMimetype = () => {
|
||||
form.alternate_mimetype.push("");
|
||||
};
|
||||
const removeAliasMimetype = (index: number) => {
|
||||
form.alternate_mimetype.splice(index, 1);
|
||||
};
|
||||
|
||||
// Function to reset the object
|
||||
function resetFileExtensions() {
|
||||
// Reset to an empty object
|
||||
Object.keys(file_extensions).forEach(key => {
|
||||
delete file_extensions[key];
|
||||
});
|
||||
}
|
||||
|
||||
const inputElClass = computed(() => {
|
||||
const base = [
|
||||
'block p-2.5 w-full z-20 text-sm text-gray-900 bg-gray-50 rounded-r-lg',
|
||||
'dark:placeholder-gray-400 dark:text-white dark:focus:border-blue-500',
|
||||
'h-12',
|
||||
props.borderless ? 'border-0' : 'border',
|
||||
props.transparent ? 'bg-transparent' : 'bg-white dark:bg-slate-800',
|
||||
];
|
||||
// if (props.icon) {
|
||||
base.push('pl-10');
|
||||
// }
|
||||
return base;
|
||||
});
|
||||
|
||||
// Check if the MIME type is valid
|
||||
const isValidMimeType = (mimeType: string): boolean => {
|
||||
let extensions = mime.getExtension(mimeType)
|
||||
let extensions = mimeTypesMap.get(mimeType) || null;
|
||||
return extensions !== null;
|
||||
};
|
||||
|
||||
async function handleInputChange(e: Event) {
|
||||
const target = <HTMLInputElement>e.target;
|
||||
newExtension.value = target.value;
|
||||
const clearInput = () => {
|
||||
// newExtension.value = '';
|
||||
// showDropdown.value = false;
|
||||
form.name = '';
|
||||
resetFileExtensions();
|
||||
};
|
||||
|
||||
if (newExtension.value.length >= 2) {
|
||||
showDropdown.value = true;
|
||||
filteredMimetypes.value = mimeTypes.filter(mimeType =>
|
||||
mimeType.toLowerCase().includes(newExtension.value.toLowerCase())
|
||||
);
|
||||
} else {
|
||||
// data.results = [];
|
||||
showDropdown.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
// Handle MIME type selection from the dropdown
|
||||
const selectResult = (mimeType: string) => {
|
||||
form.name = mimeType;
|
||||
// file_extensions.values = [];
|
||||
resetFileExtensions();
|
||||
showDropdown.value = false;
|
||||
newExtension.value = ''; // Reset the input
|
||||
selectedIndex.value = -1;
|
||||
// showDropdown.value = false;
|
||||
// newExtension.value = '';
|
||||
// selectedIndex.value = -1;
|
||||
|
||||
if (form.name && isValidMimeType(form.name)) {
|
||||
const extensions = mime.getAllExtensions(form.name) as Set<string>;
|
||||
// Iterate over each extension and set both key and value to the extension
|
||||
Array.from(extensions).forEach(extension => {
|
||||
// const extensions = mime.getAllExtensions(form.name) as Set<string>;
|
||||
const extensions = mimeTypesMap.get(mimeType);
|
||||
extensions?.forEach(extension => {
|
||||
file_extensions[extension] = extension;
|
||||
});
|
||||
} else {
|
||||
|
@ -126,61 +108,14 @@ const selectResult = (mimeType: string) => {
|
|||
}
|
||||
};
|
||||
|
||||
function onArrowDown() {
|
||||
if (filteredMimetypes.value.length > 0) {
|
||||
selectedIndex.value = selectedIndex.value === filteredMimetypes.value.length - 1 ? 0 : selectedIndex.value + 1;
|
||||
// const currentElement: HTMLLIElement = ul.value[selectedIndex.value];
|
||||
}
|
||||
}
|
||||
|
||||
function onArrowUp() {
|
||||
if (filteredMimetypes.value.length > 0) {
|
||||
selectedIndex.value = selectedIndex.value == 0 || selectedIndex.value == -1 ? filteredMimetypes.value.length - 1 : selectedIndex.value - 1;
|
||||
}
|
||||
}
|
||||
|
||||
function onEnter() {
|
||||
if (Array.isArray(filteredMimetypes.value) && filteredMimetypes.value.length && selectedIndex.value !== -1 && selectedIndex.value < filteredMimetypes.value.length) {
|
||||
const mimeType = filteredMimetypes.value[selectedIndex.value];
|
||||
// this.$emit('person', person);
|
||||
form.name = mimeType;
|
||||
// reset form file extensions
|
||||
// file_extensions.values = [];
|
||||
resetFileExtensions();
|
||||
showDropdown.value = false;
|
||||
newExtension.value = ''; // Reset the input
|
||||
selectedIndex.value = -1;
|
||||
if (form.name) {
|
||||
// clear all loaded file extensions
|
||||
// file_extensions.values = [];
|
||||
resetFileExtensions();
|
||||
if (isValidMimeType(form.name)) {
|
||||
let extensions = mime.getAllExtensions(form.name) as Set<string>;
|
||||
// Convert the Set to an array of objects
|
||||
// Convert the Set to an object
|
||||
Array.from(extensions).forEach(extension => {
|
||||
file_extensions[extension] = extension;
|
||||
});
|
||||
|
||||
// file_extensions.push(...formattedExtensions);
|
||||
} else {
|
||||
mimetypeError.value = 'Invalid MIME type.';
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Handle form submission
|
||||
const submit = async () => {
|
||||
if (isValidForm()) {
|
||||
await form.post(stardust.route('settings.mimetype.store'), {
|
||||
preserveScroll: true,
|
||||
});
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
// Form validation before submission
|
||||
const isValidForm = (): boolean => {
|
||||
if (!form.name) {
|
||||
form.errors.name = 'Name is required.';
|
||||
|
@ -190,6 +125,7 @@ const isValidForm = (): boolean => {
|
|||
}
|
||||
if (!form.file_extension.length) {
|
||||
form.errors.file_extension = 'At least one file extension is required.';
|
||||
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
|
@ -205,59 +141,15 @@ const isValidForm = (): boolean => {
|
|||
<BaseButton :route-name="stardust.route('settings.mimetype.index')" :icon="mdiArrowLeftBoldOutline"
|
||||
label="Back" color="white" rounded-full small />
|
||||
</SectionTitleLineWithButton>
|
||||
<!-- <CardBox form @submit.prevent="form.post(stardust.route('role.store'))"> -->
|
||||
<CardBox form @submit.prevent="submit()">
|
||||
|
||||
<!-- MIME Type Input Field with Autocomplete -->
|
||||
<div class="relative mb-4">
|
||||
|
||||
<input v-model="newExtension" type="text" placeholder="Enter Mimetype Name"
|
||||
class="block w-full border border-gray-300 rounded-lg px-4 py-2 focus:ring-blue-500 focus:border-blue-500"
|
||||
:class="inputElClass" @input="handleInputChange" @keydown.down="onArrowDown"
|
||||
@keydown.up="onArrowUp" @keydown.prevent.enter="onEnter">
|
||||
</input>
|
||||
<svg class="w-4 h-4 absolute left-2.5 top-3.5" v-show="newExtension.length < 2"
|
||||
xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
|
||||
d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z" />
|
||||
</svg>
|
||||
<svg class="w-4 h-4 absolute left-2.5 top-3.5" v-show="newExtension.length >= 2"
|
||||
xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor" @click="() => {
|
||||
newExtension = '';
|
||||
showDropdown = false;
|
||||
form.name = '';
|
||||
resetFileExtensions();
|
||||
}
|
||||
">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M6 18L18 6M6 6l12 12" />
|
||||
</svg>
|
||||
|
||||
<ul v-if="showDropdown && filteredMimetypes.length"
|
||||
class="bg-white dark:bg-slate-800 w-full mt-2 max-h-28 overflow-y-auto scroll-smooth">
|
||||
<li v-for="(mimeType, index) in filteredMimetypes" :key="index" @click="selectResult(mimeType)"
|
||||
class="pl-8 pr-2 py-1 border-b-2 border-gray-100 relative cursor-pointer hover:bg-blue-500 hover:text-white"
|
||||
:class="{
|
||||
'bg-blue-500 text-white': selectedIndex === index,
|
||||
'bg-white text-gray-900': selectedIndex !== index
|
||||
}" :ref="(el) => {
|
||||
if (ul) {
|
||||
ul[index] = el as HTMLLIElement;
|
||||
}
|
||||
}">
|
||||
<svg class="absolute w-4 h-4 left-2 top-2" xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 20 20" fill="currentColor">
|
||||
<path fill-rule="evenodd"
|
||||
d="M12.293 5.293a1 1 0 011.414 0l4 4a1 1 0 010 1.414l-4 4a1 1 0 01-1.414-1.414L14.586 11H3a1 1 0 110-2h11.586l-2.293-2.293a1 1 0 010-1.414z"
|
||||
clip-rule="evenodd" />
|
||||
</svg>
|
||||
<span>{{ mimeType }}</span>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<CardBox form>
|
||||
<MimetypeInput @on-select-result="selectResult" @on-clear-input="clearInput" :transparent="transparent"
|
||||
:borderless="borderless" :mimeTypes="mimeTypes" :isValidMimeType="isValidMimeType" />
|
||||
<div v-if="mimetypeError" class="text-red-400 text-sm mt-1">
|
||||
{{ mimetypeError }}
|
||||
</div>
|
||||
|
||||
<BaseDivider v-if="form.name" />
|
||||
|
||||
<FormField v-if="form.name" label="Mimetype Name" :class="{ 'text-red-400': form.errors.name }">
|
||||
<FormControl v-model="form.name" name="display_name" :error="form.errors.name"
|
||||
:is-read-only=isReadOnly>
|
||||
|
@ -266,34 +158,79 @@ const isValidForm = (): boolean => {
|
|||
</div>
|
||||
</FormControl>
|
||||
</FormField>
|
||||
|
||||
|
||||
<FormField v-if="form.name" help="Activate mimetype immediately?" wrap-body
|
||||
<!-- <FormField v-if="form.name" help="Activate mimetype immediately?" wrap-body
|
||||
class="mt-8 w-full mx-2 flex-1 flex-col">
|
||||
<label for="rights" class="checkbox mr-6 mb-3 last:mr-0">
|
||||
<input type="checkbox" id="rights" required v-model="form.enabled" />
|
||||
<span class="check" />
|
||||
<a class="pl-2" target="_blank">Enable mimetype immediately </a>
|
||||
|
||||
</label>
|
||||
</FormField>
|
||||
|
||||
<FormField label="Extensions" wrap-body>
|
||||
</FormField> -->
|
||||
<FormField v-if="Object.keys(file_extensions).length > 0" label="File Extensions" wrap-body>
|
||||
<!-- <div class="flex items-center mt-2">
|
||||
<FormControl v-model="newExtension" placeholder="Enter file extension" class="mr-2" />
|
||||
<BaseButton color="info" @click="addFileExtension" label="Add" />
|
||||
</div> -->
|
||||
<FormCheckRadioGroup v-model="form.file_extension" :options="file_extensions" name="file_extensions"
|
||||
is-column />
|
||||
is-column allow-manual-adding manual-adding-placeholder="Enter additional file extension manually" />
|
||||
|
||||
</FormField>
|
||||
<div class="text-red-400 text-sm"
|
||||
v-if="form.errors.file_extension && Array.isArray(form.errors.file_extension)">
|
||||
{{ form.errors.file_extension.join(', ') }}
|
||||
<div class="text-red-400 text-sm" v-if="form.errors.file_extension">
|
||||
{{ form.errors.file_extension }}
|
||||
</div>
|
||||
|
||||
<BaseDivider />
|
||||
<BaseDivider v-if="Object.keys(file_extensions).length > 0" />
|
||||
|
||||
<CardBox v-if="form.name" class="mb-6 shadow" has-table :icon="mdiImageText" title="Alternate Mimetypes"
|
||||
:header-icon="mdiPlus" @header-icon-click="addAlternateMimetype">
|
||||
<div v-if="form.alternate_mimetype.length === 0" class="text-center py-4">
|
||||
<p class="text-gray-600">No alternate mimetypes added yet.</p>
|
||||
<p class="text-gray-400">
|
||||
Click the plus icon above to add a new alternate mimetype.
|
||||
<br>
|
||||
An alternate mimetype is needed to ensure compatibility across different systems and
|
||||
software.
|
||||
For example, the GeoPackage standard mimetype is
|
||||
'application/vnd.opengeospatial.geopackage+sqlite3', but most software stores it as
|
||||
'application/x-sqlite3'. Therefore, 'application/x-sqlite3' must be added as an alternate
|
||||
mimetype.
|
||||
</p>
|
||||
</div>
|
||||
<table class="table-fixed border-green-900" v-if="form.alternate_mimetype.length > 0">
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="w-10/12">Alias Mimetype</th>
|
||||
<th class="w-2/12"></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr v-for="(alias, index) in form.alternate_mimetype" :key="index">
|
||||
<td>
|
||||
<FormControl required v-model="form.alternate_mimetype[index]"
|
||||
placeholder="[alternate mimetype]">
|
||||
<div class="text-red-400 text-sm"
|
||||
v-if="Array.isArray(form.errors[`alternate_mimetype.${index}`])">
|
||||
{{ form.errors[`alternate_mimetype.${index}`]?.join(', ') }}
|
||||
</div>
|
||||
</FormControl>
|
||||
</td>
|
||||
<td class="before:hidden lg:w-1 whitespace-nowrap">
|
||||
<BaseButton color="danger" :icon="mdiTrashCan" small
|
||||
@click.prevent="removeAliasMimetype(index)" />
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<div class="text-red-400 text-sm"
|
||||
v-if="form.errors.alternate_mimetype && Array.isArray(form.errors.alternate_mimetype)">
|
||||
{{ form.errors.alternate_mimetype.join(', ') }}
|
||||
</div>
|
||||
</CardBox>
|
||||
|
||||
<template #footer>
|
||||
<BaseButtons>
|
||||
<BaseButton type="submit" color="info" label="Create" :class="{ 'opacity-25': form.processing }"
|
||||
:disabled="form.processing" />
|
||||
:disabled="form.processing" @click.prevent="submit()" />
|
||||
</BaseButtons>
|
||||
</template>
|
||||
</CardBox>
|
||||
|
|
|
@ -32,7 +32,7 @@ const form = useForm({
|
|||
// isPreferationRequired: false,
|
||||
});
|
||||
|
||||
const handleSubmit = async (e) => {
|
||||
const handleSubmit = async (e: Event) => {
|
||||
e.preventDefault();
|
||||
await form.delete(stardust.route('settings.mimetype.deleteStore', [props.mimetype.id]));
|
||||
};
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<script lang="ts" setup>
|
||||
import { Head, usePage } from '@inertiajs/vue3';
|
||||
import { mdiAccountKey, mdiSquareEditOutline, mdiAlertBoxOutline, mdiPlus, mdiTrashCan } from '@mdi/js';
|
||||
import { mdiAccountKey, mdiSquareEditOutline, mdiAlertBoxOutline, mdiPlus, mdiTrashCan, mdiCheckCircle, mdiCloseCircle } from '@mdi/js';
|
||||
import { computed, ComputedRef } from 'vue';
|
||||
import type { PropType } from "vue";
|
||||
import LayoutAuthenticated from '@/Layouts/LayoutAuthenticated.vue';
|
||||
|
@ -16,6 +16,7 @@ interface MimeType {
|
|||
id: number;
|
||||
name: string;
|
||||
file_extension: string;
|
||||
alternate_mimetype: string;
|
||||
enabled: boolean;
|
||||
}
|
||||
|
||||
|
@ -54,24 +55,41 @@ const flash: ComputedRef<any> = computed(() => {
|
|||
{{ flash.message }}
|
||||
</NotificationBar>
|
||||
<CardBox class="mb-6" has-table>
|
||||
<table>
|
||||
<table class="min-w-full divide-y divide-gray-200">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Name</th>
|
||||
<th>Status</th>
|
||||
<th v-if="can.edit">Actions</th>
|
||||
<th class="px-4 py-2 text-left text-sm font-medium uppercase tracking-wider">Mimetype</th>
|
||||
<th class="px-4 py-2 text-left text-sm font-medium uppercase tracking-wider">Alternate Mime Types</th>
|
||||
<th v-if="can.edit" class="px-4 py-2 text-left text-sm font-medium uppercase tracking-wider">Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tbody class="divide-y divide-gray-200">
|
||||
<tr v-for="mimetype in mimetypes" :key="mimetype.id">
|
||||
<td data-label="Name">
|
||||
{{ mimetype.name }} ({{ mimetype.file_extension }})
|
||||
<td class="px-4 py-2 whitespace-nowrap text-left text-sm" data-label="Name">
|
||||
<span class="flex items-center">
|
||||
<svg viewBox="0 0 24 24" v-if="mimetype.enabled" :class="{'text-green-500': mimetype.enabled}" class="w-4 h-4 mr-2">
|
||||
<path fill="currentColor" :d="mdiCheckCircle" />
|
||||
</svg>
|
||||
<svg v-else viewBox="0 0 24 24" :class="{'text-red-500': !mimetype.enabled}" class="w-4 h-4 mr-2">
|
||||
<path fill="currentColor" :d="mdiCloseCircle" />
|
||||
</svg>
|
||||
<br>
|
||||
<span class="truncate block max-w-xs">{{ mimetype.name }}</span>
|
||||
</span>
|
||||
<ul class="list-none pl-0">
|
||||
<li v-for="ext in mimetype.file_extension?.split('|')" :key="ext" class="flex items-center truncate block max-w-xs">- .{{ ext }}</li>
|
||||
</ul>
|
||||
</td>
|
||||
<td data-label="Status">
|
||||
<td class="px-4 py-2 whitespace-nowrap text-left text-sm" data-label="Alternate Mime Types">
|
||||
<ul class="list-none pl-0">
|
||||
<li v-for="alt in mimetype.alternate_mimetype?.split('|')" :key="alt" class="flex items-center truncate block max-w-xs">- {{ alt }}</li>
|
||||
</ul>
|
||||
</td>
|
||||
<!-- <td class="px-4 py-2 whitespace-nowrap" data-label="Status">
|
||||
<template v-if="mimetype.enabled">Active</template>
|
||||
<template v-else>Inactive</template>
|
||||
</td>
|
||||
<td v-if="can.edit" class="before:hidden lg:w-1 whitespace-nowrap">
|
||||
</td> -->
|
||||
<td v-if="can.edit" class="before:hidden lg:w-1 whitespace-nowrap px-4 py-2 whitespace-nowrap text-left text-sm">
|
||||
<BaseButtons type="justify-start lg:justify-end" no-wrap>
|
||||
<BaseButton v-if="mimetype.enabled"
|
||||
:route-name="stardust.route('settings.mimetype.down', [mimetype.id])"
|
||||
|
|
|
@ -28,7 +28,7 @@ const form = useForm({
|
|||
});
|
||||
|
||||
const submit = async () => {
|
||||
await form.post(stardust.route('settings.role.store'), form);
|
||||
await form.post(stardust.route('settings.role.store'));
|
||||
};
|
||||
</script>
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<script setup>
|
||||
import { Head, Link, useForm } from '@inertiajs/vue3';
|
||||
<script setup lang="ts">
|
||||
import { Head, useForm } from '@inertiajs/vue3';
|
||||
import { mdiAccountKey, mdiArrowLeftBoldOutline, mdiFormTextarea } from '@mdi/js';
|
||||
import LayoutAuthenticated from '@/Layouts/LayoutAuthenticated.vue';
|
||||
import SectionMain from '@/Components/SectionMain.vue';
|
||||
|
@ -29,15 +29,15 @@ const props = defineProps({
|
|||
});
|
||||
|
||||
const form = useForm({
|
||||
_method: 'put',
|
||||
name: props.role.name,
|
||||
description: props.role.description,
|
||||
permissions: props.roleHasPermissions,
|
||||
});
|
||||
|
||||
const submit = async () => {
|
||||
// await Inertia.post(stardust.route('user.store'), form);
|
||||
await form.put(stardust.route('settings.role.update', [props.role.id]), form);
|
||||
// await Inertia.post(stardust.route('user.store'), form); old
|
||||
await form.put(stardust.route('settings.role.update', [props.role.id]));
|
||||
// await router.put(stardust.route('settings.role.update', [props.role.id]), form);
|
||||
};
|
||||
</script>
|
||||
|
||||
|
@ -58,7 +58,7 @@ const submit = async () => {
|
|||
<!-- <CardBox form @submit.prevent="form.put(stardust.route('role.update', [props.role.id]))"> -->
|
||||
<CardBox form @submit.prevent="submit()">
|
||||
<FormField label="Name" :class="{ 'text-red-400': form.errors.name }">
|
||||
<FormControl v-model="form.name" type="text" placeholder="Enter Name" required :error="form.errors.name" is-read-only="true">
|
||||
<FormControl v-model="form.name" type="text" placeholder="Enter Name" required :error="form.errors.name" :is-read-only=true>
|
||||
<div class="text-red-400 text-sm" v-if="form.errors.name">
|
||||
{{ form.errors.name }}
|
||||
</div>
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
<!-- <SectionFullScreen v-slot="{ cardClass }" :bg="'greenBlue'"> -->
|
||||
<SectionFullScreen v-slot="{ cardClass }">
|
||||
<a class="text-2xl font-semibold flex justify-center items-center mb-8 lg:mb-10">
|
||||
<img src="/logo.svg" class="h-10 mr-4" alt="Windster Logo" />
|
||||
<img src="../../logo.svg" class="h-10 mr-4" alt="Windster Logo" />
|
||||
<!-- <span class="self-center text-2xl font-bold whitespace-nowrap">Tethys</span> -->
|
||||
</a>
|
||||
|
||||
|
|
|
@ -20,7 +20,7 @@
|
|||
import AuthLayout from '@/Layouts/Auth.vue';
|
||||
import { reactive } from 'vue';
|
||||
import { useForm } from '@inertiajs/vue3';
|
||||
import { Inertia } from '@inertiajs/inertia';
|
||||
// import { Inertia } from '@inertiajs/inertia';
|
||||
// import { NButton, NInput } from 'naive-ui';
|
||||
// import { useForm } from '@inertiajs/inertia-vue3'
|
||||
import FormInput from '@/Components/FormInput.vue';
|
||||
|
@ -45,7 +45,7 @@ export default {
|
|||
});
|
||||
|
||||
const submit = async () => {
|
||||
await Inertia.post('/app/register', form);
|
||||
// await Inertia.post('/app/register', form);
|
||||
};
|
||||
|
||||
return { form, submit };
|
||||
|
|
|
@ -69,10 +69,10 @@ const datasets = computed(() => mainService.datasets);
|
|||
<SectionMain>
|
||||
<SectionTitleLineWithButton v-bind:icon="mdiChartTimelineVariant" title="Overview" main>
|
||||
<BaseButton
|
||||
href="https://gitea.geologie.ac.at/geolba/tethys"
|
||||
href="https://gitea.geosphere.at/geolba/tethys.backend"
|
||||
target="_blank"
|
||||
:icon="mdiGithub"
|
||||
label="Star on Gitea"
|
||||
label="Star on GeoSphere Forgejo"
|
||||
color="contrast"
|
||||
rounded-full
|
||||
small
|
||||
|
|
|
@ -4,10 +4,10 @@
|
|||
<h1 class="text-xl font-bold">SKOS Browser</h1>
|
||||
<div class="flex space-x-2">
|
||||
<button @click="updateApp" title="Update the application">
|
||||
<img src="/Resources/Images/refresh.png" alt="Update" class="w-4 h-4" />
|
||||
<!-- <img src="/Resources/Images/refresh.png" alt="Update" class="w-4 h-4" /> -->
|
||||
</button>
|
||||
<button @click="showInfo" title="Info">
|
||||
<img src="/Resources/Images/info.png" alt="Info" class="w-4 h-4" />
|
||||
<!-- <img src="/Resources/Images/info.png" alt="Info" class="w-4 h-4" /> -->
|
||||
</button>
|
||||
</div>
|
||||
</header>
|
||||
|
|
|
@ -45,7 +45,7 @@ import { LayerOptions } from '@/Components/Map/LayerOptions';
|
|||
import TableKeywords from '@/Components/TableKeywords.vue';
|
||||
import NotificationBar from '@/Components/NotificationBar.vue';
|
||||
import FileUploadComponent from '@/Components/FileUpload.vue';
|
||||
import Person from '#models/person';
|
||||
import type Person from '#models/person';
|
||||
|
||||
const props = defineProps({
|
||||
licenses: {
|
||||
|
@ -96,6 +96,27 @@ const flash: ComputedRef<any> = computed(() => {
|
|||
return usePage().props.flash;
|
||||
});
|
||||
|
||||
// Computed property to determine the placeholder based on the selected option
|
||||
const getPlaceholder = computed(() => (type: string) => {
|
||||
|
||||
switch (type) {
|
||||
case 'DOI':
|
||||
return 'https://doi.org/10.24341/tethys.236';
|
||||
case 'Handle':
|
||||
return '20.500.12345/67890';
|
||||
case 'ISBN':
|
||||
return '978-3-85316-076-3';
|
||||
case 'ISSN':
|
||||
return '1234-5678';
|
||||
case 'URL':
|
||||
return 'https://example.com';
|
||||
case 'URN':
|
||||
return 'urn:nbn:de:1234-5678';
|
||||
default:
|
||||
return '[VALUE]';
|
||||
}
|
||||
});
|
||||
|
||||
const mainService = MainService();
|
||||
|
||||
// let serrors = reactive([]);
|
||||
|
@ -1050,7 +1071,7 @@ Removes a selected keyword
|
|||
<!-- <input name="Reference Value" class="form-control"
|
||||
placeholder="[VALUE]" v-model="item.value" /> -->
|
||||
<FormControl required v-model="item.value" :type="'text'"
|
||||
placeholder="[VALUE]" :errors="form.errors.embargo_date">
|
||||
:placeholder="getPlaceholder(form.references[index].type)" :errors="form.errors.embargo_date">
|
||||
<div class="text-red-400 text-sm"
|
||||
v-if="form.errors[`references.${index}.value`] && Array.isArray(form.errors[`references.${index}.value`])">
|
||||
{{ form.errors[`references.${index}.value`].join(', ') }}
|
||||
|
|
|
@ -9,8 +9,8 @@ import { StyleService } from '@/Stores/style.service';
|
|||
import { LayoutService } from '@/Stores/layout';
|
||||
import { LocaleStore } from '@/Stores/locale';
|
||||
import { darkModeKey, styleKey } from '@/config';
|
||||
// import type { DefineComponent } from 'vue';
|
||||
// import { resolvePageComponent } from '@adonisjs/inertia/helpers';
|
||||
import type { DefineComponent } from 'vue';
|
||||
import { resolvePageComponent } from '@adonisjs/inertia/helpers';
|
||||
const pinia = createPinia();
|
||||
// import i18n from './i18n';
|
||||
import { EmitterPlugin } from '@/EmitterDirective';
|
||||
|
@ -37,32 +37,19 @@ createInertiaApp({
|
|||
// color: '#4B5563',
|
||||
color: '#22C55E',
|
||||
},
|
||||
// Webpack
|
||||
// resolve: (name) => require(`./Pages/${name}`),
|
||||
// resolve: (name) => require(`./Pages/${name}.vue`),
|
||||
// add default layout
|
||||
// resolve: (name) => {
|
||||
// const page = require(`./Pages/${name}.vue`).default;
|
||||
// Webpack
|
||||
// resolve: async (name: string) => {
|
||||
// // Dynamically import the Vue component using import
|
||||
// const { default: page } = await import(`./Pages/${name}.vue`);
|
||||
// // const page = require(`./Pages/${name}.vue`).default;
|
||||
// // if (!page.layout) {
|
||||
// // page.layout = DefaultLayout;
|
||||
// // }
|
||||
// return page;
|
||||
// },
|
||||
resolve: async (name: string) => {
|
||||
// Dynamically import the Vue component using import
|
||||
const { default: page } = await import(`./Pages/${name}.vue`);
|
||||
// const page = require(`./Pages/${name}.vue`).default;
|
||||
// if (!page.layout) {
|
||||
// page.layout = DefaultLayout;
|
||||
// }
|
||||
return page;
|
||||
resolve: (name) => {
|
||||
return resolvePageComponent(`./Pages/${name}.vue`, import.meta.glob<DefineComponent>('./Pages/**/*.vue'));
|
||||
},
|
||||
// resolve: (name) => {
|
||||
// return resolvePageComponent(
|
||||
// `./Pages/${name}.vue`,
|
||||
// import.meta.glob<DefineComponent>('./pages/**/*.vue'),
|
||||
// )
|
||||
// },
|
||||
|
||||
setup({ el, App, props, plugin }) {
|
||||
const app = createApp({ render: () => h(App, props) })
|
||||
|
@ -72,11 +59,16 @@ createInertiaApp({
|
|||
.use(EmitterPlugin);
|
||||
// .component('inertia-link', Link)
|
||||
|
||||
// Listen for navigation event to handle layout changes
|
||||
// window.addEventListener('inertia:navigate', () => {
|
||||
// layoutService.isAsideMobileExpanded = false;
|
||||
// layoutService.isAsideLgActive = false;
|
||||
// });
|
||||
|
||||
asyncPlugin.install('settings').then(() => {
|
||||
app.mount(el);
|
||||
});
|
||||
},
|
||||
|
||||
});
|
||||
|
||||
const styleService = StyleService(pinia);
|
||||
|
|
183
resources/js/logo.svg
Normal file
183
resources/js/logo.svg
Normal file
|
@ -0,0 +1,183 @@
|
|||
<!-- <svg width="60" height="59" viewBox="0 0 60 59" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path
|
||||
d="M22.0604 27.0103C29.7333 23.0893 35.8474 16.6142 39.6254 8.51905C40.1123 7.47585 39.871 6.25371 39.3648 5.21976C38.1966 2.83369 37.9273 0.35731 31.5792 1.07481L29.0769 1.19405C30.0128 1.19405 29.5449 1.19405 29.0769 1.19405C26.2213 9.83921 20.8705 16.9667 13.0175 20.9078C7.54419 23.7048 3.49869 28.7902 1.59493 34.8927L1.08063 36.5412C1.02718 36.7125 0.953783 36.7439 1.03271 36.905V36.905C1.69551 38.2585 2.41237 37.8338 1.24774 36.8773C-0.0162787 35.8391 4.54649 41.9692 8.20235 42.3859C8.98846 42.4755 9.62624 41.8869 9.99718 41.188C12.8897 35.7384 16.5983 29.7497 22.0604 27.0103Z"
|
||||
fill="#3798A6" />
|
||||
<path
|
||||
d="M54.293 18.2545C52.9177 18.0829 51.6326 19.0064 50.8501 20.1503C46.5712 26.4051 40.9276 31.4619 34.0992 34.9362C28.0309 37.9875 23.3905 43.7085 21.2488 50.5738V50.5738C20.8823 51.9051 21.321 53.3053 22.0817 54.4577C22.8541 55.6279 23.2013 56.5055 25.0387 57.2056C25.2331 57.2797 25.4363 57.33 25.6412 57.3659L29.6561 58.0696C30.1014 58.1477 30.5803 57.9029 30.6385 57.4546V57.4546C30.6522 57.3488 30.6656 57.26 30.6995 57.1589C33.5732 48.5843 39.3809 41.6511 47.1875 37.7332C52.0449 35.251 56.5674 29.4173 58.7712 23.8703C59.2774 22.5963 58.9189 21.1675 57.9822 20.1666V20.1666C57.743 19.9111 57.4687 19.6866 57.1678 19.5079C55.698 18.635 54.964 18.3382 54.293 18.2545Z"
|
||||
fill="#3798A6" />
|
||||
<path
|
||||
d="M17.8462 46.7817C18.4399 48.0437 20.2086 47.5179 20.8231 46.2658C23.9715 39.8511 29.07 34.8495 35.2979 31.6915C41.4799 28.5111 46.6705 23.683 50.3399 17.7735C50.6236 17.3166 50.7683 16.7849 50.7594 16.2472C50.658 10.1604 49.3958 9.67645 47.3183 8.9339C45.5442 8.29976 43.3135 8.84337 42.332 10.4516C37.9465 17.6372 31.7406 23.4608 24.3513 27.2417C19.6664 29.5615 15.8593 33.5228 13.4571 38.3374C13.2609 38.7306 13.1639 39.1681 13.1742 39.6074C13.3408 46.715 16.2215 43.2109 17.84 46.768C17.8439 46.7766 17.8422 46.773 17.8462 46.7817V46.7817Z"
|
||||
fill="#3798A6" />
|
||||
</svg> -->
|
||||
|
||||
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px"
|
||||
y="0px" viewBox="0 0 626.4 224.7" style="enable-background:new 0 0 626.4 224.7;" xml:space="preserve">
|
||||
<style type="text/css">
|
||||
.st0 {
|
||||
fill: #336699;
|
||||
}
|
||||
|
||||
.st1 {
|
||||
fill: #00FFFF;
|
||||
}
|
||||
|
||||
.st2 {
|
||||
fill: #30D5C8;
|
||||
}
|
||||
|
||||
.st3 {
|
||||
opacity: 0.8;
|
||||
fill: #336699;
|
||||
}
|
||||
|
||||
.st4 {
|
||||
opacity: 0.5;
|
||||
fill: #336699;
|
||||
}
|
||||
|
||||
.st5 {
|
||||
fill: #393939;
|
||||
}
|
||||
</style>
|
||||
<g>
|
||||
<g>
|
||||
<path class="st0"
|
||||
d="M215.3,69.1l-4.4,19.2h-47.1l-4.2,18h43.7l-4.5,19.2h-43.6l-5.9,25.4h47L192,170h-73.1l23.3-100.9H215.3z" />
|
||||
<path class="st0" d="M311.6,88.6h-31.4L261.4,170h-26.1L254,88.6h-31.5l4.5-19.5h89L311.6,88.6z" />
|
||||
<path class="st0" d="M422.1,69.1L398.9,170h-26.1l10.3-44.6h-38.3L334.4,170h-26.1l23.3-100.9h26.1l-8.6,37.1h38.3l8.6-37.1H422.1
|
||||
z" />
|
||||
<path class="st0"
|
||||
d="M536.7,69.1l-51.4,61.9l-9.1,39h-26.2l8.8-37.8l-23.2-63.1h27.9l13,39.6l30.2-39.6H536.7z" />
|
||||
<path class="st0" d="M563.8,171.8c-8.6,0-16.3-0.7-23.1-2.2c-6.8-1.5-12.6-3.3-17.5-5.6l5.2-24.2h2.8c4.7,4.2,10.1,7.5,16.4,9.9
|
||||
c6.3,2.3,13,3.5,20.3,3.5c7.4,0,12.9-1,16.3-3c3.5-2,5.2-4.9,5.2-8.6c0-1.4-0.3-2.6-0.8-3.6c-0.6-1-1.7-2-3.3-3
|
||||
c-1.6-1-3.9-2-6.7-2.9c-2.8-1-6.5-2.1-10.9-3.4c-4.9-1.4-9.3-2.8-13.2-4.4c-3.9-1.6-7.2-3.5-10-5.6c-2.8-2.2-4.8-4.8-6.3-7.7
|
||||
c-1.4-2.9-2.1-6.3-2.1-10.4c0-10.1,4.5-18.2,13.4-24.2c8.9-6,21.1-9,36.6-9c7.5,0,14.5,0.6,21.1,1.8c6.6,1.2,12.2,2.9,16.8,4.9
|
||||
l-4.9,23.2h-2.8c-3.5-3.2-8.2-5.9-13.9-8.1c-5.8-2.2-12.1-3.3-18.9-3.3c-6.7,0-11.9,1-15.5,2.9c-3.7,1.9-5.5,4.6-5.5,8
|
||||
c0,1.6,0.3,2.9,0.8,3.9c0.5,1,1.6,2.1,3.3,3c1.4,0.9,3.7,1.9,6.8,2.9c3.1,1.1,6.8,2.2,11,3.3c11.3,3,19.4,6.6,24.2,10.6
|
||||
s7.2,9.6,7.2,16.5c0,5.8-1.3,11-3.9,15.4c-2.6,4.4-6.2,8-10.8,10.8c-4.8,2.9-10.3,5.1-16.5,6.4
|
||||
C578.5,171.1,571.6,171.8,563.8,171.8z" />
|
||||
</g>
|
||||
<path class="st1" d="M539.2,37.1" />
|
||||
<path class="st1" d="M539.2,37.1" />
|
||||
<polygon class="st2" points="24,213.8 57.7,213.8 98.2,44.6 12.5,45.1 3.7,81 56.7,80.6 " />
|
||||
<polygon class="st0" points="72.1,170.5 112.4,2.8 199.8,2.8 192.4,39.2 137.1,39.2 105.8,170.1 " />
|
||||
<polygon class="st0" points="207,2.6 225.9,2.6 218.6,39 199.9,39 " />
|
||||
<polygon class="st3" points="233.2,2.9 252.1,2.9 244.7,39.4 226.1,39.4 " />
|
||||
<polygon class="st4" points="259.2,2.9 278.1,2.9 270.8,39.4 252.1,39.4 " />
|
||||
<g>
|
||||
<path class="st5" d="M97.4,213.7h-4.7l-8-12.1h-5.8l-2.8,12.1H72l7-30.2h8.3c1.9,0,3.4,0.1,4.5,0.4c1.2,0.2,2.2,0.7,3,1.3
|
||||
c0.8,0.6,1.4,1.2,1.8,2c0.4,0.8,0.7,1.8,0.7,2.9c0,2.5-0.8,4.7-2.4,6.6c-1.6,1.9-3.7,3.2-6.2,4L97.4,213.7z M92.9,191
|
||||
c0-0.7-0.1-1.3-0.3-1.8c-0.2-0.5-0.6-0.9-1-1.3c-0.5-0.4-1.2-0.7-1.9-0.9c-0.7-0.2-1.7-0.2-2.8-0.2h-4.6l-2.7,11.6h4.3
|
||||
c1.3,0,2.5-0.1,3.5-0.4c1-0.2,1.9-0.7,2.7-1.3c0.9-0.7,1.6-1.5,2.1-2.5C92.6,193.2,92.9,192.1,92.9,191z" />
|
||||
<path class="st5" d="M111.5,214.2c-3.2,0-5.6-0.7-7.4-2.2c-1.8-1.5-2.7-3.6-2.7-6.5c0-4.2,1.3-7.7,4-10.7c2.6-3,5.9-4.5,9.8-4.5
|
||||
c2.6,0,4.6,0.6,5.9,1.9c1.4,1.3,2.1,3.1,2.1,5.4c0,0.4-0.1,1-0.2,1.9c-0.1,0.9-0.3,1.9-0.6,3.1h-16.8c-0.1,0.4-0.1,0.8-0.2,1.2
|
||||
c0,0.4-0.1,0.7-0.1,1.1c0,1.9,0.6,3.4,1.8,4.5c1.2,1.1,2.8,1.6,5,1.6c1.5,0,3-0.3,4.6-0.9s2.9-1.2,4-2h0.2l-0.8,4.1
|
||||
c-0.7,0.2-1.3,0.5-1.8,0.7c-0.5,0.2-1.2,0.4-2.1,0.6c-0.8,0.2-1.6,0.4-2.2,0.5C113.3,214.2,112.5,214.2,111.5,214.2z M119.2,199.9
|
||||
c0.1-0.4,0.1-0.7,0.1-1c0-0.3,0-0.6,0-0.9c0-1.4-0.4-2.6-1.2-3.4c-0.8-0.8-2.1-1.2-3.8-1.2c-1.9,0-3.6,0.6-5.1,1.8
|
||||
c-1.5,1.2-2.5,2.8-3,4.7H119.2z" />
|
||||
<path class="st5" d="M132.8,214.3c-1.7,0-3.2-0.2-4.6-0.6s-2.5-0.9-3.4-1.4l0.9-4.1h0.2c0.3,0.2,0.7,0.5,1.1,0.9
|
||||
c0.5,0.3,1,0.7,1.7,1c0.6,0.3,1.4,0.6,2.2,0.8c0.8,0.2,1.7,0.3,2.6,0.3c1.9,0,3.4-0.4,4.5-1.1c1.1-0.7,1.6-1.7,1.6-3.1
|
||||
c0-0.7-0.3-1.3-0.8-1.7c-0.6-0.4-1.4-0.7-2.4-0.9c-0.5-0.1-1.2-0.3-1.9-0.4c-0.7-0.1-1.5-0.3-2.3-0.5c-1.6-0.4-2.8-1.1-3.5-1.9
|
||||
c-0.8-0.8-1.1-1.9-1.1-3.1c0-1.1,0.2-2,0.7-3c0.5-0.9,1.1-1.8,2.1-2.5c0.9-0.7,2-1.3,3.3-1.8c1.3-0.5,2.8-0.7,4.5-0.7
|
||||
c1.4,0,2.7,0.2,4.1,0.5c1.4,0.3,2.5,0.8,3.3,1.3l-0.8,3.9h-0.2c-0.2-0.2-0.5-0.4-1-0.7c-0.4-0.3-1-0.6-1.7-0.9
|
||||
c-0.6-0.3-1.3-0.5-2.1-0.7c-0.8-0.2-1.6-0.3-2.4-0.3c-1.7,0-3.1,0.4-4.1,1.1s-1.6,1.7-1.6,2.9c0,0.7,0.3,1.2,0.8,1.7
|
||||
c0.5,0.5,1.3,0.8,2.4,1.1c0.7,0.2,1.4,0.3,2.1,0.5c0.7,0.1,1.4,0.3,2.1,0.5c1.6,0.4,2.8,1,3.6,1.8s1.2,1.9,1.2,3.1
|
||||
c0,1-0.2,2.1-0.7,3.1c-0.5,1-1.2,1.9-2.2,2.6c-1,0.8-2.1,1.4-3.5,1.8C136,214,134.5,214.3,132.8,214.3z" />
|
||||
<path class="st5" d="M158.2,214.2c-3.2,0-5.6-0.7-7.4-2.2c-1.8-1.5-2.7-3.6-2.7-6.5c0-4.2,1.3-7.7,4-10.7c2.6-3,5.9-4.5,9.8-4.5
|
||||
c2.6,0,4.6,0.6,5.9,1.9c1.4,1.3,2.1,3.1,2.1,5.4c0,0.4-0.1,1-0.2,1.9c-0.1,0.9-0.3,1.9-0.6,3.1h-16.8c-0.1,0.4-0.1,0.8-0.2,1.2
|
||||
c0,0.4-0.1,0.7-0.1,1.1c0,1.9,0.6,3.4,1.8,4.5c1.2,1.1,2.8,1.6,5,1.6c1.5,0,3-0.3,4.6-0.9c1.6-0.6,2.9-1.2,4-2h0.2l-0.8,4.1
|
||||
c-0.7,0.2-1.3,0.5-1.8,0.7c-0.5,0.2-1.2,0.4-2.1,0.6c-0.8,0.2-1.6,0.4-2.2,0.5C160,214.2,159.2,214.2,158.2,214.2z M165.9,199.9
|
||||
c0.1-0.4,0.1-0.7,0.1-1c0-0.3,0-0.6,0-0.9c0-1.4-0.4-2.6-1.2-3.4c-0.8-0.8-2.1-1.2-3.8-1.2c-1.9,0-3.6,0.6-5.1,1.8
|
||||
c-1.5,1.2-2.5,2.8-3,4.7H165.9z" />
|
||||
<path class="st5"
|
||||
d="M186.8,211.3c-0.4,0.2-0.9,0.5-1.5,0.9c-0.6,0.4-1.3,0.7-1.9,1c-0.7,0.3-1.5,0.6-2.3,0.8
|
||||
c-0.9,0.2-1.8,0.3-3,0.3c-1.8,0-3.3-0.5-4.4-1.6c-1.1-1-1.7-2.4-1.7-4.1c0-1.8,0.4-3.3,1.2-4.6c0.8-1.2,2-2.2,3.5-3
|
||||
c1.5-0.8,3.4-1.3,5.6-1.7c2.2-0.3,4.6-0.6,7.4-0.6c0.1-0.4,0.2-0.7,0.2-1c0.1-0.3,0.1-0.6,0.1-0.9c0-0.6-0.1-1.2-0.4-1.6
|
||||
c-0.3-0.4-0.6-0.7-1.1-1c-0.5-0.2-1-0.4-1.7-0.5c-0.6-0.1-1.3-0.1-2.1-0.1c-1.2,0-2.5,0.2-4,0.6c-1.5,0.4-2.7,0.7-3.6,1.1H177
|
||||
l0.8-3.8c0.8-0.2,1.9-0.4,3.4-0.7c1.5-0.3,2.9-0.4,4.3-0.4c2.8,0,5,0.4,6.4,1.3c1.4,0.9,2.1,2.3,2.1,4.2c0,0.4,0,0.8-0.1,1.2
|
||||
s-0.1,0.8-0.2,1.2l-3.6,15.4h-3.8L186.8,211.3z M189.1,201.8c-2.1,0.1-4,0.2-5.6,0.5c-1.6,0.2-3,0.6-4,1c-1.1,0.4-1.9,1.1-2.5,1.8
|
||||
c-0.6,0.8-0.9,1.7-0.9,2.9c0,1,0.3,1.7,1,2.2c0.7,0.5,1.7,0.8,3.1,0.8c1.2,0,2.5-0.3,3.8-0.8c1.3-0.5,2.5-1.2,3.6-2L189.1,201.8z" />
|
||||
<path class="st5" d="M215.9,195.1h-0.2c-0.5-0.1-1-0.2-1.5-0.3c-0.5-0.1-1-0.1-1.7-0.1c-1.3,0-2.5,0.3-3.8,0.9
|
||||
c-1.3,0.6-2.5,1.3-3.6,2.1l-3.7,16.1h-3.9l5.2-22.7h3.9l-0.8,3.3c1.8-1.3,3.3-2.1,4.6-2.6c1.3-0.5,2.5-0.7,3.6-0.7
|
||||
c0.7,0,1.2,0,1.4,0.1c0.3,0,0.7,0.1,1.3,0.2L215.9,195.1z" />
|
||||
<path class="st5" d="M225.2,214.2c-1.4,0-2.7-0.2-3.8-0.5c-1.1-0.3-2.1-0.9-2.9-1.6c-0.8-0.7-1.4-1.6-1.9-2.7
|
||||
c-0.4-1.1-0.7-2.3-0.7-3.7c0-2.1,0.3-4.1,1-5.9c0.7-1.8,1.6-3.5,2.8-4.9c1.2-1.4,2.6-2.4,4.4-3.2c1.7-0.8,3.6-1.2,5.6-1.2
|
||||
c1.3,0,2.6,0.2,3.8,0.5c1.2,0.4,2.2,0.8,3.1,1.3l-0.8,4.1h-0.2c-0.3-0.2-0.6-0.5-1-0.8c-0.4-0.3-0.9-0.6-1.4-0.9
|
||||
c-0.6-0.3-1.2-0.5-1.9-0.7c-0.7-0.2-1.5-0.3-2.3-0.3c-2.6,0-4.8,1.1-6.5,3.3c-1.7,2.2-2.5,4.9-2.5,8.1c0,1.9,0.5,3.4,1.5,4.4
|
||||
c1,1,2.4,1.5,4.2,1.5c0.9,0,1.7-0.1,2.6-0.4c0.9-0.2,1.6-0.5,2.2-0.8c0.7-0.3,1.3-0.6,1.9-1c0.6-0.3,1-0.6,1.2-0.8h0.2l-0.8,4.2
|
||||
c-1.2,0.5-2.4,1-3.8,1.4C227.9,214,226.5,214.2,225.2,214.2z" />
|
||||
<path class="st5" d="M259.9,196.2c0,0.3,0,0.8-0.1,1.3c-0.1,0.6-0.1,1-0.3,1.5l-3.4,14.7h-3.8l3-12.9c0.2-0.7,0.3-1.3,0.4-1.9
|
||||
c0.1-0.5,0.1-1.1,0.1-1.6c0-1.1-0.3-2-0.9-2.6c-0.6-0.6-1.6-0.9-3.1-0.9c-1,0-2.2,0.3-3.4,0.9c-1.2,0.6-2.5,1.2-3.7,2l-3.9,16.9
|
||||
h-3.8l7.3-31.6h3.8l-2.7,11.4c1.5-1,2.8-1.8,4.1-2.3c1.3-0.5,2.6-0.8,3.9-0.8c2,0,3.5,0.5,4.6,1.5
|
||||
C259.4,192.9,259.9,194.3,259.9,196.2z" />
|
||||
<path class="st5" d="M308.1,195.1c0,3.3-0.8,6.4-2.5,9.4c-1.7,3-4,5.2-6.9,6.8c-1.8,1-3.6,1.6-5.5,1.9c-1.9,0.3-4,0.5-6.4,0.5
|
||||
h-8.2l7-30.2h7.1c2.2,0,4.2,0.2,6,0.5c1.8,0.3,3.5,1,5,2c1.4,1,2.5,2.2,3.3,3.8C307.7,191.2,308.1,193,308.1,195.1z M303.8,195.4
|
||||
c0-1.5-0.3-2.9-0.8-4c-0.6-1.1-1.4-2-2.5-2.8c-1.1-0.7-2.3-1.2-3.5-1.5c-1.3-0.2-2.8-0.4-4.8-0.4h-3.4l-5.5,23.6h4.2
|
||||
c1.9,0,3.7-0.2,5.2-0.5c1.5-0.3,3-0.9,4.3-1.6c2.2-1.2,3.9-3,5-5.4C303.3,200.6,303.8,198.1,303.8,195.4z" />
|
||||
<path class="st5"
|
||||
d="M324.7,211.3c-0.4,0.2-0.9,0.5-1.5,0.9c-0.6,0.4-1.3,0.7-1.9,1c-0.7,0.3-1.5,0.6-2.3,0.8
|
||||
c-0.9,0.2-1.8,0.3-3,0.3c-1.8,0-3.3-0.5-4.4-1.6c-1.1-1-1.7-2.4-1.7-4.1c0-1.8,0.4-3.3,1.2-4.6c0.8-1.2,2-2.2,3.5-3
|
||||
c1.5-0.8,3.4-1.3,5.6-1.7c2.2-0.3,4.6-0.6,7.4-0.6c0.1-0.4,0.2-0.7,0.2-1c0.1-0.3,0.1-0.6,0.1-0.9c0-0.6-0.1-1.2-0.4-1.6
|
||||
c-0.3-0.4-0.6-0.7-1.1-1c-0.5-0.2-1-0.4-1.7-0.5c-0.6-0.1-1.3-0.1-2.1-0.1c-1.2,0-2.5,0.2-4,0.6c-1.5,0.4-2.7,0.7-3.6,1.1h-0.2
|
||||
l0.8-3.8c0.8-0.2,1.9-0.4,3.4-0.7c1.5-0.3,2.9-0.4,4.3-0.4c2.8,0,5,0.4,6.4,1.3c1.4,0.9,2.1,2.3,2.1,4.2c0,0.4,0,0.8-0.1,1.2
|
||||
s-0.1,0.8-0.2,1.2l-3.6,15.4h-3.8L324.7,211.3z M327,201.8c-2.1,0.1-4,0.2-5.6,0.5c-1.6,0.2-3,0.6-4,1c-1.1,0.4-1.9,1.1-2.5,1.8
|
||||
c-0.6,0.8-0.9,1.7-0.9,2.9c0,1,0.3,1.7,1,2.2c0.7,0.5,1.7,0.8,3.1,0.8c1.2,0,2.5-0.3,3.8-0.8c1.3-0.5,2.5-1.2,3.6-2L327,201.8z" />
|
||||
<path class="st5" d="M352.5,191l-0.7,3.1h-7.9l-2.4,10.5c-0.1,0.5-0.3,1.1-0.4,1.8c-0.1,0.7-0.2,1.2-0.2,1.6c0,1,0.3,1.7,0.8,2.2
|
||||
c0.5,0.5,1.4,0.7,2.8,0.7c0.6,0,1.2-0.1,2-0.3c0.8-0.2,1.3-0.3,1.6-0.4h0.2l-0.7,3.3c-0.8,0.2-1.6,0.3-2.4,0.5
|
||||
c-0.9,0.1-1.6,0.2-2.3,0.2c-1.9,0-3.3-0.4-4.4-1.2c-1-0.8-1.5-2.1-1.5-3.9c0-0.4,0-0.9,0.1-1.3c0.1-0.4,0.1-0.9,0.3-1.5l2.8-12.2
|
||||
h-2.6l0.7-3.1h2.6l1.5-6.5h3.9l-1.5,6.5H352.5z" />
|
||||
<path class="st5"
|
||||
d="M366.3,211.3c-0.4,0.2-0.9,0.5-1.5,0.9c-0.6,0.4-1.3,0.7-1.9,1c-0.7,0.3-1.5,0.6-2.3,0.8
|
||||
c-0.9,0.2-1.8,0.3-3,0.3c-1.8,0-3.3-0.5-4.4-1.6c-1.1-1-1.7-2.4-1.7-4.1c0-1.8,0.4-3.3,1.2-4.6c0.8-1.2,2-2.2,3.5-3
|
||||
c1.5-0.8,3.4-1.3,5.6-1.7c2.2-0.3,4.6-0.6,7.4-0.6c0.1-0.4,0.2-0.7,0.2-1c0.1-0.3,0.1-0.6,0.1-0.9c0-0.6-0.1-1.2-0.4-1.6
|
||||
c-0.3-0.4-0.6-0.7-1.1-1c-0.5-0.2-1-0.4-1.7-0.5c-0.6-0.1-1.3-0.1-2.1-0.1c-1.2,0-2.5,0.2-4,0.6c-1.5,0.4-2.7,0.7-3.6,1.1h-0.2
|
||||
l0.8-3.8c0.8-0.2,1.9-0.4,3.4-0.7c1.5-0.3,2.9-0.4,4.3-0.4c2.8,0,5,0.4,6.4,1.3c1.4,0.9,2.1,2.3,2.1,4.2c0,0.4,0,0.8-0.1,1.2
|
||||
s-0.1,0.8-0.2,1.2l-3.6,15.4h-3.8L366.3,211.3z M368.5,201.8c-2.1,0.1-4,0.2-5.6,0.5c-1.6,0.2-3,0.6-4,1c-1.1,0.4-1.9,1.1-2.5,1.8
|
||||
c-0.6,0.8-0.9,1.7-0.9,2.9c0,1,0.3,1.7,1,2.2c0.7,0.5,1.7,0.8,3.1,0.8c1.2,0,2.5-0.3,3.8-0.8c1.3-0.5,2.5-1.2,3.6-2L368.5,201.8z" />
|
||||
<path class="st5" d="M417.4,213.7h-4.7l-8-12.1h-5.8l-2.8,12.1H392l7-30.2h8.3c1.9,0,3.4,0.1,4.5,0.4c1.2,0.2,2.2,0.7,3,1.3
|
||||
c0.8,0.6,1.4,1.2,1.8,2c0.4,0.8,0.7,1.8,0.7,2.9c0,2.5-0.8,4.7-2.4,6.6c-1.6,1.9-3.7,3.2-6.2,4L417.4,213.7z M412.8,191
|
||||
c0-0.7-0.1-1.3-0.3-1.8c-0.2-0.5-0.6-0.9-1-1.3c-0.5-0.4-1.2-0.7-1.9-0.9c-0.7-0.2-1.7-0.2-2.8-0.2h-4.6l-2.7,11.6h4.3
|
||||
c1.3,0,2.5-0.1,3.5-0.4c1-0.2,1.9-0.7,2.7-1.3c0.9-0.7,1.6-1.5,2.1-2.5C412.6,193.2,412.8,192.1,412.8,191z" />
|
||||
<path class="st5" d="M431.5,214.2c-3.2,0-5.6-0.7-7.4-2.2c-1.8-1.5-2.7-3.6-2.7-6.5c0-4.2,1.3-7.7,4-10.7s5.9-4.5,9.8-4.5
|
||||
c2.6,0,4.6,0.6,5.9,1.9c1.4,1.3,2.1,3.1,2.1,5.4c0,0.4-0.1,1-0.2,1.9c-0.1,0.9-0.3,1.9-0.6,3.1h-16.8c-0.1,0.4-0.1,0.8-0.2,1.2
|
||||
c0,0.4-0.1,0.7-0.1,1.1c0,1.9,0.6,3.4,1.8,4.5c1.2,1.1,2.8,1.6,5,1.6c1.5,0,3-0.3,4.6-0.9c1.6-0.6,2.9-1.2,4-2h0.2l-0.8,4.1
|
||||
c-0.7,0.2-1.3,0.5-1.8,0.7s-1.2,0.4-2.1,0.6c-0.8,0.2-1.6,0.4-2.2,0.5C433.3,214.2,432.5,214.2,431.5,214.2z M439.2,199.9
|
||||
c0.1-0.4,0.1-0.7,0.1-1c0-0.3,0-0.6,0-0.9c0-1.4-0.4-2.6-1.2-3.4c-0.8-0.8-2.1-1.2-3.8-1.2c-1.9,0-3.6,0.6-5.1,1.8
|
||||
c-1.5,1.2-2.5,2.8-3,4.7H439.2z" />
|
||||
<path class="st5" d="M468.8,198.2c0,2.2-0.4,4.4-1.1,6.3c-0.7,2-1.6,3.7-2.8,5c-1.2,1.4-2.5,2.5-4.1,3.4c-1.6,0.8-3.2,1.2-5,1.2
|
||||
c-1.2,0-2.4-0.1-3.4-0.4s-2-0.7-2.8-1.2l-2.2,9.5h-3.8l7.2-31h3.8l-0.6,2.4c1.3-0.9,2.5-1.6,3.7-2.2c1.2-0.6,2.6-0.8,4.1-0.8
|
||||
c2.2,0,3.9,0.7,5.1,2.1C468.2,193.8,468.8,195.7,468.8,198.2z M464.8,198.9c0-1.6-0.4-2.9-1.1-3.7c-0.7-0.9-1.8-1.3-3.4-1.3
|
||||
c-1.1,0-2.3,0.3-3.5,0.8c-1.2,0.6-2.3,1.2-3.4,1.9l-3,12.9c0.9,0.5,1.7,0.8,2.5,1.1c0.8,0.2,1.8,0.3,2.9,0.3c1.4,0,2.7-0.3,3.8-1
|
||||
s2.1-1.6,2.8-2.6c0.8-1.1,1.4-2.4,1.7-3.8C464.6,202,464.8,200.5,464.8,198.9z" />
|
||||
<path class="st5" d="M494.1,199.1c0,2-0.3,4-0.9,5.8c-0.6,1.9-1.5,3.5-2.7,4.9c-1.2,1.4-2.6,2.6-4.1,3.4c-1.6,0.8-3.4,1.2-5.4,1.2
|
||||
c-2.7,0-4.8-0.8-6.3-2.3c-1.5-1.5-2.3-3.7-2.3-6.4c0-2,0.3-4,0.9-5.8c0.6-1.8,1.5-3.5,2.7-4.9c1.1-1.4,2.5-2.5,4.2-3.3
|
||||
c1.6-0.8,3.4-1.2,5.4-1.2c2.6,0,4.7,0.7,6.3,2.2S494.1,196.3,494.1,199.1z M487.8,207.6c0.7-1.1,1.3-2.3,1.7-3.8s0.6-2.9,0.6-4.5
|
||||
c0-1.9-0.5-3.3-1.4-4.3c-0.9-1-2.2-1.5-3.9-1.5c-1.3,0-2.5,0.3-3.6,0.9c-1,0.6-2,1.5-2.7,2.6c-0.7,1.1-1.3,2.3-1.7,3.8
|
||||
c-0.4,1.4-0.6,2.9-0.6,4.5c0,1.9,0.5,3.3,1.4,4.3c0.9,1,2.2,1.5,3.9,1.5c1.3,0,2.5-0.3,3.6-0.9
|
||||
C486.2,209.6,487.1,208.7,487.8,207.6z" />
|
||||
<path class="st5" d="M504.2,214.3c-1.7,0-3.2-0.2-4.6-0.6c-1.3-0.4-2.5-0.9-3.4-1.4l0.9-4.1h0.2c0.3,0.2,0.7,0.5,1.1,0.9
|
||||
c0.5,0.3,1,0.7,1.7,1c0.6,0.3,1.4,0.6,2.2,0.8c0.8,0.2,1.7,0.3,2.6,0.3c1.9,0,3.4-0.4,4.5-1.1s1.6-1.7,1.6-3.1
|
||||
c0-0.7-0.3-1.3-0.8-1.7c-0.6-0.4-1.4-0.7-2.4-0.9c-0.5-0.1-1.2-0.3-1.9-0.4c-0.7-0.1-1.5-0.3-2.3-0.5c-1.6-0.4-2.8-1.1-3.5-1.9
|
||||
c-0.8-0.8-1.1-1.9-1.1-3.1c0-1.1,0.2-2,0.7-3c0.5-0.9,1.1-1.8,2.1-2.5c0.9-0.7,2-1.3,3.3-1.8c1.3-0.5,2.8-0.7,4.5-0.7
|
||||
c1.4,0,2.7,0.2,4.1,0.5c1.4,0.3,2.5,0.8,3.3,1.3l-0.8,3.9H516c-0.2-0.2-0.5-0.4-1-0.7c-0.4-0.3-1-0.6-1.7-0.9
|
||||
c-0.6-0.3-1.3-0.5-2.1-0.7c-0.8-0.2-1.6-0.3-2.4-0.3c-1.7,0-3.1,0.4-4.1,1.1c-1.1,0.7-1.6,1.7-1.6,2.9c0,0.7,0.3,1.2,0.8,1.7
|
||||
c0.5,0.5,1.3,0.8,2.4,1.1c0.7,0.2,1.4,0.3,2.1,0.5c0.7,0.1,1.4,0.3,2.1,0.5c1.6,0.4,2.8,1,3.6,1.8s1.2,1.9,1.2,3.1
|
||||
c0,1-0.2,2.1-0.7,3.1c-0.5,1-1.2,1.9-2.2,2.6c-1,0.8-2.1,1.4-3.5,1.8C507.4,214,505.9,214.3,504.2,214.3z" />
|
||||
<path class="st5" d="M528,191l-5.3,22.7h-3.8l5.3-22.7H528z M530.1,183.3l-0.9,4h-4.3l0.9-4H530.1z" />
|
||||
<path class="st5" d="M547.4,191l-0.7,3.1h-7.9l-2.4,10.5c-0.1,0.5-0.3,1.1-0.4,1.8c-0.1,0.7-0.2,1.2-0.2,1.6c0,1,0.3,1.7,0.8,2.2
|
||||
c0.5,0.5,1.4,0.7,2.8,0.7c0.6,0,1.2-0.1,2-0.3c0.8-0.2,1.3-0.3,1.6-0.4h0.2l-0.7,3.3c-0.8,0.2-1.6,0.3-2.4,0.5
|
||||
c-0.9,0.1-1.6,0.2-2.3,0.2c-1.9,0-3.3-0.4-4.4-1.2c-1-0.8-1.5-2.1-1.5-3.9c0-0.4,0-0.9,0.1-1.3c0.1-0.4,0.1-0.9,0.3-1.5l2.8-12.2
|
||||
h-2.6l0.7-3.1h2.6l1.5-6.5h3.9l-1.5,6.5H547.4z" />
|
||||
<path class="st5" d="M569.2,199.1c0,2-0.3,4-0.9,5.8c-0.6,1.9-1.5,3.5-2.7,4.9c-1.2,1.4-2.6,2.6-4.1,3.4c-1.5,0.8-3.4,1.2-5.4,1.2
|
||||
c-2.7,0-4.8-0.8-6.3-2.3c-1.5-1.5-2.3-3.7-2.3-6.4c0-2,0.3-4,0.9-5.8c0.6-1.8,1.5-3.5,2.7-4.9c1.1-1.4,2.5-2.5,4.2-3.3
|
||||
c1.6-0.8,3.4-1.2,5.4-1.2c2.6,0,4.7,0.7,6.3,2.2C568.4,194.1,569.2,196.3,569.2,199.1z M563,207.6c0.7-1.1,1.3-2.3,1.7-3.8
|
||||
c0.4-1.4,0.6-2.9,0.6-4.5c0-1.9-0.5-3.3-1.4-4.3c-0.9-1-2.2-1.5-3.9-1.5c-1.3,0-2.5,0.3-3.6,0.9c-1,0.6-2,1.5-2.7,2.6
|
||||
c-0.7,1.1-1.3,2.3-1.7,3.8c-0.4,1.4-0.6,2.9-0.6,4.5c0,1.9,0.5,3.3,1.4,4.3c0.9,1,2.2,1.5,3.9,1.5c1.3,0,2.5-0.3,3.6-0.9
|
||||
C561.3,209.6,562.2,208.7,563,207.6z" />
|
||||
<path class="st5" d="M590.6,195.1h-0.2c-0.5-0.1-1.1-0.2-1.5-0.3c-0.5-0.1-1-0.1-1.7-0.1c-1.3,0-2.5,0.3-3.8,0.9
|
||||
c-1.3,0.6-2.5,1.3-3.6,2.1l-3.7,16.1h-3.9l5.2-22.7h3.9l-0.8,3.3c1.8-1.3,3.3-2.1,4.6-2.6c1.3-0.5,2.5-0.7,3.6-0.7
|
||||
c0.7,0,1.2,0,1.4,0.1c0.3,0,0.7,0.1,1.3,0.2L590.6,195.1z" />
|
||||
<path class="st5" d="M594.1,222.1h-4.2l6.6-9.7l-4.1-21.3h4l3.2,16.9l10.9-16.9h4.2L594.1,222.1z" />
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
|
@ -15,5 +15,5 @@
|
|||
},
|
||||
},
|
||||
"include": ["./**/*.ts", "./**/*.vue"],
|
||||
"exclude": ["./utils/*.js"],
|
||||
"exclude": ["./utils/*.js", "./utils/Timer.js", "./utils/focusTrap.js"],
|
||||
}
|
||||
|
|
|
@ -1,16 +1,15 @@
|
|||
|
||||
/**
|
||||
* Get the first day of the week
|
||||
*
|
||||
* @return {number}
|
||||
*/
|
||||
export function getFirstDay(): number {
|
||||
if (typeof window.firstDay === 'undefined') {
|
||||
console.warn('No firstDay found')
|
||||
return 1
|
||||
}
|
||||
if (typeof window.firstDay === 'undefined') {
|
||||
console.warn('No firstDay found');
|
||||
return 1;
|
||||
}
|
||||
|
||||
return window.firstDay
|
||||
return window.firstDay;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -19,20 +18,12 @@ export function getFirstDay(): number {
|
|||
* @return {string[]}
|
||||
*/
|
||||
export function getDayNames(): string[] {
|
||||
if (typeof window.dayNames === 'undefined') {
|
||||
console.warn('No dayNames found')
|
||||
return [
|
||||
'Sunday',
|
||||
'Monday',
|
||||
'Tuesday',
|
||||
'Wednesday',
|
||||
'Thursday',
|
||||
'Friday',
|
||||
'Saturday',
|
||||
]
|
||||
}
|
||||
if (typeof window.dayNames === 'undefined') {
|
||||
console.warn('No dayNames found');
|
||||
return ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'];
|
||||
}
|
||||
|
||||
return window.dayNames
|
||||
return window.dayNames;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -41,12 +32,12 @@ export function getDayNames(): string[] {
|
|||
* @return {string[]}
|
||||
*/
|
||||
export function getDayNamesShort(): string[] {
|
||||
if (typeof window.dayNamesShort === 'undefined') {
|
||||
console.warn('No dayNamesShort found')
|
||||
return ['Sun.', 'Mon.', 'Tue.', 'Wed.', 'Thu.', 'Fri.', 'Sat.']
|
||||
}
|
||||
if (typeof window.dayNamesShort === 'undefined') {
|
||||
console.warn('No dayNamesShort found');
|
||||
return ['Sun.', 'Mon.', 'Tue.', 'Wed.', 'Thu.', 'Fri.', 'Sat.'];
|
||||
}
|
||||
|
||||
return window.dayNamesShort
|
||||
return window.dayNamesShort;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -55,12 +46,12 @@ export function getDayNamesShort(): string[] {
|
|||
* @return {string[]}
|
||||
*/
|
||||
export function getDayNamesMin(): string[] {
|
||||
if (typeof window.dayNamesMin === 'undefined') {
|
||||
console.warn('No dayNamesMin found')
|
||||
return ['Su', 'Mo', 'Tu', 'We', 'Th', 'Fr', 'Sa']
|
||||
}
|
||||
if (typeof window.dayNamesMin === 'undefined') {
|
||||
console.warn('No dayNamesMin found');
|
||||
return ['Su', 'Mo', 'Tu', 'We', 'Th', 'Fr', 'Sa'];
|
||||
}
|
||||
|
||||
return window.dayNamesMin
|
||||
return window.dayNamesMin;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -69,25 +60,12 @@ export function getDayNamesMin(): string[] {
|
|||
* @return {string[]}
|
||||
*/
|
||||
export function getMonthNames(): string[] {
|
||||
if (typeof window.monthNames === 'undefined') {
|
||||
console.warn('No monthNames found')
|
||||
return [
|
||||
'January',
|
||||
'February',
|
||||
'March',
|
||||
'April',
|
||||
'May',
|
||||
'June',
|
||||
'July',
|
||||
'August',
|
||||
'September',
|
||||
'October',
|
||||
'November',
|
||||
'December',
|
||||
]
|
||||
}
|
||||
if (typeof window.monthNames === 'undefined') {
|
||||
console.warn('No monthNames found');
|
||||
return ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'];
|
||||
}
|
||||
|
||||
return window.monthNames
|
||||
return window.monthNames;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -96,23 +74,10 @@ export function getMonthNames(): string[] {
|
|||
* @return {string[]}
|
||||
*/
|
||||
export function getMonthNamesShort(): string[] {
|
||||
if (typeof window.monthNamesShort === 'undefined') {
|
||||
console.warn('No monthNamesShort found')
|
||||
return [
|
||||
'Jan.',
|
||||
'Feb.',
|
||||
'Mar.',
|
||||
'Apr.',
|
||||
'May.',
|
||||
'Jun.',
|
||||
'Jul.',
|
||||
'Aug.',
|
||||
'Sep.',
|
||||
'Oct.',
|
||||
'Nov.',
|
||||
'Dec.',
|
||||
]
|
||||
}
|
||||
if (typeof window.monthNamesShort === 'undefined') {
|
||||
console.warn('No monthNamesShort found');
|
||||
return ['Jan.', 'Feb.', 'Mar.', 'Apr.', 'May.', 'Jun.', 'Jul.', 'Aug.', 'Sep.', 'Oct.', 'Nov.', 'Dec.'];
|
||||
}
|
||||
|
||||
return window.monthNamesShort
|
||||
return window.monthNamesShort;
|
||||
}
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
import type { Translations } from './registry';
|
||||
import { getLanguage, getBrowserLocale } from './locale';
|
||||
import { getAppTranslations, hasAppTranslations, registerAppTranslations, unregisterAppTranslations } from './registry';
|
||||
import { getLanguage } from './locale';
|
||||
import { getAppTranslations, registerAppTranslations, unregisterAppTranslations } from './registry';
|
||||
// import { generateFilePath } from '@nextcloud/router';
|
||||
import axios from 'axios';
|
||||
// import axios from 'axios';
|
||||
|
||||
// import DOMPurify from 'dompurify';
|
||||
import escapeHTML from 'escape-html';
|
||||
|
@ -206,7 +206,7 @@ export async function loadTranslations(appName: string) {
|
|||
try {
|
||||
// Making a GET request using Axios
|
||||
// const response = await axios.get(url);
|
||||
const response = await import(`@/apps/settings/l18n/${locale}`);
|
||||
const response = await import(`@/apps/settings/l18n/${locale}.js`);
|
||||
// Check if the response data contains translations
|
||||
const bundle = response.default;
|
||||
if (typeof bundle.translations === 'object') {
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
<input type="hidden" id="initial-state-settings-cronErrors" value="IiI=">
|
||||
<input type="hidden" id="initial-state-settings-cliBasedCronPossible" value="dHJ1ZQ==">
|
||||
<input type="hidden" id="initial-state-settings-cliBasedCronUser" value="Ind3dy1kYXRhIg==">
|
||||
@vite(['resources/js/app.ts'])
|
||||
|
||||
@routes('test')
|
||||
</head>
|
||||
|
@ -29,8 +30,8 @@
|
|||
<body>
|
||||
@inertia({ as: 'div', class: 'h-full' })
|
||||
|
||||
@entryPointStyles('app')
|
||||
@entryPointScripts('app')
|
||||
{{-- @entryPointStyles('app')
|
||||
@entryPointScripts('app') --}}
|
||||
</body>
|
||||
|
||||
</html>
|
52
start/env.ts
52
start/env.ts
|
@ -11,39 +11,37 @@
|
|||
| and hence do not rename or move this file to a different location.
|
||||
|
|
||||
*/
|
||||
import { Env } from "@adonisjs/core/env"
|
||||
import { Env } from '@adonisjs/core/env';
|
||||
|
||||
export default await Env.create(new URL("../", import.meta.url), {
|
||||
HOST: Env.schema.string({ format: 'host' }),
|
||||
PORT: Env.schema.number(),
|
||||
APP_KEY: Env.schema.string(),
|
||||
APP_NAME: Env.schema.string(),
|
||||
CACHE_VIEWS: Env.schema.boolean(),
|
||||
SESSION_DRIVER: Env.schema.enum(["cookie", "memory"] as const),
|
||||
export default await Env.create(new URL('../', import.meta.url), {
|
||||
HOST: Env.schema.string({ format: 'host' }),
|
||||
PORT: Env.schema.number(),
|
||||
APP_KEY: Env.schema.string(),
|
||||
APP_NAME: Env.schema.string(),
|
||||
CACHE_VIEWS: Env.schema.boolean(),
|
||||
SESSION_DRIVER: Env.schema.enum(['cookie', 'memory'] as const),
|
||||
|
||||
DRIVE_DISK: Env.schema.enum(['local'] as const),
|
||||
NODE_ENV: Env.schema.enum(['development', 'production', 'test'] as const),
|
||||
DB_CONNECTION: Env.schema.string(),
|
||||
PG_HOST: Env.schema.string({ format: 'host' }),
|
||||
PG_PORT: Env.schema.number(),
|
||||
PG_USER: Env.schema.string(),
|
||||
PG_PASSWORD: Env.schema.string.optional(),
|
||||
PG_DB_NAME: Env.schema.string(),
|
||||
DRIVE_DISK: Env.schema.enum(['local'] as const),
|
||||
NODE_ENV: Env.schema.enum(['development', 'production', 'test'] as const),
|
||||
DB_CONNECTION: Env.schema.string(),
|
||||
PG_HOST: Env.schema.string({ format: 'host' }),
|
||||
PG_PORT: Env.schema.number(),
|
||||
PG_USER: Env.schema.string(),
|
||||
PG_PASSWORD: Env.schema.string.optional(),
|
||||
PG_DB_NAME: Env.schema.string(),
|
||||
|
||||
REDIS_HOST: Env.schema.string({ format: 'host' }),
|
||||
REDIS_PORT: Env.schema.number(),
|
||||
REDIS_HOST: Env.schema.string({ format: 'host' }),
|
||||
REDIS_PORT: Env.schema.number(),
|
||||
|
||||
HASH_DRIVER: Env.schema.enum(["scrypt", "argon", "bcrypt", "laravel", undefined] as const),
|
||||
OAI_LIST_SIZE: Env.schema.number(),
|
||||
HASH_DRIVER: Env.schema.enum(['scrypt', 'argon', 'bcrypt', 'laravel', undefined] as const),
|
||||
OAI_LIST_SIZE: Env.schema.number(),
|
||||
|
||||
/*
|
||||
/*
|
||||
|----------------------------------------------------------
|
||||
| Variables for configuring the mail package
|
||||
|----------------------------------------------------------
|
||||
*/
|
||||
SMTP_HOST: Env.schema.string.optional(),
|
||||
SMTP_PORT: Env.schema.string.optional(),
|
||||
RESEND_API_KEY: Env.schema.string.optional()
|
||||
|
||||
})
|
||||
|
||||
SMTP_HOST: Env.schema.string.optional(),
|
||||
SMTP_PORT: Env.schema.string.optional(),
|
||||
RESEND_API_KEY: Env.schema.string.optional(),
|
||||
});
|
||||
|
|
|
@ -24,8 +24,8 @@ server.use([
|
|||
() => import('@adonisjs/static/static_middleware'),
|
||||
// () => import('@adonisjs/cors/cors_middleware'),
|
||||
() => import('@adonisjs/inertia/inertia_middleware'),
|
||||
() => import('@adonisjs/vite/vite_middleware'),
|
||||
]);
|
||||
|
||||
/**
|
||||
* The router middleware stack runs middleware on all the HTTP
|
||||
* requests with a registered route.
|
||||
|
|
441
start/routes.ts
441
start/routes.ts
|
@ -41,150 +41,361 @@ import db from '@adonisjs/lucid/services/db'; // Import the DB service
|
|||
router.get('/health', ({ response }: HttpContext) => response.noContent());
|
||||
|
||||
// OAI routes
|
||||
router.group(() => {
|
||||
router.get('/oai', [OaiController, 'index']).as('get');
|
||||
router.post('/oai', [OaiController, 'index']).as('post');
|
||||
}).as('oai');
|
||||
router
|
||||
.group(() => {
|
||||
router.get('/oai', [OaiController, 'index']).as('get');
|
||||
router.post('/oai', [OaiController, 'index']).as('post');
|
||||
})
|
||||
.as('oai');
|
||||
|
||||
// Welcome route
|
||||
router.get('/welcome', async ({ view }: HttpContext) => {
|
||||
return view.render('welcome');
|
||||
}).as('welcome');
|
||||
router
|
||||
.get('/welcome', async ({ view }: HttpContext) => {
|
||||
return view.render('welcome');
|
||||
})
|
||||
.as('welcome');
|
||||
|
||||
// Dashboard route
|
||||
router.get('/', async ({ response }: HttpContext) => {
|
||||
return response.redirect().toRoute('apps.dashboard');
|
||||
}).as('dashboard');
|
||||
router
|
||||
.get('/', async ({ response }: HttpContext) => {
|
||||
return response.redirect().toRoute('apps.dashboard');
|
||||
})
|
||||
.as('dashboard');
|
||||
|
||||
// Apps group
|
||||
router.group(() => {
|
||||
router.get('/dashboard', async ({ inertia }: HttpContext) => {
|
||||
return inertia.render('Dashboard');
|
||||
}).as('dashboard');
|
||||
router
|
||||
.group(() => {
|
||||
router
|
||||
.get('/dashboard', async ({ inertia }: HttpContext) => {
|
||||
return inertia.render('Dashboard');
|
||||
})
|
||||
.as('dashboard');
|
||||
|
||||
router.get('/map', async ({ inertia }: HttpContext) => {
|
||||
return inertia.render('Map');
|
||||
}).as('map');
|
||||
router
|
||||
.get('/map', async ({ inertia }: HttpContext) => {
|
||||
return inertia.render('Map');
|
||||
})
|
||||
.as('map');
|
||||
|
||||
router.get('/', async ({ inertia }: HttpContext) => {
|
||||
const users = await User.query().orderBy('login');
|
||||
return inertia.render('App', {
|
||||
testing: 'this is a test',
|
||||
users: users,
|
||||
});
|
||||
}).as('index');
|
||||
router
|
||||
.get('/', async ({ inertia }: HttpContext) => {
|
||||
const users = await User.query().orderBy('login');
|
||||
return inertia.render('App', {
|
||||
testing: 'this is a test',
|
||||
users: users,
|
||||
});
|
||||
})
|
||||
.as('index');
|
||||
|
||||
router.get('/register', async ({ inertia }: HttpContext) => {
|
||||
return inertia.render('register-view/register-view-component');
|
||||
}).as('register.show');
|
||||
router
|
||||
.get('/register', async ({ inertia }: HttpContext) => {
|
||||
return inertia.render('register-view/register-view-component');
|
||||
})
|
||||
.as('register.show');
|
||||
|
||||
router.post('/register', async ({ request, response }: HttpContext) => {
|
||||
const data = await request.validateUsing(authValidator);
|
||||
return response.redirect().toRoute('app.index');
|
||||
}).as('register.store');
|
||||
}).prefix('apps').as('apps').use(middleware.auth());
|
||||
router
|
||||
.post('/register', async ({ request, response }: HttpContext) => {
|
||||
await request.validateUsing(authValidator);
|
||||
return response.redirect().toRoute('app.index');
|
||||
})
|
||||
.as('register.store');
|
||||
})
|
||||
.prefix('apps')
|
||||
.as('apps')
|
||||
.use(middleware.auth());
|
||||
|
||||
// Auth routes
|
||||
router.get('/app/login', ({ inertia }: HttpContext) => {
|
||||
return inertia.render('Auth/Login');
|
||||
}).as('app.login.show');
|
||||
router
|
||||
.get('/app/login', ({ inertia }: HttpContext) => {
|
||||
return inertia.render('Auth/Login');
|
||||
})
|
||||
.as('app.login.show');
|
||||
|
||||
router.post('/app/login', [AuthController, 'login']).as('login.store');
|
||||
router.post('/app/twoFactorChallenge', [AuthController, 'twoFactorChallenge']).as('login.twoFactorChallenge');
|
||||
router.post('/signout', [AuthController, 'logout']).as('logout');
|
||||
|
||||
// Administrator routes
|
||||
router.group(() => {
|
||||
router.get('/settings', async ({ inertia }: HttpContext) => {
|
||||
const updatedConfigValue = await db.from('appconfigs')
|
||||
.select('configvalue')
|
||||
.where('appid', 'backgroundjob')
|
||||
.where('configkey', 'lastjob')
|
||||
.first();
|
||||
return inertia.render('Admin/Settings', {
|
||||
lastCron: updatedConfigValue?.configvalue || '',
|
||||
});
|
||||
}).as('overview');
|
||||
router
|
||||
.group(() => {
|
||||
router
|
||||
.get('/settings', async ({ inertia }: HttpContext) => {
|
||||
const updatedConfigValue = await db
|
||||
.from('appconfigs')
|
||||
.select('configvalue')
|
||||
.where('appid', 'backgroundjob')
|
||||
.where('configkey', 'lastjob')
|
||||
.first();
|
||||
return inertia.render('Admin/Settings', {
|
||||
lastCron: updatedConfigValue?.configvalue || '',
|
||||
});
|
||||
})
|
||||
.as('overview');
|
||||
|
||||
router.post('/mail/store', [MailSettingsController, 'setMailSettings']).as('mail.store').use(middleware.can(['user-create']));
|
||||
router.post('/mail/send', [MailSettingsController, 'sendTestMail']).as('mail.send').use(middleware.can(['user-create']));
|
||||
router
|
||||
.post('/mail/store', [MailSettingsController, 'setMailSettings'])
|
||||
.as('mail.store')
|
||||
.use(middleware.can(['user-create']));
|
||||
router
|
||||
.post('/mail/send', [MailSettingsController, 'sendTestMail'])
|
||||
.as('mail.send')
|
||||
.use(middleware.can(['user-create']));
|
||||
|
||||
// User routes
|
||||
router.get('/user', [AdminuserController, 'index']).as('user.index').use(middleware.can(['user-list']));
|
||||
router.get('/user/create', [AdminuserController, 'create']).as('user.create').use(middleware.can(['user-create']));
|
||||
router.post('/user/store', [AdminuserController, 'store']).as('user.store').use(middleware.can(['user-create']));
|
||||
router.get('/user/:id', [AdminuserController, 'show']).as('user.show').where('id', router.matchers.number());
|
||||
router.get('/user/:id/edit', [AdminuserController, 'edit']).as('user.edit').where('id', router.matchers.number()).use(middleware.can(['user-edit']));
|
||||
router.put('/user/:id/update', [AdminuserController, 'update']).as('user.update').where('id', router.matchers.number()).use(middleware.can(['user-edit']));
|
||||
router.delete('/user/:id', [AdminuserController, 'destroy']).as('user.destroy').where('id', router.matchers.number()).use(middleware.can(['user-delete']));
|
||||
// User routes
|
||||
router
|
||||
.get('/user', [AdminuserController, 'index'])
|
||||
.as('user.index')
|
||||
.use(middleware.can(['user-list']));
|
||||
router
|
||||
.get('/user/create', [AdminuserController, 'create'])
|
||||
.as('user.create')
|
||||
.use(middleware.can(['user-create']));
|
||||
router
|
||||
.post('/user/store', [AdminuserController, 'store'])
|
||||
.as('user.store')
|
||||
.use(middleware.can(['user-create']));
|
||||
router.get('/user/:id', [AdminuserController, 'show']).as('user.show').where('id', router.matchers.number());
|
||||
router
|
||||
.get('/user/:id/edit', [AdminuserController, 'edit'])
|
||||
.as('user.edit')
|
||||
.where('id', router.matchers.number())
|
||||
.use(middleware.can(['user-edit']));
|
||||
router
|
||||
.put('/user/:id/update', [AdminuserController, 'update'])
|
||||
.as('user.update')
|
||||
.where('id', router.matchers.number())
|
||||
.use(middleware.can(['user-edit']));
|
||||
router
|
||||
.delete('/user/:id', [AdminuserController, 'destroy'])
|
||||
.as('user.destroy')
|
||||
.where('id', router.matchers.number())
|
||||
.use(middleware.can(['user-delete']));
|
||||
|
||||
// Role routes
|
||||
router.get('/role', [RoleController, 'index']).as('role.index').use(middleware.can(['user-list']));
|
||||
router.get('/role/create', [RoleController, 'create']).as('role.create').use(middleware.can(['user-create']));
|
||||
router.post('/role/store', [RoleController, 'store']).as('role.store').use(middleware.can(['user-create']));
|
||||
router.get('/role/:id', [RoleController, 'show']).as('role.show').where('id', router.matchers.number());
|
||||
router.get('/role/:id/edit', [RoleController, 'edit']).as('role.edit').where('id', router.matchers.number()).use(middleware.can(['user-edit']));
|
||||
router.put('/role/:id/update', [RoleController, 'update']).as('role.update').where('id', router.matchers.number()).use(middleware.can(['user-edit']));
|
||||
// Role routes
|
||||
router
|
||||
.get('/role', [RoleController, 'index'])
|
||||
.as('role.index')
|
||||
.use(middleware.can(['user-list']));
|
||||
router
|
||||
.get('/role/create', [RoleController, 'create'])
|
||||
.as('role.create')
|
||||
.use(middleware.can(['user-create']));
|
||||
router
|
||||
.post('/role/store', [RoleController, 'store'])
|
||||
.as('role.store')
|
||||
.use(middleware.can(['user-create']));
|
||||
router.get('/role/:id', [RoleController, 'show']).as('role.show').where('id', router.matchers.number());
|
||||
router
|
||||
.get('/role/:id/edit', [RoleController, 'edit'])
|
||||
.as('role.edit')
|
||||
.where('id', router.matchers.number())
|
||||
.use(middleware.can(['user-edit']));
|
||||
router
|
||||
.put('/role/:id/update', [RoleController, 'update'])
|
||||
.as('role.update')
|
||||
.where('id', router.matchers.number())
|
||||
.use(middleware.can(['user-edit']));
|
||||
|
||||
// License routes
|
||||
router.get('/license', [LicenseController, 'index']).as('license.index');
|
||||
router.get('/license/:id/down', [LicenseController, 'down']).as('license.down').where('id', router.matchers.number()).use(middleware.can(['settings']));
|
||||
router.get('/license/:id/up', [LicenseController, 'up']).as('license.up').where('id', router.matchers.number()).use(middleware.can(['settings']));
|
||||
// License routes
|
||||
router.get('/license', [LicenseController, 'index']).as('license.index');
|
||||
router
|
||||
.get('/license/:id/down', [LicenseController, 'down'])
|
||||
.as('license.down')
|
||||
.where('id', router.matchers.number())
|
||||
.use(middleware.can(['settings']));
|
||||
router
|
||||
.get('/license/:id/up', [LicenseController, 'up'])
|
||||
.as('license.up')
|
||||
.where('id', router.matchers.number())
|
||||
.use(middleware.can(['settings']));
|
||||
|
||||
// Mimetype routes
|
||||
router.get('/mimetype', [MimetypeController, 'index']).as('mimetype.index');
|
||||
router.get('/mimetype/create', [MimetypeController, 'create']).as('mimetype.create').use(middleware.can(['settings']));
|
||||
router.post('/mimetype/store', [MimetypeController, 'store']).as('mimetype.store').use(middleware.can(['settings']));
|
||||
router.get('/mimetype/:id/down', [MimetypeController, 'down']).as('mimetype.down').where('id', router.matchers.number()).use(middleware.can(['settings']));
|
||||
router.get('/mimetype/:id/up', [MimetypeController, 'up']).as('mimetype.up').where('id', router.matchers.number()).use(middleware.can(['settings']));
|
||||
router.get('/mimetype/:id/delete', [MimetypeController, 'delete']).as('mimetype.delete').use([middleware.auth(), middleware.can(['dataset-delete'])]);
|
||||
router.delete('/mimetype/:id/deleteStore', [MimetypeController, 'deleteStore']).as('mimetype.deleteStore').use([middleware.auth(), middleware.can(['settings'])]);
|
||||
}).prefix('admin').as('settings').use([middleware.auth(), middleware.is(['administrator', 'moderator'])]);
|
||||
// Mimetype routes
|
||||
router.get('/mimetype', [MimetypeController, 'index']).as('mimetype.index');
|
||||
router
|
||||
.get('/mimetype/create', [MimetypeController, 'create'])
|
||||
.as('mimetype.create')
|
||||
.use(middleware.can(['settings']));
|
||||
router
|
||||
.post('/mimetype/store', [MimetypeController, 'store'])
|
||||
.as('mimetype.store')
|
||||
.use(middleware.can(['settings']));
|
||||
router
|
||||
.get('/mimetype/:id/down', [MimetypeController, 'down'])
|
||||
.as('mimetype.down')
|
||||
.where('id', router.matchers.number())
|
||||
.use(middleware.can(['settings']));
|
||||
router
|
||||
.get('/mimetype/:id/up', [MimetypeController, 'up'])
|
||||
.as('mimetype.up')
|
||||
.where('id', router.matchers.number())
|
||||
.use(middleware.can(['settings']));
|
||||
router
|
||||
.get('/mimetype/:id/delete', [MimetypeController, 'delete'])
|
||||
.as('mimetype.delete')
|
||||
.use([middleware.auth(), middleware.can(['dataset-delete'])]);
|
||||
router
|
||||
.delete('/mimetype/:id/deleteStore', [MimetypeController, 'deleteStore'])
|
||||
.as('mimetype.deleteStore')
|
||||
.use([middleware.auth(), middleware.can(['settings'])]);
|
||||
})
|
||||
.prefix('admin')
|
||||
.as('settings')
|
||||
.use([middleware.auth(), middleware.is(['administrator', 'moderator'])]);
|
||||
|
||||
router.get('/settings/user/security', [UserController, 'accountInfo']).as('settings.user').use(middleware.auth());
|
||||
router.post('/settings/user/store', [UserController, 'accountInfoStore']).as('account.password.store').use(middleware.auth());
|
||||
|
||||
// Submitter routes
|
||||
router.group(() => {
|
||||
router.get('/dataset', [DatasetController, 'index']).as('dataset.list').use([middleware.auth(), middleware.can(['dataset-list'])]);
|
||||
router.get('/dataset/create', [DatasetController, 'create']).as('dataset.create').use([middleware.auth(), middleware.can(['dataset-submit'])]);
|
||||
router.post('/dataset/first/first-step', [DatasetController, 'firstStep']).as('dataset.first.step').use([middleware.auth(), middleware.can(['dataset-submit'])]);
|
||||
router.post('/dataset/second/second-step', [DatasetController, 'secondStep']).as('dataset.second.step').use([middleware.auth(), middleware.can(['dataset-submit'])]);
|
||||
router.post('/dataset/second/third-step', [DatasetController, 'thirdStep']).as('dataset.third.step').use([middleware.auth(), middleware.can(['dataset-submit'])]);
|
||||
router.post('/dataset/submit', [DatasetController, 'store']).as('dataset.submit').use([middleware.auth(), middleware.can(['dataset-submit'])]);
|
||||
router.get('/dataset/:id/release', [DatasetController, 'release']).as('dataset.release').where('id', router.matchers.number()).use([middleware.auth(), middleware.can(['dataset-edit'])]);
|
||||
router.put('/dataset/:id/releaseupdate', [DatasetController, 'releaseUpdate']).as('dataset.releaseUpdate').use([middleware.auth(), middleware.can(['dataset-edit'])]);
|
||||
router.get('/dataset/:id/edit', [DatasetController, 'edit']).as('dataset.edit').where('id', router.matchers.number()).use([middleware.auth(), middleware.can(['dataset-edit'])]);
|
||||
router.put('/dataset/:id/update', [DatasetController, 'update']).as('dataset.update').where('id', router.matchers.number()).use([middleware.auth(), middleware.can(['dataset-edit'])]);
|
||||
router.get('/dataset/:id/delete', [DatasetController, 'delete']).as('dataset.delete').use([middleware.auth(), middleware.can(['dataset-delete'])]);
|
||||
router.put('/dataset/:id/deleteupdate', [DatasetController, 'deleteUpdate']).as('dataset.deleteUpdate').use([middleware.auth(), middleware.can(['dataset-delete'])]);
|
||||
router.get('/person', [PersonController, 'index']).as('person.index').use([middleware.auth()]);
|
||||
router.get('/dataset/categorize', ({ inertia }: HttpContext) => {
|
||||
return inertia.render('Submitter/Dataset/Category');
|
||||
});
|
||||
}).prefix('submitter');
|
||||
router
|
||||
.group(() => {
|
||||
router
|
||||
.get('/dataset', [DatasetController, 'index'])
|
||||
.as('dataset.list')
|
||||
.use([middleware.auth(), middleware.can(['dataset-list'])]);
|
||||
router
|
||||
.get('/dataset/create', [DatasetController, 'create'])
|
||||
.as('dataset.create')
|
||||
.use([middleware.auth(), middleware.can(['dataset-submit'])]);
|
||||
router
|
||||
.post('/dataset/first/first-step', [DatasetController, 'firstStep'])
|
||||
.as('dataset.first.step')
|
||||
.use([middleware.auth(), middleware.can(['dataset-submit'])]);
|
||||
router
|
||||
.post('/dataset/second/second-step', [DatasetController, 'secondStep'])
|
||||
.as('dataset.second.step')
|
||||
.use([middleware.auth(), middleware.can(['dataset-submit'])]);
|
||||
router
|
||||
.post('/dataset/second/third-step', [DatasetController, 'thirdStep'])
|
||||
.as('dataset.third.step')
|
||||
.use([middleware.auth(), middleware.can(['dataset-submit'])]);
|
||||
router
|
||||
.post('/dataset/submit', [DatasetController, 'store'])
|
||||
.as('dataset.submit')
|
||||
.use([middleware.auth(), middleware.can(['dataset-submit'])]);
|
||||
router
|
||||
.get('/dataset/:id/release', [DatasetController, 'release'])
|
||||
.as('dataset.release')
|
||||
.where('id', router.matchers.number())
|
||||
.use([middleware.auth(), middleware.can(['dataset-edit'])]);
|
||||
router
|
||||
.put('/dataset/:id/releaseupdate', [DatasetController, 'releaseUpdate'])
|
||||
.as('dataset.releaseUpdate')
|
||||
.use([middleware.auth(), middleware.can(['dataset-edit'])]);
|
||||
router
|
||||
.get('/dataset/:id/edit', [DatasetController, 'edit'])
|
||||
.as('dataset.edit')
|
||||
.where('id', router.matchers.number())
|
||||
.use([middleware.auth(), middleware.can(['dataset-edit'])]);
|
||||
router
|
||||
.put('/dataset/:id/update', [DatasetController, 'update'])
|
||||
.as('dataset.update')
|
||||
.where('id', router.matchers.number())
|
||||
.use([middleware.auth(), middleware.can(['dataset-edit'])]);
|
||||
router
|
||||
.get('/dataset/:id/delete', [DatasetController, 'delete'])
|
||||
.as('dataset.delete')
|
||||
.use([middleware.auth(), middleware.can(['dataset-delete'])]);
|
||||
router
|
||||
.put('/dataset/:id/deleteupdate', [DatasetController, 'deleteUpdate'])
|
||||
.as('dataset.deleteUpdate')
|
||||
.use([middleware.auth(), middleware.can(['dataset-delete'])]);
|
||||
router.get('/person', [PersonController, 'index']).as('person.index').use([middleware.auth()]);
|
||||
router.get('/dataset/categorize', ({ inertia }: HttpContext) => {
|
||||
return inertia.render('Submitter/Dataset/Category');
|
||||
});
|
||||
})
|
||||
.prefix('submitter');
|
||||
|
||||
// Editor routes
|
||||
router.group(() => {
|
||||
router.get('/dataset', [EditorDatasetController, 'index']).as('editor.dataset.list').use([middleware.auth(), middleware.can(['dataset-editor-list'])]);
|
||||
router.get('dataset/:id/receive', [EditorDatasetController, 'receive']).as('editor.dataset.receive').where('id', router.matchers.number()).use([middleware.auth(), middleware.can(['dataset-receive'])]);
|
||||
router.put('dataset/:id/receive', [EditorDatasetController, 'receiveUpdate']).as('editor.dataset.receiveUpdate').where('id', router.matchers.number()).use([middleware.auth(), middleware.can(['dataset-receive'])]);
|
||||
router.get('dataset/:id/approve', [EditorDatasetController, 'approve']).as('editor.dataset.approve').where('id', router.matchers.number()).use([middleware.auth(), middleware.can(['dataset-approve'])]);
|
||||
router.put('dataset/:id/approve', [EditorDatasetController, 'approveUpdate']).as('editor.dataset.approveUpdate').where('id', router.matchers.number()).use([middleware.auth(), middleware.can(['dataset-approve'])]);
|
||||
router.get('dataset/:id/reject', [EditorDatasetController, 'reject']).as('editor.dataset.reject').where('id', router.matchers.number()).use([middleware.auth(), middleware.can(['dataset-editor-reject'])]);
|
||||
router.put('dataset/:id/reject', [EditorDatasetController, 'rejectUpdate']).as('editor.dataset.rejectUpdate').where('id', router.matchers.number()).use([middleware.auth(), middleware.can(['dataset-editor-reject'])]);
|
||||
router.get('dataset/:id/publish', [EditorDatasetController, 'publish']).as('editor.dataset.publish').where('id', router.matchers.number()).use([middleware.auth(), middleware.can(['dataset-publish'])]);
|
||||
router.put('dataset/:id/publish', [EditorDatasetController, 'publishUpdate']).as('editor.dataset.publishUpdate').where('id', router.matchers.number()).use([middleware.auth(), middleware.can(['dataset-publish'])]);
|
||||
router.get('dataset/:id/doi', [EditorDatasetController, 'doiCreate']).as('editor.dataset.doi').where('id', router.matchers.number()).use([middleware.auth(), middleware.can(['dataset-publish'])]);
|
||||
router.put('dataset/:publish_id/doi', [EditorDatasetController, 'doiStore']).as('editor.dataset.doiStore').where('id', router.matchers.number()).use([middleware.auth(), middleware.can(['dataset-publish'])]);
|
||||
router.put('/dataset/:id/update', [EditorDatasetController, 'update']).as('editor.dataset.update').use([middleware.auth(), middleware.can(['dataset-editor-edit'])]);
|
||||
}).prefix('editor');
|
||||
router
|
||||
.group(() => {
|
||||
router
|
||||
.get('/dataset', [EditorDatasetController, 'index'])
|
||||
.as('editor.dataset.list')
|
||||
.use([middleware.auth(), middleware.can(['dataset-editor-list'])]);
|
||||
router
|
||||
.get('dataset/:id/receive', [EditorDatasetController, 'receive'])
|
||||
.as('editor.dataset.receive')
|
||||
.where('id', router.matchers.number())
|
||||
.use([middleware.auth(), middleware.can(['dataset-receive'])]);
|
||||
router
|
||||
.put('dataset/:id/receive', [EditorDatasetController, 'receiveUpdate'])
|
||||
.as('editor.dataset.receiveUpdate')
|
||||
.where('id', router.matchers.number())
|
||||
.use([middleware.auth(), middleware.can(['dataset-receive'])]);
|
||||
router
|
||||
.get('dataset/:id/approve', [EditorDatasetController, 'approve'])
|
||||
.as('editor.dataset.approve')
|
||||
.where('id', router.matchers.number())
|
||||
.use([middleware.auth(), middleware.can(['dataset-approve'])]);
|
||||
router
|
||||
.put('dataset/:id/approve', [EditorDatasetController, 'approveUpdate'])
|
||||
.as('editor.dataset.approveUpdate')
|
||||
.where('id', router.matchers.number())
|
||||
.use([middleware.auth(), middleware.can(['dataset-approve'])]);
|
||||
router
|
||||
.get('dataset/:id/reject', [EditorDatasetController, 'reject'])
|
||||
.as('editor.dataset.reject')
|
||||
.where('id', router.matchers.number())
|
||||
.use([middleware.auth(), middleware.can(['dataset-editor-reject'])]);
|
||||
router
|
||||
.put('dataset/:id/reject', [EditorDatasetController, 'rejectUpdate'])
|
||||
.as('editor.dataset.rejectUpdate')
|
||||
.where('id', router.matchers.number())
|
||||
.use([middleware.auth(), middleware.can(['dataset-editor-reject'])]);
|
||||
router
|
||||
.get('dataset/:id/publish', [EditorDatasetController, 'publish'])
|
||||
.as('editor.dataset.publish')
|
||||
.where('id', router.matchers.number())
|
||||
.use([middleware.auth(), middleware.can(['dataset-publish'])]);
|
||||
router
|
||||
.put('dataset/:id/publish', [EditorDatasetController, 'publishUpdate'])
|
||||
.as('editor.dataset.publishUpdate')
|
||||
.where('id', router.matchers.number())
|
||||
.use([middleware.auth(), middleware.can(['dataset-publish'])]);
|
||||
router
|
||||
.get('dataset/:id/doi', [EditorDatasetController, 'doiCreate'])
|
||||
.as('editor.dataset.doi')
|
||||
.where('id', router.matchers.number())
|
||||
.use([middleware.auth(), middleware.can(['dataset-publish'])]);
|
||||
router
|
||||
.put('dataset/:publish_id/doi', [EditorDatasetController, 'doiStore'])
|
||||
.as('editor.dataset.doiStore')
|
||||
.where('id', router.matchers.number())
|
||||
.use([middleware.auth(), middleware.can(['dataset-publish'])]);
|
||||
router
|
||||
.put('/dataset/:id/update', [EditorDatasetController, 'update'])
|
||||
.as('editor.dataset.update')
|
||||
.use([middleware.auth(), middleware.can(['dataset-editor-edit'])]);
|
||||
})
|
||||
.prefix('editor');
|
||||
|
||||
// Reviewer routes
|
||||
router.group(() => {
|
||||
router.get('/dataset', [ReviewerDatasetController, 'index']).as('reviewer.dataset.list').use([middleware.auth(), middleware.can(['dataset-review-list'])]);
|
||||
router.get('dataset/:id/review', [ReviewerDatasetController, 'review']).as('reviewer.dataset.review').where('id', router.matchers.number()).use([middleware.auth(), middleware.can(['dataset-review'])]);
|
||||
router.put('dataset/:id/review', [ReviewerDatasetController, 'reviewUpdate']).as('reviewer.dataset.reviewUpdate').where('id', router.matchers.number()).use([middleware.auth(), middleware.can(['dataset-review'])]);
|
||||
router.get('dataset/:id/reject', [ReviewerDatasetController, 'reject']).as('reviewer.dataset.reject').where('id', router.matchers.number()).use([middleware.auth(), middleware.can(['dataset-review-reject'])]);
|
||||
router.put('dataset/:id/reject', [ReviewerDatasetController, 'rejectUpdate']).as('reviewer.dataset.rejectUpdate').where('id', router.matchers.number()).use([middleware.auth(), middleware.can(['dataset-review-reject'])]);
|
||||
}).prefix('reviewer');
|
||||
router
|
||||
.group(() => {
|
||||
router
|
||||
.get('/dataset', [ReviewerDatasetController, 'index'])
|
||||
.as('reviewer.dataset.list')
|
||||
.use([middleware.auth(), middleware.can(['dataset-review-list'])]);
|
||||
router
|
||||
.get('dataset/:id/review', [ReviewerDatasetController, 'review'])
|
||||
.as('reviewer.dataset.review')
|
||||
.where('id', router.matchers.number())
|
||||
.use([middleware.auth(), middleware.can(['dataset-review'])]);
|
||||
router
|
||||
.put('dataset/:id/review', [ReviewerDatasetController, 'reviewUpdate'])
|
||||
.as('reviewer.dataset.reviewUpdate')
|
||||
.where('id', router.matchers.number())
|
||||
.use([middleware.auth(), middleware.can(['dataset-review'])]);
|
||||
router
|
||||
.get('dataset/:id/reject', [ReviewerDatasetController, 'reject'])
|
||||
.as('reviewer.dataset.reject')
|
||||
.where('id', router.matchers.number())
|
||||
.use([middleware.auth(), middleware.can(['dataset-review-reject'])]);
|
||||
router
|
||||
.put('dataset/:id/reject', [ReviewerDatasetController, 'rejectUpdate'])
|
||||
.as('reviewer.dataset.rejectUpdate')
|
||||
.where('id', router.matchers.number())
|
||||
.use([middleware.auth(), middleware.can(['dataset-review-reject'])]);
|
||||
})
|
||||
.prefix('reviewer');
|
||||
|
|
|
@ -6,30 +6,32 @@ import HomeController from '#controllers/Http/Api/HomeController';
|
|||
import FileController from '#controllers/Http/Api/FileController';
|
||||
import AvatarController from '#controllers/Http/Api/AvatarController';
|
||||
import UserController from '#controllers/Http/Api/UserController';
|
||||
import { middleware } from '../kernel.js'
|
||||
import { middleware } from '../kernel.js';
|
||||
// API
|
||||
router.group(() => {
|
||||
|
||||
router
|
||||
.group(() => {
|
||||
router.get('authors', [AuthorsController, 'index']).as('author.index');
|
||||
router.get('datasets', [DatasetController, 'index']).as('dataset.index');
|
||||
router.get('persons', [AuthorsController, 'persons']).as('author.persons');
|
||||
|
||||
|
||||
router.get('authors', [AuthorsController, "index"]).as('author.index');
|
||||
router.get('datasets', [DatasetController, "index"]).as('dataset.index');
|
||||
router.get('persons', [AuthorsController, "persons"]).as('author.persons');
|
||||
|
||||
router.get('/dataset', [DatasetController, "findAll"]).as('dataset.findAll');
|
||||
router.get('/dataset/:publish_id', [DatasetController, "findOne"]).as('dataset.findOne');
|
||||
router.get('/sitelinks/:year', [HomeController, "findDocumentsPerYear"]);
|
||||
router.get('/years', [HomeController, "findYears"]);
|
||||
router.get('/statistic/:year', [HomeController, "findPublicationsPerMonth"]);
|
||||
router.get('/dataset', [DatasetController, 'findAll']).as('dataset.findAll');
|
||||
router.get('/dataset/:publish_id', [DatasetController, 'findOne']).as('dataset.findOne');
|
||||
router.get('/sitelinks/:year', [HomeController, 'findDocumentsPerYear']);
|
||||
router.get('/years', [HomeController, 'findYears']);
|
||||
router.get('/statistic/:year', [HomeController, 'findPublicationsPerMonth']);
|
||||
|
||||
router.get('/download/:id', [FileController, "findOne"]).as('file.findOne');
|
||||
router.get('/download/:id', [FileController, 'findOne']).as('file.findOne');
|
||||
|
||||
router.get('/avatar/:name/:background?/:textColor?/:size?', [AvatarController, 'generateAvatar']);
|
||||
|
||||
|
||||
router.post('/twofactor_totp/settings/enable/:state/:code?', [UserController, 'enable']).as('apps.twofactor_totp.enable') .use(middleware.auth());
|
||||
router.post('/twofactor_backupcodes/settings/create', [UserController, 'createCodes']).as('apps.twofactor_backupcodes.create') .use(middleware.auth());
|
||||
|
||||
})
|
||||
router
|
||||
.post('/twofactor_totp/settings/enable/:state/:code?', [UserController, 'enable'])
|
||||
.as('apps.twofactor_totp.enable')
|
||||
.use(middleware.auth());
|
||||
router
|
||||
.post('/twofactor_backupcodes/settings/create', [UserController, 'createCodes'])
|
||||
.as('apps.twofactor_backupcodes.create')
|
||||
.use(middleware.auth());
|
||||
})
|
||||
// .namespace('App/Controllers/Http/Api')
|
||||
.prefix('api');
|
||||
|
|
|
@ -9,27 +9,21 @@ import vine from '@vinejs/vine';
|
|||
// import { VineString } from '@vinejs/vine';
|
||||
import { VineMultipartFile, isBodyParserFile } from '#providers/vinejs_provider';
|
||||
import type { MultipartFile } from '@adonisjs/core/bodyparser';
|
||||
// import db from '@adonisjs/lucid/services/db';
|
||||
import MimeType from '#models/mime_type';
|
||||
|
||||
/**
|
||||
* Options accepted by the unique rule
|
||||
*/
|
||||
// type Options = {
|
||||
// mainLanguageField: string;
|
||||
// typeField: string;
|
||||
// };
|
||||
type Options = {
|
||||
// size: string | number;
|
||||
// extnames: string[];
|
||||
clientNameSizeLimit: number;
|
||||
// clientNameSizeLimit?: number;
|
||||
allowedExtensions: string[];
|
||||
allowedMimeTypes: string[];
|
||||
};
|
||||
|
||||
async function allowedMimetypeExtensions(file: VineMultipartFile | unknown, options: Options | unknown, field: FieldContext) {
|
||||
// if (typeof value !== 'string' && typeof value != 'number') {
|
||||
// return;
|
||||
// }
|
||||
|
||||
// async function allowedMimetypeExtensions(file: VineMultipartFile | unknown, options: Options | unknown, field: FieldContext) {
|
||||
async function allowedMimetypeExtensions(file: VineMultipartFile | unknown, options: Options, field: FieldContext) {
|
||||
if (!isBodyParserFile(file)) {
|
||||
return;
|
||||
}
|
||||
|
@ -38,7 +32,15 @@ async function allowedMimetypeExtensions(file: VineMultipartFile | unknown, opti
|
|||
const fileExtension = validatedFile?.extname?.toLocaleLowerCase() as string; // Get file extension from the file
|
||||
|
||||
// validate if file extension is allowed in combination with mimetype
|
||||
const mimeRecord = await MimeType.query().select('file_extension').where('name', mimeType).andWhere('enabled', true).first();
|
||||
let mimeRecord = await MimeType.query().select('file_extension').where('name', mimeType).andWhere('enabled', true).first();
|
||||
|
||||
if (!mimeRecord) {
|
||||
mimeRecord = await MimeType.query()
|
||||
.select('file_extension')
|
||||
.whereRaw("? = ANY (string_to_array(alternate_mimetype, '|'))", [mimeType])
|
||||
.andWhere('enabled', true)
|
||||
.first();
|
||||
}
|
||||
|
||||
if (!mimeRecord) {
|
||||
const allowedMimetypes = await MimeType.query().select('name').where('enabled', true);
|
||||
|
@ -52,14 +54,19 @@ async function allowedMimetypeExtensions(file: VineMultipartFile | unknown, opti
|
|||
field,
|
||||
);
|
||||
} else {
|
||||
const allowedExtensions = mimeRecord.file_extension.split('|');
|
||||
let allowedExtensions: string[] = [];
|
||||
if (options && options.allowedExtensions) {
|
||||
allowedExtensions = options.allowedExtensions;
|
||||
} else {
|
||||
allowedExtensions = mimeRecord.file_extension.split('|');
|
||||
}
|
||||
// Validate if the file's extension is in the allowed extensions
|
||||
if (!allowedExtensions.includes(fileExtension)) {
|
||||
//throw new Error(`File extension ${fileExtension} is not allowed for MIME type ${mimeType}`);
|
||||
field.report(
|
||||
`File extension ${fileExtension} is not allowed for MIME type ${mimeType}. Allowed extensions are: ${mimeRecord.file_extension}`,
|
||||
'allowedMimetypeExtensions',
|
||||
field
|
||||
'allowedMimetypeExtensions',
|
||||
field,
|
||||
);
|
||||
}
|
||||
// if (validatedFile.clientName.length > options.clientNameSizeLimit) {
|
||||
|
|
|
@ -3,37 +3,16 @@
|
|||
| Preloaded File - node ace make:preload rules/fileScan
|
||||
|--------------------------------------------------------------------------
|
||||
|*/
|
||||
|
||||
import { FieldContext } from '@vinejs/vine/types';
|
||||
import vine, { errors } from '@vinejs/vine';
|
||||
|
||||
// import { VineString } from '@vinejs/vine';
|
||||
import { VineMultipartFile, isBodyParserFile } from '#providers/vinejs_provider';
|
||||
import type { MultipartFile } from '@adonisjs/core/bodyparser';
|
||||
import ClamScan from 'clamscan';
|
||||
|
||||
/**
|
||||
* Options accepted by the unique rule
|
||||
*/
|
||||
// type Options = {
|
||||
// mainLanguageField: string;
|
||||
// typeField: string;
|
||||
// };
|
||||
type Options = {
|
||||
// size: string | number;
|
||||
// extnames: string[];
|
||||
removeInfected: boolean;
|
||||
// debugMode?: boolean;
|
||||
// scanRecursively?: boolean;
|
||||
host?: string;
|
||||
port?: number;
|
||||
// clamdscan: {
|
||||
// active: boolean;
|
||||
// host: string;
|
||||
// port: number;
|
||||
// multiscan: boolean;
|
||||
// };
|
||||
// preference: string;
|
||||
};
|
||||
|
||||
async function fileScan(file: VineMultipartFile | unknown, options: Options, field: FieldContext) {
|
||||
|
@ -44,42 +23,47 @@ async function fileScan(file: VineMultipartFile | unknown, options: Options, fie
|
|||
return;
|
||||
}
|
||||
const validatedFile = file as MultipartFile;
|
||||
|
||||
|
||||
try {
|
||||
await scanFileForViruses(validatedFile.tmpPath, options.host, options.port); //, 'gitea.lan', 3310);
|
||||
// await this.scanFileForViruses("/tmp/testfile.txt");
|
||||
await scanFileForViruses(validatedFile.tmpPath, options);
|
||||
} catch (error) {
|
||||
// If the file is infected or there's an error scanning the file, throw a validation exception
|
||||
// throw error;
|
||||
field.report(`Upload error. Code: ${error.code} message: ${error.messages.uploadError}`, 'fileScan', field);
|
||||
}
|
||||
}
|
||||
async function scanFileForViruses(filePath: string | undefined, host?: string, port?: number): Promise<void> {
|
||||
// const clamscan = await (new ClamScan().init());
|
||||
|
||||
async function scanFileForViruses(filePath: string | undefined, options: Options): Promise<void> {
|
||||
if (!filePath) {
|
||||
throw new errors.E_VALIDATION_ERROR({ uploadError: 'File path is undefined!' });
|
||||
}
|
||||
const opts: ClamScan.Options = {
|
||||
removeInfected: true, // If true, removes infected files
|
||||
debugMode: false, // Whether or not to log info/debug/error msgs to the console
|
||||
removeInfected: options.removeInfected, // If true, removes infected files
|
||||
debugMode: false, // If true, deep scan folders recursively
|
||||
scanRecursively: true, // If true, deep scan folders recursively
|
||||
clamdscan: {
|
||||
active: true, // If true, this module will consider using the clamdscan binary
|
||||
host,
|
||||
port,
|
||||
host: options.host,
|
||||
port: options.port,
|
||||
multiscan: true, // Scan using all available cores! Yay!
|
||||
},
|
||||
preference: 'clamdscan', // If clamdscan is found and active, it will be used by default
|
||||
};
|
||||
|
||||
const clamscan = await new ClamScan().init(opts);
|
||||
return new Promise(async (resolve, reject) => {
|
||||
try {
|
||||
const clamscan = await new ClamScan().init(opts);
|
||||
// You can re-use the `clamscan` object as many times as you want
|
||||
// const version = await clamscan.getVersion();
|
||||
// console.log(`ClamAV Version: ${version}`);
|
||||
const { file, isInfected, viruses } = await clamscan.isInfected(filePath);
|
||||
const result = await clamscan.isInfected(filePath);
|
||||
if (!result || typeof result.isInfected === 'undefined') {
|
||||
reject(new errors.E_VALIDATION_ERROR({ uploadError: 'Unexpected response from virus scan!' }));
|
||||
return;
|
||||
}
|
||||
const { file, isInfected, viruses } = result;
|
||||
if (isInfected) {
|
||||
console.log(`${file} is infected with ${viruses}!`);
|
||||
// reject(new ValidationException(true, { 'upload error': `File ${file} is infected!` }));
|
||||
reject(new errors.E_VALIDATION_ERROR({ uploadError: `File ${file} is infected!` }));
|
||||
console.log(`${file} is infected with ${viruses}!`); // reject(new ValidationException(true, { 'upload error': `File ${file} is infected!` }));
|
||||
reject(new errors.E_VALIDATION_ERROR({ uploadError: `File ${file} is infected with ${viruses}!` }));
|
||||
} else {
|
||||
resolve();
|
||||
}
|
||||
|
|
115
start/rules/referenceValidation.ts
Normal file
115
start/rules/referenceValidation.ts
Normal file
|
@ -0,0 +1,115 @@
|
|||
import { FieldContext } from '@vinejs/vine/types';
|
||||
import vine from '@vinejs/vine';
|
||||
import { VineString } from '@vinejs/vine';
|
||||
import { default as axios } from 'axios';
|
||||
import { ReferenceIdentifierTypes } from '#contracts/enums';
|
||||
|
||||
type Options = {
|
||||
typeField: string;
|
||||
};
|
||||
|
||||
// Function to check if DOI exists using the DOI API
|
||||
async function checkDoiExists(doi: string): Promise<boolean> {
|
||||
try {
|
||||
const response = await axios.get(`${doi}`);
|
||||
return response.status === 200; // If status is 200, DOI is valid
|
||||
} catch (error) {
|
||||
return false; // If request fails, DOI does not exist
|
||||
}
|
||||
}
|
||||
|
||||
// Function to check if ISBN exists using the Open Library API
|
||||
async function checkIsbnExists(isbn: string): Promise<boolean> {
|
||||
try {
|
||||
const response = await axios.get(`https://isbnsearch.org/isbn/${isbn}`);
|
||||
return response.status === 200 && response.data.includes('ISBN'); // Check if response contains ISBN information
|
||||
} catch (error) {
|
||||
return false; // If request fails, ISBN does not exist
|
||||
}
|
||||
}
|
||||
|
||||
async function validateReference(value: unknown, options: Options, field: FieldContext) {
|
||||
if (typeof value !== 'string') {
|
||||
return;
|
||||
}
|
||||
|
||||
const type = field.parent[options.typeField];
|
||||
|
||||
if (type === ReferenceIdentifierTypes.URL) {
|
||||
if (!/^https?:\/\/[^\s$.?#].[^\s]*$/.test(value)) {
|
||||
field.report('The {{ field }} must be a valid URL', 'validateReference', field);
|
||||
} else {
|
||||
try {
|
||||
const exists = await checkDoiExists(value);
|
||||
if (!exists) {
|
||||
field.report('The {{ field }} must be an existing DOI', 'validateReference', field);
|
||||
}
|
||||
} catch (error) {
|
||||
field.report('Error checking DOI existence: ' + error.message, 'validateReference', field);
|
||||
}
|
||||
}
|
||||
}
|
||||
// Check if the value does not match the DOI pattern
|
||||
// The regex pattern ^10.\d{4,9}\/[-._;()/:a-zA-Z0-9]+$ is designed to match valid DOI formats.
|
||||
// - ^10. ensures that the string starts with "10."
|
||||
// - \d{4,9} matches a sequence of 4 to 9 digits.
|
||||
// - \/ matches the literal forward slash character.
|
||||
// - [-._;()/:a-zA-Z0-9]+ matches one or more characters that can include uppercase and lowercase letters, digits, and a set of special characters.
|
||||
// The i flag at the end of the regex makes the matching case-insensitive, meaning it will match both uppercase and lowercase letters.
|
||||
// If the value does not match this pattern, the code inside the if block will execute.
|
||||
else if (type === ReferenceIdentifierTypes.DOI) {
|
||||
// Extract the DOI from the URL if it starts with 'https://doi.org/'
|
||||
const doiPattern = /^https:\/\/doi\.org\/(10.\d{4,9}\/[-._;()/:a-zA-Z0-9]+)$/i;
|
||||
const match = value.match(doiPattern);
|
||||
const doi = match ? match[1] : value;
|
||||
// Check if the extracted DOI or the value itself matches the DOI patter
|
||||
if (!/^10.\d{4,9}\/[-._;()/:a-zA-Z0-9]+$/i.test(doi)) {
|
||||
field.report('The {{ field }} must be a valid DOI', 'validateReference', field);
|
||||
} else {
|
||||
try {
|
||||
const exists = await checkDoiExists(value);
|
||||
if (!exists) {
|
||||
field.report('The {{ field }} must be an existing DOI', 'validateReference', field);
|
||||
}
|
||||
} catch (error) {
|
||||
field.report('Error checking DOI existence: ' + error.message, 'validateReference', field);
|
||||
}
|
||||
}
|
||||
} else if (type === ReferenceIdentifierTypes.ISBN) {
|
||||
const isbnRegex = /^(?:\d{1,5}-\d{1,7}-\d{1,7}-[\dX]$|97[89]-\d{1,5}-\d{1,7}-\d{1,7}-\d)$/;
|
||||
if (!isbnRegex.test(value)) {
|
||||
field.report('Invalid {{ field }}. Expected format: 978-3-16-148410-0 or similar.', 'validateReference', field);
|
||||
} else {
|
||||
try {
|
||||
const exists = await checkIsbnExists(value);
|
||||
if (!exists) {
|
||||
field.report('The {{ field }} must be an existing ISBN', 'validateReference', field);
|
||||
}
|
||||
} catch (error) {
|
||||
field.report('Error checking ISBN existence: ' + error.message, 'validateReference', field);
|
||||
}
|
||||
}
|
||||
} else if (type === ReferenceIdentifierTypes.Handle && !/^\d{2,}.\d{4,9}\/[-._;()/:a-zA-Z0-9]+$/.test(value)) {
|
||||
/// Extract the Handle from the URL if it contains '/handle/'
|
||||
field.report('The {{ field }} must be a valid Handle', 'validateReference', field);
|
||||
} else if (
|
||||
type === ReferenceIdentifierTypes.URN &&
|
||||
!/^urn:[a-zA-Z0-9][a-zA-Z0-9-]{0,31}:[a-zA-Z0-9()+,\-.:=@;$_!*'%/?#]+$/.test(value)
|
||||
) {
|
||||
field.report('The {{ field }} must be a valid URN', 'validateReference', field);
|
||||
} else if (type === ReferenceIdentifierTypes.ISSN && !/^\d{4}-\d{3}[\dxX]$/.test(value)) {
|
||||
field.report('The {{ field }} must be a valid ISSN', 'validateReference', field);
|
||||
}
|
||||
}
|
||||
|
||||
export const validateReferenceRule = vine.createRule(validateReference);
|
||||
|
||||
declare module '@vinejs/vine' {
|
||||
interface VineString {
|
||||
validateReference(options: Options): this;
|
||||
}
|
||||
}
|
||||
|
||||
VineString.macro('validateReference', function (this: VineString, options: Options) {
|
||||
return this.use(validateReferenceRule(options));
|
||||
});
|
|
@ -17,7 +17,7 @@ type Options = {
|
|||
};
|
||||
|
||||
async function translatedLanguage(value: unknown, options: Options, field: FieldContext) {
|
||||
if (typeof value !== 'string' && typeof value != 'number') {
|
||||
if (typeof value !== 'string' && typeof value !== 'number') {
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -15,11 +15,11 @@ import { VineString, VineNumber } from '@vinejs/vine';
|
|||
type Options = {
|
||||
table: string;
|
||||
column: string;
|
||||
whereNot?: ((field: FieldContext) => string);
|
||||
whereNot?: (field: FieldContext) => string;
|
||||
};
|
||||
|
||||
async function isUnique(value: unknown, options: Options, field: FieldContext) {
|
||||
if (typeof value !== 'string' && typeof value != 'number') {
|
||||
if (typeof value !== 'string' && typeof value !== 'number') {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -37,13 +37,11 @@ async function isUnique(value: unknown, options: Options, field: FieldContext) {
|
|||
// report that value is NOT unique
|
||||
field.report('The {{ field }} field is not unique', 'isUnique', field);
|
||||
// field.report(messages.unique, "isUnique", field);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export const isUniqueRule = vine.createRule(isUnique);
|
||||
|
||||
|
||||
declare module '@vinejs/vine' {
|
||||
interface VineString {
|
||||
isUnique(options: Options): this;
|
||||
|
@ -58,4 +56,4 @@ VineString.macro('isUnique', function (this: VineString, options: Options) {
|
|||
});
|
||||
VineNumber.macro('isUnique', function (this: VineNumber, options: Options) {
|
||||
return this.use(isUniqueRule(options));
|
||||
});
|
||||
});
|
||||
|
|
|
@ -19,9 +19,8 @@ type Options = {
|
|||
idField: string;
|
||||
};
|
||||
|
||||
|
||||
async function isUniquePerson(value: unknown, options: Options, field: FieldContext) {
|
||||
if (typeof value !== 'string' && typeof value != 'number') {
|
||||
if (typeof value !== 'string' && typeof value !== 'number') {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -40,13 +39,11 @@ async function isUniquePerson(value: unknown, options: Options, field: FieldCont
|
|||
if (result) {
|
||||
// report that value is NOT unique
|
||||
field.report('The {{ field }} field is not unique', 'isUnique', field);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export const isUniquePersonRule = vine.createRule(isUniquePerson);
|
||||
|
||||
|
||||
declare module '@vinejs/vine' {
|
||||
interface VineString {
|
||||
isUniquePerson(options: Options): this;
|
||||
|
@ -61,4 +58,4 @@ VineString.macro('isUniquePerson', function (this: VineString, options: Options)
|
|||
});
|
||||
VineNumber.macro('isUniquePerson', function (this: VineNumber, options: Options) {
|
||||
return this.use(isUniquePersonRule(options));
|
||||
});
|
||||
});
|
||||
|
|
29
start/rules/valid_mimetype.ts
Normal file
29
start/rules/valid_mimetype.ts
Normal file
|
@ -0,0 +1,29 @@
|
|||
import { FieldContext } from '@vinejs/vine/types';
|
||||
import vine from '@vinejs/vine';
|
||||
import { VineString } from '@vinejs/vine';
|
||||
|
||||
async function isValidMimetype(value: unknown, options: unknown, field: FieldContext) {
|
||||
if (typeof value !== 'string') {
|
||||
return;
|
||||
}
|
||||
|
||||
// Regex pattern to match valid mimetypes (e.g., "application/json", "text/html")
|
||||
const mimetypePattern = /^[a-zA-Z0-9!#$&^_.+-]+\/[a-zA-Z0-9!#$&^_.+-]+$/;
|
||||
if (!mimetypePattern.test(value)) {
|
||||
field.report('The given value is not a valid mimetype', 'isValidMimetype', field);
|
||||
}
|
||||
}
|
||||
|
||||
export const isValidMimetypeRule = vine.createRule(isValidMimetype);
|
||||
|
||||
declare module '@vinejs/vine' {
|
||||
interface VineString {
|
||||
isValidMimetype(): this;
|
||||
}
|
||||
}
|
||||
|
||||
VineString.macro('isValidMimetype', function (this: VineString) {
|
||||
return this.use(isValidMimetypeRule());
|
||||
});
|
||||
|
||||
|
|
@ -13,20 +13,18 @@ import vine from '@vinejs/vine';
|
|||
// import db from '@adonisjs/lucid/services/db';
|
||||
import { VanillaErrorReporter } from '#validators/vanilla_error_reporter';
|
||||
|
||||
|
||||
// vine.messagesProvider = new SimpleMessagesProvider({
|
||||
// // Applicable for all fields
|
||||
// 'required': 'The {{ field }} field is required',
|
||||
// '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();
|
||||
|
||||
|
||||
// /**
|
||||
// * Options accepted by the unique rule
|
||||
|
|
|
@ -12,10 +12,10 @@ import testUtils from '@adonisjs/core/services/test_utils';
|
|||
// import { assert, runFailedTests, specReporter, apiClient } from '@japa/preset-adonis';
|
||||
|
||||
import { assert } from '@japa/assert';
|
||||
import { apiClient } from '@japa/api-client';
|
||||
// import { apiClient } from '@japa/api-client';
|
||||
import { pluginAdonisJS } from '@japa/plugin-adonisjs';
|
||||
import app from '@adonisjs/core/services/app';
|
||||
|
||||
// import env from '#start/env'
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Japa Plugins
|
||||
|
@ -28,7 +28,13 @@ import app from '@adonisjs/core/services/app';
|
|||
|
|
||||
*/
|
||||
// export const plugins: Required<Config>['plugins'] = [assert(), runFailedTests(), apiClient()];
|
||||
export const plugins: Config['plugins'] = [assert(), apiClient(), pluginAdonisJS(app)];
|
||||
export const plugins: Config['plugins'] = [
|
||||
assert(),
|
||||
// apiClient({
|
||||
// baseURL: `http://${env.get('HOST')}:${env.get('PORT')}`,
|
||||
// }),
|
||||
pluginAdonisJS(app),
|
||||
];
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
|
@ -59,11 +65,18 @@ export const reporters: Required<Config>['reporters'] = {
|
|||
*/
|
||||
export const runnerHooks: Pick<Required<Config>, 'setup' | 'teardown'> = {
|
||||
setup: [
|
||||
() => {
|
||||
console.log('running before all the tests');
|
||||
},
|
||||
// () => testUtils.ace().loadCommands(),
|
||||
() => testUtils.db().migrate(),
|
||||
// () => testUtils.httpServer().start(),
|
||||
],
|
||||
teardown: [],
|
||||
teardown: [
|
||||
() => {
|
||||
console.log('running after all the tests');
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
/*
|
||||
|
|
|
@ -8,7 +8,7 @@ import User from '#models/user';
|
|||
import Role from '#models/role';
|
||||
import Permission from '#models/permission';
|
||||
import { TestContext } from '@japa/runner/core';
|
||||
const BASE_URL = `http://${process.env.HOST}:${process.env.PORT}`
|
||||
const BASE_URL = `http://${process.env.HOST}:${process.env.PORT}`;
|
||||
|
||||
test.group('DatasetController', (group) => {
|
||||
// Write your test here
|
||||
|
@ -24,8 +24,6 @@ test.group('DatasetController', (group) => {
|
|||
// server = await supertest(BASE_URL);
|
||||
// });
|
||||
|
||||
|
||||
|
||||
test('should render dataset release page', async ({ assert }: TestContext) => {
|
||||
var testAgent = supertest(BASE_URL);
|
||||
|
||||
|
@ -35,19 +33,18 @@ test.group('DatasetController', (group) => {
|
|||
email: 'alice@email.com',
|
||||
password: 'password',
|
||||
});
|
||||
|
||||
|
||||
const role = await Role.create({
|
||||
name: 'administrator',
|
||||
display_name: 'admin',
|
||||
description: 'User has access to all system functionality'
|
||||
description: 'User has access to all system functionality',
|
||||
});
|
||||
await user.related('roles').attach([role.id]);
|
||||
|
||||
|
||||
const permission = await Permission.create({
|
||||
name: 'dataset-edit',
|
||||
display_name: 'edit dataset',
|
||||
description: 'allow role to edit datasets'
|
||||
description: 'allow role to edit datasets',
|
||||
});
|
||||
await role.related('permissions').attach([permission.id]);
|
||||
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
import { test } from '@japa/runner';
|
||||
// import { test } from '@japa/runner';
|
||||
|
||||
test('display welcome page', async ({ client }) => {
|
||||
const response = await client.get('/welcome');
|
||||
// test('display welcome page', async ({ client }) => {
|
||||
// const response = await client.get('/welcome');
|
||||
|
||||
response.assertStatus(200);
|
||||
response.assertTextIncludes('<h1 class="title"> It Works! </h1>');
|
||||
});
|
||||
// response.assertStatus(200);
|
||||
// response.assertTextIncludes('<h1 class="title"> It Works! </h1>');
|
||||
// });
|
||||
|
|
215
tests/functional/referenceValidation.spec.ts
Normal file
215
tests/functional/referenceValidation.spec.ts
Normal file
|
@ -0,0 +1,215 @@
|
|||
import { test } from '@japa/runner';
|
||||
import { ReferenceIdentifierTypes } from '#contracts/enums';
|
||||
import vine from '@vinejs/vine';
|
||||
|
||||
// node ace test functional --groups "ReferenceValidation"
|
||||
test.group('ReferenceValidation', () => {
|
||||
test('validate valid DOI', async ({ assert }) => {
|
||||
const validator = vine.compile(
|
||||
vine.object({
|
||||
reference: vine.string().validateReference({ typeField: 'type' }),
|
||||
type: vine.enum(Object.values(ReferenceIdentifierTypes)),
|
||||
}),
|
||||
);
|
||||
|
||||
const data = {
|
||||
reference: 'https://doi.org/10.24341/tethys.236',
|
||||
type: ReferenceIdentifierTypes.DOI,
|
||||
};
|
||||
|
||||
try {
|
||||
const payload = await validator.validate(data);
|
||||
assert.deepEqual(payload, data);
|
||||
} catch {
|
||||
assert.isTrue(false);
|
||||
}
|
||||
});
|
||||
|
||||
test('validate invalid DOI', async ({ assert }) => {
|
||||
const validator = vine.compile(
|
||||
vine.object({
|
||||
reference: vine.string().validateReference({ typeField: 'type' }),
|
||||
type: vine.enum(Object.values(ReferenceIdentifierTypes)),
|
||||
}),
|
||||
);
|
||||
|
||||
const data = {
|
||||
reference: 'https://doi.org/invalid-doi',
|
||||
type: ReferenceIdentifierTypes.DOI,
|
||||
};
|
||||
|
||||
let payload = {};
|
||||
try {
|
||||
payload = await validator.validate(data);
|
||||
} catch {
|
||||
assert.notDeepEqual(payload, data);
|
||||
}
|
||||
});
|
||||
|
||||
test('validate valid Handle', async ({ assert }) => {
|
||||
const validator = vine.compile(
|
||||
vine.object({
|
||||
reference: vine.string().validateReference({ typeField: 'type' }),
|
||||
type: vine.enum(Object.values(ReferenceIdentifierTypes)),
|
||||
}),
|
||||
);
|
||||
|
||||
const data = {
|
||||
reference: '20.5000/abc123',
|
||||
type: ReferenceIdentifierTypes.Handle,
|
||||
};
|
||||
|
||||
try {
|
||||
const payload = await validator.validate(data);
|
||||
assert.deepEqual(payload, data);
|
||||
} catch {
|
||||
assert.isTrue(false);
|
||||
}
|
||||
});
|
||||
test('validate valid ISBN', async ({ assert }) => {
|
||||
const validator = vine.compile(
|
||||
vine.object({
|
||||
reference: vine.string().validateReference({ typeField: 'type' }),
|
||||
type: vine.enum(Object.values(ReferenceIdentifierTypes)),
|
||||
}),
|
||||
);
|
||||
|
||||
const data = {
|
||||
// reference: '978-3-85316-090-9',
|
||||
// reference: '9783853160909',
|
||||
// reference: '978-3-900312-64-0', // Geologische Karte der Republik Österreich 1 : 50.000
|
||||
reference: '3-90031-264-8', // Geologische Karte der Republik Österreich 1 : 50.000
|
||||
type: ReferenceIdentifierTypes.ISBN,
|
||||
};
|
||||
|
||||
try {
|
||||
const payload = await validator.validate(data);
|
||||
assert.deepEqual(payload, data);
|
||||
} catch {
|
||||
assert.isTrue(false);
|
||||
}
|
||||
});
|
||||
|
||||
test('validate invalid ISBN', async ({ assert }) => {
|
||||
const validator = vine.compile(
|
||||
vine.object({
|
||||
reference: vine.string().validateReference({ typeField: 'type' }),
|
||||
type: vine.enum(Object.values(ReferenceIdentifierTypes)),
|
||||
}),
|
||||
);
|
||||
|
||||
const data = {
|
||||
reference: 'invalid-isbn',
|
||||
type: ReferenceIdentifierTypes.ISBN,
|
||||
};
|
||||
|
||||
let payload = {};
|
||||
try {
|
||||
payload = await validator.validate(data);
|
||||
} catch {
|
||||
assert.notDeepEqual(payload, data);
|
||||
}
|
||||
});
|
||||
|
||||
test('validate valid URN', async ({ assert }) => {
|
||||
const validator = vine.compile(
|
||||
vine.object({
|
||||
reference: vine.string().validateReference({ typeField: 'type' }),
|
||||
type: vine.enum(Object.values(ReferenceIdentifierTypes)),
|
||||
}),
|
||||
);
|
||||
|
||||
const data = {
|
||||
reference: 'urn:isbn:0451450523',
|
||||
type: ReferenceIdentifierTypes.URN,
|
||||
};
|
||||
|
||||
try {
|
||||
const payload = await validator.validate(data);
|
||||
assert.deepEqual(payload, data);
|
||||
} catch {
|
||||
assert.isTrue(false);
|
||||
}
|
||||
});
|
||||
|
||||
test('validate invalid URN', async ({ assert }) => {
|
||||
const validator = vine.compile(
|
||||
vine.object({
|
||||
reference: vine.string().validateReference({ typeField: 'type' }),
|
||||
type: vine.enum(Object.values(ReferenceIdentifierTypes)),
|
||||
}),
|
||||
);
|
||||
|
||||
const data = {
|
||||
reference: 'invalid-urn',
|
||||
type: ReferenceIdentifierTypes.URN,
|
||||
};
|
||||
|
||||
let payload = {};
|
||||
try {
|
||||
payload = await validator.validate(data);
|
||||
} catch {
|
||||
assert.notDeepEqual(payload, data);
|
||||
}
|
||||
});
|
||||
|
||||
test('validate valid ISSN', async ({ assert }) => {
|
||||
const validator = vine.compile(
|
||||
vine.object({
|
||||
reference: vine.string().validateReference({ typeField: 'type' }),
|
||||
type: vine.enum(Object.values(ReferenceIdentifierTypes)),
|
||||
}),
|
||||
);
|
||||
|
||||
const data = {
|
||||
reference: '1234-567X',
|
||||
type: ReferenceIdentifierTypes.ISSN,
|
||||
};
|
||||
|
||||
try {
|
||||
const payload = await validator.validate(data);
|
||||
assert.deepEqual(payload, data);
|
||||
} catch {
|
||||
assert.isTrue(false);
|
||||
}
|
||||
});
|
||||
|
||||
test('validate invalid ISSN', async ({ assert }) => {
|
||||
const validator = vine.compile(
|
||||
vine.object({
|
||||
reference: vine.string().validateReference({ typeField: 'type' }),
|
||||
type: vine.enum(Object.values(ReferenceIdentifierTypes)),
|
||||
}),
|
||||
);
|
||||
|
||||
const data = {
|
||||
reference: 'invalid-issn',
|
||||
type: ReferenceIdentifierTypes.ISSN,
|
||||
};
|
||||
|
||||
let payload = {};
|
||||
try {
|
||||
payload = await validator.validate(data);
|
||||
} catch {
|
||||
assert.notDeepEqual(payload, data);
|
||||
}
|
||||
});
|
||||
// test('validate invalid Handle', async ({ assert }) => {
|
||||
// const validator = vine.compile(
|
||||
// vine.object({
|
||||
// reference: vine.string().validateReference({ typeField: 'type' }),
|
||||
// type: vine.enum(Object.values(ReferenceIdentifierTypes)),
|
||||
// })
|
||||
// );
|
||||
|
||||
// const data = {
|
||||
// reference: 'invalid-handle',
|
||||
// type: ReferenceIdentifierTypes.Handle,
|
||||
// };
|
||||
|
||||
// const result = await validator.validate(data);
|
||||
// assert.isFalse(result.valid);
|
||||
// });
|
||||
|
||||
// Add more tests for other reference types as needed
|
||||
});
|
|
@ -10,8 +10,8 @@
|
|||
"node_modules",
|
||||
"build",
|
||||
"public",
|
||||
"./resources/js/**/*.vue",
|
||||
"./resources/js/**/*.ts"
|
||||
"./resources/js/**/*",
|
||||
// "./resources/js/**/*.ts"
|
||||
],
|
||||
// "exclude": ["./inertia/**/*"]
|
||||
"compilerOptions": {
|
||||
|
@ -19,9 +19,10 @@
|
|||
"outDir": "build",
|
||||
"rootDir": "./",
|
||||
"sourceMap": true,
|
||||
"sourceRoot": "./build",
|
||||
"experimentalDecorators": true,
|
||||
"strictPropertyInitialization": false,
|
||||
"target": "esnext",
|
||||
"target": "esnext", // Update to a version that supports top-level await
|
||||
"skipLibCheck": true,
|
||||
"esModuleInterop": true,
|
||||
"allowSyntheticDefaultImports": true,
|
||||
|
|
78
vite.config.ts
Normal file
78
vite.config.ts
Normal file
|
@ -0,0 +1,78 @@
|
|||
import { defineConfig } from 'vite';
|
||||
import adonisjs from '@adonisjs/vite/client';
|
||||
// import { getDirname } from '@adonisjs/core/helpers';
|
||||
import vue from '@vitejs/plugin-vue';
|
||||
import path from 'path';
|
||||
// import tailwind from '@tailwindcss/postcss';
|
||||
// import autoprefixer from 'autoprefixer';
|
||||
// import postcssNesting from 'postcss-nesting';
|
||||
import inertia from '@adonisjs/inertia/client';
|
||||
|
||||
export default defineConfig({
|
||||
plugins: [
|
||||
inertia(),
|
||||
vue(),
|
||||
adonisjs({
|
||||
/**
|
||||
* Entrypoints of your application. Each entrypoint will
|
||||
* result in a separate bundle.
|
||||
*/
|
||||
entrypoints: ['resources/js/app.ts', 'resources/css/app.css'],
|
||||
|
||||
/**
|
||||
* Paths to watch and reload the browser on file change
|
||||
*/
|
||||
reload: ['resources/views/**/*.edge'],
|
||||
}),
|
||||
],
|
||||
server: {
|
||||
port: 5173,
|
||||
// host: '127.0.0.1'
|
||||
},
|
||||
|
||||
// css: {
|
||||
// postcss: {
|
||||
// plugins: [
|
||||
// postcssNesting(),
|
||||
// tailwind(),
|
||||
// autoprefixer(),
|
||||
// ],
|
||||
// },
|
||||
// },
|
||||
/**
|
||||
* Define aliases for importing modules from
|
||||
* your frontend code
|
||||
*/
|
||||
resolve: {
|
||||
alias: {
|
||||
'@': path.resolve('./resources/js/'),
|
||||
'~': path.resolve(__dirname, 'node_modules/'),
|
||||
},
|
||||
},
|
||||
|
||||
// optimizeDeps: {
|
||||
// esbuildOptions: {
|
||||
// target: 'esnext'
|
||||
// },
|
||||
// include: ['resources/js/**/*.{vue,js,jsx,ts,tsx}'],
|
||||
// exclude: ['node_modules', 'app'],
|
||||
// },
|
||||
|
||||
build: {
|
||||
sourcemap: true,
|
||||
outDir: 'public/assets',
|
||||
emptyOutDir: true,
|
||||
manifest: true,
|
||||
rollupOptions: {
|
||||
input: 'resources/js/app.ts',
|
||||
},
|
||||
},
|
||||
// build: {
|
||||
// outDir: 'public/assets',
|
||||
// emptyOutDir: true,
|
||||
// manifest: true,
|
||||
// rollupOptions: {
|
||||
// input: path.resolve(__dirname, 'resources/js/app.ts'),
|
||||
// },
|
||||
// },
|
||||
});
|
|
@ -302,18 +302,18 @@ Encore.addLoader({
|
|||
// vue$: 'vue/dist/vue.runtime.esm-bundler.js',
|
||||
// });
|
||||
|
||||
Encore.addLoader(babelLoader)
|
||||
// Encore.enableTypeScriptLoader(config => {
|
||||
// // Loader-specific options
|
||||
// config.configFile = 'resources/js/tsconfig.json';
|
||||
// config.appendTsSuffixTo = [/\.vue$/];
|
||||
// config.transpileOnly = true;
|
||||
// config.happyPackMode = false;
|
||||
// }, {
|
||||
// // Directly change the exclude rule
|
||||
// exclude: /node_modules/,
|
||||
// Encore.addLoader(babelLoader)
|
||||
Encore.enableTypeScriptLoader(config => {
|
||||
// Loader-specific options
|
||||
config.configFile = 'resources/js/tsconfig.json';
|
||||
config.appendTsSuffixTo = [/\.vue$/];
|
||||
config.transpileOnly = true;
|
||||
config.happyPackMode = false;
|
||||
}, {
|
||||
// Directly change the exclude rule
|
||||
exclude: /node_modules/,
|
||||
|
||||
// })
|
||||
})
|
||||
.addAliases({
|
||||
'@': join(__dirname, 'resources/js'),
|
||||
'vue$': 'vue/dist/vue.runtime.esm-bundler.js',
|
||||
|
|
Loading…
Add table
Reference in a new issue