oneuptime/Common/Models/BaseModel.ts

380 lines
10 KiB
TypeScript
Raw Normal View History

2022-04-29 19:54:29 +00:00
import {
DeleteDateColumn,
UpdateDateColumn,
CreateDateColumn,
VersionColumn,
PrimaryGeneratedColumn,
BaseEntity,
} from 'typeorm';
2022-07-10 20:04:01 +00:00
2022-05-01 21:35:04 +00:00
import Columns from '../Types/Database/Columns';
2022-05-19 19:41:12 +00:00
import TableColumn, {
getTableColumn,
2022-05-20 12:30:11 +00:00
getTableColumns,
TableColumnMetadata,
2022-05-19 19:41:12 +00:00
} from '../Types/Database/TableColumn';
2022-08-01 15:25:30 +00:00
import { JSONArray, JSONFunctions, JSONObject, JSONValue } from '../Types/JSON';
2022-04-30 13:25:36 +00:00
import ObjectID from '../Types/ObjectID';
2022-05-18 20:49:52 +00:00
import Dictionary from '../Types/Dictionary';
2022-05-31 13:01:53 +00:00
import HashedString from '../Types/HashedString';
2022-06-06 11:00:39 +00:00
import Email from '../Types/Email';
import Phone from '../Types/Phone';
import PositiveNumber from '../Types/PositiveNumber';
2022-06-29 20:51:49 +00:00
import Route from '../Types/API/Route';
2022-06-29 23:09:29 +00:00
import TableColumnType from '../Types/Database/TableColumnType';
2022-07-11 16:07:56 +00:00
import Permission from '../Types/Permission';
2022-08-05 14:40:47 +00:00
import { ColumnAccessControl } from '../Types/Database/AccessControl/AccessControl';
import { getColumnAccessControlForAllColumns } from '../Types/Database/AccessControl/ColumnAccessControl';
2022-06-06 11:00:39 +00:00
export type DbTypes =
2022-06-06 13:08:59 +00:00
| string
| number
| PositiveNumber
| Email
| HashedString
| URL
| Phone
| JSONObject
| JSONArray
| Buffer;
2022-04-26 20:24:24 +00:00
2022-05-02 20:27:46 +00:00
export default class BaseModel extends BaseEntity {
2022-06-29 23:09:29 +00:00
@TableColumn({ title: 'ID', type: TableColumnType.ObjectID })
2022-05-10 19:26:44 +00:00
@PrimaryGeneratedColumn('uuid')
2022-05-18 20:49:52 +00:00
public _id?: string = undefined;
2022-05-10 19:26:44 +00:00
2022-06-29 23:09:29 +00:00
@TableColumn({ title: 'Created', type: TableColumnType.Date })
2022-05-10 19:26:44 +00:00
@CreateDateColumn()
2022-05-18 20:49:52 +00:00
public createdAt?: Date = undefined;
2022-05-10 19:26:44 +00:00
2022-06-29 23:09:29 +00:00
@TableColumn({ title: 'Updated', type: TableColumnType.Date })
2022-05-10 19:26:44 +00:00
@UpdateDateColumn()
2022-05-18 20:49:52 +00:00
public updatedAt?: Date = undefined;
2022-05-10 19:26:44 +00:00
2022-06-29 23:09:29 +00:00
@TableColumn({ title: 'Deleted', type: TableColumnType.Date })
2022-05-10 19:26:44 +00:00
@DeleteDateColumn()
2022-05-18 20:49:52 +00:00
public deletedAt?: Date = undefined;
2022-05-10 19:26:44 +00:00
2022-06-29 23:09:29 +00:00
@TableColumn({ title: 'Version', type: TableColumnType.Version })
2022-05-10 19:26:44 +00:00
@VersionColumn()
2022-05-18 20:49:52 +00:00
public version?: number = undefined;
2022-05-10 19:26:44 +00:00
2022-07-10 20:04:01 +00:00
public createRecordPermissions!: Array<Permission>;
public readRecordPermissions!: Array<Permission>;
public deleteRecordPermissions!: Array<Permission>;
public updateRecordPermissions!: Array<Permission>;
2022-05-24 21:03:32 +00:00
2022-07-11 16:07:56 +00:00
public userColumn!: string | null;
public labelsColumn!: string | null;
2022-05-24 21:03:32 +00:00
public slugifyColumn!: string | null;
public saveSlugToColumn!: string | null;
2022-07-18 18:48:51 +00:00
public singularName!: string | null;
public pluralName!: string | null;
2022-04-30 13:25:36 +00:00
2022-07-11 19:46:55 +00:00
public isPermissionIf: Dictionary<JSONObject> = {};
2022-07-11 19:40:09 +00:00
2022-08-13 15:07:05 +00:00
public isMultiTenantRequestAllowed!: boolean | null;
2022-08-07 19:52:20 +00:00
2022-06-29 20:51:49 +00:00
public crudApiPath!: Route | null;
2022-05-11 18:49:44 +00:00
// If this resource is by projectId, which column does projectId belong to?
2022-08-10 18:14:01 +00:00
public tenantColumn!: string | null;
2022-05-11 18:49:44 +00:00
2022-05-05 20:17:31 +00:00
public constructor(id?: ObjectID) {
super();
if (id) {
2022-05-05 20:40:56 +00:00
this.id = id;
2022-05-05 20:17:31 +00:00
}
}
2022-05-10 19:26:44 +00:00
public getHashedColumns(): Columns {
2022-05-20 12:30:11 +00:00
const dictionary: Dictionary<TableColumnMetadata> =
getTableColumns(this);
const columns: Array<string> = [];
for (const key in dictionary) {
if (dictionary[key]?.hashed) {
columns.push(key);
}
}
return new Columns(columns);
2022-05-10 19:26:44 +00:00
}
2022-05-17 21:57:52 +00:00
public getDisplayColumnPlaceholderAs(columnName: string): string | null {
2022-05-21 13:25:14 +00:00
return getTableColumn(this, columnName)?.placeholder || null;
2022-05-17 21:57:52 +00:00
}
2022-05-14 13:50:58 +00:00
public getDisplayColumnTitleAs(columnName: string): string | null {
2022-05-21 13:25:14 +00:00
return getTableColumn(this, columnName)?.title || null;
2022-05-14 13:50:58 +00:00
}
public getDisplayColumnDescriptionAs(columnName: string): string | null {
2022-05-21 13:25:14 +00:00
return getTableColumn(this, columnName)?.description || null;
2022-05-13 13:39:21 +00:00
}
2022-05-01 21:35:04 +00:00
public getEncryptedColumns(): Columns {
2022-05-20 12:30:11 +00:00
const dictionary: Dictionary<TableColumnMetadata> =
getTableColumns(this);
const columns: Array<string> = [];
for (const key in dictionary) {
if (dictionary[key]?.encrypted) {
columns.push(key);
}
}
return new Columns(columns);
2022-05-01 12:41:55 +00:00
}
2022-05-11 20:11:09 +00:00
public getTableColumns(): Columns {
2022-05-20 12:30:11 +00:00
return new Columns(Object.keys(getTableColumns(this)));
2022-05-11 20:11:09 +00:00
}
2022-08-13 15:03:18 +00:00
public canQueryMultiTenant(): boolean {
2022-08-13 15:07:05 +00:00
return Boolean(this.isMultiTenantRequestAllowed);
2022-08-07 19:52:20 +00:00
}
2022-06-29 23:09:29 +00:00
public getTableColumnMetadata(columnName: string): TableColumnMetadata {
const dictionary: Dictionary<TableColumnMetadata> =
getTableColumns(this);
return dictionary[columnName] as TableColumnMetadata;
}
2022-08-06 14:09:03 +00:00
public getColumnAccessControlForAllColumns(): Dictionary<ColumnAccessControl> {
const dictionary: Dictionary<ColumnAccessControl> =
getColumnAccessControlForAllColumns(this);
2022-08-05 14:40:47 +00:00
2022-08-06 14:09:03 +00:00
const defaultColumns: Array<string> = [
'_id',
'createdAt',
'deletedAt',
'updatedAt',
];
2022-08-05 14:40:47 +00:00
for (const key of defaultColumns) {
dictionary[key] = {
read: this.readRecordPermissions,
create: this.createRecordPermissions,
2022-08-06 14:09:03 +00:00
update: this.updateRecordPermissions,
};
2022-08-05 14:40:47 +00:00
}
return dictionary;
}
2022-06-06 13:08:59 +00:00
public hasValue(columnName: string): boolean {
return Boolean((this as any)[columnName]);
2022-06-06 11:00:39 +00:00
}
public getValue<T extends DbTypes>(columnName: string): T {
return (this as any)[columnName] as T;
}
2022-06-06 13:08:59 +00:00
public setValue<T extends DbTypes>(columnName: string, value: T): void {
(this as any)[columnName] = value;
2022-06-06 11:00:39 +00:00
}
2022-07-11 19:46:55 +00:00
public doesPermissionHasConfitions(
permission: Permission
): JSONObject | null {
return this.isPermissionIf[permission]
? (this.isPermissionIf[permission] as JSONObject)
: null;
2022-07-11 19:40:09 +00:00
}
2022-05-01 21:35:04 +00:00
public getUniqueColumns(): Columns {
2022-05-20 12:30:11 +00:00
const dictionary: Dictionary<TableColumnMetadata> =
getTableColumns(this);
const columns: Array<string> = [];
for (const key in dictionary) {
if (dictionary[key]?.unique) {
columns.push(key);
}
}
return new Columns(columns);
2022-04-30 13:25:36 +00:00
}
2022-07-10 20:04:01 +00:00
public setSlugifyColumn(columnName: string): void {
this.slugifyColumn = columnName;
2022-05-11 18:49:44 +00:00
}
2022-07-10 20:04:01 +00:00
public getRequiredColumns(): Columns {
const dictionary: Dictionary<TableColumnMetadata> =
getTableColumns(this);
2022-05-19 19:41:12 +00:00
const columns: Array<string> = [];
2022-07-10 20:04:01 +00:00
for (const key in dictionary) {
if (dictionary[key]?.required) {
2022-05-18 20:49:52 +00:00
columns.push(key);
}
2022-05-03 18:23:17 +00:00
}
2022-05-01 21:35:04 +00:00
2022-05-18 20:49:52 +00:00
return new Columns(columns);
2022-05-01 21:35:04 +00:00
}
2022-07-10 20:04:01 +00:00
public getSlugifyColumn(): string | null {
return this.slugifyColumn;
2022-05-01 21:35:04 +00:00
}
2022-07-10 20:04:01 +00:00
public getCrudApiPath(): Route | null {
return this.crudApiPath;
2022-05-11 18:49:44 +00:00
}
2022-07-10 20:04:01 +00:00
public getSaveSlugToColumn(): string | null {
return this.saveSlugToColumn;
2022-05-11 18:49:44 +00:00
}
2022-08-07 18:44:03 +00:00
public getTenantColumn(): string | null {
2022-08-10 18:14:01 +00:00
return this.tenantColumn;
2022-07-11 16:07:56 +00:00
}
public getuserColumn(): string | null {
return this.userColumn;
}
public getLabelsColumn(): string | null {
return this.labelsColumn;
2022-05-11 18:49:44 +00:00
}
2022-07-10 20:04:01 +00:00
public get id(): ObjectID | null {
return this._id ? new ObjectID(this._id) : null;
2022-05-11 18:49:44 +00:00
}
2022-07-10 20:04:01 +00:00
public set id(value: ObjectID | null) {
if (value) {
this._id = value.toString();
2022-05-10 19:26:44 +00:00
}
}
2022-07-10 20:04:01 +00:00
private static _fromJSON<T extends BaseModel>(
json: JSONObject,
2022-08-13 15:07:05 +00:00
type: { new (): T }
2022-07-10 20:04:01 +00:00
): T {
2022-07-23 08:51:18 +00:00
json = JSONFunctions.deserialize(json);
2022-07-10 20:04:01 +00:00
const baseModel: T = new type();
2022-05-18 20:49:52 +00:00
2022-07-10 20:04:01 +00:00
for (const key of Object.keys(json)) {
if (baseModel.getTableColumnMetadata(key)) {
(baseModel as any)[key] = json[key];
}
2022-05-10 19:26:44 +00:00
}
2022-05-18 20:49:52 +00:00
2022-07-10 20:04:01 +00:00
return baseModel as T;
2022-05-10 19:26:44 +00:00
}
2022-07-10 20:04:01 +00:00
public static fromJSON<T extends BaseModel>(
json: JSONObject | JSONArray,
2022-08-13 15:07:05 +00:00
type: { new (): T }
2022-07-10 20:04:01 +00:00
): T | Array<T> {
if (Array.isArray(json)) {
const arr: Array<T> = [];
2022-05-18 20:49:52 +00:00
2022-07-10 20:04:01 +00:00
for (const item of json) {
arr.push(this._fromJSON<T>(item, type));
2022-05-18 20:49:52 +00:00
}
2022-07-10 20:04:01 +00:00
return arr;
2022-05-10 19:26:44 +00:00
}
2022-07-10 20:04:01 +00:00
return this._fromJSON<T>(json, type);
2022-05-10 19:26:44 +00:00
}
2022-07-13 18:41:47 +00:00
public fromJSON<T extends BaseModel>(
json: JSONObject,
2022-08-13 15:07:05 +00:00
type: { new (): T }
2022-07-13 18:41:47 +00:00
): T {
return BaseModel._fromJSON<T>(json, type);
}
public fromJSONArray<T extends BaseModel>(
json: Array<JSONObject>,
2022-08-13 15:07:05 +00:00
type: { new (): T }
2022-07-13 18:41:47 +00:00
): Array<T> {
const arr: Array<T> = [];
for (const item of json) {
arr.push(BaseModel._fromJSON<T>(item, type));
}
return arr;
}
2022-07-10 20:04:01 +00:00
public isDefaultValueColumn(columnName: string): boolean {
return Boolean(getTableColumn(this, columnName).isDefaultValueColumn);
2022-05-20 09:47:21 +00:00
}
2022-08-01 15:25:30 +00:00
public getColumnValue(columnName: string): JSONValue | null {
if (getTableColumn(this, columnName) && (this as any)[columnName]) {
return (this as any)[columnName] as JSONValue;
}
return null;
}
public setColumnValue(columnName: string, value: JSONValue): void {
if (getTableColumn(this, columnName)) {
2022-08-03 11:30:38 +00:00
return ((this as any)[columnName] = value as any);
2022-08-01 15:25:30 +00:00
}
}
2022-08-01 09:37:14 +00:00
public isEntityColumn(columnName: string): boolean {
2022-08-03 11:30:38 +00:00
const tableColumnType: TableColumnMetadata = getTableColumn(
this,
columnName
);
return Boolean(
tableColumnType.type === TableColumnType.Entity ||
2022-08-13 15:07:05 +00:00
tableColumnType.type === TableColumnType.EntityArray
2022-08-03 11:30:38 +00:00
);
2022-08-01 09:37:14 +00:00
}
2022-05-11 20:11:09 +00:00
public toJSON(): JSONObject {
2022-07-29 19:38:34 +00:00
const json: JSONObject = this.toJSONObject();
2022-07-24 11:12:14 +00:00
return JSONFunctions.serialize(json);
}
public toJSONObject(): JSONObject {
2022-05-12 20:08:19 +00:00
const json: JSONObject = {};
2022-07-24 11:12:14 +00:00
2022-06-29 23:09:29 +00:00
for (const key of this.getTableColumns().columns) {
2022-08-03 11:30:38 +00:00
if (typeof (this as any)[key] === 'boolean') {
2022-08-02 19:51:46 +00:00
json[key] = (this as any)[key];
2022-08-03 11:30:38 +00:00
} else if ((this as any)[key]) {
2022-07-23 08:51:18 +00:00
json[key] = (this as any)[key];
2022-05-11 20:11:09 +00:00
}
}
2022-07-29 19:22:59 +00:00
return json;
2022-07-24 11:12:14 +00:00
}
public static toJSONObjectArray(list: Array<BaseModel>): JSONArray {
const array: JSONArray = [];
for (const item of list) {
array.push(item.toJSONObject());
}
return array;
2022-05-11 20:11:09 +00:00
}
public static toJSONArray(list: Array<BaseModel>): JSONArray {
const array: JSONArray = [];
2022-05-12 20:08:19 +00:00
for (const item of list) {
2022-05-11 20:11:09 +00:00
array.push(item.toJSON());
}
return array;
}
2022-07-11 16:07:56 +00:00
public hasPermission(_permissions: Array<Permission>): boolean {
return false;
}
2022-08-12 11:12:53 +00:00
public isTenantModel(): boolean {
return false;
}
public isUserModel(): boolean {
return false;
}
2022-04-29 19:54:29 +00:00
}