Compare commits
No commits in common. "a89e8d48e6ad88263dcaaf8b7eb35263fc326f37" and "d13d354707afcc3975f65202d139e81deed0a57b" have entirely different histories.
a89e8d48e6
...
d13d354707
@ -1,38 +0,0 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: syuilo and misskey-project
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
export class RemoteObjectStorage1729518620697 {
|
||||
async up(queryRunner) {
|
||||
await queryRunner.query(`ALTER TABLE "meta" ADD COLUMN useRemoteObjectStorage BOOLEAN DEFAULT false;`);
|
||||
await queryRunner.query(`ALTER TABLE "meta" ADD COLUMN remoteObjectStorageBucket VARCHAR(1024) NOT NULL;`);
|
||||
await queryRunner.query(`ALTER TABLE "meta" ADD COLUMN remoteObjectStoragePrefix VARCHAR(1024) NOT NULL;`);
|
||||
await queryRunner.query(`ALTER TABLE "meta" ADD COLUMN remoteObjectStorageBaseUrl VARCHAR(1024);`);
|
||||
await queryRunner.query(`ALTER TABLE "meta" ADD COLUMN remoteObjectStorageEndpoint VARCHAR(1024);`);
|
||||
await queryRunner.query(`ALTER TABLE "meta" ADD COLUMN remoteObjectStorageRegion VARCHAR(1024);`);
|
||||
await queryRunner.query(`ALTER TABLE "meta" ADD COLUMN remoteObjectStorageAccessKey VARCHAR(1024);`);
|
||||
await queryRunner.query(`ALTER TABLE "meta" ADD COLUMN remoteObjectStorageSecretKey VARCHAR(1024);`);
|
||||
await queryRunner.query(`ALTER TABLE "meta" ADD COLUMN remoteObjectStoragePort INTEGER;`);
|
||||
await queryRunner.query(`ALTER TABLE "meta" ADD COLUMN remoteObjectStorageUseSSL BOOLEAN DEFAULT true;`);
|
||||
await queryRunner.query(`ALTER TABLE "meta" ADD COLUMN remoteObjectStorageUseProxy BOOLEAN DEFAULT true;`);
|
||||
await queryRunner.query(`ALTER TABLE "meta" ADD COLUMN remoteObjectStorageSetPublicRead BOOLEAN DEFAULT false;`);
|
||||
await queryRunner.query(`ALTER TABLE "meta" ADD COLUMN remoteObjectStorageS3ForcePathStyle BOOLEAN DEFAULT true;`);
|
||||
}
|
||||
|
||||
async down(queryRunner) {
|
||||
await queryRunner.query(`ALTER TABLE "meta" DROP COLUMN remoteObjectStorageS3ForcePathStyle;`);
|
||||
await queryRunner.query(`ALTER TABLE "meta" DROP COLUMN remoteObjectStorageSetPublicRead;`);
|
||||
await queryRunner.query(`ALTER TABLE "meta" DROP COLUMN remoteObjectStorageUseProxy;`);
|
||||
await queryRunner.query(`ALTER TABLE "meta" DROP COLUMN remoteObjectStorageUseSSL;`);
|
||||
await queryRunner.query(`ALTER TABLE "meta" DROP COLUMN remoteObjectStoragePort;`);
|
||||
await queryRunner.query(`ALTER TABLE "meta" DROP COLUMN remoteObjectStorageSecretKey;`);
|
||||
await queryRunner.query(`ALTER TABLE "meta" DROP COLUMN remoteObjectStorageAccessKey;`);
|
||||
await queryRunner.query(`ALTER TABLE "meta" DROP COLUMN remoteObjectStorageRegion;`);
|
||||
await queryRunner.query(`ALTER TABLE "meta" DROP COLUMN remoteObjectStorageEndpoint;`);
|
||||
await queryRunner.query(`ALTER TABLE "meta" DROP COLUMN remoteObjectStorageBaseUrl;`);
|
||||
await queryRunner.query(`ALTER TABLE "meta" DROP COLUMN remoteObjectStoragePrefix;`);
|
||||
await queryRunner.query(`ALTER TABLE "meta" DROP COLUMN remoteObjectStorageBucket;`);
|
||||
await queryRunner.query(`ALTER TABLE "meta" DROP COLUMN useRemoteObjectStorage;`);
|
||||
}
|
||||
}
|
@ -146,7 +146,7 @@ export class DriveService {
|
||||
* @param size Size for original
|
||||
*/
|
||||
@bindThis
|
||||
private async save(file: MiDriveFile, path: string, name: string, type: string, hash: string, size: number, isRemote = false): Promise<MiDriveFile> {
|
||||
private async save(file: MiDriveFile, path: string, name: string, type: string, hash: string, size: number): Promise<MiDriveFile> {
|
||||
// thunbnail, webpublic を必要なら生成
|
||||
const alts = await this.generateAlts(path, type, !file.uri);
|
||||
|
||||
@ -169,37 +169,11 @@ export class DriveService {
|
||||
ext = '';
|
||||
}
|
||||
|
||||
const useRemoteObjectStorage = isRemote && this.meta.useRemoteObjectStorage;
|
||||
|
||||
const objectStorageBaseUrl = useRemoteObjectStorage
|
||||
? this.meta.remoteObjectStorageBaseUrl
|
||||
: this.meta.objectStorageBaseUrl;
|
||||
|
||||
const objectStorageUseSSL = useRemoteObjectStorage
|
||||
? this.meta.remoteObjectStorageUseSSL
|
||||
: this.meta.objectStorageUseSSL;
|
||||
|
||||
const objectStorageEndpoint = useRemoteObjectStorage
|
||||
? this.meta.remoteObjectStorageEndpoint
|
||||
: this.meta.objectStorageEndpoint;
|
||||
|
||||
const objectStoragePort = useRemoteObjectStorage
|
||||
? this.meta.remoteObjectStoragePort
|
||||
: this.meta.objectStoragePort;
|
||||
|
||||
const objectStorageBucket = useRemoteObjectStorage
|
||||
? this.meta.remoteObjectStorageBucket
|
||||
: this.meta.objectStorageBucket;
|
||||
|
||||
const objectStoragePrefix = useRemoteObjectStorage
|
||||
? this.meta.remoteObjectStoragePrefix
|
||||
: this.meta.objectStoragePrefix;
|
||||
|
||||
const baseUrl = objectStorageBaseUrl
|
||||
?? `${objectStorageUseSSL ? 'https' : 'http'}://${objectStorageEndpoint}${objectStoragePort ? `:${objectStoragePort}` : ''}/${objectStorageBucket}`;
|
||||
const baseUrl = this.meta.objectStorageBaseUrl
|
||||
?? `${ this.meta.objectStorageUseSSL ? 'https' : 'http' }://${ this.meta.objectStorageEndpoint }${ this.meta.objectStoragePort ? `:${this.meta.objectStoragePort}` : '' }/${ this.meta.objectStorageBucket }`;
|
||||
|
||||
// for original
|
||||
const key = `${objectStoragePrefix}/${randomUUID()}${ext}`;
|
||||
const key = `${this.meta.objectStoragePrefix}/${randomUUID()}${ext}`;
|
||||
const url = `${ baseUrl }/${ key }`;
|
||||
|
||||
// for alts
|
||||
@ -212,7 +186,7 @@ export class DriveService {
|
||||
//#region Uploads
|
||||
this.registerLogger.info(`uploading original: ${key}`);
|
||||
const uploads = [
|
||||
this.upload(key, fs.createReadStream(path), type, isRemote, null, name),
|
||||
this.upload(key, fs.createReadStream(path), type, null, name),
|
||||
];
|
||||
|
||||
if (alts.webpublic) {
|
||||
@ -220,7 +194,7 @@ export class DriveService {
|
||||
webpublicUrl = `${ baseUrl }/${ webpublicKey }`;
|
||||
|
||||
this.registerLogger.info(`uploading webpublic: ${webpublicKey}`);
|
||||
uploads.push(this.upload(webpublicKey, alts.webpublic.data, alts.webpublic.type, isRemote, alts.webpublic.ext, name));
|
||||
uploads.push(this.upload(webpublicKey, alts.webpublic.data, alts.webpublic.type, alts.webpublic.ext, name));
|
||||
}
|
||||
|
||||
if (alts.thumbnail) {
|
||||
@ -228,7 +202,7 @@ export class DriveService {
|
||||
thumbnailUrl = `${ baseUrl }/${ thumbnailKey }`;
|
||||
|
||||
this.registerLogger.info(`uploading thumbnail: ${thumbnailKey}`);
|
||||
uploads.push(this.upload(thumbnailKey, alts.thumbnail.data, alts.thumbnail.type, isRemote, alts.thumbnail.ext, `${name}.thumbnail`));
|
||||
uploads.push(this.upload(thumbnailKey, alts.thumbnail.data, alts.thumbnail.type, alts.thumbnail.ext, `${name}.thumbnail`));
|
||||
}
|
||||
|
||||
await Promise.all(uploads);
|
||||
@ -397,22 +371,12 @@ export class DriveService {
|
||||
* Upload to ObjectStorage
|
||||
*/
|
||||
@bindThis
|
||||
private async upload(key: string, stream: fs.ReadStream | Buffer, type: string, isRemote = false, ext?: string | null, filename?: string) {
|
||||
private async upload(key: string, stream: fs.ReadStream | Buffer, type: string, ext?: string | null, filename?: string) {
|
||||
if (type === 'image/apng') type = 'image/png';
|
||||
if (!FILE_TYPE_BROWSERSAFE.includes(type)) type = 'application/octet-stream';
|
||||
|
||||
const useRemoteObjectStorage = isRemote && this.meta.useRemoteObjectStorage;
|
||||
|
||||
const objectStorageBucket = useRemoteObjectStorage
|
||||
? this.meta.remoteObjectStorageBucket
|
||||
: this.meta.objectStorageBucket;
|
||||
|
||||
const objectStorageSetPublicRead = useRemoteObjectStorage
|
||||
? this.meta.remoteObjectStorageSetPublicRead
|
||||
: this.meta.objectStorageSetPublicRead;
|
||||
|
||||
const params = {
|
||||
Bucket: objectStorageBucket,
|
||||
Bucket: this.meta.objectStorageBucket,
|
||||
Key: key,
|
||||
Body: stream,
|
||||
ContentType: type,
|
||||
@ -425,9 +389,9 @@ export class DriveService {
|
||||
// 許可されているファイル形式でしか拡張子をつけない
|
||||
ext ? correctFilename(filename, ext) : filename,
|
||||
);
|
||||
if (objectStorageSetPublicRead) params.ACL = 'public-read';
|
||||
if (this.meta.objectStorageSetPublicRead) params.ACL = 'public-read';
|
||||
|
||||
await this.s3Service.upload(this.meta, params, isRemote)
|
||||
await this.s3Service.upload(this.meta, params)
|
||||
.then(
|
||||
result => {
|
||||
if ('Bucket' in result) { // CompleteMultipartUploadCommandOutput
|
||||
@ -666,8 +630,7 @@ export class DriveService {
|
||||
}
|
||||
}
|
||||
} else {
|
||||
const isRemote = user ? this.userEntityService.isRemoteUser(user) : false;
|
||||
file = await (this.save(file, path, detectedName, info.type.mime, info.md5, info.size, isRemote));
|
||||
file = await (this.save(file, path, detectedName, info.type.mime, info.md5, info.size));
|
||||
}
|
||||
|
||||
this.registerLogger.succ(`drive file has been created ${file.id}`);
|
||||
@ -777,7 +740,7 @@ export class DriveService {
|
||||
}
|
||||
|
||||
@bindThis
|
||||
public async deleteFileSync(file: MiDriveFile, isExpired = false, isRemote = false, deleter?: MiUser) {
|
||||
public async deleteFileSync(file: MiDriveFile, isExpired = false, deleter?: MiUser) {
|
||||
if (file.storedInternal) {
|
||||
this.internalStorageService.del(file.accessKey!);
|
||||
|
||||
@ -791,14 +754,14 @@ export class DriveService {
|
||||
} else if (!file.isLink) {
|
||||
const promises = [];
|
||||
|
||||
promises.push(this.deleteObjectStorageFile(file.accessKey!, isRemote));
|
||||
promises.push(this.deleteObjectStorageFile(file.accessKey!));
|
||||
|
||||
if (file.thumbnailUrl) {
|
||||
promises.push(this.deleteObjectStorageFile(file.thumbnailAccessKey!, isRemote));
|
||||
promises.push(this.deleteObjectStorageFile(file.thumbnailAccessKey!));
|
||||
}
|
||||
|
||||
if (file.webpublicUrl) {
|
||||
promises.push(this.deleteObjectStorageFile(file.webpublicAccessKey!, isRemote));
|
||||
promises.push(this.deleteObjectStorageFile(file.webpublicAccessKey!));
|
||||
}
|
||||
|
||||
await Promise.all(promises);
|
||||
@ -852,19 +815,14 @@ export class DriveService {
|
||||
}
|
||||
|
||||
@bindThis
|
||||
public async deleteObjectStorageFile(key: string, isRemote = false) {
|
||||
const useRemoteObjectStorage = isRemote && this.meta.useRemoteObjectStorage;
|
||||
const objectStorageBucket = useRemoteObjectStorage
|
||||
? this.meta.remoteObjectStorageBucket
|
||||
: this.meta.objectStorageBucket;
|
||||
|
||||
public async deleteObjectStorageFile(key: string) {
|
||||
try {
|
||||
const param = {
|
||||
Bucket: objectStorageBucket,
|
||||
Bucket: this.meta.objectStorageBucket,
|
||||
Key: key,
|
||||
} as DeleteObjectCommandInput;
|
||||
|
||||
await this.s3Service.delete(this.meta, param, isRemote);
|
||||
await this.s3Service.delete(this.meta, param);
|
||||
} catch (err: any) {
|
||||
if (err.name === 'NoSuchKey') {
|
||||
this.deleteLogger.warn(`The object storage had no such key to delete: ${key}. Skipping this.`, err as Error);
|
||||
|
@ -19,64 +19,39 @@ import type { DeleteObjectCommandInput, PutObjectCommandInput } from '@aws-sdk/c
|
||||
export class S3Service {
|
||||
constructor(
|
||||
private httpRequestService: HttpRequestService,
|
||||
) {}
|
||||
) {
|
||||
}
|
||||
|
||||
@bindThis
|
||||
public getS3Client(meta: MiMeta, isRemote = false): S3Client {
|
||||
const useRemoteObjectStorage = isRemote && meta.useRemoteObjectStorage;
|
||||
public getS3Client(meta: MiMeta): S3Client {
|
||||
const u = meta.objectStorageEndpoint
|
||||
? `${meta.objectStorageUseSSL ? 'https' : 'http'}://${meta.objectStorageEndpoint}`
|
||||
: `${meta.objectStorageUseSSL ? 'https' : 'http'}://example.net`; // dummy url to select http(s) agent
|
||||
|
||||
const objectStorageEndpoint = useRemoteObjectStorage
|
||||
? meta.remoteObjectStorageEndpoint
|
||||
: meta.objectStorageEndpoint;
|
||||
|
||||
const objectStorageUseSSL = useRemoteObjectStorage
|
||||
? meta.remoteObjectStorageUseSSL
|
||||
: meta.objectStorageUseSSL;
|
||||
|
||||
const objectStorageAccessKey = useRemoteObjectStorage
|
||||
? meta.remoteObjectStorageAccessKey
|
||||
: meta.objectStorageAccessKey;
|
||||
|
||||
const objectStorageSecretKey = useRemoteObjectStorage
|
||||
? meta.remoteObjectStorageSecretKey
|
||||
: meta.objectStorageSecretKey;
|
||||
|
||||
const objectStorageRegion = useRemoteObjectStorage
|
||||
? meta.remoteObjectStorageRegion
|
||||
: meta.objectStorageRegion;
|
||||
|
||||
const objectStorageS3ForcePathStyle = useRemoteObjectStorage
|
||||
? meta.remoteObjectStorageS3ForcePathStyle
|
||||
: meta.objectStorageS3ForcePathStyle;
|
||||
|
||||
const u = objectStorageEndpoint
|
||||
? `${objectStorageUseSSL ? 'https' : 'http'}://${objectStorageEndpoint}`
|
||||
: `${objectStorageUseSSL ? 'https' : 'http'}://example.net`; // dummy url to select http(s) agent
|
||||
|
||||
const agent = this.httpRequestService.getAgentByUrl(new URL(u), !objectStorageUseSSL);
|
||||
const agent = this.httpRequestService.getAgentByUrl(new URL(u), !meta.objectStorageUseProxy);
|
||||
const handlerOption: NodeHttpHandlerOptions = {};
|
||||
if (objectStorageUseSSL) {
|
||||
if (meta.objectStorageUseSSL) {
|
||||
handlerOption.httpsAgent = agent as https.Agent;
|
||||
} else {
|
||||
handlerOption.httpAgent = agent as http.Agent;
|
||||
}
|
||||
|
||||
return new S3Client({
|
||||
endpoint: objectStorageEndpoint ? u : undefined,
|
||||
credentials: (objectStorageAccessKey !== null && objectStorageSecretKey !== null) ? {
|
||||
accessKeyId: objectStorageAccessKey,
|
||||
secretAccessKey: objectStorageSecretKey,
|
||||
endpoint: meta.objectStorageEndpoint ? u : undefined,
|
||||
credentials: (meta.objectStorageAccessKey !== null && meta.objectStorageSecretKey !== null) ? {
|
||||
accessKeyId: meta.objectStorageAccessKey,
|
||||
secretAccessKey: meta.objectStorageSecretKey,
|
||||
} : undefined,
|
||||
region: objectStorageRegion || undefined, // 空文字列もundefinedにするため ?? は使わない
|
||||
tls: objectStorageUseSSL,
|
||||
forcePathStyle: objectStorageEndpoint ? objectStorageS3ForcePathStyle : false, // AWS with endPoint omitted
|
||||
region: meta.objectStorageRegion ? meta.objectStorageRegion : undefined, // 空文字列もundefinedにするため ?? は使わない
|
||||
tls: meta.objectStorageUseSSL,
|
||||
forcePathStyle: meta.objectStorageEndpoint ? meta.objectStorageS3ForcePathStyle : false, // AWS with endPoint omitted
|
||||
requestHandler: new NodeHttpHandler(handlerOption),
|
||||
});
|
||||
}
|
||||
|
||||
@bindThis
|
||||
public async upload(meta: MiMeta, input: PutObjectCommandInput, isRemote = false) {
|
||||
const client = this.getS3Client(meta, isRemote);
|
||||
public async upload(meta: MiMeta, input: PutObjectCommandInput) {
|
||||
const client = this.getS3Client(meta);
|
||||
return new Upload({
|
||||
client,
|
||||
params: input,
|
||||
@ -87,8 +62,8 @@ export class S3Service {
|
||||
}
|
||||
|
||||
@bindThis
|
||||
public delete(meta: MiMeta, input: DeleteObjectCommandInput, isRemote = false) {
|
||||
const client = this.getS3Client(meta, isRemote);
|
||||
public delete(meta: MiMeta, input: DeleteObjectCommandInput) {
|
||||
const client = this.getS3Client(meta);
|
||||
return client.send(new DeleteObjectCommand(input));
|
||||
}
|
||||
}
|
||||
|
@ -481,78 +481,6 @@ export class MiMeta {
|
||||
})
|
||||
public objectStorageS3ForcePathStyle: boolean;
|
||||
|
||||
@Column('boolean', {
|
||||
default: false,
|
||||
})
|
||||
public useRemoteObjectStorage: boolean;
|
||||
|
||||
@Column('varchar', {
|
||||
length: 1024,
|
||||
nullable: true,
|
||||
})
|
||||
public remoteObjectStorageBucket: string | null;
|
||||
|
||||
@Column('varchar', {
|
||||
length: 1024,
|
||||
nullable: true,
|
||||
})
|
||||
public remoteObjectStoragePrefix: string | null;
|
||||
|
||||
@Column('varchar', {
|
||||
length: 1024,
|
||||
nullable: true,
|
||||
})
|
||||
public remoteObjectStorageBaseUrl: string | null;
|
||||
|
||||
@Column('varchar', {
|
||||
length: 1024,
|
||||
nullable: true,
|
||||
})
|
||||
public remoteObjectStorageEndpoint: string | null;
|
||||
|
||||
@Column('varchar', {
|
||||
length: 1024,
|
||||
nullable: true,
|
||||
})
|
||||
public remoteObjectStorageRegion: string | null;
|
||||
|
||||
@Column('varchar', {
|
||||
length: 1024,
|
||||
nullable: true,
|
||||
})
|
||||
public remoteObjectStorageAccessKey: string | null;
|
||||
|
||||
@Column('varchar', {
|
||||
length: 1024,
|
||||
nullable: true,
|
||||
})
|
||||
public remoteObjectStorageSecretKey: string | null;
|
||||
|
||||
@Column('integer', {
|
||||
nullable: true,
|
||||
})
|
||||
public remoteObjectStoragePort: number | null;
|
||||
|
||||
@Column('boolean', {
|
||||
default: true,
|
||||
})
|
||||
public remoteObjectStorageUseSSL: boolean;
|
||||
|
||||
@Column('boolean', {
|
||||
default: true,
|
||||
})
|
||||
public remoteObjectStorageUseProxy: boolean;
|
||||
|
||||
@Column('boolean', {
|
||||
default: false,
|
||||
})
|
||||
public remoteObjectStorageSetPublicRead: boolean;
|
||||
|
||||
@Column('boolean', {
|
||||
default: true,
|
||||
})
|
||||
public remoteObjectStorageS3ForcePathStyle: boolean;
|
||||
|
||||
@Column('boolean', {
|
||||
default: false,
|
||||
})
|
||||
|
@ -54,7 +54,7 @@ export class CleanRemoteFilesProcessorService {
|
||||
|
||||
cursor = files.at(-1)?.id ?? null;
|
||||
|
||||
await Promise.all(files.map(file => this.driveService.deleteFileSync(file, true, true)));
|
||||
await Promise.all(files.map(file => this.driveService.deleteFileSync(file, true)));
|
||||
|
||||
deletedCount += 8;
|
||||
|
||||
|
@ -17,7 +17,6 @@ import { SearchService } from '@/core/SearchService.js';
|
||||
import { QueueLoggerService } from '../QueueLoggerService.js';
|
||||
import type * as Bull from 'bullmq';
|
||||
import type { DbUserDeleteJobData } from '../types.js';
|
||||
import { UserEntityService } from '@/core/entities/UserEntityService.js';
|
||||
|
||||
@Injectable()
|
||||
export class DeleteAccountProcessorService {
|
||||
@ -36,7 +35,6 @@ export class DeleteAccountProcessorService {
|
||||
@Inject(DI.driveFilesRepository)
|
||||
private driveFilesRepository: DriveFilesRepository,
|
||||
|
||||
private userEntityService: UserEntityService,
|
||||
private driveService: DriveService,
|
||||
private emailService: EmailService,
|
||||
private queueLoggerService: QueueLoggerService,
|
||||
@ -50,7 +48,6 @@ export class DeleteAccountProcessorService {
|
||||
this.logger.info(`Deleting account of ${job.data.user.id} ...`);
|
||||
|
||||
const user = await this.usersRepository.findOneBy({ id: job.data.user.id });
|
||||
const isRemote = user ? this.userEntityService.isRemoteUser(user) : false;
|
||||
if (user == null) {
|
||||
return;
|
||||
}
|
||||
@ -108,7 +105,7 @@ export class DeleteAccountProcessorService {
|
||||
cursor = files.at(-1)?.id ?? null;
|
||||
|
||||
for (const file of files) {
|
||||
await this.driveService.deleteFileSync(file, undefined, isRemote);
|
||||
await this.driveService.deleteFileSync(file);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -13,7 +13,6 @@ import { bindThis } from '@/decorators.js';
|
||||
import { QueueLoggerService } from '../QueueLoggerService.js';
|
||||
import type * as Bull from 'bullmq';
|
||||
import type { DbJobDataWithUser } from '../types.js';
|
||||
import { UserEntityService } from "@/core/entities/UserEntityService.js";
|
||||
|
||||
@Injectable()
|
||||
export class DeleteDriveFilesProcessorService {
|
||||
@ -26,7 +25,6 @@ export class DeleteDriveFilesProcessorService {
|
||||
@Inject(DI.driveFilesRepository)
|
||||
private driveFilesRepository: DriveFilesRepository,
|
||||
|
||||
private userEntityService: UserEntityService,
|
||||
private driveService: DriveService,
|
||||
private queueLoggerService: QueueLoggerService,
|
||||
) {
|
||||
@ -38,7 +36,6 @@ export class DeleteDriveFilesProcessorService {
|
||||
this.logger.info(`Deleting drive files of ${job.data.user.id} ...`);
|
||||
|
||||
const user = await this.usersRepository.findOneBy({ id: job.data.user.id });
|
||||
const isRemote = user ? this.userEntityService.isRemoteUser(user) : false;
|
||||
if (user == null) {
|
||||
return;
|
||||
}
|
||||
@ -66,7 +63,7 @@ export class DeleteDriveFilesProcessorService {
|
||||
cursor = files.at(-1)?.id ?? null;
|
||||
|
||||
for (const file of files) {
|
||||
await this.driveService.deleteFileSync(file, undefined, isRemote);
|
||||
await this.driveService.deleteFileSync(file);
|
||||
deletedCount++;
|
||||
}
|
||||
|
||||
|
@ -3,26 +3,19 @@
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
import { Injectable, Inject } from '@nestjs/common';
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import type Logger from '@/logger.js';
|
||||
import { DriveService } from '@/core/DriveService.js';
|
||||
import { bindThis } from '@/decorators.js';
|
||||
import { QueueLoggerService } from '../QueueLoggerService.js';
|
||||
import type * as Bull from 'bullmq';
|
||||
import type { ObjectStorageFileJobData } from '../types.js';
|
||||
import type { DriveFilesRepository } from "@/models/_.js";
|
||||
import { UserEntityService } from "@/core/entities/UserEntityService.js";
|
||||
import { DI } from '@/di-symbols.js';
|
||||
|
||||
@Injectable()
|
||||
export class DeleteFileProcessorService {
|
||||
private logger: Logger;
|
||||
|
||||
constructor(
|
||||
@Inject(DI.driveFilesRepository)
|
||||
private driveFilesRepository: DriveFilesRepository,
|
||||
|
||||
private userEntityService: UserEntityService,
|
||||
private driveService: DriveService,
|
||||
private queueLoggerService: QueueLoggerService,
|
||||
) {
|
||||
@ -33,14 +26,7 @@ export class DeleteFileProcessorService {
|
||||
public async process(job: Bull.Job<ObjectStorageFileJobData>): Promise<string> {
|
||||
const key: string = job.data.key;
|
||||
|
||||
const file = await this.driveFilesRepository.createQueryBuilder('file')
|
||||
.where('file.accessKey = :accessKey', { accessKey: key })
|
||||
.orWhere('file.thumbnailAccessKey = :thumbnailAccessKey', { thumbnailAccessKey: key })
|
||||
.orWhere('file.webpublicAccessKey = :webpublicAccessKey', { webpublicAccessKey: key })
|
||||
.getOne();
|
||||
const isRemote = file?.user ? this.userEntityService.isRemoteUser(file.user) : false;
|
||||
|
||||
await this.driveService.deleteObjectStorageFile(key, isRemote);
|
||||
await this.driveService.deleteObjectStorageFile(key);
|
||||
|
||||
return 'Success';
|
||||
}
|
||||
|
@ -312,66 +312,6 @@ export const meta = {
|
||||
type: 'boolean',
|
||||
optional: false, nullable: false,
|
||||
},
|
||||
useRemoteObjectStorage: {
|
||||
type: 'boolean',
|
||||
optional: false,
|
||||
nullable: false,
|
||||
},
|
||||
remoteObjectStorageBaseUrl: {
|
||||
type: 'string',
|
||||
optional: false,
|
||||
nullable: true,
|
||||
},
|
||||
remoteObjectStorageBucket: {
|
||||
type: 'string',
|
||||
optional: false,
|
||||
nullable: true,
|
||||
},
|
||||
remoteObjectStoragePrefix: {
|
||||
type: 'string',
|
||||
optional: false,
|
||||
nullable: true,
|
||||
},
|
||||
remoteObjectStorageEndpoint: {
|
||||
type: 'string',
|
||||
optional: false,
|
||||
nullable: true,
|
||||
},
|
||||
remoteObjectStorageRegion: {
|
||||
type: 'string',
|
||||
optional: false,
|
||||
nullable: true,
|
||||
},
|
||||
remoteObjectStoragePort: {
|
||||
type: 'number',
|
||||
optional: false,
|
||||
nullable: true,
|
||||
},
|
||||
remoteObjectStorageAccessKey: {
|
||||
type: 'string',
|
||||
optional: false,
|
||||
nullable: true,
|
||||
},
|
||||
remoteObjectStorageSecretKey: {
|
||||
type: 'string',
|
||||
optional: false,
|
||||
nullable: true,
|
||||
},
|
||||
remoteObjectStorageUseSSL: {
|
||||
type: 'boolean',
|
||||
optional: false,
|
||||
nullable: false,
|
||||
},
|
||||
remoteObjectStorageUseProxy: {
|
||||
type: 'boolean',
|
||||
optional: false,
|
||||
nullable: false,
|
||||
},
|
||||
remoteObjectStorageSetPublicRead: {
|
||||
type: 'boolean',
|
||||
optional: false,
|
||||
nullable: false,
|
||||
},
|
||||
enableIpLogging: {
|
||||
type: 'boolean',
|
||||
optional: false, nullable: false,
|
||||
@ -512,10 +452,6 @@ export const meta = {
|
||||
type: 'boolean',
|
||||
optional: false, nullable: false,
|
||||
},
|
||||
remoteObjectStorageS3ForcePathStyle: {
|
||||
type: 'boolean',
|
||||
optional: false, nullable: false,
|
||||
},
|
||||
privacyPolicyUrl: {
|
||||
type: 'string',
|
||||
optional: false, nullable: true,
|
||||
@ -692,19 +628,6 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
||||
objectStorageUseProxy: instance.objectStorageUseProxy,
|
||||
objectStorageSetPublicRead: instance.objectStorageSetPublicRead,
|
||||
objectStorageS3ForcePathStyle: instance.objectStorageS3ForcePathStyle,
|
||||
useRemoteObjectStorage: instance.useRemoteObjectStorage,
|
||||
remoteObjectStorageBaseUrl: instance.remoteObjectStorageBaseUrl,
|
||||
remoteObjectStorageBucket: instance.remoteObjectStorageBucket,
|
||||
remoteObjectStoragePrefix: instance.remoteObjectStoragePrefix,
|
||||
remoteObjectStorageEndpoint: instance.remoteObjectStorageEndpoint,
|
||||
remoteObjectStorageRegion: instance.remoteObjectStorageRegion,
|
||||
remoteObjectStoragePort: instance.remoteObjectStoragePort,
|
||||
remoteObjectStorageAccessKey: instance.remoteObjectStorageAccessKey,
|
||||
remoteObjectStorageSecretKey: instance.remoteObjectStorageSecretKey,
|
||||
remoteObjectStorageUseSSL: instance.remoteObjectStorageUseSSL,
|
||||
remoteObjectStorageUseProxy: instance.remoteObjectStorageUseProxy,
|
||||
remoteObjectStorageSetPublicRead: instance.remoteObjectStorageSetPublicRead,
|
||||
remoteObjectStorageS3ForcePathStyle: instance.remoteObjectStorageS3ForcePathStyle,
|
||||
deeplAuthKey: instance.deeplAuthKey,
|
||||
deeplIsPro: instance.deeplIsPro,
|
||||
enableIpLogging: instance.enableIpLogging,
|
||||
|
@ -127,19 +127,6 @@ export const paramDef = {
|
||||
objectStorageUseProxy: { type: 'boolean' },
|
||||
objectStorageSetPublicRead: { type: 'boolean' },
|
||||
objectStorageS3ForcePathStyle: { type: 'boolean' },
|
||||
useRemoteObjectStorage: { type: 'boolean' },
|
||||
remoteObjectStorageBaseUrl: { type: 'string', nullable: true },
|
||||
remoteObjectStorageBucket: { type: 'string', nullable: true },
|
||||
remoteObjectStoragePrefix: { type: 'string', nullable: true },
|
||||
remoteObjectStorageEndpoint: { type: 'string', nullable: true },
|
||||
remoteObjectStorageRegion: { type: 'string', nullable: true },
|
||||
remoteObjectStoragePort: { type: 'integer', nullable: true },
|
||||
remoteObjectStorageAccessKey: { type: 'string', nullable: true },
|
||||
remoteObjectStorageSecretKey: { type: 'string', nullable: true },
|
||||
remoteObjectStorageUseSSL: { type: 'boolean' },
|
||||
remoteObjectStorageUseProxy: { type: 'boolean' },
|
||||
remoteObjectStorageSetPublicRead: { type: 'boolean' },
|
||||
remoteObjectStorageS3ForcePathStyle: { type: 'boolean' },
|
||||
enableIpLogging: { type: 'boolean' },
|
||||
enableActiveEmailValidation: { type: 'boolean' },
|
||||
enableVerifymailApi: { type: 'boolean' },
|
||||
@ -532,58 +519,6 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
||||
set.objectStorageS3ForcePathStyle = ps.objectStorageS3ForcePathStyle;
|
||||
}
|
||||
|
||||
if (ps.useRemoteObjectStorage !== undefined) {
|
||||
set.useRemoteObjectStorage = ps.useRemoteObjectStorage;
|
||||
}
|
||||
|
||||
if (ps.remoteObjectStorageBaseUrl !== undefined) {
|
||||
set.remoteObjectStorageBaseUrl = ps.remoteObjectStorageBaseUrl;
|
||||
}
|
||||
|
||||
if (ps.remoteObjectStorageBucket !== undefined) {
|
||||
set.remoteObjectStorageBucket = ps.remoteObjectStorageBucket;
|
||||
}
|
||||
|
||||
if (ps.remoteObjectStoragePrefix !== undefined) {
|
||||
set.remoteObjectStoragePrefix = ps.remoteObjectStoragePrefix;
|
||||
}
|
||||
|
||||
if (ps.remoteObjectStorageEndpoint !== undefined) {
|
||||
set.remoteObjectStorageEndpoint = ps.remoteObjectStorageEndpoint;
|
||||
}
|
||||
|
||||
if (ps.remoteObjectStorageRegion !== undefined) {
|
||||
set.remoteObjectStorageRegion = ps.remoteObjectStorageRegion;
|
||||
}
|
||||
|
||||
if (ps.remoteObjectStoragePort !== undefined) {
|
||||
set.remoteObjectStoragePort = ps.remoteObjectStoragePort;
|
||||
}
|
||||
|
||||
if (ps.remoteObjectStorageAccessKey !== undefined) {
|
||||
set.remoteObjectStorageAccessKey = ps.remoteObjectStorageAccessKey;
|
||||
}
|
||||
|
||||
if (ps.remoteObjectStorageSecretKey !== undefined) {
|
||||
set.remoteObjectStorageSecretKey = ps.remoteObjectStorageSecretKey;
|
||||
}
|
||||
|
||||
if (ps.remoteObjectStorageUseSSL !== undefined) {
|
||||
set.remoteObjectStorageUseSSL = ps.remoteObjectStorageUseSSL;
|
||||
}
|
||||
|
||||
if (ps.remoteObjectStorageUseProxy !== undefined) {
|
||||
set.remoteObjectStorageUseProxy = ps.remoteObjectStorageUseProxy;
|
||||
}
|
||||
|
||||
if (ps.remoteObjectStorageSetPublicRead !== undefined) {
|
||||
set.remoteObjectStorageSetPublicRead = ps.remoteObjectStorageSetPublicRead;
|
||||
}
|
||||
|
||||
if (ps.remoteObjectStorageS3ForcePathStyle !== undefined) {
|
||||
set.remoteObjectStorageS3ForcePathStyle = ps.remoteObjectStorageS3ForcePathStyle;
|
||||
}
|
||||
|
||||
if (ps.deeplAuthKey !== undefined) {
|
||||
if (ps.deeplAuthKey === '') {
|
||||
set.deeplAuthKey = null;
|
||||
|
@ -14,10 +14,7 @@ import { sqlLikeEscape } from '@/misc/sql-like-escape.js';
|
||||
export const meta = {
|
||||
tags: ['federation'],
|
||||
|
||||
requireCredential: true,
|
||||
requireModerator: true,
|
||||
secure: true,
|
||||
kind: 'read:admin:federation',
|
||||
requireCredential: false,
|
||||
allowGet: true,
|
||||
cacheSec: 3600,
|
||||
|
||||
|
@ -24,7 +24,7 @@ export const meta = {
|
||||
|
||||
limit: {
|
||||
duration: ms('1hour'),
|
||||
max: 300,
|
||||
max: 10,
|
||||
minInterval: ms('1sec'),
|
||||
},
|
||||
|
||||
|
@ -116,11 +116,6 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||
<MkTime :time="appearNote.createdAt" mode="detail" colored/>
|
||||
</MkA>
|
||||
</div>
|
||||
<div v-if="appearNote.updatedAt" style="margin-top: 0; opacity: 0.7; font-size: 0.7em;">
|
||||
<MkA :to="notePage(appearNote)">
|
||||
{{ i18n.ts.updatedAt }}: <MkTime :time="appearNote.updatedAt" mode="detail"/>
|
||||
</MkA>
|
||||
</div>
|
||||
<MkReactionsViewer v-if="appearNote.reactionAcceptance !== 'likeOnly'" ref="reactionsViewer" :note="appearNote"/>
|
||||
<button class="_button" :class="$style.noteFooterButton" @click="reply()">
|
||||
<i class="ti ti-arrow-back-up"></i>
|
||||
|
@ -13,6 +13,9 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||
<MkSpacer v-else-if="tab === 'emojis'" :contentMax="1000" :marginMin="20">
|
||||
<XEmojis/>
|
||||
</MkSpacer>
|
||||
<MkSpacer v-else-if="tab === 'federation'" :contentMax="1000" :marginMin="20">
|
||||
<XFederation/>
|
||||
</MkSpacer>
|
||||
<MkSpacer v-else-if="tab === 'charts'" :contentMax="1000" :marginMin="20">
|
||||
<MkInstanceStats/>
|
||||
</MkSpacer>
|
||||
@ -29,6 +32,7 @@ import MkHorizontalSwipe from '@/components/MkHorizontalSwipe.vue';
|
||||
|
||||
const XOverview = defineAsyncComponent(() => import('@/pages/about.overview.vue'));
|
||||
const XEmojis = defineAsyncComponent(() => import('@/pages/about.emojis.vue'));
|
||||
const XFederation = defineAsyncComponent(() => import('@/pages/about.federation.vue'));
|
||||
const MkInstanceStats = defineAsyncComponent(() => import('@/components/MkInstanceStats.vue'));
|
||||
|
||||
const props = withDefaults(defineProps<{
|
||||
@ -54,6 +58,10 @@ const headerTabs = computed(() => [{
|
||||
key: 'emojis',
|
||||
title: i18n.ts.customEmojis,
|
||||
icon: 'ti ti-icons',
|
||||
}, {
|
||||
key: 'federation',
|
||||
title: i18n.ts.federation,
|
||||
icon: 'ti ti-whirl',
|
||||
}, {
|
||||
key: 'charts',
|
||||
title: i18n.ts.charts,
|
||||
|
@ -4,153 +4,82 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||
-->
|
||||
|
||||
<template>
|
||||
<MkStickyContainer>
|
||||
<template #header><XHeader :tabs="headerTabs"/></template>
|
||||
<MkSpacer :contentMax="700" :marginMin="16" :marginMax="32">
|
||||
<FormSuspense :p="init">
|
||||
<div class="_gaps_m">
|
||||
<MkFolder :defaultOpen="false">
|
||||
<template #icon><i class="ti ti-cloud"></i></template>
|
||||
<template #label>{{ i18n.ts.objectStorage }}</template>
|
||||
<MkStickyContainer>
|
||||
<template #header><XHeader :tabs="headerTabs"/></template>
|
||||
<MkSpacer :contentMax="700" :marginMin="16" :marginMax="32">
|
||||
<FormSuspense :p="init">
|
||||
<div class="_gaps_m">
|
||||
<MkSwitch v-model="useObjectStorage">{{ i18n.ts.useObjectStorage }}</MkSwitch>
|
||||
|
||||
<MkSwitch v-model="useObjectStorage">{{ i18n.ts.useObjectStorage }}</MkSwitch>
|
||||
<template v-if="useObjectStorage">
|
||||
<MkInput v-model="objectStorageBaseUrl" :placeholder="'https://example.com'" type="url">
|
||||
<template #label>{{ i18n.ts.objectStorageBaseUrl }}</template>
|
||||
<template #caption>{{ i18n.ts.objectStorageBaseUrlDesc }}</template>
|
||||
</MkInput>
|
||||
|
||||
<template v-if="useObjectStorage">
|
||||
<MkInput v-model="objectStorageBaseUrl" :placeholder="'https://example.com'" type="url">
|
||||
<template #label>{{ i18n.ts.objectStorageBaseUrl }}</template>
|
||||
<template #caption>{{ i18n.ts.objectStorageBaseUrlDesc }}</template>
|
||||
</MkInput>
|
||||
<MkInput v-model="objectStorageBucket">
|
||||
<template #label>{{ i18n.ts.objectStorageBucket }}</template>
|
||||
<template #caption>{{ i18n.ts.objectStorageBucketDesc }}</template>
|
||||
</MkInput>
|
||||
|
||||
<MkInput v-model="objectStorageBucket">
|
||||
<template #label>{{ i18n.ts.objectStorageBucket }}</template>
|
||||
<template #caption>{{ i18n.ts.objectStorageBucketDesc }}</template>
|
||||
</MkInput>
|
||||
<MkInput v-model="objectStoragePrefix">
|
||||
<template #label>{{ i18n.ts.objectStoragePrefix }}</template>
|
||||
<template #caption>{{ i18n.ts.objectStoragePrefixDesc }}</template>
|
||||
</MkInput>
|
||||
|
||||
<MkInput v-model="objectStoragePrefix">
|
||||
<template #label>{{ i18n.ts.objectStoragePrefix }}</template>
|
||||
<template #caption>{{ i18n.ts.objectStoragePrefixDesc }}</template>
|
||||
</MkInput>
|
||||
<MkInput v-model="objectStorageEndpoint" :placeholder="'example.com'">
|
||||
<template #label>{{ i18n.ts.objectStorageEndpoint }}</template>
|
||||
<template #prefix>https://</template>
|
||||
<template #caption>{{ i18n.ts.objectStorageEndpointDesc }}</template>
|
||||
</MkInput>
|
||||
|
||||
<MkInput v-model="objectStorageEndpoint" :placeholder="'example.com'">
|
||||
<template #label>{{ i18n.ts.objectStorageEndpoint }}</template>
|
||||
<template #prefix>https://</template>
|
||||
<template #caption>{{ i18n.ts.objectStorageEndpointDesc }}</template>
|
||||
</MkInput>
|
||||
<MkInput v-model="objectStorageRegion">
|
||||
<template #label>{{ i18n.ts.objectStorageRegion }}</template>
|
||||
<template #caption>{{ i18n.ts.objectStorageRegionDesc }}</template>
|
||||
</MkInput>
|
||||
|
||||
<MkInput v-model="objectStorageRegion">
|
||||
<template #label>{{ i18n.ts.objectStorageRegion }}</template>
|
||||
<template #caption>{{ i18n.ts.objectStorageRegionDesc }}</template>
|
||||
</MkInput>
|
||||
<FormSplit :minWidth="280">
|
||||
<MkInput v-model="objectStorageAccessKey">
|
||||
<template #prefix><i class="ti ti-key"></i></template>
|
||||
<template #label>Access key</template>
|
||||
</MkInput>
|
||||
|
||||
<FormSplit :minWidth="280">
|
||||
<MkInput v-model="objectStorageAccessKey">
|
||||
<template #prefix><i class="ti ti-key"></i></template>
|
||||
<template #label>Access key</template>
|
||||
</MkInput>
|
||||
<MkInput v-model="objectStorageSecretKey" type="password">
|
||||
<template #prefix><i class="ti ti-key"></i></template>
|
||||
<template #label>Secret key</template>
|
||||
</MkInput>
|
||||
</FormSplit>
|
||||
|
||||
<MkInput v-model="objectStorageSecretKey" type="password">
|
||||
<template #prefix><i class="ti ti-key"></i></template>
|
||||
<template #label>Secret key</template>
|
||||
</MkInput>
|
||||
</FormSplit>
|
||||
<MkSwitch v-model="objectStorageUseSSL">
|
||||
<template #label>{{ i18n.ts.objectStorageUseSSL }}</template>
|
||||
<template #caption>{{ i18n.ts.objectStorageUseSSLDesc }}</template>
|
||||
</MkSwitch>
|
||||
|
||||
<MkSwitch v-model="objectStorageUseSSL">
|
||||
<template #label>{{ i18n.ts.objectStorageUseSSL }}</template>
|
||||
<template #caption>{{ i18n.ts.objectStorageUseSSLDesc }}</template>
|
||||
</MkSwitch>
|
||||
<MkSwitch v-model="objectStorageUseProxy">
|
||||
<template #label>{{ i18n.ts.objectStorageUseProxy }}</template>
|
||||
<template #caption>{{ i18n.ts.objectStorageUseProxyDesc }}</template>
|
||||
</MkSwitch>
|
||||
|
||||
<MkSwitch v-model="objectStorageUseProxy">
|
||||
<template #label>{{ i18n.ts.objectStorageUseProxy }}</template>
|
||||
<template #caption>{{ i18n.ts.objectStorageUseProxyDesc }}</template>
|
||||
</MkSwitch>
|
||||
<MkSwitch v-model="objectStorageSetPublicRead">
|
||||
<template #label>{{ i18n.ts.objectStorageSetPublicRead }}</template>
|
||||
</MkSwitch>
|
||||
|
||||
<MkSwitch v-model="objectStorageSetPublicRead">
|
||||
<template #label>{{ i18n.ts.objectStorageSetPublicRead }}</template>
|
||||
</MkSwitch>
|
||||
|
||||
<MkSwitch v-model="objectStorageS3ForcePathStyle">
|
||||
<template #label>s3ForcePathStyle</template>
|
||||
<template #caption>{{ i18n.ts.s3ForcePathStyleDesc }}</template>
|
||||
</MkSwitch>
|
||||
</template>
|
||||
</MkFolder>
|
||||
|
||||
<MkFolder :defaultOpen="false">
|
||||
<template #icon><i class="ti ti-cloud"></i></template>
|
||||
<template #label>{{ i18n.ts.objectStorage }} ({{ i18n.ts.remote }})</template>
|
||||
|
||||
<MkSwitch v-model="useRemoteObjectStorage">{{ i18n.ts.useObjectStorage }} ({{ i18n.ts.remote }})</MkSwitch>
|
||||
|
||||
<template v-if="useRemoteObjectStorage">
|
||||
<MkInput v-model="remoteObjectStorageBaseUrl" :placeholder="'https://example.com'" type="url">
|
||||
<template #label>{{ i18n.ts.objectStorageBaseUrl }}</template>
|
||||
<template #caption>{{ i18n.ts.objectStorageBaseUrlDesc }}</template>
|
||||
</MkInput>
|
||||
|
||||
<MkInput v-model="remoteObjectStorageBucket">
|
||||
<template #label>{{ i18n.ts.objectStorageBucket }}</template>
|
||||
<template #caption>{{ i18n.ts.objectStorageBucketDesc }}</template>
|
||||
</MkInput>
|
||||
|
||||
<MkInput v-model="remoteObjectStoragePrefix">
|
||||
<template #label>{{ i18n.ts.objectStoragePrefix }}</template>
|
||||
<template #caption>{{ i18n.ts.objectStoragePrefixDesc }}</template>
|
||||
</MkInput>
|
||||
|
||||
<MkInput v-model="remoteObjectStorageEndpoint" :placeholder="'example.com'">
|
||||
<template #label>{{ i18n.ts.objectStorageEndpoint }}</template>
|
||||
<template #prefix>https://</template>
|
||||
<template #caption>{{ i18n.ts.objectStorageEndpointDesc }}</template>
|
||||
</MkInput>
|
||||
|
||||
<MkInput v-model="remoteObjectStorageRegion">
|
||||
<template #label>{{ i18n.ts.objectStorageRegion }}</template>
|
||||
<template #caption>{{ i18n.ts.objectStorageRegionDesc }}</template>
|
||||
</MkInput>
|
||||
|
||||
<FormSplit :minWidth="280">
|
||||
<MkInput v-model="remoteObjectStorageAccessKey">
|
||||
<template #prefix><i class="ti ti-key"></i></template>
|
||||
<template #label>Access key</template>
|
||||
</MkInput>
|
||||
|
||||
<MkInput v-model="remoteObjectStorageSecretKey" type="password">
|
||||
<template #prefix><i class="ti ti-key"></i></template>
|
||||
<template #label>Secret key</template>
|
||||
</MkInput>
|
||||
</FormSplit>
|
||||
|
||||
<MkSwitch v-model="remoteObjectStorageUseSSL">
|
||||
<template #label>{{ i18n.ts.objectStorageUseSSL }}</template>
|
||||
<template #caption>{{ i18n.ts.objectStorageUseSSLDesc }}</template>
|
||||
</MkSwitch>
|
||||
|
||||
<MkSwitch v-model="remoteObjectStorageUseProxy">
|
||||
<template #label>{{ i18n.ts.objectStorageUseProxy }}</template>
|
||||
<template #caption>{{ i18n.ts.objectStorageUseProxyDesc }}</template>
|
||||
</MkSwitch>
|
||||
|
||||
<MkSwitch v-model="remoteObjectStorageSetPublicRead">
|
||||
<template #label>{{ i18n.ts.objectStorageSetPublicRead }}</template>
|
||||
</MkSwitch>
|
||||
|
||||
<MkSwitch v-model="remoteObjectStorageS3ForcePathStyle">
|
||||
<template #label>s3ForcePathStyle</template>
|
||||
<template #caption>{{ i18n.ts.s3ForcePathStyleDesc }}</template>
|
||||
</MkSwitch>
|
||||
</template>
|
||||
</MkFolder>
|
||||
</div>
|
||||
</FormSuspense>
|
||||
</MkSpacer>
|
||||
<template #footer>
|
||||
<div :class="$style.footer">
|
||||
<MkSpacer :contentMax="700" :marginMin="16" :marginMax="16">
|
||||
<MkButton primary rounded @click="save"><i class="ti ti-check"></i> {{ i18n.ts.save }}</MkButton>
|
||||
</MkSpacer>
|
||||
<MkSwitch v-model="objectStorageS3ForcePathStyle">
|
||||
<template #label>s3ForcePathStyle</template>
|
||||
<template #caption>{{ i18n.ts.s3ForcePathStyleDesc }}</template>
|
||||
</MkSwitch>
|
||||
</template>
|
||||
</div>
|
||||
</template>
|
||||
</MkStickyContainer>
|
||||
</FormSuspense>
|
||||
</MkSpacer>
|
||||
<template #footer>
|
||||
<div :class="$style.footer">
|
||||
<MkSpacer :contentMax="700" :marginMin="16" :marginMax="16">
|
||||
<MkButton primary rounded @click="save"><i class="ti ti-check"></i> {{ i18n.ts.save }}</MkButton>
|
||||
</MkSpacer>
|
||||
</div>
|
||||
</template>
|
||||
</MkStickyContainer>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
@ -166,7 +95,6 @@ import { fetchInstance } from '@/instance.js';
|
||||
import { i18n } from '@/i18n.js';
|
||||
import { definePageMetadata } from '@/scripts/page-metadata.js';
|
||||
import MkButton from '@/components/MkButton.vue';
|
||||
import MkFolder from "@/components/MkFolder.vue";
|
||||
|
||||
const useObjectStorage = ref<boolean>(false);
|
||||
const objectStorageBaseUrl = ref<string | null>(null);
|
||||
@ -181,19 +109,6 @@ const objectStorageUseSSL = ref<boolean>(false);
|
||||
const objectStorageUseProxy = ref<boolean>(false);
|
||||
const objectStorageSetPublicRead = ref<boolean>(false);
|
||||
const objectStorageS3ForcePathStyle = ref<boolean>(true);
|
||||
const useRemoteObjectStorage = ref<boolean>(false);
|
||||
const remoteObjectStorageBaseUrl = ref<string | null>(null);
|
||||
const remoteObjectStorageBucket = ref<string | null>(null);
|
||||
const remoteObjectStoragePrefix = ref<string | null>(null);
|
||||
const remoteObjectStorageEndpoint = ref<string | null>(null);
|
||||
const remoteObjectStorageRegion = ref<string | null>(null);
|
||||
const remoteObjectStoragePort = ref<number | null>(null);
|
||||
const remoteObjectStorageAccessKey = ref<string | null>(null);
|
||||
const remoteObjectStorageSecretKey = ref<string | null>(null);
|
||||
const remoteObjectStorageUseSSL = ref<boolean>(false);
|
||||
const remoteObjectStorageUseProxy = ref<boolean>(false);
|
||||
const remoteObjectStorageSetPublicRead = ref<boolean>(false);
|
||||
const remoteObjectStorageS3ForcePathStyle = ref<boolean>(true);
|
||||
|
||||
async function init() {
|
||||
const meta = await misskeyApi('admin/meta');
|
||||
@ -210,19 +125,6 @@ async function init() {
|
||||
objectStorageUseProxy.value = meta.objectStorageUseProxy;
|
||||
objectStorageSetPublicRead.value = meta.objectStorageSetPublicRead;
|
||||
objectStorageS3ForcePathStyle.value = meta.objectStorageS3ForcePathStyle;
|
||||
useRemoteObjectStorage.value = meta.useRemoteObjectStorage;
|
||||
remoteObjectStorageBaseUrl.value = meta.remoteObjectStorageBaseUrl;
|
||||
remoteObjectStorageBucket.value = meta.remoteObjectStorageBucket;
|
||||
remoteObjectStoragePrefix.value = meta.remoteObjectStoragePrefix;
|
||||
remoteObjectStorageEndpoint.value = meta.remoteObjectStorageEndpoint;
|
||||
remoteObjectStorageRegion.value = meta.remoteObjectStorageRegion;
|
||||
remoteObjectStoragePort.value = meta.remoteObjectStoragePort;
|
||||
remoteObjectStorageAccessKey.value = meta.remoteObjectStorageAccessKey;
|
||||
remoteObjectStorageSecretKey.value = meta.remoteObjectStorageSecretKey;
|
||||
remoteObjectStorageUseSSL.value = meta.remoteObjectStorageUseSSL;
|
||||
remoteObjectStorageUseProxy.value = meta.remoteObjectStorageUseProxy;
|
||||
remoteObjectStorageSetPublicRead.value = meta.remoteObjectStorageSetPublicRead;
|
||||
remoteObjectStorageS3ForcePathStyle.value = meta.remoteObjectStorageS3ForcePathStyle;
|
||||
}
|
||||
|
||||
function save() {
|
||||
@ -240,19 +142,6 @@ function save() {
|
||||
objectStorageUseProxy: objectStorageUseProxy.value,
|
||||
objectStorageSetPublicRead: objectStorageSetPublicRead.value,
|
||||
objectStorageS3ForcePathStyle: objectStorageS3ForcePathStyle.value,
|
||||
useRemoteObjectStorage: useRemoteObjectStorage.value,
|
||||
remoteObjectStorageBaseUrl: remoteObjectStorageBaseUrl.value,
|
||||
remoteObjectStorageBucket: remoteObjectStorageBucket.value,
|
||||
remoteObjectStoragePrefix: remoteObjectStoragePrefix.value,
|
||||
remoteObjectStorageEndpoint: remoteObjectStorageEndpoint.value,
|
||||
remoteObjectStorageRegion: remoteObjectStorageRegion.value,
|
||||
remoteObjectStoragePort: remoteObjectStoragePort.value,
|
||||
remoteObjectStorageAccessKey: remoteObjectStorageAccessKey.value,
|
||||
remoteObjectStorageSecretKey: remoteObjectStorageSecretKey.value,
|
||||
remoteObjectStorageUseSSL: remoteObjectStorageUseSSL.value,
|
||||
remoteObjectStorageUseProxy: remoteObjectStorageUseProxy.value,
|
||||
remoteObjectStorageSetPublicRead: remoteObjectStorageSetPublicRead.value,
|
||||
remoteObjectStorageS3ForcePathStyle: remoteObjectStorageS3ForcePathStyle.value,
|
||||
}).then(() => {
|
||||
fetchInstance(true);
|
||||
});
|
||||
|
@ -11,7 +11,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||
<div class="shape2"></div>
|
||||
<div class="logo-wrapper">
|
||||
<div class="powered-by">Powered by</div>
|
||||
<img :src="misskeysvg" class="misskey" alt="Misskey Logo"/>
|
||||
<img :src="misskeysvg" class="misskey"/>
|
||||
</div>
|
||||
<div class="emojis">
|
||||
<MkEmoji :normal="true" :noStyle="true" emoji="🍮"/>
|
||||
@ -23,15 +23,45 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||
<div class="contents">
|
||||
<MkVisitorDashboard/>
|
||||
</div>
|
||||
<div v-if="instances && instances.length > 0" class="federation">
|
||||
<MarqueeText :duration="40">
|
||||
<MkA v-for="instance in instances" :key="instance.id" :class="$style.federationInstance" :to="`/instance-info/${instance.host}`" behavior="window">
|
||||
<!--<MkInstanceCardMini :instance="instance"/>-->
|
||||
<img v-if="instance.iconUrl" class="icon" :src="getInstanceIcon(instance)" alt=""/>
|
||||
<span class="name _monospace">{{ instance.host }}</span>
|
||||
</MkA>
|
||||
</MarqueeText>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref } from 'vue';
|
||||
import * as Misskey from 'misskey-js';
|
||||
import XTimeline from './welcome.timeline.vue';
|
||||
import MarqueeText from '@/components/MkMarquee.vue';
|
||||
import MkFeaturedPhotos from '@/components/MkFeaturedPhotos.vue';
|
||||
import misskeysvg from '/client-assets/misskey.svg';
|
||||
import { misskeyApiGet } from '@/scripts/misskey-api.js';
|
||||
import MkVisitorDashboard from '@/components/MkVisitorDashboard.vue';
|
||||
import { getProxiedImageUrl } from '@/scripts/media-proxy.js';
|
||||
import { instance as meta } from '@/instance.js';
|
||||
|
||||
const instances = ref<Misskey.entities.FederationInstance[]>();
|
||||
|
||||
function getInstanceIcon(instance: Misskey.entities.FederationInstance): string {
|
||||
if (!instance.iconUrl) {
|
||||
return '';
|
||||
}
|
||||
return getProxiedImageUrl(instance.iconUrl, 'preview');
|
||||
}
|
||||
|
||||
misskeyApiGet('federation/instances', {
|
||||
sort: '+pubSub',
|
||||
limit: 20,
|
||||
}).then(_instances => {
|
||||
instances.value = _instances;
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
|
@ -4,10 +4,10 @@
|
||||
*/
|
||||
|
||||
import { defineAsyncComponent } from 'vue';
|
||||
import { host } from '@@/js/config.js';
|
||||
import type { MenuItem } from '@/types/menu.js';
|
||||
import * as os from '@/os.js';
|
||||
import { instance } from '@/instance.js';
|
||||
import { host } from '@@/js/config.js';
|
||||
import { i18n } from '@/i18n.js';
|
||||
import { $i } from '@/account.js';
|
||||
|
||||
@ -56,6 +56,11 @@ export function openInstanceMenu(ev: MouseEvent) {
|
||||
text: i18n.ts.customEmojis,
|
||||
icon: 'ti ti-icons',
|
||||
to: '/about#emojis',
|
||||
}, {
|
||||
type: 'link',
|
||||
text: i18n.ts.federation,
|
||||
icon: 'ti ti-whirl',
|
||||
to: '/about#federation',
|
||||
}, {
|
||||
type: 'link',
|
||||
text: i18n.ts.charts,
|
||||
|
@ -5169,18 +5169,6 @@ export type operations = {
|
||||
objectStorageUseSSL: boolean;
|
||||
objectStorageUseProxy: boolean;
|
||||
objectStorageSetPublicRead: boolean;
|
||||
useRemoteObjectStorage: boolean;
|
||||
remoteObjectStorageBaseUrl: string | null;
|
||||
remoteObjectStorageBucket: string | null;
|
||||
remoteObjectStoragePrefix: string | null;
|
||||
remoteObjectStorageEndpoint: string | null;
|
||||
remoteObjectStorageRegion: string | null;
|
||||
remoteObjectStoragePort: number | null;
|
||||
remoteObjectStorageAccessKey: string | null;
|
||||
remoteObjectStorageSecretKey: string | null;
|
||||
remoteObjectStorageUseSSL: boolean;
|
||||
remoteObjectStorageUseProxy: boolean;
|
||||
remoteObjectStorageSetPublicRead: boolean;
|
||||
enableIpLogging: boolean;
|
||||
enableActiveEmailValidation: boolean;
|
||||
enableVerifymailApi: boolean;
|
||||
@ -5216,7 +5204,6 @@ export type operations = {
|
||||
name: string | null;
|
||||
shortName: string | null;
|
||||
objectStorageS3ForcePathStyle: boolean;
|
||||
remoteObjectStorageS3ForcePathStyle: boolean;
|
||||
privacyPolicyUrl: string | null;
|
||||
inquiryUrl: string | null;
|
||||
repositoryUrl: string | null;
|
||||
@ -9565,19 +9552,6 @@ export type operations = {
|
||||
objectStorageUseProxy?: boolean;
|
||||
objectStorageSetPublicRead?: boolean;
|
||||
objectStorageS3ForcePathStyle?: boolean;
|
||||
useRemoteObjectStorage?: boolean;
|
||||
remoteObjectStorageBaseUrl?: string | null;
|
||||
remoteObjectStorageBucket?: string | null;
|
||||
remoteObjectStoragePrefix?: string | null;
|
||||
remoteObjectStorageEndpoint?: string | null;
|
||||
remoteObjectStorageRegion?: string | null;
|
||||
remoteObjectStoragePort?: number | null;
|
||||
remoteObjectStorageAccessKey?: string | null;
|
||||
remoteObjectStorageSecretKey?: string | null;
|
||||
remoteObjectStorageUseSSL?: boolean;
|
||||
remoteObjectStorageUseProxy?: boolean;
|
||||
remoteObjectStorageSetPublicRead?: boolean;
|
||||
remoteObjectStorageS3ForcePathStyle?: boolean;
|
||||
enableIpLogging?: boolean;
|
||||
enableActiveEmailValidation?: boolean;
|
||||
enableVerifymailApi?: boolean;
|
||||
|
Loading…
Reference in New Issue
Block a user