2018-03-30 15:30:30 -04:00
|
|
|
import 'reflect-metadata';
|
|
|
|
import {Connection, ConnectionOptions, createConnection, getConnection} from 'typeorm';
|
|
|
|
import {UserEntity} from './enitites/UserEntity';
|
2019-12-14 17:27:01 +01:00
|
|
|
import {UserRoles} from '../../../../common/entities/UserDTO';
|
2018-03-30 15:30:30 -04:00
|
|
|
import {PhotoEntity} from './enitites/PhotoEntity';
|
|
|
|
import {DirectoryEntity} from './enitites/DirectoryEntity';
|
2019-12-14 17:27:01 +01:00
|
|
|
import {Config} from '../../../../common/config/private/Config';
|
2018-03-30 15:30:30 -04:00
|
|
|
import {SharingEntity} from './enitites/SharingEntity';
|
2019-12-14 17:27:01 +01:00
|
|
|
import {PasswordHelper} from '../../PasswordHelper';
|
|
|
|
import {ProjectPath} from '../../../ProjectPath';
|
2018-03-30 15:30:30 -04:00
|
|
|
import {VersionEntity} from './enitites/VersionEntity';
|
2019-12-14 17:27:01 +01:00
|
|
|
import {Logger} from '../../../Logger';
|
2018-11-17 19:32:31 +01:00
|
|
|
import {MediaEntity} from './enitites/MediaEntity';
|
|
|
|
import {VideoEntity} from './enitites/VideoEntity';
|
2019-12-14 17:27:01 +01:00
|
|
|
import {DataStructureVersion} from '../../../../common/DataStructureVersion';
|
2018-11-26 00:26:29 +01:00
|
|
|
import {FileEntity} from './enitites/FileEntity';
|
2019-01-12 16:41:45 +01:00
|
|
|
import {FaceRegionEntry} from './enitites/FaceRegionEntry';
|
|
|
|
import {PersonEntry} from './enitites/PersonEntry';
|
2019-12-14 17:27:01 +01:00
|
|
|
import {Utils} from '../../../../common/Utils';
|
2019-12-29 00:35:41 +01:00
|
|
|
import * as path from 'path';
|
2021-04-18 15:48:35 +02:00
|
|
|
import {DatabaseType, ServerDataBaseConfig, SQLLogLevel} from '../../../../common/config/private/PrivateConfig';
|
2021-05-28 19:21:18 +02:00
|
|
|
import {AlbumBaseEntity} from './enitites/album/AlbumBaseEntity';
|
|
|
|
import {SavedSearchEntity} from './enitites/album/SavedSearchEntity';
|
2021-12-31 14:38:01 +01:00
|
|
|
import {NotificationManager} from '../../NotifocationManager';
|
2022-02-22 14:06:52 +01:00
|
|
|
import {ActiveExperiments, Experiments} from '../../../../../benchmark/Experiments';
|
2016-12-27 16:09:47 +01:00
|
|
|
|
2021-05-30 15:09:47 +02:00
|
|
|
const LOG_TAG = '[SQLConnection]';
|
2016-12-27 16:09:47 +01:00
|
|
|
|
2017-07-20 23:37:10 +02:00
|
|
|
export class SQLConnection {
|
2016-12-27 16:09:47 +01:00
|
|
|
|
|
|
|
|
2019-01-27 14:36:42 -05:00
|
|
|
private static connection: Connection = null;
|
|
|
|
|
2018-01-20 20:36:38 -05:00
|
|
|
constructor() {
|
2017-07-03 19:17:49 +02:00
|
|
|
}
|
2016-12-27 16:09:47 +01:00
|
|
|
|
2017-07-03 19:17:49 +02:00
|
|
|
public static async getConnection(): Promise<Connection> {
|
2022-02-22 14:06:52 +01:00
|
|
|
if (ActiveExperiments[Experiments.db.name] === Experiments.db.groups.sqlite3) {
|
|
|
|
Config.Server.Database.type = DatabaseType.sqlite;
|
|
|
|
}
|
|
|
|
if (ActiveExperiments[Experiments.db.name] === Experiments.db.groups.betterSqlite) {
|
|
|
|
Config.Server.Database.type = DatabaseType.better_sqlite3;
|
|
|
|
}
|
2017-07-03 19:17:49 +02:00
|
|
|
if (this.connection == null) {
|
2019-12-09 14:05:06 +01:00
|
|
|
const options: any = this.getDriver(Config.Server.Database);
|
2018-12-22 11:49:56 +01:00
|
|
|
// options.name = 'main';
|
2017-10-19 12:08:07 -04:00
|
|
|
options.entities = [
|
|
|
|
UserEntity,
|
2018-11-26 00:26:29 +01:00
|
|
|
FileEntity,
|
2019-01-12 16:41:45 +01:00
|
|
|
FaceRegionEntry,
|
|
|
|
PersonEntry,
|
2018-11-17 19:32:31 +01:00
|
|
|
MediaEntity,
|
2017-10-19 12:08:07 -04:00
|
|
|
PhotoEntity,
|
2018-11-17 19:32:31 +01:00
|
|
|
VideoEntity,
|
2017-12-17 21:34:07 -05:00
|
|
|
DirectoryEntity,
|
2018-01-20 20:36:38 -05:00
|
|
|
SharingEntity,
|
2021-05-28 19:21:18 +02:00
|
|
|
AlbumBaseEntity,
|
|
|
|
SavedSearchEntity,
|
2018-01-20 20:36:38 -05:00
|
|
|
VersionEntity
|
2017-10-19 12:08:07 -04:00
|
|
|
];
|
2018-01-20 20:36:38 -05:00
|
|
|
options.synchronize = false;
|
2021-04-18 15:48:35 +02:00
|
|
|
if (Config.Server.Log.sqlLevel !== SQLLogLevel.none) {
|
|
|
|
options.logging = SQLLogLevel[Config.Server.Log.sqlLevel];
|
2019-02-07 10:44:51 -05:00
|
|
|
}
|
2021-05-30 15:09:47 +02:00
|
|
|
Logger.debug(LOG_TAG, 'Creating connection: ' + DatabaseType[Config.Server.Database.type]);
|
2019-01-27 14:36:42 -05:00
|
|
|
this.connection = await this.createConnection(options);
|
2018-01-30 20:01:16 -05:00
|
|
|
await SQLConnection.schemeSync(this.connection);
|
2016-12-27 16:09:47 +01:00
|
|
|
}
|
2017-07-03 19:17:49 +02:00
|
|
|
return this.connection;
|
|
|
|
}
|
2016-12-27 16:09:47 +01:00
|
|
|
|
2021-04-18 15:48:35 +02:00
|
|
|
public static async tryConnection(config: ServerDataBaseConfig): Promise<boolean> {
|
2017-07-12 18:31:19 +02:00
|
|
|
try {
|
2018-03-30 15:30:30 -04:00
|
|
|
await getConnection('test').close();
|
2017-07-12 18:31:19 +02:00
|
|
|
} catch (err) {
|
|
|
|
}
|
2017-12-17 21:34:07 -05:00
|
|
|
const options: any = this.getDriver(config);
|
2018-03-30 15:30:30 -04:00
|
|
|
options.name = 'test';
|
2017-12-17 21:34:07 -05:00
|
|
|
options.entities = [
|
|
|
|
UserEntity,
|
2018-11-26 00:26:29 +01:00
|
|
|
FileEntity,
|
2019-01-12 16:41:45 +01:00
|
|
|
FaceRegionEntry,
|
|
|
|
PersonEntry,
|
2018-11-17 19:32:31 +01:00
|
|
|
MediaEntity,
|
2017-12-17 21:34:07 -05:00
|
|
|
PhotoEntity,
|
2018-11-17 19:32:31 +01:00
|
|
|
VideoEntity,
|
2017-12-17 21:34:07 -05:00
|
|
|
DirectoryEntity,
|
2018-01-20 20:36:38 -05:00
|
|
|
SharingEntity,
|
2021-05-28 19:21:18 +02:00
|
|
|
AlbumBaseEntity,
|
|
|
|
SavedSearchEntity,
|
2018-01-20 20:36:38 -05:00
|
|
|
VersionEntity
|
2017-12-17 21:34:07 -05:00
|
|
|
];
|
2018-01-20 20:36:38 -05:00
|
|
|
options.synchronize = false;
|
2021-04-18 15:48:35 +02:00
|
|
|
if (Config.Server.Log.sqlLevel !== SQLLogLevel.none) {
|
|
|
|
options.logging = SQLLogLevel[Config.Server.Log.sqlLevel];
|
2019-02-07 10:44:51 -05:00
|
|
|
}
|
2019-01-27 14:36:42 -05:00
|
|
|
const conn = await this.createConnection(options);
|
2018-01-30 20:01:16 -05:00
|
|
|
await SQLConnection.schemeSync(conn);
|
2017-07-20 23:37:10 +02:00
|
|
|
await conn.close();
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2018-03-30 15:30:30 -04:00
|
|
|
public static async init(): Promise<void> {
|
|
|
|
const connection = await this.getConnection();
|
2021-01-04 10:32:19 +01:00
|
|
|
|
2022-01-13 23:55:29 +01:00
|
|
|
// Adding enforced users to the db
|
2018-05-12 12:19:51 -04:00
|
|
|
const userRepository = connection.getRepository(UserEntity);
|
2022-01-15 14:39:30 +01:00
|
|
|
if (Array.isArray(Config.Server.Database.enforcedUsers) &&
|
2022-01-14 11:02:17 +01:00
|
|
|
Config.Server.Database.enforcedUsers.length > 0) {
|
|
|
|
for (const uc of Config.Server.Database.enforcedUsers) {
|
|
|
|
const user = await userRepository.findOne({name: uc.name});
|
|
|
|
if (!user) {
|
|
|
|
Logger.info(LOG_TAG, 'Saving enforced user: ' + uc.name);
|
|
|
|
const a = new UserEntity();
|
|
|
|
a.name = uc.name;
|
|
|
|
// encrypt password and save back to the db
|
|
|
|
if (!uc.encryptedPassword) {
|
|
|
|
uc.encryptedPassword = PasswordHelper.cryptPassword(uc.password);
|
|
|
|
uc.password = '';
|
|
|
|
await Config.save();
|
|
|
|
}
|
|
|
|
a.password = uc.encryptedPassword;
|
|
|
|
a.role = uc.role;
|
|
|
|
await userRepository.save(a);
|
2022-01-13 23:55:29 +01:00
|
|
|
}
|
2021-12-31 14:38:01 +01:00
|
|
|
}
|
|
|
|
}
|
2022-01-20 19:45:25 +01:00
|
|
|
|
|
|
|
// Add dummy Admin to the db
|
|
|
|
const admins = await userRepository.find({role: UserRoles.Admin});
|
|
|
|
if (admins.length === 0) {
|
|
|
|
const a = new UserEntity();
|
|
|
|
a.name = 'admin';
|
|
|
|
a.password = PasswordHelper.cryptPassword('admin');
|
|
|
|
a.role = UserRoles.Admin;
|
|
|
|
await userRepository.save(a);
|
|
|
|
}
|
|
|
|
|
2022-01-13 23:55:29 +01:00
|
|
|
const defAdmin = await userRepository.findOne({name: 'admin', role: UserRoles.Admin});
|
2022-01-14 11:02:17 +01:00
|
|
|
if (defAdmin && PasswordHelper.comparePassword('admin', defAdmin.password)) {
|
2022-01-13 23:55:29 +01:00
|
|
|
NotificationManager.error('Using default admin user!', 'You are using the default admin/admin user/password, please change or remove it.');
|
|
|
|
}
|
2018-03-30 15:30:30 -04:00
|
|
|
|
|
|
|
}
|
|
|
|
|
2021-04-18 15:48:35 +02:00
|
|
|
public static async close(): Promise<void> {
|
2019-01-27 14:36:42 -05:00
|
|
|
try {
|
|
|
|
if (this.connection != null) {
|
|
|
|
await this.connection.close();
|
|
|
|
this.connection = null;
|
|
|
|
}
|
|
|
|
} catch (err) {
|
2020-12-30 21:13:19 +01:00
|
|
|
console.error('Error during closing sql db:');
|
2019-01-27 14:36:42 -05:00
|
|
|
console.error(err);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-04-18 15:48:35 +02:00
|
|
|
public static getSQLiteDB(config: ServerDataBaseConfig): any {
|
2020-01-28 18:36:52 +01:00
|
|
|
return path.join(ProjectPath.getAbsolutePath(config.dbFolder), 'sqlite.db');
|
|
|
|
}
|
|
|
|
|
2021-04-18 15:48:35 +02:00
|
|
|
private static async createConnection(options: ConnectionOptions): Promise<Connection> {
|
2019-01-27 14:36:42 -05:00
|
|
|
if (options.type === 'sqlite') {
|
|
|
|
return await createConnection(options);
|
|
|
|
}
|
|
|
|
try {
|
|
|
|
return await createConnection(options);
|
|
|
|
} catch (e) {
|
|
|
|
if (e.sqlMessage === 'Unknown database \'' + options.database + '\'') {
|
2021-05-30 15:09:47 +02:00
|
|
|
Logger.debug(LOG_TAG, 'creating database: ' + options.database);
|
2019-01-27 14:36:42 -05:00
|
|
|
const tmpOption = Utils.clone(options);
|
|
|
|
// @ts-ignore
|
|
|
|
delete tmpOption.database;
|
|
|
|
const tmpConn = await createConnection(tmpOption);
|
|
|
|
await tmpConn.query('CREATE DATABASE IF NOT EXISTS ' + options.database);
|
|
|
|
await tmpConn.close();
|
|
|
|
return await createConnection(options);
|
|
|
|
}
|
|
|
|
throw e;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-04-18 15:48:35 +02:00
|
|
|
private static async schemeSync(connection: Connection): Promise<void> {
|
2018-01-20 20:36:38 -05:00
|
|
|
let version = null;
|
|
|
|
try {
|
|
|
|
version = await connection.getRepository(VersionEntity).findOne();
|
|
|
|
} catch (ex) {
|
|
|
|
}
|
2018-11-18 22:56:05 +01:00
|
|
|
if (version && version.version === DataStructureVersion) {
|
2018-01-20 20:36:38 -05:00
|
|
|
return;
|
|
|
|
}
|
2021-05-30 15:09:47 +02:00
|
|
|
Logger.info(LOG_TAG, 'Updating database scheme');
|
2018-01-20 20:36:38 -05:00
|
|
|
if (!version) {
|
|
|
|
version = new VersionEntity();
|
|
|
|
}
|
2018-11-18 22:56:05 +01:00
|
|
|
version.version = DataStructureVersion;
|
2018-01-20 20:36:38 -05:00
|
|
|
|
2018-12-23 16:50:20 +01:00
|
|
|
let users: UserEntity[] = [];
|
|
|
|
try {
|
|
|
|
users = await connection.getRepository(UserEntity).createQueryBuilder('user').getMany();
|
|
|
|
} catch (ex) {
|
|
|
|
}
|
2018-01-20 20:36:38 -05:00
|
|
|
await connection.dropDatabase();
|
|
|
|
await connection.synchronize();
|
|
|
|
await connection.getRepository(VersionEntity).save(version);
|
2018-12-22 11:49:56 +01:00
|
|
|
try {
|
|
|
|
await connection.getRepository(UserEntity).save(users);
|
|
|
|
} catch (e) {
|
|
|
|
await connection.dropDatabase();
|
|
|
|
await connection.synchronize();
|
|
|
|
await connection.getRepository(VersionEntity).save(version);
|
2021-05-30 15:09:47 +02:00
|
|
|
Logger.warn(LOG_TAG, 'Could not move users to the new db scheme, deleting them. Details:' + e.toString());
|
2018-12-22 11:49:56 +01:00
|
|
|
}
|
2018-01-20 20:36:38 -05:00
|
|
|
}
|
|
|
|
|
2021-04-18 15:48:35 +02:00
|
|
|
private static getDriver(config: ServerDataBaseConfig): ConnectionOptions {
|
2017-10-19 12:08:07 -04:00
|
|
|
let driver: ConnectionOptions = null;
|
2021-04-18 15:48:35 +02:00
|
|
|
if (config.type === DatabaseType.mysql) {
|
2017-07-20 23:37:10 +02:00
|
|
|
driver = {
|
2018-03-30 15:30:30 -04:00
|
|
|
type: 'mysql',
|
2017-07-08 12:43:42 +02:00
|
|
|
host: config.mysql.host,
|
2020-01-29 16:15:00 +01:00
|
|
|
port: config.mysql.port,
|
2017-07-08 12:43:42 +02:00
|
|
|
username: config.mysql.username,
|
|
|
|
password: config.mysql.password,
|
2019-02-07 10:21:23 -05:00
|
|
|
database: config.mysql.database,
|
2022-01-14 12:14:28 +01:00
|
|
|
charset: 'utf8mb4'
|
2017-07-20 23:37:10 +02:00
|
|
|
};
|
2021-04-18 15:48:35 +02:00
|
|
|
} else if (config.type === DatabaseType.sqlite) {
|
2017-07-20 23:37:10 +02:00
|
|
|
driver = {
|
2018-03-30 15:30:30 -04:00
|
|
|
type: 'sqlite',
|
2020-12-28 22:08:57 +01:00
|
|
|
database: path.join(ProjectPath.getAbsolutePath(config.dbFolder), config.sqlite.DBFileName)
|
2017-07-20 23:37:10 +02:00
|
|
|
};
|
2022-02-22 14:06:52 +01:00
|
|
|
} else if (config.type === DatabaseType.better_sqlite3) {
|
|
|
|
driver = {
|
|
|
|
type: 'better-sqlite3',
|
|
|
|
database: path.join(ProjectPath.getAbsolutePath(config.dbFolder), 'better_', config.sqlite.DBFileName)
|
|
|
|
};
|
2017-07-20 23:37:10 +02:00
|
|
|
}
|
|
|
|
return driver;
|
2017-07-08 12:43:42 +02:00
|
|
|
}
|
2016-12-27 16:09:47 +01:00
|
|
|
|
2017-07-03 19:17:49 +02:00
|
|
|
}
|