- addes @adonisjs/redis fo saving session into redis with redis.ts contract and config
Some checks failed
CI Pipeline / japa-tests (push) Failing after 52s
Some checks failed
CI Pipeline / japa-tests (push) Failing after 52s
- npm updated - added createHashValues and dlete inside File.ts - added dataset_count property inside Subject.ts - corrected rotes.ts with correct permissions
This commit is contained in:
parent
d8bdce1369
commit
b6fdfbff41
|
@ -19,11 +19,15 @@
|
|||
"./start/kernel",
|
||||
{
|
||||
"file": "./start/inertia",
|
||||
"environment": ["web"]
|
||||
"environment": [
|
||||
"web"
|
||||
]
|
||||
},
|
||||
{
|
||||
"file": "./start/validator",
|
||||
"environment": ["web"]
|
||||
"environment": [
|
||||
"web"
|
||||
]
|
||||
}
|
||||
],
|
||||
"providers": [
|
||||
|
@ -37,7 +41,8 @@
|
|||
"@adonisjs/auth",
|
||||
"@eidellev/adonis-stardust",
|
||||
"./providers/QueryBuilderProvider",
|
||||
"./providers/TokenWorkerProvider"
|
||||
"./providers/TokenWorkerProvider",
|
||||
"@adonisjs/redis"
|
||||
],
|
||||
"metaFiles": [
|
||||
{
|
||||
|
@ -49,15 +54,21 @@
|
|||
"reloadServer": false
|
||||
}
|
||||
],
|
||||
"aceProviders": ["@adonisjs/repl"],
|
||||
"aceProviders": [
|
||||
"@adonisjs/repl"
|
||||
],
|
||||
"tests": {
|
||||
"suites": [
|
||||
{
|
||||
"name": "functional",
|
||||
"files": ["tests/functional/**/*.spec(.ts|.js)"],
|
||||
"files": [
|
||||
"tests/functional/**/*.spec(.ts|.js)"
|
||||
],
|
||||
"timeout": 60000
|
||||
}
|
||||
]
|
||||
},
|
||||
"testProviders": ["@japa/preset-adonis/TestsProvider"]
|
||||
"testProviders": [
|
||||
"@japa/preset-adonis/TestsProvider"
|
||||
]
|
||||
}
|
||||
|
|
|
@ -11,3 +11,7 @@ PG_PORT=5432
|
|||
PG_USER=lucid
|
||||
PG_PASSWORD=
|
||||
PG_DB_NAME=lucid
|
||||
REDIS_CONNECTION=local
|
||||
REDIS_HOST=127.0.0.1
|
||||
REDIS_PORT=6379
|
||||
REDIS_PASSWORD=
|
||||
|
|
|
@ -34,6 +34,7 @@ import ClamScan from 'clamscan';
|
|||
import { ValidationException } from '@ioc:Adonis/Core/Validator';
|
||||
import Drive from '@ioc:Adonis/Core/Drive';
|
||||
import { Exception } from '@adonisjs/core/build/standalone';
|
||||
import { MultipartFileContract } from '@ioc:Adonis/Core/BodyParser';
|
||||
|
||||
export default class DatasetController {
|
||||
public async index({ auth, request, inertia }: HttpContextContract) {
|
||||
|
@ -335,8 +336,8 @@ export default class DatasetController {
|
|||
}
|
||||
|
||||
session.flash('message', 'Dataset has been created successfully');
|
||||
// return response.redirect().toRoute('user.index');
|
||||
return response.redirect().back();
|
||||
return response.redirect().toRoute('user.index');
|
||||
// return response.redirect().back();
|
||||
}
|
||||
|
||||
private async createDatasetAndAssociations(user: User, request: HttpContextContract['request'], trx: TransactionClientContract) {
|
||||
|
@ -691,7 +692,10 @@ export default class DatasetController {
|
|||
.preload('licenses')
|
||||
.preload('authors')
|
||||
.preload('contributors')
|
||||
.preload('subjects')
|
||||
// .preload('subjects')
|
||||
.preload('subjects', (builder) => {
|
||||
builder.orderBy('id', 'asc').withCount('datasets');
|
||||
})
|
||||
.preload('references')
|
||||
.preload('files');
|
||||
|
||||
|
@ -779,6 +783,7 @@ export default class DatasetController {
|
|||
throw error;
|
||||
// return response.badRequest(error.messages);
|
||||
}
|
||||
// await request.validate(UpdateDatasetValidator);
|
||||
const id = request.param('id');
|
||||
|
||||
let trx: TransactionClientContract | null = null;
|
||||
|
@ -843,6 +848,25 @@ export default class DatasetController {
|
|||
}
|
||||
}
|
||||
|
||||
// await dataset.useTransaction(trx).related('subjects').sync([]);
|
||||
const keywords = request.input('subjects');
|
||||
for (const keywordData of keywords) {
|
||||
if (keywordData.id) {
|
||||
const subject = await Subject.findOrFail(keywordData.id);
|
||||
// await dataset.useTransaction(trx).related('subjects').attach([keywordData.id]);
|
||||
subject.value = keywordData.value;
|
||||
subject.type = keywordData.type;
|
||||
subject.external_key = keywordData.external_key;
|
||||
if (subject.$isDirty) {
|
||||
await subject.save();
|
||||
}
|
||||
} else {
|
||||
const keyword = new Subject();
|
||||
keyword.fill(keywordData);
|
||||
await dataset.useTransaction(trx).related('subjects').save(keyword, false);
|
||||
}
|
||||
}
|
||||
|
||||
// Save already existing files
|
||||
const files = request.input('fileInputs', []);
|
||||
for (const fileData of files) {
|
||||
|
@ -857,43 +881,57 @@ export default class DatasetController {
|
|||
}
|
||||
|
||||
// handle new uploaded files:
|
||||
const uploadedFiles = request.files('files');
|
||||
const uploadedFiles: MultipartFileContract[] = request.files('files');
|
||||
if (Array.isArray(uploadedFiles) && uploadedFiles.length > 0) {
|
||||
// let index = 1;
|
||||
// for (const key in files) {
|
||||
// const formFile = files[key]
|
||||
// for (const fileData of files) {
|
||||
for (const [index, fileData] of uploadedFiles.entries()) {
|
||||
// const uploads = request.file('uploads');
|
||||
// const fileIndex = formFile.file;
|
||||
// const file = uploads[fileIndex];
|
||||
|
||||
const fileName = `file-${cuid()}.${fileData.extname}`;
|
||||
const mimeType = fileData.headers['content-type'] || 'application/octet-stream'; // Fallback to a default MIME type
|
||||
const datasetFolder = `files/${dataset.id}`;
|
||||
await fileData.moveToDisk(
|
||||
datasetFolder,
|
||||
{
|
||||
name: fileName,
|
||||
overwrite: true, // overwrite in case of conflict
|
||||
},
|
||||
'local',
|
||||
);
|
||||
// save file metadata into db
|
||||
const newFile = new File();
|
||||
newFile.pathName = `${datasetFolder}/${fileName}`;
|
||||
newFile.fileSize = fileData.size;
|
||||
newFile.mimeType = mimeType;
|
||||
newFile.label = fileData.clientName;
|
||||
newFile.sortOrder = index;
|
||||
newFile.visibleInFrontdoor = true;
|
||||
newFile.visibleInOai = true;
|
||||
|
||||
await fileData.moveToDisk(datasetFolder, { name: fileName, overwrite: true }, 'local');
|
||||
// let path = coverImage.filePath;
|
||||
await dataset.useTransaction(trx).related('files').save(newFile);
|
||||
await newFile.createHashValues();
|
||||
|
||||
const { clientFileName, sortOrder } = this.extractVariableNameAndSortOrder(fileData.clientName);
|
||||
const mimeType = fileData.headers['content-type'] || 'application/octet-stream'; // Fallback to a default MIME type
|
||||
// save file metadata into db
|
||||
// const newFile = new File();
|
||||
// newFile.pathName = `${datasetFolder}/${fileName}`;
|
||||
// newFile.fileSize = fileData.size;
|
||||
// newFile.mimeType = mimeType;
|
||||
// newFile.label = clientFileName;
|
||||
// newFile.sortOrder = sortOrder ? sortOrder : index;
|
||||
// newFile.visibleInFrontdoor = true;
|
||||
// newFile.visibleInOai = true;
|
||||
|
||||
const newFile = await dataset
|
||||
.useTransaction(trx)
|
||||
.related('files')
|
||||
.create({
|
||||
pathName: `${datasetFolder}/${fileName}`,
|
||||
fileSize: fileData.size,
|
||||
mimeType,
|
||||
label: clientFileName,
|
||||
sortOrder: sortOrder || index,
|
||||
visibleInFrontdoor: true,
|
||||
visibleInOai: true,
|
||||
});
|
||||
|
||||
// save many related HashValue Instances to the file:
|
||||
await newFile.createHashValues(trx);
|
||||
}
|
||||
}
|
||||
|
||||
// save collection
|
||||
// const collection: Collection | null = await Collection.query().where('id', 21).first();
|
||||
// collection && (await dataset.useTransaction(trx).related('collections').attach([collection.id]));
|
||||
|
||||
// // Save coverage
|
||||
// if (data.coverage && !this.containsOnlyNull(data.coverage)) {
|
||||
// const formCoverage = request.input('coverage');
|
||||
// const coverage = await dataset.related('coverage').updateOrCreate({ dataset_id: dataset.id }, formCoverage);
|
||||
// } else if (data.coverage && this.containsOnlyNull(data.coverage) && !dataset.coverage) {
|
||||
// await dataset.coverage().delete();
|
||||
// }
|
||||
|
||||
const input = request.only(['project_id', 'embargo_date', 'language', 'type', 'creating_corporation']);
|
||||
// dataset.type = request.input('type');
|
||||
dataset.merge(input);
|
||||
|
@ -911,11 +949,30 @@ export default class DatasetController {
|
|||
throw error;
|
||||
}
|
||||
|
||||
session.flash('message', 'Dataset has been created successfully');
|
||||
session.flash('message', 'Dataset has been updated successfully');
|
||||
// return response.redirect().toRoute('user.index');
|
||||
return response.redirect().back();
|
||||
}
|
||||
|
||||
private extractVariableNameAndSortOrder(inputString: string): { clientFileName: string; sortOrder?: number } {
|
||||
const regex = /^([^?]+)(?:\?([^=]+)=([^&]+))?/;
|
||||
const match = inputString.match(regex);
|
||||
|
||||
if (match) {
|
||||
const clientFileName = match[1];
|
||||
|
||||
const param = match[2];
|
||||
let sortOrder;
|
||||
if (param && param.toLowerCase() === 'sortorder') {
|
||||
sortOrder = parseInt(match[3], 10);
|
||||
}
|
||||
|
||||
return { clientFileName, sortOrder };
|
||||
} else {
|
||||
return { clientFileName: '', sortOrder: undefined }; // Or handle as needed for no match
|
||||
}
|
||||
}
|
||||
|
||||
public async delete({ request, inertia, response, session }) {
|
||||
const id = request.param('id');
|
||||
try {
|
||||
|
@ -923,8 +980,8 @@ export default class DatasetController {
|
|||
.preload('user', (builder) => {
|
||||
builder.select('id', 'login');
|
||||
})
|
||||
.preload('files')
|
||||
.where('id', id)
|
||||
.preload('files')
|
||||
.firstOrFail();
|
||||
const validStates = ['inprogress', 'rejected_editor'];
|
||||
if (!validStates.includes(dataset.server_state)) {
|
||||
|
@ -958,11 +1015,16 @@ export default class DatasetController {
|
|||
if (validStates.includes(dataset.server_state)) {
|
||||
if (dataset.files && dataset.files.length > 0) {
|
||||
for (const file of dataset.files) {
|
||||
if (file.pathName) {
|
||||
// delete file from filesystem
|
||||
await Drive.delete(file.pathName);
|
||||
// overwriten delete method also delets file on filespace
|
||||
await file.delete();
|
||||
}
|
||||
}
|
||||
const datasetFolder = `files/${params.id}`;
|
||||
const folderExists = await Drive.exists(datasetFolder);
|
||||
if (folderExists) {
|
||||
const folderContents = await Drive.list(datasetFolder).toArray();
|
||||
if (folderContents.length === 0) {
|
||||
await Drive.delete(datasetFolder);
|
||||
}
|
||||
// delete dataset wirh relation from db
|
||||
await dataset.delete();
|
||||
|
@ -970,9 +1032,10 @@ export default class DatasetController {
|
|||
return response.redirect().toRoute('dataset.list');
|
||||
} else {
|
||||
session.flash({
|
||||
warning: `You cannot delete this dataset! The status of this dataset is "${dataset.server_state}"!`,
|
||||
warning: `You cannot delete this dataset! Invalid server_state: "${dataset.server_state}"!`,
|
||||
});
|
||||
return response.redirect().back();
|
||||
return response.status(400).redirect().back();
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
if (error instanceof ValidationException) {
|
||||
|
|
|
@ -203,7 +203,7 @@ export default class Dataset extends DatasetExtension {
|
|||
pivotForeignKey: 'document_id',
|
||||
pivotRelatedForeignKey: 'person_id',
|
||||
pivotTable: 'link_documents_persons',
|
||||
pivotColumns: ['role', 'sort_order', 'allow_email_contact'],
|
||||
pivotColumns: ['role', 'sort_order', 'allow_email_contact', 'contributor_type'],
|
||||
onQuery(query) {
|
||||
query.wherePivot('role', 'contributor');
|
||||
},
|
||||
|
|
|
@ -7,6 +7,7 @@ import BaseModel from './BaseModel';
|
|||
import * as fs from 'fs';
|
||||
import crypto from 'crypto';
|
||||
import { TransactionClientContract } from '@ioc:Adonis/Lucid/Database';
|
||||
import Drive from '@ioc:Adonis/Core/Drive';
|
||||
|
||||
export default class File extends BaseModel {
|
||||
// private readonly _data: Uint8Array;
|
||||
|
@ -116,21 +117,20 @@ export default class File extends BaseModel {
|
|||
serializeAs: 'fileData',
|
||||
})
|
||||
public get fileData(): string {
|
||||
// return this.fileData;
|
||||
// const fileData = fs.readFileSync(path.resolve(__dirname, this.filePath));
|
||||
// const fileData = fs.readFileSync(this.filePath);
|
||||
try {
|
||||
const fileContent: Buffer = fs.readFileSync(this.filePath);
|
||||
// Create a Blob from the file content
|
||||
// const blob = new Blob([fileContent], { type: this.type }); // Adjust
|
||||
// let fileSrc = URL.createObjectURL(blob);
|
||||
// return fileSrc;
|
||||
|
||||
// return Buffer.from(fileContent);
|
||||
// get the buffer from somewhere
|
||||
// const buff = fs.readFileSync('./test.bin');
|
||||
// create a JSON string that contains the data in the property "blob"
|
||||
const json = JSON.stringify({ blob: fileContent.toString('base64') });
|
||||
return json;
|
||||
} catch (err) {
|
||||
// console.error(`Error reading file: ${err}`);
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
public async createHashValues(trx?: TransactionClientContract) {
|
||||
|
@ -139,7 +139,7 @@ export default class File extends BaseModel {
|
|||
for (const type of hashtypes) {
|
||||
const hash = new HashValue();
|
||||
hash.type = type;
|
||||
const hashString = await this.checksumFile(this.filePath, type); // Assuming getRealHash is a method in the same model
|
||||
const hashString = await this._checksumFile(this.filePath, type); // Assuming getRealHash is a method in the same model
|
||||
hash.value = hashString;
|
||||
|
||||
// https://github.com/adonisjs/core/discussions/1872#discussioncomment-132289
|
||||
|
@ -152,7 +152,17 @@ export default class File extends BaseModel {
|
|||
}
|
||||
}
|
||||
|
||||
private async checksumFile(path, hashName = 'md5'): Promise<string> {
|
||||
public async delete() {
|
||||
if (this.pathName) {
|
||||
// Delete file from additional storage
|
||||
await Drive.delete(this.pathName);
|
||||
}
|
||||
|
||||
// Call the original delete method of the BaseModel to remove the record from the database
|
||||
await super.delete();
|
||||
}
|
||||
|
||||
private async _checksumFile(path, hashName = 'md5'): Promise<string> {
|
||||
return new Promise((resolve, reject) => {
|
||||
const hash = crypto.createHash(hashName);
|
||||
const stream = fs.createReadStream(path);
|
||||
|
|
|
@ -69,6 +69,12 @@ export default class Person extends BaseModel {
|
|||
return stock;
|
||||
}
|
||||
|
||||
@computed()
|
||||
public get pivot_contributor_type() {
|
||||
const contributor_type = this.$extras.pivot_contributor_type; //my pivot column name was "stock"
|
||||
return contributor_type;
|
||||
}
|
||||
|
||||
@manyToMany(() => Dataset, {
|
||||
pivotForeignKey: 'person_id',
|
||||
pivotRelatedForeignKey: 'document_id',
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { column, SnakeCaseNamingStrategy, manyToMany, ManyToMany, beforeCreate, beforeUpdate } from '@ioc:Adonis/Lucid/Orm';
|
||||
import { column, SnakeCaseNamingStrategy, manyToMany, ManyToMany, computed} from '@ioc:Adonis/Lucid/Orm';
|
||||
import BaseModel from './BaseModel';
|
||||
|
||||
import { DateTime } from 'luxon';
|
||||
|
@ -44,28 +44,33 @@ export default class Subject extends BaseModel {
|
|||
})
|
||||
public updated_at: DateTime;
|
||||
|
||||
@beforeCreate()
|
||||
@beforeUpdate()
|
||||
public static async resetDate(role) {
|
||||
role.created_at = this.formatDateTime(role.created_at);
|
||||
role.updated_at = this.formatDateTime(role.updated_at);
|
||||
}
|
||||
// @beforeCreate()
|
||||
// @beforeUpdate()
|
||||
// public static async resetDate(role) {
|
||||
// role.created_at = this.formatDateTime(role.created_at);
|
||||
// role.updated_at = this.formatDateTime(role.updated_at);
|
||||
// }
|
||||
|
||||
private static formatDateTime(datetime) {
|
||||
let value = new Date(datetime);
|
||||
return datetime
|
||||
? value.getFullYear() +
|
||||
'-' +
|
||||
(value.getMonth() + 1) +
|
||||
'-' +
|
||||
value.getDate() +
|
||||
' ' +
|
||||
value.getHours() +
|
||||
':' +
|
||||
value.getMinutes() +
|
||||
':' +
|
||||
value.getSeconds()
|
||||
: datetime;
|
||||
// private static formatDateTime(datetime) {
|
||||
// let value = new Date(datetime);
|
||||
// return datetime
|
||||
// ? value.getFullYear() +
|
||||
// '-' +
|
||||
// (value.getMonth() + 1) +
|
||||
// '-' +
|
||||
// value.getDate() +
|
||||
// ' ' +
|
||||
// value.getHours() +
|
||||
// ':' +
|
||||
// value.getMinutes() +
|
||||
// ':' +
|
||||
// value.getSeconds()
|
||||
// : datetime;
|
||||
// }
|
||||
@computed()
|
||||
public get dataset_count() : number{
|
||||
const count = this.$extras.datasets_count; //my pivot column name was "stock"
|
||||
return count;
|
||||
}
|
||||
|
||||
@manyToMany(() => Dataset, {
|
||||
|
|
|
@ -135,7 +135,7 @@ export default class CreateDatasetValidator {
|
|||
'required': '{{ field }} is required',
|
||||
'unique': '{{ field }} must be unique, and this value is already taken',
|
||||
// 'confirmed': '{{ field }} is not correct',
|
||||
'licenses.minLength': 'at least {{ options.minLength }} permission must be defined',
|
||||
'licenses.minLength': 'at least {{ options.minLength }} licenses must be defined',
|
||||
'licenses.*.number': 'Define licences as valid numbers',
|
||||
'rights.equalTo': 'you must agree to continue',
|
||||
|
||||
|
|
|
@ -136,7 +136,7 @@ export default class UpdateDatasetValidator {
|
|||
'required': '{{ field }} is required',
|
||||
'unique': '{{ field }} must be unique, and this value is already taken',
|
||||
// 'confirmed': '{{ field }} is not correct',
|
||||
'licenses.minLength': 'at least {{ options.minLength }} permission must be defined',
|
||||
'licenses.minLength': 'at least {{ options.minLength }} licenses must be defined',
|
||||
'licenses.*.number': 'Define licences as valid numbers',
|
||||
'rights.equalTo': 'you must agree to continue',
|
||||
|
||||
|
|
46
config/redis.ts
Normal file
46
config/redis.ts
Normal file
|
@ -0,0 +1,46 @@
|
|||
/**
|
||||
* Config source: https://git.io/JemcF
|
||||
*
|
||||
* Feel free to let us know via PR, if you find something broken in this config
|
||||
* file.
|
||||
*/
|
||||
|
||||
import Env from '@ioc:Adonis/Core/Env'
|
||||
import { redisConfig } from '@adonisjs/redis/build/config'
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Redis configuration
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Following is the configuration used by the Redis provider to connect to
|
||||
| the redis server and execute redis commands.
|
||||
|
|
||||
| Do make sure to pre-define the connections type inside `contracts/redis.ts`
|
||||
| file for AdonisJs to recognize connections.
|
||||
|
|
||||
| Make sure to check `contracts/redis.ts` file for defining extra connections
|
||||
*/
|
||||
export default redisConfig({
|
||||
connection: Env.get('REDIS_CONNECTION'),
|
||||
|
||||
connections: {
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| The default connection
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| The main connection you want to use to execute redis commands. The same
|
||||
| connection will be used by the session provider, if you rely on the
|
||||
| redis driver.
|
||||
|
|
||||
*/
|
||||
local: {
|
||||
host: Env.get('REDIS_HOST'),
|
||||
port: Env.get('REDIS_PORT'),
|
||||
password: Env.get('REDIS_PASSWORD', ''),
|
||||
db: 0,
|
||||
keyPrefix: '',
|
||||
},
|
||||
},
|
||||
})
|
13
contracts/redis.ts
Normal file
13
contracts/redis.ts
Normal file
|
@ -0,0 +1,13 @@
|
|||
/**
|
||||
* Contract source: https://git.io/JemcN
|
||||
*
|
||||
* Feel free to let us know via PR, if you find something broken in this config
|
||||
* file.
|
||||
*/
|
||||
|
||||
import { InferConnectionsFromConfig } from '@adonisjs/redis/build/config'
|
||||
import redisConfig from '../config/redis'
|
||||
|
||||
declare module '@ioc:Adonis/Addons/Redis' {
|
||||
interface RedisConnectionsList extends InferConnectionsFromConfig<typeof redisConfig> {}
|
||||
}
|
92
package-lock.json
generated
92
package-lock.json
generated
|
@ -11,6 +11,7 @@
|
|||
"@adonisjs/auth": "^8.2.3",
|
||||
"@adonisjs/core": "^5.9.0",
|
||||
"@adonisjs/lucid": "^18.3.0",
|
||||
"@adonisjs/redis": "^7.3.4",
|
||||
"@adonisjs/repl": "^3.1.11",
|
||||
"@adonisjs/session": "^6.4.0",
|
||||
"@adonisjs/shield": "^7.1.0",
|
||||
|
@ -529,6 +530,19 @@
|
|||
"truncatise": "0.0.8"
|
||||
}
|
||||
},
|
||||
"node_modules/@adonisjs/redis": {
|
||||
"version": "7.3.4",
|
||||
"resolved": "https://registry.npmjs.org/@adonisjs/redis/-/redis-7.3.4.tgz",
|
||||
"integrity": "sha512-74SApmgimjwU8QflnhANeo7CpQeP9aoObM217LJ51AtKwTvnb0yXaqdj2v60G9uCqcqZAIFWJmeUdXGgUwGcXw==",
|
||||
"dependencies": {
|
||||
"@poppinss/utils": "^5.0.0",
|
||||
"@types/ioredis": "^4.28.10",
|
||||
"ioredis": "^5.2.3"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@adonisjs/core": "^5.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@adonisjs/repl": {
|
||||
"version": "3.1.11",
|
||||
"resolved": "https://registry.npmjs.org/@adonisjs/repl/-/repl-3.1.11.tgz",
|
||||
|
@ -2886,6 +2900,11 @@
|
|||
"vue": "^3.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@ioredis/commands": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/@ioredis/commands/-/commands-1.2.0.tgz",
|
||||
"integrity": "sha512-Sx1pU8EM64o2BrqNpEO1CNLtKQwyhuXuqyfH7oGKCk+1a33d2r5saW8zNwm3j6BTExtjrv2BxTgzzkMwts6vGg=="
|
||||
},
|
||||
"node_modules/@japa/api-client": {
|
||||
"version": "1.4.4",
|
||||
"resolved": "https://registry.npmjs.org/@japa/api-client/-/api-client-1.4.4.tgz",
|
||||
|
@ -4055,6 +4074,14 @@
|
|||
"@types/node": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/ioredis": {
|
||||
"version": "4.28.10",
|
||||
"resolved": "https://registry.npmjs.org/@types/ioredis/-/ioredis-4.28.10.tgz",
|
||||
"integrity": "sha512-69LyhUgrXdgcNDv7ogs1qXZomnfOEnSmrmMFqKgt1XMJxmoOSG/u3wYy13yACIfKuMJ8IhKgHafDO3sx19zVQQ==",
|
||||
"dependencies": {
|
||||
"@types/node": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/istanbul-lib-coverage": {
|
||||
"version": "2.0.6",
|
||||
"resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.6.tgz",
|
||||
|
@ -7794,6 +7821,14 @@
|
|||
"node": ">=0.4.0"
|
||||
}
|
||||
},
|
||||
"node_modules/denque": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/denque/-/denque-2.1.0.tgz",
|
||||
"integrity": "sha512-HVQE3AAb/pxF8fQAoiqpvg9i3evqug3hoiwakOyZAwJm+6vZehbkYXZ0l4JxS+I3QxM97v5aaRNhj8v5oBhekw==",
|
||||
"engines": {
|
||||
"node": ">=0.10"
|
||||
}
|
||||
},
|
||||
"node_modules/depd": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz",
|
||||
|
@ -10365,6 +10400,29 @@
|
|||
"node": ">= 0.10"
|
||||
}
|
||||
},
|
||||
"node_modules/ioredis": {
|
||||
"version": "5.3.2",
|
||||
"resolved": "https://registry.npmjs.org/ioredis/-/ioredis-5.3.2.tgz",
|
||||
"integrity": "sha512-1DKMMzlIHM02eBBVOFQ1+AolGjs6+xEcM4PDL7NqOS6szq7H9jSaEkIUH6/a5Hl241LzW6JLSiAbNvTQjUupUA==",
|
||||
"dependencies": {
|
||||
"@ioredis/commands": "^1.1.1",
|
||||
"cluster-key-slot": "^1.1.0",
|
||||
"debug": "^4.3.4",
|
||||
"denque": "^2.1.0",
|
||||
"lodash.defaults": "^4.2.0",
|
||||
"lodash.isarguments": "^3.1.0",
|
||||
"redis-errors": "^1.2.0",
|
||||
"redis-parser": "^3.0.0",
|
||||
"standard-as-callback": "^2.1.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=12.22.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/ioredis"
|
||||
}
|
||||
},
|
||||
"node_modules/ipaddr.js": {
|
||||
"version": "1.9.1",
|
||||
"resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz",
|
||||
|
@ -11493,6 +11551,11 @@
|
|||
"integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/lodash.defaults": {
|
||||
"version": "4.2.0",
|
||||
"resolved": "https://registry.npmjs.org/lodash.defaults/-/lodash.defaults-4.2.0.tgz",
|
||||
"integrity": "sha512-qjxPLHd3r5DnsdGacqOMU6pb/avJzdh9tFX2ymgoZE27BmjXrNy/y4LoaiTeAb+O3gL8AfpJGtqfX/ae2leYYQ=="
|
||||
},
|
||||
"node_modules/lodash.flatten": {
|
||||
"version": "4.4.0",
|
||||
"resolved": "https://registry.npmjs.org/lodash.flatten/-/lodash.flatten-4.4.0.tgz",
|
||||
|
@ -11505,6 +11568,11 @@
|
|||
"integrity": "sha512-z+Uw/vLuy6gQe8cfaFWD7p0wVv8fJl3mbzXh33RS+0oW2wvUqiRXiQ69gLWSLpgB5/6sU+r6BlQR0MBILadqTQ==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/lodash.isarguments": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz",
|
||||
"integrity": "sha512-chi4NHZlZqZD18a0imDHnZPrDeBbTtVN7GXMwuGdRH9qotxAjYs3aVLKc7zNOG9eddR5Ksd8rvFEBc9SsggPpg=="
|
||||
},
|
||||
"node_modules/lodash.isequal": {
|
||||
"version": "4.5.0",
|
||||
"resolved": "https://registry.npmjs.org/lodash.isequal/-/lodash.isequal-4.5.0.tgz",
|
||||
|
@ -14363,6 +14431,25 @@
|
|||
"@redis/time-series": "1.0.5"
|
||||
}
|
||||
},
|
||||
"node_modules/redis-errors": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/redis-errors/-/redis-errors-1.2.0.tgz",
|
||||
"integrity": "sha512-1qny3OExCf0UvUV/5wpYKf2YwPcOqXzkwKKSmKHiE6ZMQs5heeE/c8eXK+PNllPvmjgAbfnsbpkGZWy8cBpn9w==",
|
||||
"engines": {
|
||||
"node": ">=4"
|
||||
}
|
||||
},
|
||||
"node_modules/redis-parser": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/redis-parser/-/redis-parser-3.0.0.tgz",
|
||||
"integrity": "sha512-DJnGAeenTdpMEH6uAJRK/uiyEIH9WVsUmoLwzudwGJUwZPp80PDBWPHXSAGNPwNvIXAbe7MSUB1zQFugFml66A==",
|
||||
"dependencies": {
|
||||
"redis-errors": "^1.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=4"
|
||||
}
|
||||
},
|
||||
"node_modules/reflect-metadata": {
|
||||
"version": "0.1.13",
|
||||
"resolved": "https://registry.npmjs.org/reflect-metadata/-/reflect-metadata-0.1.13.tgz",
|
||||
|
@ -15514,6 +15601,11 @@
|
|||
"get-source": "^2.0.12"
|
||||
}
|
||||
},
|
||||
"node_modules/standard-as-callback": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/standard-as-callback/-/standard-as-callback-2.1.0.tgz",
|
||||
"integrity": "sha512-qoRRSyROncaz1z0mvYqIE4lCd9p2R90i6GxW3uZv5ucSu8tU7B5HXUP1gG8pVZsYNVaXjk8ClXHPttLyxAL48A=="
|
||||
},
|
||||
"node_modules/static-extend": {
|
||||
"version": "0.1.2",
|
||||
"resolved": "https://registry.npmjs.org/static-extend/-/static-extend-0.1.2.tgz",
|
||||
|
|
|
@ -69,6 +69,7 @@
|
|||
"@adonisjs/auth": "^8.2.3",
|
||||
"@adonisjs/core": "^5.9.0",
|
||||
"@adonisjs/lucid": "^18.3.0",
|
||||
"@adonisjs/redis": "^7.3.4",
|
||||
"@adonisjs/repl": "^3.1.11",
|
||||
"@adonisjs/session": "^6.4.0",
|
||||
"@adonisjs/shield": "^7.1.0",
|
||||
|
|
|
@ -10,6 +10,7 @@ import OverlayLayer from '@/Components/OverlayLayer.vue';
|
|||
// let menu = reactive({});
|
||||
// menu = computed(() => usePage().props.navigation?.menu);
|
||||
|
||||
|
||||
const layoutService = LayoutService();
|
||||
</script>
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<script setup>
|
||||
import { ref, computed } from 'vue';
|
||||
import { Link } from '@inertiajs/vue3';
|
||||
<script lang="ts" setup>
|
||||
import { ref, computed, ComputedRef } from 'vue';
|
||||
import { Link, usePage } from '@inertiajs/vue3';
|
||||
// import { Link } from '@inertiajs/inertia-vue3';
|
||||
|
||||
import { StyleService } from '@/Stores/style';
|
||||
|
@ -9,6 +9,7 @@ import { getButtonColor } from '@/colors.js';
|
|||
import BaseIcon from '@/Components/BaseIcon.vue';
|
||||
import AsideMenuList from '@/Components/AsideMenuList.vue';
|
||||
import { stardust } from '@eidellev/adonis-stardust/client';
|
||||
import type { User } from '@/Dataset';
|
||||
|
||||
const props = defineProps({
|
||||
item: {
|
||||
|
@ -18,6 +19,10 @@ const props = defineProps({
|
|||
isDropdownList: Boolean,
|
||||
});
|
||||
|
||||
const user: ComputedRef<User> = computed(() => {
|
||||
return usePage().props.authUser as User;
|
||||
});
|
||||
|
||||
const itemRoute = computed(() => (props.item && props.item.route ? stardust.route(props.item.route) : ''));
|
||||
// const isCurrentRoute = computed(() => (props.item && props.item.route ? stardust.isCurrent(props.item.route): false));
|
||||
const itemHref = computed(() => (props.item && props.item.href ? props.item.href : ''));
|
||||
|
@ -65,12 +70,20 @@ const is = computed(() => {
|
|||
return 'div';
|
||||
});
|
||||
|
||||
const hasRoles = computed(() => {
|
||||
if (props.item.roles) {
|
||||
return user.value.roles.some(role => props.item.roles.includes(role.name));
|
||||
// return test;
|
||||
}
|
||||
return true
|
||||
});
|
||||
|
||||
// props.routeName && stardust.isCurrent(props.routeName) ? props.activeColor : null
|
||||
</script>
|
||||
|
||||
<!-- :target="props.item.target ?? null" -->
|
||||
<template>
|
||||
<li>
|
||||
<li v-if="hasRoles">
|
||||
<!-- <component :is="itemHref ? 'div' : Link" :href="itemHref ? itemHref : itemRoute" -->
|
||||
<component
|
||||
:is="is"
|
||||
|
|
|
@ -19,10 +19,10 @@ const menuClick = (event, item) => {
|
|||
<template>
|
||||
<ul>
|
||||
<AsideMenuItem
|
||||
v-for="(item, index) in menu"
|
||||
v-for="(menuItem, index) in menu"
|
||||
:key="index"
|
||||
v-bind:item="item"
|
||||
:is-dropdown-list="item.children?.length > 0"
|
||||
v-bind:item="menuItem"
|
||||
:is-dropdown-list="menuItem.children?.length > 0"
|
||||
@menu-click="menuClick"
|
||||
/>
|
||||
</ul>
|
||||
|
|
|
@ -250,7 +250,7 @@ class FileUploadComponent extends Vue {
|
|||
}
|
||||
|
||||
@Watch("files", {
|
||||
deep: true
|
||||
deep: true //also in case of pushing
|
||||
})
|
||||
public propertyWatcher(newItems: Array<TethysFile>) {
|
||||
// Update sort_order based on the new index when the list is changed
|
||||
|
@ -361,10 +361,11 @@ class FileUploadComponent extends Vue {
|
|||
let localUrl: string = "";
|
||||
if (file instanceof File) {
|
||||
localUrl = URL.createObjectURL(file as Blob);
|
||||
} else if (file.filePath) {
|
||||
} 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' });
|
||||
|
|
|
@ -34,7 +34,7 @@ import UserAvatarCurrentUser from '@/Components/UserAvatarCurrentUser.vue';
|
|||
import BaseIcon from '@/Components/BaseIcon.vue';
|
||||
import NavBarSearch from '@/Components/NavBarSearch.vue';
|
||||
import { stardust } from '@eidellev/adonis-stardust/client';
|
||||
import type User from 'App/Models/User';
|
||||
import type { User } from '@/Dataset';
|
||||
|
||||
// const mainStore = MainService();
|
||||
// const userName = computed(() =>mainStore.userName);
|
||||
|
@ -68,6 +68,9 @@ const menuNavBarToggle = () => {
|
|||
const menuOpenLg = () => {
|
||||
layoutStore.isAsideLgActive = true;
|
||||
};
|
||||
const userHasRoles = (roleNames): boolean => {
|
||||
return user.value.roles.some(role => roleNames.includes(role.name));
|
||||
};
|
||||
|
||||
// const logout = () => {
|
||||
// // router.post(route('logout'))
|
||||
|
@ -133,7 +136,7 @@ const logout = async () => {
|
|||
<NavBarItem :route-name="'admin.account.info'">
|
||||
<NavBarItemLabel :icon="mdiAccount" label="My Profile" />
|
||||
</NavBarItem>
|
||||
<NavBarItem :route-name="'settings'">
|
||||
<NavBarItem v-if="userHasRoles(['moderator', 'administrator'])" :route-name="'settings'">
|
||||
<NavBarItemLabel :icon="mdiCogOutline" label="Settings" />
|
||||
</NavBarItem>
|
||||
<NavBarItem>
|
||||
|
|
|
@ -3,13 +3,9 @@
|
|||
<div class="flex">
|
||||
<!-- <label for="search-dropdown" class="mb-2 text-sm font-medium text-gray-900 sr-only dark:text-white">Your Email</label> -->
|
||||
<div class="relative" data-te-dropdown-ref>
|
||||
<button
|
||||
id="states-button"
|
||||
data-dropdown-toggle="dropdown-states"
|
||||
<button id="states-button" data-dropdown-toggle="dropdown-states"
|
||||
class="whitespace-nowrap h-12 z-10 inline-flex items-center py-2.5 px-4 text-sm font-medium text-center text-gray-500 bg-gray-100 border border-gray-300 rounded-l-lg hover:bg-gray-200 focus:ring-4 focus:outline-none focus:ring-gray-100 dark:bg-gray-700 dark:hover:bg-gray-600 dark:focus:ring-gray-700 dark:text-white dark:border-gray-600"
|
||||
type="button"
|
||||
@click.prevent="showStates"
|
||||
>
|
||||
type="button" @click.prevent="showStates">
|
||||
<!-- <svg aria-hidden="true" class="h-3 mr-2" viewBox="0 0 15 12" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<rect x="0.5" width="14" height="12" rx="2" fill="white" />
|
||||
<mask id="mask0_12694_49953" style="mask-type: alpha" maskUnits="userSpaceOnUse" x="0" y="0" width="15" height="12">
|
||||
|
@ -69,26 +65,20 @@
|
|||
</svg> -->
|
||||
<!-- eng -->
|
||||
{{ language }}
|
||||
<svg aria-hidden="true" class="w-4 h-4 ml-1" fill="currentColor" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg">
|
||||
<path
|
||||
fill-rule="evenodd"
|
||||
<svg aria-hidden="true" class="w-4 h-4 ml-1" fill="currentColor" viewBox="0 0 20 20"
|
||||
xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd"
|
||||
d="M5.293 7.293a1 1 0 011.414 0L10 10.586l3.293-3.293a1 1 0 111.414 1.414l-4 4a1 1 0 01-1.414 0l-4-4a1 1 0 010-1.414z"
|
||||
clip-rule="evenodd"
|
||||
></path>
|
||||
clip-rule="evenodd"></path>
|
||||
</svg>
|
||||
</button>
|
||||
<!-- class="w-full overflow-visible z-10 bg-white divide-y divide-gray-100 rounded-lg shadow w-44 dark:bg-gray-700"-->
|
||||
<div
|
||||
id="dropdown-states"
|
||||
v-show="statesToggle"
|
||||
class="absolute z-[1000] float-left m-0 min-w-max list-none overflow-hidden rounded-lg border-none bg-white bg-clip-padding text-left text-base shadow-lg dark:bg-neutral-700"
|
||||
>
|
||||
<div id="dropdown-states" v-show="statesToggle"
|
||||
class="absolute z-[1000] float-left m-0 min-w-max list-none overflow-hidden rounded-lg border-none bg-white bg-clip-padding text-left text-base shadow-lg dark:bg-neutral-700">
|
||||
<ul class="py-2 text-sm text-gray-700 dark:text-gray-200" aria-labelledby="states-button">
|
||||
<li v-for="(item, index) in dropDownStates" :key="index" @click.prevent="setLanguage(item)">
|
||||
<button
|
||||
type="button"
|
||||
class="inline-flex w-full px-4 py-2 text-sm text-gray-700 hover:bg-gray-100 dark:text-gray-400 dark:hover:bg-gray-600 dark:hover:text-white"
|
||||
>
|
||||
<button type="button"
|
||||
class="inline-flex w-full px-4 py-2 text-sm text-gray-700 hover:bg-gray-100 dark:text-gray-400 dark:hover:bg-gray-600 dark:hover:text-white">
|
||||
<div class="inline-flex items-center">
|
||||
<span v-html="item.svg"></span>
|
||||
{{ item.name }}
|
||||
|
@ -102,57 +92,30 @@
|
|||
<div class="w-full relative">
|
||||
<!-- :class="inputElClass" -->
|
||||
<!-- class="block p-2.5 w-full z-20 text-sm text-gray-900 bg-gray-50 rounded-r-lg border-l-gray-50 border-l-2 border border-gray-300 focus:ring-blue-500 focus:border-blue-500 dark:bg-gray-700 dark:border-l-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:border-blue-500" -->
|
||||
<input
|
||||
v-model="computedValue"
|
||||
type="text"
|
||||
:name="props.name"
|
||||
autocomplete="off"
|
||||
:class="inputElClass"
|
||||
placeholder="Search Keywords..."
|
||||
required
|
||||
@input="handleInput"
|
||||
/>
|
||||
<input v-model="computedValue" type="text" :name="props.name" autocomplete="off" :class="inputElClass"
|
||||
placeholder="Search Keywords..." required @input="handleInput" />
|
||||
<!-- v-model="data.search" -->
|
||||
<svg
|
||||
class="w-4 h-4 absolute left-2.5 top-3.5"
|
||||
v-show="computedValue.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 class="w-4 h-4 absolute left-2.5 top-3.5" v-show="computedValue.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="computedValue.length >= 2"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
stroke="currentColor"
|
||||
@click="
|
||||
() => {
|
||||
<svg class="w-4 h-4 absolute left-2.5 top-3.5" v-show="computedValue.length >= 2"
|
||||
xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor" @click="() => {
|
||||
computedValue = '';
|
||||
data.isOpen = false;
|
||||
}
|
||||
"
|
||||
>
|
||||
">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M6 18L18 6M6 6l12 12" />
|
||||
</svg>
|
||||
</div>
|
||||
<slot />
|
||||
</div>
|
||||
<ul
|
||||
v-if="data.isOpen"
|
||||
class="absolute absolute z-[1000] float-left m-0 list-none bg-white dark:bg-slate-800 m-0 max-h-32 overflow-y-auto scroll-smooth min-w-full"
|
||||
>
|
||||
<li
|
||||
class="leading-3 pl-4 py-3 border-b-2 line border-gray-100 relative cursor-pointer hover:bg-yellow-50 hover:text-gray-900"
|
||||
v-for="(item, index) in data.results"
|
||||
@click.prevent="setResult(item)"
|
||||
:key="index"
|
||||
>
|
||||
<ul v-if="data.isOpen"
|
||||
class="absolute absolute z-[1000] float-left m-0 list-none bg-white dark:bg-slate-800 m-0 max-h-32 overflow-y-auto scroll-smooth min-w-full">
|
||||
<li class="leading-3 pl-4 py-3 border-b-2 line border-gray-100 relative cursor-pointer hover:bg-yellow-50 hover:text-gray-900"
|
||||
v-for="(item, index) in data.results" @click.prevent="setResult(item)" :key="index">
|
||||
<!-- <a href="${BASE}?uri=${a.s.value}&lang=${USER_LANG}"> -->
|
||||
<strong class="text-sm"> {{ item.title.value }}</strong>
|
||||
<!-- </a> -->
|
||||
|
@ -406,7 +369,10 @@ function setResult(item) {
|
|||
computedValue.value = item.title.value;
|
||||
clear();
|
||||
// this.$emit('person', person);
|
||||
emit('subject', language.value);
|
||||
emit('subject', {
|
||||
language: language.value,
|
||||
uri: item.s.value
|
||||
});
|
||||
}
|
||||
|
||||
function clear() {
|
||||
|
|
|
@ -8,7 +8,6 @@ import { mdiTrashCan } from '@mdi/js';
|
|||
import BaseLevel from '@/Components/BaseLevel.vue';
|
||||
import BaseButtons from '@/Components/BaseButtons.vue';
|
||||
import BaseButton from '@/Components/BaseButton.vue';
|
||||
// import Person from 'App/Models/Person';
|
||||
import { Subject } from '@/Dataset';
|
||||
// import FormField from '@/Components/FormField.vue';
|
||||
import FormControl from '@/Components/FormControl.vue';
|
||||
|
@ -120,7 +119,7 @@ const removeItem = (key) => {
|
|||
<UserAvatar :username="client.value" class="w-24 h-24 mx-auto lg:w-6 lg:h-6" />
|
||||
</td> -->
|
||||
<td data-label="Type" scope="row">
|
||||
<FormControl required v-model="item.type" :type="'select'" placeholder="[Enter Language]" :options="props.subjectTypes">
|
||||
<FormControl required v-model="item.type" @update:modelValue="() => {item.external_key = undefined; item.value= '';}" :type="'select'" placeholder="[Enter Language]" :options="props.subjectTypes">
|
||||
<div class="text-red-400 text-sm" v-if="errors[`subjects.${index}.type`]">
|
||||
{{ errors[`subjects.${index}.type`].join(', ') }}
|
||||
</div>
|
||||
|
@ -132,8 +131,9 @@ const removeItem = (key) => {
|
|||
v-if="item.type !== 'uncontrolled'"
|
||||
v-model="item.value"
|
||||
@subject="
|
||||
(language) => {
|
||||
item.language = language;
|
||||
(result) => {
|
||||
item.language = result.language;
|
||||
item.external_key = result.uri;
|
||||
}
|
||||
"
|
||||
>
|
||||
|
|
|
@ -1,4 +1,24 @@
|
|||
import { Ref } from 'vue';
|
||||
import { DateTime } from 'luxon';
|
||||
|
||||
export interface User {
|
||||
id: number;
|
||||
login: string;
|
||||
email: string;
|
||||
password: string;
|
||||
createdAt: DateTime;
|
||||
updatedAt: DateTime;
|
||||
roles: Array<Role>;
|
||||
}
|
||||
|
||||
export interface Role {
|
||||
id: number;
|
||||
display_name: string;
|
||||
name: string;
|
||||
description: string;
|
||||
created_at: DateTime;
|
||||
updated_at: DateTime;
|
||||
}
|
||||
|
||||
export interface Dataset {
|
||||
[key: string]:
|
||||
|
@ -75,11 +95,12 @@ export interface TethysFile {
|
|||
}
|
||||
|
||||
export interface Subject {
|
||||
// id: number;
|
||||
id?: number;
|
||||
language: string;
|
||||
type: string;
|
||||
value: string;
|
||||
external_key?: string;
|
||||
dataset_count: number;
|
||||
}
|
||||
export interface DatasetReference {
|
||||
// id: number;
|
||||
|
|
|
@ -290,14 +290,15 @@ const submit = async () => {
|
|||
|
||||
// this.currentStatus = STATUS_SAVING;
|
||||
// serrors = [];
|
||||
// const files = form.files.map((obj) => {
|
||||
// return new File([obj.blob], obj.label, { type: obj.type, lastModified: obj.lastModified });
|
||||
// });
|
||||
const files = form.files.map((obj) => {
|
||||
return new File([obj.blob], obj.label, { type: obj.type, lastModified: obj.lastModified });
|
||||
});
|
||||
|
||||
// formStep.value++;
|
||||
await form
|
||||
.transform((data) => ({
|
||||
...data,
|
||||
files: files,
|
||||
rights: form.rights && form.rights == true ? 'true' : 'false',
|
||||
}))
|
||||
.post(route, {
|
||||
|
@ -404,7 +405,7 @@ const onMapInitialized = (newItem) => {
|
|||
adds a new Keyword
|
||||
*/
|
||||
const addKeyword = () => {
|
||||
let newSubject: Subject = { value: 'test', language: '', type: 'uncontrolled' };
|
||||
let newSubject: Subject = { value: 'test', language: '', type: 'uncontrolled', dataset_count: 0 };
|
||||
//this.dataset.files.push(uploadedFiles[i]);
|
||||
form.subjects.push(newSubject);
|
||||
};
|
||||
|
|
|
@ -8,11 +8,15 @@
|
|||
color="white" rounded-full small />
|
||||
</SectionTitleLineWithButton>
|
||||
|
||||
<NotificationBar v-if="flash.message" color="success" :icon="mdiAlertBoxOutline">
|
||||
{{ flash.message }}
|
||||
</NotificationBar>
|
||||
<FormValidationErrors v-bind:errors="errors" />
|
||||
<!-- max-w-2xl max-width: 42rem; /* 672px */ -->
|
||||
<!-- <div class="max-w-2xl mx-auto"> -->
|
||||
|
||||
<CardBox :form="true">
|
||||
<FormValidationErrors v-bind:errors="errors" />
|
||||
<!-- <FormValidationErrors v-bind:errors="errors" /> -->
|
||||
<div class="mb-4">
|
||||
<!-- <label for="title" class="block text-gray-700 font-bold mb-2">Title:</label>
|
||||
<input
|
||||
|
@ -218,8 +222,8 @@
|
|||
<td class="before:hidden lg:w-1 whitespace-nowrap">
|
||||
<BaseButtons type="justify-start lg:justify-end" no-wrap>
|
||||
<!-- <BaseButton color="info" :icon="mdiEye" small @click="isModalActive = true" /> -->
|
||||
<BaseButton color="danger" :icon="mdiTrashCan" small v-if="item.id == undefined"
|
||||
@click.prevent="removeDescription(index)" />
|
||||
<BaseButton color="danger" :icon="mdiTrashCan" small
|
||||
v-if="item.id == undefined" @click.prevent="removeDescription(index)" />
|
||||
</BaseButtons>
|
||||
</td>
|
||||
</tr>
|
||||
|
@ -469,7 +473,8 @@
|
|||
// import { Component, Vue, Prop, Setup, toNative } from 'vue-facing-decorator';
|
||||
// import AuthLayout from '@/Layouts/Auth.vue';
|
||||
import LayoutAuthenticated from '@/Layouts/LayoutAuthenticated.vue';
|
||||
import { useForm, Head } from '@inertiajs/vue3';
|
||||
import { useForm, Head, usePage } from '@inertiajs/vue3';
|
||||
import { computed, ComputedRef } from 'vue';
|
||||
// import { ref } from 'vue';
|
||||
// import { MainService } from '@/Stores/main';
|
||||
// import FormInput from '@/Components/FormInput.vue'; // @/Components/FormInput.vue'
|
||||
|
@ -502,8 +507,10 @@ import {
|
|||
mdiTrashCan,
|
||||
mdiBookOpenPageVariant,
|
||||
mdiEarthPlus,
|
||||
mdiAlertBoxOutline,
|
||||
} from '@mdi/js';
|
||||
import { notify } from '@/notiwind';
|
||||
import NotificationBar from '@/Components/NotificationBar.vue';
|
||||
|
||||
const props = defineProps({
|
||||
errors: {
|
||||
|
@ -557,6 +564,11 @@ const props = defineProps({
|
|||
|
||||
|
||||
|
||||
});
|
||||
const flash: ComputedRef<any> = computed(() => {
|
||||
// let test = usePage();
|
||||
// console.log(test);
|
||||
return usePage().props.flash;
|
||||
});
|
||||
|
||||
// const projects = reactive([]);
|
||||
|
@ -639,11 +651,17 @@ const submit = async (): Promise<void> => {
|
|||
form.licenses = form.licenses.map((obj) => obj.id.toString());
|
||||
}
|
||||
|
||||
// const files = form.files.map((obj) => {
|
||||
// return new File([obj.blob], obj.label, { type: obj.type, lastModified: obj.lastModified });
|
||||
// });
|
||||
|
||||
const [fileUploads, fileInputs] = form.files?.reduce(
|
||||
([fileUploads, fileInputs], obj) => {
|
||||
if (!obj.id) {
|
||||
// return MultipartFile for file upload
|
||||
fileUploads[obj.sort_order] = new File([obj.blob], obj.label, { type: obj.type, lastModified: obj.lastModified });
|
||||
let file = new File([obj.blob], `${obj.label}?sortOrder=${obj.sort_order}`, { type: obj.type, lastModified: obj.lastModified });
|
||||
// fileUploads[obj.sort_order] = file;
|
||||
fileUploads.push(file);
|
||||
} else {
|
||||
// return normal request input
|
||||
fileInputs.push(obj);
|
||||
|
@ -723,7 +741,7 @@ const onAddContributor = (person) => {
|
|||
};
|
||||
|
||||
const addKeyword = () => {
|
||||
let newSubject: Subject = { value: 'test', language: '', type: 'uncontrolled' };
|
||||
let newSubject: Subject = { value: 'test', language: '', type: 'uncontrolled', dataset_count: 0 };
|
||||
//this.dataset.files.push(uploadedFiles[i]);
|
||||
form.subjects.push(newSubject);
|
||||
};
|
||||
|
@ -743,7 +761,7 @@ const onMapInitialized = (newItem) => {
|
|||
};
|
||||
</script>
|
||||
|
||||
<style>
|
||||
<style scoped>
|
||||
.max-w-2xl {
|
||||
max-width: 2xl;
|
||||
}
|
||||
|
|
|
@ -118,7 +118,7 @@ const flash: ComputedRef<any> = computed(() => {
|
|||
:route-name="stardust.route('dataset.release', [dataset.id])" color="info"
|
||||
:icon="mdiLockOpen" :label="'Release'" small />
|
||||
<!-- && (dataset.server_state === 'inprogress' || dataset.server_state === 'rejected_editor')" -->
|
||||
<BaseButton v-if="can.edit" :route-name="stardust.route('dataset.edit', [dataset.id])"
|
||||
<BaseButton :route-name="stardust.route('dataset.edit', [dataset.id])"
|
||||
color="info" :icon="mdiSquareEditOutline" :label="'Edit'" small />
|
||||
<!-- @click="destroy(dataset.id)" -->
|
||||
<BaseButton v-if="can.delete" color="danger"
|
||||
|
|
|
@ -216,7 +216,7 @@ class EditComponent extends Vue {
|
|||
}
|
||||
|
||||
public addKeyword() {
|
||||
let newSubject: Subject = { value: 'test', language: '', type: 'uncontrolled' };
|
||||
let newSubject: Subject = { value: 'test', language: '', type: 'uncontrolled', dataset_count: 0 };
|
||||
//this.dataset.files.push(uploadedFiles[i]);
|
||||
this.form.subjects.push(newSubject);
|
||||
}
|
||||
|
|
|
@ -36,6 +36,7 @@ export default [
|
|||
// route: 'dataset.create',
|
||||
icon: mdiDatabasePlus,
|
||||
label: 'Submitter',
|
||||
permissions: ['submitter'],
|
||||
children: [
|
||||
{
|
||||
route: 'dataset.list',
|
||||
|
|
|
@ -24,8 +24,9 @@ Inertia.share({
|
|||
},
|
||||
|
||||
// params: ({ params }) => params,
|
||||
authUser: ({ auth }: HttpContextContract) => {
|
||||
authUser: async ({ auth }: HttpContextContract) => {
|
||||
if (auth.user) {
|
||||
await auth.user.load('roles');
|
||||
return auth.user;
|
||||
// {
|
||||
// 'id': auth.user.id,
|
||||
|
|
|
@ -94,6 +94,8 @@ Route.post('/app/login', 'Auth/AuthController.login').as('login.store');
|
|||
// Route.post("/signup", "AuthController.signup");
|
||||
Route.post('/signout', 'Auth/AuthController.logout').as('logout');
|
||||
|
||||
|
||||
// administrator
|
||||
Route.group(() => {
|
||||
Route.get('/settings', async ({ inertia }) => {
|
||||
return inertia.render('Admin/Settings');
|
||||
|
@ -133,6 +135,10 @@ Route.group(() => {
|
|||
// .middleware(['auth', 'can:dataset-list,dataset-publish']);
|
||||
.middleware(['auth', 'is:administrator,moderator']);
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Route.get('/edit-account-info', 'UsersController.accountInfo')
|
||||
.as('admin.account.info')
|
||||
.namespace('App/Controllers/Http/Admin')
|
||||
|
@ -145,9 +151,10 @@ Route.post('/edit-account-info/store/:id', 'UsersController.accountInfoStore')
|
|||
.middleware(['auth']);
|
||||
// Route::post('change-password', 'UserController@changePasswordStore')->name('admin.account.password.store');
|
||||
|
||||
// submitter:
|
||||
Route.group(() => {
|
||||
// Route.get('/user', 'UsersController.index').as('user.index');
|
||||
Route.get('/dataset', 'DatasetController.index').as('dataset.list').middleware(['auth']); //.middleware(['can:dataset-list']);
|
||||
Route.get('/dataset', 'DatasetController.index').as('dataset.list').middleware(['auth', 'can:dataset-list']);
|
||||
Route.get('/dataset/create', 'DatasetController.create').as('dataset.create').middleware(['auth', 'can:dataset-submit']);
|
||||
Route.post('/dataset/first/first-step', 'DatasetController.firstStep')
|
||||
.as('dataset.first.step')
|
||||
|
@ -158,25 +165,23 @@ Route.group(() => {
|
|||
Route.post('/dataset/second/third-step', 'DatasetController.thirdStep')
|
||||
.as('dataset.third.step')
|
||||
.middleware(['auth', 'can:dataset-submit']);
|
||||
|
||||
Route.post('/dataset/submit', 'DatasetController.store').as('dataset.submit').middleware(['auth', 'can:dataset-submit']);
|
||||
|
||||
Route.get('/dataset/:id/release', 'DatasetController.release')
|
||||
.as('dataset.release')
|
||||
.where('id', Route.matchers.number())
|
||||
.middleware(['auth']); //, 'can:dataset-submit']);
|
||||
.middleware(['auth', 'can:dataset-edit']);
|
||||
Route.put('/dataset/:id/releaseupdate', 'DatasetController.releaseUpdate')
|
||||
.as('dataset.releaseUpdate')
|
||||
.middleware(['auth', 'can:dataset-submit']);
|
||||
.middleware(['auth', 'can:dataset-edit']);
|
||||
Route.get('/dataset/:id/edit', 'DatasetController.edit')
|
||||
.as('dataset.edit')
|
||||
.where('id', Route.matchers.number())
|
||||
.middleware(['auth', 'can:dataset-submit']);
|
||||
|
||||
.middleware(['auth', 'can:dataset-edit']);
|
||||
Route.put('/dataset/:id/update', 'DatasetController.update')
|
||||
.as('dataset.update')
|
||||
.where('id', Route.matchers.number())
|
||||
.middleware(['auth', 'can:dataset-submit']);
|
||||
.middleware(['auth', 'can:dataset-edit']);
|
||||
|
||||
Route.get('/dataset/:id/delete', 'DatasetController.delete').as('dataset.delete').middleware(['auth', 'can:dataset-delete']);
|
||||
Route.put('/dataset/:id/deleteupdate', 'DatasetController.deleteUpdate')
|
||||
|
@ -195,7 +200,7 @@ Route.group(() => {
|
|||
// .middleware(['auth', 'is:submitter']);
|
||||
|
||||
Route.group(() => {
|
||||
Route.put('/dataset/:id/update', 'DatasetsController.update').as('editor.dataset.update').middleware(['auth', 'can:dataset-submit']);
|
||||
Route.put('/dataset/:id/update', 'DatasetsController.update').as('editor.dataset.update').middleware(['auth', 'can:dataset-editor-edit']);
|
||||
})
|
||||
.namespace('App/Controllers/Http/Editor')
|
||||
.prefix('editor');
|
||||
|
|
|
@ -30,12 +30,22 @@
|
|||
"esModuleInterop": true, //neu
|
||||
"allowSyntheticDefaultImports": true, //neu,
|
||||
"paths": {
|
||||
"App/*": ["./app/*"],
|
||||
"Config/*": ["./config/*"],
|
||||
"Contracts/*": ["./contracts/*"],
|
||||
"Database/*": ["./database/*"],
|
||||
"App/*": [
|
||||
"./app/*"
|
||||
],
|
||||
"Config/*": [
|
||||
"./config/*"
|
||||
],
|
||||
"Contracts/*": [
|
||||
"./contracts/*"
|
||||
],
|
||||
"Database/*": [
|
||||
"./database/*"
|
||||
],
|
||||
// "@/*": ["./resources/js/"],
|
||||
"@/*": ["./resources/js/*"]
|
||||
"@/*": [
|
||||
"./resources/js/*"
|
||||
]
|
||||
// "vue$": ["vue/dist/vue.runtime.esm-bundler.js"],
|
||||
},
|
||||
"types": [
|
||||
|
@ -48,8 +58,11 @@
|
|||
"@eidellev/inertia-adonisjs",
|
||||
"naive-ui/volar",
|
||||
"@adonisjs/lucid",
|
||||
"@adonisjs/auth"
|
||||
"@adonisjs/auth",
|
||||
"@adonisjs/redis"
|
||||
]
|
||||
},
|
||||
"files": ["index.d.ts"]
|
||||
"files": [
|
||||
"index.d.ts"
|
||||
]
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user