Skip to content

Commit

Permalink
Implement basic sharing listing on UI #607
Browse files Browse the repository at this point in the history
  • Loading branch information
bpatrik committed Aug 11, 2023
1 parent d35d9e8 commit 4c10f9d
Show file tree
Hide file tree
Showing 12 changed files with 174 additions and 67 deletions.
59 changes: 46 additions & 13 deletions src/backend/middlewares/SharingMWs.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import { NextFunction, Request, Response } from 'express';
import { CreateSharingDTO, SharingDTO } from '../../common/entities/SharingDTO';
import { ObjectManagers } from '../model/ObjectManagers';
import { ErrorCodes, ErrorDTO } from '../../common/entities/Error';
import { Config } from '../../common/config/private/Config';
import { QueryParams } from '../../common/QueryParams';
import {NextFunction, Request, Response} from 'express';
import {CreateSharingDTO, SharingDTO} from '../../common/entities/SharingDTO';
import {ObjectManagers} from '../model/ObjectManagers';
import {ErrorCodes, ErrorDTO} from '../../common/entities/Error';
import {Config} from '../../common/config/private/Config';
import {QueryParams} from '../../common/QueryParams';
import * as path from 'path';
import { UserRoles } from '../../common/entities/UserDTO';
import {UserRoles} from '../../common/entities/UserDTO';

