mirror of
https://github.com/xuthus83/pigallery2.git
synced 2025-01-14 14:43:17 +08:00
implementing database settings
This commit is contained in:
parent
a9b06912c6
commit
8b090603b6
63
backend/middlewares/AdminMWs.ts
Normal file
63
backend/middlewares/AdminMWs.ts
Normal file
@ -0,0 +1,63 @@
|
||||
import {NextFunction, Request, Response} from "express";
|
||||
import {Error, ErrorCodes} from "../../common/entities/Error";
|
||||
import {ObjectManagerRepository} from "../model/ObjectManagerRepository";
|
||||
import {Logger} from "../Logger";
|
||||
import {MySQLConnection} from "../model/mysql/MySQLConnection";
|
||||
import {DataBaseConfig, DatabaseType} from "../../common/config/private/IPrivateConfig";
|
||||
import {Config} from "../../common/config/private/Config";
|
||||
|
||||
|
||||
const LOG_TAG = "[AdminMWs]";
|
||||
export class AdminMWs {
|
||||
|
||||
|
||||
public static async updateDatabaseSettings(req: Request, res: Response, next: NextFunction) {
|
||||
|
||||
if ((typeof req.body === 'undefined') || (typeof req.body.databaseSettings === 'undefined')) {
|
||||
return next(new Error(ErrorCodes.INPUT_ERROR, "databaseSettings is needed"));
|
||||
}
|
||||
|
||||
const databaseSettings = <DataBaseConfig>req.body.databaseSettings;
|
||||
|
||||
try {
|
||||
if (Config.Server.database.type == DatabaseType.mysql) {
|
||||
await MySQLConnection.tryConnection(databaseSettings);
|
||||
}
|
||||
Config.Server.database = databaseSettings;
|
||||
Config.save();
|
||||
Logger.info(LOG_TAG, "new config:");
|
||||
Logger.info(LOG_TAG, JSON.stringify(Config, null, '\t'));
|
||||
|
||||
ObjectManagerRepository.reset();
|
||||
if (Config.Server.database.type == DatabaseType.mysql) {
|
||||
await ObjectManagerRepository.InitMySQLManagers();
|
||||
} else {
|
||||
await ObjectManagerRepository.InitMemoryManagers();
|
||||
}
|
||||
|
||||
return next();
|
||||
} catch (err) {
|
||||
Logger.warn(LOG_TAG, "Error saving database settings", err);
|
||||
return next(new Error(ErrorCodes.SETTINGS_ERROR, err));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static async testDatabaseSettings(req: Request, res: Response, next: NextFunction) {
|
||||
if ((typeof req.body === 'undefined') || (typeof req.body.databaseSettings === 'undefined')) {
|
||||
return next(new Error(ErrorCodes.INPUT_ERROR, "databaseSettings is needed"));
|
||||
}
|
||||
|
||||
const databaseSettings = <DataBaseConfig>req.body.databaseSettings;
|
||||
|
||||
try {
|
||||
if (Config.Server.database.type == DatabaseType.mysql) {
|
||||
await MySQLConnection.tryConnection(databaseSettings);
|
||||
}
|
||||
return next();
|
||||
} catch (err) {
|
||||
Logger.warn(LOG_TAG, "Error saving database settings", err);
|
||||
return next(new Error(ErrorCodes.SETTINGS_ERROR, err));
|
||||
}
|
||||
}
|
||||
}
|
@ -3,6 +3,8 @@ import {Error, ErrorCodes} from "../../common/entities/Error";
|
||||
import {Utils} from "../../common/Utils";
|
||||
import {Message} from "../../common/entities/Message";
|
||||
import {SharingDTO} from "../../common/entities/SharingDTO";
|
||||
import {Config} from "../../common/config/private/Config";
|
||||
import {PrivateConfigClass} from "../../common/config/private/PrivateConfigClass";
|
||||
|
||||
export class RenderingMWs {
|
||||
|
||||
@ -45,6 +47,13 @@ export class RenderingMWs {
|
||||
res.json(message);
|
||||
}
|
||||
|
||||
|
||||
public static renderConfig(req: Request, res: Response, next: NextFunction) {
|
||||
let message = new Message<PrivateConfigClass>(null, Config);
|
||||
res.json(message);
|
||||
}
|
||||
|
||||
|
||||
public static renderError(err: any, req: Request, res: Response, next: NextFunction): any {
|
||||
if (err instanceof Error) {
|
||||
let message = new Message<any>(err, null);
|
||||
|
@ -96,8 +96,8 @@ export class UserMWs {
|
||||
for (let i = 0; i < result.length; i++) {
|
||||
result[i].password = "";
|
||||
}
|
||||
|
||||
req.resultPipe = result;
|
||||
next();
|
||||
} catch (err) {
|
||||
return next(new Error(ErrorCodes.GENERAL_ERROR));
|
||||
}
|
||||
|
@ -6,6 +6,7 @@ import {PhotoEntity, PhotoMetadataEntity} from "./enitites/PhotoEntity";
|
||||
import {DirectoryEntity} from "./enitites/DirectoryEntity";
|
||||
import {Config} from "../../../common/config/private/Config";
|
||||
import {SharingEntity} from "./enitites/SharingEntity";
|
||||
import {DataBaseConfig} from "../../../common/config/private/IPrivateConfig";
|
||||
|
||||
|
||||
export class MySQLConnection {
|
||||
@ -21,6 +22,7 @@ export class MySQLConnection {
|
||||
|
||||
if (this.connection == null) {
|
||||
this.connection = await createConnection({
|
||||
name: "main",
|
||||
driver: {
|
||||
type: "mysql",
|
||||
host: Config.Server.database.mysql.host,
|
||||
@ -49,23 +51,48 @@ export class MySQLConnection {
|
||||
|
||||
}
|
||||
|
||||
public static init(): Promise<void> {
|
||||
return new Promise<void>((resolve, reject) => {
|
||||
this.getConnection().then(async connection => {
|
||||
|
||||
let userRepository = connection.getRepository(UserEntity);
|
||||
let admins = await userRepository.find({role: UserRoles.Admin});
|
||||
if (admins.length == 0) {
|
||||
let a = new UserEntity();
|
||||
a.name = "admin";
|
||||
a.password = "admin";
|
||||
a.role = UserRoles.Admin;
|
||||
await userRepository.persist(a);
|
||||
}
|
||||
|
||||
resolve();
|
||||
}).catch(err => reject(err));
|
||||
public static async tryConnection(config: DataBaseConfig) {
|
||||
const conn = await createConnection({
|
||||
name: "test",
|
||||
driver: {
|
||||
type: "mysql",
|
||||
host: config.mysql.host,
|
||||
port: 3306,
|
||||
username: config.mysql.username,
|
||||
password: config.mysql.password,
|
||||
database: config.mysql.database
|
||||
},
|
||||
entities: [
|
||||
UserEntity,
|
||||
DirectoryEntity,
|
||||
PhotoMetadataEntity,
|
||||
PhotoEntity,
|
||||
SharingEntity
|
||||
],
|
||||
autoSchemaSync: true,
|
||||
logging: {
|
||||
logQueries: true,
|
||||
logOnlyFailedQueries: true,
|
||||
logFailedQueryError: true,
|
||||
logSchemaCreation: true
|
||||
}
|
||||
});
|
||||
await conn.close();
|
||||
return true;
|
||||
}
|
||||
|
||||
public static async init(): Promise<void> {
|
||||
const connection = await this.getConnection();
|
||||
let userRepository = connection.getRepository(UserEntity);
|
||||
let admins = await userRepository.find({role: UserRoles.Admin});
|
||||
if (admins.length == 0) {
|
||||
let a = new UserEntity();
|
||||
a.name = "admin";
|
||||
a.password = "admin";
|
||||
a.role = UserRoles.Admin;
|
||||
await userRepository.persist(a);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
@ -1,11 +1,14 @@
|
||||
import {AuthenticationMWs} from "../middlewares/user/AuthenticationMWs";
|
||||
import {UserRoles} from "../../common/entities/UserDTO";
|
||||
import {RenderingMWs} from "../middlewares/RenderingMWs";
|
||||
import {AdminMWs} from "../middlewares/AdminMWs";
|
||||
|
||||
export class AdminRouter {
|
||||
public static route(app: any) {
|
||||
|
||||
this.addResetDB(app);
|
||||
this.addIndexGallery(app);
|
||||
this.addSettings(app);
|
||||
}
|
||||
|
||||
private static addResetDB(app) {
|
||||
@ -24,5 +27,28 @@ export class AdminRouter {
|
||||
);
|
||||
};
|
||||
|
||||
private static addSettings(app) {
|
||||
app.get("/api/settings",
|
||||
AuthenticationMWs.authenticate,
|
||||
AuthenticationMWs.authorise(UserRoles.Admin),
|
||||
RenderingMWs.renderConfig
|
||||
);
|
||||
|
||||
|
||||
app.put("/api/settings/database",
|
||||
AuthenticationMWs.authenticate,
|
||||
AuthenticationMWs.authorise(UserRoles.Admin),
|
||||
AdminMWs.updateDatabaseSettings,
|
||||
RenderingMWs.renderOK
|
||||
);
|
||||
|
||||
app.post("/api/settings/test/database",
|
||||
AuthenticationMWs.authenticate,
|
||||
AuthenticationMWs.authorise(UserRoles.Admin),
|
||||
AdminMWs.testDatabaseSettings,
|
||||
RenderingMWs.renderOK
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
|
@ -6,12 +6,16 @@ export class Utils {
|
||||
}
|
||||
|
||||
static equalsFilter(object: any, filter: any): boolean {
|
||||
|
||||
let keys = Object.keys(filter);
|
||||
const keys = Object.keys(filter);
|
||||
for (let i = 0; i < keys.length; i++) {
|
||||
let key = keys[i];
|
||||
if (object[key] !== filter[key]) {
|
||||
const key = keys[i];
|
||||
if (typeof filter[key] === "object") {
|
||||
if (Utils.equalsFilter(object[key], filter[key]) == false) {
|
||||
return false;
|
||||
}
|
||||
} else if (object[key] !== filter[key]) {
|
||||
return false;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@ -19,7 +23,8 @@ export class Utils {
|
||||
}
|
||||
|
||||
|
||||
static concatUrls(...args: Array<string>) {
|
||||
static
|
||||
concatUrls(...args: Array<string>) {
|
||||
let url = "";
|
||||
for (let i = 0; i < args.length; i++) {
|
||||
if (args[i] === "" || typeof args[i] === "undefined") continue;
|
||||
@ -34,7 +39,8 @@ export class Utils {
|
||||
return url.substring(0, url.length - 1);
|
||||
}
|
||||
|
||||
public static updateKeys(targetObject: any, sourceObject: any) {
|
||||
public static
|
||||
updateKeys(targetObject: any, sourceObject: any) {
|
||||
Object.keys(sourceObject).forEach((key) => {
|
||||
if (typeof targetObject[key] === "undefined") {
|
||||
return;
|
||||
@ -47,7 +53,8 @@ export class Utils {
|
||||
});
|
||||
}
|
||||
|
||||
public static setKeys(targetObject: any, sourceObject: any) {
|
||||
public static
|
||||
setKeys(targetObject: any, sourceObject: any) {
|
||||
Object.keys(sourceObject).forEach((key) => {
|
||||
if (typeof targetObject[key] === "object") {
|
||||
Utils.setKeys(targetObject[key], sourceObject[key]);
|
||||
@ -57,7 +64,8 @@ export class Utils {
|
||||
});
|
||||
}
|
||||
|
||||
public static setKeysForced(targetObject: any, sourceObject: any) {
|
||||
public static
|
||||
setKeysForced(targetObject: any, sourceObject: any) {
|
||||
Object.keys(sourceObject).forEach((key) => {
|
||||
if (typeof sourceObject[key] === "object") {
|
||||
if (typeof targetObject[key] === "undefined") {
|
||||
@ -70,7 +78,11 @@ export class Utils {
|
||||
});
|
||||
}
|
||||
|
||||
public static enumToArray(EnumType: any): Array<{ key: number; value: string; }> {
|
||||
public static
|
||||
enumToArray(EnumType: any): Array<{
|
||||
key: number;
|
||||
value: string;
|
||||
}> {
|
||||
let arr: Array<{ key: number; value: string; }> = [];
|
||||
for (let enumMember in EnumType) {
|
||||
if (!EnumType.hasOwnProperty(enumMember)) {
|
||||
@ -85,7 +97,8 @@ export class Utils {
|
||||
}
|
||||
|
||||
|
||||
public static findClosest(number: number, arr: Array<number>) {
|
||||
public static
|
||||
findClosest(number: number, arr: Array<number>) {
|
||||
|
||||
let curr = arr[0];
|
||||
let diff = Math.abs(number - curr);
|
||||
|
@ -1,11 +1,5 @@
|
||||
import * as path from "path";
|
||||
import {PrivateConfigClass} from "./PrivateConfigClass";
|
||||
import {ConfigLoader} from "typeconfig";
|
||||
|
||||
|
||||
export let Config = new PrivateConfigClass();
|
||||
|
||||
|
||||
ConfigLoader.loadBackendConfig(Config,
|
||||
path.join(__dirname, './../../../config.json'),
|
||||
[["PORT", "Server-port"]]);
|
||||
Config.load();
|
||||
|
@ -1,3 +1,4 @@
|
||||
import {ClientConfig} from "../public/ConfigClass";
|
||||
export enum DatabaseType{
|
||||
memory = 0, mysql = 1
|
||||
}
|
||||
@ -37,3 +38,7 @@ export interface ServerConfig {
|
||||
enableThreading: boolean;
|
||||
sharing: SharingConfig;
|
||||
}
|
||||
export interface IPrivateConfig {
|
||||
Server: ServerConfig;
|
||||
Client: ClientConfig;
|
||||
}
|
||||
|
@ -1,11 +1,12 @@
|
||||
import {PublicConfigClass} from "../public/ConfigClass";
|
||||
import {DatabaseType, ServerConfig, ThumbnailProcessingLib} from "./IPrivateConfig";
|
||||
|
||||
import {DatabaseType, IPrivateConfig, ServerConfig, ThumbnailProcessingLib} from "./IPrivateConfig";
|
||||
import * as path from "path";
|
||||
import {ConfigLoader} from "typeconfig";
|
||||
|
||||
/**
|
||||
* This configuration will be only at backend
|
||||
*/
|
||||
export class PrivateConfigClass extends PublicConfigClass {
|
||||
export class PrivateConfigClass extends PublicConfigClass implements IPrivateConfig {
|
||||
|
||||
public Server: ServerConfig = {
|
||||
port: 80,
|
||||
@ -30,6 +31,7 @@ export class PrivateConfigClass extends PublicConfigClass {
|
||||
},
|
||||
enableThreading: true
|
||||
};
|
||||
private ConfigLoader: any;
|
||||
|
||||
public setDatabaseType(type: DatabaseType) {
|
||||
this.Server.database.type = type;
|
||||
@ -40,5 +42,15 @@ export class PrivateConfigClass extends PublicConfigClass {
|
||||
}
|
||||
}
|
||||
|
||||
public load() {
|
||||
ConfigLoader.loadBackendConfig(this,
|
||||
path.join(__dirname, './../../../config.json'),
|
||||
[["PORT", "Server-port"]]);
|
||||
|
||||
}
|
||||
|
||||
public save() {
|
||||
ConfigLoader.saveConfigFile(path.join(__dirname, './../../../config.json'), this);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -9,7 +9,7 @@ interface SharingConfig {
|
||||
passwordProtected: boolean;
|
||||
}
|
||||
|
||||
interface ClientConfig {
|
||||
export interface ClientConfig {
|
||||
applicationTitle: string;
|
||||
iconSize: number;
|
||||
thumbnailSizes: Array<number>;
|
||||
|
@ -15,8 +15,9 @@ export enum ErrorCodes{
|
||||
|
||||
USER_MANAGEMENT_DISABLED = 9,
|
||||
|
||||
INPUT_ERROR = 10
|
||||
INPUT_ERROR = 10,
|
||||
|
||||
SETTINGS_ERROR = 11
|
||||
}
|
||||
|
||||
export class Error {
|
||||
|
@ -1,5 +1,6 @@
|
||||
<app-frame>
|
||||
<div body class="container">
|
||||
<settings-usermanager *ngIf="userManagementEnable"></settings-usermanager>
|
||||
<settings-usermanager *ngIf="userManagementEnable"></settings-usermanager>
|
||||
<settings-database></settings-database>
|
||||
</div>
|
||||
</app-frame>
|
||||
|
@ -16,7 +16,8 @@ export class AdminComponent implements OnInit {
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
if (!this._authService.isAuthenticated() || this._authService.user.value.role < UserRoles.Admin) {
|
||||
if (!this._authService.isAuthenticated()
|
||||
|| this._authService.user.value.role < UserRoles.Admin) {
|
||||
this._router.navigate(['login']);
|
||||
return;
|
||||
}
|
||||
|
@ -1,9 +1,10 @@
|
||||
import {Component, OnInit} from "@angular/core";
|
||||
import {Component, OnInit, ViewContainerRef} from "@angular/core";
|
||||
import {AuthenticationService} from "./model/network/authentication.service";
|
||||
import {UserDTO} from "../../common/entities/UserDTO";
|
||||
import {Router} from "@angular/router";
|
||||
import {Config} from "../../common/config/public/Config";
|
||||
import {Title} from "@angular/platform-browser";
|
||||
import {NotificationService} from "./model/notification.service";
|
||||
|
||||
|
||||
@Component({
|
||||
@ -13,7 +14,11 @@ import {Title} from "@angular/platform-browser";
|
||||
})
|
||||
export class AppComponent implements OnInit {
|
||||
|
||||
constructor(private _router: Router, private _authenticationService: AuthenticationService, private _title: Title) {
|
||||
constructor(private _router: Router,
|
||||
private _authenticationService: AuthenticationService,
|
||||
private _title: Title, vcr: ViewContainerRef,
|
||||
notificatin: NotificationService) {
|
||||
notificatin.setRootViewContainerRef(vcr);
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
|
@ -36,7 +36,11 @@ import {SlimLoadingBarModule} from "ng2-slim-loading-bar";
|
||||
import {GalleryShareComponent} from "./gallery/share/share.gallery.component";
|
||||
import {ShareLoginComponent} from "./sharelogin/share-login.component";
|
||||
import {ShareService} from "./gallery/share.service";
|
||||
import {TypeaheadModule} from "ngx-bootstrap";
|
||||
import {ModalModule} from "ngx-bootstrap/modal";
|
||||
import {DatabaseSettingsComponent} from "./settings/database/database.settings.component";
|
||||
import {ToastModule} from "ng2-toastr/ng2-toastr";
|
||||
import {BrowserAnimationsModule} from "@angular/platform-browser/animations";
|
||||
import {NotificationService} from "./model/notification.service";
|
||||
|
||||
@Injectable()
|
||||
export class GoogleMapsConfig {
|
||||
@ -52,18 +56,19 @@ export class GoogleMapsConfig {
|
||||
BrowserModule,
|
||||
FormsModule,
|
||||
HttpModule,
|
||||
BrowserAnimationsModule,
|
||||
appRoutes,
|
||||
TypeaheadModule.forRoot(),
|
||||
ToastModule.forRoot(),
|
||||
ModalModule.forRoot(),
|
||||
AgmCoreModule.forRoot(),
|
||||
SlimLoadingBarModule.forRoot()
|
||||
],
|
||||
declarations: [AppComponent,
|
||||
LoginComponent,
|
||||
ShareLoginComponent,
|
||||
AdminComponent,
|
||||
GalleryComponent,
|
||||
FrameComponent,
|
||||
UserMangerSettingsComponent,
|
||||
//Gallery
|
||||
GalleryLightboxPhotoComponent,
|
||||
GalleryPhotoLoadingComponent,
|
||||
GalleryGridComponent,
|
||||
@ -76,7 +81,10 @@ export class GoogleMapsConfig {
|
||||
GalleryShareComponent,
|
||||
GalleryNavigatorComponent,
|
||||
GalleryPhotoComponent,
|
||||
FrameComponent,
|
||||
AdminComponent,
|
||||
//Settings
|
||||
UserMangerSettingsComponent,
|
||||
DatabaseSettingsComponent,
|
||||
StringifyRole],
|
||||
providers: [
|
||||
{provide: LAZY_MAPS_API_CONFIG, useClass: GoogleMapsConfig},
|
||||
@ -88,6 +96,7 @@ export class GoogleMapsConfig {
|
||||
AuthenticationService,
|
||||
ThumbnailLoaderService,
|
||||
ThumbnailManagerService,
|
||||
NotificationService,
|
||||
FullScreenService,
|
||||
OverlayService],
|
||||
|
||||
|
40
frontend/app/model/notification.service.ts
Normal file
40
frontend/app/model/notification.service.ts
Normal file
@ -0,0 +1,40 @@
|
||||
import {Injectable, ViewContainerRef} from "@angular/core";
|
||||
import {ToastsManager} from "ng2-toastr/ng2-toastr";
|
||||
|
||||
@Injectable()
|
||||
export class NotificationService {
|
||||
|
||||
options = {
|
||||
positionClass: "toast-top-center",
|
||||
animate: "flyLeft"
|
||||
};
|
||||
|
||||
constructor(private _toastr: ToastsManager) {
|
||||
|
||||
}
|
||||
|
||||
setRootViewContainerRef(vcr: ViewContainerRef) {
|
||||
this._toastr.setRootViewContainerRef(vcr);
|
||||
}
|
||||
|
||||
success(text, title = null) {
|
||||
this._toastr.success(text, title, this.options);
|
||||
}
|
||||
|
||||
error(text, title?) {
|
||||
this._toastr.error(text, title, this.options);
|
||||
}
|
||||
|
||||
warning(text, title?) {
|
||||
this._toastr.warning(text, title, this.options);
|
||||
}
|
||||
|
||||
info(text, title = null) {
|
||||
this._toastr.info(text, title, this.options);
|
||||
}
|
||||
|
||||
|
||||
get Toastr(): ToastsManager {
|
||||
return this._toastr;
|
||||
}
|
||||
}
|
@ -1,27 +0,0 @@
|
||||
import {Injectable} from "@angular/core";
|
||||
|
||||
@Injectable()
|
||||
export class NotificationService {
|
||||
|
||||
|
||||
constructor() {
|
||||
|
||||
}
|
||||
|
||||
public showException(message: string) {
|
||||
|
||||
}
|
||||
|
||||
public showError(message: string) {
|
||||
|
||||
}
|
||||
|
||||
public showWarn(message: string) {
|
||||
|
||||
}
|
||||
|
||||
public showInfo(message: string) {
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
.title {
|
||||
margin-left: -5px;
|
||||
}
|
||||
|
||||
.btn {
|
||||
margin-left: 10px;
|
||||
}
|
||||
|
||||
.form-control {
|
||||
margin: 5px 0;
|
||||
}
|
@ -0,0 +1,40 @@
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
<h3 class="panel-title">Database settings</h3>
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
<div [hidden]="!error" class="alert alert-danger" role="alert"><strong>Error: </strong>{{error}}</div>
|
||||
<form #settingsForm="ngForm">
|
||||
<p class="title">Type:</p>
|
||||
<select class="form-control" [(ngModel)]="settings.type" name="type" required>
|
||||
<option *ngFor="let type of types" [value]="type.key">{{type.value}}
|
||||
</option>
|
||||
</select>
|
||||
<ng-container *ngIf="settings.type == DatabaseType.mysql">
|
||||
<p class="title">MySQL settings:</p>
|
||||
<input type="text" class="form-control" placeholder="Host" autofocus
|
||||
[(ngModel)]="settings.mysql.host" name="host" required>
|
||||
<input type="text" class="form-control" placeholder="Database" autofocus
|
||||
[(ngModel)]="settings.mysql.database" name="database" required>
|
||||
<input type="text" class="form-control" placeholder="Username"
|
||||
[(ngModel)]="settings.mysql.username" name="username">
|
||||
<input type="password" class="form-control" placeholder="Password"
|
||||
[(ngModel)]="settings.mysql.password" name="password">
|
||||
</ng-container>
|
||||
|
||||
</form>
|
||||
<button class="btn btn-primary pull-right"
|
||||
*ngIf="tested==false"
|
||||
[disabled]="!settingsForm.form.valid || !changed"
|
||||
(click)="test()">Test
|
||||
</button>
|
||||
<button class="btn btn-success pull-right"
|
||||
*ngIf="tested==true"
|
||||
[disabled]="!settingsForm.form.valid || !changed"
|
||||
(click)="save()">Save
|
||||
</button>
|
||||
<button class="btn btn-default pull-right"
|
||||
(click)="reset()">Reset
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
@ -0,0 +1,90 @@
|
||||
import {Component, OnInit, ViewChild} from "@angular/core";
|
||||
import {AuthenticationService} from "../../model/network/authentication.service";
|
||||
import {Router} from "@angular/router";
|
||||
import {UserRoles} from "../../../../common/entities/UserDTO";
|
||||
import {DatabaseSettingsService} from "./database.settings.service";
|
||||
import {DataBaseConfig, DatabaseType} from "../../../../common/config/private/IPrivateConfig";
|
||||
import {Utils} from "../../../../common/Utils";
|
||||
import {Error} from "../../../../common/entities/Error";
|
||||
import {NotificationService} from "../../model/notification.service";
|
||||
|
||||
@Component({
|
||||
selector: 'settings-database',
|
||||
templateUrl: './database.settings.component.html',
|
||||
styleUrls: ['./database.settings.component.css'],
|
||||
providers: [DatabaseSettingsService],
|
||||
})
|
||||
export class DatabaseSettingsComponent implements OnInit {
|
||||
@ViewChild('settingsForm') form;
|
||||
|
||||
public settings: DataBaseConfig = <DataBaseConfig> {
|
||||
type: DatabaseType.memory,
|
||||
mysql: {}
|
||||
};
|
||||
private original: DataBaseConfig;
|
||||
public types: Array<any> = [];
|
||||
public DatabaseType: any;
|
||||
public tested = false;
|
||||
public error: string = null;
|
||||
public changed: boolean = false;
|
||||
|
||||
constructor(private _authService: AuthenticationService,
|
||||
private _router: Router,
|
||||
private _dbSettings: DatabaseSettingsService,
|
||||
private notification: NotificationService) {
|
||||
this.original = Utils.clone(this.settings);
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
if (!this._authService.isAuthenticated() ||
|
||||
this._authService.user.value.role < UserRoles.Admin) {
|
||||
this._router.navigate(['login']);
|
||||
return;
|
||||
}
|
||||
this.types = Utils
|
||||
.enumToArray(DatabaseType);
|
||||
this.DatabaseType = DatabaseType;
|
||||
this.getSettings();
|
||||
|
||||
this.form.valueChanges.subscribe((data) => {
|
||||
this.changed = !Utils.equalsFilter(this.settings, this.original);
|
||||
|
||||
this.tested = false;
|
||||
});
|
||||
}
|
||||
|
||||
private async getSettings() {
|
||||
const s = await this._dbSettings.getSettings();
|
||||
this.original = Utils.clone(s);
|
||||
this.settings = s;
|
||||
this.tested = false;
|
||||
this.changed = false;
|
||||
}
|
||||
|
||||
public reset() {
|
||||
this.getSettings();
|
||||
}
|
||||
|
||||
public async test() {
|
||||
try {
|
||||
await this._dbSettings.testSettings(this.settings);
|
||||
this.tested = true;
|
||||
} catch (err) {
|
||||
if (err.message)
|
||||
this.error = (<Error>err).message;
|
||||
}
|
||||
}
|
||||
|
||||
public async save() {
|
||||
if (typeof this.settings.type == "undefined" || !this.tested) {
|
||||
return;
|
||||
}
|
||||
await this._dbSettings.updateSettings(this.settings);
|
||||
await this.getSettings();
|
||||
this.notification.success('Database settings saved', "Success");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
23
frontend/app/settings/database/database.settings.service.ts
Normal file
23
frontend/app/settings/database/database.settings.service.ts
Normal file
@ -0,0 +1,23 @@
|
||||
import {Injectable} from "@angular/core";
|
||||
import {NetworkService} from "../../model/network/network.service";
|
||||
import {DataBaseConfig, IPrivateConfig} from "../../../../common/config/private/IPrivateConfig";
|
||||
|
||||
@Injectable()
|
||||
export class DatabaseSettingsService {
|
||||
|
||||
|
||||
constructor(private _networkService: NetworkService) {
|
||||
}
|
||||
|
||||
public async getSettings(): Promise<DataBaseConfig> {
|
||||
return (await <Promise<IPrivateConfig>>this._networkService.getJson("/settings")).Server.database;
|
||||
}
|
||||
|
||||
public updateSettings(settings): Promise<void> {
|
||||
return this._networkService.putJson("/settings/database", {databaseSettings: settings});
|
||||
}
|
||||
|
||||
public testSettings(settings): Promise<void> {
|
||||
return this._networkService.postJson("/settings/test/database", {databaseSettings: settings});
|
||||
}
|
||||
}
|
@ -0,0 +1,3 @@
|
||||
.form-control {
|
||||
margin: 5px 0;
|
||||
}
|
@ -1,74 +1,76 @@
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
<h3 class="panel-title">User management</h3>
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
<div class="panel-heading">
|
||||
<h3 class="panel-title">User management</h3>
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
|
||||
<table class="table table-hover">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Name</th>
|
||||
<th>Role</th>
|
||||
<th></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tr *ngFor="let user of users">
|
||||
<td>{{user.name}}</td>
|
||||
<td *ngIf="canModifyUser(user)">
|
||||
<select class="form-control" [(ngModel)]="user.role" (change)="updateRole(user)" required>
|
||||
<option *ngFor="let repository of userRoles" [value]="repository.key">
|
||||
{{repository.value}}
|
||||
</option>
|
||||
</select>
|
||||
</td>
|
||||
<td *ngIf="!canModifyUser(user)">
|
||||
{{user.role | stringifyRole}}
|
||||
</td>
|
||||
<td>
|
||||
<button *ngIf="canModifyUser(user)" (click)="deleteUser(user)"
|
||||
class="btn btn-danger pull-right">
|
||||
<span class="glyphicon glyphicon-trash" aria-hidden="true" aria-label="Delete"></span>
|
||||
</button>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<table class="table table-hover">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Name</th>
|
||||
<th>Role</th>
|
||||
<th></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tr *ngFor="let user of users">
|
||||
<td>{{user.name}}</td>
|
||||
<td *ngIf="canModifyUser(user)">
|
||||
<select class="form-control" [(ngModel)]="user.role" (change)="updateRole(user)" required>
|
||||
<option *ngFor="let repository of userRoles" [value]="repository.key">
|
||||
{{repository.value}}
|
||||
</option>
|
||||
</select>
|
||||
</td>
|
||||
<td *ngIf="!canModifyUser(user)">
|
||||
{{user.role | stringifyRole}}
|
||||
</td>
|
||||
<td>
|
||||
<button [disabled]="!canModifyUser(user)" (click)="deleteUser(user)"
|
||||
[ngClass]="canModifyUser(user)? 'btn-danger':'btn-default'"
|
||||
class="btn pull-right">
|
||||
<span class="glyphicon glyphicon-trash" aria-hidden="true" aria-label="Delete"></span>
|
||||
</button>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<button class="btn btn-default pull-right" data-toggle="modal" data-target="#myModal"
|
||||
(click)="initNewUser()">+ Add
|
||||
user
|
||||
</button>
|
||||
</div>
|
||||
<button class="btn btn-primary pull-right"
|
||||
(click)="initNewUser()">+ Add
|
||||
user
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Modal -->
|
||||
<div class="modal fade" id="myModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel">
|
||||
<div class="modal-dialog" role="document">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span
|
||||
aria-hidden="true">×</span></button>
|
||||
<h4 class="modal-title" id="myModalLabel">Modal title</h4>
|
||||
</div>
|
||||
<div bsModal #userModal="bs-modal" class="modal fade" id="userModal" tabindex="-1" role="dialog"
|
||||
aria-labelledby="userModalLabel">
|
||||
<div class="modal-dialog" role="document">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<button type="button" class="close" (click)="userModal.hide()" aria-label="Close"><span
|
||||
aria-hidden="true">×</span></button>
|
||||
<h4 class="modal-title" id="userModalLabel">Add new User</h4>
|
||||
</div>
|
||||
|
||||
<form #NewUserForm="ngForm">
|
||||
<div class="modal-body">
|
||||
<input type="text" class="form-control" placeholder="Username" autofocus
|
||||
[(ngModel)]="newUser.name" name="name" required>
|
||||
<input type="password" class="form-control" placeholder="Password"
|
||||
[(ngModel)]="newUser.password" name="password" required>
|
||||
<select class="form-control" [(ngModel)]="newUser.role" name="role" required>
|
||||
<option *ngFor="let repository of userRoles" [value]="repository.key">{{repository.value}}
|
||||
</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
|
||||
<button type="button" class="btn btn-primary" data-dismiss="modal"
|
||||
(click)="addNewUser()"
|
||||
[disabled]="!NewUserForm.form.valid">Add User
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
<form #NewUserForm="ngForm">
|
||||
<div class="modal-body">
|
||||
<input type="text" class="form-control" placeholder="Username" autofocus
|
||||
[(ngModel)]="newUser.name" name="name" required>
|
||||
<input type="password" class="form-control" placeholder="Password"
|
||||
[(ngModel)]="newUser.password" name="password" required>
|
||||
<select class="form-control" [(ngModel)]="newUser.role" name="role" required>
|
||||
<option *ngFor="let repository of userRoles" [value]="repository.key">{{repository.value}}
|
||||
</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-default" (click)="userModal.hide()">Close</button>
|
||||
<button type="button" class="btn btn-primary" data-dismiss="modal"
|
||||
(click)="addNewUser()"
|
||||
[disabled]="!NewUserForm.form.valid">Add User
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -1,9 +1,10 @@
|
||||
import {Component, OnInit} from "@angular/core";
|
||||
import {Component, OnInit, ViewChild} from "@angular/core";
|
||||
import {AuthenticationService} from "../../model/network/authentication.service";
|
||||
import {Router} from "@angular/router";
|
||||
import {UserDTO, UserRoles} from "../../../../common/entities/UserDTO";
|
||||
import {Utils} from "../../../../common/Utils";
|
||||
import {UserManagerSettingsService} from "./usermanager.settings.service";
|
||||
import {ModalDirective} from "ngx-bootstrap/modal";
|
||||
|
||||
@Component({
|
||||
selector: 'settings-usermanager',
|
||||
@ -12,7 +13,7 @@ import {UserManagerSettingsService} from "./usermanager.settings.service";
|
||||
providers: [UserManagerSettingsService],
|
||||
})
|
||||
export class UserMangerSettingsComponent implements OnInit {
|
||||
|
||||
@ViewChild('userModal') public childModal: ModalDirective;
|
||||
public newUser = <UserDTO>{};
|
||||
public userRoles: Array<any> = [];
|
||||
public users: Array<UserDTO> = [];
|
||||
@ -25,7 +26,11 @@ export class UserMangerSettingsComponent implements OnInit {
|
||||
this._router.navigate(['login']);
|
||||
return;
|
||||
}
|
||||
this.userRoles = Utils.enumToArray(UserRoles).filter(r => r.key <= this._authService.user.value.role);
|
||||
this.userRoles = Utils
|
||||
.enumToArray(UserRoles)
|
||||
.filter(r => r.key <= this._authService.user.value.role)
|
||||
.sort((a, b) => a.key - b.key);
|
||||
|
||||
this.getUsersList();
|
||||
}
|
||||
|
||||
@ -45,24 +50,25 @@ export class UserMangerSettingsComponent implements OnInit {
|
||||
|
||||
initNewUser() {
|
||||
this.newUser = <UserDTO>{role: UserRoles.User};
|
||||
this.childModal.show();
|
||||
}
|
||||
|
||||
addNewUser() {
|
||||
this._userSettings.createUser(this.newUser).then(() => {
|
||||
this.getUsersList();
|
||||
});
|
||||
async addNewUser() {
|
||||
await this._userSettings.createUser(this.newUser);
|
||||
await this.getUsersList();
|
||||
this.childModal.hide();
|
||||
}
|
||||
|
||||
updateRole(user: UserDTO) {
|
||||
this._userSettings.updateRole(user).then(() => {
|
||||
this.getUsersList();
|
||||
});
|
||||
async updateRole(user: UserDTO) {
|
||||
await this._userSettings.updateRole(user);
|
||||
await this.getUsersList();
|
||||
this.childModal.hide();
|
||||
}
|
||||
|
||||
deleteUser(user: UserDTO) {
|
||||
this._userSettings.deleteUser(user).then(() => {
|
||||
this.getUsersList();
|
||||
});
|
||||
async deleteUser(user: UserDTO) {
|
||||
await this._userSettings.deleteUser(user);
|
||||
await this.getUsersList();
|
||||
this.childModal.hide();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -6,6 +6,7 @@
|
||||
<title>PiGallery2</title>
|
||||
<link rel="shortcut icon" href="assets/icon.png">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<link href="../node_modules/ng2-toastr/bundles/ng2-toastr.min.css" rel="stylesheet"/>
|
||||
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet">
|
||||
<script type="text/javascript" src="config_inject.js"></script>
|
||||
</head>
|
||||
|
@ -6,3 +6,4 @@
|
||||
.navbar-right {
|
||||
margin-right: 0;
|
||||
}
|
||||
|
||||
|
@ -35,12 +35,13 @@
|
||||
"mysql": "^2.13.0",
|
||||
"node-iptc": "^1.0.4",
|
||||
"reflect-metadata": "^0.1.10",
|
||||
"typeconfig": "^1.0.1",
|
||||
"typeconfig": "^1.0.3",
|
||||
"typeorm": "0.0.11",
|
||||
"winston": "^2.3.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@agm/core": "^1.0.0-beta.0",
|
||||
"@angular/animations": "^4.2.6",
|
||||
"@angular/cli": "1.2.0",
|
||||
"@angular/common": "~4.2.5",
|
||||
"@angular/compiler": "~4.2.5",
|
||||
@ -82,6 +83,7 @@
|
||||
"mocha": "^3.4.2",
|
||||
"ng2-cookies": "^1.0.12",
|
||||
"ng2-slim-loading-bar": "^4.0.0",
|
||||
"ng2-toastr": "^4.1.2",
|
||||
"ngx-bootstrap": "^1.7.1",
|
||||
"phantomjs-prebuilt": "^2.1.14",
|
||||
"protractor": "^5.1.2",
|
||||
|
Loading…
x
Reference in New Issue
Block a user