Feat: マネージドなサービスで使えるように
オブジェクトストレージの設定を秘匿するように Config で設定できます。 その他バグ修正
This commit is contained in:
parent
c2cf3149ab
commit
9f5b0c3ca1
|
@ -186,6 +186,24 @@ redis:
|
||||||
# index: ''
|
# index: ''
|
||||||
# scope: local
|
# scope: local
|
||||||
|
|
||||||
|
# ┌─────────────────────────────┐
|
||||||
|
#───┘ ObjectStorage configuration └─────────────────────────────
|
||||||
|
|
||||||
|
#objectStorage:
|
||||||
|
# useObjectStorage: true
|
||||||
|
# objectStorageBaseUrl: 'https://'
|
||||||
|
# objectStorageBucket: ''
|
||||||
|
# objectStoragePrefix: ''
|
||||||
|
# objectStorageEndpoint: '' # Please enter the following format: s3.example.com
|
||||||
|
# objectStorageRegion: ''
|
||||||
|
# objectStoragePort: 443
|
||||||
|
# objectStorageAccessKey: ''
|
||||||
|
# objectStorageSecretKey: ''
|
||||||
|
# objectStorageUseSSL: true
|
||||||
|
# objectStorageUseProxy: false
|
||||||
|
# objectStorageSetPublicRead: true
|
||||||
|
# objectStorageS3ForcePathStyle: true
|
||||||
|
|
||||||
# ┌───────────────┐
|
# ┌───────────────┐
|
||||||
#───┘ ID generation └───────────────────────────────────────────
|
#───┘ ID generation └───────────────────────────────────────────
|
||||||
|
|
||||||
|
|
4
locales/index.d.ts
vendored
4
locales/index.d.ts
vendored
|
@ -60,6 +60,10 @@ export interface Locale extends ILocale {
|
||||||
* OK
|
* OK
|
||||||
*/
|
*/
|
||||||
"ok": string;
|
"ok": string;
|
||||||
|
/**
|
||||||
|
* マネージドインスタンスではこの設定は変更することができません。
|
||||||
|
*/
|
||||||
|
"managedInstanceIsNotEditable": string;
|
||||||
/**
|
/**
|
||||||
* ノートの投稿フォームを開き直した際に、下書きを復元しないようにします。
|
* ノートの投稿フォームを開き直した際に、下書きを復元しないようにします。
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -11,7 +11,7 @@ password: "パスワード"
|
||||||
forgotPassword: "パスワードを忘れた"
|
forgotPassword: "パスワードを忘れた"
|
||||||
fetchingAsApObject: "連合に照会中"
|
fetchingAsApObject: "連合に照会中"
|
||||||
ok: "OK"
|
ok: "OK"
|
||||||
|
managedInstanceIsNotEditable: "マネージドインスタンスではこの設定は変更することができません。"
|
||||||
disableNoteDraftingDescription: "ノートの投稿フォームを開き直した際に、下書きを復元しないようにします。"
|
disableNoteDraftingDescription: "ノートの投稿フォームを開き直した際に、下書きを復元しないようにします。"
|
||||||
setDefaultProfileConfirm: "このプロファイルをデフォルトにしますか?"
|
setDefaultProfileConfirm: "このプロファイルをデフォルトにしますか?"
|
||||||
emojiPickerProfile: "絵文字ピッカーのプロファイル"
|
emojiPickerProfile: "絵文字ピッカーのプロファイル"
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
{
|
{
|
||||||
"name": "type4ny",
|
"name": "type4ny",
|
||||||
"version": "2024.5.0-mattyatea4",
|
"version": "0.1.0-beta",
|
||||||
"codename": "nasubi",
|
"codename": "apollo-11",
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/type4ny-project/type4ny.git"
|
"url": "https://github.com/type4ny-project/type4ny.git"
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Misskey Entry Point!
|
* Type4ny Entry Point!
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import cluster from 'node:cluster';
|
import cluster from 'node:cluster';
|
||||||
|
@ -19,7 +19,7 @@ import { readyRef } from './ready.js';
|
||||||
|
|
||||||
import 'reflect-metadata';
|
import 'reflect-metadata';
|
||||||
|
|
||||||
process.title = `Misskey (${cluster.isPrimary ? 'master' : 'worker'})`;
|
process.title = `Type4ny (${cluster.isPrimary ? 'master' : 'worker'})`;
|
||||||
|
|
||||||
Error.stackTraceLimit = Infinity;
|
Error.stackTraceLimit = Infinity;
|
||||||
EventEmitter.defaultMaxListeners = 128;
|
EventEmitter.defaultMaxListeners = 128;
|
||||||
|
|
|
@ -27,28 +27,29 @@ const meta = JSON.parse(fs.readFileSync(`${_dirname}/../../../../built/meta.json
|
||||||
const logger = new Logger('core', 'cyan');
|
const logger = new Logger('core', 'cyan');
|
||||||
const bootLogger = logger.createSubLogger('boot', 'magenta');
|
const bootLogger = logger.createSubLogger('boot', 'magenta');
|
||||||
|
|
||||||
const themeColor = chalk.hex('#86b300');
|
const themeColor = chalk.hex('#00a968');
|
||||||
|
|
||||||
function greet() {
|
function greet() {
|
||||||
if (!envOption.quiet) {
|
if (!envOption.quiet) {
|
||||||
//#region Misskey logo
|
//#region Type4ny logo
|
||||||
const v = `v${meta.version}`;
|
const v = `v${meta.version}`;
|
||||||
console.log(themeColor(' _____ _ _ '));
|
console.log(themeColor(' _____ _ _ '));
|
||||||
console.log(themeColor(' | |_|___ ___| |_ ___ _ _ '));
|
console.log(themeColor('|_ _| _ _ __ ___| | | _ _ _ _ '));
|
||||||
console.log(themeColor(' | | | | |_ -|_ -| \'_| -_| | |'));
|
console.log(themeColor(' | || || | \'_ \\/ -_)_ _| \' \\ || |'));
|
||||||
console.log(themeColor(' |_|_|_|_|___|___|_,_|___|_ |'));
|
console.log(themeColor(' |_| \\_, | .__/\\___| |_||_||_\\_, |'));
|
||||||
console.log(' ' + chalk.gray(v) + themeColor(' |___|\n'.substring(v.length)));
|
console.log(themeColor(' |__/|_| |__/ '));
|
||||||
|
console.log(chalk.gray(v));
|
||||||
//#endregion
|
//#endregion
|
||||||
|
|
||||||
console.log(' Misskey is an open-source decentralized microblogging platform.');
|
console.log(' Type4ny is an open-source decentralized microblogging platform.');
|
||||||
console.log(chalk.rgb(255, 136, 0)(' If you like Misskey, please donate to support development. https://www.patreon.com/syuilo'));
|
console.log(chalk.rgb(255, 136, 0)(' If you like Type4ny, please donate to support development. https://mattyatea.fanbox.cc'));
|
||||||
|
|
||||||
console.log('');
|
console.log('');
|
||||||
console.log(chalkTemplate`--- ${os.hostname()} {gray (PID: ${process.pid.toString()})} ---`);
|
console.log(chalkTemplate`--- ${os.hostname()} {gray (PID: ${process.pid.toString()})} ---`);
|
||||||
}
|
}
|
||||||
|
|
||||||
bootLogger.info('Welcome to Misskey!');
|
bootLogger.info('Welcome to Type4ny!');
|
||||||
bootLogger.info(`Misskey v${meta.version}`, null, true);
|
bootLogger.info(`Type4ny v${meta.version}`, null, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -71,7 +72,7 @@ export async function masterMain() {
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
bootLogger.succ('Misskey initialized');
|
bootLogger.succ('Type4ny initialized');
|
||||||
|
|
||||||
if (config.sentryForBackend) {
|
if (config.sentryForBackend) {
|
||||||
Sentry.init({
|
Sentry.init({
|
||||||
|
@ -121,6 +122,7 @@ export async function masterMain() {
|
||||||
|
|
||||||
function showEnvironment(): void {
|
function showEnvironment(): void {
|
||||||
const env = process.env.NODE_ENV;
|
const env = process.env.NODE_ENV;
|
||||||
|
const managed = process.env.IS_MANAGED === 'true';
|
||||||
const logger = bootLogger.createSubLogger('env');
|
const logger = bootLogger.createSubLogger('env');
|
||||||
logger.info(typeof env === 'undefined' ? 'NODE_ENV is not set' : `NODE_ENV: ${env}`);
|
logger.info(typeof env === 'undefined' ? 'NODE_ENV is not set' : `NODE_ENV: ${env}`);
|
||||||
|
|
||||||
|
@ -128,6 +130,9 @@ function showEnvironment(): void {
|
||||||
logger.warn('The environment is not in production mode.');
|
logger.warn('The environment is not in production mode.');
|
||||||
logger.warn('DO NOT USE FOR PRODUCTION PURPOSE!', null, true);
|
logger.warn('DO NOT USE FOR PRODUCTION PURPOSE!', null, true);
|
||||||
}
|
}
|
||||||
|
if (managed) {
|
||||||
|
logger.info('Type4ny is running in a managed mode.');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function showNodejsVersion(): void {
|
function showNodejsVersion(): void {
|
||||||
|
|
|
@ -62,6 +62,22 @@ type Source = {
|
||||||
|
|
||||||
publishTarballInsteadOfProvideRepositoryUrl?: boolean;
|
publishTarballInsteadOfProvideRepositoryUrl?: boolean;
|
||||||
|
|
||||||
|
objectStorage?: {
|
||||||
|
useObjectStorage: boolean;
|
||||||
|
objectStorageBaseUrl: string;
|
||||||
|
objectStorageBucket: string;
|
||||||
|
objectStoragePrefix: string;
|
||||||
|
objectStorageEndpoint: string;
|
||||||
|
objectStorageRegion: string;
|
||||||
|
objectStoragePort?: number;
|
||||||
|
objectStorageAccessKey: string;
|
||||||
|
objectStorageSecretKey: string;
|
||||||
|
objectStorageUseSSL?: boolean;
|
||||||
|
objectStorageUseProxy?: boolean;
|
||||||
|
objectStorageSetPublicRead?: boolean;
|
||||||
|
objectStorageS3ForcePathStyle?: boolean;
|
||||||
|
};
|
||||||
|
|
||||||
proxy?: string;
|
proxy?: string;
|
||||||
proxySmtp?: string;
|
proxySmtp?: string;
|
||||||
proxyBypassHosts?: string[];
|
proxyBypassHosts?: string[];
|
||||||
|
@ -95,6 +111,7 @@ type Source = {
|
||||||
perChannelMaxNoteCacheCount?: number;
|
perChannelMaxNoteCacheCount?: number;
|
||||||
perUserNotificationsMaxCount?: number;
|
perUserNotificationsMaxCount?: number;
|
||||||
deactivateAntennaThreshold?: number;
|
deactivateAntennaThreshold?: number;
|
||||||
|
maxLocalUsers?: number;
|
||||||
pidFile: string;
|
pidFile: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -174,6 +191,22 @@ export type Config = {
|
||||||
perChannelMaxNoteCacheCount: number;
|
perChannelMaxNoteCacheCount: number;
|
||||||
perUserNotificationsMaxCount: number;
|
perUserNotificationsMaxCount: number;
|
||||||
deactivateAntennaThreshold: number;
|
deactivateAntennaThreshold: number;
|
||||||
|
maxLocalUsers: number;
|
||||||
|
objectStorage?: {
|
||||||
|
useObjectStorage?: boolean;
|
||||||
|
objectStorageBaseUrl?: string;
|
||||||
|
objectStorageBucket?: string;
|
||||||
|
objectStoragePrefix?: string;
|
||||||
|
objectStorageEndpoint?: string;
|
||||||
|
objectStorageRegion?: string;
|
||||||
|
objectStoragePort?: number;
|
||||||
|
objectStorageAccessKey?: string;
|
||||||
|
objectStorageSecretKey?: string;
|
||||||
|
objectStorageUseSSL?: boolean;
|
||||||
|
objectStorageUseProxy?: boolean;
|
||||||
|
objectStorageSetPublicRead?: boolean;
|
||||||
|
objectStorageS3ForcePathStyle?: boolean;
|
||||||
|
};
|
||||||
pidFile: string;
|
pidFile: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -269,12 +302,14 @@ export function loadConfig(): Config {
|
||||||
videoThumbnailGenerator: config.videoThumbnailGenerator ?
|
videoThumbnailGenerator: config.videoThumbnailGenerator ?
|
||||||
config.videoThumbnailGenerator.endsWith('/') ? config.videoThumbnailGenerator.substring(0, config.videoThumbnailGenerator.length - 1) : config.videoThumbnailGenerator
|
config.videoThumbnailGenerator.endsWith('/') ? config.videoThumbnailGenerator.substring(0, config.videoThumbnailGenerator.length - 1) : config.videoThumbnailGenerator
|
||||||
: null,
|
: null,
|
||||||
userAgent: `Misskey/${version} (${config.url})`,
|
userAgent: `Type4ny/${version} (${config.url})`,
|
||||||
clientEntry: clientManifest['src/_boot_.ts'],
|
clientEntry: clientManifest['src/_boot_.ts'],
|
||||||
clientManifestExists: clientManifestExists,
|
clientManifestExists: clientManifestExists,
|
||||||
perChannelMaxNoteCacheCount: config.perChannelMaxNoteCacheCount ?? 1000,
|
perChannelMaxNoteCacheCount: config.perChannelMaxNoteCacheCount ?? 1000,
|
||||||
perUserNotificationsMaxCount: config.perUserNotificationsMaxCount ?? 500,
|
perUserNotificationsMaxCount: config.perUserNotificationsMaxCount ?? 500,
|
||||||
deactivateAntennaThreshold: config.deactivateAntennaThreshold ?? (1000 * 60 * 60 * 24 * 7),
|
deactivateAntennaThreshold: config.deactivateAntennaThreshold ?? (1000 * 60 * 60 * 24 * 7),
|
||||||
|
maxLocalUsers: config.maxLocalUsers ?? -1,
|
||||||
|
objectStorage: config.objectStorage ?? {},
|
||||||
pidFile: config.pidFile,
|
pidFile: config.pidFile,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,47 +6,79 @@
|
||||||
import { URL } from 'node:url';
|
import { URL } from 'node:url';
|
||||||
import * as http from 'node:http';
|
import * as http from 'node:http';
|
||||||
import * as https from 'node:https';
|
import * as https from 'node:https';
|
||||||
import { Injectable } from '@nestjs/common';
|
import { Inject, Injectable } from '@nestjs/common';
|
||||||
import { DeleteObjectCommand, S3Client } from '@aws-sdk/client-s3';
|
import { DeleteObjectCommand, S3Client } from '@aws-sdk/client-s3';
|
||||||
import { Upload } from '@aws-sdk/lib-storage';
|
import { Upload } from '@aws-sdk/lib-storage';
|
||||||
import { NodeHttpHandler, NodeHttpHandlerOptions } from '@smithy/node-http-handler';
|
import { NodeHttpHandler, NodeHttpHandlerOptions } from '@smithy/node-http-handler';
|
||||||
import type { MiMeta } from '@/models/Meta.js';
|
import type { MiMeta } from '@/models/Meta.js';
|
||||||
import { HttpRequestService } from '@/core/HttpRequestService.js';
|
import { HttpRequestService } from '@/core/HttpRequestService.js';
|
||||||
import { bindThis } from '@/decorators.js';
|
import { bindThis } from '@/decorators.js';
|
||||||
|
import { DI } from '@/di-symbols.js';
|
||||||
|
import type { Config } from '@/config.js';
|
||||||
|
import { envOption } from '@/env.js';
|
||||||
import type { DeleteObjectCommandInput, PutObjectCommandInput } from '@aws-sdk/client-s3';
|
import type { DeleteObjectCommandInput, PutObjectCommandInput } from '@aws-sdk/client-s3';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class S3Service {
|
export class S3Service {
|
||||||
constructor(
|
constructor(
|
||||||
private httpRequestService: HttpRequestService,
|
private httpRequestService: HttpRequestService,
|
||||||
|
@Inject(DI.config)
|
||||||
|
private config: Config,
|
||||||
) {
|
) {
|
||||||
}
|
}
|
||||||
|
|
||||||
@bindThis
|
@bindThis
|
||||||
public getS3Client(meta: MiMeta): S3Client {
|
public getS3Client(meta: MiMeta): S3Client {
|
||||||
const u = meta.objectStorageEndpoint
|
if (envOption.managed){
|
||||||
? `${meta.objectStorageUseSSL ? 'https' : 'http'}://${meta.objectStorageEndpoint}`
|
const objectStorageConfig = this.config.objectStorage;
|
||||||
: `${meta.objectStorageUseSSL ? 'https' : 'http'}://example.net`; // dummy url to select http(s) agent
|
const u = objectStorageConfig?.objectStorageEndpoint
|
||||||
|
? `${objectStorageConfig.objectStorageUseSSL ? 'https' : 'http'}://${objectStorageConfig.objectStorageEndpoint}`
|
||||||
|
: `${objectStorageConfig?.objectStorageUseSSL ? 'https' : 'http'}://example.net`; // dummy url to select http(s) agent
|
||||||
|
|
||||||
const agent = this.httpRequestService.getAgentByUrl(new URL(u), !meta.objectStorageUseProxy);
|
const agent = this.httpRequestService.getAgentByUrl(new URL(u), !objectStorageConfig?.objectStorageUseProxy);
|
||||||
const handlerOption: NodeHttpHandlerOptions = {};
|
const handlerOption: NodeHttpHandlerOptions = {};
|
||||||
if (meta.objectStorageUseSSL) {
|
if (meta.objectStorageUseSSL) {
|
||||||
handlerOption.httpsAgent = agent as https.Agent;
|
handlerOption.httpsAgent = agent as https.Agent;
|
||||||
|
} else {
|
||||||
|
handlerOption.httpAgent = agent as http.Agent;
|
||||||
|
}
|
||||||
|
|
||||||
|
return new S3Client({
|
||||||
|
endpoint: objectStorageConfig?.objectStorageEndpoint ? u : undefined,
|
||||||
|
credentials: (objectStorageConfig?.objectStorageAccessKey && objectStorageConfig?.objectStorageSecretKey ) ? {
|
||||||
|
accessKeyId: objectStorageConfig.objectStorageAccessKey,
|
||||||
|
secretAccessKey: objectStorageConfig.objectStorageSecretKey,
|
||||||
|
} : undefined,
|
||||||
|
region: objectStorageConfig?.objectStorageRegion ? objectStorageConfig.objectStorageRegion : undefined, // 空文字列もundefinedにするため ?? は使わない
|
||||||
|
tls: objectStorageConfig?.objectStorageUseSSL ?? false,
|
||||||
|
forcePathStyle: objectStorageConfig?.objectStorageEndpoint ? objectStorageConfig?.objectStorageS3ForcePathStyle : false, // AWS with endPoint omitted
|
||||||
|
requestHandler: new NodeHttpHandler(handlerOption),
|
||||||
|
});
|
||||||
} else {
|
} else {
|
||||||
handlerOption.httpAgent = agent as http.Agent;
|
const u = meta.objectStorageEndpoint
|
||||||
}
|
? `${meta.objectStorageUseSSL ? 'https' : 'http'}://${meta.objectStorageEndpoint}`
|
||||||
|
: `${meta.objectStorageUseSSL ? 'https' : 'http'}://example.net`; // dummy url to select http(s) agent
|
||||||
|
|
||||||
return new S3Client({
|
const agent = this.httpRequestService.getAgentByUrl(new URL(u), !meta.objectStorageUseProxy);
|
||||||
endpoint: meta.objectStorageEndpoint ? u : undefined,
|
const handlerOption: NodeHttpHandlerOptions = {};
|
||||||
credentials: (meta.objectStorageAccessKey !== null && meta.objectStorageSecretKey !== null) ? {
|
if (meta.objectStorageUseSSL) {
|
||||||
accessKeyId: meta.objectStorageAccessKey,
|
handlerOption.httpsAgent = agent as https.Agent;
|
||||||
secretAccessKey: meta.objectStorageSecretKey,
|
} else {
|
||||||
} : undefined,
|
handlerOption.httpAgent = agent as http.Agent;
|
||||||
region: meta.objectStorageRegion ? meta.objectStorageRegion : undefined, // 空文字列もundefinedにするため ?? は使わない
|
}
|
||||||
tls: meta.objectStorageUseSSL,
|
|
||||||
forcePathStyle: meta.objectStorageEndpoint ? meta.objectStorageS3ForcePathStyle : false, // AWS with endPoint omitted
|
return new S3Client({
|
||||||
requestHandler: new NodeHttpHandler(handlerOption),
|
endpoint: meta.objectStorageEndpoint ? u : undefined,
|
||||||
});
|
credentials: (meta.objectStorageAccessKey !== null && meta.objectStorageSecretKey !== null) ? {
|
||||||
|
accessKeyId: meta.objectStorageAccessKey,
|
||||||
|
secretAccessKey: meta.objectStorageSecretKey,
|
||||||
|
} : undefined,
|
||||||
|
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
|
@bindThis
|
||||||
|
@ -67,3 +99,4 @@ export class S3Service {
|
||||||
return client.send(new DeleteObjectCommand(input));
|
return client.send(new DeleteObjectCommand(input));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -21,6 +21,7 @@ import { bindThis } from '@/decorators.js';
|
||||||
import UsersChart from '@/core/chart/charts/users.js';
|
import UsersChart from '@/core/chart/charts/users.js';
|
||||||
import { UtilityService } from '@/core/UtilityService.js';
|
import { UtilityService } from '@/core/UtilityService.js';
|
||||||
import { MetaService } from '@/core/MetaService.js';
|
import { MetaService } from '@/core/MetaService.js';
|
||||||
|
import type { Config } from '@/config.js';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class SignupService {
|
export class SignupService {
|
||||||
|
@ -34,6 +35,9 @@ export class SignupService {
|
||||||
@Inject(DI.usedUsernamesRepository)
|
@Inject(DI.usedUsernamesRepository)
|
||||||
private usedUsernamesRepository: UsedUsernamesRepository,
|
private usedUsernamesRepository: UsedUsernamesRepository,
|
||||||
|
|
||||||
|
@Inject(DI.config)
|
||||||
|
private config: Config,
|
||||||
|
|
||||||
private utilityService: UtilityService,
|
private utilityService: UtilityService,
|
||||||
private userEntityService: UserEntityService,
|
private userEntityService: UserEntityService,
|
||||||
private idService: IdService,
|
private idService: IdService,
|
||||||
|
@ -58,7 +62,9 @@ export class SignupService {
|
||||||
if (!this.userEntityService.validateLocalUsername(username)) {
|
if (!this.userEntityService.validateLocalUsername(username)) {
|
||||||
throw new Error('INVALID_USERNAME');
|
throw new Error('INVALID_USERNAME');
|
||||||
}
|
}
|
||||||
|
if (this.config.maxLocalUsers !== -1 && await this.usersRepository.count({ where: { host: IsNull() } }) >= this.config.maxLocalUsers) {
|
||||||
|
throw new Error('MAX_LOCAL_USERS');
|
||||||
|
}
|
||||||
if (password != null && passwordHash == null) {
|
if (password != null && passwordHash == null) {
|
||||||
// Validate password
|
// Validate password
|
||||||
if (!this.userEntityService.validatePassword(password)) {
|
if (!this.userEntityService.validatePassword(password)) {
|
||||||
|
|
|
@ -11,6 +11,7 @@ const envOption = {
|
||||||
verbose: false,
|
verbose: false,
|
||||||
withLogTime: false,
|
withLogTime: false,
|
||||||
quiet: false,
|
quiet: false,
|
||||||
|
managed: true,
|
||||||
};
|
};
|
||||||
|
|
||||||
for (const key of Object.keys(envOption) as (keyof typeof envOption)[]) {
|
for (const key of Object.keys(envOption) as (keyof typeof envOption)[]) {
|
||||||
|
|
|
@ -379,14 +379,14 @@ export class MiMeta {
|
||||||
|
|
||||||
@Column('varchar', {
|
@Column('varchar', {
|
||||||
length: 1024,
|
length: 1024,
|
||||||
default: 'https://github.com/misskey-dev/misskey',
|
default: 'https://github.com/type4ny-project/type4ny',
|
||||||
nullable: true,
|
nullable: true,
|
||||||
})
|
})
|
||||||
public repositoryUrl: string | null;
|
public repositoryUrl: string | null;
|
||||||
|
|
||||||
@Column('varchar', {
|
@Column('varchar', {
|
||||||
length: 1024,
|
length: 1024,
|
||||||
default: 'https://github.com/misskey-dev/misskey/issues/new',
|
default: 'https://github.com/type4ny-project/type4ny/issues/new',
|
||||||
nullable: true,
|
nullable: true,
|
||||||
})
|
})
|
||||||
public feedbackUrl: string | null;
|
public feedbackUrl: string | null;
|
||||||
|
|
|
@ -124,7 +124,7 @@ export class NodeinfoServerService {
|
||||||
enableEmail: meta.enableEmail,
|
enableEmail: meta.enableEmail,
|
||||||
enableServiceWorker: meta.enableServiceWorker,
|
enableServiceWorker: meta.enableServiceWorker,
|
||||||
proxyAccountName: proxyAccount ? proxyAccount.username : null,
|
proxyAccountName: proxyAccount ? proxyAccount.username : null,
|
||||||
themeColor: meta.themeColor ?? '#86b300',
|
themeColor: meta.themeColor ?? '#00a968',
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
if (version >= 21) {
|
if (version >= 21) {
|
||||||
|
|
|
@ -9,6 +9,7 @@ import { MetaService } from '@/core/MetaService.js';
|
||||||
import type { Config } from '@/config.js';
|
import type { Config } from '@/config.js';
|
||||||
import { DI } from '@/di-symbols.js';
|
import { DI } from '@/di-symbols.js';
|
||||||
import { DEFAULT_POLICIES } from '@/core/RoleService.js';
|
import { DEFAULT_POLICIES } from '@/core/RoleService.js';
|
||||||
|
import {envOption} from "@/env.js";
|
||||||
|
|
||||||
export const meta = {
|
export const meta = {
|
||||||
tags: ['meta'],
|
tags: ['meta'],
|
||||||
|
@ -525,131 +526,260 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
||||||
) {
|
) {
|
||||||
super(meta, paramDef, async () => {
|
super(meta, paramDef, async () => {
|
||||||
const instance = await this.metaService.fetch(true);
|
const instance = await this.metaService.fetch(true);
|
||||||
|
if (!envOption.managed) {
|
||||||
|
return {
|
||||||
|
maintainerName: instance.maintainerName,
|
||||||
|
maintainerEmail: instance.maintainerEmail,
|
||||||
|
version: this.config.version,
|
||||||
|
name: instance.name,
|
||||||
|
shortName: instance.shortName,
|
||||||
|
uri: this.config.url,
|
||||||
|
description: instance.description,
|
||||||
|
langs: instance.langs,
|
||||||
|
tosUrl: instance.termsOfServiceUrl,
|
||||||
|
repositoryUrl: instance.repositoryUrl,
|
||||||
|
feedbackUrl: instance.feedbackUrl,
|
||||||
|
impressumUrl: instance.impressumUrl,
|
||||||
|
privacyPolicyUrl: instance.privacyPolicyUrl,
|
||||||
|
inquiryUrl: instance.inquiryUrl,
|
||||||
|
disableRegistration: instance.disableRegistration,
|
||||||
|
emailRequiredForSignup: instance.emailRequiredForSignup,
|
||||||
|
enableHcaptcha: instance.enableHcaptcha,
|
||||||
|
hcaptchaSiteKey: instance.hcaptchaSiteKey,
|
||||||
|
enableMcaptcha: instance.enableMcaptcha,
|
||||||
|
mcaptchaSiteKey: instance.mcaptchaSitekey,
|
||||||
|
mcaptchaInstanceUrl: instance.mcaptchaInstanceUrl,
|
||||||
|
enableRecaptcha: instance.enableRecaptcha,
|
||||||
|
recaptchaSiteKey: instance.recaptchaSiteKey,
|
||||||
|
enableTurnstile: instance.enableTurnstile,
|
||||||
|
turnstileSiteKey: instance.turnstileSiteKey,
|
||||||
|
swPublickey: instance.swPublicKey,
|
||||||
|
themeColor: instance.themeColor,
|
||||||
|
requestEmojiAllOk: instance.requestEmojiAllOk,
|
||||||
|
mascotImageUrl: instance.mascotImageUrl,
|
||||||
|
bannerUrl: instance.bannerUrl,
|
||||||
|
serverErrorImageUrl: instance.serverErrorImageUrl,
|
||||||
|
notFoundImageUrl: instance.notFoundImageUrl,
|
||||||
|
infoImageUrl: instance.infoImageUrl,
|
||||||
|
iconUrl: instance.iconUrl,
|
||||||
|
app192IconUrl: instance.app192IconUrl,
|
||||||
|
app512IconUrl: instance.app512IconUrl,
|
||||||
|
backgroundImageUrl: instance.backgroundImageUrl,
|
||||||
|
logoImageUrl: instance.logoImageUrl,
|
||||||
|
defaultLightTheme: instance.defaultLightTheme,
|
||||||
|
defaultDarkTheme: instance.defaultDarkTheme,
|
||||||
|
enableEmail: instance.enableEmail,
|
||||||
|
enableServiceWorker: instance.enableServiceWorker,
|
||||||
|
translatorAvailable: instance.deeplAuthKey != null,
|
||||||
|
cacheRemoteFiles: instance.cacheRemoteFiles,
|
||||||
|
cacheRemoteSensitiveFiles: instance.cacheRemoteSensitiveFiles,
|
||||||
|
pinnedUsers: instance.pinnedUsers,
|
||||||
|
hiddenTags: instance.hiddenTags,
|
||||||
|
blockedHosts: instance.blockedHosts,
|
||||||
|
silencedHosts: instance.silencedHosts,
|
||||||
|
sensitiveWords: instance.sensitiveWords,
|
||||||
|
prohibitedWords: instance.prohibitedWords,
|
||||||
|
preservedUsernames: instance.preservedUsernames,
|
||||||
|
hcaptchaSecretKey: instance.hcaptchaSecretKey,
|
||||||
|
mcaptchaSecretKey: instance.mcaptchaSecretKey,
|
||||||
|
recaptchaSecretKey: instance.recaptchaSecretKey,
|
||||||
|
turnstileSecretKey: instance.turnstileSecretKey,
|
||||||
|
sensitiveMediaDetection: instance.sensitiveMediaDetection,
|
||||||
|
sensitiveMediaDetectionSensitivity: instance.sensitiveMediaDetectionSensitivity,
|
||||||
|
setSensitiveFlagAutomatically: instance.setSensitiveFlagAutomatically,
|
||||||
|
enableSensitiveMediaDetectionForVideos: instance.enableSensitiveMediaDetectionForVideos,
|
||||||
|
proxyAccountId: instance.proxyAccountId,
|
||||||
|
email: instance.email,
|
||||||
|
smtpSecure: instance.smtpSecure,
|
||||||
|
smtpHost: instance.smtpHost,
|
||||||
|
smtpPort: instance.smtpPort,
|
||||||
|
smtpUser: instance.smtpUser,
|
||||||
|
smtpPass: instance.smtpPass,
|
||||||
|
swPrivateKey: instance.swPrivateKey,
|
||||||
|
useObjectStorage: instance.useObjectStorage,
|
||||||
|
objectStorageBaseUrl: instance.objectStorageBaseUrl,
|
||||||
|
objectStorageBucket: instance.objectStorageBucket,
|
||||||
|
objectStoragePrefix: instance.objectStoragePrefix,
|
||||||
|
objectStorageEndpoint: instance.objectStorageEndpoint,
|
||||||
|
objectStorageRegion: instance.objectStorageRegion,
|
||||||
|
objectStoragePort: instance.objectStoragePort,
|
||||||
|
objectStorageAccessKey: instance.objectStorageAccessKey,
|
||||||
|
objectStorageSecretKey: instance.objectStorageSecretKey,
|
||||||
|
objectStorageUseSSL: instance.objectStorageUseSSL,
|
||||||
|
objectStorageUseProxy: instance.objectStorageUseProxy,
|
||||||
|
objectStorageSetPublicRead: instance.objectStorageSetPublicRead,
|
||||||
|
objectStorageS3ForcePathStyle: instance.objectStorageS3ForcePathStyle,
|
||||||
|
deeplAuthKey: instance.deeplAuthKey,
|
||||||
|
deeplIsPro: instance.deeplIsPro,
|
||||||
|
enableIpLogging: instance.enableIpLogging,
|
||||||
|
enableActiveEmailValidation: instance.enableActiveEmailValidation,
|
||||||
|
enableVerifymailApi: instance.enableVerifymailApi,
|
||||||
|
verifymailAuthKey: instance.verifymailAuthKey,
|
||||||
|
enableTruemailApi: instance.enableTruemailApi,
|
||||||
|
truemailInstance: instance.truemailInstance,
|
||||||
|
truemailAuthKey: instance.truemailAuthKey,
|
||||||
|
enableChartsForRemoteUser: instance.enableChartsForRemoteUser,
|
||||||
|
enableChartsForFederatedInstances: instance.enableChartsForFederatedInstances,
|
||||||
|
enableServerMachineStats: instance.enableServerMachineStats,
|
||||||
|
enableIdenticonGeneration: instance.enableIdenticonGeneration,
|
||||||
|
bannedEmailDomains: instance.bannedEmailDomains,
|
||||||
|
policies: { ...DEFAULT_POLICIES, ...instance.policies },
|
||||||
|
manifestJsonOverride: instance.manifestJsonOverride,
|
||||||
|
enableFanoutTimeline: instance.enableFanoutTimeline,
|
||||||
|
enableFanoutTimelineDbFallback: instance.enableFanoutTimelineDbFallback,
|
||||||
|
perLocalUserUserTimelineCacheMax: instance.perLocalUserUserTimelineCacheMax,
|
||||||
|
perRemoteUserUserTimelineCacheMax: instance.perRemoteUserUserTimelineCacheMax,
|
||||||
|
perUserHomeTimelineCacheMax: instance.perUserHomeTimelineCacheMax,
|
||||||
|
perUserListTimelineCacheMax: instance.perUserListTimelineCacheMax,
|
||||||
|
notesPerOneAd: instance.notesPerOneAd,
|
||||||
|
DiscordWebhookUrl: instance.DiscordWebhookUrl,
|
||||||
|
DiscordWebhookUrlWordBlock: instance.DiscordWebhookUrlWordBlock,
|
||||||
|
EmojiBotToken: instance.EmojiBotToken,
|
||||||
|
ApiBase: instance.ApiBase,
|
||||||
|
enableGDPRMode: instance.enableGDPRMode,
|
||||||
|
enableProxyCheckio: instance.enableProxyCheckio,
|
||||||
|
proxyCheckioApiKey: instance.proxyCheckioApiKey,
|
||||||
|
summalyProxy: instance.urlPreviewSummaryProxyUrl,
|
||||||
|
urlPreviewEnabled: instance.urlPreviewEnabled,
|
||||||
|
urlPreviewTimeout: instance.urlPreviewTimeout,
|
||||||
|
urlPreviewMaximumContentLength: instance.urlPreviewMaximumContentLength,
|
||||||
|
urlPreviewRequireContentLength: instance.urlPreviewRequireContentLength,
|
||||||
|
urlPreviewUserAgent: instance.urlPreviewUserAgent,
|
||||||
|
urlPreviewSummaryProxyUrl: instance.urlPreviewSummaryProxyUrl,
|
||||||
|
iconLight: instance.iconLight,
|
||||||
|
iconDark: instance.iconDark,
|
||||||
|
bannerLight: instance.bannerLight,
|
||||||
|
bannerDark: instance.bannerDark,
|
||||||
|
isManaged: false,
|
||||||
|
|
||||||
return {
|
};
|
||||||
maintainerName: instance.maintainerName,
|
} else {
|
||||||
maintainerEmail: instance.maintainerEmail,
|
return {
|
||||||
version: this.config.version,
|
maintainerName: instance.maintainerName,
|
||||||
name: instance.name,
|
maintainerEmail: instance.maintainerEmail,
|
||||||
shortName: instance.shortName,
|
version: this.config.version,
|
||||||
uri: this.config.url,
|
name: instance.name,
|
||||||
description: instance.description,
|
shortName: instance.shortName,
|
||||||
langs: instance.langs,
|
uri: this.config.url,
|
||||||
tosUrl: instance.termsOfServiceUrl,
|
description: instance.description,
|
||||||
repositoryUrl: instance.repositoryUrl,
|
langs: instance.langs,
|
||||||
feedbackUrl: instance.feedbackUrl,
|
tosUrl: instance.termsOfServiceUrl,
|
||||||
impressumUrl: instance.impressumUrl,
|
repositoryUrl: instance.repositoryUrl,
|
||||||
privacyPolicyUrl: instance.privacyPolicyUrl,
|
feedbackUrl: instance.feedbackUrl,
|
||||||
inquiryUrl: instance.inquiryUrl,
|
impressumUrl: instance.impressumUrl,
|
||||||
disableRegistration: instance.disableRegistration,
|
privacyPolicyUrl: instance.privacyPolicyUrl,
|
||||||
emailRequiredForSignup: instance.emailRequiredForSignup,
|
inquiryUrl: instance.inquiryUrl,
|
||||||
enableHcaptcha: instance.enableHcaptcha,
|
disableRegistration: instance.disableRegistration,
|
||||||
hcaptchaSiteKey: instance.hcaptchaSiteKey,
|
emailRequiredForSignup: instance.emailRequiredForSignup,
|
||||||
enableMcaptcha: instance.enableMcaptcha,
|
enableHcaptcha: instance.enableHcaptcha,
|
||||||
mcaptchaSiteKey: instance.mcaptchaSitekey,
|
hcaptchaSiteKey: instance.hcaptchaSiteKey,
|
||||||
mcaptchaInstanceUrl: instance.mcaptchaInstanceUrl,
|
enableMcaptcha: instance.enableMcaptcha,
|
||||||
enableRecaptcha: instance.enableRecaptcha,
|
mcaptchaSiteKey: instance.mcaptchaSitekey,
|
||||||
recaptchaSiteKey: instance.recaptchaSiteKey,
|
mcaptchaInstanceUrl: instance.mcaptchaInstanceUrl,
|
||||||
enableTurnstile: instance.enableTurnstile,
|
enableRecaptcha: instance.enableRecaptcha,
|
||||||
turnstileSiteKey: instance.turnstileSiteKey,
|
recaptchaSiteKey: instance.recaptchaSiteKey,
|
||||||
swPublickey: instance.swPublicKey,
|
enableTurnstile: instance.enableTurnstile,
|
||||||
themeColor: instance.themeColor,
|
turnstileSiteKey: instance.turnstileSiteKey,
|
||||||
requestEmojiAllOk: instance.requestEmojiAllOk,
|
swPublickey: instance.swPublicKey,
|
||||||
mascotImageUrl: instance.mascotImageUrl,
|
themeColor: instance.themeColor,
|
||||||
bannerUrl: instance.bannerUrl,
|
requestEmojiAllOk: instance.requestEmojiAllOk,
|
||||||
serverErrorImageUrl: instance.serverErrorImageUrl,
|
mascotImageUrl: instance.mascotImageUrl,
|
||||||
notFoundImageUrl: instance.notFoundImageUrl,
|
bannerUrl: instance.bannerUrl,
|
||||||
infoImageUrl: instance.infoImageUrl,
|
serverErrorImageUrl: instance.serverErrorImageUrl,
|
||||||
iconUrl: instance.iconUrl,
|
notFoundImageUrl: instance.notFoundImageUrl,
|
||||||
app192IconUrl: instance.app192IconUrl,
|
infoImageUrl: instance.infoImageUrl,
|
||||||
app512IconUrl: instance.app512IconUrl,
|
iconUrl: instance.iconUrl,
|
||||||
backgroundImageUrl: instance.backgroundImageUrl,
|
app192IconUrl: instance.app192IconUrl,
|
||||||
logoImageUrl: instance.logoImageUrl,
|
app512IconUrl: instance.app512IconUrl,
|
||||||
defaultLightTheme: instance.defaultLightTheme,
|
backgroundImageUrl: instance.backgroundImageUrl,
|
||||||
defaultDarkTheme: instance.defaultDarkTheme,
|
logoImageUrl: instance.logoImageUrl,
|
||||||
enableEmail: instance.enableEmail,
|
defaultLightTheme: instance.defaultLightTheme,
|
||||||
enableServiceWorker: instance.enableServiceWorker,
|
defaultDarkTheme: instance.defaultDarkTheme,
|
||||||
translatorAvailable: instance.deeplAuthKey != null,
|
enableEmail: instance.enableEmail,
|
||||||
cacheRemoteFiles: instance.cacheRemoteFiles,
|
enableServiceWorker: instance.enableServiceWorker,
|
||||||
cacheRemoteSensitiveFiles: instance.cacheRemoteSensitiveFiles,
|
translatorAvailable: instance.deeplAuthKey != null,
|
||||||
pinnedUsers: instance.pinnedUsers,
|
cacheRemoteFiles: instance.cacheRemoteFiles,
|
||||||
hiddenTags: instance.hiddenTags,
|
cacheRemoteSensitiveFiles: instance.cacheRemoteSensitiveFiles,
|
||||||
blockedHosts: instance.blockedHosts,
|
pinnedUsers: instance.pinnedUsers,
|
||||||
silencedHosts: instance.silencedHosts,
|
hiddenTags: instance.hiddenTags,
|
||||||
sensitiveWords: instance.sensitiveWords,
|
blockedHosts: instance.blockedHosts,
|
||||||
prohibitedWords: instance.prohibitedWords,
|
silencedHosts: instance.silencedHosts,
|
||||||
preservedUsernames: instance.preservedUsernames,
|
sensitiveWords: instance.sensitiveWords,
|
||||||
hcaptchaSecretKey: instance.hcaptchaSecretKey,
|
prohibitedWords: instance.prohibitedWords,
|
||||||
mcaptchaSecretKey: instance.mcaptchaSecretKey,
|
preservedUsernames: instance.preservedUsernames,
|
||||||
recaptchaSecretKey: instance.recaptchaSecretKey,
|
hcaptchaSecretKey: instance.hcaptchaSecretKey,
|
||||||
turnstileSecretKey: instance.turnstileSecretKey,
|
mcaptchaSecretKey: instance.mcaptchaSecretKey,
|
||||||
sensitiveMediaDetection: instance.sensitiveMediaDetection,
|
recaptchaSecretKey: instance.recaptchaSecretKey,
|
||||||
sensitiveMediaDetectionSensitivity: instance.sensitiveMediaDetectionSensitivity,
|
turnstileSecretKey: instance.turnstileSecretKey,
|
||||||
setSensitiveFlagAutomatically: instance.setSensitiveFlagAutomatically,
|
sensitiveMediaDetection: instance.sensitiveMediaDetection,
|
||||||
enableSensitiveMediaDetectionForVideos: instance.enableSensitiveMediaDetectionForVideos,
|
sensitiveMediaDetectionSensitivity: instance.sensitiveMediaDetectionSensitivity,
|
||||||
proxyAccountId: instance.proxyAccountId,
|
setSensitiveFlagAutomatically: instance.setSensitiveFlagAutomatically,
|
||||||
email: instance.email,
|
enableSensitiveMediaDetectionForVideos: instance.enableSensitiveMediaDetectionForVideos,
|
||||||
smtpSecure: instance.smtpSecure,
|
proxyAccountId: instance.proxyAccountId,
|
||||||
smtpHost: instance.smtpHost,
|
email: instance.email,
|
||||||
smtpPort: instance.smtpPort,
|
smtpSecure: instance.smtpSecure,
|
||||||
smtpUser: instance.smtpUser,
|
smtpHost: instance.smtpHost,
|
||||||
smtpPass: instance.smtpPass,
|
smtpPort: instance.smtpPort,
|
||||||
swPrivateKey: instance.swPrivateKey,
|
smtpUser: instance.smtpUser,
|
||||||
useObjectStorage: instance.useObjectStorage,
|
smtpPass: instance.smtpPass,
|
||||||
objectStorageBaseUrl: instance.objectStorageBaseUrl,
|
swPrivateKey: instance.swPrivateKey,
|
||||||
objectStorageBucket: instance.objectStorageBucket,
|
useObjectStorage: true,
|
||||||
objectStoragePrefix: instance.objectStoragePrefix,
|
objectStorageBaseUrl: 'Masked',
|
||||||
objectStorageEndpoint: instance.objectStorageEndpoint,
|
objectStorageBucket: 'Masked',
|
||||||
objectStorageRegion: instance.objectStorageRegion,
|
objectStoragePrefix: 'Masked',
|
||||||
objectStoragePort: instance.objectStoragePort,
|
objectStorageEndpoint: 'Masked',
|
||||||
objectStorageAccessKey: instance.objectStorageAccessKey,
|
objectStorageRegion: 'Masked',
|
||||||
objectStorageSecretKey: instance.objectStorageSecretKey,
|
objectStoragePort: 0,
|
||||||
objectStorageUseSSL: instance.objectStorageUseSSL,
|
objectStorageAccessKey: 'Masked',
|
||||||
objectStorageUseProxy: instance.objectStorageUseProxy,
|
objectStorageSecretKey: 'Masked',
|
||||||
objectStorageSetPublicRead: instance.objectStorageSetPublicRead,
|
objectStorageUseSSL: false,
|
||||||
objectStorageS3ForcePathStyle: instance.objectStorageS3ForcePathStyle,
|
objectStorageUseProxy: false,
|
||||||
deeplAuthKey: instance.deeplAuthKey,
|
objectStorageSetPublicRead: false,
|
||||||
deeplIsPro: instance.deeplIsPro,
|
objectStorageS3ForcePathStyle: false,
|
||||||
enableIpLogging: instance.enableIpLogging,
|
deeplAuthKey: instance.deeplAuthKey,
|
||||||
enableActiveEmailValidation: instance.enableActiveEmailValidation,
|
deeplIsPro: instance.deeplIsPro,
|
||||||
enableVerifymailApi: instance.enableVerifymailApi,
|
enableIpLogging: instance.enableIpLogging,
|
||||||
verifymailAuthKey: instance.verifymailAuthKey,
|
enableActiveEmailValidation: instance.enableActiveEmailValidation,
|
||||||
enableTruemailApi: instance.enableTruemailApi,
|
enableVerifymailApi: instance.enableVerifymailApi,
|
||||||
truemailInstance: instance.truemailInstance,
|
verifymailAuthKey: instance.verifymailAuthKey,
|
||||||
truemailAuthKey: instance.truemailAuthKey,
|
enableTruemailApi: instance.enableTruemailApi,
|
||||||
enableChartsForRemoteUser: instance.enableChartsForRemoteUser,
|
truemailInstance: instance.truemailInstance,
|
||||||
enableChartsForFederatedInstances: instance.enableChartsForFederatedInstances,
|
truemailAuthKey: instance.truemailAuthKey,
|
||||||
enableServerMachineStats: instance.enableServerMachineStats,
|
enableChartsForRemoteUser: instance.enableChartsForRemoteUser,
|
||||||
enableIdenticonGeneration: instance.enableIdenticonGeneration,
|
enableChartsForFederatedInstances: instance.enableChartsForFederatedInstances,
|
||||||
bannedEmailDomains: instance.bannedEmailDomains,
|
enableServerMachineStats: instance.enableServerMachineStats,
|
||||||
policies: { ...DEFAULT_POLICIES, ...instance.policies },
|
enableIdenticonGeneration: instance.enableIdenticonGeneration,
|
||||||
manifestJsonOverride: instance.manifestJsonOverride,
|
bannedEmailDomains: instance.bannedEmailDomains,
|
||||||
enableFanoutTimeline: instance.enableFanoutTimeline,
|
policies: { ...DEFAULT_POLICIES, ...instance.policies },
|
||||||
enableFanoutTimelineDbFallback: instance.enableFanoutTimelineDbFallback,
|
manifestJsonOverride: instance.manifestJsonOverride,
|
||||||
perLocalUserUserTimelineCacheMax: instance.perLocalUserUserTimelineCacheMax,
|
enableFanoutTimeline: instance.enableFanoutTimeline,
|
||||||
perRemoteUserUserTimelineCacheMax: instance.perRemoteUserUserTimelineCacheMax,
|
enableFanoutTimelineDbFallback: instance.enableFanoutTimelineDbFallback,
|
||||||
perUserHomeTimelineCacheMax: instance.perUserHomeTimelineCacheMax,
|
perLocalUserUserTimelineCacheMax: instance.perLocalUserUserTimelineCacheMax,
|
||||||
perUserListTimelineCacheMax: instance.perUserListTimelineCacheMax,
|
perRemoteUserUserTimelineCacheMax: instance.perRemoteUserUserTimelineCacheMax,
|
||||||
notesPerOneAd: instance.notesPerOneAd,
|
perUserHomeTimelineCacheMax: instance.perUserHomeTimelineCacheMax,
|
||||||
DiscordWebhookUrl: instance.DiscordWebhookUrl,
|
perUserListTimelineCacheMax: instance.perUserListTimelineCacheMax,
|
||||||
DiscordWebhookUrlWordBlock: instance.DiscordWebhookUrlWordBlock,
|
notesPerOneAd: instance.notesPerOneAd,
|
||||||
EmojiBotToken: instance.EmojiBotToken,
|
DiscordWebhookUrl: instance.DiscordWebhookUrl,
|
||||||
ApiBase: instance.ApiBase,
|
DiscordWebhookUrlWordBlock: instance.DiscordWebhookUrlWordBlock,
|
||||||
enableGDPRMode: instance.enableGDPRMode,
|
EmojiBotToken: instance.EmojiBotToken,
|
||||||
enableProxyCheckio: instance.enableProxyCheckio,
|
ApiBase: instance.ApiBase,
|
||||||
proxyCheckioApiKey: instance.proxyCheckioApiKey,
|
enableGDPRMode: instance.enableGDPRMode,
|
||||||
summalyProxy: instance.urlPreviewSummaryProxyUrl,
|
enableProxyCheckio: instance.enableProxyCheckio,
|
||||||
urlPreviewEnabled: instance.urlPreviewEnabled,
|
proxyCheckioApiKey: instance.proxyCheckioApiKey,
|
||||||
urlPreviewTimeout: instance.urlPreviewTimeout,
|
summalyProxy: instance.urlPreviewSummaryProxyUrl,
|
||||||
urlPreviewMaximumContentLength: instance.urlPreviewMaximumContentLength,
|
urlPreviewEnabled: instance.urlPreviewEnabled,
|
||||||
urlPreviewRequireContentLength: instance.urlPreviewRequireContentLength,
|
urlPreviewTimeout: instance.urlPreviewTimeout,
|
||||||
urlPreviewUserAgent: instance.urlPreviewUserAgent,
|
urlPreviewMaximumContentLength: instance.urlPreviewMaximumContentLength,
|
||||||
urlPreviewSummaryProxyUrl: instance.urlPreviewSummaryProxyUrl,
|
urlPreviewRequireContentLength: instance.urlPreviewRequireContentLength,
|
||||||
iconLight: instance.iconLight,
|
urlPreviewUserAgent: instance.urlPreviewUserAgent,
|
||||||
iconDark: instance.iconDark,
|
urlPreviewSummaryProxyUrl: instance.urlPreviewSummaryProxyUrl,
|
||||||
bannerLight: instance.bannerLight,
|
iconLight: instance.iconLight,
|
||||||
bannerDark: instance.bannerDark,
|
iconDark: instance.iconDark,
|
||||||
};
|
bannerLight: instance.bannerLight,
|
||||||
|
bannerDark: instance.bannerDark,
|
||||||
|
isManaged: true,
|
||||||
|
};
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,6 +8,7 @@ import type { MiMeta } from '@/models/Meta.js';
|
||||||
import { ModerationLogService } from '@/core/ModerationLogService.js';
|
import { ModerationLogService } from '@/core/ModerationLogService.js';
|
||||||
import { Endpoint } from '@/server/api/endpoint-base.js';
|
import { Endpoint } from '@/server/api/endpoint-base.js';
|
||||||
import { MetaService } from '@/core/MetaService.js';
|
import { MetaService } from '@/core/MetaService.js';
|
||||||
|
import { envOption } from '@/env.js';
|
||||||
|
|
||||||
export const meta = {
|
export const meta = {
|
||||||
tags: ['admin'],
|
tags: ['admin'],
|
||||||
|
@ -91,7 +92,6 @@ export const paramDef = {
|
||||||
type: 'string',
|
type: 'string',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
summalyProxy: { type: 'string', nullable: true },
|
|
||||||
DiscordWebhookUrl: { type: 'string', nullable: true },
|
DiscordWebhookUrl: { type: 'string', nullable: true },
|
||||||
DiscordWebhookUrlWordBlock: { type: 'string', nullable: true },
|
DiscordWebhookUrlWordBlock: { type: 'string', nullable: true },
|
||||||
deeplAuthKey: { type: 'string', nullable: true },
|
deeplAuthKey: { type: 'string', nullable: true },
|
||||||
|
@ -190,9 +190,98 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
||||||
) {
|
) {
|
||||||
super(meta, paramDef, async (ps, me) => {
|
super(meta, paramDef, async (ps, me) => {
|
||||||
const set = {} as Partial<MiMeta>;
|
const set = {} as Partial<MiMeta>;
|
||||||
|
if (!envOption.managed) {
|
||||||
|
if (typeof ps.disableRegistration === 'boolean') {
|
||||||
|
set.disableRegistration = ps.disableRegistration;
|
||||||
|
}
|
||||||
|
|
||||||
if (typeof ps.disableRegistration === 'boolean') {
|
if (ps.useObjectStorage !== undefined) {
|
||||||
set.disableRegistration = ps.disableRegistration;
|
set.useObjectStorage = ps.useObjectStorage;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ps.objectStorageBaseUrl !== undefined) {
|
||||||
|
set.objectStorageBaseUrl = ps.objectStorageBaseUrl;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ps.objectStorageBucket !== undefined) {
|
||||||
|
set.objectStorageBucket = ps.objectStorageBucket;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ps.objectStoragePrefix !== undefined) {
|
||||||
|
set.objectStoragePrefix = ps.objectStoragePrefix;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ps.objectStorageEndpoint !== undefined) {
|
||||||
|
set.objectStorageEndpoint = ps.objectStorageEndpoint;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ps.objectStorageRegion !== undefined) {
|
||||||
|
set.objectStorageRegion = ps.objectStorageRegion;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ps.objectStoragePort !== undefined) {
|
||||||
|
set.objectStoragePort = ps.objectStoragePort;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ps.objectStorageAccessKey !== undefined) {
|
||||||
|
set.objectStorageAccessKey = ps.objectStorageAccessKey;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ps.objectStorageSecretKey !== undefined) {
|
||||||
|
set.objectStorageSecretKey = ps.objectStorageSecretKey;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ps.objectStorageUseSSL !== undefined) {
|
||||||
|
set.objectStorageUseSSL = ps.objectStorageUseSSL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ps.objectStorageUseProxy !== undefined) {
|
||||||
|
set.objectStorageUseProxy = ps.objectStorageUseProxy;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ps.objectStorageSetPublicRead !== undefined) {
|
||||||
|
set.objectStorageSetPublicRead = ps.objectStorageSetPublicRead;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ps.objectStorageS3ForcePathStyle !== undefined) {
|
||||||
|
set.objectStorageS3ForcePathStyle = ps.objectStorageS3ForcePathStyle;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ps.enableServerMachineStats !== undefined) {
|
||||||
|
set.enableServerMachineStats = ps.enableServerMachineStats;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ps.cacheRemoteFiles !== undefined) {
|
||||||
|
set.cacheRemoteFiles = ps.cacheRemoteFiles;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ps.cacheRemoteSensitiveFiles !== undefined) {
|
||||||
|
set.cacheRemoteSensitiveFiles = ps.cacheRemoteSensitiveFiles;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ps.enableFanoutTimeline !== undefined) {
|
||||||
|
set.enableFanoutTimeline = ps.enableFanoutTimeline;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ps.enableFanoutTimelineDbFallback !== undefined) {
|
||||||
|
set.enableFanoutTimelineDbFallback = ps.enableFanoutTimelineDbFallback;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ps.perLocalUserUserTimelineCacheMax !== undefined) {
|
||||||
|
set.perLocalUserUserTimelineCacheMax = ps.perLocalUserUserTimelineCacheMax;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ps.perRemoteUserUserTimelineCacheMax !== undefined) {
|
||||||
|
set.perRemoteUserUserTimelineCacheMax = ps.perRemoteUserUserTimelineCacheMax;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ps.perUserHomeTimelineCacheMax !== undefined) {
|
||||||
|
set.perUserHomeTimelineCacheMax = ps.perUserHomeTimelineCacheMax;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ps.perUserListTimelineCacheMax !== undefined) {
|
||||||
|
set.perUserListTimelineCacheMax = ps.perUserListTimelineCacheMax;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Array.isArray(ps.pinnedUsers)) {
|
if (Array.isArray(ps.pinnedUsers)) {
|
||||||
|
@ -313,14 +402,6 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
||||||
set.defaultDarkTheme = ps.defaultDarkTheme;
|
set.defaultDarkTheme = ps.defaultDarkTheme;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ps.cacheRemoteFiles !== undefined) {
|
|
||||||
set.cacheRemoteFiles = ps.cacheRemoteFiles;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ps.cacheRemoteSensitiveFiles !== undefined) {
|
|
||||||
set.cacheRemoteSensitiveFiles = ps.cacheRemoteSensitiveFiles;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ps.emailRequiredForSignup !== undefined) {
|
if (ps.emailRequiredForSignup !== undefined) {
|
||||||
set.emailRequiredForSignup = ps.emailRequiredForSignup;
|
set.emailRequiredForSignup = ps.emailRequiredForSignup;
|
||||||
}
|
}
|
||||||
|
@ -473,58 +554,6 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
||||||
set.inquiryUrl = ps.inquiryUrl;
|
set.inquiryUrl = ps.inquiryUrl;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ps.useObjectStorage !== undefined) {
|
|
||||||
set.useObjectStorage = ps.useObjectStorage;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ps.objectStorageBaseUrl !== undefined) {
|
|
||||||
set.objectStorageBaseUrl = ps.objectStorageBaseUrl;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ps.objectStorageBucket !== undefined) {
|
|
||||||
set.objectStorageBucket = ps.objectStorageBucket;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ps.objectStoragePrefix !== undefined) {
|
|
||||||
set.objectStoragePrefix = ps.objectStoragePrefix;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ps.objectStorageEndpoint !== undefined) {
|
|
||||||
set.objectStorageEndpoint = ps.objectStorageEndpoint;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ps.objectStorageRegion !== undefined) {
|
|
||||||
set.objectStorageRegion = ps.objectStorageRegion;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ps.objectStoragePort !== undefined) {
|
|
||||||
set.objectStoragePort = ps.objectStoragePort;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ps.objectStorageAccessKey !== undefined) {
|
|
||||||
set.objectStorageAccessKey = ps.objectStorageAccessKey;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ps.objectStorageSecretKey !== undefined) {
|
|
||||||
set.objectStorageSecretKey = ps.objectStorageSecretKey;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ps.objectStorageUseSSL !== undefined) {
|
|
||||||
set.objectStorageUseSSL = ps.objectStorageUseSSL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ps.objectStorageUseProxy !== undefined) {
|
|
||||||
set.objectStorageUseProxy = ps.objectStorageUseProxy;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ps.objectStorageSetPublicRead !== undefined) {
|
|
||||||
set.objectStorageSetPublicRead = ps.objectStorageSetPublicRead;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ps.objectStorageS3ForcePathStyle !== undefined) {
|
|
||||||
set.objectStorageS3ForcePathStyle = ps.objectStorageS3ForcePathStyle;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ps.deeplAuthKey !== undefined) {
|
if (ps.deeplAuthKey !== undefined) {
|
||||||
if (ps.deeplAuthKey === '') {
|
if (ps.deeplAuthKey === '') {
|
||||||
set.deeplAuthKey = null;
|
set.deeplAuthKey = null;
|
||||||
|
@ -585,10 +614,6 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
||||||
set.enableChartsForFederatedInstances = ps.enableChartsForFederatedInstances;
|
set.enableChartsForFederatedInstances = ps.enableChartsForFederatedInstances;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ps.enableServerMachineStats !== undefined) {
|
|
||||||
set.enableServerMachineStats = ps.enableServerMachineStats;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ps.enableIdenticonGeneration !== undefined) {
|
if (ps.enableIdenticonGeneration !== undefined) {
|
||||||
set.enableIdenticonGeneration = ps.enableIdenticonGeneration;
|
set.enableIdenticonGeneration = ps.enableIdenticonGeneration;
|
||||||
}
|
}
|
||||||
|
@ -605,30 +630,6 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
||||||
set.manifestJsonOverride = ps.manifestJsonOverride;
|
set.manifestJsonOverride = ps.manifestJsonOverride;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ps.enableFanoutTimeline !== undefined) {
|
|
||||||
set.enableFanoutTimeline = ps.enableFanoutTimeline;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ps.enableFanoutTimelineDbFallback !== undefined) {
|
|
||||||
set.enableFanoutTimelineDbFallback = ps.enableFanoutTimelineDbFallback;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ps.perLocalUserUserTimelineCacheMax !== undefined) {
|
|
||||||
set.perLocalUserUserTimelineCacheMax = ps.perLocalUserUserTimelineCacheMax;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ps.perRemoteUserUserTimelineCacheMax !== undefined) {
|
|
||||||
set.perRemoteUserUserTimelineCacheMax = ps.perRemoteUserUserTimelineCacheMax;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ps.perUserHomeTimelineCacheMax !== undefined) {
|
|
||||||
set.perUserHomeTimelineCacheMax = ps.perUserHomeTimelineCacheMax;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ps.perUserListTimelineCacheMax !== undefined) {
|
|
||||||
set.perUserListTimelineCacheMax = ps.perUserListTimelineCacheMax;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ps.notesPerOneAd !== undefined) {
|
if (ps.notesPerOneAd !== undefined) {
|
||||||
set.notesPerOneAd = ps.notesPerOneAd;
|
set.notesPerOneAd = ps.notesPerOneAd;
|
||||||
}
|
}
|
||||||
|
|
|
@ -73,24 +73,28 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
||||||
const range = max - min + 1;
|
const range = max - min + 1;
|
||||||
const randomBuffer = new Uint32Array(1);
|
const randomBuffer = new Uint32Array(1);
|
||||||
crypto.getRandomValues(randomBuffer);
|
crypto.getRandomValues(randomBuffer);
|
||||||
const randomNumber = randomBuffer[0] / (0xFFFFFFFF + 1); // 0から1未満の浮動小数点数
|
const randomNumber = randomBuffer[0] / (0xFFFFFFFF + 1);
|
||||||
return Math.floor(randomNumber * range) + min;
|
return Math.floor(randomNumber * range) + min;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!userProfile.loggedInDates.includes(today)) {
|
if (!userProfile.loggedInDates.includes(today)) {
|
||||||
|
|
||||||
todayGetPoints = generateSecureRandomNumber(1, 5);
|
todayGetPoints = generateSecureRandomNumber(1, 5);
|
||||||
this.userProfilesRepository.update({ userId: user.id }, {
|
|
||||||
|
void this.userProfilesRepository.update({ userId: user.id }, {
|
||||||
loggedInDates: [...userProfile.loggedInDates, today],
|
loggedInDates: [...userProfile.loggedInDates, today],
|
||||||
});
|
});
|
||||||
|
|
||||||
const user_ = await this.usersRepository.findOne({
|
const user_ = await this.usersRepository.findOne({
|
||||||
where: {
|
where: {
|
||||||
id: user.id,
|
id: user.id,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
if (user_ == null) {
|
if (user_ == null) {
|
||||||
throw new ApiError(meta.errors.userIsDeleted);
|
throw new ApiError(meta.errors.userIsDeleted);
|
||||||
}
|
}
|
||||||
this.usersRepository.update( user.id, {
|
void this.usersRepository.update( user.id, {
|
||||||
getPoints: user_.getPoints + todayGetPoints,
|
getPoints: user_.getPoints + todayGetPoints,
|
||||||
});
|
});
|
||||||
this.notificationService.createNotification(user.id, 'loginbonus', {
|
this.notificationService.createNotification(user.id, 'loginbonus', {
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
<!--
|
<!--
|
||||||
SPDX-FileCopyrightText: syuilo and misskey-project , Type4ny-project
|
SPDX-FileCopyrightText: syuilo and misskey-project
|
||||||
SPDX-License-Identifier: AGPL-3.0-only
|
SPDX-License-Identifier: AGPL-3.0-only
|
||||||
-->
|
-->
|
||||||
|
|
||||||
|
@ -10,7 +10,13 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
v-hotkey="keymap"
|
v-hotkey="keymap"
|
||||||
tabindex="0"
|
tabindex="0"
|
||||||
class="_popup _shadow"
|
class="_popup _shadow"
|
||||||
:class="[$style.root, { [$style.center]: align === 'center', [$style.asDrawer]: asDrawer },{[$style.gamingDark]: gamingType === 'dark',[$style.gamingLight]: gamingType === 'light' }]"
|
:class="{
|
||||||
|
[$style.root]: true,
|
||||||
|
[$style.center]: align === 'center',
|
||||||
|
[$style.asDrawer]: asDrawer,
|
||||||
|
[$style.gamingDark]: gamingType === 'dark',
|
||||||
|
[$style.gamingLight]: gamingType === 'light'
|
||||||
|
}"
|
||||||
:style="{
|
:style="{
|
||||||
width: (width && !asDrawer) ? `${width}px` : '',
|
width: (width && !asDrawer) ? `${width}px` : '',
|
||||||
maxHeight: maxHeight ? `${maxHeight}px` : '',
|
maxHeight: maxHeight ? `${maxHeight}px` : '',
|
||||||
|
@ -20,21 +26,22 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
>
|
>
|
||||||
<template v-for="item in (items2 ?? [])">
|
<template v-for="item in (items2 ?? [])">
|
||||||
<div v-if="item.type === 'divider'" role="separator" tabindex="-1" :class="$style.divider"></div>
|
<div v-if="item.type === 'divider'" role="separator" tabindex="-1" :class="$style.divider"></div>
|
||||||
<span v-else-if="item.type === 'label'" role="menuitem" tabindex="-1" :class="[$style.label, $style.item,{[$style.gamingDark]: gamingType === 'dark',[$style.gamingLight]: gamingType === 'light' }]">
|
<span v-else-if="item.type === 'label'" role="menuitem" tabindex="-1" :class="[$style.label, $style.item, {[$style.gamingDark]: gamingType === 'dark', [$style.gamingLight]: gamingType === 'light'}]">
|
||||||
<span style="opacity: 0.7;">{{ item.text }}</span>
|
<span style="opacity: 0.7;">{{ item.text }}</span>
|
||||||
</span>
|
</span>
|
||||||
<span v-else-if="item.type === 'pending'" role="menuitem" tabindex="0" :class="[$style.pending, $style.item,{[$style.gamingDark]: gamingType === 'dark',[$style.gamingLight]: gamingType === 'light' }]">
|
<span v-else-if="item.type === 'pending'" role="menuitem" tabindex="0" :class="[$style.pending, $style.item,{[$style.gamingDark]: gamingType === 'dark', [$style.gamingLight]: gamingType === 'light'}]">
|
||||||
<span><MkEllipsis/></span>
|
<span><MkEllipsis/></span>
|
||||||
</span>
|
</span>
|
||||||
<MkA
|
<MkA
|
||||||
v-else-if="item.type === 'link'"
|
v-else-if="item.type === 'link'"
|
||||||
role="menuitem"
|
role="menuitem"
|
||||||
|
tabindex="0"
|
||||||
|
:class="['_button', $style.item ,{[$style.gamingDark]: gamingType === 'dark', [$style.gamingLight]: gamingType === 'light'}]"
|
||||||
:to="item.to"
|
:to="item.to"
|
||||||
class="_button"
|
|
||||||
:class="[$style.item,{[$style.gamingDark]: gamingType === 'dark',[$style.gamingLight]: gamingType === 'light' }]"
|
|
||||||
@click.passive="close(true)"
|
@click.passive="close(true)"
|
||||||
@mouseenter.passive="onItemMouseEnter"
|
@mouseenter.passive="onItemMouseEnter"
|
||||||
@mouseleave.passive="onItemMouseLeave">
|
@mouseleave.passive="onItemMouseLeave"
|
||||||
|
>
|
||||||
<i v-if="item.icon" class="ti-fw" :class="[$style.icon, item.icon]"></i>
|
<i v-if="item.icon" class="ti-fw" :class="[$style.icon, item.icon]"></i>
|
||||||
<MkAvatar v-if="item.avatar" :user="item.avatar" :class="$style.avatar"/>
|
<MkAvatar v-if="item.avatar" :user="item.avatar" :class="$style.avatar"/>
|
||||||
<div :class="$style.item_content">
|
<div :class="$style.item_content">
|
||||||
|
@ -45,14 +52,16 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
<a
|
<a
|
||||||
v-else-if="item.type === 'a'"
|
v-else-if="item.type === 'a'"
|
||||||
role="menuitem"
|
role="menuitem"
|
||||||
|
tabindex="0"
|
||||||
|
:class="['_button', $style.item,{[$style.gamingDark]: gamingType === 'dark', [$style.gamingLight]: gamingType === 'light'}]"
|
||||||
:href="item.href"
|
:href="item.href"
|
||||||
:target="item.target"
|
:target="item.target"
|
||||||
|
:rel="item.target === '_blank' ? 'noopener noreferrer' : undefined"
|
||||||
:download="item.download"
|
:download="item.download"
|
||||||
class="_button"
|
|
||||||
:class="[$style.item,{[$style.gamingDark]: gamingType === 'dark',[$style.gamingLight]: gamingType === 'light' }]"
|
|
||||||
@click.passive="close(true)"
|
@click.passive="close(true)"
|
||||||
@mouseenter.passive="onItemMouseEnter"
|
@mouseenter.passive="onItemMouseEnter"
|
||||||
@mouseleave.passive="onItemMouseLeave">
|
@mouseleave.passive="onItemMouseLeave"
|
||||||
|
>
|
||||||
<i v-if="item.icon" class="ti-fw" :class="[$style.icon, item.icon]"></i>
|
<i v-if="item.icon" class="ti-fw" :class="[$style.icon, item.icon]"></i>
|
||||||
<div :class="$style.item_content">
|
<div :class="$style.item_content">
|
||||||
<span :class="$style.item_content_text">{{ item.text }}</span>
|
<span :class="$style.item_content_text">{{ item.text }}</span>
|
||||||
|
@ -63,7 +72,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
v-else-if="item.type === 'user'"
|
v-else-if="item.type === 'user'"
|
||||||
role="menuitem"
|
role="menuitem"
|
||||||
tabindex="0"
|
tabindex="0"
|
||||||
:class="['_button', $style.item, { [$style.active]: item.active },{[$style.gamingDark]: gamingType === 'dark',[$style.gamingLight]: gamingType === 'light' }]"
|
:class="['_button', $style.item, { [$style.active]: item.active },{[$style.gamingDark]: gamingType === 'dark', [$style.gamingLight]: gamingType === 'light'}]"
|
||||||
@click.prevent="item.active ? close(false) : clicked(item.action, $event)"
|
@click.prevent="item.active ? close(false) : clicked(item.action, $event)"
|
||||||
@mouseenter.passive="onItemMouseEnter"
|
@mouseenter.passive="onItemMouseEnter"
|
||||||
@mouseleave.passive="onItemMouseLeave"
|
@mouseleave.passive="onItemMouseLeave"
|
||||||
|
@ -76,14 +85,15 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
<button
|
<button
|
||||||
v-else-if="item.type === 'switch'"
|
v-else-if="item.type === 'switch'"
|
||||||
role="menuitemcheckbox"
|
role="menuitemcheckbox"
|
||||||
class="_button"
|
tabindex="0"
|
||||||
:class="[$style.item, $style.switch, { [$style.switchDisabled]: item.disabled } , { [$style.gamingDark]: gamingType === 'dark',[$style.gamingLight]: gamingType === 'light' }]"
|
:class="['_button', $style.item]"
|
||||||
:disabled="unref(item.disabled)"
|
:disabled="unref(item.disabled)"
|
||||||
@click.prevent="switchItem(item)"
|
@click.prevent="switchItem(item)"
|
||||||
@mouseenter.passive="onItemMouseEnter"
|
@mouseenter.passive="onItemMouseEnter"
|
||||||
@mouseleave.passive="onItemMouseLeave">
|
@mouseleave.passive="onItemMouseLeave"
|
||||||
<i v-if="item.icon" class="ti-fw" :class="[$style.icon, item.icon]"></i>
|
>
|
||||||
<MkSwitchButton v-else :class="$style.switchButton" :checked="item.ref" :disabled="item.disabled" @toggle="switchItem(item)" model-value/>
|
<i v-if="item.icon" class="ti-fw" :class="[$style.icon, item.icon]"></i>
|
||||||
|
<MkSwitchButton v-else :class="$style.switchButton" :checked="item.ref" :disabled="item.disabled" @toggle="switchItem(item)"/>
|
||||||
<div :class="$style.item_content">
|
<div :class="$style.item_content">
|
||||||
<span :class="[$style.item_content_text, { [$style.switchText]: !item.icon }]">{{ item.text }}</span>
|
<span :class="[$style.item_content_text, { [$style.switchText]: !item.icon }]">{{ item.text }}</span>
|
||||||
<MkSwitchButton v-if="item.icon" :class="[$style.switchButton, $style.caret]" :checked="item.ref" :disabled="item.disabled" @toggle="switchItem(item)"/>
|
<MkSwitchButton v-if="item.icon" :class="[$style.switchButton, $style.caret]" :checked="item.ref" :disabled="item.disabled" @toggle="switchItem(item)"/>
|
||||||
|
@ -125,7 +135,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
v-else-if="item.type === 'parent'"
|
v-else-if="item.type === 'parent'"
|
||||||
role="menuitem"
|
role="menuitem"
|
||||||
tabindex="0"
|
tabindex="0"
|
||||||
:class="['_button', $style.item, $style.parent, { [$style.active]: childShowingItem === item } , { [$style.gamingDark]: gamingType === 'dark',[$style.gamingLight]: gamingType === 'light' }]"
|
:class="['_button', $style.item, $style.parent, { [$style.active]: childShowingItem === item },{[$style.gamingDark]: gamingType === 'dark', [$style.gamingLight]: gamingType === 'light'}]"
|
||||||
@mouseenter.prevent="preferClick ? null : showChildren(item, $event)"
|
@mouseenter.prevent="preferClick ? null : showChildren(item, $event)"
|
||||||
@keydown.enter.prevent="preferClick ? null : showChildren(item, $event)"
|
@keydown.enter.prevent="preferClick ? null : showChildren(item, $event)"
|
||||||
@click.prevent="!preferClick ? null : showChildren(item, $event)"
|
@click.prevent="!preferClick ? null : showChildren(item, $event)"
|
||||||
|
@ -139,12 +149,12 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
<button
|
<button
|
||||||
v-else role="menuitem"
|
v-else role="menuitem"
|
||||||
tabindex="0"
|
tabindex="0"
|
||||||
:class="['_button', $style.item, { [$style.danger]: item.danger, [$style.active]: unref(item.active) }, { [$style.gamingDark]: gamingType === 'dark',[$style.gamingLight]: gamingType === 'light' }]"
|
:class="['_button', $style.item, { [$style.danger]: item.danger, [$style.active]: unref(item.active) },{[$style.gamingDark]: gamingType === 'dark', [$style.gamingLight]: gamingType === 'light'}]"
|
||||||
@click.prevent="unref(item.active) ? close(false) : clicked(item.action, $event)"
|
@click.prevent="unref(item.active) ? close(false) : clicked(item.action, $event)"
|
||||||
@mouseenter.passive="onItemMouseEnter"
|
@mouseenter.passive="onItemMouseEnter"
|
||||||
@mouseleave.passive="onItemMouseLeave"
|
@mouseleave.passive="onItemMouseLeave"
|
||||||
>
|
>
|
||||||
<i v-if="item.icon" class="ti-fw" :class="[$style.icon, item.icon, { [$style.gamingDark]: gamingType === 'dark',[$style.gamingLight]: gamingType === 'light' }]"></i>
|
<i v-if="item.icon" class="ti-fw" :class="[$style.icon, item.icon]"></i>
|
||||||
<MkAvatar v-if="item.avatar" :user="item.avatar" :class="$style.avatar"/>
|
<MkAvatar v-if="item.avatar" :user="item.avatar" :class="$style.avatar"/>
|
||||||
<div :class="$style.item_content">
|
<div :class="$style.item_content">
|
||||||
<span :class="$style.item_content_text">{{ item.text }}</span>
|
<span :class="$style.item_content_text">{{ item.text }}</span>
|
||||||
|
@ -163,18 +173,17 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { inject, computed, defineAsyncComponent, nextTick, onBeforeUnmount, onMounted, ref, shallowRef, watch, unref } from 'vue';
|
import { computed, defineAsyncComponent, inject, nextTick, onBeforeUnmount, onMounted, ref, shallowRef, unref, watch } from 'vue';
|
||||||
import { focusPrev, focusNext } from '@/scripts/focus.js';
|
import MkSwitchButton from '@/components/MkSwitch.button.vue';
|
||||||
import { MenuItem, InnerMenuItem, MenuPending, MenuAction, MenuSwitch, MenuRadio, MenuRadioOption, MenuParent } from '@/types/menu.js';
|
import { MenuItem, InnerMenuItem, MenuPending, MenuAction, MenuSwitch, MenuRadio, MenuRadioOption, MenuParent } from '@/types/menu.js';
|
||||||
import * as os from '@/os.js';
|
import * as os from '@/os.js';
|
||||||
import { i18n } from '@/i18n.js';
|
import { i18n } from '@/i18n.js';
|
||||||
import { isTouchUsing } from '@/scripts/touch.js';
|
import { isTouchUsing } from '@/scripts/touch.js';
|
||||||
import {defaultStore} from '@/store.js'
|
|
||||||
import MkSwitchButton from '@/components/MkSwitch.button.vue';
|
|
||||||
let gamingType = computed(defaultStore.makeGetterSetter('gamingType'));
|
|
||||||
import { type Keymap } from '@/scripts/hotkey.js';
|
import { type Keymap } from '@/scripts/hotkey.js';
|
||||||
import { isFocusable } from '@/scripts/focus.js';
|
import { isFocusable } from '@/scripts/focus.js';
|
||||||
import { getNodeOrNull } from '@/scripts/get-dom-node-or-null.js';
|
import { getNodeOrNull } from '@/scripts/get-dom-node-or-null.js';
|
||||||
|
import {defaultStore} from '@/store.js'
|
||||||
|
let gamingType = computed(defaultStore.makeGetterSetter('gamingType'));
|
||||||
|
|
||||||
const childrenCache = new WeakMap<MenuParent, MenuItem[]>();
|
const childrenCache = new WeakMap<MenuParent, MenuItem[]>();
|
||||||
</script>
|
</script>
|
||||||
|
@ -488,35 +497,6 @@ onBeforeUnmount(() => {
|
||||||
border-radius: 6px;
|
border-radius: 6px;
|
||||||
}
|
}
|
||||||
|
|
||||||
&:not(:disabled):hover {
|
|
||||||
color: var(--accent);
|
|
||||||
text-decoration: none;
|
|
||||||
&:before {
|
|
||||||
background: var(--accentedBg);
|
|
||||||
}
|
|
||||||
&.gamingDark{
|
|
||||||
color:black !important;
|
|
||||||
}
|
|
||||||
&.gamingLight{
|
|
||||||
color:white !important;
|
|
||||||
}
|
|
||||||
&.gamingDark:before{
|
|
||||||
color:black !important;
|
|
||||||
background: linear-gradient(270deg, #e7a2a2, #e3cfa2, #ebefa1, #b3e7a6, #a6ebe7, #aec5e3, #cabded, #e0b9e3, #f4bddd); background-size: 1800% 1800%;
|
|
||||||
-webkit-animation: AnimationDark var(--gamingspeed) cubic-bezier(0, 0.2, 0.90, 1) infinite;
|
|
||||||
-moz-animation: AnimationDark var(--gamingspeed) cubic-bezier(0, 0.2, 0.90, 1) infinite;
|
|
||||||
animation: AnimationDark var(--gamingspeed) cubic-bezier(0, 0.2, 0.90, 1) infinite;
|
|
||||||
|
|
||||||
}
|
|
||||||
&.gamingLight:before{
|
|
||||||
color:white !important;
|
|
||||||
background: linear-gradient(270deg, #c06161, #c0a567, #b6ba69, #81bc72, #63c3be, #8bacd6, #9f8bd6, #d18bd6, #d883b4); background-size: 1800% 1800% !important;
|
|
||||||
-webkit-animation: AnimationLight var(--gamingspeed) cubic-bezier(0, 0.2, 0.90, 1) infinite !important;
|
|
||||||
-moz-animation: AnimationLight var(--gamingspeed) cubic-bezier(0, 0.2, 0.90, 1) infinite !important;
|
|
||||||
animation: AnimationLight var(--gamingspeed) cubic-bezier(0, 0.2, 0.90, 1) infinite !important;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
&:focus-visible {
|
&:focus-visible {
|
||||||
outline: none;
|
outline: none;
|
||||||
|
|
||||||
|
@ -531,6 +511,27 @@ onBeforeUnmount(() => {
|
||||||
&:focus-visible:active,
|
&:focus-visible:active,
|
||||||
&:focus-visible.active {
|
&:focus-visible.active {
|
||||||
color: var(--menuHoverFg, var(--accent));
|
color: var(--menuHoverFg, var(--accent));
|
||||||
|
&.gamingDark{
|
||||||
|
color:black !important;
|
||||||
|
}
|
||||||
|
&.gamingLight{
|
||||||
|
color:white !important;
|
||||||
|
}
|
||||||
|
&.gamingDark:before{
|
||||||
|
color:black !important;
|
||||||
|
background: linear-gradient(270deg, #e7a2a2, #e3cfa2, #ebefa1, #b3e7a6, #a6ebe7, #aec5e3, #cabded, #e0b9e3, #f4bddd); background-size: 1800% 1800%;
|
||||||
|
-webkit-animation: AnimationDark var(--gamingspeed) cubic-bezier(0, 0.2, 0.90, 1) infinite;
|
||||||
|
-moz-animation: AnimationDark var(--gamingspeed) cubic-bezier(0, 0.2, 0.90, 1) infinite;
|
||||||
|
animation: AnimationDark var(--gamingspeed) cubic-bezier(0, 0.2, 0.90, 1) infinite;
|
||||||
|
|
||||||
|
}
|
||||||
|
&.gamingLight:before{
|
||||||
|
color:white !important;
|
||||||
|
background: linear-gradient(270deg, #c06161, #c0a567, #b6ba69, #81bc72, #63c3be, #8bacd6, #9f8bd6, #d18bd6, #d883b4); background-size: 1800% 1800% !important;
|
||||||
|
-webkit-animation: AnimationLight var(--gamingspeed) cubic-bezier(0, 0.2, 0.90, 1) infinite !important;
|
||||||
|
-moz-animation: AnimationLight var(--gamingspeed) cubic-bezier(0, 0.2, 0.90, 1) infinite !important;
|
||||||
|
animation: AnimationLight var(--gamingspeed) cubic-bezier(0, 0.2, 0.90, 1) infinite !important;
|
||||||
|
}
|
||||||
|
|
||||||
&::before {
|
&::before {
|
||||||
background-color: var(--menuHoverBg, var(--accentedBg));
|
background-color: var(--menuHoverBg, var(--accentedBg));
|
||||||
|
@ -587,9 +588,6 @@ onBeforeUnmount(() => {
|
||||||
-moz-animation: AnimationLight var(--gamingspeed) cubic-bezier(0, 0.2, 0.90, 1) infinite !important;
|
-moz-animation: AnimationLight var(--gamingspeed) cubic-bezier(0, 0.2, 0.90, 1) infinite !important;
|
||||||
animation: AnimationLight var(--gamingspeed) cubic-bezier(0, 0.2, 0.90, 1) infinite !important;
|
animation: AnimationLight var(--gamingspeed) cubic-bezier(0, 0.2, 0.90, 1) infinite !important;
|
||||||
}
|
}
|
||||||
&.radio {
|
|
||||||
--menuActiveFg: var(--accent);
|
|
||||||
--menuActiveBg: var(--accentedBg);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
&.parent {
|
&.parent {
|
||||||
|
@ -612,45 +610,6 @@ onBeforeUnmount(() => {
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
opacity: 0.7;
|
opacity: 0.7;
|
||||||
}
|
}
|
||||||
|
|
||||||
&.parent {
|
|
||||||
pointer-events: auto;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
cursor: default;
|
|
||||||
|
|
||||||
&.childShowing {
|
|
||||||
color: var(--accent);
|
|
||||||
text-decoration: none;
|
|
||||||
|
|
||||||
&:before {
|
|
||||||
background: var(--accentedBg);
|
|
||||||
}
|
|
||||||
&.gamingDark{
|
|
||||||
color:black !important;
|
|
||||||
}
|
|
||||||
&.gamingLight{
|
|
||||||
color:white !important;
|
|
||||||
}
|
|
||||||
&.gamingDark:before{
|
|
||||||
color:black !important;
|
|
||||||
background: linear-gradient(270deg, #e7a2a2, #e3cfa2, #ebefa1, #b3e7a6, #a6ebe7, #aec5e3, #cabded, #e0b9e3, #f4bddd); background-size: 1800% 1800%;
|
|
||||||
-webkit-animation: AnimationDark var(--gamingspeed) cubic-bezier(0, 0.2, 0.90, 1) infinite;
|
|
||||||
-moz-animation: AnimationDark var(--gamingspeed) cubic-bezier(0, 0.2, 0.90, 1) infinite;
|
|
||||||
animation: AnimationDark var(--gamingspeed) cubic-bezier(0, 0.2, 0.90, 1) infinite;
|
|
||||||
}
|
|
||||||
|
|
||||||
&.gamingLight:before{
|
|
||||||
color:white !important;
|
|
||||||
background: linear-gradient(270deg, #c06161, #c0a567, #b6ba69, #81bc72, #63c3be, #8bacd6, #9f8bd6, #d18bd6, #d883b4); background-size: 1800% 1800% !important;
|
|
||||||
-webkit-animation: AnimationLight var(--gamingspeed) cubic-bezier(0, 0.2, 0.90, 1) infinite !important;
|
|
||||||
-moz-animation: AnimationLight var(--gamingspeed) cubic-bezier(0, 0.2, 0.90, 1) infinite !important;
|
|
||||||
animation: AnimationLight var(--gamingspeed) cubic-bezier(0, 0.2, 0.90, 1) infinite !important;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.item_content {
|
.item_content {
|
||||||
|
@ -696,11 +655,10 @@ onBeforeUnmount(() => {
|
||||||
}
|
}
|
||||||
|
|
||||||
.indicator {
|
.indicator {
|
||||||
position: absolute;
|
display: flex;
|
||||||
top: 5px;
|
align-items: center;
|
||||||
right: 18px;
|
|
||||||
color: var(--indicator);
|
color: var(--indicator);
|
||||||
font-size: 8px;
|
font-size: 12px;
|
||||||
animation: global-blink 1s infinite;
|
animation: global-blink 1s infinite;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -800,7 +758,5 @@ onBeforeUnmount(() => {
|
||||||
100% {
|
100% {
|
||||||
background-position: 0% 50%
|
background-position: 0% 50%
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -46,7 +46,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
</FormLink>
|
</FormLink>
|
||||||
</div>
|
</div>
|
||||||
</FormSection>
|
</FormSection>
|
||||||
<FormSection v-if="instance.repositoryUrl !== 'https://github.com/misskey-dev/misskey'">
|
<FormSection v-if="instance.repositoryUrl !== 'https://github.com/type4ny-project/type4ny'">
|
||||||
<div class="_gaps_s">
|
<div class="_gaps_s">
|
||||||
<MkInfo>
|
<MkInfo>
|
||||||
{{ i18n.tsx._aboutType4ny.thisIsModifiedVersion({ name: instance.name }) }}
|
{{ i18n.tsx._aboutType4ny.thisIsModifiedVersion({ name: instance.name }) }}
|
||||||
|
|
|
@ -22,14 +22,14 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
<FormSection>
|
<FormSection>
|
||||||
<div class="_gaps_m">
|
<div class="_gaps_m">
|
||||||
<MkKeyValue :copy="version">
|
<MkKeyValue :copy="version">
|
||||||
<template #key>Misskey</template>
|
<template #key>Type4ny</template>
|
||||||
<template #value>{{ version }}</template>
|
<template #value>{{ version }}</template>
|
||||||
</MkKeyValue>
|
</MkKeyValue>
|
||||||
<div v-html="i18n.tsx.poweredByMisskeyDescription({ name: instance.name ?? host })">
|
<div v-html="i18n.tsx.poweredByType4nyDescription({ name: instance.name ?? host })">
|
||||||
</div>
|
</div>
|
||||||
<FormLink to="/about-misskey">
|
<FormLink to="/about-type4ny">
|
||||||
<template #icon><i class="ti ti-info-circle"></i></template>
|
<template #icon><i class="ti ti-info-circle"></i></template>
|
||||||
{{ i18n.ts.aboutMisskey }}
|
{{ i18n.ts.aboutType4ny }}
|
||||||
</FormLink>
|
</FormLink>
|
||||||
<FormLink v-if="instance.repositoryUrl || instance.providesTarball" :to="instance.repositoryUrl || `/tarball/misskey-${version}.tar.gz`" external>
|
<FormLink v-if="instance.repositoryUrl || instance.providesTarball" :to="instance.repositoryUrl || `/tarball/misskey-${version}.tar.gz`" external>
|
||||||
<template #icon><i class="ti ti-code"></i></template>
|
<template #icon><i class="ti ti-code"></i></template>
|
||||||
|
@ -138,6 +138,7 @@ import FormSuspense from '@/components/form/suspense.vue';
|
||||||
import MkFolder from '@/components/MkFolder.vue';
|
import MkFolder from '@/components/MkFolder.vue';
|
||||||
import MkKeyValue from '@/components/MkKeyValue.vue';
|
import MkKeyValue from '@/components/MkKeyValue.vue';
|
||||||
import MkLink from '@/components/MkLink.vue';
|
import MkLink from '@/components/MkLink.vue';
|
||||||
|
import MkInfo from "@/components/MkInfo.vue";
|
||||||
|
|
||||||
const initStats = () => misskeyApi('stats', {});
|
const initStats = () => misskeyApi('stats', {});
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -10,8 +10,11 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
<MkSpacer :contentMax="700" :marginMin="16" :marginMax="32">
|
<MkSpacer :contentMax="700" :marginMin="16" :marginMax="32">
|
||||||
<FormSuspense :p="init">
|
<FormSuspense :p="init">
|
||||||
<div class="_gaps_m">
|
<div class="_gaps_m">
|
||||||
<MkSwitch v-model="enableRegistration">
|
<MkSwitch v-model="enableRegistration" :disabled="isManaged" >
|
||||||
<template #label>{{ i18n.ts.enableRegistration }}</template>
|
<template #label>
|
||||||
|
{{ i18n.ts.enableRegistration }}
|
||||||
|
</template>
|
||||||
|
<template #caption v-if="isManaged">{{ i18n.ts.managedInstanceIsNotEditable }}</template>
|
||||||
</MkSwitch>
|
</MkSwitch>
|
||||||
|
|
||||||
<MkSwitch v-model="emailRequiredForSignup">
|
<MkSwitch v-model="emailRequiredForSignup">
|
||||||
|
@ -89,6 +92,7 @@ import MkButton from '@/components/MkButton.vue';
|
||||||
import FormLink from '@/components/form/link.vue';
|
import FormLink from '@/components/form/link.vue';
|
||||||
|
|
||||||
const enableRegistration = ref<boolean>(false);
|
const enableRegistration = ref<boolean>(false);
|
||||||
|
const isManaged = ref<boolean>(false);
|
||||||
const emailRequiredForSignup = ref<boolean>(false);
|
const emailRequiredForSignup = ref<boolean>(false);
|
||||||
const sensitiveWords = ref<string>('');
|
const sensitiveWords = ref<string>('');
|
||||||
const prohibitedWords = ref<string>('');
|
const prohibitedWords = ref<string>('');
|
||||||
|
@ -101,6 +105,7 @@ const enableGDPRMode = ref<boolean>(false);
|
||||||
|
|
||||||
async function init() {
|
async function init() {
|
||||||
const meta = await misskeyApi('admin/meta');
|
const meta = await misskeyApi('admin/meta');
|
||||||
|
isManaged.value = meta.isManaged;
|
||||||
enableRegistration.value = !meta.disableRegistration;
|
enableRegistration.value = !meta.disableRegistration;
|
||||||
emailRequiredForSignup.value = meta.emailRequiredForSignup;
|
emailRequiredForSignup.value = meta.emailRequiredForSignup;
|
||||||
sensitiveWords.value = meta.sensitiveWords.join('\n');
|
sensitiveWords.value = meta.sensitiveWords.join('\n');
|
||||||
|
|
|
@ -8,7 +8,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
<template #header><XHeader :tabs="headerTabs"/></template>
|
<template #header><XHeader :tabs="headerTabs"/></template>
|
||||||
<MkSpacer :contentMax="700" :marginMin="16" :marginMax="32">
|
<MkSpacer :contentMax="700" :marginMin="16" :marginMax="32">
|
||||||
<FormSuspense :p="init">
|
<FormSuspense :p="init">
|
||||||
<div class="_gaps_m">
|
<div v-if="!isManaged" class="_gaps_m">
|
||||||
<MkSwitch v-model="useObjectStorage">{{ i18n.ts.useObjectStorage }}</MkSwitch>
|
<MkSwitch v-model="useObjectStorage">{{ i18n.ts.useObjectStorage }}</MkSwitch>
|
||||||
|
|
||||||
<template v-if="useObjectStorage">
|
<template v-if="useObjectStorage">
|
||||||
|
@ -70,12 +70,15 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
</MkSwitch>
|
</MkSwitch>
|
||||||
</template>
|
</template>
|
||||||
</div>
|
</div>
|
||||||
|
<div v-else class="_gaps_m">
|
||||||
|
{{i18n.ts.managedInstanceIsNotEditable}}
|
||||||
|
</div>
|
||||||
</FormSuspense>
|
</FormSuspense>
|
||||||
</MkSpacer>
|
</MkSpacer>
|
||||||
<template #footer>
|
<template #footer>
|
||||||
<div :class="$style.footer">
|
<div :class="$style.footer">
|
||||||
<MkSpacer :contentMax="700" :marginMin="16" :marginMax="16">
|
<MkSpacer :contentMax="700" :marginMin="16" :marginMax="16">
|
||||||
<MkButton primary rounded @click="save"><i class="ti ti-check"></i> {{ i18n.ts.save }}</MkButton>
|
<MkButton primary rounded @click="save" v-if="!isManaged"><i class="ti ti-check"></i> {{ i18n.ts.save }}</MkButton>
|
||||||
</MkSpacer>
|
</MkSpacer>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
@ -109,9 +112,11 @@ const objectStorageUseSSL = ref<boolean>(false);
|
||||||
const objectStorageUseProxy = ref<boolean>(false);
|
const objectStorageUseProxy = ref<boolean>(false);
|
||||||
const objectStorageSetPublicRead = ref<boolean>(false);
|
const objectStorageSetPublicRead = ref<boolean>(false);
|
||||||
const objectStorageS3ForcePathStyle = ref<boolean>(true);
|
const objectStorageS3ForcePathStyle = ref<boolean>(true);
|
||||||
|
const isManaged = ref<boolean>(false);
|
||||||
|
|
||||||
async function init() {
|
async function init() {
|
||||||
const meta = await misskeyApi('admin/meta');
|
const meta = await misskeyApi('admin/meta');
|
||||||
|
isManaged.value = meta.isManaged;
|
||||||
useObjectStorage.value = meta.useObjectStorage;
|
useObjectStorage.value = meta.useObjectStorage;
|
||||||
objectStorageBaseUrl.value = meta.objectStorageBaseUrl;
|
objectStorageBaseUrl.value = meta.objectStorageBaseUrl;
|
||||||
objectStorageBucket.value = meta.objectStorageBucket;
|
objectStorageBucket.value = meta.objectStorageBucket;
|
||||||
|
|
|
@ -10,9 +10,12 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
<FormSuspense :p="init">
|
<FormSuspense :p="init">
|
||||||
<div class="_gaps">
|
<div class="_gaps">
|
||||||
<div class="_panel" style="padding: 16px;">
|
<div class="_panel" style="padding: 16px;">
|
||||||
<MkSwitch v-model="enableServerMachineStats">
|
<MkSwitch v-model="enableServerMachineStats" :disabled="isManaged">
|
||||||
<template #label>{{ i18n.ts.enableServerMachineStats }}</template>
|
<template #label>{{ i18n.ts.enableServerMachineStats }}</template>
|
||||||
<template #caption>{{ i18n.ts.turnOffToImprovePerformance }}</template>
|
<template #caption>
|
||||||
|
{{ i18n.ts.turnOffToImprovePerformance }}
|
||||||
|
<span v-if="isManaged">{{ i18n.ts.managedInstanceIsNotEditable }}</span>
|
||||||
|
</template>
|
||||||
</MkSwitch>
|
</MkSwitch>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -78,6 +81,7 @@ const enableIdenticonGeneration = ref<boolean>(false);
|
||||||
const enableChartsForRemoteUser = ref<boolean>(false);
|
const enableChartsForRemoteUser = ref<boolean>(false);
|
||||||
const enableChartsForFederatedInstances = ref<boolean>(false);
|
const enableChartsForFederatedInstances = ref<boolean>(false);
|
||||||
const requestEmojiAllOk = ref(false);
|
const requestEmojiAllOk = ref(false);
|
||||||
|
const isManaged = ref(false);
|
||||||
let DiscordWebhookUrl = ref(null);
|
let DiscordWebhookUrl = ref(null);
|
||||||
let DiscordWebhookUrlWordBlock = ref(null);
|
let DiscordWebhookUrlWordBlock = ref(null);
|
||||||
let EmojiBotToken = ref(null);
|
let EmojiBotToken = ref(null);
|
||||||
|
@ -89,6 +93,7 @@ async function init() {
|
||||||
enableIdenticonGeneration.value = meta.enableIdenticonGeneration;
|
enableIdenticonGeneration.value = meta.enableIdenticonGeneration;
|
||||||
enableChartsForRemoteUser.value = meta.enableChartsForRemoteUser;
|
enableChartsForRemoteUser.value = meta.enableChartsForRemoteUser;
|
||||||
enableChartsForFederatedInstances.value = meta.enableChartsForFederatedInstances;
|
enableChartsForFederatedInstances.value = meta.enableChartsForFederatedInstances;
|
||||||
|
isManaged.value = meta.isManaged;
|
||||||
requestEmojiAllOk.value = meta.requestEmojiAllOk;
|
requestEmojiAllOk.value = meta.requestEmojiAllOk;
|
||||||
DiscordWebhookUrl.value = meta.DiscordWebhookUrl;
|
DiscordWebhookUrl.value = meta.DiscordWebhookUrl;
|
||||||
DiscordWebhookUrlWordBlock.value = meta.DiscordWebhookUrlWordBlock;
|
DiscordWebhookUrlWordBlock.value = meta.DiscordWebhookUrlWordBlock;
|
||||||
|
|
|
@ -57,9 +57,9 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
<FormSection>
|
<FormSection>
|
||||||
<template #label>{{ i18n.ts.files }}</template>
|
<template #label>{{ i18n.ts.files }}</template>
|
||||||
|
<template #description v-if="isManaged">{{ i18n.ts.managedInstanceIsNotEditable }}</template>
|
||||||
<div class="_gaps_m">
|
<div class="_gaps_m">
|
||||||
<MkSwitch v-model="cacheRemoteFiles">
|
<MkSwitch v-model="cacheRemoteFiles" :disabled="isManaged">
|
||||||
<template #label>{{ i18n.ts.cacheRemoteFiles }}</template>
|
<template #label>{{ i18n.ts.cacheRemoteFiles }}</template>
|
||||||
<template #caption>{{ i18n.ts.cacheRemoteFilesDescription }}{{ i18n.ts.youCanCleanRemoteFilesCache }}</template>
|
<template #caption>{{ i18n.ts.cacheRemoteFilesDescription }}{{ i18n.ts.youCanCleanRemoteFilesCache }}</template>
|
||||||
</MkSwitch>
|
</MkSwitch>
|
||||||
|
@ -98,31 +98,32 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
<FormSection>
|
<FormSection>
|
||||||
<template #label>Misskey® Fan-out Timeline Technology™ (FTT)</template>
|
<template #label>Misskey® Fan-out Timeline Technology™ (FTT)</template>
|
||||||
|
<template #description v-if="isManaged">{{ i18n.ts.managedInstanceIsNotEditable }}</template>
|
||||||
|
|
||||||
<div class="_gaps_m">
|
<div class="_gaps_m">
|
||||||
<MkSwitch v-model="enableFanoutTimeline">
|
<MkSwitch v-model="enableFanoutTimeline" :disabled="isManaged">
|
||||||
<template #label>{{ i18n.ts.enable }}</template>
|
<template #label>{{ i18n.ts.enable }}</template>
|
||||||
<template #caption>{{ i18n.ts._serverSettings.fanoutTimelineDescription }}</template>
|
<template #caption>{{ i18n.ts._serverSettings.fanoutTimelineDescription }}</template>
|
||||||
</MkSwitch>
|
</MkSwitch>
|
||||||
|
|
||||||
<MkSwitch v-model="enableFanoutTimelineDbFallback">
|
<MkSwitch v-model="enableFanoutTimelineDbFallback" :disabled="isManaged">
|
||||||
<template #label>{{ i18n.ts._serverSettings.fanoutTimelineDbFallback }}</template>
|
<template #label>{{ i18n.ts._serverSettings.fanoutTimelineDbFallback }}</template>
|
||||||
<template #caption>{{ i18n.ts._serverSettings.fanoutTimelineDbFallbackDescription }}</template>
|
<template #caption>{{ i18n.ts._serverSettings.fanoutTimelineDbFallbackDescription }}</template>
|
||||||
</MkSwitch>
|
</MkSwitch>
|
||||||
|
|
||||||
<MkInput v-model="perLocalUserUserTimelineCacheMax" type="number">
|
<MkInput v-model="perLocalUserUserTimelineCacheMax" type="number" :disabled="isManaged">
|
||||||
<template #label>perLocalUserUserTimelineCacheMax</template>
|
<template #label>perLocalUserUserTimelineCacheMax</template>
|
||||||
</MkInput>
|
</MkInput>
|
||||||
|
|
||||||
<MkInput v-model="perRemoteUserUserTimelineCacheMax" type="number">
|
<MkInput v-model="perRemoteUserUserTimelineCacheMax" type="number" :disabled="isManaged">
|
||||||
<template #label>perRemoteUserUserTimelineCacheMax</template>
|
<template #label>perRemoteUserUserTimelineCacheMax</template>
|
||||||
</MkInput>
|
</MkInput>
|
||||||
|
|
||||||
<MkInput v-model="perUserHomeTimelineCacheMax" type="number">
|
<MkInput v-model="perUserHomeTimelineCacheMax" type="number" :disabled="isManaged">
|
||||||
<template #label>perUserHomeTimelineCacheMax</template>
|
<template #label>perUserHomeTimelineCacheMax</template>
|
||||||
</MkInput>
|
</MkInput>
|
||||||
|
|
||||||
<MkInput v-model="perUserListTimelineCacheMax" type="number">
|
<MkInput v-model="perUserListTimelineCacheMax" type="number" :disabled="isManaged">
|
||||||
<template #label>perUserListTimelineCacheMax</template>
|
<template #label>perUserListTimelineCacheMax</template>
|
||||||
</MkInput>
|
</MkInput>
|
||||||
</div>
|
</div>
|
||||||
|
@ -249,7 +250,7 @@ const urlPreviewMaximumContentLength = ref<number>(1024 * 1024 * 10);
|
||||||
const urlPreviewRequireContentLength = ref<boolean>(true);
|
const urlPreviewRequireContentLength = ref<boolean>(true);
|
||||||
const urlPreviewUserAgent = ref<string | null>(null);
|
const urlPreviewUserAgent = ref<string | null>(null);
|
||||||
const urlPreviewSummaryProxyUrl = ref<string | null>(null);
|
const urlPreviewSummaryProxyUrl = ref<string | null>(null);
|
||||||
|
const isManaged = ref<boolean>(false);
|
||||||
async function init(): Promise<void> {
|
async function init(): Promise<void> {
|
||||||
const meta = await misskeyApi('admin/meta');
|
const meta = await misskeyApi('admin/meta');
|
||||||
name.value = meta.name;
|
name.value = meta.name;
|
||||||
|
@ -278,6 +279,7 @@ async function init(): Promise<void> {
|
||||||
urlPreviewRequireContentLength.value = meta.urlPreviewRequireContentLength;
|
urlPreviewRequireContentLength.value = meta.urlPreviewRequireContentLength;
|
||||||
urlPreviewUserAgent.value = meta.urlPreviewUserAgent;
|
urlPreviewUserAgent.value = meta.urlPreviewUserAgent;
|
||||||
urlPreviewSummaryProxyUrl.value = meta.urlPreviewSummaryProxyUrl;
|
urlPreviewSummaryProxyUrl.value = meta.urlPreviewSummaryProxyUrl;
|
||||||
|
isManaged.value = meta.isManaged;
|
||||||
}
|
}
|
||||||
|
|
||||||
async function save() {
|
async function save() {
|
||||||
|
|
|
@ -4,5 +4,7 @@
|
||||||
*/
|
*/
|
||||||
import { $i } from '@/account.js';
|
import { $i } from '@/account.js';
|
||||||
import { instance } from '@/instance.js';
|
import { instance } from '@/instance.js';
|
||||||
export const isLocalTimelineAvailable = ($i == null && instance.policies.ltlAvailable) || ($i != null && $i.policies.ltlAvailable);
|
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
||||||
export const isGlobalTimelineAvailable = ($i == null && instance.policies.gtlAvailable) || ($i != null && $i.policies.gtlAvailable);
|
export const isLocalTimelineAvailable = ($i == null && instance?.policies?.ltlAvailable) || ($i != null && $i?.policies?.ltlAvailable);
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
||||||
|
export const isGlobalTimelineAvailable = ($i == null && instance?.policies?.gtlAvailable) || ($i != null && $i?.policies?.gtlAvailable);
|
||||||
|
|
|
@ -4,7 +4,7 @@ SPDX-FileCopyrightText: syuilo and misskey-project , Type4ny-projectSPDX-License
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="mk-app">
|
<div class="mk-app">
|
||||||
<a v-if="isRoot" href="https://github.com/misskey-dev/misskey" target="_blank" class="github-corner" aria-label="View source on GitHub"><svg width="80" height="80" viewBox="0 0 250 250" style="fill:var(--panel); color:var(--fg); position: fixed; z-index: 10; top: 0; border: 0; right: 0;" aria-hidden="true"><path d="M0,0 L115,115 L130,115 L142,142 L250,250 L250,0 Z"></path><path d="M128.3,109.0 C113.8,99.7 119.0,89.6 119.0,89.6 C122.0,82.7 120.5,78.6 120.5,78.6 C119.2,72.0 123.4,76.3 123.4,76.3 C127.3,80.9 125.5,87.3 125.5,87.3 C122.9,97.6 130.6,101.9 134.4,103.2" fill="currentColor" style="transform-origin: 130px 106px;" class="octo-arm"></path><path d="M115.0,115.0 C114.9,115.1 118.7,116.5 119.8,115.4 L133.7,101.6 C136.9,99.2 139.9,98.4 142.2,98.6 C133.8,88.0 127.5,74.4 143.8,58.0 C148.5,53.4 154.0,51.2 159.7,51.0 C160.3,49.4 163.2,43.6 171.4,40.1 C171.4,40.1 176.1,42.5 178.8,56.2 C183.1,58.6 187.2,61.8 190.9,65.4 C194.5,69.0 197.7,73.2 200.1,77.6 C213.8,80.2 216.3,84.9 216.3,84.9 C212.7,93.1 206.9,96.0 205.4,96.6 C205.1,102.4 203.0,107.8 198.3,112.5 C181.9,128.9 168.3,122.5 157.7,114.1 C157.9,116.9 156.7,120.9 152.7,124.9 L141.0,136.5 C139.8,137.7 141.6,141.9 141.8,141.8 Z" fill="currentColor" class="octo-body"></path></svg></a>
|
<a v-if="isRoot" href="https://github.com/type4ny-project/type4ny" target="_blank" class="github-corner" aria-label="View source on GitHub"><svg width="80" height="80" viewBox="0 0 250 250" style="fill:var(--panel); color:var(--fg); position: fixed; z-index: 10; top: 0; border: 0; right: 0;" aria-hidden="true"><path d="M0,0 L115,115 L130,115 L142,142 L250,250 L250,0 Z"></path><path d="M128.3,109.0 C113.8,99.7 119.0,89.6 119.0,89.6 C122.0,82.7 120.5,78.6 120.5,78.6 C119.2,72.0 123.4,76.3 123.4,76.3 C127.3,80.9 125.5,87.3 125.5,87.3 C122.9,97.6 130.6,101.9 134.4,103.2" fill="currentColor" style="transform-origin: 130px 106px;" class="octo-arm"></path><path d="M115.0,115.0 C114.9,115.1 118.7,116.5 119.8,115.4 L133.7,101.6 C136.9,99.2 139.9,98.4 142.2,98.6 C133.8,88.0 127.5,74.4 143.8,58.0 C148.5,53.4 154.0,51.2 159.7,51.0 C160.3,49.4 163.2,43.6 171.4,40.1 C171.4,40.1 176.1,42.5 178.8,56.2 C183.1,58.6 187.2,61.8 190.9,65.4 C194.5,69.0 197.7,73.2 200.1,77.6 C213.8,80.2 216.3,84.9 216.3,84.9 C212.7,93.1 206.9,96.0 205.4,96.6 C205.1,102.4 203.0,107.8 198.3,112.5 C181.9,128.9 168.3,122.5 157.7,114.1 C157.9,116.9 156.7,120.9 152.7,124.9 L141.0,136.5 C139.8,137.7 141.6,141.9 141.8,141.8 Z" fill="currentColor" class="octo-body"></path></svg></a>
|
||||||
|
|
||||||
<div v-if="!narrow && !isRoot" class="side">
|
<div v-if="!narrow && !isRoot" class="side">
|
||||||
<div class="banner" :style="{ backgroundImage: instance.backgroundImageUrl ? `url(${ instance.backgroundImageUrl })` : 'none' }"></div>
|
<div class="banner" :style="{ backgroundImage: instance.backgroundImageUrl ? `url(${ instance.backgroundImageUrl })` : 'none' }"></div>
|
||||||
|
|
|
@ -35,7 +35,7 @@ async function offlineContentHTML() {
|
||||||
reload: i18n.ts?.reload ?? 'Reload',
|
reload: i18n.ts?.reload ?? 'Reload',
|
||||||
};
|
};
|
||||||
|
|
||||||
return `<!DOCTYPE html><html lang="ja"><head><meta charset="UTF-8"><meta content="width=device-width,initial-scale=1"name="viewport"><title>${messages.title}</title><style>body{background-color:#0c1210;color:#dee7e4;font-family:Hiragino Maru Gothic Pro,BIZ UDGothic,Roboto,HelveticaNeue,Arial,sans-serif;line-height:1.35;display:flex;flex-direction:column;align-items:center;justify-content:center;min-height:100vh;margin:0;padding:24px;box-sizing:border-box}.icon{max-width:120px;width:100%;height:auto;margin-bottom:20px;}.message{text-align:center;font-size:20px;font-weight:700;margin-bottom:20px}.version{text-align:center;font-size:90%;margin-bottom:20px}button{padding:7px 14px;min-width:100px;font-weight:700;font-family:Hiragino Maru Gothic Pro,BIZ UDGothic,Roboto,HelveticaNeue,Arial,sans-serif;line-height:1.35;border-radius:99rem;background-color:#b4e900;color:#192320;border:none;cursor:pointer;-webkit-tap-highlight-color:transparent}button:hover{background-color:#c6ff03}</style></head><body><svg class="icon"fill="none"height="24"stroke="currentColor"stroke-linecap="round"stroke-linejoin="round"stroke-width="2"viewBox="0 0 24 24"width="24"xmlns="http://www.w3.org/2000/svg"><path d="M0 0h24v24H0z"fill="none"stroke="none"/><path d="M9.58 5.548c.24 -.11 .492 -.207 .752 -.286c1.88 -.572 3.956 -.193 5.444 1c1.488 1.19 2.162 3.007 1.77 4.769h.99c1.913 0 3.464 1.56 3.464 3.486c0 .957 -.383 1.824 -1.003 2.454m-2.997 1.033h-11.343c-2.572 -.004 -4.657 -2.011 -4.657 -4.487c0 -2.475 2.085 -4.482 4.657 -4.482c.13 -.582 .37 -1.128 .7 -1.62"/><path d="M3 3l18 18"/></svg><div class="message">${messages.header}</div><div class="version">v${_VERSION_}</div><button onclick="reloadPage()">${messages.reload}</button><script>function reloadPage(){location.reload(!0)}</script></body></html>`;
|
return `<!DOCTYPE html><html lang="ja"><head><meta charset="UTF-8"><meta content="width=device-width,initial-scale=1"name="viewport"><title>${messages.title}</title><style>body{background-color:#1b2b34;color:#ffffff;font-family:Hiragino Maru Gothic Pro,BIZ UDGothic,Roboto,HelveticaNeue,Arial,sans-serif;line-height:1.35;display:flex;flex-direction:column;align-items:center;justify-content:center;min-height:100vh;margin:0;padding:24px;box-sizing:border-box}.icon{max-width:120px;width:100%;height:auto;margin-bottom:20px;}.message{text-align:center;font-size:20px;font-weight:700;margin-bottom:20px}.version{text-align:center;font-size:90%;margin-bottom:20px}button{padding:7px 14px;min-width:100px;font-weight:700;font-family:Hiragino Maru Gothic Pro,BIZ UDGothic,Roboto,HelveticaNeue,Arial,sans-serif;line-height:1.35;border-radius:99rem;background-color:#2ECC71;color:#1b2b34;border:none;cursor:pointer;-webkit-tap-highlight-color:transparent}button:hover{background-color:#40d37e}</style></head><body><svg class="icon"fill="none"height="24"stroke="currentColor"stroke-linecap="round"stroke-linejoin="round"stroke-width="2"viewBox="0 0 24 24"width="24"xmlns="http://www.w3.org/2000/svg"><path d="M0 0h24v24H0z"fill="none"stroke="none"/><path d="M9.58 5.548c.24 -.11 .492 -.207 .752 -.286c1.88 -.572 3.956 -.193 5.444 1c1.488 1.19 2.162 3.007 1.77 4.769h.99c1.913 0 3.464 1.56 3.464 3.486c0 .957 -.383 1.824 -1.003 2.454m-2.997 1.033h-11.343c-2.572 -.004 -4.657 -2.011 -4.657 -4.487c0 -2.475 2.085 -4.482 4.657 -4.482c.13 -.582 .37 -1.128 .7 -1.62"/><path d="M3 3l18 18"/></svg><div class="message">${messages.header}</div><div class="version">v${_VERSION_}</div><button onclick="reloadPage()">${messages.reload}</button><script>function reloadPage(){location.reload(!0)}</script></body></html>`;
|
||||||
}
|
}
|
||||||
|
|
||||||
globalThis.addEventListener('fetch', ev => {
|
globalThis.addEventListener('fetch', ev => {
|
||||||
|
|
Loading…
Reference in a new issue