You've already forked pigallery2
mirror of
https://github.com/bpatrik/pigallery2.git
synced 2025-09-16 09:16:27 +02:00
improving sharing
This commit is contained in:
@@ -63,12 +63,12 @@ To configure it. Run `PiGallery2` first to create `config.json` file, then edit
|
||||
* supporting several core CPU
|
||||
* supporting hardware acceleration ([sharp](https://github.com/lovell/sharp) and [gm](https://github.com/aheckmann/gm) as optional and JS-based [Jimp](https://github.com/oliver-moran/jimp) as fallback)
|
||||
* Custom lightbox for full screen photo viewing
|
||||
* keyboard support for navigation - `In progress`
|
||||
* keyboard support for navigation
|
||||
* showing low-res thumbnail while full image loads
|
||||
* Information panel for showing **Exif info** - `In progress`
|
||||
* Client side caching (directories and search results)
|
||||
* Rendering **photos** with GPS coordinates **on google map**
|
||||
* .gpx file support - `In progress`
|
||||
* .gpx file support - `future plan`
|
||||
* **Two modes: SQL database and no-database mode**
|
||||
* both modes supports
|
||||
* user management
|
||||
@@ -77,11 +77,11 @@ To configure it. Run `PiGallery2` first to create `config.json` file, then edit
|
||||
* faster directory listing
|
||||
* searching
|
||||
* instant search, auto complete
|
||||
* sharing - `In progress`
|
||||
* sharing
|
||||
* setting link expiration time
|
||||
* Nice design - `In progress`
|
||||
* responsive design (phone, tablet desktop support)
|
||||
* Setup page - `In progress`
|
||||
* **Markdown based blogging support** - `In progress`
|
||||
* **Markdown based blogging support** - `future plan`
|
||||
* you can write some note in the blog.md for every directory
|
||||
* bug free :) - `In progress`
|
||||
|
7
USERRIGHTS.md
Normal file
7
USERRIGHTS.md
Normal file
@@ -0,0 +1,7 @@
|
||||
# User rights
|
||||
|
||||
* Limited Guest - list dir
|
||||
* Guest - +search
|
||||
* User - +share
|
||||
* Admin - +settings
|
||||
* Developer - +see errors
|
@@ -10,7 +10,7 @@ import {PhotoDTO} from "../../common/entities/PhotoDTO";
|
||||
import {ProjectPath} from "../ProjectPath";
|
||||
import {Logger} from "../Logger";
|
||||
import {Config} from "../../common/config/private/Config";
|
||||
import {UserUtil} from "../../common/entities/UserDTO";
|
||||
import {UserDTO} from "../../common/entities/UserDTO";
|
||||
|
||||
|
||||
const LOG_TAG = "[GalleryMWs]";
|
||||
@@ -32,7 +32,7 @@ export class GalleryMWs {
|
||||
req.session.user.permissions.length > 0 &&
|
||||
req.session.user.permissions[0] != "/") {
|
||||
directory.directories = directory.directories.filter(d =>
|
||||
UserUtil.isDirectoryAvailable(d, req.session.user.permissions));
|
||||
UserDTO.isDirectoryAvailable(d, req.session.user.permissions));
|
||||
}
|
||||
req.resultPipe = new ContentWrapper(directory, null);
|
||||
return next();
|
||||
|
@@ -1,7 +1,7 @@
|
||||
///<reference path="../customtypings/ExtendedRequest.d.ts"/>
|
||||
import {NextFunction, Request, Response} from "express";
|
||||
import {Error, ErrorCodes} from "../../../common/entities/Error";
|
||||
import {UserDTO, UserRoles, UserUtil} from "../../../common/entities/UserDTO";
|
||||
import {UserDTO, UserRoles} from "../../../common/entities/UserDTO";
|
||||
import {ObjectManagerRepository} from "../../model/ObjectManagerRepository";
|
||||
import {Config} from "../../../common/config/private/Config";
|
||||
|
||||
@@ -9,12 +9,15 @@ export class AuthenticationMWs {
|
||||
|
||||
private static async getSharingUser(req: Request) {
|
||||
if (Config.Client.Sharing.enabled === true &&
|
||||
Config.Client.Sharing.passwordProtected === false &&
|
||||
(!!req.query.sk || !!req.params.sharingKey)) {
|
||||
const sharing = await ObjectManagerRepository.getInstance().SharingManager.findOne({
|
||||
sharingKey: req.query.sk || req.params.sharingKey,
|
||||
});
|
||||
if (!sharing) {
|
||||
if (!sharing || sharing.expires < Date.now()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (Config.Client.Sharing.passwordProtected === true && sharing.password) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -22,7 +25,7 @@ export class AuthenticationMWs {
|
||||
if (sharing.includeSubfolders == true) {
|
||||
path += "*";
|
||||
}
|
||||
return <UserDTO>{name: "Guest", role: UserRoles.Guest, permissions: [path]};
|
||||
return <UserDTO>{name: "Guest", role: UserRoles.LimitedGuest, permissions: [path]};
|
||||
|
||||
}
|
||||
return null;
|
||||
@@ -67,7 +70,7 @@ export class AuthenticationMWs {
|
||||
}
|
||||
|
||||
const directoryName = req.params.directory || "/";
|
||||
if (UserUtil.isPathAvailable(directoryName, req.session.user.permissions) == true) {
|
||||
if (UserDTO.isPathAvailable(directoryName, req.session.user.permissions) == true) {
|
||||
return next();
|
||||
|
||||
}
|
||||
@@ -117,6 +120,42 @@ export class AuthenticationMWs {
|
||||
|
||||
}
|
||||
|
||||
|
||||
public static async shareLogin(req: Request, res: Response, next: NextFunction) {
|
||||
|
||||
if (Config.Client.Sharing.enabled === false) {
|
||||
return next();
|
||||
}
|
||||
//not enough parameter
|
||||
if ((!req.query.sk && !req.params.sharingKey)) {
|
||||
return next(new Error(ErrorCodes.INPUT_ERROR));
|
||||
}
|
||||
|
||||
try {
|
||||
const password = (req.body ? req.body.password : null) || null;
|
||||
|
||||
const sharing = await ObjectManagerRepository.getInstance().SharingManager.findOne({
|
||||
sharingKey: req.query.sk || req.params.sharingKey,
|
||||
});
|
||||
if (!sharing || sharing.expires < Date.now() ||
|
||||
(Config.Client.Sharing.passwordProtected === true && sharing.password !== password)) {
|
||||
return next(new Error(ErrorCodes.CREDENTIAL_NOT_FOUND));
|
||||
}
|
||||
|
||||
let path = sharing.path;
|
||||
if (sharing.includeSubfolders == true) {
|
||||
path += "*";
|
||||
}
|
||||
|
||||
req.session.user = <UserDTO>{name: "Guest", role: UserRoles.LimitedGuest, permissions: [path]};
|
||||
return next();
|
||||
|
||||
} catch (err) {
|
||||
return next(new Error(ErrorCodes.GENERAL_ERROR));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static logout(req: Request, res: Response, next: NextFunction) {
|
||||
delete req.session.user;
|
||||
return next();
|
||||
|
@@ -34,7 +34,7 @@ export class UserManager implements IUserManager {
|
||||
this.createUser(<UserDTO>{name: "developer", password: "developer", role: UserRoles.Developer});
|
||||
this.createUser(<UserDTO>{name: "admin", password: "admin", role: UserRoles.Admin});
|
||||
this.createUser(<UserDTO>{name: "user", password: "user", role: UserRoles.User});
|
||||
this.createUser(<UserDTO>{name: "guest", password: "guest", role: UserRoles.Guest});
|
||||
this.createUser(<UserDTO>{name: "guest", password: "guest", role: UserRoles.LimitedGuest});
|
||||
}
|
||||
|
||||
|
||||
|
@@ -2,6 +2,7 @@ import {AuthenticationMWs} from "../middlewares/user/AuthenticationMWs";
|
||||
import {GalleryMWs} from "../middlewares/GalleryMWs";
|
||||
import {RenderingMWs} from "../middlewares/RenderingMWs";
|
||||
import {ThumbnailGeneratorMWs} from "../middlewares/thumbnail/ThumbnailGeneratorMWs";
|
||||
import {UserRoles} from "../../common/entities/UserDTO";
|
||||
|
||||
export class GalleryRouter {
|
||||
public static route(app: any) {
|
||||
@@ -31,6 +32,7 @@ export class GalleryRouter {
|
||||
private static addGetImage(app) {
|
||||
app.get(["/api/gallery/content/:imagePath(*\.(jpg|bmp|png|gif|jpeg))"],
|
||||
AuthenticationMWs.authenticate,
|
||||
//TODO: authorize path
|
||||
GalleryMWs.loadImage,
|
||||
RenderingMWs.renderFile
|
||||
);
|
||||
@@ -39,6 +41,7 @@ export class GalleryRouter {
|
||||
private static addGetImageThumbnail(app) {
|
||||
app.get("/api/gallery/content/:imagePath(*\.(jpg|bmp|png|gif|jpeg))/thumbnail/:size?",
|
||||
AuthenticationMWs.authenticate,
|
||||
//TODO: authorize path
|
||||
GalleryMWs.loadImage,
|
||||
ThumbnailGeneratorMWs.generateThumbnail,
|
||||
RenderingMWs.renderFile
|
||||
@@ -48,6 +51,7 @@ export class GalleryRouter {
|
||||
private static addGetImageIcon(app) {
|
||||
app.get("/api/gallery/content/:imagePath(*\.(jpg|bmp|png|gif|jpeg))/icon",
|
||||
AuthenticationMWs.authenticate,
|
||||
//TODO: authorize path
|
||||
GalleryMWs.loadImage,
|
||||
ThumbnailGeneratorMWs.generateIcon,
|
||||
RenderingMWs.renderFile
|
||||
@@ -57,6 +61,7 @@ export class GalleryRouter {
|
||||
private static addSearch(app) {
|
||||
app.get("/api/search/:text",
|
||||
AuthenticationMWs.authenticate,
|
||||
AuthenticationMWs.authorise(UserRoles.Guest),
|
||||
GalleryMWs.search,
|
||||
ThumbnailGeneratorMWs.addThumbnailInformation,
|
||||
GalleryMWs.removeCyclicDirectoryReferences,
|
||||
@@ -67,6 +72,7 @@ export class GalleryRouter {
|
||||
private static addInstantSearch(app) {
|
||||
app.get("/api/instant-search/:text",
|
||||
AuthenticationMWs.authenticate,
|
||||
AuthenticationMWs.authorise(UserRoles.Guest),
|
||||
GalleryMWs.instantSearch,
|
||||
ThumbnailGeneratorMWs.addThumbnailInformation,
|
||||
GalleryMWs.removeCyclicDirectoryReferences,
|
||||
@@ -77,6 +83,7 @@ export class GalleryRouter {
|
||||
private static addAutoComplete(app) {
|
||||
app.get("/api/autocomplete/:text",
|
||||
AuthenticationMWs.authenticate,
|
||||
AuthenticationMWs.authorise(UserRoles.Guest),
|
||||
GalleryMWs.autocomplete,
|
||||
RenderingMWs.renderResult
|
||||
);
|
||||
|
@@ -6,15 +6,24 @@ import {SharingMWs} from "../middlewares/SharingMWs";
|
||||
export class SharingRouter {
|
||||
public static route(app: any) {
|
||||
|
||||
this.addShareLogin(app);
|
||||
this.addGetSharing(app);
|
||||
this.addCreateSharing(app);
|
||||
this.addUpdateSharing(app);
|
||||
}
|
||||
|
||||
private static addShareLogin(app) {
|
||||
app.post("/api/share/login",
|
||||
AuthenticationMWs.inverseAuthenticate,
|
||||
AuthenticationMWs.shareLogin,
|
||||
RenderingMWs.renderSessionUser
|
||||
);
|
||||
};
|
||||
|
||||
private static addGetSharing(app) {
|
||||
app.get("/api/share/:sharingKey",
|
||||
AuthenticationMWs.authenticate,
|
||||
AuthenticationMWs.authorise(UserRoles.Guest),
|
||||
AuthenticationMWs.authorise(UserRoles.LimitedGuest),
|
||||
SharingMWs.getSharing,
|
||||
RenderingMWs.renderSharing
|
||||
);
|
||||
|
@@ -8,7 +8,13 @@ declare module ServerInject {
|
||||
|
||||
export let Config = new PublicConfigClass();
|
||||
|
||||
|
||||
if (typeof ServerInject !== "undefined" && typeof ServerInject.ConfigInject !== "undefined") {
|
||||
WebConfigLoader.loadFrontendConfig(Config.Client, ServerInject.ConfigInject);
|
||||
}
|
||||
|
||||
|
||||
if (Config.Client.publicUrl == "") {
|
||||
Config.Client.publicUrl = location.origin;
|
||||
}
|
||||
|
||||
|
@@ -21,6 +21,7 @@ export interface ClientConfig {
|
||||
enableOnScrollThumbnailPrioritising: boolean;
|
||||
authenticationRequired: boolean;
|
||||
googleApiKey: string;
|
||||
publicUrl: string;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -46,7 +47,8 @@ export class PublicConfigClass {
|
||||
enableOnScrollRendering: true,
|
||||
enableOnScrollThumbnailPrioritising: true,
|
||||
authenticationRequired: true,
|
||||
googleApiKey: ""
|
||||
googleApiKey: "",
|
||||
publicUrl: ""
|
||||
};
|
||||
|
||||
}
|
||||
|
@@ -10,8 +10,8 @@ export interface DirectoryDTO {
|
||||
photos: Array<PhotoDTO>;
|
||||
}
|
||||
|
||||
export module DirectoryUtil {
|
||||
export const addReferences = (dir: DirectoryDTO) => {
|
||||
export module DirectoryDTO {
|
||||
export const addReferences = (dir: DirectoryDTO): void => {
|
||||
dir.photos.forEach((photo: PhotoDTO) => {
|
||||
photo.directory = dir;
|
||||
});
|
||||
|
@@ -1,8 +1,8 @@
|
||||
import {DirectoryDTO} from "./DirectoryDTO";
|
||||
import {Utils} from "../Utils";
|
||||
export enum UserRoles{
|
||||
Guest = 0,
|
||||
TrustedGuest = 1,
|
||||
LimitedGuest = 0,
|
||||
Guest = 1,
|
||||
User = 2,
|
||||
Admin = 3,
|
||||
Developer = 4,
|
||||
@@ -17,7 +17,7 @@ export interface UserDTO {
|
||||
permissions: string[]; //user can only see these permissions. if ends with *, its recursive
|
||||
}
|
||||
|
||||
export module UserUtil {
|
||||
export module UserDTO {
|
||||
|
||||
export const isPathAvailable = (path: string, permissions: string[]): boolean => {
|
||||
if (permissions == null || permissions.length == 0 || permissions[0] == "/") {
|
||||
|
@@ -5,6 +5,7 @@ import {Router} from "@angular/router";
|
||||
import {Config} from "../../common/config/public/Config";
|
||||
import {Title} from "@angular/platform-browser";
|
||||
import {NotificationService} from "./model/notification.service";
|
||||
import {ShareService} from "./gallery/share.service";
|
||||
|
||||
|
||||
@Component({
|
||||
@@ -16,23 +17,23 @@ export class AppComponent implements OnInit {
|
||||
|
||||
constructor(private _router: Router,
|
||||
private _authenticationService: AuthenticationService,
|
||||
private _shareService: ShareService,
|
||||
private _title: Title, vcr: ViewContainerRef,
|
||||
notificatin: NotificationService) {
|
||||
notificatin.setRootViewContainerRef(vcr);
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
async ngOnInit() {
|
||||
this._title.setTitle(Config.Client.applicationTitle);
|
||||
await this._shareService.wait();
|
||||
this._authenticationService.user.subscribe((user: UserDTO) => {
|
||||
if (user != null) {
|
||||
if (this._router.isActive('login', true)) {
|
||||
console.log("routing");
|
||||
this._router.navigate(["gallery", ""]);
|
||||
if (this._authenticationService.isAuthenticated()) {
|
||||
if (this.isLoginPage()) {
|
||||
return this.toGallery();
|
||||
}
|
||||
} else {
|
||||
if (!this._router.isActive('login', true)) {
|
||||
console.log("routing");
|
||||
this._router.navigate(["login"]);
|
||||
if (!this.isLoginPage()) {
|
||||
return this.toLogin();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -41,5 +42,23 @@ export class AppComponent implements OnInit {
|
||||
|
||||
}
|
||||
|
||||
|
||||
private isLoginPage() {
|
||||
return this._router.isActive('login', true) || this._router.isActive('shareLogin', false);
|
||||
}
|
||||
|
||||
private toLogin() {
|
||||
if (this._shareService.isSharing()) {
|
||||
return this._router.navigate(["shareLogin"], {queryParams: {sk: this._shareService.getSharingKey()}});
|
||||
} else {
|
||||
return this._router.navigate(["login"]);
|
||||
}
|
||||
}
|
||||
|
||||
private toGallery() {
|
||||
if (this._shareService.isSharing()) {
|
||||
return this._router.navigate(["share", this._shareService.getSharingKey()]);
|
||||
} else {
|
||||
return this._router.navigate(["gallery", ""]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -42,6 +42,9 @@ import {ToastModule} from "ng2-toastr/ng2-toastr";
|
||||
import {BrowserAnimationsModule} from "@angular/platform-browser/animations";
|
||||
import {NotificationService} from "./model/notification.service";
|
||||
|
||||
import {ClipboardModule} from "ngx-clipboard";
|
||||
import {NavigationService} from "./model/navigation.service";
|
||||
|
||||
@Injectable()
|
||||
export class GoogleMapsConfig {
|
||||
apiKey: string;
|
||||
@@ -58,6 +61,7 @@ export class GoogleMapsConfig {
|
||||
HttpModule,
|
||||
BrowserAnimationsModule,
|
||||
appRoutes,
|
||||
ClipboardModule,
|
||||
ToastModule.forRoot(),
|
||||
ModalModule.forRoot(),
|
||||
AgmCoreModule.forRoot(),
|
||||
@@ -98,6 +102,7 @@ export class GoogleMapsConfig {
|
||||
ThumbnailManagerService,
|
||||
NotificationService,
|
||||
FullScreenService,
|
||||
NavigationService,
|
||||
OverlayService],
|
||||
|
||||
bootstrap: [AppComponent]
|
||||
|
@@ -1,6 +1,6 @@
|
||||
import {Injectable} from "@angular/core";
|
||||
import {PhotoDTO} from "../../../common/entities/PhotoDTO";
|
||||
import {DirectoryDTO, DirectoryUtil} from "../../../common/entities/DirectoryDTO";
|
||||
import {DirectoryDTO} from "../../../common/entities/DirectoryDTO";
|
||||
import {Utils} from "../../../common/Utils";
|
||||
import {Config} from "../../../common/config/public/Config";
|
||||
|
||||
@@ -16,7 +16,7 @@ export class GalleryCacheService {
|
||||
if (value != null) {
|
||||
let directory: DirectoryDTO = JSON.parse(value);
|
||||
|
||||
DirectoryUtil.addReferences(directory);
|
||||
DirectoryDTO.addReferences(directory);
|
||||
return directory;
|
||||
}
|
||||
return null;
|
||||
|
@@ -2,6 +2,12 @@
|
||||
<app-frame>
|
||||
|
||||
<ng-container navbar>
|
||||
|
||||
<li *ngIf="countDown">
|
||||
<p class="navbar-text">Link availability: {{countDown.day}} days,
|
||||
{{("0"+countDown.hour).slice(-2)}}:{{("0"+countDown.minute).slice(-2)}}:{{("0"+countDown.second).slice(-2)}}
|
||||
</p>
|
||||
</li>
|
||||
<li *ngIf="showSearchBar">
|
||||
<gallery-search #search></gallery-search>
|
||||
</li>
|
||||
|
@@ -9,6 +9,9 @@ import {Config} from "../../../common/config/public/Config";
|
||||
import {DirectoryDTO} from "../../../common/entities/DirectoryDTO";
|
||||
import {SearchResultDTO} from "../../../common/entities/SearchResult";
|
||||
import {ShareService} from "./share.service";
|
||||
import {NavigationService} from "../model/navigation.service";
|
||||
import {UserRoles} from "../../../common/entities/UserDTO";
|
||||
import {Observable} from "rxjs/Rx";
|
||||
|
||||
@Component({
|
||||
selector: 'gallery',
|
||||
@@ -20,42 +23,61 @@ export class GalleryComponent implements OnInit, OnDestroy {
|
||||
@ViewChild(GallerySearchComponent) search: GallerySearchComponent;
|
||||
@ViewChild(GalleryGridComponent) grid: GalleryGridComponent;
|
||||
|
||||
public showSearchBar: boolean = true;
|
||||
public showShare: boolean = true;
|
||||
public showSearchBar: boolean = false;
|
||||
public showShare: boolean = false;
|
||||
public directories: DirectoryDTO[] = [];
|
||||
public isPhotoWithLocation = false;
|
||||
private $counter;
|
||||
private subscription = {
|
||||
content: null,
|
||||
route: null
|
||||
route: null,
|
||||
timer: null
|
||||
};
|
||||
public countDown = null;
|
||||
|
||||
constructor(public _galleryService: GalleryService,
|
||||
private _authService: AuthenticationService,
|
||||
private _router: Router,
|
||||
private shareService: ShareService,
|
||||
private _route: ActivatedRoute) {
|
||||
private _route: ActivatedRoute,
|
||||
private _navigation: NavigationService) {
|
||||
|
||||
this.showSearchBar = Config.Client.Search.searchEnabled;
|
||||
this.showShare = Config.Client.Sharing.enabled;
|
||||
}
|
||||
|
||||
|
||||
ngOnInit() {
|
||||
if (!this._authService.isAuthenticated() &&
|
||||
(!this.shareService.isSharing() ||
|
||||
(this.shareService.isSharing() && Config.Client.Sharing.passwordProtected == true))
|
||||
) {
|
||||
if (this.shareService.isSharing()) {
|
||||
this._router.navigate(['shareLogin']);
|
||||
} else {
|
||||
this._router.navigate(['login']);
|
||||
}
|
||||
updateTimer(t: number) {
|
||||
if (this.shareService.sharing.value == null) {
|
||||
return;
|
||||
}
|
||||
t = Math.floor((this.shareService.sharing.value.expires - Date.now()) / 1000);
|
||||
this.countDown = {};
|
||||
this.countDown.day = Math.floor(t / 86400);
|
||||
t -= this.countDown.day * 86400;
|
||||
this.countDown.hour = Math.floor(t / 3600) % 24;
|
||||
t -= this.countDown.hour * 3600;
|
||||
this.countDown.minute = Math.floor(t / 60) % 60;
|
||||
t -= this.countDown.minute * 60;
|
||||
this.countDown.second = t % 60;
|
||||
}
|
||||
|
||||
async ngOnInit() {
|
||||
await this.shareService.wait();
|
||||
if (!this._authService.isAuthenticated() &&
|
||||
(!this.shareService.isSharing() ||
|
||||
(this.shareService.isSharing() && Config.Client.Sharing.passwordProtected == true))) {
|
||||
|
||||
return this._navigation.toLogin();
|
||||
}
|
||||
this.showSearchBar = Config.Client.Search.searchEnabled && this._authService.isAuthorized(UserRoles.Guest);
|
||||
this.showShare = Config.Client.Sharing.enabled && this._authService.isAuthorized(UserRoles.User);
|
||||
|
||||
this.subscription.content = this._galleryService.content.subscribe(this.onContentChange);
|
||||
this.subscription.route = this._route.params.subscribe(this.onRoute);
|
||||
|
||||
if (this.shareService.isSharing()) {
|
||||
this.$counter = Observable.interval(1000);
|
||||
this.subscription.timer = this.$counter.subscribe((x) => this.updateTimer(x));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
ngOnDestroy() {
|
||||
@@ -109,7 +131,7 @@ export class GalleryComponent implements OnInit, OnDestroy {
|
||||
}
|
||||
|
||||
if (params['sharingKey'] && params['sharingKey'] != "") {
|
||||
const sharing = await this._galleryService.getSharing(this.shareService.getSharingKey());
|
||||
const sharing = await this.shareService.getSharing();
|
||||
this._router.navigate(['/gallery', sharing.path], {queryParams: {sk: this.shareService.getSharingKey()}});
|
||||
return;
|
||||
}
|
||||
|
@@ -1,7 +1,7 @@
|
||||
import {Injectable} from "@angular/core";
|
||||
import {NetworkService} from "../model/network/network.service";
|
||||
import {ContentWrapper} from "../../../common/entities/ConentWrapper";
|
||||
import {DirectoryDTO, DirectoryUtil} from "../../../common/entities/DirectoryDTO";
|
||||
import {DirectoryDTO} from "../../../common/entities/DirectoryDTO";
|
||||
import {SearchTypes} from "../../../common/entities/AutoCompleteItem";
|
||||
import {GalleryCacheService} from "./cache.gallery.service";
|
||||
import {BehaviorSubject} from "rxjs/BehaviorSubject";
|
||||
@@ -53,7 +53,7 @@ export class GalleryService {
|
||||
}
|
||||
|
||||
|
||||
DirectoryUtil.addReferences(cw.directory);
|
||||
DirectoryDTO.addReferences(cw.directory);
|
||||
|
||||
|
||||
this.lastDirectory = cw.directory;
|
||||
|
@@ -1,7 +1,7 @@
|
||||
import {Component, Input, OnChanges} from "@angular/core";
|
||||
import {DirectoryDTO} from "../../../../common/entities/DirectoryDTO";
|
||||
import {RouterLink} from "@angular/router";
|
||||
import {UserUtil} from "../../../../common/entities/UserDTO";
|
||||
import {UserDTO} from "../../../../common/entities/UserDTO";
|
||||
import {AuthenticationService} from "../../model/network/authentication.service";
|
||||
import {ShareService} from "../share.service";
|
||||
|
||||
@@ -49,7 +49,7 @@ export class GalleryNavigatorComponent implements OnChanges {
|
||||
if (dirs.length == 0) {
|
||||
arr.push({name: "Images", route: null});
|
||||
} else {
|
||||
arr.push({name: "Images", route: UserUtil.isPathAvailable("/", user.permissions) ? "/" : null});
|
||||
arr.push({name: "Images", route: UserDTO.isPathAvailable("/", user.permissions) ? "/" : null});
|
||||
|
||||
}
|
||||
|
||||
@@ -59,7 +59,7 @@ export class GalleryNavigatorComponent implements OnChanges {
|
||||
if (dirs.length - 1 == index) {
|
||||
arr.push({name: name, route: null});
|
||||
} else {
|
||||
arr.push({name: name, route: UserUtil.isPathAvailable(route, user.permissions) ? route : null});
|
||||
arr.push({name: name, route: UserDTO.isPathAvailable(route, user.permissions) ? route : null});
|
||||
}
|
||||
});
|
||||
|
||||
|
@@ -2,10 +2,12 @@ import {Injectable} from "@angular/core";
|
||||
import {NetworkService} from "../model/network/network.service";
|
||||
import {CreateSharingDTO, SharingDTO} from "../../../common/entities/SharingDTO";
|
||||
import {Router, RoutesRecognized} from "@angular/router";
|
||||
import {BehaviorSubject} from "rxjs/BehaviorSubject";
|
||||
|
||||
@Injectable()
|
||||
export class ShareService {
|
||||
|
||||
public sharing: BehaviorSubject<SharingDTO>;
|
||||
param = null;
|
||||
queryParam = null;
|
||||
sharingKey = null;
|
||||
@@ -15,7 +17,7 @@ export class ShareService {
|
||||
|
||||
|
||||
constructor(private _networkService: NetworkService, private router: Router) {
|
||||
|
||||
this.sharing = new BehaviorSubject(null);
|
||||
this.ReadyPR = new Promise((resolve) => {
|
||||
if (this.inited == true) {
|
||||
return resolve();
|
||||
@@ -27,7 +29,11 @@ export class ShareService {
|
||||
if (val instanceof RoutesRecognized) {
|
||||
this.param = val.state.root.firstChild.params["sharingKey"] || null;
|
||||
this.queryParam = val.state.root.firstChild.queryParams["sk"] || null;
|
||||
const changed = this.sharingKey != this.param || this.queryParam;
|
||||
if (changed) {
|
||||
this.sharingKey = this.param || this.queryParam;
|
||||
this.getSharing();
|
||||
}
|
||||
if (this.resolve) {
|
||||
this.resolve();
|
||||
this.inited = true;
|
||||
@@ -43,7 +49,7 @@ export class ShareService {
|
||||
return this.ReadyPR;
|
||||
}
|
||||
|
||||
public getSharing(dir: string, includeSubfolders: boolean, valid: number): Promise<SharingDTO> {
|
||||
public createSharing(dir: string, includeSubfolders: boolean, valid: number): Promise<SharingDTO> {
|
||||
return this._networkService.postJson("/share/" + dir, {
|
||||
createSharing: <CreateSharingDTO>{
|
||||
includeSubfolders: includeSubfolders,
|
||||
@@ -70,4 +76,10 @@ export class ShareService {
|
||||
return this.sharingKey != null;
|
||||
|
||||
}
|
||||
|
||||
public async getSharing(): Promise<SharingDTO> {
|
||||
const sharing = await this._networkService.getJson<SharingDTO>("/share/" + this.getSharingKey());
|
||||
this.sharing.next(sharing);
|
||||
return sharing;
|
||||
}
|
||||
}
|
||||
|
@@ -2,7 +2,11 @@
|
||||
z-index: 9999;
|
||||
}
|
||||
|
||||
button {
|
||||
padding-left: 0;
|
||||
padding-right: 0;
|
||||
.full-width {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.row {
|
||||
padding-top: 1px;
|
||||
padding-bottom: 1px;
|
||||
}
|
||||
|
@@ -1,70 +1,98 @@
|
||||
<button id="shareButton" class="btn btn-default navbar-btn btn-link" type="button"
|
||||
data-toggle="modal" data-target="#shareModal" [disabled]="!enabled" (click)="get()">
|
||||
<button id="shareButton" class="btn btn-default navbar-btn btn-link"
|
||||
type="button" [disabled]="!enabled" (click)="showModal()">
|
||||
<span class="glyphicon glyphicon-share-alt"></span>
|
||||
Share
|
||||
</button>
|
||||
|
||||
<!-- sharing Modal-->
|
||||
<div class="modal fade" id="shareModal" tabindex="-1" role="dialog" aria-labelledby="shareModalLabel"
|
||||
data-backdrop="false"
|
||||
<div bsModal #shareModal="bs-modal"
|
||||
class="modal fade" id="shareModal"
|
||||
tabindex="-1" role="dialog" aria-labelledby="shareModalLabel"
|
||||
[config]="{ backdrop: false }"
|
||||
aria-hidden="true">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span
|
||||
<button type="button" class="close" (click)="shareModal.hide()" aria-label="Close"><span
|
||||
aria-hidden="true">×</span></button>
|
||||
<h4 class="modal-title" id="shareModalLabel">Share</h4>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<div class="row">
|
||||
<div class="col-sm-10">
|
||||
<input id="shareLink" name="shareLink" placeholder="link" class="form-control input-md" type="text"
|
||||
<input id="shareLink"
|
||||
name="shareLink"
|
||||
placeholder="link"
|
||||
class="form-control input-md"
|
||||
type="text"
|
||||
[ngModel]="url">
|
||||
</div>
|
||||
<div class="col-sm-2 pull-right">
|
||||
<button id="copyButton" name="copyButton" data-clipboard-target="shareLink" class="btn btn-primary">Copy
|
||||
<button id="copyButton" name="copyButton"
|
||||
ngxClipboard [cbContent]="url"
|
||||
(cbOnSuccess)="onCopy()"
|
||||
class="btn btn-primary">Copy
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<hr/>
|
||||
<div class="form-horizontal">
|
||||
<div class="form-group" style="padding: 0 15px 0 15px;">
|
||||
|
||||
<div style="display: inline;">
|
||||
<label class="control-label">sharing:</label>
|
||||
<div class="form-control-static" id="sharingPath">{{currentDir}}</div>
|
||||
</div>
|
||||
|
||||
<label class="checkbox pull-right">
|
||||
<input id="recursiveShareBox" type="checkbox" (change)="update()" [(ngModel)]="input.includeSubfolders"
|
||||
checked="true" value="remember-me"> Include subfolders
|
||||
</label>
|
||||
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-sm-4">
|
||||
Valid:
|
||||
<p id="sliderText"></p>
|
||||
<div class="col-sm-2">
|
||||
<label class="control-label">Sharing:</label>
|
||||
</div>
|
||||
<div class="col-sm-10">
|
||||
<input disabled type="text"
|
||||
class="full-width form-control"
|
||||
[ngModel]="currentDir">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-sm-2">
|
||||
<label class="control-label">Include subfolders:</label>
|
||||
</div>
|
||||
<div class="col-sm-4">
|
||||
<input id="shareSlider" data-slider-id='shareSlider' [(ngModel)]="input.valid.amount" (change)="update()"
|
||||
<input id="recursiveShareBox"
|
||||
type="checkbox"
|
||||
(change)="update()"
|
||||
[(ngModel)]="input.includeSubfolders"
|
||||
checked="checked"
|
||||
value="remember-me">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-sm-2">
|
||||
<label class="control-label">Password:</label>
|
||||
</div>
|
||||
<div class="col-sm-4">
|
||||
<input id="password"
|
||||
class="form-control"
|
||||
type="password"
|
||||
(change)="update()"
|
||||
[(ngModel)]="input.password"
|
||||
placeholder="Password">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-sm-2">
|
||||
<label class="control-label">Valid:</label>
|
||||
</div>
|
||||
<div class="col-sm-3" style="padding-right: 1px">
|
||||
<input class="form-control" [(ngModel)]="input.valid.amount" (change)="update()"
|
||||
name="validAmount"
|
||||
type="number" min="0" step="1"/>
|
||||
</div>
|
||||
<div class="col-sm-4">
|
||||
<select class="form-control" [(ngModel)]="input.valid.type" (change)="update()" name="validType" required>
|
||||
<div class="col-sm-3" style="padding-left: 1px">
|
||||
<select class="form-control col-md-3" [(ngModel)]="input.valid.type" (change)="update()" name="validType"
|
||||
required>
|
||||
<option *ngFor="let repository of validityTypes" [value]="repository.key">{{repository.value}}
|
||||
</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-sm-2 col-sm-push-10">
|
||||
<button id="updatebutton" name="updatebutton" class="btn btn-primary">Update</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
@@ -1,9 +1,13 @@
|
||||
import {Component, OnDestroy, OnInit} from "@angular/core";
|
||||
import {Component, OnDestroy, OnInit, ViewChild} from "@angular/core";
|
||||
import {Utils} from "../../../../common/Utils";
|
||||
import {ShareService} from "../share.service";
|
||||
import {GalleryService} from "../gallery.service";
|
||||
import {ContentWrapper} from "../../../../common/entities/ConentWrapper";
|
||||
import {SharingDTO} from "../../../../common/entities/SharingDTO";
|
||||
import {ModalDirective} from "ngx-bootstrap/modal";
|
||||
import {Config} from "../../../../common/config/public/Config";
|
||||
import {NotificationService} from "../../model/notification.service";
|
||||
|
||||
|
||||
@Component({
|
||||
selector: 'gallery-share',
|
||||
@@ -11,6 +15,7 @@ import {SharingDTO} from "../../../../common/entities/SharingDTO";
|
||||
styleUrls: ['./share.gallery.component.css'],
|
||||
})
|
||||
export class GalleryShareComponent implements OnInit, OnDestroy {
|
||||
@ViewChild('shareModal') public childModal: ModalDirective;
|
||||
|
||||
enabled: boolean = true;
|
||||
url: string = "";
|
||||
@@ -26,8 +31,11 @@ export class GalleryShareComponent implements OnInit, OnDestroy {
|
||||
currentDir: string = "";
|
||||
sharing: SharingDTO;
|
||||
contentSubscription = null;
|
||||
passwordProtection = false;
|
||||
|
||||
constructor(private _sharingService: ShareService, public _galleryService: GalleryService) {
|
||||
constructor(private _sharingService: ShareService,
|
||||
public _galleryService: GalleryService,
|
||||
private _notification: NotificationService) {
|
||||
this.validityTypes = Utils.enumToArray(ValidityTypes);
|
||||
|
||||
|
||||
@@ -42,6 +50,7 @@ export class GalleryShareComponent implements OnInit, OnDestroy {
|
||||
}
|
||||
this.currentDir = Utils.concatUrls(content.directory.path, content.directory.name);
|
||||
});
|
||||
this.passwordProtection = Config.Client.Sharing.passwordProtected;
|
||||
}
|
||||
|
||||
ngOnDestroy() {
|
||||
@@ -68,14 +77,23 @@ export class GalleryShareComponent implements OnInit, OnDestroy {
|
||||
this.url = "loading..";
|
||||
this.sharing = await this._sharingService.updateSharing(this.currentDir, this.sharing.id, this.input.includeSubfolders, this.calcValidity());
|
||||
console.log(this.sharing);
|
||||
this.url = location.origin + "/share/" + this.sharing.sharingKey
|
||||
this.url = Config.Client.publicUrl + "/share/" + this.sharing.sharingKey
|
||||
}
|
||||
|
||||
async get() {
|
||||
this.url = "loading..";
|
||||
this.sharing = await this._sharingService.getSharing(this.currentDir, this.input.includeSubfolders, this.calcValidity());
|
||||
this.sharing = await this._sharingService.createSharing(this.currentDir, this.input.includeSubfolders, this.calcValidity());
|
||||
console.log(this.sharing);
|
||||
this.url = location.origin + "/share/" + this.sharing.sharingKey
|
||||
this.url = Config.Client.publicUrl + "/share/" + this.sharing.sharingKey
|
||||
}
|
||||
|
||||
async showModal() {
|
||||
await this.get();
|
||||
this.childModal.show();
|
||||
}
|
||||
|
||||
onCopy() {
|
||||
this._notification.success("Url has been copied to clipboard");
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -52,43 +52,3 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!--
|
||||
<div class="login mat-typography" fxLayoutGap="80px" fxLayoutAlign="start center" fxFlexFill fxLayout="column">
|
||||
<h1><img src="assets/icon.png">PiGallery 2</h1>
|
||||
<form class="form-signin" #LoginForm="ngForm" (submit)="onLogin()" fxLayout="row">
|
||||
<md-card fxFlex="400px">
|
||||
<md-card-header>
|
||||
<md-card-title>Please sign in</md-card-title>
|
||||
</md-card-header>
|
||||
<md-card-content fxFlexFill fxLayoutAlign="center center" fxLayout="column">
|
||||
<div *ngIf="loginError">
|
||||
{{loginError}}
|
||||
</div>
|
||||
<md-input-container>
|
||||
<input fxFlexFill mdInput autofocus [(ngModel)]="loginCredential.username" name="name" required>
|
||||
<md-placeholder>
|
||||
<i class="material-icons app-input-icon">face</i> Username
|
||||
</md-placeholder>
|
||||
</md-input-container>
|
||||
<md-input-container>
|
||||
<input fxFlexFill mdInput type="password" [(ngModel)]="loginCredential.password" name="password" required>
|
||||
<md-placeholder>
|
||||
<i class="material-icons app-input-icon">lock_open</i> Password
|
||||
</md-placeholder>
|
||||
</md-input-container>
|
||||
<div fxLayout="row" fxLayoutAlign="start center">
|
||||
<md-checkbox [(ngModel)]="loginCredential.rememberM">Remember me</md-checkbox>
|
||||
</div>
|
||||
</md-card-content>
|
||||
<md-card-actions fxLayout="row" fxLayoutAlign="end center">
|
||||
<button md-raised-button color="primary"
|
||||
[disabled]="!LoginForm.form.valid"
|
||||
type="submit"
|
||||
name="action">Login
|
||||
</button>
|
||||
</md-card-actions>
|
||||
</md-card>
|
||||
</form>
|
||||
</div>
|
||||
-->
|
||||
|
@@ -1,9 +1,9 @@
|
||||
import {Component, OnInit} from "@angular/core";
|
||||
import {LoginCredential} from "../../../common/entities/LoginCredential";
|
||||
import {AuthenticationService} from "../model/network/authentication.service";
|
||||
import {Router} from "@angular/router";
|
||||
import {ErrorCodes} from "../../../common/entities/Error";
|
||||
import {Config} from "../../../common/config/public/Config";
|
||||
import {NavigationService} from "../model/navigation.service";
|
||||
|
||||
@Component({
|
||||
selector: 'login',
|
||||
@@ -15,14 +15,14 @@ export class LoginComponent implements OnInit {
|
||||
loginError: any = null;
|
||||
title: string;
|
||||
|
||||
constructor(private _authService: AuthenticationService, private _router: Router) {
|
||||
constructor(private _authService: AuthenticationService, private _navigation: NavigationService) {
|
||||
this.loginCredential = new LoginCredential();
|
||||
this.title = Config.Client.applicationTitle;
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
if (this._authService.isAuthenticated()) {
|
||||
this._router.navigate(['gallery', "/"]);
|
||||
this._navigation.toGallery();
|
||||
}
|
||||
}
|
||||
|
||||
|
38
frontend/app/model/navigation.service.ts
Normal file
38
frontend/app/model/navigation.service.ts
Normal file
@@ -0,0 +1,38 @@
|
||||
import {Injectable} from "@angular/core";
|
||||
|
||||
import {Router} from "@angular/router";
|
||||
import {ShareService} from "../gallery/share.service";
|
||||
|
||||
@Injectable()
|
||||
export class NavigationService {
|
||||
|
||||
|
||||
constructor(private _router: Router,
|
||||
private _shareService: ShareService) {
|
||||
|
||||
}
|
||||
|
||||
public isLoginPage() {
|
||||
return this._router.isActive('login', true) || this._router.isActive('shareLogin', true);
|
||||
}
|
||||
|
||||
public async toLogin() {
|
||||
console.log("toLogin");
|
||||
await this._shareService.wait();
|
||||
if (this._shareService.isSharing()) {
|
||||
return this._router.navigate(["shareLogin"], {queryParams: {sk: this._shareService.getSharingKey()}});
|
||||
} else {
|
||||
return this._router.navigate(["login"]);
|
||||
}
|
||||
}
|
||||
|
||||
public async toGallery() {
|
||||
console.log("toGallery");
|
||||
await this._shareService.wait();
|
||||
if (this._shareService.isSharing()) {
|
||||
return this._router.navigate(["gallery", ""], {queryParams: {sk: this._shareService.getSharingKey()}});
|
||||
} else {
|
||||
return this._router.navigate(["gallery", ""]);
|
||||
}
|
||||
}
|
||||
}
|
@@ -49,6 +49,13 @@ export class AuthenticationService {
|
||||
}
|
||||
|
||||
|
||||
public async shareLogin(password: string): Promise<UserDTO> {
|
||||
const user = await this._userService.shareLogin(password);
|
||||
this.user.next(user);
|
||||
return user;
|
||||
}
|
||||
|
||||
|
||||
public isAuthenticated(): boolean {
|
||||
if (Config.Client.authenticationRequired === false) {
|
||||
return true;
|
||||
@@ -56,7 +63,9 @@ export class AuthenticationService {
|
||||
return !!(this.user.value && this.user.value != null);
|
||||
}
|
||||
|
||||
|
||||
public isAuthorized(role: UserRoles) {
|
||||
return this.user.value && this.user.value.role >= role;
|
||||
}
|
||||
|
||||
public logout() {
|
||||
this._userService.logout();
|
||||
|
@@ -18,7 +18,11 @@ export class UserService {
|
||||
}
|
||||
|
||||
public login(credential: LoginCredential): Promise<UserDTO> {
|
||||
return this._networkService.postJson("/user/login", {"loginCredential": credential});
|
||||
return this._networkService.postJson<UserDTO>("/user/login", {"loginCredential": credential});
|
||||
}
|
||||
|
||||
public async shareLogin(password: string): Promise<UserDTO> {
|
||||
return this._networkService.postJson<UserDTO>("/share/login?sk=" + this._shareService.getSharingKey(), {"password": password});
|
||||
}
|
||||
|
||||
public async getSessionUser(): Promise<UserDTO> {
|
||||
|
@@ -1,12 +1,21 @@
|
||||
import {Injectable} from "@angular/core";
|
||||
import {NetworkService} from "../../model/network/network.service";
|
||||
import {DataBaseConfig, IPrivateConfig} from "../../../../common/config/private/IPrivateConfig";
|
||||
import {NavigationService} from "../../model/navigation.service";
|
||||
import {UserRoles} from "../../../../common/entities/UserDTO";
|
||||
import {AuthenticationService} from "../../model/network/authentication.service";
|
||||
|
||||
@Injectable()
|
||||
export class DatabaseSettingsService {
|
||||
|
||||
|
||||
constructor(private _networkService: NetworkService) {
|
||||
constructor(private _networkService: NetworkService, private _authService: AuthenticationService, private _navigation: NavigationService) {
|
||||
|
||||
if (!this._authService.isAuthenticated() ||
|
||||
this._authService.user.value.role < UserRoles.Admin) {
|
||||
this._navigation.toLogin();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
public async getSettings(): Promise<DataBaseConfig> {
|
||||
|
@@ -1,10 +1,10 @@
|
||||
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";
|
||||
import {NavigationService} from "../../model/navigation.service";
|
||||
|
||||
@Component({
|
||||
selector: 'settings-usermanager',
|
||||
@@ -18,16 +18,18 @@ export class UserMangerSettingsComponent implements OnInit {
|
||||
public userRoles: Array<any> = [];
|
||||
public users: Array<UserDTO> = [];
|
||||
|
||||
constructor(private _authService: AuthenticationService, private _router: Router, private _userSettings: UserManagerSettingsService) {
|
||||
constructor(private _authService: AuthenticationService, private _navigation: NavigationService, private _userSettings: UserManagerSettingsService) {
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
if (!this._authService.isAuthenticated() || this._authService.user.value.role < UserRoles.Admin) {
|
||||
this._router.navigate(['login']);
|
||||
if (!this._authService.isAuthenticated() ||
|
||||
this._authService.user.value.role < UserRoles.Admin) {
|
||||
this._navigation.toLogin();
|
||||
return;
|
||||
}
|
||||
this.userRoles = Utils
|
||||
.enumToArray(UserRoles)
|
||||
.filter(r => r.key != UserRoles.LimitedGuest)
|
||||
.filter(r => r.key <= this._authService.user.value.role)
|
||||
.sort((a, b) => a.key - b.key);
|
||||
|
||||
|
@@ -1,3 +1,57 @@
|
||||
body {
|
||||
background: #eee;
|
||||
.container {
|
||||
}
|
||||
|
||||
.title h1 {
|
||||
font-size: 80px;
|
||||
font-weight: bold;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.title img {
|
||||
height: 80px;
|
||||
}
|
||||
|
||||
.title {
|
||||
margin-top: 40px;
|
||||
width: 100%;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.card {
|
||||
padding: 15px;
|
||||
max-width: 350px;
|
||||
width: 100% !important;
|
||||
background-color: #F7F7F7;
|
||||
margin: 0 auto;
|
||||
border-radius: 2px;
|
||||
box-shadow: 0px 2px 2px rgba(0, 0, 0, 0.3);
|
||||
overflow: hidden;
|
||||
height: 150px;
|
||||
margin-top: 0px;
|
||||
}
|
||||
|
||||
/*Margin by pixel:*/
|
||||
@media screen and ( min-height: 400px ) {
|
||||
.card {
|
||||
margin-top: calc((100vh - 120px - 150px) / 2 - 60px)
|
||||
}
|
||||
}
|
||||
|
||||
.has-margin {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.input-group .form-control, .checkbox {
|
||||
padding: 10px;
|
||||
font-size: 16px;
|
||||
|
||||
}
|
||||
|
||||
.error-message {
|
||||
color: #d9534f;
|
||||
}
|
||||
|
||||
button {
|
||||
width: 100%;
|
||||
font-size: 18px;
|
||||
}
|
||||
|
@@ -1,15 +1,41 @@
|
||||
<div class="container">
|
||||
<div class="col-sm-offset-3 col-sm-6 col-lg-4 col-lg-offset-4">
|
||||
<form class="form-signin" #LoginForm="ngForm">
|
||||
<h2 class="form-signin-heading">The link is password protected</h2>
|
||||
<div *ngIf="loginError">
|
||||
{{loginError}}
|
||||
|
||||
<div class="row title">
|
||||
<h1><img src="assets/icon.png"/>{{title}}</h1>
|
||||
</div>
|
||||
<input type="password" class="form-control" placeholder="Password"
|
||||
[(ngModel)]="loginCredential.password" name="password" required>
|
||||
<br/>
|
||||
<button class="btn btn-lg btn-primary btn-block" [disabled]="!LoginForm.form.valid" (click)="onLogin()">OK
|
||||
|
||||
<div class="row card">
|
||||
<div class="col-md-12">
|
||||
<form name="form" id="form" class="form-horizontal" #LoginForm="ngForm" (submit)="onLogin()">
|
||||
<div class="error-message">
|
||||
{{loginError}}
|
||||
</div>
|
||||
|
||||
<div class="input-group has-margin">
|
||||
<span class="input-group-addon"><i class="glyphicon glyphicon-lock"></i></span>
|
||||
<input id="password"
|
||||
class="form-control"
|
||||
type="password"
|
||||
[(ngModel)]="password"
|
||||
name="password"
|
||||
placeholder="Password"
|
||||
required>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="form-group">
|
||||
<!-- Button -->
|
||||
<div class="col-sm-12 controls">
|
||||
<button class="btn btn-primary pull-right"
|
||||
[disabled]="!LoginForm.form.valid"
|
||||
type="submit"
|
||||
name="action">Enter
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
</div> <!-- /container -->
|
||||
</div>
|
||||
</form>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
@@ -1,8 +1,8 @@
|
||||
import {Component, OnInit} from "@angular/core";
|
||||
import {LoginCredential} from "../../../common/entities/LoginCredential";
|
||||
import {AuthenticationService} from "../model/network/authentication.service";
|
||||
import {Router} from "@angular/router";
|
||||
import {ErrorCodes} from "../../../common/entities/Error";
|
||||
import {Config} from "../../../common/config/public/Config";
|
||||
import {NavigationService} from "../model/navigation.service";
|
||||
|
||||
@Component({
|
||||
selector: 'share-login',
|
||||
@@ -10,16 +10,17 @@ import {ErrorCodes} from "../../../common/entities/Error";
|
||||
styleUrls: ['./share-login.component.css'],
|
||||
})
|
||||
export class ShareLoginComponent implements OnInit {
|
||||
loginCredential: LoginCredential;
|
||||
password: string;
|
||||
loginError: any = null;
|
||||
title: string;
|
||||
|
||||
constructor(private _authService: AuthenticationService, private _router: Router) {
|
||||
this.loginCredential = new LoginCredential();
|
||||
constructor(private _authService: AuthenticationService, private _navigation: NavigationService) {
|
||||
this.title = Config.Client.applicationTitle;
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
if (this._authService.isAuthenticated()) {
|
||||
this._router.navigate(['gallery', "/"]);
|
||||
this._navigation.toGallery();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,11 +28,11 @@ export class ShareLoginComponent implements OnInit {
|
||||
this.loginError = null;
|
||||
|
||||
try {
|
||||
await this._authService.login(this.loginCredential);
|
||||
await this._authService.shareLogin(this.password);
|
||||
|
||||
} catch (error) {
|
||||
if (error && error.code === ErrorCodes.CREDENTIAL_NOT_FOUND) {
|
||||
this.loginError = "Wrong username or password";
|
||||
this.loginError = "Wrong password";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -85,6 +85,7 @@
|
||||
"ng2-slim-loading-bar": "^4.0.0",
|
||||
"ng2-toastr": "^4.1.2",
|
||||
"ngx-bootstrap": "^1.7.1",
|
||||
"ngx-clipboard": "^8.0.3",
|
||||
"phantomjs-prebuilt": "^2.1.14",
|
||||
"protractor": "^5.1.2",
|
||||
"remap-istanbul": "^0.9.5",
|
||||
|
@@ -86,7 +86,7 @@ describe('Authentication middleware', () => {
|
||||
let req: any = {
|
||||
session: {
|
||||
user: {
|
||||
role: UserRoles.Guest
|
||||
role: UserRoles.LimitedGuest
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -94,7 +94,7 @@ describe('Authentication middleware', () => {
|
||||
expect(err).to.be.undefined;
|
||||
done();
|
||||
};
|
||||
AuthenticationMWs.authorise(UserRoles.Guest)(req, null, next);
|
||||
AuthenticationMWs.authorise(UserRoles.LimitedGuest)(req, null, next);
|
||||
|
||||
});
|
||||
|
||||
@@ -102,7 +102,7 @@ describe('Authentication middleware', () => {
|
||||
let req: any = {
|
||||
session: {
|
||||
user: {
|
||||
role: UserRoles.Guest
|
||||
role: UserRoles.LimitedGuest
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -230,7 +230,7 @@ describe('Authentication middleware', () => {
|
||||
let req: any = {
|
||||
session: {
|
||||
user: {
|
||||
role: UserRoles.Guest
|
||||
role: UserRoles.LimitedGuest
|
||||
}
|
||||
}
|
||||
};
|
||||
|
Reference in New Issue
Block a user