- renamed 'models' and 'validators' folders - removed unneccessary files in contracts folder
This commit is contained in:
parent
a29865b781
commit
08c2edca3b
62 changed files with 371 additions and 458 deletions
98
app/models/DocumentXmlCache.ts
Normal file
98
app/models/DocumentXmlCache.ts
Normal file
|
@ -0,0 +1,98 @@
|
|||
import { column, BaseModel, SnakeCaseNamingStrategy, belongsTo } from '@adonisjs/lucid/orm';
|
||||
import Dataset from './dataset.js';
|
||||
import { builder, create } from 'xmlbuilder2';
|
||||
import { XMLBuilder } from 'xmlbuilder2/lib/interfaces.js';
|
||||
import db from '@adonisjs/lucid/services/db';
|
||||
import { DateTime } from 'luxon';
|
||||
import type { BelongsTo } from "@adonisjs/lucid/types/relations";
|
||||
|
||||
export default class DocumentXmlCache extends BaseModel {
|
||||
public static namingStrategy = new SnakeCaseNamingStrategy();
|
||||
public static table = 'document_xml_cache';
|
||||
// public static fillable: string[] = ['value', 'label', 'type', 'relation'];
|
||||
// public static primaryKey = false;
|
||||
static primaryKey = ''; // Set primaryKey to null to indicate there is no primary key
|
||||
|
||||
@column({
|
||||
isPrimary: true,
|
||||
})
|
||||
public document_id: number;
|
||||
|
||||
@column({})
|
||||
public xml_version: number;
|
||||
|
||||
@column()
|
||||
public server_date_modified?: string;
|
||||
|
||||
// @column.dateTime({
|
||||
// autoCreate: true,
|
||||
// autoUpdate: true,
|
||||
// })
|
||||
// public updated_at?: DateTime;
|
||||
|
||||
@column({})
|
||||
public xml_data: string;
|
||||
|
||||
@belongsTo(() => Dataset, {
|
||||
foreignKey: 'document_id',
|
||||
})
|
||||
public dataset: BelongsTo<typeof Dataset>;
|
||||
|
||||
/**
|
||||
* Get dom document of 'xml_data' string
|
||||
*
|
||||
* @returns {XMLBuilder}
|
||||
*/
|
||||
public getDomDocument(): XMLBuilder {
|
||||
// const dom = xmlbuilder.create({ version: "1.0", encoding: "UTF-8", standalone: true });
|
||||
let dom: XMLBuilder = create({ version: '1.0', encoding: 'UTF-8', standalone: true }, this.xml_data);
|
||||
// return dom.first();
|
||||
|
||||
const rdrDataset = dom.find(
|
||||
(n) => {
|
||||
const test = n.node.nodeName == 'Rdr_Dataset';
|
||||
return test;
|
||||
},
|
||||
false,
|
||||
true,
|
||||
)?.node;
|
||||
|
||||
if (rdrDataset == undefined) {
|
||||
return dom.first();
|
||||
} else {
|
||||
dom = builder({ version: '1.0', encoding: 'UTF-8', standalone: true }, rdrDataset);
|
||||
return dom;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a dataset in a specific xml version is already cached or not.
|
||||
*
|
||||
* @param mixed datasetId
|
||||
* @param mixed serverDateModified
|
||||
* @returns {Promise<boolean>} Returns true on cached hit else false.
|
||||
*/
|
||||
// public static async hasValidEntry(datasetId: number, datasetServerDateModified: DateTime): Promise<boolean> {
|
||||
// // const formattedDate = dayjs(datasetServerDateModified).format('YYYY-MM-DD HH:mm:ss');
|
||||
|
||||
// const query = Database.from(this.table)
|
||||
// .where('document_id', datasetId)
|
||||
// .where('server_date_modified', '2023-08-17 16:51:03')
|
||||
// .first();
|
||||
|
||||
// const row = await query;
|
||||
// return !!row;
|
||||
// }
|
||||
|
||||
// Assuming 'DocumentXmlCache' has a table with a 'server_date_modified' column in your database
|
||||
public static async hasValidEntry(datasetId: number, datasetServerDateModified: DateTime): Promise<boolean> {
|
||||
const serverDateModifiedString: string = datasetServerDateModified.toFormat('yyyy-MM-dd HH:mm:ss'); // Convert DateTime to ISO string
|
||||
const query = db.from(this.table)
|
||||
.where('document_id', datasetId)
|
||||
.where('server_date_modified', '>=', serverDateModifiedString) // Check if server_date_modified is newer or equal
|
||||
.first();
|
||||
|
||||
const row = await query;
|
||||
return !!row;
|
||||
}
|
||||
}
|
130
app/models/base_model.ts
Normal file
130
app/models/base_model.ts
Normal file
|
@ -0,0 +1,130 @@
|
|||
import { BaseModel as LucidBaseModel } from '@adonisjs/lucid/orm';
|
||||
// import { ManyToManyQueryClient } from '@ioc:Adonis/Lucid/Orm';
|
||||
|
||||
// export class CustomManyToManyQueryClient extends ManyToManyQueryClient {
|
||||
// public attach(
|
||||
// relatedIds: any | any[],
|
||||
// pivotAttributes: any = {},
|
||||
// trx?: ReturnType<typeof this.model.transaction>
|
||||
// ) {
|
||||
// return super.attach(relatedIds, (row) => {
|
||||
// row.pivot.fill(pivotAttributes);
|
||||
// }, trx);
|
||||
// }
|
||||
// }
|
||||
|
||||
/**
|
||||
* Helper to find if value is a valid Object or
|
||||
* not
|
||||
*/
|
||||
export function isObject(value: any): boolean {
|
||||
return value !== null && typeof value === 'object' && !Array.isArray(value);
|
||||
}
|
||||
|
||||
export default class BaseModel extends LucidBaseModel {
|
||||
/**
|
||||
* When `fill` method is called, then we may have a situation where it
|
||||
* removed the values which exists in `original` and hence the dirty
|
||||
* diff has to do a negative diff as well
|
||||
*/
|
||||
// private fillInvoked: boolean = false;
|
||||
|
||||
[key: string]: any;
|
||||
|
||||
public static fillable: string[] = [];
|
||||
|
||||
public fill(attributes: any, allowExtraProperties: boolean = false): this {
|
||||
this.$attributes = {};
|
||||
// const Model = this.constructor as typeof BaseModel;
|
||||
|
||||
// for (const key in attributes) {
|
||||
// if (Model.fillable.includes(key)) {
|
||||
// const value = attributes[key];
|
||||
// if (Model.$hasColumn(key)) {
|
||||
// this[key] = value;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
this.mergeFillableAttributes(attributes, allowExtraProperties);
|
||||
// this.fillInvoked = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Merge bulk attributes with existing attributes.
|
||||
*
|
||||
* 1. If key is unknown, it will be added to the `extras` object.
|
||||
* 2. If key is defined as a relationship, it will be ignored and one must call `$setRelated`.
|
||||
*/
|
||||
public mergeFillableAttributes(values: any, allowExtraProperties: boolean = false): this {
|
||||
const Model = this.constructor as typeof BaseModel;
|
||||
|
||||
/**
|
||||
* Merge values with the attributes
|
||||
*/
|
||||
if (isObject(values)) {
|
||||
// Object.keys(values).forEach((key) => {
|
||||
for (const key in values) {
|
||||
if (Model.fillable.includes(key)) {
|
||||
const value = values[key];
|
||||
|
||||
/**
|
||||
* Set as column
|
||||
*/
|
||||
if (Model.$hasColumn(key)) {
|
||||
this[key] = value;
|
||||
continue;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolve the attribute name from the column names. Since people
|
||||
* usaully define the column names directly as well by
|
||||
* accepting them directly from the API.
|
||||
*/
|
||||
const attributeName = Model.$keys.columnsToAttributes.get(key);
|
||||
if (attributeName) {
|
||||
this[attributeName] = value;
|
||||
continue;
|
||||
}
|
||||
|
||||
/**
|
||||
* If key is defined as a relation, then ignore it, since one
|
||||
* must pass a qualified model to `this.$setRelated()`
|
||||
*/
|
||||
if (Model.$relationsDefinitions.has(key)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/**
|
||||
* If the property already exists on the model, then set it
|
||||
* as it is vs defining it as an extra property
|
||||
*/
|
||||
if (this.hasOwnProperty(key)) {
|
||||
this[key] = value;
|
||||
continue;
|
||||
}
|
||||
|
||||
/**
|
||||
* Raise error when not instructed to ignore non-existing properties.
|
||||
*/
|
||||
if (!allowExtraProperties) {
|
||||
throw new Error(`Cannot define "${key}" on "${Model.name}" model, since it is not defined as a model property`);
|
||||
}
|
||||
|
||||
this.$extras[key] = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
// export class DatasetRelatedBaseModel extends LucidBaseModel {
|
||||
// public dataset: BelongsTo<typeof Dataset>;
|
||||
// }
|
||||
// export interface DatasetRelatedBaseModel {
|
||||
// dataset: BelongsTo<typeof Dataset>;
|
||||
// }
|
54
app/models/collection.ts
Normal file
54
app/models/collection.ts
Normal file
|
@ -0,0 +1,54 @@
|
|||
import { column, SnakeCaseNamingStrategy, manyToMany, belongsTo } from '@adonisjs/lucid/orm';
|
||||
import Dataset from './dataset.js';
|
||||
import BaseModel from './base_model.js';
|
||||
import CollectionRole from './collection_role.js';
|
||||
import type { ManyToMany } from "@adonisjs/lucid/types/relations";
|
||||
import type { BelongsTo } from "@adonisjs/lucid/types/relations";
|
||||
|
||||
export default class Collection extends BaseModel {
|
||||
public static namingStrategy = new SnakeCaseNamingStrategy();
|
||||
public static primaryKey = 'id';
|
||||
public static table = 'collections';
|
||||
public static fillable: string[] = ['name', 'number', 'role_id'];
|
||||
|
||||
@column({
|
||||
isPrimary: true,
|
||||
})
|
||||
public id: number;
|
||||
|
||||
@column({})
|
||||
public document_id: number;
|
||||
|
||||
@column({})
|
||||
public role_id?: number;
|
||||
|
||||
@column({})
|
||||
public number?: string;
|
||||
|
||||
@column({})
|
||||
public name: string;
|
||||
|
||||
@column({})
|
||||
public oai_subset?: string;
|
||||
|
||||
@column({})
|
||||
public parent_id?: number;
|
||||
|
||||
@column({})
|
||||
public visible: boolean;
|
||||
|
||||
@column({})
|
||||
public visible_publish: boolean;
|
||||
|
||||
@manyToMany(() => Dataset, {
|
||||
pivotForeignKey: 'collection_id',
|
||||
pivotRelatedForeignKey: 'document_id',
|
||||
pivotTable: 'link_documents_collections',
|
||||
})
|
||||
public datasets: ManyToMany<typeof Dataset>;
|
||||
|
||||
@belongsTo(() => CollectionRole, {
|
||||
foreignKey: 'role_id',
|
||||
})
|
||||
public collectionRole: BelongsTo<typeof CollectionRole>;
|
||||
}
|
39
app/models/collection_role.ts
Normal file
39
app/models/collection_role.ts
Normal file
|
@ -0,0 +1,39 @@
|
|||
import { column, SnakeCaseNamingStrategy, hasMany } from '@adonisjs/lucid/orm';
|
||||
import BaseModel from './base_model.js';
|
||||
import Collection from './collection.js';
|
||||
import type { HasMany } from "@adonisjs/lucid/types/relations";
|
||||
|
||||
export default class CollectionRole extends BaseModel {
|
||||
public static namingStrategy = new SnakeCaseNamingStrategy();
|
||||
public static primaryKey = 'id';
|
||||
public static table = 'collections_roles';
|
||||
public static fillable: string[] = ['name', 'oai_name', 'visible'];
|
||||
|
||||
@column({
|
||||
isPrimary: true,
|
||||
})
|
||||
public id: number;
|
||||
|
||||
@column({})
|
||||
public name: string;
|
||||
|
||||
@column({})
|
||||
public oai_name?: string;
|
||||
|
||||
@column({})
|
||||
public position: number;
|
||||
|
||||
@column({})
|
||||
public visible: boolean;
|
||||
|
||||
@column({})
|
||||
public visible_frontdoor: boolean;
|
||||
|
||||
@column({})
|
||||
public visible_oai: boolean;
|
||||
|
||||
@hasMany(() => Collection, {
|
||||
foreignKey: 'role_id',
|
||||
})
|
||||
public collections: HasMany<typeof Collection>;
|
||||
}
|
90
app/models/coverage.ts
Normal file
90
app/models/coverage.ts
Normal file
|
@ -0,0 +1,90 @@
|
|||
import { column, SnakeCaseNamingStrategy, belongsTo } from '@adonisjs/lucid/orm';
|
||||
import { DateTime } from 'luxon';
|
||||
import Dataset from './dataset.js';
|
||||
import BaseModel from './base_model.js';
|
||||
import type { BelongsTo } from "@adonisjs/lucid/types/relations";
|
||||
|
||||
export default class Coverage extends BaseModel {
|
||||
public static namingStrategy = new SnakeCaseNamingStrategy();
|
||||
public static primaryKey = 'id';
|
||||
public static table = 'coverage';
|
||||
public static selfAssignPrimaryKey = false;
|
||||
public static fillable: string[] = [
|
||||
'elevation_min',
|
||||
'elevation_max',
|
||||
'elevation_absolut',
|
||||
'depth_min',
|
||||
'depth_max',
|
||||
'depth_absolut',
|
||||
'time_min',
|
||||
'time_max',
|
||||
'time_absolut',
|
||||
'x_min',
|
||||
'x_max',
|
||||
'y_min',
|
||||
'y_max',
|
||||
];
|
||||
|
||||
@column({
|
||||
isPrimary: true,
|
||||
})
|
||||
public id: number;
|
||||
|
||||
@column({})
|
||||
public dataset_id: number;
|
||||
|
||||
@column({})
|
||||
public elevation_min: number;
|
||||
|
||||
@column({})
|
||||
public elevation_max: number;
|
||||
|
||||
@column({})
|
||||
public elevation_absolut: number;
|
||||
|
||||
@column({})
|
||||
public depth_min: number;
|
||||
|
||||
@column({})
|
||||
public depth_max: number;
|
||||
|
||||
@column({})
|
||||
public depth_absolut: number;
|
||||
|
||||
@column.dateTime({})
|
||||
public time_min: DateTime;
|
||||
|
||||
@column.dateTime({})
|
||||
public time_max: DateTime;
|
||||
|
||||
@column.dateTime({})
|
||||
public time_absolut: DateTime;
|
||||
|
||||
@column({})
|
||||
public x_min: number;
|
||||
|
||||
@column({})
|
||||
public x_max: number;
|
||||
|
||||
@column({})
|
||||
public y_min: number;
|
||||
|
||||
@column({})
|
||||
public y_max: number;
|
||||
|
||||
@column.dateTime({
|
||||
autoCreate: true,
|
||||
})
|
||||
public created_at: DateTime;
|
||||
|
||||
@column.dateTime({
|
||||
autoCreate: true,
|
||||
autoUpdate: true,
|
||||
})
|
||||
public updated_at: DateTime;
|
||||
|
||||
@belongsTo(() => Dataset, {
|
||||
foreignKey: 'dataset_id',
|
||||
})
|
||||
public dataset: BelongsTo<typeof Dataset>;
|
||||
}
|
273
app/models/dataset.ts
Normal file
273
app/models/dataset.ts
Normal file
|
@ -0,0 +1,273 @@
|
|||
import {
|
||||
column,
|
||||
SnakeCaseNamingStrategy,
|
||||
manyToMany,
|
||||
belongsTo,
|
||||
hasMany,
|
||||
computed,
|
||||
hasOne
|
||||
} from '@adonisjs/lucid/orm';
|
||||
import { DateTime } from 'luxon';
|
||||
import dayjs from 'dayjs';
|
||||
import Person from './person.js';
|
||||
import User from './user.js';
|
||||
import Title from './title.js';
|
||||
import Description from './description.js';
|
||||
import License from './license.js';
|
||||
import Subject from './subject.js';
|
||||
import File from './file.js';
|
||||
import Coverage from './coverage.js';
|
||||
import DatasetReference from './dataset_reference.js';
|
||||
import Collection from './collection.js';
|
||||
import DatasetIdentifier from './dataset_identifier.js';
|
||||
import Project from './project.js';
|
||||
import DocumentXmlCache from './DocumentXmlCache.js';
|
||||
import DatasetExtension from '#models/traits/dataset_extension';
|
||||
import type { ManyToMany } from "@adonisjs/lucid/types/relations";
|
||||
import type { BelongsTo } from "@adonisjs/lucid/types/relations";
|
||||
import type { HasMany } from "@adonisjs/lucid/types/relations";
|
||||
import type { HasOne } from "@adonisjs/lucid/types/relations";
|
||||
|
||||
export default class Dataset extends DatasetExtension {
|
||||
public static namingStrategy = new SnakeCaseNamingStrategy();
|
||||
public static primaryKey = 'id';
|
||||
public static table = 'documents';
|
||||
public static selfAssignPrimaryKey = false;
|
||||
|
||||
@column({ isPrimary: true })
|
||||
public id: number;
|
||||
|
||||
@column({})
|
||||
public server_state: string;
|
||||
|
||||
@column({})
|
||||
public publisher_name: string;
|
||||
|
||||
@column({ columnName: 'creating_corporation' })
|
||||
public creating_corporation: string;
|
||||
|
||||
@column.dateTime({ columnName: 'embargo_date' })
|
||||
public embargo_date: DateTime;
|
||||
|
||||
@column({})
|
||||
public type: string;
|
||||
|
||||
@column({})
|
||||
public language: string;
|
||||
|
||||
@column({columnName: 'publish_id'})
|
||||
public publish_id: number | null = null;
|
||||
|
||||
@column({})
|
||||
public project_id: number | null = null;
|
||||
|
||||
@column({})
|
||||
public account_id: number | null = null;
|
||||
|
||||
@column({})
|
||||
public editor_id: number | null = null;
|
||||
|
||||
@column({})
|
||||
public reviewer_id: number | null = null;
|
||||
|
||||
@column({})
|
||||
public reject_editor_note: string | null;
|
||||
|
||||
@column({})
|
||||
public preferred_reviewer: string | null;
|
||||
|
||||
@column({})
|
||||
public preferred_reviewer_email: string | null;
|
||||
|
||||
@column({})
|
||||
public reject_reviewer_note: string | null;
|
||||
|
||||
@column.dateTime({ columnName: 'server_date_published' })
|
||||
public server_date_published: DateTime;
|
||||
|
||||
// @column.dateTime({ autoCreate: true, columnName: 'created_at' })
|
||||
@column.dateTime({
|
||||
serialize: (value: Date | null) => {
|
||||
return value ? dayjs(value).format('MMMM D YYYY HH:mm a') : value;
|
||||
},
|
||||
autoCreate: true,
|
||||
columnName: 'created_at',
|
||||
})
|
||||
public created_at: DateTime;
|
||||
|
||||
@column.dateTime({
|
||||
serialize: (value: Date | null) => {
|
||||
return value ? dayjs(value).format('MMMM D YYYY HH:mm a') : value;
|
||||
},
|
||||
autoCreate: true,
|
||||
autoUpdate: true,
|
||||
columnName: 'server_date_modified',
|
||||
})
|
||||
public server_date_modified: DateTime;
|
||||
|
||||
@manyToMany(() => Person, {
|
||||
pivotForeignKey: 'document_id',
|
||||
pivotRelatedForeignKey: 'person_id',
|
||||
pivotTable: 'link_documents_persons',
|
||||
pivotColumns: ['role', 'sort_order', 'allow_email_contact'],
|
||||
})
|
||||
public persons: ManyToMany<typeof Person>;
|
||||
|
||||
/**
|
||||
* Get the account that the dataset belongs to
|
||||
*/
|
||||
@belongsTo(() => User, {
|
||||
foreignKey: 'account_id',
|
||||
})
|
||||
public user: BelongsTo<typeof User>;
|
||||
|
||||
@belongsTo(() => Project, {
|
||||
foreignKey: 'project_id',
|
||||
})
|
||||
public project: BelongsTo<typeof Project>;
|
||||
|
||||
@hasMany(() => Title, {
|
||||
foreignKey: 'document_id',
|
||||
})
|
||||
public titles: HasMany<typeof Title>;
|
||||
|
||||
@hasMany(() => Description, {
|
||||
foreignKey: 'document_id',
|
||||
})
|
||||
public descriptions: HasMany<typeof Description>;
|
||||
|
||||
@manyToMany(() => License, {
|
||||
pivotForeignKey: 'document_id',
|
||||
pivotRelatedForeignKey: 'licence_id',
|
||||
pivotTable: 'link_documents_licences',
|
||||
})
|
||||
public licenses: ManyToMany<typeof License>;
|
||||
|
||||
@manyToMany(() => Subject, {
|
||||
pivotForeignKey: 'document_id',
|
||||
pivotRelatedForeignKey: 'subject_id',
|
||||
pivotTable: 'link_dataset_subjects',
|
||||
})
|
||||
public subjects: ManyToMany<typeof Subject>;
|
||||
|
||||
@hasMany(() => File, {
|
||||
foreignKey: 'document_id',
|
||||
})
|
||||
public files: HasMany<typeof File>;
|
||||
|
||||
@hasOne(() => Coverage, {
|
||||
foreignKey: 'dataset_id',
|
||||
})
|
||||
public coverage: HasOne<typeof Coverage>;
|
||||
|
||||
@hasMany(() => DatasetReference, {
|
||||
foreignKey: 'document_id',
|
||||
})
|
||||
public references: HasMany<typeof DatasetReference>;
|
||||
|
||||
// Dataset.hasMany(Reference, {
|
||||
// foreignKey: "related_document_id",
|
||||
// as: "referenced_by",
|
||||
// });
|
||||
@hasMany(() => DatasetReference, {
|
||||
foreignKey: 'related_document_id',
|
||||
})
|
||||
public referenced_by: HasMany<typeof DatasetReference>;
|
||||
|
||||
@manyToMany(() => Collection, {
|
||||
pivotForeignKey: 'document_id',
|
||||
pivotRelatedForeignKey: 'collection_id',
|
||||
pivotTable: 'link_documents_collections',
|
||||
})
|
||||
public collections: ManyToMany<typeof Collection>;
|
||||
|
||||
@hasOne(() => DatasetIdentifier, {
|
||||
foreignKey: 'dataset_id',
|
||||
})
|
||||
public identifier: HasOne<typeof DatasetIdentifier>;
|
||||
|
||||
@computed({
|
||||
serializeAs: 'main_title',
|
||||
})
|
||||
public get mainTitle() {
|
||||
// return `${this.firstName} ${this.lastName}`;
|
||||
const mainTitle = this.titles?.find((title) => title.type === 'Main');
|
||||
return mainTitle ? mainTitle.value : null;
|
||||
}
|
||||
|
||||
@computed({
|
||||
serializeAs: 'main_abstract',
|
||||
})
|
||||
public get mainAbstract() {
|
||||
// return `${this.firstName} ${this.lastName}`;
|
||||
const mainTitle = this.descriptions?.find((desc) => desc.type === 'Abstract');
|
||||
return mainTitle ? mainTitle.value : null;
|
||||
}
|
||||
|
||||
@manyToMany(() => Person, {
|
||||
pivotForeignKey: 'document_id',
|
||||
pivotRelatedForeignKey: 'person_id',
|
||||
pivotTable: 'link_documents_persons',
|
||||
pivotColumns: ['role', 'sort_order', 'allow_email_contact'],
|
||||
onQuery(query) {
|
||||
query.wherePivot('role', 'author');
|
||||
},
|
||||
})
|
||||
public authors: ManyToMany<typeof Person>;
|
||||
|
||||
@manyToMany(() => Person, {
|
||||
pivotForeignKey: 'document_id',
|
||||
pivotRelatedForeignKey: 'person_id',
|
||||
pivotTable: 'link_documents_persons',
|
||||
pivotColumns: ['role', 'sort_order', 'allow_email_contact', 'contributor_type'],
|
||||
onQuery(query) {
|
||||
query.wherePivot('role', 'contributor');
|
||||
},
|
||||
})
|
||||
public contributors: ManyToMany<typeof Person>;
|
||||
|
||||
@hasOne(() => DocumentXmlCache, {
|
||||
foreignKey: 'document_id',
|
||||
})
|
||||
public xmlCache: HasOne<typeof DocumentXmlCache>;
|
||||
|
||||
/**
|
||||
* Get the account that the dataset belongs to
|
||||
*/
|
||||
@belongsTo(() => User, {
|
||||
foreignKey: 'editor_id',
|
||||
})
|
||||
public editor: BelongsTo<typeof User>;
|
||||
|
||||
@belongsTo(() => User, {
|
||||
foreignKey: 'reviewer_id',
|
||||
})
|
||||
public reviewer: BelongsTo<typeof User>;
|
||||
|
||||
static async earliestPublicationDate(): Promise<Dataset | null> {
|
||||
const serverState = 'published';
|
||||
|
||||
const model = await this.query().where('server_state', serverState).orderBy('server_date_published', 'asc').first();
|
||||
|
||||
return model || null;
|
||||
}
|
||||
|
||||
static async getMax (column: string) {
|
||||
let dataset = await this.query().max(column + ' as max_publish_id').firstOrFail();
|
||||
return dataset.$extras.max_publish_id;
|
||||
}
|
||||
|
||||
@computed({
|
||||
serializeAs: 'remaining_time',
|
||||
})
|
||||
public get remainingTime() {
|
||||
const dateFuture = this.server_date_modified.plus({ days: 14 });
|
||||
if (this.server_state === 'approved') {
|
||||
const now = DateTime.now();
|
||||
let duration = dateFuture.diff(now, ['days', 'hours', 'months']).toObject();
|
||||
return duration.days;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
50
app/models/dataset_identifier.ts
Normal file
50
app/models/dataset_identifier.ts
Normal file
|
@ -0,0 +1,50 @@
|
|||
import { column, SnakeCaseNamingStrategy, belongsTo } from '@adonisjs/lucid/orm';
|
||||
import { DateTime } from 'luxon';
|
||||
import Dataset from './dataset.js';
|
||||
import BaseModel from './base_model.js';
|
||||
import type { BelongsTo } from "@adonisjs/lucid/types/relations";
|
||||
|
||||
export default class DatasetIdentifier extends BaseModel {
|
||||
public static namingStrategy = new SnakeCaseNamingStrategy();
|
||||
public static primaryKey = 'id';
|
||||
public static table = 'dataset_identifiers';
|
||||
public static fillable: string[] = ['value', 'label', 'type', 'relation'];
|
||||
|
||||
@column({
|
||||
isPrimary: true,
|
||||
})
|
||||
public id: number;
|
||||
|
||||
@column({})
|
||||
public dataset_id: number;
|
||||
|
||||
@column({})
|
||||
public type: string;
|
||||
|
||||
@column({})
|
||||
public status: string;
|
||||
|
||||
@column({})
|
||||
public value: string;
|
||||
|
||||
@column.dateTime({
|
||||
autoCreate: true,
|
||||
})
|
||||
public created_at?: DateTime;
|
||||
|
||||
@column.dateTime({
|
||||
autoCreate: true,
|
||||
autoUpdate: true,
|
||||
})
|
||||
public updated_at?: DateTime;
|
||||
|
||||
@belongsTo(() => Dataset, {
|
||||
foreignKey: 'dataset_id',
|
||||
})
|
||||
public dataset: BelongsTo<typeof Dataset>;
|
||||
|
||||
// // Specify the relationships to touch when this model is updated
|
||||
// public static get touches() {
|
||||
// return ['dataset'];
|
||||
// }
|
||||
}
|
61
app/models/dataset_reference.ts
Normal file
61
app/models/dataset_reference.ts
Normal file
|
@ -0,0 +1,61 @@
|
|||
import { column, SnakeCaseNamingStrategy, belongsTo } from '@adonisjs/lucid/orm';
|
||||
import { DateTime } from 'luxon';
|
||||
import Dataset from './dataset.js';
|
||||
import BaseModel from './base_model.js';
|
||||
import type { BelongsTo } from "@adonisjs/lucid/types/relations";
|
||||
|
||||
export default class DatasetReference extends BaseModel {
|
||||
public static namingStrategy = new SnakeCaseNamingStrategy();
|
||||
public static primaryKey = 'id';
|
||||
public static table = 'document_references';
|
||||
public static fillable: string[] = ['value', 'label', 'type', 'relation'];
|
||||
|
||||
@column({
|
||||
isPrimary: true,
|
||||
})
|
||||
public id: number;
|
||||
|
||||
@column({})
|
||||
public document_id: number;
|
||||
|
||||
@column({})
|
||||
public related_document_id?: number;
|
||||
|
||||
@column({})
|
||||
public type: string;
|
||||
|
||||
@column({})
|
||||
public relation: string;
|
||||
|
||||
@column({})
|
||||
public value: string;
|
||||
|
||||
@column({})
|
||||
public label: string;
|
||||
|
||||
@column.dateTime({
|
||||
autoCreate: true,
|
||||
})
|
||||
public created_at?: DateTime;
|
||||
|
||||
@column.dateTime({
|
||||
autoCreate: true,
|
||||
autoUpdate: true,
|
||||
})
|
||||
public updated_at?: DateTime;
|
||||
|
||||
@belongsTo(() => Dataset, {
|
||||
foreignKey: 'document_id',
|
||||
})
|
||||
public dataset: BelongsTo<typeof Dataset>;
|
||||
|
||||
// Reference.belongsTo(Dataset, {
|
||||
// foreignKey: "related_document_id",
|
||||
// as: "new_dataset",
|
||||
// include: "identifier"
|
||||
// });
|
||||
@belongsTo(() => Dataset, {
|
||||
foreignKey: 'related_document_id',
|
||||
})
|
||||
public new_dataset: BelongsTo<typeof Dataset>;
|
||||
}
|
34
app/models/description.ts
Normal file
34
app/models/description.ts
Normal file
|
@ -0,0 +1,34 @@
|
|||
import { column, belongsTo } from '@adonisjs/lucid/orm';
|
||||
import Dataset from './dataset.js';
|
||||
import BaseModel from './base_model.js';
|
||||
import type { BelongsTo } from "@adonisjs/lucid/types/relations";
|
||||
|
||||
export default class Description extends BaseModel {
|
||||
public static primaryKey = 'id';
|
||||
public static table = 'dataset_abstracts';
|
||||
public static selfAssignPrimaryKey = false;
|
||||
public static timestamps = false;
|
||||
public static fillable: string[] = ['value', 'type', 'language'];
|
||||
|
||||
@column({
|
||||
isPrimary: true,
|
||||
})
|
||||
public id: number;
|
||||
|
||||
@column({})
|
||||
public document_id: number;
|
||||
|
||||
@column()
|
||||
public type: string;
|
||||
|
||||
@column()
|
||||
public value: string;
|
||||
|
||||
@column()
|
||||
public language: string;
|
||||
|
||||
@belongsTo(() => Dataset, {
|
||||
foreignKey: 'document_id',
|
||||
})
|
||||
public dataset: BelongsTo<typeof Dataset>;
|
||||
}
|
184
app/models/file.ts
Normal file
184
app/models/file.ts
Normal file
|
@ -0,0 +1,184 @@
|
|||
import { DateTime } from 'luxon';
|
||||
import { column, hasMany, belongsTo, SnakeCaseNamingStrategy, computed } from '@adonisjs/lucid/orm';
|
||||
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';
|
||||
// import Drive from '@adonisjs/drive';
|
||||
import drive from '#services/drive';
|
||||
|
||||
import type { HasMany } from "@adonisjs/lucid/types/relations";
|
||||
import type { BelongsTo } from "@adonisjs/lucid/types/relations";
|
||||
// import { TransactionClientContract } from "@adonisjs/lucid/database";
|
||||
import { TransactionClientContract } from '@adonisjs/lucid/types/database';
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
export default class File extends BaseModel {
|
||||
// private readonly _data: Uint8Array;
|
||||
// private readonly _type: string;
|
||||
// private readonly _size: number;
|
||||
|
||||
public static namingStrategy = new SnakeCaseNamingStrategy();
|
||||
public static primaryKey = 'id';
|
||||
public static table = 'document_files';
|
||||
public static selfAssignPrimaryKey = false;
|
||||
|
||||
@column({
|
||||
isPrimary: true,
|
||||
})
|
||||
public id: number;
|
||||
|
||||
@column({})
|
||||
public document_id: number;
|
||||
|
||||
@column({})
|
||||
public pathName: string;
|
||||
|
||||
@column()
|
||||
public label: string;
|
||||
|
||||
@column()
|
||||
public comment: string;
|
||||
|
||||
@column()
|
||||
public mimeType: string;
|
||||
|
||||
@column()
|
||||
public language: string;
|
||||
|
||||
@column()
|
||||
public fileSize: number;
|
||||
|
||||
@column()
|
||||
public visibleInOai: boolean;
|
||||
|
||||
@column()
|
||||
public visibleInFrontdoor: boolean;
|
||||
|
||||
@column()
|
||||
public sortOrder: number;
|
||||
|
||||
@column.dateTime({ autoCreate: true })
|
||||
public createdAt: DateTime;
|
||||
|
||||
@column.dateTime({ autoCreate: true, autoUpdate: true })
|
||||
public updatedAt: DateTime;
|
||||
|
||||
// public function dataset()
|
||||
// {
|
||||
// return $this->belongsTo(Dataset::class, 'document_id', 'id');
|
||||
// }
|
||||
@belongsTo(() => Dataset, {
|
||||
foreignKey: 'document_id',
|
||||
})
|
||||
public dataset: BelongsTo<typeof Dataset>;
|
||||
|
||||
@hasMany(() => HashValue, {
|
||||
foreignKey: 'file_id',
|
||||
})
|
||||
public hashvalues: HasMany<typeof HashValue>;
|
||||
|
||||
@computed({
|
||||
serializeAs: 'filePath',
|
||||
})
|
||||
public get filePath() {
|
||||
return `/storage/app/public/${this.pathName}`;
|
||||
// const mainTitle = this.titles?.find((title) => title.type === 'Main');
|
||||
// return mainTitle ? mainTitle.value : null;
|
||||
}
|
||||
|
||||
@computed({
|
||||
serializeAs: 'size',
|
||||
})
|
||||
public get size() {
|
||||
return this.fileSize;
|
||||
}
|
||||
|
||||
@computed({
|
||||
serializeAs: 'type',
|
||||
})
|
||||
public get type() {
|
||||
return this.mimeType;
|
||||
}
|
||||
|
||||
@computed({
|
||||
serializeAs: 'name',
|
||||
})
|
||||
get name(): string {
|
||||
return this.label;
|
||||
}
|
||||
|
||||
@computed({
|
||||
serializeAs: 'lastModified',
|
||||
})
|
||||
get lastModified(): number {
|
||||
return this.updatedAt.toUnixInteger(); //.toFormat("yyyy-MM-dd'T'HH:mm:ss'Z'");
|
||||
}
|
||||
|
||||
readonly webkitRelativePath: string = '';
|
||||
|
||||
@computed({
|
||||
serializeAs: 'fileData',
|
||||
})
|
||||
public get fileData(): string {
|
||||
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;
|
||||
|
||||
// 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) {
|
||||
const hashtypes: string[] = ['md5', 'sha512'];
|
||||
|
||||
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
|
||||
hash.value = hashString;
|
||||
|
||||
// https://github.com/adonisjs/core/discussions/1872#discussioncomment-132289
|
||||
const file: File = this;
|
||||
if (trx) {
|
||||
await file.useTransaction(trx).related('hashvalues').save(hash); // Save the hash value to the database
|
||||
} else {
|
||||
await file.related('hashvalues').save(hash); // Save the hash value to the database
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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: string, hashName = 'md5'): Promise<string> {
|
||||
return new Promise((resolve, reject) => {
|
||||
const hash = crypto.createHash(hashName);
|
||||
const stream = fs.createReadStream(path);
|
||||
stream.on('error', (err) => reject(err));
|
||||
stream.on('data', (chunk) => hash.update(chunk));
|
||||
stream.on('end', () => resolve(hash.digest('hex')));
|
||||
});
|
||||
}
|
||||
}
|
35
app/models/hash_value.ts
Normal file
35
app/models/hash_value.ts
Normal file
|
@ -0,0 +1,35 @@
|
|||
import { column, BaseModel, belongsTo, SnakeCaseNamingStrategy } from '@adonisjs/lucid/orm';
|
||||
import File from './file.js';
|
||||
import type { BelongsTo } from "@adonisjs/lucid/types/relations";
|
||||
|
||||
export default class HashValue extends BaseModel {
|
||||
public static namingStrategy = new SnakeCaseNamingStrategy();
|
||||
// public static primaryKey = 'file_id,type';
|
||||
public static table = 'file_hashvalues';
|
||||
|
||||
// static get primaryKey () {
|
||||
// return 'type, value'
|
||||
// }
|
||||
|
||||
public static get incrementing() {
|
||||
return false;
|
||||
}
|
||||
|
||||
// @column({
|
||||
// isPrimary: true,
|
||||
// })
|
||||
// public id: number;
|
||||
|
||||
// Foreign key is still on the same model
|
||||
@column({ isPrimary: true })
|
||||
public file_id: number;
|
||||
|
||||
@column({ isPrimary: true })
|
||||
public type: string;
|
||||
|
||||
@column()
|
||||
public value: string;
|
||||
|
||||
@belongsTo(() => File)
|
||||
public file: BelongsTo<typeof File>;
|
||||
}
|
36
app/models/language.ts
Normal file
36
app/models/language.ts
Normal file
|
@ -0,0 +1,36 @@
|
|||
import { column, SnakeCaseNamingStrategy } from '@adonisjs/lucid/orm';
|
||||
import BaseModel from './base_model.js';
|
||||
// import { DateTime } from 'luxon';
|
||||
|
||||
export default class Language extends BaseModel {
|
||||
public static namingStrategy = new SnakeCaseNamingStrategy();
|
||||
public static primaryKey = 'id';
|
||||
public static table = 'languages';
|
||||
public static selfAssignPrimaryKey = false;
|
||||
|
||||
@column({
|
||||
isPrimary: true,
|
||||
})
|
||||
public id: number;
|
||||
|
||||
@column({})
|
||||
public part2_b: string;
|
||||
|
||||
@column({})
|
||||
public part2_T: string;
|
||||
|
||||
@column({})
|
||||
public description: string;
|
||||
|
||||
@column({})
|
||||
public part1: string;
|
||||
|
||||
@column({})
|
||||
public type: string;
|
||||
|
||||
@column({})
|
||||
public ref_name: string;
|
||||
|
||||
@column({})
|
||||
public active: boolean;
|
||||
}
|
54
app/models/license.ts
Normal file
54
app/models/license.ts
Normal file
|
@ -0,0 +1,54 @@
|
|||
import { column, SnakeCaseNamingStrategy } from '@adonisjs/lucid/orm';
|
||||
import BaseModel from './base_model.js';
|
||||
|
||||
export default class License extends BaseModel {
|
||||
public static namingStrategy = new SnakeCaseNamingStrategy();
|
||||
public static primaryKey = 'id';
|
||||
public static table = 'document_licences';
|
||||
public static selfAssignPrimaryKey = false;
|
||||
public static timestamps = false;
|
||||
public static fillable: string[] = [
|
||||
'name_long',
|
||||
'name',
|
||||
'language',
|
||||
'link_licence',
|
||||
'link_logo',
|
||||
'desc_text',
|
||||
'desc_markup',
|
||||
'comment_internal',
|
||||
'mime_type',
|
||||
'sort_order',
|
||||
'language',
|
||||
'active',
|
||||
'pod_allowed',
|
||||
];
|
||||
|
||||
@column({
|
||||
isPrimary: true,
|
||||
})
|
||||
public id: number;
|
||||
|
||||
@column({})
|
||||
public active: boolean;
|
||||
|
||||
@column({})
|
||||
public langauge: string;
|
||||
|
||||
@column({})
|
||||
public link_licence: string;
|
||||
|
||||
@column({})
|
||||
public link_logo: string;
|
||||
|
||||
@column({})
|
||||
public display_name: string;
|
||||
|
||||
@column({})
|
||||
public name_long: string;
|
||||
|
||||
@column({})
|
||||
public name: string;
|
||||
|
||||
@column({})
|
||||
public sortOrder: number;
|
||||
}
|
94
app/models/permission.ts
Normal file
94
app/models/permission.ts
Normal file
|
@ -0,0 +1,94 @@
|
|||
import { column, manyToMany, SnakeCaseNamingStrategy } from '@adonisjs/lucid/orm';
|
||||
import { DateTime } from 'luxon';
|
||||
import dayjs from 'dayjs';
|
||||
import Role from '#models/role';
|
||||
import BaseModel from './base_model.js';
|
||||
import type { ManyToMany } from "@adonisjs/lucid/types/relations";
|
||||
|
||||
export default class Permission extends BaseModel {
|
||||
public static namingStrategy = new SnakeCaseNamingStrategy();
|
||||
public static primaryKey = 'id';
|
||||
public static table = 'permissions';
|
||||
public static selfAssignPrimaryKey = false;
|
||||
|
||||
@column({
|
||||
isPrimary: true,
|
||||
})
|
||||
public id: number;
|
||||
|
||||
@column({})
|
||||
public role_id: number;
|
||||
|
||||
@column({})
|
||||
public display_name: string;
|
||||
|
||||
@column({})
|
||||
public name: string;
|
||||
|
||||
@column({})
|
||||
public description: string;
|
||||
|
||||
@column.dateTime({
|
||||
serialize: (value: Date | null) => {
|
||||
return value ? dayjs(value).format('MMMM D YYYY HH:mm a') : value;
|
||||
},
|
||||
autoCreate: true,
|
||||
})
|
||||
public created_at: DateTime;
|
||||
|
||||
@column.dateTime({
|
||||
serialize: (value: Date | null) => {
|
||||
return value ? dayjs(value).format('MMMM D YYYY HH:mm a') : value;
|
||||
},
|
||||
autoCreate: true,
|
||||
autoUpdate: true,
|
||||
})
|
||||
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);
|
||||
// }
|
||||
|
||||
// public static boot() {
|
||||
// super.boot()
|
||||
|
||||
// this.before('create', async (_modelInstance) => {
|
||||
// _modelInstance.created_at = this.formatDateTime(_modelInstance.created_at)
|
||||
// _modelInstance.updated_at = this.formatDateTime(_modelInstance.updated_at)
|
||||
// })
|
||||
// this.before('update', async (_modelInstance) => {
|
||||
// _modelInstance.created_at = this.formatDateTime(_modelInstance.created_at)
|
||||
// _modelInstance.updated_at = this.formatDateTime(_modelInstance.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;
|
||||
// }
|
||||
|
||||
// @belongsTo(() => Role)
|
||||
// public role: BelongsTo<typeof Role>;
|
||||
|
||||
@manyToMany(() => Role, {
|
||||
pivotForeignKey: 'permission_id',
|
||||
pivotRelatedForeignKey: 'role_id',
|
||||
pivotTable: 'role_has_permissions',
|
||||
})
|
||||
public roles: ManyToMany<typeof Role>;
|
||||
}
|
86
app/models/person.ts
Normal file
86
app/models/person.ts
Normal file
|
@ -0,0 +1,86 @@
|
|||
import { column, SnakeCaseNamingStrategy, computed, manyToMany } from '@adonisjs/lucid/orm';
|
||||
import { DateTime } from 'luxon';
|
||||
import dayjs from 'dayjs';
|
||||
import Dataset from './dataset.js';
|
||||
import BaseModel from './base_model.js';
|
||||
import type { ManyToMany } from "@adonisjs/lucid/types/relations";
|
||||
|
||||
export default class Person extends BaseModel {
|
||||
public static namingStrategy = new SnakeCaseNamingStrategy();
|
||||
public static primaryKey = 'id';
|
||||
public static table = 'persons';
|
||||
public static selfAssignPrimaryKey = false;
|
||||
// only the academic_title, email, first_name, identifier_orcid, last_name and name_type attributes are allowed to be mass assigned.
|
||||
public static fillable: string[] = ['academic_title', 'email', 'first_name', 'identifier_orcid', 'last_name', 'name_type'];
|
||||
|
||||
@column({
|
||||
isPrimary: true,
|
||||
})
|
||||
public id: number;
|
||||
|
||||
@column({ columnName: 'academic_title' })
|
||||
public academicTitle: string;
|
||||
|
||||
@column()
|
||||
public email: string;
|
||||
|
||||
@column({})
|
||||
public firstName: string;
|
||||
|
||||
@column({})
|
||||
public lastName: string;
|
||||
|
||||
@column({})
|
||||
public identifierOrcid: string;
|
||||
|
||||
@column({})
|
||||
public status: boolean;
|
||||
|
||||
@column({})
|
||||
public nameType: string;
|
||||
|
||||
@column.dateTime({
|
||||
serialize: (value: Date | null) => {
|
||||
return value ? dayjs(value).format('MMMM D YYYY HH:mm a') : value;
|
||||
},
|
||||
autoCreate: true,
|
||||
})
|
||||
public createdAt: DateTime;
|
||||
|
||||
@computed({
|
||||
serializeAs: 'name',
|
||||
})
|
||||
public get fullName() {
|
||||
return `${this.firstName} ${this.lastName}`;
|
||||
}
|
||||
|
||||
// @computed()
|
||||
// public get progress(): number {
|
||||
// return 50;
|
||||
// }
|
||||
|
||||
// @computed()
|
||||
// public get created_at() {
|
||||
// return '2023-03-21 08:45:00';
|
||||
// }
|
||||
|
||||
@computed()
|
||||
public get datasetCount() {
|
||||
const stock = this.$extras.datasets_count; //my pivot column name was "stock"
|
||||
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',
|
||||
pivotTable: 'link_documents_persons',
|
||||
pivotColumns: ['role', 'sort_order', 'allow_email_contact'],
|
||||
})
|
||||
public datasets: ManyToMany<typeof Dataset>;
|
||||
}
|
35
app/models/project.ts
Normal file
35
app/models/project.ts
Normal file
|
@ -0,0 +1,35 @@
|
|||
import { column, SnakeCaseNamingStrategy } from '@adonisjs/lucid/orm';
|
||||
import { DateTime } from 'luxon';
|
||||
import BaseModel from './base_model.js';
|
||||
|
||||
export default class Project extends BaseModel {
|
||||
public static namingStrategy = new SnakeCaseNamingStrategy();
|
||||
public static primaryKey = 'id';
|
||||
public static table = 'projects';
|
||||
public static selfAssignPrimaryKey = false;
|
||||
|
||||
@column({
|
||||
isPrimary: true,
|
||||
})
|
||||
public id: number;
|
||||
|
||||
@column({})
|
||||
public label: string;
|
||||
|
||||
@column({})
|
||||
public name: string;
|
||||
|
||||
@column({})
|
||||
public description: string;
|
||||
|
||||
@column.dateTime({
|
||||
autoCreate: true,
|
||||
})
|
||||
public created_at: DateTime;
|
||||
|
||||
@column.dateTime({
|
||||
autoCreate: true,
|
||||
autoUpdate: true,
|
||||
})
|
||||
public updated_at: DateTime;
|
||||
}
|
98
app/models/role.ts
Normal file
98
app/models/role.ts
Normal file
|
@ -0,0 +1,98 @@
|
|||
import { column, SnakeCaseNamingStrategy, manyToMany, beforeCreate, beforeUpdate } from '@adonisjs/lucid/orm';
|
||||
import BaseModel from './base_model.js';
|
||||
import { DateTime } from 'luxon';
|
||||
// import moment from 'moment';
|
||||
import dayjs from 'dayjs';
|
||||
import User from './user.js';
|
||||
import Permission from '#models/permission';
|
||||
import type { ManyToMany } from "@adonisjs/lucid/types/relations";
|
||||
|
||||
export default class Role extends BaseModel {
|
||||
public static namingStrategy = new SnakeCaseNamingStrategy();
|
||||
public static primaryKey = 'id';
|
||||
public static table = 'roles';
|
||||
public static selfAssignPrimaryKey = false;
|
||||
|
||||
@column({
|
||||
isPrimary: true,
|
||||
})
|
||||
public id: number;
|
||||
|
||||
@column({})
|
||||
public display_name: string;
|
||||
|
||||
@column({})
|
||||
public name: string;
|
||||
|
||||
@column({})
|
||||
public description: string;
|
||||
|
||||
@column.dateTime({
|
||||
serialize: (value: Date | null) => {
|
||||
// return value ? moment(value).format('MMMM Do YYYY, HH:mm:ss') : value;
|
||||
return value ? dayjs(value).format('MMMM D YYYY HH:mm a') : value;
|
||||
},
|
||||
autoCreate: true,
|
||||
})
|
||||
public created_at: DateTime;
|
||||
|
||||
@column.dateTime({
|
||||
serialize: (value: Date | null) => {
|
||||
return value ? dayjs(value).format('MMMM D YYYY HH:mm a') : value;
|
||||
},
|
||||
autoCreate: true,
|
||||
autoUpdate: true,
|
||||
})
|
||||
public updated_at: DateTime;
|
||||
|
||||
@beforeCreate()
|
||||
@beforeUpdate()
|
||||
public static async resetDate(role: Role) {
|
||||
role.created_at = this.formatDateTime(role.created_at);
|
||||
role.updated_at = this.formatDateTime(role.updated_at);
|
||||
}
|
||||
|
||||
// public static boot() {
|
||||
// super.boot();
|
||||
|
||||
// this.before('create', async (_modelInstance) => {
|
||||
// _modelInstance.created_at = this.formatDateTime(_modelInstance.created_at);
|
||||
// _modelInstance.updated_at = this.formatDateTime(_modelInstance.updated_at);
|
||||
// });
|
||||
// this.before('update', async (_modelInstance) => {
|
||||
// _modelInstance.created_at = this.formatDateTime(_modelInstance.created_at);
|
||||
// _modelInstance.updated_at = this.formatDateTime(_modelInstance.updated_at);
|
||||
// });
|
||||
// }
|
||||
|
||||
private static formatDateTime(datetime: any) {
|
||||
let value = new Date(datetime);
|
||||
return datetime
|
||||
? value.getFullYear() +
|
||||
'-' +
|
||||
(value.getMonth() + 1) +
|
||||
'-' +
|
||||
value.getDate() +
|
||||
' ' +
|
||||
value.getHours() +
|
||||
':' +
|
||||
value.getMinutes() +
|
||||
':' +
|
||||
value.getSeconds()
|
||||
: datetime;
|
||||
}
|
||||
|
||||
@manyToMany(() => User, {
|
||||
pivotForeignKey: 'role_id',
|
||||
pivotRelatedForeignKey: 'account_id',
|
||||
pivotTable: 'link_accounts_roles',
|
||||
})
|
||||
public users: ManyToMany<typeof User>;
|
||||
|
||||
@manyToMany(() => Permission, {
|
||||
pivotForeignKey: 'role_id',
|
||||
pivotRelatedForeignKey: 'permission_id',
|
||||
pivotTable: 'role_has_permissions',
|
||||
})
|
||||
public permissions: ManyToMany<typeof Permission>;
|
||||
}
|
83
app/models/subject.ts
Normal file
83
app/models/subject.ts
Normal file
|
@ -0,0 +1,83 @@
|
|||
import { column, SnakeCaseNamingStrategy, manyToMany, computed} from '@adonisjs/lucid/orm';
|
||||
import BaseModel from './base_model.js';
|
||||
|
||||
import { DateTime } from 'luxon';
|
||||
import dayjs from 'dayjs';
|
||||
import Dataset from './dataset.js';
|
||||
import type { ManyToMany } from "@adonisjs/lucid/types/relations";
|
||||
|
||||
export default class Subject extends BaseModel {
|
||||
public static namingStrategy = new SnakeCaseNamingStrategy();
|
||||
public static table = 'dataset_subjects';
|
||||
public static selfAssignPrimaryKey = false;
|
||||
|
||||
@column({
|
||||
isPrimary: true,
|
||||
})
|
||||
public id: number;
|
||||
|
||||
@column({})
|
||||
public language: string;
|
||||
|
||||
@column({})
|
||||
public type: string;
|
||||
|
||||
@column({})
|
||||
public value: string;
|
||||
|
||||
@column({})
|
||||
public external_key: string;
|
||||
|
||||
@column.dateTime({
|
||||
serialize: (value: Date | null) => {
|
||||
return value ? dayjs(value).format('MMMM D YYYY HH:mm a') : value;
|
||||
},
|
||||
autoCreate: true,
|
||||
})
|
||||
public created_at: DateTime;
|
||||
|
||||
@column.dateTime({
|
||||
serialize: (value: Date | null) => {
|
||||
return value ? dayjs(value).format('MMMM D YYYY HH:mm a') : value;
|
||||
},
|
||||
autoCreate: true,
|
||||
autoUpdate: true,
|
||||
})
|
||||
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);
|
||||
// }
|
||||
|
||||
// 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, {
|
||||
pivotForeignKey: 'subject_id',
|
||||
pivotRelatedForeignKey: 'document_id',
|
||||
pivotTable: 'link_dataset_subjects',
|
||||
})
|
||||
public datasets: ManyToMany<typeof Dataset>;
|
||||
}
|
36
app/models/title.ts
Normal file
36
app/models/title.ts
Normal file
|
@ -0,0 +1,36 @@
|
|||
import { column, belongsTo } from '@adonisjs/lucid/orm';
|
||||
import Dataset from './dataset.js';
|
||||
import BaseModel from './base_model.js';
|
||||
import type { BelongsTo } from "@adonisjs/lucid/types/relations";
|
||||
|
||||
// import { DatasetRelatedBaseModel } from './BaseModel';
|
||||
|
||||
export default class Title extends BaseModel {
|
||||
public static primaryKey = 'id';
|
||||
public static table = 'dataset_titles';
|
||||
public static selfAssignPrimaryKey = false;
|
||||
public static timestamps = false;
|
||||
public static fillable: string[] = ['value', 'type', 'language'];
|
||||
|
||||
@column({
|
||||
isPrimary: true,
|
||||
})
|
||||
public id: number;
|
||||
|
||||
@column({})
|
||||
public document_id: number;
|
||||
|
||||
@column()
|
||||
public type: string;
|
||||
|
||||
@column()
|
||||
public value: string;
|
||||
|
||||
@column()
|
||||
public language: string;
|
||||
|
||||
@belongsTo(() => Dataset, {
|
||||
foreignKey: 'document_id',
|
||||
})
|
||||
public dataset: BelongsTo<typeof Dataset>;
|
||||
}
|
65
app/models/totp_secret.ts
Normal file
65
app/models/totp_secret.ts
Normal file
|
@ -0,0 +1,65 @@
|
|||
import { column, BaseModel, SnakeCaseNamingStrategy, belongsTo } from '@adonisjs/lucid/orm';
|
||||
import User from './user.js';
|
||||
import { DateTime } from 'luxon';
|
||||
import dayjs from 'dayjs';
|
||||
// import Encryption from '@ioc:Adonis/Core/Encryption';
|
||||
import encryption from '@adonisjs/core/services/encryption';
|
||||
import type { BelongsTo } from "@adonisjs/lucid/types/relations";
|
||||
|
||||
export default class TotpSecret extends BaseModel {
|
||||
public static namingStrategy = new SnakeCaseNamingStrategy();
|
||||
public static table = 'totp_secrets';
|
||||
// public static fillable: string[] = ['value', 'label', 'type', 'relation'];
|
||||
|
||||
@column({
|
||||
isPrimary: true,
|
||||
})
|
||||
public id: number;
|
||||
|
||||
@column({})
|
||||
public user_id: number;
|
||||
|
||||
// @column()
|
||||
// public twoFactorSecret: string;
|
||||
@column({
|
||||
serializeAs: null,
|
||||
consume: (value: string) => (value ? JSON.parse(encryption.decrypt(value) ?? '{}') : null),
|
||||
prepare: (value: string) => encryption.encrypt(JSON.stringify(value)),
|
||||
})
|
||||
public twoFactorSecret?: string | null;
|
||||
|
||||
// serializeAs: null removes the model properties from the serialized output.
|
||||
@column({
|
||||
serializeAs: null,
|
||||
consume: (value: string) => (value ? JSON.parse(encryption.decrypt(value) ?? '[]') : []),
|
||||
prepare: (value: string[]) => encryption.encrypt(JSON.stringify(value)),
|
||||
})
|
||||
public twoFactorRecoveryCodes?: string[] | null;
|
||||
|
||||
@column({})
|
||||
public state: number;
|
||||
|
||||
@column.dateTime({
|
||||
serialize: (value: Date | null) => {
|
||||
// return value ? moment(value).format('MMMM Do YYYY, HH:mm:ss') : value;
|
||||
return value ? dayjs(value).format('MMMM D YYYY HH:mm a') : value;
|
||||
},
|
||||
autoCreate: true,
|
||||
})
|
||||
public created_at: DateTime;
|
||||
|
||||
@column.dateTime({
|
||||
serialize: (value: Date | null) => {
|
||||
return value ? dayjs(value).format('MMMM D YYYY HH:mm a') : value;
|
||||
},
|
||||
autoCreate: true,
|
||||
autoUpdate: true,
|
||||
})
|
||||
public updated_at: DateTime;
|
||||
|
||||
@belongsTo(() => User, {
|
||||
foreignKey: 'user_id',
|
||||
})
|
||||
public user: BelongsTo<typeof User>;
|
||||
|
||||
}
|
329
app/models/traits/dataset_extension.ts
Normal file
329
app/models/traits/dataset_extension.ts
Normal file
|
@ -0,0 +1,329 @@
|
|||
import Title from '#models/title';
|
||||
import Description from '#models/description';
|
||||
import License from '#models/license';
|
||||
import Person from '#models/person';
|
||||
import DatasetReference from '#models/dataset_reference';
|
||||
import DatasetIdentifier from '#models/dataset_identifier';
|
||||
import Subject from '#models/subject';
|
||||
import File from '#models/file';
|
||||
import Coverage from '#models/coverage';
|
||||
import Collection from '#models/collection';
|
||||
import { BaseModel as LucidBaseModel } from '@adonisjs/lucid/orm';
|
||||
import Field from '#app/Library/Field';
|
||||
import { DateTime } from 'luxon';
|
||||
|
||||
// @StaticImplements<LucidModel>()
|
||||
// class LucidDatasetModel extends BaseModel{
|
||||
// @belongsTo(() => Dataset, {
|
||||
// foreignKey: 'dataset_id',
|
||||
// })
|
||||
// dataset: BelongsTo<typeof Dataset>;
|
||||
// }
|
||||
|
||||
export type DatasetRelatedModel =
|
||||
| typeof Title
|
||||
| typeof Description
|
||||
| typeof Coverage
|
||||
| typeof DatasetIdentifier
|
||||
| typeof DatasetReference
|
||||
| typeof Description
|
||||
| typeof DatasetIdentifier
|
||||
| typeof File;
|
||||
|
||||
export default abstract class DatasetExtension extends LucidBaseModel {
|
||||
public abstract id: number;
|
||||
public externalFields: Record<string, any> = this.getExternalFields();
|
||||
// which fields shoud#t be published
|
||||
protected internalFields: Record<string, any> = {};
|
||||
protected fields: Record<string, any> = {};
|
||||
[key: string]: any;
|
||||
|
||||
private getExternalFields(): Record<string, any> {
|
||||
// External fields definition
|
||||
return {
|
||||
TitleMain: {
|
||||
model: Title,
|
||||
options: { type: ['Main'] },
|
||||
fetch: 'eager',
|
||||
},
|
||||
TitleAdditional: {
|
||||
model: Title,
|
||||
options: { type: ['Alternative', 'Sub', 'Translated', 'Other'] },
|
||||
fetch: 'eager',
|
||||
},
|
||||
TitleAbstract: {
|
||||
model: Description,
|
||||
options: { type: ['Abstract', 'Translated'] },
|
||||
fetch: 'eager',
|
||||
},
|
||||
TitleAbstractAdditional: {
|
||||
model: Description,
|
||||
options: { type: ['Methods', 'Technical_info', 'Series_information', 'Other'] },
|
||||
fetch: 'eager',
|
||||
},
|
||||
Licence: {
|
||||
model: License,
|
||||
through: 'link_documents_licences',
|
||||
relation: 'licenses',
|
||||
fetch: 'eager',
|
||||
},
|
||||
PersonAuthor: {
|
||||
model: Person,
|
||||
through: 'link_documents_persons',
|
||||
pivot: { role: 'author', sort_order: 'sort_order', allow_email_contact: 'allow_email_contact' },
|
||||
relation: 'persons',
|
||||
fetch: 'eager',
|
||||
},
|
||||
PersonContributor: {
|
||||
model: Person,
|
||||
through: 'link_documents_persons',
|
||||
pivot: {
|
||||
role: 'contributor',
|
||||
contributor_type: 'contributor_type',
|
||||
sort_order: 'sort_order',
|
||||
allow_email_contact: 'allow_email_contact',
|
||||
},
|
||||
relation: 'contributors',
|
||||
fetch: 'eager',
|
||||
},
|
||||
Reference: {
|
||||
model: DatasetReference,
|
||||
relation: 'references',
|
||||
fetch: 'eager',
|
||||
},
|
||||
Identifier: {
|
||||
model: DatasetIdentifier,
|
||||
relation: 'identifier',
|
||||
fetch: 'eager',
|
||||
},
|
||||
Subject: {
|
||||
model: Subject,
|
||||
through: 'link_dataset_subjects',
|
||||
relation: 'subjects',
|
||||
fetch: 'eager',
|
||||
},
|
||||
File: {
|
||||
model: File,
|
||||
relation: 'files',
|
||||
fetch: 'eager',
|
||||
},
|
||||
Coverage: {
|
||||
model: Coverage,
|
||||
relation: 'coverage',
|
||||
fetch: 'eager',
|
||||
},
|
||||
Collection: {
|
||||
model: Collection,
|
||||
through: 'link_documents_collections',
|
||||
relation: 'collections',
|
||||
fetch: 'eager',
|
||||
// 'include': { 'model': CollectionRole, 'relation': 'collectionrole' }
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
public initFields(): void {
|
||||
// Initialize internal fields
|
||||
let fields = new Array<string>(
|
||||
'Id',
|
||||
'PublisherName',
|
||||
'PublishId',
|
||||
'ContributingCorporation',
|
||||
'CreatingCorporation',
|
||||
'Language',
|
||||
'PublishedDate',
|
||||
// 'PublishedYear',
|
||||
'PublisherName',
|
||||
// 'PublisherPlace',
|
||||
'PublicationState',
|
||||
'EmbargoDate',
|
||||
'CreatedAt',
|
||||
'ServerDateModified',
|
||||
'ServerDatePublished',
|
||||
'ServerDateDeleted',
|
||||
'ServerState',
|
||||
'Type',
|
||||
'BelongsToBibliography',
|
||||
);
|
||||
fields.forEach((fieldname) => {
|
||||
let field = new Field(fieldname);
|
||||
this.addField(field);
|
||||
});
|
||||
// Initialize external fields
|
||||
const fieldNames = Object.keys(this.externalFields);
|
||||
for (const fieldName of fieldNames) {
|
||||
// const field = this.externalFields[fieldName];
|
||||
let field = new Field(fieldName);
|
||||
field.setMultiplicity('*');
|
||||
this.addField(field);
|
||||
}
|
||||
|
||||
// // Initialize available date fields and set up date validator
|
||||
// // if the particular field is present
|
||||
let dateFields = new Array<string>('EmbargoDate', 'CreatedAt', 'ServerDateModified', 'ServerDatePublished', 'ServerDateDeleted');
|
||||
dateFields.forEach((fieldname) => {
|
||||
let dateField = this.getField(fieldname);
|
||||
dateField instanceof Field && dateField.setValueModelClass(DateTime.now());
|
||||
});
|
||||
}
|
||||
|
||||
public async describe(): Promise<Array<string>> {
|
||||
let length: number = Object.keys(this.fields).length;
|
||||
if (length == 0) {
|
||||
await this.fetchValues();
|
||||
}
|
||||
// Get an array of all field names in the 'fields' object
|
||||
const allFields = Object.keys(this.fields);
|
||||
// Get an array of all field names in the 'internalFields' array
|
||||
const internalFields = Object.keys(this.internalFields);
|
||||
// Use the `filter` method to find field names that are not in 'internalFields'
|
||||
const filteredFields = allFields.filter((fieldName) => !internalFields.includes(fieldName));
|
||||
return filteredFields;
|
||||
}
|
||||
|
||||
private addField(field: Field): void {
|
||||
// Add field
|
||||
const fieldName = field.getName();
|
||||
if (fieldName && this.externalFields[fieldName]) {
|
||||
const options = this.externalFields[fieldName];
|
||||
|
||||
// Set ValueModelClass if a model option is given
|
||||
if (options.model) {
|
||||
field.setValueModelClass(options.model);
|
||||
}
|
||||
}
|
||||
|
||||
this.fields[field.getName()] = field;
|
||||
// field.setOwningModelClass(this.constructor.name);
|
||||
}
|
||||
|
||||
public getField(name: string): Field | null {
|
||||
// Get field
|
||||
return this.fields[name] !== undefined ? this.fields[name] : null;
|
||||
}
|
||||
|
||||
public async fetchValues(): Promise<void> {
|
||||
this.initFields();
|
||||
await this.loadFieldValues();
|
||||
}
|
||||
|
||||
private async loadFieldValues(): Promise<void> {
|
||||
for (const [fieldname, field] of Object.entries(this.fields)) {
|
||||
// extern fields via model relation
|
||||
if (this.externalFields.hasOwnProperty(fieldname)) {
|
||||
await this.loadExternal(fieldname);
|
||||
// dataset attributes itself
|
||||
} else {
|
||||
// Field is not external and gets handled by simply reading. to snake_case
|
||||
const property_name = this.convertFieldnameToColumn(fieldname); //id
|
||||
const fieldVal = this[property_name]; //276
|
||||
|
||||
// Explicitly set null if the field represents a model except for dates.
|
||||
if (field.getValueModelClass() !== null) {
|
||||
field.setValue(fieldVal === undefined || fieldVal === null ? null : fieldVal);
|
||||
} else {
|
||||
field.setValue(fieldVal);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private async loadExternal(fieldname: string): Promise<void> {
|
||||
const field = this.fields[fieldname];
|
||||
|
||||
// let modelclass: typeof Title | typeof Description;
|
||||
let modelclass: DatasetRelatedModel = field.getValueModelClass();
|
||||
let modelInstance = new modelclass();
|
||||
|
||||
// Create a query builder
|
||||
const select = modelclass.query();
|
||||
|
||||
// If any declared constraints, add them to the query
|
||||
if (this.externalFields[fieldname]?.options) {
|
||||
const options: Array<string> = this.externalFields[fieldname].options;
|
||||
for (const [column, value] of Object.entries(options)) {
|
||||
if (Array.isArray(value)) {
|
||||
select.whereIn(column, value);
|
||||
} else {
|
||||
select.where(column, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Get dependent rows
|
||||
const result: Record<string, any>[] = [];
|
||||
const datasetId = this.id;
|
||||
let rows: any[] = [];
|
||||
|
||||
if (this.externalFields[fieldname]?.through) {
|
||||
const relation = this.externalFields[fieldname].relation;
|
||||
// rows = this[relation];
|
||||
rows = await this.related(relation).query();
|
||||
|
||||
if (this.externalFields[fieldname].pivot) {
|
||||
const pivotArray = this.externalFields[fieldname].pivot;
|
||||
const pivotValue = pivotArray.role;
|
||||
// rows = this[relation]().wherePivot('role', pivotValue).get();
|
||||
rows = await this.related(relation).query().wherePivot('role', pivotValue);
|
||||
}
|
||||
} else if (modelInstance.hasOwnProperty('dataset')) {
|
||||
rows = await select
|
||||
.whereHas('dataset', (q) => {
|
||||
q.where('id', datasetId);
|
||||
})
|
||||
.orderBy('id')
|
||||
.select();
|
||||
}
|
||||
|
||||
// 1 ..n relations
|
||||
for (const row of rows) {
|
||||
const attributes = Object.keys(row.$attributes);
|
||||
|
||||
if (this.externalFields[fieldname]?.pivot) {
|
||||
const pivotArray = this.externalFields[fieldname].pivot;
|
||||
const arrayKeys = Object.keys(pivotArray);
|
||||
const extendedArrayKeys = arrayKeys.map((pivotAttribute) => {
|
||||
return `pivot_${pivotAttribute}`;
|
||||
});
|
||||
attributes.push(...extendedArrayKeys);
|
||||
}
|
||||
|
||||
const objArray: Record<string, any> = {};
|
||||
|
||||
for (const property_name of attributes) {
|
||||
let fieldName = this.convertColumnToFieldname(property_name);
|
||||
let fieldval = '';
|
||||
|
||||
if (property_name.startsWith('pivot_')) {
|
||||
const str = property_name.replace('pivot_', '');
|
||||
fieldName = this.convertColumnToFieldname(str);
|
||||
// fieldval = row.$pivot[str];
|
||||
fieldval = row.$extras[property_name];
|
||||
} else if (fieldName === 'Type') {
|
||||
fieldval = row[property_name]?.charAt(0).toUpperCase() + row[property_name]?.slice(1);
|
||||
} else {
|
||||
fieldval = row[property_name];
|
||||
}
|
||||
|
||||
objArray[fieldName] = fieldval;
|
||||
}
|
||||
|
||||
result.push(objArray);
|
||||
}
|
||||
|
||||
// Set the field value
|
||||
field.setValue(result);
|
||||
}
|
||||
|
||||
// to snakeCase
|
||||
private convertFieldnameToColumn(fieldname: string): string {
|
||||
return fieldname.replace(/([a-z\d])([A-Z])/g, '$1_$2').toLowerCase();
|
||||
}
|
||||
|
||||
private convertColumnToFieldname(columnName: string): string {
|
||||
return columnName
|
||||
.split(/[-_]/)
|
||||
.map((word) => word.charAt(0).toUpperCase() + word.slice(1))
|
||||
.join('');
|
||||
}
|
||||
}
|
160
app/models/user.ts
Normal file
160
app/models/user.ts
Normal file
|
@ -0,0 +1,160 @@
|
|||
import { DateTime } from 'luxon';
|
||||
import { withAuthFinder } from '@adonisjs/auth/mixins/lucid'
|
||||
import { column, manyToMany, hasMany } from '@adonisjs/lucid/orm';
|
||||
import hash from '@adonisjs/core/services/hash';
|
||||
import Role from './role.js';
|
||||
import db from '@adonisjs/lucid/services/db';
|
||||
import config from '@adonisjs/core/services/config';
|
||||
import Dataset from './dataset.js';
|
||||
import BaseModel from './base_model.js';
|
||||
// import Encryption from '@ioc:Adonis/Core/Encryption';
|
||||
import encryption from '@adonisjs/core/services/encryption';
|
||||
import { TotpState } from '#contracts/enums';
|
||||
import type { ManyToMany } from '@adonisjs/lucid/types/relations';
|
||||
import type { HasMany } from '@adonisjs/lucid/types/relations';
|
||||
import { compose } from '@adonisjs/core/helpers';
|
||||
|
||||
const AuthFinder = withAuthFinder(() => hash.use('laravel'), {
|
||||
uids: ['email'],
|
||||
passwordColumnName: 'password',
|
||||
});
|
||||
|
||||
// import TotpSecret from './TotpSecret';
|
||||
|
||||
// export default interface IUser {
|
||||
// id: number;
|
||||
// login: string;
|
||||
// email: string;
|
||||
// // password: string;
|
||||
// // createdAt: DateTime;
|
||||
// // updatedAt: DateTime;
|
||||
// // async (user): Promise<void>;
|
||||
// }
|
||||
|
||||
// const permissionTable = config.get('rolePermission.permission_table', 'permissions');
|
||||
// const rolePermissionTable = config.get('rolePermission.role_permission_table', 'role_has_permissions');
|
||||
|
||||
// const roleTable = config.get('rolePermission.role_table', 'roles');
|
||||
// const userRoleTable = config.get('rolePermission.user_role_table', 'link_accounts_roles');
|
||||
|
||||
export default class User extends compose(BaseModel, AuthFinder) {
|
||||
// export default class User extends BaseModel {
|
||||
public static table = 'accounts';
|
||||
|
||||
@column({ isPrimary: true })
|
||||
public id: number;
|
||||
|
||||
@column()
|
||||
public login: string;
|
||||
|
||||
@column()
|
||||
public email: string;
|
||||
|
||||
@column({ serializeAs: null })
|
||||
public password: string;
|
||||
|
||||
@column.dateTime({ autoCreate: true })
|
||||
public createdAt: DateTime;
|
||||
|
||||
@column.dateTime({ autoCreate: true, autoUpdate: true })
|
||||
public updatedAt: DateTime;
|
||||
|
||||
// serializeAs: null removes the model properties from the serialized output.
|
||||
@column({
|
||||
serializeAs: null,
|
||||
consume: (value: string) => (value ? JSON.parse(encryption.decrypt(value) ?? '{}') : null),
|
||||
prepare: (value: string) => encryption.encrypt(JSON.stringify(value)),
|
||||
})
|
||||
public twoFactorSecret?: string | null;
|
||||
|
||||
// serializeAs: null removes the model properties from the serialized output.
|
||||
@column({
|
||||
serializeAs: null,
|
||||
consume: (value: string) => (value ? JSON.parse(encryption.decrypt(value) ?? '[]') : []),
|
||||
prepare: (value: string[]) => encryption.encrypt(JSON.stringify(value)),
|
||||
})
|
||||
public twoFactorRecoveryCodes?: string[] | null;
|
||||
|
||||
@column({})
|
||||
public state: number;
|
||||
|
||||
// @hasOne(() => TotpSecret, {
|
||||
// foreignKey: 'user_id',
|
||||
// })
|
||||
// public totp_secret: HasOne<typeof TotpSecret>;
|
||||
|
||||
// @beforeSave()
|
||||
// public static async hashPassword(user: User) {
|
||||
// if (user.$dirty.password) {
|
||||
// user.password = await hash.use('laravel').make(user.password);
|
||||
// }
|
||||
// }
|
||||
|
||||
public get isTwoFactorEnabled(): boolean {
|
||||
return Boolean(this?.twoFactorSecret && this.state == TotpState.STATE_ENABLED);
|
||||
// return Boolean(this.totp_secret?.twoFactorSecret);
|
||||
}
|
||||
|
||||
@manyToMany(() => Role, {
|
||||
pivotForeignKey: 'account_id',
|
||||
pivotRelatedForeignKey: 'role_id',
|
||||
pivotTable: 'link_accounts_roles',
|
||||
})
|
||||
public roles: ManyToMany<typeof Role>;
|
||||
|
||||
@hasMany(() => Dataset, {
|
||||
foreignKey: 'account_id',
|
||||
})
|
||||
public datasets: HasMany<typeof Dataset>;
|
||||
|
||||
// https://github.com/adonisjs/core/discussions/1872#discussioncomment-132289
|
||||
public async getRoles(this: User): Promise<string[]> {
|
||||
const test = await this.related('roles').query();
|
||||
return test.map((role) => role.name);
|
||||
}
|
||||
|
||||
public async can(permissionNames: Array<string>): Promise<boolean> {
|
||||
// const permissions = await this.getPermissions()
|
||||
// return Acl.check(expression, operand => _.includes(permissions, operand))
|
||||
const hasPermission = await this.checkHasPermissions(this, permissionNames);
|
||||
return hasPermission;
|
||||
}
|
||||
|
||||
private async checkHasPermissions(user: User, permissionNames: Array<string>): Promise<boolean> {
|
||||
const permissionTable = config.get('rolePermission.permission_table', 'permissions');
|
||||
const rolePermissionTable = config.get('rolePermission.role_permission_table', 'role_has_permissions');
|
||||
|
||||
const roleTable = config.get('rolePermission.role_table', 'roles');
|
||||
const userRoleTable = config.get('rolePermission.user_role_table', 'link_accounts_roles');
|
||||
|
||||
let permissionPlaceHolder = '(';
|
||||
let placeholders = new Array(permissionNames.length).fill('?');
|
||||
permissionPlaceHolder += placeholders.join(',');
|
||||
permissionPlaceHolder += ')';
|
||||
|
||||
let {
|
||||
rows: {
|
||||
0: { permissioncount },
|
||||
},
|
||||
} = await db.rawQuery(
|
||||
'SELECT count("p"."name") as permissionCount FROM ' +
|
||||
roleTable +
|
||||
' r INNER JOIN ' +
|
||||
userRoleTable +
|
||||
' ur ON ur.role_id=r.id AND "ur"."account_id"=? ' +
|
||||
' INNER JOIN ' +
|
||||
rolePermissionTable +
|
||||
' rp ON rp.role_id=r.id ' +
|
||||
' INNER JOIN ' +
|
||||
permissionTable +
|
||||
' p ON rp.permission_id=p.id AND "p"."name" in ' +
|
||||
permissionPlaceHolder +
|
||||
' LIMIT 1',
|
||||
[user.id, ...permissionNames],
|
||||
);
|
||||
|
||||
return permissioncount > 0;
|
||||
}
|
||||
}
|
||||
|
||||
// export default User;
|
76
app/models/user_role.ts
Normal file
76
app/models/user_role.ts
Normal file
|
@ -0,0 +1,76 @@
|
|||
import { column, BaseModel, belongsTo, SnakeCaseNamingStrategy } from '@adonisjs/lucid/orm';
|
||||
|
||||
import User from '#models/user';
|
||||
import Role from '#models/role';
|
||||
import { DateTime } from 'luxon';
|
||||
import type { BelongsTo } from "@adonisjs/lucid/types/relations";
|
||||
|
||||
// import moment from 'moment'
|
||||
|
||||
export default class UserRole extends BaseModel {
|
||||
public static namingStrategy = new SnakeCaseNamingStrategy();
|
||||
public static primaryKey = 'id';
|
||||
public static table = 'user_roles';
|
||||
public static selfAssignPrimaryKey = false;
|
||||
|
||||
@column({
|
||||
isPrimary: true,
|
||||
})
|
||||
public id: number;
|
||||
|
||||
@column({})
|
||||
public user_id: number;
|
||||
|
||||
@column({})
|
||||
public role_id: number;
|
||||
|
||||
@column({
|
||||
// serialize: (value: DateTime | null) => {
|
||||
// return value ? moment(value).format('lll') : value
|
||||
// },
|
||||
})
|
||||
public created_at: DateTime;
|
||||
|
||||
@column({
|
||||
// serialize: (value: DateTime | null) => {
|
||||
// return value ? moment(value).format('lll') : value
|
||||
// },
|
||||
})
|
||||
public updated_at: DateTime;
|
||||
|
||||
public static boot() {
|
||||
super.boot();
|
||||
|
||||
this.before('create', async (_modelInstance) => {
|
||||
_modelInstance.created_at = this.formatDateTime(_modelInstance.created_at);
|
||||
_modelInstance.updated_at = this.formatDateTime(_modelInstance.updated_at);
|
||||
});
|
||||
this.before('update', async (_modelInstance) => {
|
||||
_modelInstance.created_at = this.formatDateTime(_modelInstance.created_at);
|
||||
_modelInstance.updated_at = this.formatDateTime(_modelInstance.updated_at);
|
||||
});
|
||||
}
|
||||
|
||||
private static formatDateTime(datetime: any) {
|
||||
let value = new Date(datetime);
|
||||
return datetime
|
||||
? value.getFullYear() +
|
||||
'-' +
|
||||
(value.getMonth() + 1) +
|
||||
'-' +
|
||||
value.getDate() +
|
||||
' ' +
|
||||
value.getHours() +
|
||||
':' +
|
||||
value.getMinutes() +
|
||||
':' +
|
||||
value.getSeconds()
|
||||
: datetime;
|
||||
}
|
||||
|
||||
@belongsTo(() => User)
|
||||
public user: BelongsTo<typeof User>;
|
||||
|
||||
@belongsTo(() => Role)
|
||||
public role: BelongsTo<typeof Role>;
|
||||
}
|
Loading…
Add table
editor.link_modal.header
Reference in a new issue