44 changed files with 1667 additions and 159 deletions
@ -0,0 +1,27 @@ |
|||||
|
-----BEGIN RSA PRIVATE KEY----- |
||||
|
MIIEowIBAAKCAQEApNcN8cn0872DhGSdPobrIR9kBfd+qSL/Sqrgk3mywEuuzhN3 |
||||
|
MOYbaejwdIJacC0OjCMVgm3f2TziefYd2ssvAUjT+M9FCESUSSDHgPVxt22UDZxz |
||||
|
ZraasA+jdVW0QQtBv8AjyDCXAmMZxcGT1x1htKsKfG2JDxxc1DXub1BaBSkrqcZ1 |
||||
|
1u50UK0DBbRcUhd85z9Oivju3IktDaVow09fpwUR/tK1xO8PPsaAUQMKdN1ArGA/ |
||||
|
O+FFXAirQ7OD8tT4gCmJYrU2h4mAlcjKwpvmXbtHGmZ2tn4nJsaYUxL0vMPHWoTl |
||||
|
ymOkFbKujBDkTSdKgUdTBy7Bda9ZzAcEBJoGgQIDAQABAoIBAEGVmuO3obEUlu4n |
||||
|
BfUpwwVzst044nkzBnXT1PR4OCmQMyWk0whulTunRXxlnMwC8UXKc7VoN+b79XPm |
||||
|
+2vg6XvOWSAmf2XRu1n5I8doYG1FuOFNfRDB2HvyTOvTRJuYeflr3hC5XGvDuC5Z |
||||
|
XZP6CbTTVKG7BwwvEbQRHSPGyXpBiqd+OOfTpeoobrkGJJAKxvXHO0G7zgB5h/H+ |
||||
|
0fjSWvo4QxzOAF74f0qUmWBbvLjWL3yZhVE8mxNcVoV1HlIdXV5anMe9FURci5D4 |
||||
|
U8ehGky3sbHjcc7wro5IPWJYTrDAmvhI8wMMx7gbHe2HOzyWRX++ifjfP77kw2e3 |
||||
|
IYnwMAECgYEA05Ehmsipk4rmJeCgmDJomQVsJgMW1zjOJwIljSZ9o55+LHpma6r0 |
||||
|
O6sdQYgiNwQT0f//iJZkatpDAyC3U6EU9RY7Yoc0R3XK86vryKQlB/Nh1boLldt6 |
||||
|
9TGdL5eCzaraiYuLjGvXMGTS8LjB0ftFCGQswl2kcuOFx1YjE4WPoUECgYEAx3Wo |
||||
|
yenPXHCdD4kIrQ9SxPha2aobh33MjdwSYSiDliaEoBg/voWJExFmMJuvhR46xqmy |
||||
|
i8E0RuzzBrG4Zhbdo4kcpdF2GtAuxNw8uYvG+SQub8zAmBT7YpXzTmpGQ2TR3i8S |
||||
|
XzD57s7C1mSkBIwWuVJYcx3Kgm1mQNIOELU31UECgYEAhNc14HhqcaffRp06eRX9 |
||||
|
s0dCVsPNzalvV/LzHSOz886KrubT9HrNC8Ivhnwx75Vx1IQHMP4tYyJUvVwHgE0+ |
||||
|
WX1yIDWAz/XYTxP94meekNVy8r30lE3RcK+MYNujV/wVaBPktXDpFwvXnyqDGJPL |
||||
|
Dq/HouslXLYbw8QEFjfgrYECgYB+oSU6ozThpCEihsY6ULskj+PlwohdubEO8wO8 |
||||
|
KSN5RRT4Ksz1YQPIVkiBXaXOJoX8MCpJbayJxs73lgbS0Xt+4oKMh3GqzjaTBpuK |
||||
|
1MHK1Hyiv+QZ6WA7k6V3SCM5kB1pKItKYeabBStPP2+d725R04SR+PzjVx8O0gzZ |
||||
|
8KL0wQKBgC7LRztq8PMDGTHGXVxWXwZ08ZAf2MAsBvYyAU5xudS+pRqlNGDgyxiv |
||||
|
YQEe9n2DVu7GVsoNnKIapmXV1qx0vTU/CpKV0cpXi6m3XVnbtjBsaYtkYNNZfHVl |
||||
|
E++gP4qgvALKugnzaGn5oby0PPcFFhnNqRwFb5c3diihwMQhkudG |
||||
|
-----END RSA PRIVATE KEY----- |
@ -0,0 +1,5 @@ |
|||||
|
#!/bin/bash |
||||
|
|
||||
|
yarn prod |
||||
|
rsync -avz --delete --exclude '/apis/conn.conn' --exclude '.well-known' --exclude '/uploads' -e "ssh -i ./auth/identity.pem -p2222" ./dist/dslak-website/* cdr@2.238.194.8:/www/dslak.it/ |
||||
|
|
@ -0,0 +1,41 @@ |
|||||
|
<?php |
||||
|
@include 'conn.conn'; |
||||
|
$GLOBALS['conn']; |
||||
|
$conn = @mysqli_connect($DATAhst,$DATAusr,$DATApwd,$DATAdtb)or die("CONNECTION ERROR"); |
||||
|
|
||||
|
$content = null; |
||||
|
$content->status = 200; |
||||
|
|
||||
|
$data = json_decode(file_get_contents("php://input")); |
||||
|
|
||||
|
if(isset($_GET['act']) && $_GET['act'] == 'login') { |
||||
|
if(isset($data->usr) && $data->usr == 'admin' && isset($data->pwd) && $data->pwd == 'JohnHolmes') { |
||||
|
http_response_code(200); |
||||
|
$content->status = 200; |
||||
|
$content->authToken = base64_encode('admin:JohnHolmes'.date("Y-m-d")); |
||||
|
} else { |
||||
|
http_response_code(401); |
||||
|
$content->status = 401; |
||||
|
$content->action = 'login'; |
||||
|
} |
||||
|
} else if(isset($_GET['act']) && $_GET['act'] == 'check') { |
||||
|
if(isset($data->token) && $data->token == base64_encode('admin:JohnHolmes'.date("Y-m-d"))) { |
||||
|
http_response_code(200); |
||||
|
$content->status = 200; |
||||
|
$content->authToken = base64_encode('admin:JohnHolmes'.date("Y-m-d")); |
||||
|
} else { |
||||
|
http_response_code(200); |
||||
|
$content->status = 401; |
||||
|
$content->action = 'check'; |
||||
|
$content->token = $data->token; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
header("Access-Control-Allow-Origin: *"); |
||||
|
header("Content-Type: application/json; charset=UTF-8"); |
||||
|
header("Access-Control-Allow-Methods: POST"); |
||||
|
header("Access-Control-Max-Age: 3600"); |
||||
|
|
||||
|
echo json_encode($content); |
||||
|
|
||||
|
?> |
@ -0,0 +1,80 @@ |
|||||
|
<?php |
||||
|
@include 'conn.conn'; |
||||
|
$GLOBALS['conn']; |
||||
|
$conn = @mysqli_connect($DATAhst,$DATAusr,$DATApwd,$DATAdtb)or die("CONNECTION ERROR"); |
||||
|
|
||||
|
$content = null; |
||||
|
$data = json_decode(file_get_contents("php://input")); |
||||
|
|
||||
|
if(isset($data->token) && $data->token == base64_encode('admin:JohnHolmes'.date("Y-m-d"))) { |
||||
|
|
||||
|
if(isset($_GET['act'])) { |
||||
|
if($_GET['act'] == 'save') { |
||||
|
if(isset($data->id)) { |
||||
|
$q = mysqli_query($conn,"UPDATE `exhibitions` SET title = '".addslashes($data->title)."', content = '".addslashes($data->content)."', |
||||
|
tags = '".$data->tags."', date_from = '".$data->date_from."', date_to = '".$data->date_to."', |
||||
|
image = '".$data->image."', works = '".$data->works."', gallery = '".$data->gallery."', |
||||
|
videos = '".$data->videos."' WHERE id = ".$data->id.""); |
||||
|
} else { |
||||
|
$q = mysqli_query($conn,"INSERT INTO `exhibitions` |
||||
|
(`id`, `title`, `content`, `tags`, `date_from`, `date_to`, `image`, `works`, `gallery`, `videos`) |
||||
|
VALUES (NULL, '".addslashes($data->title)."', '".addslashes($data->content)."', '".$data->tags."', |
||||
|
'".$data->date_from."', '".$data->date_to."', '".$data->image."', '".$data->works."', |
||||
|
'".$data->gallery."', '".$data->videos."')"); |
||||
|
} |
||||
|
|
||||
|
if($q) { |
||||
|
http_response_code(201); |
||||
|
$content->status = 201; |
||||
|
} else { |
||||
|
http_response_code(403); |
||||
|
$content->status = "UPDATE `exhibitions` SET title = '".addslashes($data->title)."', content = '".addslashes($data->content)."', |
||||
|
tags = '".$data->tags."', date_from = '".$data->date_from."', date_to = '".$data->date_to."', |
||||
|
image = '".$data->image."', works = '".$data->works."', gallery = '".$data->gallery."', |
||||
|
videos = '".$data->videos."' WHERE id = ".$data->id.""; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
if($_GET['act'] == 'delete') { |
||||
|
if(isset($data->id)) { |
||||
|
$q = mysqli_query($conn,"DELETE FROM `exhibitions` WHERE id = ".$data->id.""); |
||||
|
if($q) { |
||||
|
http_response_code(201); |
||||
|
$content->status = 201; |
||||
|
} else { |
||||
|
http_response_code(403); |
||||
|
$content->status = 403; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
if($q) { |
||||
|
$qe = mysqli_query($conn,"SELECT * FROM `exhibitions` ORDER BY id DESC"); |
||||
|
if(mysqli_num_rows($qe) > 0) { |
||||
|
$content->items = array(); |
||||
|
while($re = mysqli_fetch_array($qe)) { |
||||
|
$item = null; |
||||
|
$item->id = $re['id']; |
||||
|
$item->title = $re['title']; |
||||
|
$item->date_from = $re['date_from']; |
||||
|
$item->date_to = $re['date_to']; |
||||
|
$item->tags = $re['tags']; |
||||
|
$item->image = $re['image']; |
||||
|
array_push($content->items, $item); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
} else { |
||||
|
http_response_code(401); |
||||
|
$content->status = 401; |
||||
|
} |
||||
|
header("Access-Control-Allow-Origin: *"); |
||||
|
header("Content-Type: application/json; charset=UTF-8"); |
||||
|
header("Access-Control-Allow-Methods: POST"); |
||||
|
header("Access-Control-Max-Age: 3600"); |
||||
|
|
||||
|
echo json_encode($content); |
||||
|
|
||||
|
?> |
@ -0,0 +1,24 @@ |
|||||
|
<?php |
||||
|
|
||||
|
$content = null; |
||||
|
$data = json_decode(file_get_contents("php://input")); |
||||
|
|
||||
|
if(isset($data->token) && $data->token == base64_encode('admin:JohnHolmes'.date("Y-m-d"))) { |
||||
|
|
||||
|
@unlink('..'.$data->url); |
||||
|
http_response_code(200); |
||||
|
$content->status = 200; |
||||
|
|
||||
|
} else { |
||||
|
http_response_code(401); |
||||
|
$content->status = 401; |
||||
|
} |
||||
|
|
||||
|
header("Access-Control-Allow-Origin: *"); |
||||
|
header("Content-Type: application/json; charset=UTF-8"); |
||||
|
header("Access-Control-Allow-Methods: POST"); |
||||
|
header("Access-Control-Max-Age: 3600"); |
||||
|
|
||||
|
echo json_encode($content); |
||||
|
|
||||
|
?> |
@ -0,0 +1,35 @@ |
|||||
|
<?php |
||||
|
|
||||
|
$content = null; |
||||
|
|
||||
|
if(isset($_POST['token']) && $_POST['token'] == base64_encode('admin:JohnHolmes'.date("Y-m-d"))) { |
||||
|
|
||||
|
if(is_uploaded_file($_FILES['file']['tmp_name'])) { |
||||
|
$file = $_FILES['file']['tmp_name']; |
||||
|
$filename = date("YmdHis").".".end((explode(".", $_FILES["file"]["name"]))); |
||||
|
|
||||
|
$path = isset($_POST['path']) ? "/uploads/".$_POST['path'] : "/uploads/"; |
||||
|
@move_uploaded_file($file, "..".$path."/".$filename); |
||||
|
|
||||
|
http_response_code(200); |
||||
|
$content->status = 200; |
||||
|
$content->imageUrl = $path."/".$filename; |
||||
|
|
||||
|
} else { |
||||
|
http_response_code(401); |
||||
|
$content->status = 401; |
||||
|
$content->megssage = 'No file uploaded'; |
||||
|
} |
||||
|
} else { |
||||
|
http_response_code(401); |
||||
|
$content->status = 401; |
||||
|
} |
||||
|
|
||||
|
header("Access-Control-Allow-Origin: *"); |
||||
|
header("Content-Type: application/json; charset=UTF-8"); |
||||
|
header("Access-Control-Allow-Methods: POST"); |
||||
|
header("Access-Control-Max-Age: 3600"); |
||||
|
|
||||
|
echo json_encode($content); |
||||
|
|
||||
|
?> |
@ -0,0 +1,75 @@ |
|||||
|
<?php |
||||
|
@include 'conn.conn'; |
||||
|
$GLOBALS['conn']; |
||||
|
$conn = @mysqli_connect($DATAhst,$DATAusr,$DATApwd,$DATAdtb)or die("CONNECTION ERROR"); |
||||
|
|
||||
|
$content = null; |
||||
|
$data = json_decode(file_get_contents("php://input")); |
||||
|
|
||||
|
if(isset($data->token) && $data->token == base64_encode('admin:JohnHolmes'.date("Y-m-d"))) { |
||||
|
|
||||
|
if(isset($_GET['act'])) { |
||||
|
if($_GET['act'] == 'save') { |
||||
|
if(isset($data->id)) { |
||||
|
$q = mysqli_query($conn,"UPDATE `works` SET title = '".addslashes($data->title)."', content = '".addslashes($data->content)."', |
||||
|
type = '".$data->type."', tags = '".$data->tags."', image = '".$data->image."', |
||||
|
exhibitions = '".$data->exhibitions."', gallery = '".$data->gallery."', videos = '".$data->videos."' |
||||
|
WHERE id = ".$data->id.""); |
||||
|
} else { |
||||
|
$q = mysqli_query($conn,"INSERT INTO `works` (`id`, `title`, `content`, `type`, `tags`, `image`, `exhibitions`, `gallery`, `videos`) |
||||
|
VALUES (NULL, '".addslashes($data->title)."', '".addslashes($data->content)."', '".$data->type."', |
||||
|
'".$data->tags."', '".$data->image."', '".$data->exhibitions."', '".$data->gallery."', |
||||
|
'".$data->videos."')"); |
||||
|
} |
||||
|
|
||||
|
if($q) { |
||||
|
http_response_code(201); |
||||
|
$content->status = 201; |
||||
|
} else { |
||||
|
http_response_code(403); |
||||
|
$content->status = 403; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
if($_GET['act'] == 'delete') { |
||||
|
if(isset($data->id)) { |
||||
|
$q = mysqli_query($conn,"DELETE FROM `works` WHERE id = ".$data->id.""); |
||||
|
if($q) { |
||||
|
http_response_code(201); |
||||
|
$content->status = 201; |
||||
|
} else { |
||||
|
http_response_code(403); |
||||
|
$content->status = 403; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
if($q) { |
||||
|
$qe = mysqli_query($conn,"SELECT * FROM `works` ORDER BY id DESC"); |
||||
|
if(mysqli_num_rows($qe) > 0) { |
||||
|
$content->items = array(); |
||||
|
while($re = mysqli_fetch_array($qe)) { |
||||
|
$item = null; |
||||
|
$item->id = $re['id']; |
||||
|
$item->title = $re['title']; |
||||
|
$item->type = $re['type']; |
||||
|
$item->tags = $re['tags']; |
||||
|
$item->image = $re['image']; |
||||
|
array_push($content->items, $item); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
} else { |
||||
|
http_response_code(401); |
||||
|
$content->status = 401; |
||||
|
} |
||||
|
header("Access-Control-Allow-Origin: *"); |
||||
|
header("Content-Type: application/json; charset=UTF-8"); |
||||
|
header("Access-Control-Allow-Methods: POST"); |
||||
|
header("Access-Control-Max-Age: 3600"); |
||||
|
|
||||
|
echo json_encode($content); |
||||
|
|
||||
|
?> |
@ -0,0 +1,191 @@ |
|||||
|
<div class="component-admin"> |
||||
|
<div class="row no-gutters" *ngIf="!authCheck"> |
||||
|
<div class="col-12 col-md-6 mx-auto"> |
||||
|
<form class="login-form-container" (submit)="login()"> |
||||
|
<div class="m-2"> |
||||
|
<span class="login-label">Username</span> |
||||
|
<input type="text" class="input-text" name="userName" [(ngModel)]="userName"> |
||||
|
</div> |
||||
|
<div class="m-2"> |
||||
|
<span class="login-label">Password</span> |
||||
|
<input type="password" class="input-text" name="password" [(ngModel)]="password"> |
||||
|
</div> |
||||
|
<div class="m-2 pt-4"> |
||||
|
<button type="submit" class="button">Sign-in</button> |
||||
|
</div> |
||||
|
</form> |
||||
|
</div> |
||||
|
</div> |
||||
|
|
||||
|
<div class="row no-gutters" *ngIf="authCheck"> |
||||
|
<div class="col-12 col-md-3 col-lg-2"> |
||||
|
<div class="menu"> |
||||
|
<span class="section-title">Works</span> |
||||
|
<button class="action" [ngClass]="{'active': activeEditor == 'works-add'}" (click)="showEditor('works-add')">Add</button> |
||||
|
<button class="action" [ngClass]="{'active': activeEditor == 'works-modify'}" (click)="showEditor('works-modify')">Modify</button> |
||||
|
<button class="action" [ngClass]="{'active': activeEditor == 'works-delete'}" (click)="showEditor('works-delete')">Delete</button> |
||||
|
|
||||
|
<span class="section-title">Exhibitions</span> |
||||
|
<button class="action" [ngClass]="{'active': activeEditor == 'exhibitions-add'}" (click)="showEditor('exhibitions-add')">Add</button> |
||||
|
<button class="action" [ngClass]="{'active': activeEditor == 'exhibitions-modify'}" (click)="showEditor('exhibitions-modify')">Modify</button> |
||||
|
<button class="action" [ngClass]="{'active': activeEditor == 'exhibitions-delete'}" (click)="showEditor('exhibitions-delete')">Delete</button> |
||||
|
</div> |
||||
|
</div> |
||||
|
<div class="col px-5 py-4"> |
||||
|
<div class="edit-container"> |
||||
|
<span class="title">{{sectionTitle}}</span> |
||||
|
<form class="form row" *ngIf="activeEditor == 'works-modify' || activeEditor == 'works-delete'"> |
||||
|
<div class="col-12"> |
||||
|
<select class="input-select" (change)="selectWork($event.target.value)"> |
||||
|
<option value="">- Select work from list -</option> |
||||
|
<option value="{{work.id}}" *ngFor="let work of works"> |
||||
|
{{work.type}} | {{work.title}} |
||||
|
</option> |
||||
|
</select> |
||||
|
</div> |
||||
|
</form> |
||||
|
<form class="form row" *ngIf="activeEditor == 'exhibitions-modify' || activeEditor == 'exhibitions-delete'"> |
||||
|
<div class="col-12"> |
||||
|
<select class="input-select" (change)="selectExhibition($event.target.value)"> |
||||
|
<option value="">- Select exhibition from list -</option> |
||||
|
<option value="{{exhibition.id}}" *ngFor="let exhibition of exhibitions"> |
||||
|
{{exhibition.date_from | date}} | {{exhibition.title}} |
||||
|
</option> |
||||
|
</select> |
||||
|
</div> |
||||
|
</form> |
||||
|
<form class="form row" (submit)="saveData()" |
||||
|
*ngIf="activeEditor == 'works-add' || (activeEditor == 'works-modify' && activeModify) || |
||||
|
activeEditor == 'exhibitions-add' || (activeEditor == 'exhibitions-modify' && activeModify)"> |
||||
|
<div [ngClass]="{'col-8': activeEditor == 'works-add' || activeEditor == 'works-modify', |
||||
|
'col-6': activeEditor == 'exhibitions-add' || activeEditor == 'exhibitions-modify'}"> |
||||
|
<span class="label">Title</span> |
||||
|
<input type="text" class="input-text" name="title" [(ngModel)]="title"> |
||||
|
</div> |
||||
|
<div class="col-4" *ngIf="activeEditor == 'works-add' || activeEditor == 'works-modify'"> |
||||
|
<span class="label">Type</span> |
||||
|
<select class="input-select" name="type" [(ngModel)]="type"> |
||||
|
<option [value]="sec.section" *ngFor="let sec of workSections">{{sec.title}}</option> |
||||
|
</select> |
||||
|
</div> |
||||
|
<div class="col-3" *ngIf="activeEditor == 'exhibitions-add' || activeEditor == 'exhibitions-modify'"> |
||||
|
<span class="label">Date from</span> |
||||
|
<input type="date" class="input-text w-100" name="dateFrom" [(ngModel)]="dateFrom" (change)="dateTo = dateFrom"> |
||||
|
</div> |
||||
|
<div class="col-3" *ngIf="activeEditor == 'exhibitions-add' || activeEditor == 'exhibitions-modify'"> |
||||
|
<span class="label">Date to</span> |
||||
|
<input type="date" class="input-text w-100" name="dateTo" [(ngModel)]="dateTo"> |
||||
|
</div> |
||||
|
<div class="col-12"> |
||||
|
<span class="label">Content</span> |
||||
|
<angular-editor [placeholder]="'Enter text here...'" [config]="editorConfig" name="content" [(ngModel)]="content"></angular-editor> |
||||
|
</div> |
||||
|
<div class="col-12"> |
||||
|
<span class="label">Tags</span> |
||||
|
<input type="text" class="input-text" name="tags" [(ngModel)]="tags"> |
||||
|
</div> |
||||
|
<div class="col-12"> |
||||
|
<span class="label">Gallery</span> |
||||
|
<div class="gallery-container"> |
||||
|
|
||||
|
<label class="image-add" for="image-add"> |
||||
|
<input type="file" id="image-add" (change)="onFileChanged($event)"> |
||||
|
</label> |
||||
|
|
||||
|
<div class="image-box" [ngClass]="{'main': image.main}" *ngFor="let image of selectedGallery"> |
||||
|
<img class="image" [src]="basePath+image.url"> |
||||
|
<button type="button" class="remove" (click)="galleryRemove(image.url)"><span class="icon-trash-2"></span></button> |
||||
|
<button type="button" class="set-main" (click)="gallerySetMain(image.url)" *ngIf="!image.main"><span class="icon-check"></span></button> |
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
|
||||
|
<div class="col-6" *ngIf="activeEditor == 'works-add' || activeEditor == 'works-modify'"> |
||||
|
<span class="label">Exhibitions</span> |
||||
|
<select class="input-select" name="exhibitions" (change)="exhibitionAdd($event.target.value)"> |
||||
|
<option value=""></option> |
||||
|
<option value="{{exhibition.id}}" *ngFor="let exhibition of exhibitions"> |
||||
|
{{exhibition.date_from | date}} | {{exhibition.title}} |
||||
|
</option> |
||||
|
</select> |
||||
|
|
||||
|
<span class="label font-12 pt-2">Selected exhibitions</span> |
||||
|
<span class="selected-exhibition" *ngFor="let se of selectedExhibitions" (click)="exhibitionRemove(se.id)"> |
||||
|
{{se.date_from | date}} | {{se.title}} |
||||
|
</span> |
||||
|
</div> |
||||
|
|
||||
|
<div class="col-6" *ngIf="activeEditor == 'exhibitions-add' || activeEditor == 'exhibitions-modify'"> |
||||
|
<span class="label">Works</span> |
||||
|
<select class="input-select" name="works" (change)="workAdd($event.target.value)"> |
||||
|
<option value=""></option> |
||||
|
<option value="{{work.id}}" *ngFor="let work of works"> |
||||
|
{{work.type}} | {{work.title}} |
||||
|
</option> |
||||
|
</select> |
||||
|
|
||||
|
<span class="label font-12 pt-2">Selected works</span> |
||||
|
<span class="selected-work" *ngFor="let sw of selectedWorks" (click)="workRemove(sw.id)"> |
||||
|
{{sw.type}} | {{sw.title}} |
||||
|
</span> |
||||
|
|
||||
|
</div> |
||||
|
|
||||
|
<div class="col-6"> |
||||
|
<span class="label">Video</span> |
||||
|
<div class="w-30 d-inline-block pr-2"> |
||||
|
<select class="input-select" name="videoType" [(ngModel)]="videoType"> |
||||
|
<option value="youtube">YouTube</option> |
||||
|
<option value="vimeo">Vimeo</option> |
||||
|
<option value="embed">Embed</option> |
||||
|
</select> |
||||
|
</div> |
||||
|
<div class="w-60 d-inline-block pr-2"> |
||||
|
<input type="text" class="input-text" name="videoURL" [(ngModel)]="videoURL"> |
||||
|
</div> |
||||
|
<div class="w-10 d-inline-block"> |
||||
|
<span class="button button-transparent icon-plus-square px-0 w-100" (click)="videoAdd()"></span> |
||||
|
</div> |
||||
|
|
||||
|
<span class="label font-12 pt-2">Selected Videos</span> |
||||
|
<span class="selected-video" *ngFor="let sv of selectedVideos" (click)="videoRemove(sv.url)"> |
||||
|
{{sv.type}} | {{sv.url}} |
||||
|
</span> |
||||
|
</div> |
||||
|
<div class="col-12 pt-5"> |
||||
|
<button class="button w-100" type="submit">Save</button> |
||||
|
</div> |
||||
|
</form> |
||||
|
|
||||
|
|
||||
|
<form class="form row" (submit)="deleteData(modifyId)" |
||||
|
*ngIf="(activeEditor == 'works-delete' || activeEditor == 'exhibitions-delete') && modifyId"> |
||||
|
<div class="col-12"> |
||||
|
<span class="label">Title</span> |
||||
|
<div class="preview-box" *ngIf="activeEditor == 'works-delete'">{{type}} | {{title}}</div> |
||||
|
<div class="preview-box" *ngIf="activeEditor == 'exhibitions-delete'">{{dateFrom}} | {{title}}</div> |
||||
|
</div> |
||||
|
<div class="col-12"> |
||||
|
<span class="label">Content</span> |
||||
|
<div class="preview-box" [innerHTML]="content"></div> |
||||
|
</div> |
||||
|
|
||||
|
<div class="col-12"> |
||||
|
<span class="label">Gallery</span> |
||||
|
<div class="gallery-container"> |
||||
|
<div class="image-box" [ngClass]="{'main': image.main}" *ngFor="let image of selectedGallery"> |
||||
|
<img class="image" [src]="basePath+image.url"> |
||||
|
<button type="button" class="remove" (click)="galleryRemove(image.url)"><span class="icon-trash-2"></span></button> |
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
|
||||
|
<div class="col-12 pt-5"> |
||||
|
<button class="button w-100" type="submit">Delete</button> |
||||
|
</div> |
||||
|
</form> |
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
|
@ -0,0 +1,210 @@ |
|||||
|
@import "../../assets/scss/variables"; |
||||
|
|
||||
|
.component-admin { |
||||
|
|
||||
|
.login-form-container { |
||||
|
text-align: center; |
||||
|
padding: 30px 40px; |
||||
|
color: $white; |
||||
|
|
||||
|
.login-label { |
||||
|
font-size: $font-14; |
||||
|
color: $black; |
||||
|
padding: 8px; |
||||
|
} |
||||
|
|
||||
|
.button { |
||||
|
width: 300px; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
.edit-container { |
||||
|
.title { |
||||
|
display: block; |
||||
|
font-size: $font-30; |
||||
|
font-weight: bolder; |
||||
|
text-transform: uppercase; |
||||
|
padding: 20px 0; |
||||
|
} |
||||
|
.form { |
||||
|
.label { |
||||
|
display: block; |
||||
|
font-size: $font-20; |
||||
|
text-transform: uppercase; |
||||
|
padding: 20px 0 5px 0; |
||||
|
} |
||||
|
|
||||
|
.gallery-container { |
||||
|
display: flex; |
||||
|
background: $white; |
||||
|
border-radius: 4px; |
||||
|
width: 100%; |
||||
|
padding: 5px; |
||||
|
min-height: 100px; |
||||
|
|
||||
|
.image-add { |
||||
|
appearance: none; |
||||
|
display: inline-block; |
||||
|
position: relative; |
||||
|
border: 2px solid $light-gray; |
||||
|
border-radius: 4px; |
||||
|
height: 100px; |
||||
|
width: 100px; |
||||
|
margin: 5px; |
||||
|
cursor: pointer; |
||||
|
|
||||
|
&:before { |
||||
|
content: '\e90a'; |
||||
|
font-family: $font-icon; |
||||
|
font-size: $font-30; |
||||
|
color: $light-gray; |
||||
|
position: absolute; |
||||
|
top: 50%; |
||||
|
left: 50%; |
||||
|
transform: translate(-50%, -50%); |
||||
|
} |
||||
|
|
||||
|
input { |
||||
|
visibility: hidden; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
.image-box { |
||||
|
display: inline-block; |
||||
|
position: relative; |
||||
|
border: 2px solid $light-gray; |
||||
|
height: 100px; |
||||
|
width: 120px; |
||||
|
margin: 5px; |
||||
|
border-radius: 4px; |
||||
|
overflow: hidden; |
||||
|
|
||||
|
.image { |
||||
|
position: absolute; |
||||
|
height: 100%; |
||||
|
width: 100%; |
||||
|
object-fit: cover; |
||||
|
z-index: 0; |
||||
|
} |
||||
|
|
||||
|
.remove, |
||||
|
.set-main { |
||||
|
position: absolute; |
||||
|
top: 4px; |
||||
|
right: 4px; |
||||
|
border: 0; |
||||
|
border-radius: 2px; |
||||
|
color: $black; |
||||
|
height: 20px; |
||||
|
width: 20px; |
||||
|
background: $white-alpha; |
||||
|
padding: 0; |
||||
|
margin: 0; |
||||
|
cursor: pointer; |
||||
|
font-size: $font-12; |
||||
|
z-index: 10; |
||||
|
} |
||||
|
|
||||
|
.remove { |
||||
|
color: $red; |
||||
|
} |
||||
|
.set-main { |
||||
|
color: $green; |
||||
|
right: 30px; |
||||
|
} |
||||
|
|
||||
|
&.main { |
||||
|
border: 2px solid $yellow; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
.selected-exhibition, |
||||
|
.selected-work, |
||||
|
.selected-video { |
||||
|
display: block; |
||||
|
position: relative; |
||||
|
font-size: $font-16; |
||||
|
font-weight: bolder; |
||||
|
border-radius: 4px; |
||||
|
border: 2px solid $white; |
||||
|
background: $white-alpha; |
||||
|
cursor: pointer; |
||||
|
padding: 8px 50px 8px 15px; |
||||
|
margin-bottom: 5px; |
||||
|
|
||||
|
&:before { |
||||
|
content: '\e903'; |
||||
|
position: absolute; |
||||
|
top: 8px; |
||||
|
right: 10px; |
||||
|
font-family: $font-icon; |
||||
|
font-size: $font-20; |
||||
|
color: $gray; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
.preview-box { |
||||
|
border-radius: 4px; |
||||
|
background: $white-alpha2; |
||||
|
padding: 10px; |
||||
|
width: 100%; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
.menu { |
||||
|
background: $dark-gray; |
||||
|
|
||||
|
.section-title { |
||||
|
display: block; |
||||
|
width: 100%; |
||||
|
padding: 50px 10px 10px; |
||||
|
font-size: $font-22; |
||||
|
font-weight: bolder; |
||||
|
text-transform: uppercase; |
||||
|
color: $white; |
||||
|
text-align: center; |
||||
|
border-bottom: 1px solid $black-alpha; |
||||
|
} |
||||
|
|
||||
|
.action { |
||||
|
display: block; |
||||
|
appearance: none; |
||||
|
border: none; |
||||
|
border-radius: 0px; |
||||
|
width: 100%; |
||||
|
padding: 10px; |
||||
|
font-size: $font-14; |
||||
|
text-transform: uppercase; |
||||
|
color: $white; |
||||
|
background: $dark-gray; |
||||
|
cursor: pointer; |
||||
|
border-bottom: 1px solid $black-alpha; |
||||
|
|
||||
|
&.active { |
||||
|
background: $yellow; |
||||
|
color: $black; |
||||
|
border: none; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
@media (min-width: map-get($grid-breakpoints, 'md')) { |
||||
|
.component-admin { |
||||
|
.menu { |
||||
|
position: fixed; |
||||
|
height: 100vh; |
||||
|
width: 25%; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
@media (min-width: map-get($grid-breakpoints, 'lg')) { |
||||
|
.component-admin { |
||||
|
.menu { |
||||
|
width: 16.66%; |
||||
|
} |
||||
|
} |
||||
|
} |
@ -1,20 +1,20 @@ |
|||||
import { async, ComponentFixture, TestBed } from '@angular/core/testing'; |
import { async, ComponentFixture, TestBed } from '@angular/core/testing'; |
||||
|
|
||||
import { WorkshopsComponent } from './workshops.component'; |
|
||||
|
import { AdminComponent } from './admin.component'; |
||||
|
|
||||
describe('WorkshopsComponent', () => { |
|
||||
let component: WorkshopsComponent; |
|
||||
let fixture: ComponentFixture<WorkshopsComponent>; |
|
||||
|
describe('AdminComponent', () => { |
||||
|
let component: AdminComponent; |
||||
|
let fixture: ComponentFixture<AdminComponent>; |
||||
|
|
||||
beforeEach(async(() => { |
beforeEach(async(() => { |
||||
TestBed.configureTestingModule({ |
TestBed.configureTestingModule({ |
||||
declarations: [ WorkshopsComponent ] |
|
||||
|
declarations: [ AdminComponent ] |
||||
}) |
}) |
||||
.compileComponents(); |
.compileComponents(); |
||||
})); |
})); |
||||
|
|
||||
beforeEach(() => { |
beforeEach(() => { |
||||
fixture = TestBed.createComponent(WorkshopsComponent); |
|
||||
|
fixture = TestBed.createComponent(AdminComponent); |
||||
component = fixture.componentInstance; |
component = fixture.componentInstance; |
||||
fixture.detectChanges(); |
fixture.detectChanges(); |
||||
}); |
}); |
@ -0,0 +1,437 @@ |
|||||
|
import { Component, OnInit } from '@angular/core' |
||||
|
import { ApisService } from '../services/apis.service' |
||||
|
import { AuthService } from '../services/auth.service' |
||||
|
import { AngularEditorConfig } from '@kolkov/angular-editor' |
||||
|
import { environment } from '../../environments/environment' |
||||
|
import { editorConfig } from '../../config/config' |
||||
|
|
||||
|
@Component({ |
||||
|
selector: 'app-admin', |
||||
|
templateUrl: './admin.component.html', |
||||
|
styleUrls: ['./admin.component.scss'] |
||||
|
}) |
||||
|
export class AdminComponent implements OnInit { |
||||
|
|
||||
|
private restApi = `${environment.API_URL}` |
||||
|
public basePath = `${environment.BASE_PATH}` |
||||
|
|
||||
|
public authCheck: boolean = false |
||||
|
public userName: string = '' |
||||
|
public password: string = '' |
||||
|
public activeEditor: string = '' |
||||
|
public sectionTitle: string = '' |
||||
|
public activeModify: boolean = false |
||||
|
public modifyId: number = null |
||||
|
|
||||
|
public exhibitions: any = [] |
||||
|
public works: any = [] |
||||
|
public selectedExhibitions: any = [] |
||||
|
public selectedWorks: any = [] |
||||
|
public selectedVideos: any = [] |
||||
|
public selectedGallery: any = [] |
||||
|
|
||||
|
// ngModels
|
||||
|
public title: string = '' |
||||
|
public type: string = '' |
||||
|
public content: string = '' |
||||
|
public tags: string = '' |
||||
|
public dateFrom: string = '' |
||||
|
public dateTo: string = '' |
||||
|
public mainImage: string = '' |
||||
|
public videoType: string = '' |
||||
|
public videoURL: string = '' |
||||
|
|
||||
|
public editorConfig: AngularEditorConfig = editorConfig |
||||
|
public workSections: any = [ |
||||
|
{title: 'Entertainment', section: 'entertainment'}, |
||||
|
{title: 'Installations', section: 'installations'}, |
||||
|
{title: 'Performances', section: 'performances'}, |
||||
|
{title: 'Workshops', section: 'workshops'} |
||||
|
] |
||||
|
|
||||
|
constructor( |
||||
|
private authService: AuthService, |
||||
|
private apisService: ApisService |
||||
|
) { } |
||||
|
|
||||
|
ngOnInit(): void { |
||||
|
|
||||
|
const body = { token: window.sessionStorage.getItem('authToken') } |
||||
|
this.authService.authCheck(body).toPromise().then((response) => { |
||||
|
this.authCheck = response.status && response.status == 200 |
||||
|
|
||||
|
if(this.authCheck) { |
||||
|
this.loadData() |
||||
|
} |
||||
|
|
||||
|
},(error) => { |
||||
|
this.authCheck = false |
||||
|
console.error('Auth ERROR INIT', error) |
||||
|
}).catch((e) => { |
||||
|
this.authCheck = false |
||||
|
console.error('Auth CATCH INIT', e) |
||||
|
}) |
||||
|
} |
||||
|
|
||||
|
login(): void { |
||||
|
const body = { usr: this.userName, pwd: this.password } |
||||
|
this.authService.login(body).toPromise().then((response) => { |
||||
|
this.authCheck = response.status && response.status == 200 |
||||
|
if(this.authCheck) { |
||||
|
window.sessionStorage.setItem('authToken', response.authToken) |
||||
|
this.loadData() |
||||
|
} |
||||
|
},(error) => { |
||||
|
console.error('Auth ERROR', error) |
||||
|
}).catch((e) => { |
||||
|
console.error('Auth CATCH', e) |
||||
|
}) |
||||
|
} |
||||
|
|
||||
|
loadData(): void { |
||||
|
this.apisService.getPortfolio('exhibitions').toPromise().then((response) => { |
||||
|
this.exhibitions = response.items |
||||
|
},(error) => { |
||||
|
console.error('getPortfolio ERROR', error) |
||||
|
}).catch((e) => { |
||||
|
console.error('getPortfolio CATCH', e) |
||||
|
}) |
||||
|
|
||||
|
this.apisService.getPortfolio('portfolio').toPromise().then((response) => { |
||||
|
this.works = response.items |
||||
|
},(error) => { |
||||
|
console.error('getPortfolio ERROR', error) |
||||
|
}).catch((e) => { |
||||
|
console.error('getPortfolio CATCH', e) |
||||
|
}) |
||||
|
} |
||||
|
|
||||
|
showEditor(section): void { |
||||
|
switch(section) { |
||||
|
case 'works-add': |
||||
|
this.sectionTitle = 'Add work' |
||||
|
break; |
||||
|
case 'works-modify': |
||||
|
this.sectionTitle = 'Modify work' |
||||
|
break; |
||||
|
case 'works-delete': |
||||
|
this.sectionTitle = 'Delete work' |
||||
|
break; |
||||
|
case 'exhibitions-add': |
||||
|
this.sectionTitle = 'Add exhibition' |
||||
|
break; |
||||
|
case 'exhibitions-modify': |
||||
|
this.sectionTitle = 'Modify exhibition' |
||||
|
break; |
||||
|
case 'exhibitions-delete': |
||||
|
this.sectionTitle = 'Delete exhibition' |
||||
|
break; |
||||
|
} |
||||
|
this.activeModify = false |
||||
|
this.activeEditor = section |
||||
|
this.modifyId = null |
||||
|
this.resetFields() |
||||
|
} |
||||
|
|
||||
|
exhibitionAdd(id): void { |
||||
|
this.selectedExhibitions.push( |
||||
|
this.exhibitions.filter(item => item.id == id)[0] |
||||
|
) |
||||
|
this.exhibitions = this.exhibitions.filter(item => item.id != id) |
||||
|
} |
||||
|
|
||||
|
exhibitionRemove(id): void { |
||||
|
this.exhibitions.push( |
||||
|
this.selectedExhibitions.filter(item => item.id == id)[0] |
||||
|
) |
||||
|
this.selectedExhibitions = this.selectedExhibitions.filter(item => item.id != id) |
||||
|
} |
||||
|
|
||||
|
workAdd(id): void { |
||||
|
this.selectedWorks.push( |
||||
|
this.works.filter(item => item.id == id)[0] |
||||
|
) |
||||
|
this.works = this.works.filter(item => item.id != id) |
||||
|
} |
||||
|
|
||||
|
workRemove(id): void { |
||||
|
this.works.push( |
||||
|
this.selectedWorks.filter(item => item.id == id)[0] |
||||
|
) |
||||
|
this.selectedWorks = this.selectedWorks.filter(item => item.id != id) |
||||
|
} |
||||
|
|
||||
|
videoAdd(): void { |
||||
|
this.selectedVideos.push({ |
||||
|
type: this.videoType, |
||||
|
url: this.videoURL.replace(/\"/g, "\\\"") |
||||
|
}) |
||||
|
this.videoURL = '' |
||||
|
} |
||||
|
|
||||
|
videoRemove(url): void { |
||||
|
this.selectedVideos = this.selectedVideos.filter(item => item.url != url) |
||||
|
} |
||||
|
|
||||
|
onFileChanged(e) { |
||||
|
const file = (<HTMLInputElement>e.target).files[0] |
||||
|
const uploadData = new FormData() |
||||
|
uploadData.append('token', window.sessionStorage.getItem('authToken')) |
||||
|
uploadData.append('path', 'assets') |
||||
|
uploadData.append('file', file, file.name) |
||||
|
this.apisService.uploadImage(uploadData).toPromise().then((response) => { |
||||
|
this.selectedGallery.push({ |
||||
|
title: response.title || '', |
||||
|
url: response.imageUrl |
||||
|
}) |
||||
|
},(error) => { |
||||
|
console.error(error) |
||||
|
}).catch((e) => { |
||||
|
console.error(e) |
||||
|
}) |
||||
|
} |
||||
|
|
||||
|
gallerySetMain(url): void { |
||||
|
this.selectedGallery.forEach((e) => { |
||||
|
if(e.url == url) { |
||||
|
e.main = true |
||||
|
} else { |
||||
|
delete e.main |
||||
|
} |
||||
|
}) |
||||
|
} |
||||
|
|
||||
|
galleryRemove(url): void { |
||||
|
const body = { |
||||
|
token: window.sessionStorage.getItem('authToken'), |
||||
|
url: url |
||||
|
} |
||||
|
this.apisService.removeImage(body).toPromise().then((response) => { |
||||
|
this.selectedGallery = this.selectedGallery.filter(item => item.url != url) |
||||
|
},(error) => { |
||||
|
console.error(error) |
||||
|
}).catch((e) => { |
||||
|
console.error(e) |
||||
|
}) |
||||
|
} |
||||
|
|
||||
|
selectWork(id): void { |
||||
|
this.activeModify = true |
||||
|
this.modifyId = id |
||||
|
this.apisService.getDetails('works', id).toPromise().then((response) => { |
||||
|
const detail = response.item |
||||
|
this.apisService.getPortfolio('exhibitions').toPromise().then((response) => { |
||||
|
this.exhibitions = response.items |
||||
|
this.title = detail.title |
||||
|
this.content = detail.content |
||||
|
this.type = detail.type |
||||
|
this.tags = detail.tags |
||||
|
this.selectedExhibitions = detail.exhibitions.length ? |
||||
|
this.exhibitions.filter(item => detail.exhibitions.map(a => a.id).indexOf(item.id) > -1) : [] |
||||
|
this.selectedGallery = detail.gallery ? JSON.parse(detail.gallery) : [] |
||||
|
this.selectedVideos = detail.videos ? JSON.parse(detail.videos) : [] |
||||
|
|
||||
|
},(error) => { |
||||
|
console.error(error) |
||||
|
}).catch((e) => { |
||||
|
console.error(e) |
||||
|
}) |
||||
|
},(error) => { |
||||
|
console.error(error) |
||||
|
}).catch((e) => { |
||||
|
console.error(e) |
||||
|
}) |
||||
|
} |
||||
|
|
||||
|
selectExhibition(id): void { |
||||
|
|
||||
|
this.activeModify = true |
||||
|
this.modifyId = id |
||||
|
this.apisService.getDetails('exhibitions', id).toPromise().then((response) => { |
||||
|
const detail = response.item |
||||
|
this.apisService.getPortfolio('portfolio').toPromise().then((response) => { |
||||
|
this.works = response.items |
||||
|
this.title = detail.title |
||||
|
this.content = detail.content |
||||
|
this.tags = detail.tags |
||||
|
this.dateFrom = detail.date_from |
||||
|
this.dateTo = detail.date_to |
||||
|
this.selectedWorks = detail.works.length ? |
||||
|
this.works.filter(item => detail.works.map(a => a.id).indexOf(item.id) > -1) : [] |
||||
|
this.selectedGallery = detail.gallery ? JSON.parse(detail.gallery) : [] |
||||
|
this.selectedVideos = detail.videos ? JSON.parse(detail.videos) : [] |
||||
|
|
||||
|
},(error) => { |
||||
|
console.error(error) |
||||
|
}).catch((e) => { |
||||
|
console.error(e) |
||||
|
}) |
||||
|
},(error) => { |
||||
|
console.error(error) |
||||
|
}).catch((e) => { |
||||
|
console.error(e) |
||||
|
}) |
||||
|
} |
||||
|
|
||||
|
saveData(): void { |
||||
|
if(this.activeEditor == 'works-add' || this.activeEditor == 'works-modify') { |
||||
|
this.saveWork() |
||||
|
} |
||||
|
if(this.activeEditor == 'exhibitions-add' || this.activeEditor == 'exhibitions-modify') { |
||||
|
this.saveExhibition() |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
saveWork(): void { |
||||
|
let error = false |
||||
|
let errorMessages = [] |
||||
|
const mainImage = this.selectedGallery.filter(item => item.main) |
||||
|
|
||||
|
if(!this.title){ |
||||
|
error = true |
||||
|
errorMessages.push('No title') |
||||
|
} |
||||
|
if(!this.type){ |
||||
|
error = true |
||||
|
errorMessages.push('No type selected') |
||||
|
} |
||||
|
|
||||
|
if(this.selectedGallery.length == 0 || mainImage.length == 0){ |
||||
|
error = true |
||||
|
errorMessages.push('No main image selected') |
||||
|
} |
||||
|
|
||||
|
if(error) { |
||||
|
console.log('ERRORS:',errorMessages) |
||||
|
} else { |
||||
|
const body = { |
||||
|
id: this.activeModify ? this.modifyId : null, |
||||
|
token: window.sessionStorage.getItem('authToken'), |
||||
|
title: this.title, |
||||
|
content: this.content, |
||||
|
type: this.type, |
||||
|
tags: this.tags, |
||||
|
image: mainImage[0].url, |
||||
|
exhibitions: this.selectedExhibitions.map(a => a.id).join(','), |
||||
|
gallery: JSON.stringify(this.selectedGallery), |
||||
|
videos: JSON.stringify(this.selectedVideos) |
||||
|
} |
||||
|
|
||||
|
this.apisService.saveWork(body).toPromise().then((response) => { |
||||
|
this.resetFields() |
||||
|
this.works = response.items |
||||
|
},(error) => { |
||||
|
console.error(error) |
||||
|
}).catch((e) => { |
||||
|
console.error(e) |
||||
|
}) |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
saveExhibition(): void { |
||||
|
let error = false |
||||
|
let errorMessages = [] |
||||
|
const mainImage = this.selectedGallery.filter(item => item.main) |
||||
|
|
||||
|
if(!this.title){ |
||||
|
error = true |
||||
|
errorMessages.push('No title') |
||||
|
} |
||||
|
if(!this.dateFrom){ |
||||
|
error = true |
||||
|
errorMessages.push('No date from selected') |
||||
|
} |
||||
|
if(!this.dateTo){ |
||||
|
error = true |
||||
|
errorMessages.push('No date to selected') |
||||
|
} |
||||
|
if(this.selectedGallery.length == 0 || mainImage.length == 0){ |
||||
|
error = true |
||||
|
errorMessages.push('No main image selected') |
||||
|
} |
||||
|
|
||||
|
if(error) { |
||||
|
console.log('ERRORS:',errorMessages) |
||||
|
} else { |
||||
|
const body = { |
||||
|
id: this.activeModify ? this.modifyId : null, |
||||
|
token: window.sessionStorage.getItem('authToken'), |
||||
|
title: this.title, |
||||
|
content: this.content, |
||||
|
date_from: this.dateFrom, |
||||
|
date_to: this.dateTo, |
||||
|
tags: this.tags, |
||||
|
image: mainImage[0].url, |
||||
|
works: this.selectedWorks.map(a => a.id).join(','), |
||||
|
gallery: JSON.stringify(this.selectedGallery), |
||||
|
videos: JSON.stringify(this.selectedVideos) |
||||
|
} |
||||
|
|
||||
|
this.apisService.saveExhibition(body).toPromise().then((response) => { |
||||
|
this.resetFields() |
||||
|
this.exhibitions = response.items |
||||
|
},(error) => { |
||||
|
console.error(error) |
||||
|
}).catch((e) => { |
||||
|
console.error(e) |
||||
|
}) |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
deleteData(id): void { |
||||
|
if(this.activeEditor == 'works-delete') { |
||||
|
this.deleteWork(id) |
||||
|
} |
||||
|
if(this.activeEditor == 'exhibitions-delete') { |
||||
|
this.deleteExhibition(id) |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
deleteWork(id): void { |
||||
|
|
||||
|
const body = { |
||||
|
id: id, |
||||
|
token: window.sessionStorage.getItem('authToken') |
||||
|
} |
||||
|
|
||||
|
this.apisService.deleteWork(body).toPromise().then((response) => { |
||||
|
this.resetFields() |
||||
|
this.works = response.items |
||||
|
},(error) => { |
||||
|
console.error(error) |
||||
|
}).catch((e) => { |
||||
|
console.error(e) |
||||
|
}) |
||||
|
} |
||||
|
|
||||
|
deleteExhibition(id): void { |
||||
|
|
||||
|
const body = { |
||||
|
id: id, |
||||
|
token: window.sessionStorage.getItem('authToken') |
||||
|
} |
||||
|
|
||||
|
this.apisService.deleteExhibition(body).toPromise().then((response) => { |
||||
|
this.resetFields() |
||||
|
this.exhibitions = response.items |
||||
|
},(error) => { |
||||
|
console.error(error) |
||||
|
}).catch((e) => { |
||||
|
console.error(e) |
||||
|
}) |
||||
|
} |
||||
|
|
||||
|
resetFields(): void { |
||||
|
this.title = '' |
||||
|
this.content = '' |
||||
|
this.type = '' |
||||
|
this.tags = '' |
||||
|
this.dateFrom = '' |
||||
|
this.dateTo = '' |
||||
|
this.selectedExhibitions = [] |
||||
|
this.selectedWorks = [] |
||||
|
this.selectedGallery = [] |
||||
|
this.selectedVideos = [] |
||||
|
this.modifyId = null |
||||
|
} |
||||
|
} |
@ -1,4 +1,5 @@ |
|||||
<app-header></app-header> |
|
||||
|
<app-header *ngIf="page != '/admin'"></app-header> |
||||
<router-outlet></router-outlet> |
<router-outlet></router-outlet> |
||||
|
|
||||
<Particles class="particles" [id]="id" [options]="particlesOptions" (particlesLoaded)="particlesLoaded($event)" *ngIf="particlesEnabled"></Particles> |
|
||||
|
<Particles class="particles" *ngIf="particlesEnabled && page != '/admin'" |
||||
|
[id]="id" [options]="particlesOptions" (particlesLoaded)="particlesLoaded($event)"></Particles> |
||||
|
@ -0,0 +1,16 @@ |
|||||
|
import { TestBed } from '@angular/core/testing'; |
||||
|
|
||||
|
import { AuthService } from './auth.service'; |
||||
|
|
||||
|
describe('AuthService', () => { |
||||
|
let service: AuthService; |
||||
|
|
||||
|
beforeEach(() => { |
||||
|
TestBed.configureTestingModule({}); |
||||
|
service = TestBed.inject(AuthService); |
||||
|
}); |
||||
|
|
||||
|
it('should be created', () => { |
||||
|
expect(service).toBeTruthy(); |
||||
|
}); |
||||
|
}); |
@ -0,0 +1,33 @@ |
|||||
|
import { Injectable } from '@angular/core' |
||||
|
import { HttpClient, HttpHeaders, HttpParams, HttpRequest } from '@angular/common/http' |
||||
|
import { Observable, Subject, throwError } from 'rxjs' |
||||
|
import { catchError } from 'rxjs/operators' |
||||
|
import { BaseService } from './base-service' |
||||
|
import { environment } from '../../environments/environment' |
||||
|
|
||||
|
@Injectable({ |
||||
|
providedIn: 'root' |
||||
|
}) |
||||
|
export class AuthService extends BaseService { |
||||
|
|
||||
|
private restApi = `${environment.API_URL}` |
||||
|
|
||||
|
constructor(private http: HttpClient) { |
||||
|
super() |
||||
|
} |
||||
|
|
||||
|
login(body): Observable<any> { |
||||
|
let urlApi = `${this.restApi}auth.php?act=login` |
||||
|
return this.http.post<any>(urlApi, JSON.stringify(body)).pipe( |
||||
|
catchError(this.handleError) |
||||
|
) |
||||
|
} |
||||
|
|
||||
|
authCheck(body): Observable<any> { |
||||
|
let urlApi = `${this.restApi}auth.php?act=check` |
||||
|
return this.http.post<any>(urlApi, JSON.stringify(body)).pipe( |
||||
|
catchError(this.handleError) |
||||
|
) |
||||
|
} |
||||
|
|
||||
|
} |
@ -1 +0,0 @@ |
|||||
<p>workshops works!</p> |
|
@ -1,15 +0,0 @@ |
|||||
import { Component, OnInit } from '@angular/core'; |
|
||||
|
|
||||
@Component({ |
|
||||
selector: 'app-workshops', |
|
||||
templateUrl: './workshops.component.html', |
|
||||
styleUrls: ['./workshops.component.scss'] |
|
||||
}) |
|
||||
export class WorkshopsComponent implements OnInit { |
|
||||
|
|
||||
constructor() { } |
|
||||
|
|
||||
ngOnInit(): void { |
|
||||
} |
|
||||
|
|
||||
} |
|
Binary file not shown.
Before Width: | Height: | Size: 18 KiB After Width: | Height: | Size: 28 KiB |
Binary file not shown.
Binary file not shown.
File diff suppressed because one or more lines are too long
After Width: | Height: | Size: 432 B |
After Width: | Height: | Size: 79 KiB |
@ -0,0 +1,90 @@ |
|||||
|
|
||||
|
|
||||
|
input, |
||||
|
select, |
||||
|
button, |
||||
|
textarea { |
||||
|
border: none; |
||||
|
border-radius: 4px; |
||||
|
background: $white; |
||||
|
appearance: none; |
||||
|
font-family: $font-primary; |
||||
|
font-size: $font-20; |
||||
|
resize: none; |
||||
|
&::-ms-clear { |
||||
|
display: none; |
||||
|
} |
||||
|
&:focus {outline:none;} |
||||
|
&::-moz-focus-inner {border:0;} |
||||
|
} |
||||
|
|
||||
|
input[type=text], |
||||
|
input[type=password], |
||||
|
input[type=file], |
||||
|
select { |
||||
|
color: $black; |
||||
|
padding: 10px 20px; |
||||
|
width: 100%; |
||||
|
text-align: left; |
||||
|
box-sizing: border-box; |
||||
|
&:focus::placeholder { |
||||
|
color: transparent; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
.input-text { |
||||
|
padding: 10px 20px !important; |
||||
|
} |
||||
|
|
||||
|
.input-file { |
||||
|
padding: 6px 20px !important; |
||||
|
} |
||||
|
|
||||
|
.input-textarea, |
||||
|
.angular-editor { |
||||
|
border-radius: 4px; |
||||
|
background: $white; |
||||
|
padding: 10px; |
||||
|
width: 100%; |
||||
|
} |
||||
|
|
||||
|
.input-select { |
||||
|
padding: 9px 20px !important; |
||||
|
background-image: url('/assets/images/angle-down.svg'); |
||||
|
background-size: 28px; |
||||
|
background-position: right 10px top 10px; |
||||
|
background-repeat: no-repeat; |
||||
|
} |
||||
|
|
||||
|
.button { |
||||
|
position: relative; |
||||
|
appearance: none; |
||||
|
color: $white; |
||||
|
border: none; |
||||
|
border-radius: 4px; |
||||
|
background: $black; |
||||
|
display: inline-block; |
||||
|
padding: 10px 20px 10px 20px !important; |
||||
|
text-align: center; |
||||
|
font-family: $font-20; |
||||
|
text-transform: uppercase; |
||||
|
font-weight: 500; |
||||
|
transition: opacity .3s; |
||||
|
white-space: nowrap; |
||||
|
outline: none; |
||||
|
cursor: pointer; |
||||
|
|
||||
|
&:disabled { |
||||
|
opacity: 0.5; |
||||
|
} |
||||
|
|
||||
|
&.button-white { |
||||
|
background: $white; |
||||
|
color: $black !important; |
||||
|
} |
||||
|
|
||||
|
&.button-transparent { |
||||
|
background: $white-alpha2; |
||||
|
color: $black !important; |
||||
|
} |
||||
|
} |
@ -0,0 +1,52 @@ |
|||||
|
import { environment } from '../environments/environment' |
||||
|
import { AngularEditorConfig } from '@kolkov/angular-editor' |
||||
|
|
||||
|
export const editorConfig: AngularEditorConfig = { |
||||
|
editable: true, |
||||
|
spellcheck: true, |
||||
|
height: '300px', |
||||
|
translate: 'no', |
||||
|
enableToolbar: true, |
||||
|
showToolbar: true, |
||||
|
placeholder: 'Enter text here...', |
||||
|
defaultParagraphSeparator: 'p', |
||||
|
defaultFontName: '', |
||||
|
defaultFontSize: '', |
||||
|
uploadUrl: `${environment.API_URL}upload.php`, |
||||
|
uploadWithCredentials: false, |
||||
|
sanitize: true, |
||||
|
toolbarPosition: 'top', |
||||
|
toolbarHiddenButtons: [ |
||||
|
[ |
||||
|
'undo', |
||||
|
'redo', |
||||
|
//'bold',
|
||||
|
//'italic',
|
||||
|
//'underline',
|
||||
|
'strikeThrough', |
||||
|
'subscript', |
||||
|
'superscript', |
||||
|
//'justifyLeft',
|
||||
|
//'justifyCenter',
|
||||
|
//'justifyRight',
|
||||
|
//'justifyFull',
|
||||
|
'indent', |
||||
|
'outdent', |
||||
|
'insertUnorderedList', |
||||
|
'insertOrderedList', |
||||
|
'heading', |
||||
|
'fontName', |
||||
|
'fontSize', |
||||
|
'textColor', |
||||
|
'backgroundColor', |
||||
|
'customClasses', |
||||
|
//'link',
|
||||
|
'unlink', |
||||
|
//'insertImage',
|
||||
|
'insertVideo', |
||||
|
'insertHorizontalRule', |
||||
|
//'removeFormat',
|
||||
|
//'toggleEditorMode'
|
||||
|
] |
||||
|
] |
||||
|
} |
@ -1,5 +1,5 @@ |
|||||
export const environment = { |
export const environment = { |
||||
production: true, |
production: true, |
||||
|
|
||||
API_URL: `https://apis.dslak.it/` |
|
||||
|
API_URL: `https://www.dslak.it/apis/`, |
||||
|
BASE_PATH: `https://www.dslak.it` |
||||
} |
} |
||||
|
@ -1,5 +1,5 @@ |
|||||
export const environment = { |
export const environment = { |
||||
production: false, |
production: false, |
||||
|
|
||||
API_URL: `http://dslakng.local/apis/` |
|
||||
|
API_URL: `http://dslakng.local/apis/`, |
||||
|
BASE_PATH: `http://dslakng.local` |
||||
} |
} |
||||
|
Loading…
Reference in new issue