mirror of
https://github.com/CaramelFur/Picsur.git
synced 2026-05-07 13:18:04 +02:00
add ability to make image expire
This commit is contained in:
@@ -12,6 +12,11 @@
|
||||
<mat-card-title>{{ image.file_name | truncate }}</mat-card-title>
|
||||
<mat-card-subtitle>
|
||||
Uploaded {{ image.created | amTimeAgo }}
|
||||
{{
|
||||
image.expires_at === null
|
||||
? ''
|
||||
: '| Expires ' + (image.expires_at | amTimeAgo)
|
||||
}}
|
||||
</mat-card-subtitle>
|
||||
</mat-card-header>
|
||||
<picsur-img
|
||||
|
||||
@@ -5,6 +5,7 @@ import { ImageFileType } from 'picsur-shared/dist/dto/mimes.dto';
|
||||
import { EImage } from 'picsur-shared/dist/entities/image.entity';
|
||||
import { HasFailed } from 'picsur-shared/dist/types/failable';
|
||||
import { ImageService } from 'src/app/services/api/image.service';
|
||||
import { UserService } from 'src/app/services/api/user.service';
|
||||
import { Logger } from 'src/app/services/logger/logger.service';
|
||||
import { BootstrapService, BSScreenSize } from 'src/app/util/bootstrap.service';
|
||||
import { DialogService } from 'src/app/util/dialog-manager/dialog.service';
|
||||
@@ -27,6 +28,7 @@ export class ImagesComponent implements OnInit {
|
||||
private readonly route: ActivatedRoute,
|
||||
private readonly router: Router,
|
||||
private readonly bootstrapService: BootstrapService,
|
||||
private readonly userService: UserService,
|
||||
private readonly imageService: ImageService,
|
||||
private readonly errorService: ErrorService,
|
||||
private readonly dialogService: DialogService,
|
||||
@@ -44,14 +46,7 @@ export class ImagesComponent implements OnInit {
|
||||
this.page = thispage;
|
||||
|
||||
this.subscribeMobile();
|
||||
|
||||
const list = await this.imageService.ListMyImages(24, this.page - 1);
|
||||
if (HasFailed(list)) {
|
||||
return this.logger.error(list.getReason());
|
||||
}
|
||||
|
||||
this.pages = list.pages;
|
||||
this.images = list.results;
|
||||
this.subscribeUser();
|
||||
}
|
||||
|
||||
@AutoUnsubscribe()
|
||||
@@ -67,6 +62,19 @@ export class ImagesComponent implements OnInit {
|
||||
});
|
||||
}
|
||||
|
||||
@AutoUnsubscribe()
|
||||
private subscribeUser() {
|
||||
return this.userService.live.subscribe(async () => {
|
||||
const list = await this.imageService.ListMyImages(24, this.page - 1);
|
||||
if (HasFailed(list)) {
|
||||
return this.logger.error(list.getReason());
|
||||
}
|
||||
|
||||
this.pages = list.pages;
|
||||
this.images = list.results;
|
||||
});
|
||||
}
|
||||
|
||||
getThumbnailUrl(image: EImage) {
|
||||
return (
|
||||
this.imageService.GetImageURL(image.id, ImageFileType.QOI) +
|
||||
|
||||
@@ -91,6 +91,6 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="dialog-buttons">
|
||||
<button mat-stroked-button (click)="close()">Close</button>
|
||||
<button mat-flat-button (click)="close()">CLOSE</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
<div class="dialog-text">
|
||||
<div class="row">
|
||||
<div class="col-12">
|
||||
<h1>Edit Image Properties</h1>
|
||||
</div>
|
||||
<div class="col-12">
|
||||
<mat-form-field appearance="outline" color="accent">
|
||||
<mat-label>Title</mat-label>
|
||||
<input matInput type="text" [(ngModel)]="image.file_name" />
|
||||
</mat-form-field>
|
||||
</div>
|
||||
<div class="col-12">
|
||||
<mat-form-field>
|
||||
<mat-label>Expires After</mat-label>
|
||||
<mat-select [(value)]="expiresAfter" >
|
||||
<mat-option *ngFor="let option of ExpireOptions" [value]="option[1]">
|
||||
{{ option[0] }}
|
||||
</mat-option>
|
||||
</mat-select>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
</div>
|
||||
<div class="dialog-buttons">
|
||||
<button mat-flat-button (click)="close()">CANCEL</button>
|
||||
<button mat-raised-button color="accent" (click)="save()">SAVE</button>
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,3 @@
|
||||
mat-form-field {
|
||||
width: 100%;
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
import { Component, Inject, OnInit } from '@angular/core';
|
||||
import { MatDialogRef, MAT_DIALOG_DATA } from '@angular/material/dialog';
|
||||
import { EImage } from 'picsur-shared/dist/entities/image.entity';
|
||||
import { HasFailed } from 'picsur-shared/dist/types';
|
||||
import { ImageService } from 'src/app/services/api/image.service';
|
||||
import { Logger } from 'src/app/services/logger/logger.service';
|
||||
import { ErrorService } from 'src/app/util/error-manager/error.service';
|
||||
|
||||
export interface EditDialogData {
|
||||
image: EImage;
|
||||
}
|
||||
|
||||
@Component({
|
||||
selector: 'edit-dialog',
|
||||
templateUrl: './edit-dialog.component.html',
|
||||
styleUrls: ['./edit-dialog.component.scss'],
|
||||
})
|
||||
export class EditDialogComponent implements OnInit {
|
||||
private readonly logger = new Logger(EditDialogComponent.name);
|
||||
|
||||
public readonly ExpireOptions: Array<[string, null | number]> = [
|
||||
['Never', 0],
|
||||
['5 Minutes', 5 * 60],
|
||||
['10 Minutes', 10 * 60],
|
||||
['30 Minutes', 15 * 60],
|
||||
['1 Hour', 60 * 60],
|
||||
['6 Hours', 2 * 60 * 60],
|
||||
['12 Hours', 12 * 60 * 60],
|
||||
['1 Day', 24 * 60 * 60],
|
||||
['1 Week', 7 * 24 * 60 * 60],
|
||||
['1 Month', 30 * 24 * 60 * 60],
|
||||
];
|
||||
|
||||
public expiresAfter: number = 0;
|
||||
public image: EImage;
|
||||
|
||||
constructor(
|
||||
public readonly dialogRef: MatDialogRef<EditDialogComponent>,
|
||||
private readonly imageService: ImageService,
|
||||
private readonly errorService: ErrorService,
|
||||
@Inject(MAT_DIALOG_DATA) data: EditDialogData,
|
||||
) {
|
||||
if (!data.image) {
|
||||
throw new Error('imageID is required');
|
||||
}
|
||||
|
||||
this.image = data.image;
|
||||
}
|
||||
|
||||
async ngOnInit() {
|
||||
console.log(this.image);
|
||||
}
|
||||
|
||||
close() {
|
||||
this.dialogRef.close(null);
|
||||
}
|
||||
|
||||
async save() {
|
||||
const result = await this.imageService.UpdateImage(this.image.id, {
|
||||
file_name: this.image.file_name,
|
||||
expires_at:
|
||||
this.expiresAfter === 0
|
||||
? null
|
||||
: new Date(Date.now() + this.expiresAfter * 1000),
|
||||
});
|
||||
|
||||
if (HasFailed(result)) {
|
||||
this.errorService.showFailure(result, this.logger);
|
||||
return this.close();
|
||||
}
|
||||
|
||||
this.errorService.success('Image successfully updated');
|
||||
|
||||
this.dialogRef.close(result);
|
||||
}
|
||||
}
|
||||
@@ -8,7 +8,14 @@
|
||||
</div>
|
||||
|
||||
<div class="col-12" *ngIf="image !== null">
|
||||
<h3>Uploaded {{ image.created | amTimeAgo }}</h3>
|
||||
<h3>
|
||||
Uploaded {{ image.created | amTimeAgo }}
|
||||
{{
|
||||
image.expires_at === null
|
||||
? ''
|
||||
: '| Expires ' + (image.expires_at | amTimeAgo)
|
||||
}}
|
||||
</h3>
|
||||
</div>
|
||||
|
||||
<div class="col-12 py-3">
|
||||
@@ -66,7 +73,15 @@
|
||||
<mat-icon fontSet="material-icons-outlined"> share </mat-icon>
|
||||
</button>
|
||||
<button
|
||||
*ngIf="canDelete"
|
||||
*ngIf="canManage"
|
||||
mat-mini-fab
|
||||
matTooltip="Edit image"
|
||||
(click)="editImage()"
|
||||
>
|
||||
<mat-icon fontSet="material-icons-outlined"> edit </mat-icon>
|
||||
</button>
|
||||
<button
|
||||
*ngIf="canManage"
|
||||
mat-mini-fab
|
||||
matTooltip="Delete image"
|
||||
(click)="deleteImage()"
|
||||
|
||||
@@ -28,6 +28,10 @@ import {
|
||||
CustomizeDialogComponent,
|
||||
CustomizeDialogData,
|
||||
} from './customize-dialog/customize-dialog.component';
|
||||
import {
|
||||
EditDialogComponent,
|
||||
EditDialogData,
|
||||
} from './edit-dialog/edit-dialog.component';
|
||||
|
||||
@Component({
|
||||
templateUrl: './view.component.html',
|
||||
@@ -70,7 +74,7 @@ export class ViewComponent implements OnInit {
|
||||
public image: EImage | null = null;
|
||||
public imageUser: EUser | null = null;
|
||||
|
||||
public canDelete: boolean = false;
|
||||
public canManage: boolean = false;
|
||||
|
||||
async ngOnInit() {
|
||||
this.subscribePermissions();
|
||||
@@ -194,6 +198,26 @@ export class ViewComponent implements OnInit {
|
||||
);
|
||||
}
|
||||
|
||||
async editImage() {
|
||||
if (this.image === null) return;
|
||||
|
||||
const options: EditDialogData = {
|
||||
image: { ...this.image },
|
||||
};
|
||||
|
||||
const res: EImage | null = await this.dialogService.showCustomDialog(
|
||||
EditDialogComponent,
|
||||
options,
|
||||
{
|
||||
dismissable: false,
|
||||
},
|
||||
);
|
||||
|
||||
if (res !== null) {
|
||||
this.image = res;
|
||||
}
|
||||
}
|
||||
|
||||
@AutoUnsubscribe()
|
||||
private subscribePermissions() {
|
||||
return this.permissionService.live.subscribe(
|
||||
@@ -204,21 +228,21 @@ export class ViewComponent implements OnInit {
|
||||
private updatePermissions() {
|
||||
const permissions = this.permissionService.snapshot;
|
||||
if (permissions.includes(Permission.ImageAdmin)) {
|
||||
this.canDelete = true;
|
||||
this.canManage = true;
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.imageUser === null) return;
|
||||
|
||||
if (
|
||||
permissions.includes(Permission.ImageUpload) &&
|
||||
permissions.includes(Permission.ImageManage) &&
|
||||
this.imageUser.id === this.userService.snapshot?.id
|
||||
) {
|
||||
this.canDelete = true;
|
||||
this.canManage = true;
|
||||
return;
|
||||
}
|
||||
|
||||
this.canDelete = false;
|
||||
this.canManage = false;
|
||||
}
|
||||
|
||||
private updateFormatOptions() {
|
||||
|
||||
@@ -17,10 +17,12 @@ import { PipesModule } from 'src/app/pipes/pipes.module';
|
||||
import { DownloadManagerModule } from 'src/app/util/download-manager/dialog-manager.module';
|
||||
import { ErrorManagerModule } from 'src/app/util/error-manager/error-manager.module';
|
||||
import { CustomizeDialogComponent } from './customize-dialog/customize-dialog.component';
|
||||
import { EditDialogComponent } from './edit-dialog/edit-dialog.component';
|
||||
import { ViewComponent } from './view.component';
|
||||
import { ViewRoutingModule } from './view.routing.module';
|
||||
|
||||
@NgModule({
|
||||
declarations: [ViewComponent, CustomizeDialogComponent],
|
||||
declarations: [ViewComponent, CustomizeDialogComponent, EditDialogComponent],
|
||||
imports: [
|
||||
CommonModule,
|
||||
ErrorManagerModule,
|
||||
|
||||
@@ -4,6 +4,8 @@ import {
|
||||
ImageDeleteResponse,
|
||||
ImageListRequest,
|
||||
ImageListResponse,
|
||||
ImageUpdateRequest,
|
||||
ImageUpdateResponse,
|
||||
ImageUploadResponse,
|
||||
} from 'picsur-shared/dist/dto/api/image-manage.dto';
|
||||
import {
|
||||
@@ -79,6 +81,21 @@ export class ImageService {
|
||||
return await this.ListAllImages(count, page, userID);
|
||||
}
|
||||
|
||||
public async UpdateImage(
|
||||
id: string,
|
||||
settings: Partial<Pick<EImage, 'file_name' | 'expires_at'>>,
|
||||
): AsyncFailable<EImage> {
|
||||
return await this.api.post(
|
||||
ImageUpdateRequest,
|
||||
ImageUpdateResponse,
|
||||
'/api/image/update',
|
||||
{
|
||||
id,
|
||||
...settings,
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
public async DeleteImages(
|
||||
images: string[],
|
||||
): AsyncFailable<ImageDeleteResponse> {
|
||||
|
||||
Reference in New Issue
Block a user