mirror of
https://github.com/CaramelFur/Picsur.git
synced 2025-11-12 23:05:39 +01:00
link image with user
This commit is contained in:
@@ -19,11 +19,13 @@ export class ImageDBService {
|
|||||||
private imageDerivativeRepo: Repository<EImageDerivativeBackend>,
|
private imageDerivativeRepo: Repository<EImageDerivativeBackend>,
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
public async create(): AsyncFailable<EImageBackend> {
|
public async create(userid: string): AsyncFailable<EImageBackend> {
|
||||||
let imageEntity = new EImageBackend();
|
let imageEntity = new EImageBackend();
|
||||||
|
imageEntity.user_id = userid;
|
||||||
|
imageEntity.created = new Date();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
imageEntity = await this.imageRepo.save(imageEntity);
|
imageEntity = await this.imageRepo.save(imageEntity, { reload: true });
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
return Fail(e);
|
return Fail(e);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -86,10 +86,7 @@ export class ImageFileDBService {
|
|||||||
|
|
||||||
if (!found) return Fail('Image not found');
|
if (!found) return Fail('Image not found');
|
||||||
return Object.fromEntries(
|
return Object.fromEntries(
|
||||||
types.map((type) => [
|
types.map((type) => [type, found.find((f) => f.type === type)?.mime]),
|
||||||
type,
|
|
||||||
found.find((f) => f.type === type)?.mime,
|
|
||||||
]),
|
|
||||||
);
|
);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
return Fail(e);
|
return Fail(e);
|
||||||
@@ -107,7 +104,7 @@ export class ImageFileDBService {
|
|||||||
imageDerivative.key = key;
|
imageDerivative.key = key;
|
||||||
imageDerivative.mime = mime;
|
imageDerivative.mime = mime;
|
||||||
imageDerivative.data = file;
|
imageDerivative.data = file;
|
||||||
imageDerivative.last_read_unix_sec = Math.floor(Date.now() / 1000);
|
imageDerivative.last_read = new Date();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
return await this.imageDerivativeRepo.save(imageDerivative);
|
return await this.imageDerivativeRepo.save(imageDerivative);
|
||||||
@@ -126,9 +123,9 @@ export class ImageFileDBService {
|
|||||||
});
|
});
|
||||||
if (!derivative) return null;
|
if (!derivative) return null;
|
||||||
|
|
||||||
const unix_seconds = Math.floor(Date.now() / 1000);
|
const yesterday = new Date(Date.now() - A_DAY_IN_SECONDS * 1000);
|
||||||
if (derivative.last_read_unix_sec > unix_seconds - A_DAY_IN_SECONDS) {
|
if (derivative.last_read > yesterday) {
|
||||||
derivative.last_read_unix_sec = unix_seconds;
|
derivative.last_read = new Date();
|
||||||
return await this.imageDerivativeRepo.save(derivative);
|
return await this.imageDerivativeRepo.save(derivative);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -159,9 +156,8 @@ export class ImageFileDBService {
|
|||||||
olderThanSeconds: number,
|
olderThanSeconds: number,
|
||||||
): AsyncFailable<number> {
|
): AsyncFailable<number> {
|
||||||
try {
|
try {
|
||||||
const unix_seconds = Math.floor(Date.now() / 1000);
|
|
||||||
const result = await this.imageDerivativeRepo.delete({
|
const result = await this.imageDerivativeRepo.delete({
|
||||||
last_read_unix_sec: LessThan(unix_seconds - olderThanSeconds),
|
last_read: LessThan(new Date()),
|
||||||
});
|
});
|
||||||
|
|
||||||
return result.affected ?? 0;
|
return result.affected ?? 0;
|
||||||
|
|||||||
@@ -66,7 +66,7 @@ export class SuccessInterceptor<T> implements NestInterceptor {
|
|||||||
const parseResult = schema.safeParse(data);
|
const parseResult = schema.safeParse(data);
|
||||||
if (!parseResult.success) {
|
if (!parseResult.success) {
|
||||||
this.logger.warn(
|
this.logger.warn(
|
||||||
`Function ${context.getHandler().name} failed validation`,
|
`Function ${context.getHandler().name} failed validation: ${parseResult.error}`,
|
||||||
);
|
);
|
||||||
throw new InternalServerErrorException(
|
throw new InternalServerErrorException(
|
||||||
'Server produced invalid response',
|
'Server produced invalid response',
|
||||||
|
|||||||
@@ -37,12 +37,6 @@ export class ImageManagerService {
|
|||||||
return await this.imagesService.findOne(id);
|
return await this.imagesService.findOne(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Image data buffer is not included by default, this also returns that buffer
|
|
||||||
// Dont send to client, keep in backend
|
|
||||||
public async retrieveComplete(id: string): AsyncFailable<EImageBackend> {
|
|
||||||
return await this.imagesService.findOne(id);
|
|
||||||
}
|
|
||||||
|
|
||||||
public async upload(
|
public async upload(
|
||||||
image: Buffer,
|
image: Buffer,
|
||||||
userid: string,
|
userid: string,
|
||||||
@@ -62,7 +56,7 @@ export class ImageManagerService {
|
|||||||
if (HasFailed(processResult)) return processResult;
|
if (HasFailed(processResult)) return processResult;
|
||||||
|
|
||||||
// Save processed to db
|
// Save processed to db
|
||||||
const imageEntity = await this.imagesService.create();
|
const imageEntity = await this.imagesService.create(userid);
|
||||||
if (HasFailed(imageEntity)) return imageEntity;
|
if (HasFailed(imageEntity)) return imageEntity;
|
||||||
|
|
||||||
const imageFileEntity = await this.imageFilesService.setFile(
|
const imageFileEntity = await this.imageFilesService.setFile(
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ export class EImageDerivativeBackend {
|
|||||||
mime: string;
|
mime: string;
|
||||||
|
|
||||||
@Column({ name: 'last_read', nullable: false })
|
@Column({ name: 'last_read', nullable: false })
|
||||||
last_read_unix_sec: number;
|
last_read: Date;
|
||||||
|
|
||||||
// Binary data
|
// Binary data
|
||||||
@Column({ type: 'bytea', nullable: false })
|
@Column({ type: 'bytea', nullable: false })
|
||||||
|
|||||||
@@ -1,8 +1,18 @@
|
|||||||
import { EImage } from 'picsur-shared/dist/entities/image.entity';
|
import { EImage } from 'picsur-shared/dist/entities/image.entity';
|
||||||
import { Entity, PrimaryGeneratedColumn } from 'typeorm';
|
import { Column, Entity, PrimaryGeneratedColumn } from 'typeorm';
|
||||||
|
|
||||||
@Entity()
|
@Entity()
|
||||||
export class EImageBackend implements EImage {
|
export class EImageBackend implements EImage {
|
||||||
@PrimaryGeneratedColumn('uuid')
|
@PrimaryGeneratedColumn('uuid')
|
||||||
id: string;
|
id: string;
|
||||||
|
|
||||||
|
@Column({
|
||||||
|
nullable: false,
|
||||||
|
})
|
||||||
|
user_id: string;
|
||||||
|
|
||||||
|
@Column({
|
||||||
|
nullable: false
|
||||||
|
})
|
||||||
|
created: Date;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ type OverriddenEUser = z.infer<typeof OverriddenEUserSchema>;
|
|||||||
@Entity()
|
@Entity()
|
||||||
export class EUserBackend implements OverriddenEUser {
|
export class EUserBackend implements OverriddenEUser {
|
||||||
@PrimaryGeneratedColumn('uuid', {})
|
@PrimaryGeneratedColumn('uuid', {})
|
||||||
id?: string;
|
id: string;
|
||||||
|
|
||||||
@Index()
|
@Index()
|
||||||
@Column({ nullable: false, unique: true })
|
@Column({ nullable: false, unique: true })
|
||||||
|
|||||||
@@ -7,15 +7,16 @@ import {
|
|||||||
NotFoundException,
|
NotFoundException,
|
||||||
Post,
|
Post,
|
||||||
Query,
|
Query,
|
||||||
Res
|
Res,
|
||||||
} from '@nestjs/common';
|
} from '@nestjs/common';
|
||||||
import { FastifyReply } from 'fastify';
|
import { FastifyReply } from 'fastify';
|
||||||
import {
|
import {
|
||||||
ImageMetaResponse,
|
ImageMetaResponse,
|
||||||
ImageRequestParams,
|
ImageRequestParams,
|
||||||
ImageUploadResponse
|
ImageUploadResponse,
|
||||||
} from 'picsur-shared/dist/dto/api/image.dto';
|
} from 'picsur-shared/dist/dto/api/image.dto';
|
||||||
import { HasFailed } from 'picsur-shared/dist/types';
|
import { HasFailed } from 'picsur-shared/dist/types';
|
||||||
|
import { UsersService } from '../../collections/user-db/user-db.service';
|
||||||
import { ImageFullIdParam } from '../../decorators/image-id/image-full-id.decorator';
|
import { ImageFullIdParam } from '../../decorators/image-id/image-full-id.decorator';
|
||||||
import { ImageIdParam } from '../../decorators/image-id/image-id.decorator';
|
import { ImageIdParam } from '../../decorators/image-id/image-id.decorator';
|
||||||
import { MultiPart } from '../../decorators/multipart/multipart.decorator';
|
import { MultiPart } from '../../decorators/multipart/multipart.decorator';
|
||||||
@@ -26,6 +27,7 @@ import { ImageManagerService } from '../../managers/image/image.service';
|
|||||||
import { ImageFullId } from '../../models/constants/image-full-id.const';
|
import { ImageFullId } from '../../models/constants/image-full-id.const';
|
||||||
import { Permission } from '../../models/constants/permissions.const';
|
import { Permission } from '../../models/constants/permissions.const';
|
||||||
import { ImageUploadDto } from '../../models/dto/image-upload.dto';
|
import { ImageUploadDto } from '../../models/dto/image-upload.dto';
|
||||||
|
import { EUserBackend2EUser } from '../../models/transformers/user.transformer';
|
||||||
|
|
||||||
// This is the only controller with CORS enabled
|
// This is the only controller with CORS enabled
|
||||||
@Controller('i')
|
@Controller('i')
|
||||||
@@ -33,7 +35,10 @@ import { ImageUploadDto } from '../../models/dto/image-upload.dto';
|
|||||||
export class ImageController {
|
export class ImageController {
|
||||||
private readonly logger = new Logger('ImageController');
|
private readonly logger = new Logger('ImageController');
|
||||||
|
|
||||||
constructor(private readonly imagesService: ImageManagerService) {}
|
constructor(
|
||||||
|
private readonly imagesService: ImageManagerService,
|
||||||
|
private readonly userService: UsersService,
|
||||||
|
) {}
|
||||||
|
|
||||||
@Get(':id')
|
@Get(':id')
|
||||||
async getImage(
|
async getImage(
|
||||||
@@ -96,13 +101,20 @@ export class ImageController {
|
|||||||
throw new NotFoundException('Could not find image');
|
throw new NotFoundException('Could not find image');
|
||||||
}
|
}
|
||||||
|
|
||||||
const fileMimes = await this.imagesService.getAllFileMimes(id);
|
const [fileMimes, imageUser] = await Promise.all([
|
||||||
|
this.imagesService.getAllFileMimes(id),
|
||||||
|
this.userService.findOne(image.user_id),
|
||||||
|
]);
|
||||||
if (HasFailed(fileMimes)) {
|
if (HasFailed(fileMimes)) {
|
||||||
this.logger.warn(fileMimes.getReason());
|
this.logger.warn(fileMimes.getReason());
|
||||||
throw new InternalServerErrorException('Could not get image mime');
|
throw new InternalServerErrorException('Could not get image mime');
|
||||||
}
|
}
|
||||||
|
if (HasFailed(imageUser)) {
|
||||||
|
this.logger.warn(imageUser.getReason());
|
||||||
|
throw new InternalServerErrorException('Could not get image user');
|
||||||
|
}
|
||||||
|
|
||||||
return { image, fileMimes };
|
return { image, user: EUserBackend2EUser(imageUser), fileMimes };
|
||||||
}
|
}
|
||||||
|
|
||||||
@Post()
|
@Post()
|
||||||
|
|||||||
@@ -1,10 +1,11 @@
|
|||||||
import { Module } from '@nestjs/common';
|
import { Module } from '@nestjs/common';
|
||||||
|
import { UsersModule } from '../../collections/user-db/user-db.module';
|
||||||
import { DecoratorsModule } from '../../decorators/decorators.module';
|
import { DecoratorsModule } from '../../decorators/decorators.module';
|
||||||
import { ImageManagerModule } from '../../managers/image/image.module';
|
import { ImageManagerModule } from '../../managers/image/image.module';
|
||||||
import { ImageController } from './image.controller';
|
import { ImageController } from './image.controller';
|
||||||
|
|
||||||
@Module({
|
@Module({
|
||||||
imports: [ImageManagerModule, DecoratorsModule],
|
imports: [ImageManagerModule, UsersModule, DecoratorsModule],
|
||||||
controllers: [ImageController],
|
controllers: [ImageController],
|
||||||
})
|
})
|
||||||
export class ImageModule {}
|
export class ImageModule {}
|
||||||
|
|||||||
@@ -27,6 +27,7 @@
|
|||||||
"bootstrap": "^5.1.3",
|
"bootstrap": "^5.1.3",
|
||||||
"fuse.js": "^6.5.3",
|
"fuse.js": "^6.5.3",
|
||||||
"jwt-decode": "^3.1.2",
|
"jwt-decode": "^3.1.2",
|
||||||
|
"moment": "^2.29.3",
|
||||||
"ngx-auto-unsubscribe-decorator": "^1.1.0",
|
"ngx-auto-unsubscribe-decorator": "^1.1.0",
|
||||||
"ngx-dropzone": "^3.1.0",
|
"ngx-dropzone": "^3.1.0",
|
||||||
"picsur-shared": "*",
|
"picsur-shared": "*",
|
||||||
|
|||||||
@@ -1,7 +1,11 @@
|
|||||||
<div class="container centered">
|
<div class="container centered">
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-12">
|
<div class="col-12">
|
||||||
<h1>Uploaded Image</h1>
|
<h1>Image uploaded by {{imageUser?.username}}</h1>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="col-12" *ngIf="image !== null">
|
||||||
|
<h3>{{(timeAgo | async)}}</h3>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="col-12 py-3">
|
<div class="col-12 py-3">
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import { Component, OnInit } from '@angular/core';
|
import { Component, OnInit } from '@angular/core';
|
||||||
import { ActivatedRoute, Router } from '@angular/router';
|
import { ActivatedRoute, Router } from '@angular/router';
|
||||||
|
import moment from 'moment';
|
||||||
import { ImageLinks } from 'picsur-shared/dist/dto/image-links.dto';
|
import { ImageLinks } from 'picsur-shared/dist/dto/image-links.dto';
|
||||||
import {
|
import {
|
||||||
AnimMime,
|
AnimMime,
|
||||||
@@ -10,10 +11,13 @@ import {
|
|||||||
SupportedImageMimes,
|
SupportedImageMimes,
|
||||||
SupportedMimeCategory
|
SupportedMimeCategory
|
||||||
} from 'picsur-shared/dist/dto/mimes.dto';
|
} from 'picsur-shared/dist/dto/mimes.dto';
|
||||||
|
import { EImage } from 'picsur-shared/dist/entities/image.entity';
|
||||||
|
import { EUser } from 'picsur-shared/dist/entities/user.entity';
|
||||||
import { HasFailed, HasSuccess } from 'picsur-shared/dist/types';
|
import { HasFailed, HasSuccess } from 'picsur-shared/dist/types';
|
||||||
import { UUIDRegex } from 'picsur-shared/dist/util/common-regex';
|
import { UUIDRegex } from 'picsur-shared/dist/util/common-regex';
|
||||||
import { ParseMime } from 'picsur-shared/dist/util/parse-mime';
|
import { ParseMime } from 'picsur-shared/dist/util/parse-mime';
|
||||||
import { ImageService } from 'src/app/services/api/image.service';
|
import { ImageService } from 'src/app/services/api/image.service';
|
||||||
|
import { rxjs_poll } from 'src/app/util/poll';
|
||||||
import { UtilService } from 'src/app/util/util-module/util.service';
|
import { UtilService } from 'src/app/util/util-module/util.service';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
@@ -45,6 +49,14 @@ export class ViewComponent implements OnInit {
|
|||||||
public previewLink = '';
|
public previewLink = '';
|
||||||
public imageLinks = new ImageLinks();
|
public imageLinks = new ImageLinks();
|
||||||
|
|
||||||
|
public image: EImage | null = null;
|
||||||
|
public imageUser: EUser | null = null;
|
||||||
|
|
||||||
|
public timeAgo = rxjs_poll(
|
||||||
|
1000,
|
||||||
|
(() => moment(this.image?.created).fromNow()).bind(this)
|
||||||
|
);
|
||||||
|
|
||||||
async ngOnInit() {
|
async ngOnInit() {
|
||||||
const params = this.route.snapshot.paramMap;
|
const params = this.route.snapshot.paramMap;
|
||||||
|
|
||||||
@@ -64,6 +76,9 @@ export class ViewComponent implements OnInit {
|
|||||||
|
|
||||||
this.hasOriginal = metadata.fileMimes.original !== undefined;
|
this.hasOriginal = metadata.fileMimes.original !== undefined;
|
||||||
|
|
||||||
|
this.imageUser = metadata.user;
|
||||||
|
this.image = metadata.image;
|
||||||
|
|
||||||
const masterMime = ParseMime(metadata.fileMimes.master);
|
const masterMime = ParseMime(metadata.fileMimes.master);
|
||||||
if (HasSuccess(masterMime)) {
|
if (HasSuccess(masterMime)) {
|
||||||
this.masterMime = masterMime;
|
this.masterMime = masterMime;
|
||||||
|
|||||||
5
frontend/src/app/util/poll.ts
Normal file
5
frontend/src/app/util/poll.ts
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
import { map, Observable, timer } from 'rxjs';
|
||||||
|
|
||||||
|
export function rxjs_poll<T>(period: number, action: () => T): Observable<T> {
|
||||||
|
return timer(0, 1000).pipe(map(() => action()));
|
||||||
|
}
|
||||||
@@ -9,4 +9,4 @@ if (Environment.production) {
|
|||||||
|
|
||||||
platformBrowserDynamic()
|
platformBrowserDynamic()
|
||||||
.bootstrapModule(AppModule)
|
.bootstrapModule(AppModule)
|
||||||
.catch((err) => console.error(err));
|
.catch(console.error);
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import { z } from 'zod';
|
import { z } from 'zod';
|
||||||
import { EImageSchema } from '../../entities/image.entity';
|
import { EImageSchema } from '../../entities/image.entity';
|
||||||
|
import { EUserSchema } from '../../entities/user.entity';
|
||||||
import { createZodDto } from '../../util/create-zod-dto';
|
import { createZodDto } from '../../util/create-zod-dto';
|
||||||
import { ImageFileType } from '../image-file-types.dto';
|
import { ImageFileType } from '../image-file-types.dto';
|
||||||
|
|
||||||
@@ -32,6 +33,7 @@ export class ImageRequestParams extends createZodDto(
|
|||||||
|
|
||||||
export const ImageMetaResponseSchema = z.object({
|
export const ImageMetaResponseSchema = z.object({
|
||||||
image: EImageSchema,
|
image: EImageSchema,
|
||||||
|
user: EUserSchema,
|
||||||
fileMimes: z.object({
|
fileMimes: z.object({
|
||||||
[ImageFileType.MASTER]: z.string(),
|
[ImageFileType.MASTER]: z.string(),
|
||||||
[ImageFileType.ORIGINAL]: z.union([z.string(), z.undefined()]),
|
[ImageFileType.ORIGINAL]: z.union([z.string(), z.undefined()]),
|
||||||
|
|||||||
@@ -3,5 +3,7 @@ import { IsEntityID } from '../validators/entity-id.validator';
|
|||||||
|
|
||||||
export const EImageSchema = z.object({
|
export const EImageSchema = z.object({
|
||||||
id: IsEntityID(),
|
id: IsEntityID(),
|
||||||
|
user_id: z.string(),
|
||||||
|
created: z.preprocess((data: any) => new Date(data), z.date()),
|
||||||
});
|
});
|
||||||
export type EImage = z.infer<typeof EImageSchema>;
|
export type EImage = z.infer<typeof EImageSchema>;
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ export const SimpleUserSchema = z.object({
|
|||||||
export type SimpleUser = z.infer<typeof SimpleUserSchema>;
|
export type SimpleUser = z.infer<typeof SimpleUserSchema>;
|
||||||
|
|
||||||
export const EUserSchema = z.object({
|
export const EUserSchema = z.object({
|
||||||
id: IsEntityID().optional(),
|
id: IsEntityID(),
|
||||||
username: IsUsername(),
|
username: IsUsername(),
|
||||||
roles: IsStringList(),
|
roles: IsStringList(),
|
||||||
hashedPassword: z.undefined(),
|
hashedPassword: z.undefined(),
|
||||||
|
|||||||
36
yarn.lock
36
yarn.lock
@@ -1331,7 +1331,8 @@
|
|||||||
secure-json-parse "^2.4.0"
|
secure-json-parse "^2.4.0"
|
||||||
stream-wormhole "^1.1.0"
|
stream-wormhole "^1.1.0"
|
||||||
|
|
||||||
"@fastify/static@^5.0.0", fastify-static@^4.7.0, "fastify-static@npm:@fastify/static":
|
"@fastify/static@^5.0.0", "fastify-static@npm:@fastify/static":
|
||||||
|
name fastify-static
|
||||||
version "5.0.1"
|
version "5.0.1"
|
||||||
resolved "https://registry.yarnpkg.com/@fastify/static/-/static-5.0.1.tgz#6bb6b94c2b51d9fafb06261b79ed5da5038dd5a1"
|
resolved "https://registry.yarnpkg.com/@fastify/static/-/static-5.0.1.tgz#6bb6b94c2b51d9fafb06261b79ed5da5038dd5a1"
|
||||||
integrity sha512-0lReUKWVOt2i5i1KoBLYsbcMBthq5eiEoUQrFceoXJkCv+OyA0iLl6hGxcmnMRxLsl/Netrzt1NNOpg4muCcuw==
|
integrity sha512-0lReUKWVOt2i5i1KoBLYsbcMBthq5eiEoUQrFceoXJkCv+OyA0iLl6hGxcmnMRxLsl/Netrzt1NNOpg4muCcuw==
|
||||||
@@ -3957,6 +3958,27 @@ fastify-plugin@^3.0.0:
|
|||||||
resolved "https://registry.yarnpkg.com/fastify-plugin/-/fastify-plugin-3.0.1.tgz#79e84c29f401020f38b524f59f2402103fd21ed2"
|
resolved "https://registry.yarnpkg.com/fastify-plugin/-/fastify-plugin-3.0.1.tgz#79e84c29f401020f38b524f59f2402103fd21ed2"
|
||||||
integrity sha512-qKcDXmuZadJqdTm6vlCqioEbyewF60b/0LOFCcYN1B6BIZGlYJumWWOYs70SFYLDAH4YqdE1cxH/RKMG7rFxgA==
|
integrity sha512-qKcDXmuZadJqdTm6vlCqioEbyewF60b/0LOFCcYN1B6BIZGlYJumWWOYs70SFYLDAH4YqdE1cxH/RKMG7rFxgA==
|
||||||
|
|
||||||
|
"fastify-static-deprecated@npm:fastify-static@4.6.1":
|
||||||
|
version "4.6.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/fastify-static/-/fastify-static-4.6.1.tgz#687131da76f1d4391fb8b47f71ea2118cdc85803"
|
||||||
|
integrity sha512-vy7N28U4AMhuOim12ZZWHulEE6OQKtzZbHgiB8Zj4llUuUQXPka0WHAQI3njm1jTCx4W6fixUHfpITxweMtAIA==
|
||||||
|
dependencies:
|
||||||
|
content-disposition "^0.5.3"
|
||||||
|
encoding-negotiator "^2.0.1"
|
||||||
|
fastify-plugin "^3.0.0"
|
||||||
|
glob "^7.1.4"
|
||||||
|
p-limit "^3.1.0"
|
||||||
|
readable-stream "^3.4.0"
|
||||||
|
send "^0.17.1"
|
||||||
|
|
||||||
|
fastify-static@^4.7.0:
|
||||||
|
version "4.7.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/fastify-static/-/fastify-static-4.7.0.tgz#e802658d69c1dcddb380b9afc2456d467a3494be"
|
||||||
|
integrity sha512-zZhCfJv/hkmud2qhWqpU3K9XVAuy3+IV8Tp9BC5J5U+GyA2XwoB6h8lh9GqpEIqdXOw01WyWQllV7dOWVyAlXg==
|
||||||
|
dependencies:
|
||||||
|
fastify-static-deprecated "npm:fastify-static@4.6.1"
|
||||||
|
process-warning "^1.0.0"
|
||||||
|
|
||||||
fastify@3.28.0:
|
fastify@3.28.0:
|
||||||
version "3.28.0"
|
version "3.28.0"
|
||||||
resolved "https://registry.yarnpkg.com/fastify/-/fastify-3.28.0.tgz#14d939a2f176b82af1094de7abcb0b2d83bcff8f"
|
resolved "https://registry.yarnpkg.com/fastify/-/fastify-3.28.0.tgz#14d939a2f176b82af1094de7abcb0b2d83bcff8f"
|
||||||
@@ -5333,7 +5355,12 @@ minimatch@^3.0.4:
|
|||||||
dependencies:
|
dependencies:
|
||||||
brace-expansion "^1.1.7"
|
brace-expansion "^1.1.7"
|
||||||
|
|
||||||
minimist@1.2.6, minimist@^1.2.0, minimist@^1.2.3, minimist@^1.2.6, "minimist@npm:minimist-lite":
|
minimist@1.2.6, minimist@^1.2.0, minimist@^1.2.3, minimist@^1.2.6:
|
||||||
|
version "1.2.6"
|
||||||
|
resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.6.tgz#8637a5b759ea0d6e98702cfb3a9283323c93af44"
|
||||||
|
integrity sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==
|
||||||
|
|
||||||
|
"minimist@npm:minimist-lite":
|
||||||
version "2.2.1"
|
version "2.2.1"
|
||||||
resolved "https://registry.yarnpkg.com/minimist-lite/-/minimist-lite-2.2.1.tgz#abb71db2c9b454d7cf4496868c03e9802de9934d"
|
resolved "https://registry.yarnpkg.com/minimist-lite/-/minimist-lite-2.2.1.tgz#abb71db2c9b454d7cf4496868c03e9802de9934d"
|
||||||
integrity sha512-RSrWIRWGYoM2TDe102s7aIyeSipXMIXKb1fSHYx1tAbxAV0z4g2xR6ra3oPzkTqFb0EIUz1H3A/qvYYeDd+/qQ==
|
integrity sha512-RSrWIRWGYoM2TDe102s7aIyeSipXMIXKb1fSHYx1tAbxAV0z4g2xR6ra3oPzkTqFb0EIUz1H3A/qvYYeDd+/qQ==
|
||||||
@@ -5417,6 +5444,11 @@ mkdirp@^1.0.3, mkdirp@^1.0.4:
|
|||||||
resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-1.0.4.tgz#3eb5ed62622756d79a5f0e2a221dfebad75c2f7e"
|
resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-1.0.4.tgz#3eb5ed62622756d79a5f0e2a221dfebad75c2f7e"
|
||||||
integrity sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==
|
integrity sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==
|
||||||
|
|
||||||
|
moment@^2.29.3:
|
||||||
|
version "2.29.3"
|
||||||
|
resolved "https://registry.yarnpkg.com/moment/-/moment-2.29.3.tgz#edd47411c322413999f7a5940d526de183c031f3"
|
||||||
|
integrity sha512-c6YRvhEo//6T2Jz/vVtYzqBzwvPT95JBQ+smCytzf7c50oMZRsR/a4w88aD34I+/QVSfnoAnSBFPJHItlOMJVw==
|
||||||
|
|
||||||
ms@2.0.0:
|
ms@2.0.0:
|
||||||
version "2.0.0"
|
version "2.0.0"
|
||||||
resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8"
|
resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8"
|
||||||
|
|||||||
Reference in New Issue
Block a user