export class SharingMWs {
public static async getSharing(
Expand All @@ -20,9 +20,7 @@ export class SharingMWs {

try {
req.resultPipe =
await ObjectManagers.getInstance().SharingManager.findOne({
sharingKey,
});
await ObjectManagers.getInstance().SharingManager.findOne(sharingKey);
return next();
} catch (err) {
return next(
Expand Down Expand Up @@ -58,9 +56,7 @@ export class SharingMWs {
// eslint-disable-next-line no-constant-condition
while (true) {
try {
await ObjectManagers.getInstance().SharingManager.findOne({
sharingKey,
});
await ObjectManagers.getInstance().SharingManager.findOne(sharingKey);
sharingKey = this.generateKey();
} catch (err) {
break;
Expand Down Expand Up @@ -173,6 +169,13 @@ export class SharingMWs {
const sharingKey: string = req.params['sharingKey'];

try {
// Check if user has the right to delete sharing.
if (req.session['user'].role < UserRoles.Admin) {
const s = await ObjectManagers.getInstance().SharingManager.findOne(sharingKey);
if (s.creator.id !== req.session['user'].id) {
return next(new ErrorDTO(ErrorCodes.NOT_AUTHORISED, 'Can\'t delete sharing.'));
}
}
req.resultPipe =
await ObjectManagers.getInstance().SharingManager.deleteSharing(
sharingKey
Expand Down Expand Up @@ -213,6 +216,36 @@ export class SharingMWs {
}
}

public static async listSharingForDir(
req: Request,
res: Response,
next: NextFunction
): Promise<void> {
if (Config.Sharing.enabled === false) {
return next();
}

const dir = path.normalize(req.params['directory'] || '/');
try {
if (req.session['user'].role >= UserRoles.Admin) {
req.resultPipe =
await ObjectManagers.getInstance().SharingManager.listAllForDir(dir);
} else {
req.resultPipe =
await ObjectManagers.getInstance().SharingManager.listAllForDir(dir, req.session['user']);
}
return next();
} catch (err) {
return next(
new ErrorDTO(
ErrorCodes.GENERAL_ERROR,
'Error during listing shares',
err
)
);
}
}

private static generateKey(): string {
function s4(): string {
return Math.floor((1 + Math.random()) * 0x10000)
Expand Down
12 changes: 2 additions & 10 deletions src/backend/middlewares/user/AuthenticationMWs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -151,11 +151,7 @@ export class AuthenticationMWs {
const sharingKey: string =
(req.query[QueryParams.gallery.sharingKey_query] as string) ||
(req.params[QueryParams.gallery.sharingKey_params] as string);
const sharing = await ObjectManagers.getInstance().SharingManager.findOne(
{
sharingKey,
}
);
const sharing = await ObjectManagers.getInstance().SharingManager.findOne(sharingKey);

if (
!sharing ||
Expand Down Expand Up @@ -264,11 +260,7 @@ export class AuthenticationMWs {
const sharingKey: string =
(req.query[QueryParams.gallery.sharingKey_query] as string) ||
(req.params[QueryParams.gallery.sharingKey_params] as string);
const sharing = await ObjectManagers.getInstance().SharingManager.findOne(
{
sharingKey,
}
);
const sharing = await ObjectManagers.getInstance().SharingManager.findOne(sharingKey);
if (!sharing || sharing.expires < Date.now()) {
return null;
}
Expand Down
26 changes: 23 additions & 3 deletions src/backend/model/database/SharingManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@ import {SQLConnection} from './SQLConnection';
import {SharingEntity} from './enitites/SharingEntity';
import {Config} from '../../../common/config/private/Config';
import {PasswordHelper} from '../PasswordHelper';
import {DeleteResult, FindOptionsWhere} from 'typeorm';
import {DeleteResult, SelectQueryBuilder} from 'typeorm';
import {UserDTO} from '../../../common/entities/UserDTO';

export class SharingManager {
private static async removeExpiredLink(): Promise<DeleteResult> {
Expand Down Expand Up @@ -34,10 +35,29 @@ export class SharingManager {
.getMany();
}

async findOne(filter: FindOptionsWhere<SharingDTO>): Promise<SharingDTO> {

async listAllForDir(dir: string, user?: UserDTO): Promise<SharingDTO[]> {
await SharingManager.removeExpiredLink();
const connection = await SQLConnection.getConnection();
return await connection.getRepository(SharingEntity).findOneBy(filter);
const q: SelectQueryBuilder<SharingEntity> = connection
.getRepository(SharingEntity)
.createQueryBuilder('share')
.leftJoinAndSelect('share.creator', 'creator')
.where('path = :dir', {dir});
if (user) {
q.andWhere('share.creator = :user', {user: user.id});
}
return await q.getMany();
}

async findOne(sharingKey: string): Promise<SharingDTO> {
await SharingManager.removeExpiredLink();
const connection = await SQLConnection.getConnection();
return await connection.getRepository(SharingEntity)
.createQueryBuilder('share')
.leftJoinAndSelect('share.creator', 'creator')
.where('share.sharingKey = :sharingKey', {sharingKey})
.getOne();
}

async createSharing(sharing: SharingDTO): Promise<SharingDTO> {
Expand Down
20 changes: 17 additions & 3 deletions src/backend/routes/SharingRouter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ export class SharingRouter {
this.addCreateSharing(app);
this.addUpdateSharing(app);
this.addListSharing(app);
this.addListSharingForDir(app);
this.addDeleteSharing(app);
}

Expand Down Expand Up @@ -64,7 +65,7 @@ export class SharingRouter {
app.delete(
[Config.Server.apiPath + '/share/:' + QueryParams.gallery.sharingKey_params],
AuthenticationMWs.authenticate,
AuthenticationMWs.authorise(UserRoles.Admin),
AuthenticationMWs.authorise(UserRoles.User),
SharingMWs.deleteSharing,
ServerTimingMWs.addServerTiming,
RenderingMWs.renderResult
Expand All @@ -73,12 +74,25 @@ export class SharingRouter {

private static addListSharing(app: express.Express): void {
app.get(
[Config.Server.apiPath + '/share/list'],
[Config.Server.apiPath + '/share/listAll'],
AuthenticationMWs.authenticate,
AuthenticationMWs.authorise(UserRoles.User),
AuthenticationMWs.authorise(UserRoles.Admin),
SharingMWs.listSharing,
ServerTimingMWs.addServerTiming,
RenderingMWs.renderSharingList
);
}

private static addListSharingForDir(app: express.Express): void {
app.get(
[Config.Server.apiPath + '/share/list/:directory(*)',
Config.Server.apiPath + '/share/list//',
Config.Server.apiPath + '/share/list'],
AuthenticationMWs.authenticate,
AuthenticationMWs.authorise(UserRoles.User),
SharingMWs.listSharingForDir,
ServerTimingMWs.addServerTiming,
RenderingMWs.renderSharingList
);
}
}
26 changes: 26 additions & 0 deletions src/frontend/app/ui/gallery/share.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ import {BehaviorSubject} from 'rxjs';
import {distinctUntilChanged, filter} from 'rxjs/operators';
import {QueryParams} from '../../../../common/QueryParams';
import {UserDTO} from '../../../../common/entities/UserDTO';
import {Utils} from '../../../../common/Utils';
import {Config} from '../../../../common/config/public/Config';


@Injectable()
Expand Down Expand Up @@ -61,6 +63,11 @@ export class ShareService {
});
}

public getUrl(share: SharingDTO): string {
return Utils.concatUrls(Config.Server.publicUrl, '/share/', share.sharingKey);
}


onNewUser = async (user: UserDTO) => {
if (user && !!user.usedSharingKey) {
if (
Expand Down Expand Up @@ -135,4 +142,23 @@ export class ShareService {
console.error(e);
}
}

public async getSharingListForDir(
dir: string
): Promise<SharingDTO[]> {
return this.networkService.getJson('/share/list/' + dir);
}



public getSharingList(): Promise<SharingDTO[]> {
if (!Config.Sharing.enabled) {
return Promise.resolve([]);
}
return this.networkService.getJson('/share/listAll');
}

public deleteSharing(sharing: SharingDTO): Promise<void> {
return this.networkService.deleteJson('/share/' + sharing.sharingKey);
}
}
27 changes: 27 additions & 0 deletions src/frontend/app/ui/gallery/share/share.gallery.component.html
Original file line number Diff line number Diff line change
Expand Up @@ -117,5 +117,32 @@ <h5 class="modal-title" i18n>Share</h5>
</div>
</div>
</form>
<ng-container *ngIf="activeShares && activeShares.length>0">
<hr/>
<table class="table table-hover">
<thead>
<tr>
<th i18n>Key</th>
<th i18n>Creator</th>
<th i18n>Expires</th>
<th></th>
</tr>
</thead>
<tbody>
<tr *ngFor="let share of activeShares">
<td><a [href]="sharingService.getUrl(share)">{{share.sharingKey}}</a></td>
<td>{{share.creator.name}}</td>
<td>{{share.expires | date}}</td>
<td>
<button (click)="deleteSharing(share)"
[disabled]="share.sharingKey == sharing?.sharingKey"
class="btn btn-danger float-end">
<span class="oi oi-trash" aria-hidden="true" aria-label="Delete"></span>
</button>
</td>
</tr>
</tbody>
</table>
</ng-container>
</div>
</ng-template>
24 changes: 22 additions & 2 deletions src/frontend/app/ui/gallery/share/share.gallery.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,13 +37,15 @@ export class GalleryShareComponent implements OnInit, OnDestroy {
modalRef: BsModalRef;
invalidSettings = $localize`Invalid settings`;

activeShares: SharingDTO[] = [];

text = {
Yes: 'Yes',
No: 'No',
};

constructor(
private sharingService: ShareService,
public sharingService: ShareService,
public galleryService: ContentService,
private notification: NotificationService,
private modalService: BsModalService
Expand All @@ -54,7 +56,8 @@ export class GalleryShareComponent implements OnInit, OnDestroy {

ngOnInit(): void {
this.contentSubscription = this.galleryService.content.subscribe(
(content: ContentWrapper) => {
async (content: ContentWrapper) => {
this.activeShares = [];
this.enabled = !!content.directory;
if (!this.enabled) {
return;
Expand All @@ -63,6 +66,7 @@ export class GalleryShareComponent implements OnInit, OnDestroy {
content.directory.path,
content.directory.name
);
await this.updateActiveSharesList();
}
);
}
Expand All @@ -73,6 +77,21 @@ export class GalleryShareComponent implements OnInit, OnDestroy {
}
}


async deleteSharing(sharing: SharingDTO): Promise<void> {
await this.sharingService.deleteSharing(sharing);
await this.updateActiveSharesList();
}

private async updateActiveSharesList() {
try {
this.activeShares = await this.sharingService.getSharingListForDir(this.currentDir);
} catch (e) {
this.activeShares = [];
console.error(e);
}
}

calcValidity(): number {
switch (parseInt(this.input.valid.type.toString(), 10)) {
case ValidityTypes.Minutes:
Expand Down Expand Up @@ -112,6 +131,7 @@ export class GalleryShareComponent implements OnInit, OnDestroy {
this.calcValidity()
);
this.url = Utils.concatUrls(Config.Server.publicUrl, '/share/', this.sharing.sharingKey);
await this.updateActiveSharesList();
}

async openModal(template: TemplateRef<unknown>): Promise<void> {
Expand Down
3 changes: 3 additions & 0 deletions src/frontend/app/ui/settings/settings.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@ import {DefaultsJobs} from '../../../../common/entities/job/JobDTO';
import {StatisticDTO} from '../../../../common/entities/settings/StatisticDTO';
import {ScheduledJobsService} from './scheduled-jobs.service';
import {IWebConfigClassPrivate} from '../../../../../node_modules/typeconfig/src/decorators/class/IWebConfigClass';
import {SharingDTO} from '../../../../common/entities/SharingDTO';
import {Utils} from '../../../../common/Utils';
import {Config} from '../../../../common/config/public/Config';


export enum ConfigStyle {
Expand Down
26 changes: 0 additions & 26 deletions src/frontend/app/ui/settings/sharings-list/sharing-list.service.ts

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ <h5 i18n>Active shares</h5>
</thead>
<tbody>
<tr *ngFor="let share of shares">
<td><a [href]="sharingUrl + share.sharingKey">{{share.sharingKey}}</a></td>
<td><a [href]="sharingService.getUrl(share)">{{share.sharingKey}}</a></td>
<td>{{share.path}}</td>
<td>{{share.creator.name}}</td>
<td>{{share.expires | date}}</td>
Expand Down
Loading

0 comments on commit 4c10f9d

Please sign in to comment.