parent
10454e688c
commit
36657836f7
8
locales/index.d.ts
vendored
8
locales/index.d.ts
vendored
@ -5357,14 +5357,6 @@ export interface Locale extends ILocale {
|
|||||||
"autoSuspendedForNotResponding": string;
|
"autoSuspendedForNotResponding": string;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
/**
|
|
||||||
* ノートの自己消滅
|
|
||||||
*/
|
|
||||||
"scheduledNoteDelete": string;
|
|
||||||
/**
|
|
||||||
* このノートは{time}に消滅します
|
|
||||||
*/
|
|
||||||
"noteDeletationAt": ParameterizedString<"time">;
|
|
||||||
"_bubbleGame": {
|
"_bubbleGame": {
|
||||||
/**
|
/**
|
||||||
* 遊び方
|
* 遊び方
|
||||||
|
@ -1337,8 +1337,6 @@ _delivery:
|
|||||||
manuallySuspended: "手動停止中"
|
manuallySuspended: "手動停止中"
|
||||||
goneSuspended: "サーバー削除のため停止中"
|
goneSuspended: "サーバー削除のため停止中"
|
||||||
autoSuspendedForNotResponding: "サーバー応答なしのため停止中"
|
autoSuspendedForNotResponding: "サーバー応答なしのため停止中"
|
||||||
scheduledNoteDelete: "ノートの自己消滅"
|
|
||||||
noteDeletationAt: "このノートは{time}に消滅します"
|
|
||||||
|
|
||||||
_bubbleGame:
|
_bubbleGame:
|
||||||
howToPlay: "遊び方"
|
howToPlay: "遊び方"
|
||||||
|
@ -1,11 +0,0 @@
|
|||||||
export class ScheduledNoteDelete1709187210308 {
|
|
||||||
name = 'ScheduledNoteDelete1709187210308'
|
|
||||||
|
|
||||||
async up(queryRunner) {
|
|
||||||
await queryRunner.query(`ALTER TABLE "note" ADD "deleteAt" TIMESTAMP WITH TIME ZONE`);
|
|
||||||
}
|
|
||||||
|
|
||||||
async down(queryRunner) {
|
|
||||||
await queryRunner.query(`ALTER TABLE "note" DROP COLUMN "deleteAt"`);
|
|
||||||
}
|
|
||||||
}
|
|
@ -148,7 +148,6 @@ type Option = {
|
|||||||
uri?: string | null;
|
uri?: string | null;
|
||||||
url?: string | null;
|
url?: string | null;
|
||||||
app?: MiApp | null;
|
app?: MiApp | null;
|
||||||
deleteAt?: Date | null;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
@ -368,10 +367,6 @@ export class NoteCreateService implements OnApplicationShutdown {
|
|||||||
mentionedUsers = data.apMentions ?? await this.extractMentionedUsers(user, combinedTokens);
|
mentionedUsers = data.apMentions ?? await this.extractMentionedUsers(user, combinedTokens);
|
||||||
}
|
}
|
||||||
|
|
||||||
const willCauseNotification = mentionedUsers.some(u => u.host === null)
|
|
||||||
|| (data.visibility === 'specified' && data.visibleUsers?.some(u => u.host === null))
|
|
||||||
|| data.reply?.userHost === null || (this.isRenote(data) && this.isQuote(data) && data.renote.userHost === null) || false;
|
|
||||||
|
|
||||||
// if the host is media-silenced, custom emojis are not allowed
|
// if the host is media-silenced, custom emojis are not allowed
|
||||||
if (this.utilityService.isMediaSilencedHost(meta.mediaSilencedHosts, user.host)) emojis = [];
|
if (this.utilityService.isMediaSilencedHost(meta.mediaSilencedHosts, user.host)) emojis = [];
|
||||||
|
|
||||||
@ -444,7 +439,6 @@ export class NoteCreateService implements OnApplicationShutdown {
|
|||||||
name: data.name,
|
name: data.name,
|
||||||
text: data.text,
|
text: data.text,
|
||||||
hasPoll: data.poll != null,
|
hasPoll: data.poll != null,
|
||||||
deleteAt: data.deleteAt,
|
|
||||||
cw: data.cw ?? null,
|
cw: data.cw ?? null,
|
||||||
tags: tags.map(tag => normalizeForSearch(tag)),
|
tags: tags.map(tag => normalizeForSearch(tag)),
|
||||||
emojis,
|
emojis,
|
||||||
@ -620,16 +614,6 @@ export class NoteCreateService implements OnApplicationShutdown {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (data.deleteAt) {
|
|
||||||
const delay = data.deleteAt.getTime() - Date.now();
|
|
||||||
this.queueService.scheduledNoteDeleteQueue.add(note.id, {
|
|
||||||
noteId: note.id,
|
|
||||||
}, {
|
|
||||||
delay,
|
|
||||||
removeOnComplete: true,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!silent) {
|
if (!silent) {
|
||||||
if (this.userEntityService.isLocalUser(user)) this.activeUsersChart.write(user);
|
if (this.userEntityService.isLocalUser(user)) this.activeUsersChart.write(user);
|
||||||
|
|
||||||
|
@ -12,7 +12,6 @@ import { allSettled } from '@/misc/promise-tracker.js';
|
|||||||
import {
|
import {
|
||||||
DeliverJobData,
|
DeliverJobData,
|
||||||
EndedPollNotificationJobData,
|
EndedPollNotificationJobData,
|
||||||
ScheduledNoteDeleteJobData,
|
|
||||||
InboxJobData,
|
InboxJobData,
|
||||||
RelationshipJobData,
|
RelationshipJobData,
|
||||||
UserWebhookDeliverJobData,
|
UserWebhookDeliverJobData,
|
||||||
@ -22,7 +21,6 @@ import type { Provider } from '@nestjs/common';
|
|||||||
|
|
||||||
export type SystemQueue = Bull.Queue<Record<string, unknown>>;
|
export type SystemQueue = Bull.Queue<Record<string, unknown>>;
|
||||||
export type EndedPollNotificationQueue = Bull.Queue<EndedPollNotificationJobData>;
|
export type EndedPollNotificationQueue = Bull.Queue<EndedPollNotificationJobData>;
|
||||||
export type ScheduledNoteDeleteQueue = Bull.Queue<ScheduledNoteDeleteJobData>;
|
|
||||||
export type DeliverQueue = Bull.Queue<DeliverJobData>;
|
export type DeliverQueue = Bull.Queue<DeliverJobData>;
|
||||||
export type InboxQueue = Bull.Queue<InboxJobData>;
|
export type InboxQueue = Bull.Queue<InboxJobData>;
|
||||||
export type DbQueue = Bull.Queue;
|
export type DbQueue = Bull.Queue;
|
||||||
@ -43,12 +41,6 @@ const $endedPollNotification: Provider = {
|
|||||||
inject: [DI.config],
|
inject: [DI.config],
|
||||||
};
|
};
|
||||||
|
|
||||||
const $scheduledNoteDelete: Provider = {
|
|
||||||
provide: 'queue:scheduledNoteDelete',
|
|
||||||
useFactory: (config: Config) => new Bull.Queue(QUEUE.SCHEDULED_NOTE_DELETE, baseQueueOptions(config, QUEUE.SCHEDULED_NOTE_DELETE)),
|
|
||||||
inject: [DI.config],
|
|
||||||
};
|
|
||||||
|
|
||||||
const $deliver: Provider = {
|
const $deliver: Provider = {
|
||||||
provide: 'queue:deliver',
|
provide: 'queue:deliver',
|
||||||
useFactory: (config: Config) => new Bull.Queue(QUEUE.DELIVER, baseQueueOptions(config, QUEUE.DELIVER)),
|
useFactory: (config: Config) => new Bull.Queue(QUEUE.DELIVER, baseQueueOptions(config, QUEUE.DELIVER)),
|
||||||
@ -97,7 +89,6 @@ const $systemWebhookDeliver: Provider = {
|
|||||||
providers: [
|
providers: [
|
||||||
$system,
|
$system,
|
||||||
$endedPollNotification,
|
$endedPollNotification,
|
||||||
$scheduledNoteDelete,
|
|
||||||
$deliver,
|
$deliver,
|
||||||
$inbox,
|
$inbox,
|
||||||
$db,
|
$db,
|
||||||
@ -109,7 +100,6 @@ const $systemWebhookDeliver: Provider = {
|
|||||||
exports: [
|
exports: [
|
||||||
$system,
|
$system,
|
||||||
$endedPollNotification,
|
$endedPollNotification,
|
||||||
$scheduledNoteDelete,
|
|
||||||
$deliver,
|
$deliver,
|
||||||
$inbox,
|
$inbox,
|
||||||
$db,
|
$db,
|
||||||
@ -123,7 +113,6 @@ export class QueueModule implements OnApplicationShutdown {
|
|||||||
constructor(
|
constructor(
|
||||||
@Inject('queue:system') public systemQueue: SystemQueue,
|
@Inject('queue:system') public systemQueue: SystemQueue,
|
||||||
@Inject('queue:endedPollNotification') public endedPollNotificationQueue: EndedPollNotificationQueue,
|
@Inject('queue:endedPollNotification') public endedPollNotificationQueue: EndedPollNotificationQueue,
|
||||||
@Inject('queue:scheduledNoteDelete') public scheduledNoteDeleteQueue: ScheduledNoteDeleteQueue,
|
|
||||||
@Inject('queue:deliver') public deliverQueue: DeliverQueue,
|
@Inject('queue:deliver') public deliverQueue: DeliverQueue,
|
||||||
@Inject('queue:inbox') public inboxQueue: InboxQueue,
|
@Inject('queue:inbox') public inboxQueue: InboxQueue,
|
||||||
@Inject('queue:db') public dbQueue: DbQueue,
|
@Inject('queue:db') public dbQueue: DbQueue,
|
||||||
@ -140,7 +129,6 @@ export class QueueModule implements OnApplicationShutdown {
|
|||||||
await Promise.all([
|
await Promise.all([
|
||||||
this.systemQueue.close(),
|
this.systemQueue.close(),
|
||||||
this.endedPollNotificationQueue.close(),
|
this.endedPollNotificationQueue.close(),
|
||||||
this.scheduledNoteDeleteQueue.close(),
|
|
||||||
this.deliverQueue.close(),
|
this.deliverQueue.close(),
|
||||||
this.inboxQueue.close(),
|
this.inboxQueue.close(),
|
||||||
this.dbQueue.close(),
|
this.dbQueue.close(),
|
||||||
|
@ -26,7 +26,6 @@ import type {
|
|||||||
DbQueue,
|
DbQueue,
|
||||||
DeliverQueue,
|
DeliverQueue,
|
||||||
EndedPollNotificationQueue,
|
EndedPollNotificationQueue,
|
||||||
ScheduledNoteDeleteQueue,
|
|
||||||
InboxQueue,
|
InboxQueue,
|
||||||
ObjectStorageQueue,
|
ObjectStorageQueue,
|
||||||
RelationshipQueue,
|
RelationshipQueue,
|
||||||
@ -46,7 +45,6 @@ export class QueueService {
|
|||||||
|
|
||||||
@Inject('queue:system') public systemQueue: SystemQueue,
|
@Inject('queue:system') public systemQueue: SystemQueue,
|
||||||
@Inject('queue:endedPollNotification') public endedPollNotificationQueue: EndedPollNotificationQueue,
|
@Inject('queue:endedPollNotification') public endedPollNotificationQueue: EndedPollNotificationQueue,
|
||||||
@Inject('queue:scheduledNoteDelete') public scheduledNoteDeleteQueue: ScheduledNoteDeleteQueue,
|
|
||||||
@Inject('queue:deliver') public deliverQueue: DeliverQueue,
|
@Inject('queue:deliver') public deliverQueue: DeliverQueue,
|
||||||
@Inject('queue:inbox') public inboxQueue: InboxQueue,
|
@Inject('queue:inbox') public inboxQueue: InboxQueue,
|
||||||
@Inject('queue:db') public dbQueue: DbQueue,
|
@Inject('queue:db') public dbQueue: DbQueue,
|
||||||
|
@ -395,8 +395,6 @@ export class NoteEntityService implements OnModuleInit {
|
|||||||
withReactionAndUserPairCache: opts.withReactionAndUserPairCache,
|
withReactionAndUserPairCache: opts.withReactionAndUserPairCache,
|
||||||
_hint_: options?._hint_,
|
_hint_: options?._hint_,
|
||||||
}) : undefined,
|
}) : undefined,
|
||||||
|
|
||||||
deleteAt: note.deleteAt?.toISOString() ?? undefined,
|
|
||||||
} : {}),
|
} : {}),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -188,11 +188,6 @@ export class MiNote {
|
|||||||
})
|
})
|
||||||
public hasPoll: boolean;
|
public hasPoll: boolean;
|
||||||
|
|
||||||
@Column('timestamp with time zone', {
|
|
||||||
nullable: true,
|
|
||||||
})
|
|
||||||
public deleteAt: Date | null;
|
|
||||||
|
|
||||||
@Index()
|
@Index()
|
||||||
@Column({
|
@Column({
|
||||||
...id(),
|
...id(),
|
||||||
|
@ -152,11 +152,6 @@ export const packedNoteSchema = {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
deleteAt: {
|
|
||||||
type: 'string',
|
|
||||||
optional: true, nullable: true,
|
|
||||||
format: 'date-time',
|
|
||||||
},
|
|
||||||
emojis: {
|
emojis: {
|
||||||
type: 'object',
|
type: 'object',
|
||||||
optional: true, nullable: false,
|
optional: true, nullable: false,
|
||||||
|
@ -10,7 +10,6 @@ import { QueueLoggerService } from './QueueLoggerService.js';
|
|||||||
import { QueueProcessorService } from './QueueProcessorService.js';
|
import { QueueProcessorService } from './QueueProcessorService.js';
|
||||||
import { DeliverProcessorService } from './processors/DeliverProcessorService.js';
|
import { DeliverProcessorService } from './processors/DeliverProcessorService.js';
|
||||||
import { EndedPollNotificationProcessorService } from './processors/EndedPollNotificationProcessorService.js';
|
import { EndedPollNotificationProcessorService } from './processors/EndedPollNotificationProcessorService.js';
|
||||||
import { ScheduledNoteDeleteProcessorService } from './processors/ScheduledNoteDeleteProsessorService.js';
|
|
||||||
import { InboxProcessorService } from './processors/InboxProcessorService.js';
|
import { InboxProcessorService } from './processors/InboxProcessorService.js';
|
||||||
import { UserWebhookDeliverProcessorService } from './processors/UserWebhookDeliverProcessorService.js';
|
import { UserWebhookDeliverProcessorService } from './processors/UserWebhookDeliverProcessorService.js';
|
||||||
import { SystemWebhookDeliverProcessorService } from './processors/SystemWebhookDeliverProcessorService.js';
|
import { SystemWebhookDeliverProcessorService } from './processors/SystemWebhookDeliverProcessorService.js';
|
||||||
@ -80,7 +79,6 @@ import { RelationshipProcessorService } from './processors/RelationshipProcessor
|
|||||||
UserWebhookDeliverProcessorService,
|
UserWebhookDeliverProcessorService,
|
||||||
SystemWebhookDeliverProcessorService,
|
SystemWebhookDeliverProcessorService,
|
||||||
EndedPollNotificationProcessorService,
|
EndedPollNotificationProcessorService,
|
||||||
ScheduledNoteDeleteProcessorService,
|
|
||||||
DeliverProcessorService,
|
DeliverProcessorService,
|
||||||
InboxProcessorService,
|
InboxProcessorService,
|
||||||
AggregateRetentionProcessorService,
|
AggregateRetentionProcessorService,
|
||||||
|
@ -13,7 +13,6 @@ import { bindThis } from '@/decorators.js';
|
|||||||
import { UserWebhookDeliverProcessorService } from './processors/UserWebhookDeliverProcessorService.js';
|
import { UserWebhookDeliverProcessorService } from './processors/UserWebhookDeliverProcessorService.js';
|
||||||
import { SystemWebhookDeliverProcessorService } from './processors/SystemWebhookDeliverProcessorService.js';
|
import { SystemWebhookDeliverProcessorService } from './processors/SystemWebhookDeliverProcessorService.js';
|
||||||
import { EndedPollNotificationProcessorService } from './processors/EndedPollNotificationProcessorService.js';
|
import { EndedPollNotificationProcessorService } from './processors/EndedPollNotificationProcessorService.js';
|
||||||
import { ScheduledNoteDeleteProcessorService } from './processors/ScheduledNoteDeleteProsessorService.js';
|
|
||||||
import { DeliverProcessorService } from './processors/DeliverProcessorService.js';
|
import { DeliverProcessorService } from './processors/DeliverProcessorService.js';
|
||||||
import { InboxProcessorService } from './processors/InboxProcessorService.js';
|
import { InboxProcessorService } from './processors/InboxProcessorService.js';
|
||||||
import { DeleteDriveFilesProcessorService } from './processors/DeleteDriveFilesProcessorService.js';
|
import { DeleteDriveFilesProcessorService } from './processors/DeleteDriveFilesProcessorService.js';
|
||||||
@ -85,7 +84,6 @@ export class QueueProcessorService implements OnApplicationShutdown {
|
|||||||
private relationshipQueueWorker: Bull.Worker;
|
private relationshipQueueWorker: Bull.Worker;
|
||||||
private objectStorageQueueWorker: Bull.Worker;
|
private objectStorageQueueWorker: Bull.Worker;
|
||||||
private endedPollNotificationQueueWorker: Bull.Worker;
|
private endedPollNotificationQueueWorker: Bull.Worker;
|
||||||
private scheduledNoteDeleteQueueWorker: Bull.Worker;
|
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
@Inject(DI.config)
|
@Inject(DI.config)
|
||||||
@ -95,7 +93,6 @@ export class QueueProcessorService implements OnApplicationShutdown {
|
|||||||
private userWebhookDeliverProcessorService: UserWebhookDeliverProcessorService,
|
private userWebhookDeliverProcessorService: UserWebhookDeliverProcessorService,
|
||||||
private systemWebhookDeliverProcessorService: SystemWebhookDeliverProcessorService,
|
private systemWebhookDeliverProcessorService: SystemWebhookDeliverProcessorService,
|
||||||
private endedPollNotificationProcessorService: EndedPollNotificationProcessorService,
|
private endedPollNotificationProcessorService: EndedPollNotificationProcessorService,
|
||||||
private scheduledNoteDeleteProcessorService: ScheduledNoteDeleteProcessorService,
|
|
||||||
private deliverProcessorService: DeliverProcessorService,
|
private deliverProcessorService: DeliverProcessorService,
|
||||||
private inboxProcessorService: InboxProcessorService,
|
private inboxProcessorService: InboxProcessorService,
|
||||||
private deleteDriveFilesProcessorService: DeleteDriveFilesProcessorService,
|
private deleteDriveFilesProcessorService: DeleteDriveFilesProcessorService,
|
||||||
@ -516,12 +513,6 @@ export class QueueProcessorService implements OnApplicationShutdown {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
//#endregion
|
//#endregion
|
||||||
|
|
||||||
//#region scheduled note delete
|
|
||||||
this.scheduledNoteDeleteQueueWorker = new Bull.Worker(QUEUE.SCHEDULED_NOTE_DELETE, (job) => this.scheduledNoteDeleteProcessorService.process(job), {
|
|
||||||
...baseQueueOptions(this.config, QUEUE.SCHEDULED_NOTE_DELETE),
|
|
||||||
autorun: false,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@bindThis
|
@bindThis
|
||||||
@ -536,7 +527,6 @@ export class QueueProcessorService implements OnApplicationShutdown {
|
|||||||
this.relationshipQueueWorker.run(),
|
this.relationshipQueueWorker.run(),
|
||||||
this.objectStorageQueueWorker.run(),
|
this.objectStorageQueueWorker.run(),
|
||||||
this.endedPollNotificationQueueWorker.run(),
|
this.endedPollNotificationQueueWorker.run(),
|
||||||
this.scheduledNoteDeleteQueueWorker.run(),
|
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -552,7 +542,6 @@ export class QueueProcessorService implements OnApplicationShutdown {
|
|||||||
this.relationshipQueueWorker.close(),
|
this.relationshipQueueWorker.close(),
|
||||||
this.objectStorageQueueWorker.close(),
|
this.objectStorageQueueWorker.close(),
|
||||||
this.endedPollNotificationQueueWorker.close(),
|
this.endedPollNotificationQueueWorker.close(),
|
||||||
this.scheduledNoteDeleteQueueWorker.close(),
|
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -11,7 +11,6 @@ export const QUEUE = {
|
|||||||
INBOX: 'inbox',
|
INBOX: 'inbox',
|
||||||
SYSTEM: 'system',
|
SYSTEM: 'system',
|
||||||
ENDED_POLL_NOTIFICATION: 'endedPollNotification',
|
ENDED_POLL_NOTIFICATION: 'endedPollNotification',
|
||||||
SCHEDULED_NOTE_DELETE: 'scheduledNoteDelete',
|
|
||||||
DB: 'db',
|
DB: 'db',
|
||||||
RELATIONSHIP: 'relationship',
|
RELATIONSHIP: 'relationship',
|
||||||
OBJECT_STORAGE: 'objectStorage',
|
OBJECT_STORAGE: 'objectStorage',
|
||||||
|
@ -1,48 +0,0 @@
|
|||||||
/*
|
|
||||||
* SPDX-FileCopyrightText: syuilo and misskey-project
|
|
||||||
* SPDX-License-Identifier: AGPL-3.0-only
|
|
||||||
*/
|
|
||||||
|
|
||||||
import { Inject, Injectable } from '@nestjs/common';
|
|
||||||
import { DI } from '@/di-symbols.js';
|
|
||||||
import type { NotesRepository, UsersRepository } from '@/models/_.js';
|
|
||||||
import type Logger from '@/logger.js';
|
|
||||||
import { bindThis } from '@/decorators.js';
|
|
||||||
import { NoteDeleteService } from '@/core/NoteDeleteService.js';
|
|
||||||
import { QueueLoggerService } from '../QueueLoggerService.js';
|
|
||||||
import type * as Bull from 'bullmq';
|
|
||||||
import type { ScheduledNoteDeleteJobData } from '../types.js';
|
|
||||||
|
|
||||||
@Injectable()
|
|
||||||
export class ScheduledNoteDeleteProcessorService {
|
|
||||||
private logger: Logger;
|
|
||||||
|
|
||||||
constructor(
|
|
||||||
@Inject(DI.notesRepository)
|
|
||||||
private notesRepository: NotesRepository,
|
|
||||||
|
|
||||||
@Inject(DI.usersRepository)
|
|
||||||
private usersRepository: UsersRepository,
|
|
||||||
|
|
||||||
private noteDeleteService: NoteDeleteService,
|
|
||||||
private queueLoggerService: QueueLoggerService,
|
|
||||||
) {
|
|
||||||
this.logger = this.queueLoggerService.logger.createSubLogger('scheduled-note-delete');
|
|
||||||
}
|
|
||||||
|
|
||||||
@bindThis
|
|
||||||
public async process(job: Bull.Job<ScheduledNoteDeleteJobData>): Promise<void> {
|
|
||||||
const note = await this.notesRepository.findOneBy({ id: job.data.noteId });
|
|
||||||
if (note == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const user = await this.usersRepository.findOneBy({ id: note.userId });
|
|
||||||
if (user == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
await this.noteDeleteService.delete(user, note);
|
|
||||||
this.logger.info(`Deleted note ${note.id}`);
|
|
||||||
}
|
|
||||||
}
|
|
@ -131,10 +131,6 @@ export type EndedPollNotificationJobData = {
|
|||||||
noteId: MiNote['id'];
|
noteId: MiNote['id'];
|
||||||
};
|
};
|
||||||
|
|
||||||
export type ScheduledNoteDeleteJobData = {
|
|
||||||
noteId: MiNote['id'];
|
|
||||||
};
|
|
||||||
|
|
||||||
export type SystemWebhookDeliverJobData = {
|
export type SystemWebhookDeliverJobData = {
|
||||||
type: string;
|
type: string;
|
||||||
content: unknown;
|
content: unknown;
|
||||||
|
@ -104,18 +104,6 @@ export const meta = {
|
|||||||
id: '04da457d-b083-4055-9082-955525eda5a5',
|
id: '04da457d-b083-4055-9082-955525eda5a5',
|
||||||
},
|
},
|
||||||
|
|
||||||
cannotScheduleDeleteEarlierThanNow: {
|
|
||||||
message: 'Scheduled delete time is earlier than now.',
|
|
||||||
code: 'CANNOT_SCHEDULE_DELETE_EARLIER_THAN_NOW',
|
|
||||||
id: '05655b05-5a09-47c3-af56-de0c0900791a',
|
|
||||||
},
|
|
||||||
|
|
||||||
cannotScheduleDeleteLaterThanOneYear: {
|
|
||||||
message: 'Scheduled delete time is later than one year.',
|
|
||||||
code: 'CANNOT_SCHEDULE_DELETE_LATER_THAN_ONE_YEAR',
|
|
||||||
id: 'b02b5edb-2741-4841-b692-d9893f1e6515',
|
|
||||||
},
|
|
||||||
|
|
||||||
noSuchChannel: {
|
noSuchChannel: {
|
||||||
message: 'No such channel.',
|
message: 'No such channel.',
|
||||||
code: 'NO_SUCH_CHANNEL',
|
code: 'NO_SUCH_CHANNEL',
|
||||||
@ -209,14 +197,6 @@ export const paramDef = {
|
|||||||
},
|
},
|
||||||
required: ['choices'],
|
required: ['choices'],
|
||||||
},
|
},
|
||||||
scheduledDelete: {
|
|
||||||
type: 'object',
|
|
||||||
nullable: true,
|
|
||||||
properties: {
|
|
||||||
deleteAt: { type: 'integer', nullable: true },
|
|
||||||
deleteAfter: { type: 'integer', nullable: true, minimum: 1 },
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
// (re)note with text, files and poll are optional
|
// (re)note with text, files and poll are optional
|
||||||
if: {
|
if: {
|
||||||
@ -385,21 +365,6 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if (ps.scheduledDelete) {
|
|
||||||
if (typeof ps.scheduledDelete.deleteAt === 'number') {
|
|
||||||
if (ps.scheduledDelete.deleteAt < Date.now()) {
|
|
||||||
throw new ApiError(meta.errors.cannotScheduleDeleteEarlierThanNow);
|
|
||||||
}
|
|
||||||
} else if (typeof ps.scheduledDelete.deleteAfter === 'number') {
|
|
||||||
ps.scheduledDelete.deleteAt = Date.now() + ps.scheduledDelete.deleteAfter;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ps.scheduledDelete.deleteAt && ps.scheduledDelete.deleteAt > Date.now() + ms('1year')) {
|
|
||||||
throw new ApiError(meta.errors.cannotScheduleDeleteLaterThanOneYear);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let channel: MiChannel | null = null;
|
let channel: MiChannel | null = null;
|
||||||
if (ps.channelId != null) {
|
if (ps.channelId != null) {
|
||||||
channel = await this.channelsRepository.findOneBy({ id: ps.channelId, isArchived: false });
|
channel = await this.channelsRepository.findOneBy({ id: ps.channelId, isArchived: false });
|
||||||
@ -431,7 +396,6 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
|||||||
apMentions: ps.noExtractMentions ? [] : undefined,
|
apMentions: ps.noExtractMentions ? [] : undefined,
|
||||||
apHashtags: ps.noExtractHashtags ? [] : undefined,
|
apHashtags: ps.noExtractHashtags ? [] : undefined,
|
||||||
apEmojis: ps.noExtractEmojis ? [] : undefined,
|
apEmojis: ps.noExtractEmojis ? [] : undefined,
|
||||||
deleteAt: ps.scheduledDelete?.deleteAt ? new Date(ps.scheduledDelete.deleteAt) : null,
|
|
||||||
});
|
});
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
@ -29,7 +29,6 @@ import type {
|
|||||||
DbQueue,
|
DbQueue,
|
||||||
DeliverQueue,
|
DeliverQueue,
|
||||||
EndedPollNotificationQueue,
|
EndedPollNotificationQueue,
|
||||||
ScheduledNoteDeleteQueue,
|
|
||||||
InboxQueue,
|
InboxQueue,
|
||||||
ObjectStorageQueue,
|
ObjectStorageQueue,
|
||||||
SystemQueue,
|
SystemQueue,
|
||||||
@ -117,7 +116,6 @@ export class ClientServerService {
|
|||||||
|
|
||||||
@Inject('queue:system') public systemQueue: SystemQueue,
|
@Inject('queue:system') public systemQueue: SystemQueue,
|
||||||
@Inject('queue:endedPollNotification') public endedPollNotificationQueue: EndedPollNotificationQueue,
|
@Inject('queue:endedPollNotification') public endedPollNotificationQueue: EndedPollNotificationQueue,
|
||||||
@Inject('queue:scheduledNoteDelete') public scheduledNoteDeleteQueue: ScheduledNoteDeleteQueue,
|
|
||||||
@Inject('queue:deliver') public deliverQueue: DeliverQueue,
|
@Inject('queue:deliver') public deliverQueue: DeliverQueue,
|
||||||
@Inject('queue:inbox') public inboxQueue: InboxQueue,
|
@Inject('queue:inbox') public inboxQueue: InboxQueue,
|
||||||
@Inject('queue:db') public dbQueue: DbQueue,
|
@Inject('queue:db') public dbQueue: DbQueue,
|
||||||
@ -250,7 +248,6 @@ export class ClientServerService {
|
|||||||
queues: [
|
queues: [
|
||||||
this.systemQueue,
|
this.systemQueue,
|
||||||
this.endedPollNotificationQueue,
|
this.endedPollNotificationQueue,
|
||||||
this.scheduledNoteDeleteQueue,
|
|
||||||
this.deliverQueue,
|
this.deliverQueue,
|
||||||
this.inboxQueue,
|
this.inboxQueue,
|
||||||
this.dbQueue,
|
this.dbQueue,
|
||||||
|
@ -1,249 +0,0 @@
|
|||||||
<!--
|
|
||||||
SPDX-FileCopyrightText: syuilo and misskey-project
|
|
||||||
SPDX-License-Identifier: AGPL-3.0-only
|
|
||||||
-->
|
|
||||||
|
|
||||||
<template>
|
|
||||||
<div :class="[$style.root, { [$style.padding]: !afterOnly }]">
|
|
||||||
<div v-if="!afterOnly" :class="[$style.label, { [$style.withAccent]: !showDetail }]" @click="showDetail = !showDetail"><i class="ti" :class="showDetail ? 'ti-chevron-up' : 'ti-chevron-down'"></i> {{ summaryText }}</div>
|
|
||||||
<MkInfo v-if="!isValid" warn>{{ i18n.ts.cannotScheduleLaterThanOneYear }}</MkInfo>
|
|
||||||
<section v-if="afterOnly || showDetail">
|
|
||||||
<div>
|
|
||||||
<MkSelect v-if="!afterOnly" v-model="expiration" small>
|
|
||||||
<template #label>{{ i18n.ts._poll.expiration }}</template>
|
|
||||||
<option value="at">{{ i18n.ts._poll.at }}</option>
|
|
||||||
<option value="after">{{ i18n.ts._poll.after }}</option>
|
|
||||||
</MkSelect>
|
|
||||||
<section v-if="expiration === 'at'">
|
|
||||||
<MkInput v-model="atDate" small type="date" class="input">
|
|
||||||
<template #label>{{ i18n.ts._poll.deadlineDate }}</template>
|
|
||||||
</MkInput>
|
|
||||||
<MkInput v-model="atTime" small type="time" class="input">
|
|
||||||
<template #label>{{ i18n.ts._poll.deadlineTime }}</template>
|
|
||||||
</MkInput>
|
|
||||||
</section>
|
|
||||||
<section v-else-if="expiration === 'after'">
|
|
||||||
<MkInput v-model="after" small type="number" class="input">
|
|
||||||
<template #label>{{ i18n.ts._poll.duration }}</template>
|
|
||||||
</MkInput>
|
|
||||||
<MkSelect v-model="unit" small>
|
|
||||||
<option value="second">{{ i18n.ts._time.second }}</option>
|
|
||||||
<option value="minute">{{ i18n.ts._time.minute }}</option>
|
|
||||||
<option value="hour">{{ i18n.ts._time.hour }}</option>
|
|
||||||
<option value="day">{{ i18n.ts._time.day }}</option>
|
|
||||||
</MkSelect>
|
|
||||||
</section>
|
|
||||||
</div>
|
|
||||||
</section>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script lang="ts" setup>
|
|
||||||
import { computed, ref, watch } from 'vue';
|
|
||||||
import MkInput from './MkInput.vue';
|
|
||||||
import MkSelect from './MkSelect.vue';
|
|
||||||
import MkInfo from './MkInfo.vue';
|
|
||||||
import { formatDateTimeString } from '@/scripts/format-time-string.js';
|
|
||||||
import { addTime } from '@/scripts/time.js';
|
|
||||||
import { defaultStore } from '@/store.js';
|
|
||||||
import { i18n } from '@/i18n.js';
|
|
||||||
|
|
||||||
export type DeleteScheduleEditorModelValue = {
|
|
||||||
deleteAt: number | null;
|
|
||||||
deleteAfter: number | null;
|
|
||||||
isValid: boolean;
|
|
||||||
};
|
|
||||||
|
|
||||||
const props = defineProps<{
|
|
||||||
modelValue: DeleteScheduleEditorModelValue;
|
|
||||||
afterOnly?: boolean;
|
|
||||||
}>();
|
|
||||||
const emit = defineEmits<{
|
|
||||||
(ev: 'update:modelValue', v: DeleteScheduleEditorModelValue): void;
|
|
||||||
}>();
|
|
||||||
|
|
||||||
const expiration = ref<'at' | 'after'>('after');
|
|
||||||
const atDate = ref(formatDateTimeString(addTime(new Date(), 1, 'day'), 'yyyy-MM-dd'));
|
|
||||||
const atTime = ref('00:00');
|
|
||||||
const after = ref(0);
|
|
||||||
const unit = ref<'second' | 'minute' | 'hour' | 'day'>('second');
|
|
||||||
const isValid = ref(true);
|
|
||||||
|
|
||||||
const showDetail = ref(!defaultStore.state.defaultScheduledNoteDelete);
|
|
||||||
const summaryText = computed(() => {
|
|
||||||
if (showDetail.value) {
|
|
||||||
return i18n.ts.scheduledNoteDelete;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (expiration.value === 'at') {
|
|
||||||
return `${i18n.ts.scheduledNoteDeleteEnabled} (${formatDateTimeString(new Date(calcAt()), 'yyyy/MM/dd HH:mm')})`;
|
|
||||||
} else {
|
|
||||||
const time = unit.value === 'second' ? i18n.tsx._timeIn.seconds({ n: (after.value).toString() })
|
|
||||||
: unit.value === 'minute' ? i18n.tsx._timeIn.minutes({ n: (after.value).toString() })
|
|
||||||
: unit.value === 'hour' ? i18n.tsx._timeIn.hours({ n: (after.value).toString() })
|
|
||||||
: i18n.tsx._timeIn.days({ n: (after.value).toString() });
|
|
||||||
|
|
||||||
return `${i18n.ts.scheduledNoteDeleteEnabled} (${time})`;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
const beautifyAfter = (base: number) => {
|
|
||||||
let time = base;
|
|
||||||
|
|
||||||
if (time % 60 === 0) {
|
|
||||||
unit.value = 'minute';
|
|
||||||
time /= 60;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (time % 60 === 0) {
|
|
||||||
unit.value = 'hour';
|
|
||||||
time /= 60;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (time % 24 === 0) {
|
|
||||||
unit.value = 'day';
|
|
||||||
time /= 24;
|
|
||||||
}
|
|
||||||
|
|
||||||
after.value = time;
|
|
||||||
};
|
|
||||||
|
|
||||||
beautifyAfter(defaultStore.state.defaultScheduledNoteDeleteTime / 1000);
|
|
||||||
|
|
||||||
if (props.modelValue.deleteAt) {
|
|
||||||
expiration.value = 'at';
|
|
||||||
const deleteAt = new Date(props.modelValue.deleteAt);
|
|
||||||
atDate.value = formatDateTimeString(deleteAt, 'yyyy-MM-dd');
|
|
||||||
atTime.value = formatDateTimeString(deleteAt, 'HH:mm');
|
|
||||||
} else if (typeof props.modelValue.deleteAfter === 'number') {
|
|
||||||
expiration.value = 'after';
|
|
||||||
beautifyAfter(props.modelValue.deleteAfter / 1000);
|
|
||||||
}
|
|
||||||
|
|
||||||
const calcAt = () => {
|
|
||||||
return new Date(`${atDate.value} ${atTime.value}`).getTime();
|
|
||||||
};
|
|
||||||
|
|
||||||
const calcAfter = () => {
|
|
||||||
let base = parseInt(after.value.toString());
|
|
||||||
switch (unit.value) {
|
|
||||||
// @ts-expect-error fallthrough
|
|
||||||
case 'day': base *= 24;
|
|
||||||
// @ts-expect-error fallthrough
|
|
||||||
case 'hour': base *= 60;
|
|
||||||
// @ts-expect-error fallthrough
|
|
||||||
case 'minute': base *= 60;
|
|
||||||
// eslint-disable-next-line no-fallthrough
|
|
||||||
case 'second': return base *= 1000;
|
|
||||||
default: return null;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const isValidTime = () => {
|
|
||||||
if (expiration.value === 'at') {
|
|
||||||
return calcAt() < Date.now() + (1000 * 60 * 60 * 24 * 365);
|
|
||||||
} else {
|
|
||||||
const afterMs = calcAfter();
|
|
||||||
if (afterMs === null) return false;
|
|
||||||
return afterMs < 1000 * 60 * 60 * 24 * 365;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
isValid.value = isValidTime();
|
|
||||||
|
|
||||||
watch([expiration, atDate, atTime, after, unit, isValid], () => {
|
|
||||||
const isValidTimeValue = isValidTime();
|
|
||||||
isValid.value = isValidTimeValue;
|
|
||||||
|
|
||||||
emit('update:modelValue', {
|
|
||||||
deleteAt: expiration.value === 'at' ? calcAt() : null,
|
|
||||||
deleteAfter: expiration.value === 'after' ? calcAfter() : null,
|
|
||||||
isValid: isValidTimeValue,
|
|
||||||
});
|
|
||||||
}, {
|
|
||||||
deep: true,
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style lang="scss" module>
|
|
||||||
.root {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
gap: 8px;
|
|
||||||
padding: 8px 0px;
|
|
||||||
|
|
||||||
>span {
|
|
||||||
opacity: 0.7;
|
|
||||||
}
|
|
||||||
|
|
||||||
>ul {
|
|
||||||
display: block;
|
|
||||||
margin: 0;
|
|
||||||
padding: 0;
|
|
||||||
list-style: none;
|
|
||||||
|
|
||||||
>li {
|
|
||||||
display: flex;
|
|
||||||
margin: 8px 0;
|
|
||||||
padding: 0;
|
|
||||||
width: 100%;
|
|
||||||
|
|
||||||
>.input {
|
|
||||||
flex: 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
>button {
|
|
||||||
width: 32px;
|
|
||||||
padding: 4px 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
>section {
|
|
||||||
>div {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: row;
|
|
||||||
flex-wrap: wrap;
|
|
||||||
gap: 12px;
|
|
||||||
|
|
||||||
&:last-child {
|
|
||||||
flex: 1 0 auto;
|
|
||||||
|
|
||||||
>div {
|
|
||||||
flex-grow: 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
>section {
|
|
||||||
// MAGIC: Prevent div above from growing unless wrapped to its own line
|
|
||||||
flex-grow: 9999;
|
|
||||||
align-items: end;
|
|
||||||
display: flex;
|
|
||||||
gap: 4px;
|
|
||||||
|
|
||||||
>.input {
|
|
||||||
flex: 1 1 auto;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.padding {
|
|
||||||
padding: 8px 24px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.label {
|
|
||||||
font-size: 0.85em;
|
|
||||||
padding: 0 0 8px 0;
|
|
||||||
user-select: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.withAccent {
|
|
||||||
color: var(--MI_THEME-accent);
|
|
||||||
}
|
|
||||||
|
|
||||||
.chevronOpening {
|
|
||||||
transform: rotateX(180deg);
|
|
||||||
}
|
|
||||||
</style>
|
|
@ -116,7 +116,6 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||||||
<MkA :to="notePage(appearNote)">
|
<MkA :to="notePage(appearNote)">
|
||||||
<MkTime :time="appearNote.createdAt" mode="detail" colored/>
|
<MkTime :time="appearNote.createdAt" mode="detail" colored/>
|
||||||
</MkA>
|
</MkA>
|
||||||
<span v-if="appearNote.deleteAt"><i class="ti ti-bomb"></i>{{ i18n.ts.scheduledNoteDelete }}: <MkTime :time="appearNote.deleteAt" mode="detail" colored/></span>
|
|
||||||
</div>
|
</div>
|
||||||
<MkReactionsViewer v-if="appearNote.reactionAcceptance !== 'likeOnly'" ref="reactionsViewer" :note="appearNote"/>
|
<MkReactionsViewer v-if="appearNote.reactionAcceptance !== 'likeOnly'" ref="reactionsViewer" :note="appearNote"/>
|
||||||
<button class="_button" :class="$style.noteFooterButton" @click="reply()">
|
<button class="_button" :class="$style.noteFooterButton" @click="reply()">
|
||||||
@ -1027,9 +1026,6 @@ function animatedMFM() {
|
|||||||
margin: 16px 0;
|
margin: 16px 0;
|
||||||
opacity: 0.7;
|
opacity: 0.7;
|
||||||
font-size: 0.9em;
|
font-size: 0.9em;
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
gap: 6px;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.noteFooterButton {
|
.noteFooterButton {
|
||||||
|
@ -31,7 +31,6 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||||||
<span v-if="note.updatedAt" ref="menuVersionsButton" style="margin-left: 0.5em; cursor: pointer;" title="Edited" @mousedown="menuVersions()"><i class="ph-pencil-simple ph-bold ph-lg"></i></span>
|
<span v-if="note.updatedAt" ref="menuVersionsButton" style="margin-left: 0.5em; cursor: pointer;" title="Edited" @mousedown="menuVersions()"><i class="ph-pencil-simple ph-bold ph-lg"></i></span>
|
||||||
<span v-if="note.localOnly" style="margin-left: 0.5em;" :title="i18n.ts._visibility['disableFederation']"><i class="ti ti-rocket-off"></i></span>
|
<span v-if="note.localOnly" style="margin-left: 0.5em;" :title="i18n.ts._visibility['disableFederation']"><i class="ti ti-rocket-off"></i></span>
|
||||||
<span v-if="note.channel" style="margin-left: 0.5em;" :title="note.channel.name"><i class="ti ti-device-tv"></i></span>
|
<span v-if="note.channel" style="margin-left: 0.5em;" :title="note.channel.name"><i class="ti ti-device-tv"></i></span>
|
||||||
<span v-if="note.deleteAt" style="margin-left: 0.5em;" :title="i18n.tsx.noteDeletationAt({ time: dateTimeFormat.format(new Date(note.deleteAt)) })"><i class="ti ti-bomb"></i></span>
|
|
||||||
</div>
|
</div>
|
||||||
</header>
|
</header>
|
||||||
</template>
|
</template>
|
||||||
@ -42,7 +41,6 @@ import * as Misskey from 'misskey-js';
|
|||||||
import { i18n } from '@/i18n.js';
|
import { i18n } from '@/i18n.js';
|
||||||
import { notePage } from '@/filters/note.js';
|
import { notePage } from '@/filters/note.js';
|
||||||
import { userPage } from '@/filters/user.js';
|
import { userPage } from '@/filters/user.js';
|
||||||
import { dateTimeFormat } from '@/scripts/intl-const.js';
|
|
||||||
import { getNoteVersionsMenu } from '@/scripts/get-note-versions-menu.js';
|
import { getNoteVersionsMenu } from '@/scripts/get-note-versions-menu.js';
|
||||||
import { popupMenu } from '@/os.js';
|
import { popupMenu } from '@/os.js';
|
||||||
|
|
||||||
|
@ -74,7 +74,6 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||||||
<input v-show="withHashtags" ref="hashtagsInputEl" v-model="hashtags" :class="$style.hashtags" :placeholder="i18n.ts.hashtags" list="hashtags">
|
<input v-show="withHashtags" ref="hashtagsInputEl" v-model="hashtags" :class="$style.hashtags" :placeholder="i18n.ts.hashtags" list="hashtags">
|
||||||
<XPostFormAttaches v-model="files" @detach="detachFile" @changeSensitive="updateFileSensitive" @changeName="updateFileName" @replaceFile="replaceFile"/>
|
<XPostFormAttaches v-model="files" @detach="detachFile" @changeSensitive="updateFileSensitive" @changeName="updateFileName" @replaceFile="replaceFile"/>
|
||||||
<MkPollEditor v-if="poll" v-model="poll" @destroyed="poll = null"/>
|
<MkPollEditor v-if="poll" v-model="poll" @destroyed="poll = null"/>
|
||||||
<MkDeleteScheduleEditor v-if="scheduledNoteDelete" v-model="scheduledNoteDelete" @destroyed="scheduledNoteDelete = null"/>
|
|
||||||
<MkNotePreview v-if="showPreview" :class="$style.preview" :text="text" :files="files" :poll="poll ?? undefined" :useCw="useCw" :cw="cw" :user="postAccount ?? $i"/>
|
<MkNotePreview v-if="showPreview" :class="$style.preview" :text="text" :files="files" :poll="poll ?? undefined" :useCw="useCw" :cw="cw" :user="postAccount ?? $i"/>
|
||||||
<div v-if="showingOptions" style="padding: 8px 16px;">
|
<div v-if="showingOptions" style="padding: 8px 16px;">
|
||||||
</div>
|
</div>
|
||||||
@ -82,7 +81,6 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||||||
<div :class="$style.footerLeft">
|
<div :class="$style.footerLeft">
|
||||||
<button v-tooltip="i18n.ts.attachFile" class="_button" :class="$style.footerButton" @click="chooseFileFrom"><i class="ti ti-photo-plus"></i></button>
|
<button v-tooltip="i18n.ts.attachFile" class="_button" :class="$style.footerButton" @click="chooseFileFrom"><i class="ti ti-photo-plus"></i></button>
|
||||||
<button v-tooltip="i18n.ts.poll" class="_button" :class="[$style.footerButton, { [$style.footerButtonActive]: poll }]" @click="togglePoll"><i class="ti ti-chart-arrows"></i></button>
|
<button v-tooltip="i18n.ts.poll" class="_button" :class="[$style.footerButton, { [$style.footerButtonActive]: poll }]" @click="togglePoll"><i class="ti ti-chart-arrows"></i></button>
|
||||||
<button v-tooltip="i18n.ts.scheduledNoteDelete" class="_button" :class="[$style.footerButton, { [$style.footerButtonActive]: scheduledNoteDelete }]" @click="toggleScheduledNoteDelete"><i class="ti ti-bomb"></i></button>
|
|
||||||
<button v-tooltip="i18n.ts.useCw" class="_button" :class="[$style.footerButton, { [$style.footerButtonActive]: useCw }]" @click="useCw = !useCw"><i class="ti ti-eye-off"></i></button>
|
<button v-tooltip="i18n.ts.useCw" class="_button" :class="[$style.footerButton, { [$style.footerButtonActive]: useCw }]" @click="useCw = !useCw"><i class="ti ti-eye-off"></i></button>
|
||||||
<button v-tooltip="i18n.ts.mention" class="_button" :class="$style.footerButton" @click="insertMention"><i class="ti ti-at"></i></button>
|
<button v-tooltip="i18n.ts.mention" class="_button" :class="$style.footerButton" @click="insertMention"><i class="ti ti-at"></i></button>
|
||||||
<button v-tooltip="i18n.ts.hashtags" class="_button" :class="[$style.footerButton, { [$style.footerButtonActive]: withHashtags }]" @click="withHashtags = !withHashtags"><i class="ti ti-hash"></i></button>
|
<button v-tooltip="i18n.ts.hashtags" class="_button" :class="[$style.footerButton, { [$style.footerButtonActive]: withHashtags }]" @click="withHashtags = !withHashtags"><i class="ti ti-hash"></i></button>
|
||||||
@ -112,7 +110,6 @@ import MkNoteSimple from '@/components/MkNoteSimple.vue';
|
|||||||
import MkNotePreview from '@/components/MkNotePreview.vue';
|
import MkNotePreview from '@/components/MkNotePreview.vue';
|
||||||
import XPostFormAttaches from '@/components/MkPostFormAttaches.vue';
|
import XPostFormAttaches from '@/components/MkPostFormAttaches.vue';
|
||||||
import MkPollEditor, { type PollEditorModelValue } from '@/components/MkPollEditor.vue';
|
import MkPollEditor, { type PollEditorModelValue } from '@/components/MkPollEditor.vue';
|
||||||
import MkDeleteScheduleEditor, { type DeleteScheduleEditorModelValue } from '@/components/MkDeleteScheduleEditor.vue';
|
|
||||||
import { host, url } from '@/config.js';
|
import { host, url } from '@/config.js';
|
||||||
import { erase, unique } from '@/scripts/array.js';
|
import { erase, unique } from '@/scripts/array.js';
|
||||||
import { extractMentions } from '@/scripts/extract-mentions.js';
|
import { extractMentions } from '@/scripts/extract-mentions.js';
|
||||||
@ -185,7 +182,6 @@ const posted = ref(false);
|
|||||||
const text = ref(props.initialText ?? '');
|
const text = ref(props.initialText ?? '');
|
||||||
const files = ref(props.initialFiles ?? []);
|
const files = ref(props.initialFiles ?? []);
|
||||||
const poll = ref<PollEditorModelValue | null>(null);
|
const poll = ref<PollEditorModelValue | null>(null);
|
||||||
const scheduledNoteDelete = ref<DeleteScheduleEditorModelValue | null>(null);
|
|
||||||
const useCw = ref<boolean>(!!props.initialCw);
|
const useCw = ref<boolean>(!!props.initialCw);
|
||||||
const showPreview = ref(defaultStore.state.showPreview);
|
const showPreview = ref(defaultStore.state.showPreview);
|
||||||
watch(showPreview, () => defaultStore.set('showPreview', showPreview.value));
|
watch(showPreview, () => defaultStore.set('showPreview', showPreview.value));
|
||||||
@ -370,7 +366,6 @@ function watchForDraft() {
|
|||||||
watch(useCw, () => saveDraft());
|
watch(useCw, () => saveDraft());
|
||||||
watch(cw, () => saveDraft());
|
watch(cw, () => saveDraft());
|
||||||
watch(poll, () => saveDraft());
|
watch(poll, () => saveDraft());
|
||||||
watch(scheduledNoteDelete, () => saveDraft());
|
|
||||||
watch(files, () => saveDraft(), { deep: true });
|
watch(files, () => saveDraft(), { deep: true });
|
||||||
watch(visibility, () => saveDraft());
|
watch(visibility, () => saveDraft());
|
||||||
watch(localOnly, () => saveDraft());
|
watch(localOnly, () => saveDraft());
|
||||||
@ -426,17 +421,6 @@ function togglePoll() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function toggleScheduledNoteDelete() {
|
|
||||||
if (scheduledNoteDelete.value) {
|
|
||||||
scheduledNoteDelete.value = null;
|
|
||||||
} else {
|
|
||||||
scheduledNoteDelete.value = {
|
|
||||||
deleteAt: null,
|
|
||||||
deleteAfter: null,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function addTag(tag: string) {
|
function addTag(tag: string) {
|
||||||
insertTextAtCursor(textareaEl.value, ` #${tag} `);
|
insertTextAtCursor(textareaEl.value, ` #${tag} `);
|
||||||
}
|
}
|
||||||
@ -731,7 +715,6 @@ function saveDraft() {
|
|||||||
localOnly: localOnly.value,
|
localOnly: localOnly.value,
|
||||||
files: files.value,
|
files: files.value,
|
||||||
poll: poll.value,
|
poll: poll.value,
|
||||||
scheduledNoteDelete: scheduledNoteDelete.value,
|
|
||||||
visibleUserIds: visibility.value === 'specified' ? visibleUsers.value.map(x => x.id) : undefined,
|
visibleUserIds: visibility.value === 'specified' ? visibleUsers.value.map(x => x.id) : undefined,
|
||||||
quoteId: quoteId.value,
|
quoteId: quoteId.value,
|
||||||
reactionAcceptance: reactionAcceptance.value,
|
reactionAcceptance: reactionAcceptance.value,
|
||||||
@ -811,7 +794,6 @@ async function post(ev?: MouseEvent) {
|
|||||||
renoteId: props.renote ? props.renote.id : quoteId.value ? quoteId.value : undefined,
|
renoteId: props.renote ? props.renote.id : quoteId.value ? quoteId.value : undefined,
|
||||||
channelId: props.channel ? props.channel.id : undefined,
|
channelId: props.channel ? props.channel.id : undefined,
|
||||||
poll: poll.value,
|
poll: poll.value,
|
||||||
scheduledDelete: scheduledNoteDelete.value,
|
|
||||||
cw: useCw.value ? cw.value ?? '' : null,
|
cw: useCw.value ? cw.value ?? '' : null,
|
||||||
localOnly: localOnly.value,
|
localOnly: localOnly.value,
|
||||||
visibility: visibility.value,
|
visibility: visibility.value,
|
||||||
@ -1040,9 +1022,6 @@ onMounted(() => {
|
|||||||
if (draft.data.poll) {
|
if (draft.data.poll) {
|
||||||
poll.value = draft.data.poll;
|
poll.value = draft.data.poll;
|
||||||
}
|
}
|
||||||
if (draft.data.scheduledNoteDelete) {
|
|
||||||
scheduledNoteDelete.value = draft.data.scheduledNoteDelete;
|
|
||||||
}
|
|
||||||
if (draft.data.visibleUserIds) {
|
if (draft.data.visibleUserIds) {
|
||||||
misskeyApi('users/show', { userIds: draft.data.visibleUserIds }).then(users => {
|
misskeyApi('users/show', { userIds: draft.data.visibleUserIds }).then(users => {
|
||||||
users.forEach(u => pushVisibleUser(u));
|
users.forEach(u => pushVisibleUser(u));
|
||||||
@ -1070,12 +1049,6 @@ onMounted(() => {
|
|||||||
expiredAfter: null,
|
expiredAfter: null,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
if (init.deleteAt) {
|
|
||||||
scheduledNoteDelete.value = {
|
|
||||||
deleteAt: init.deleteAt ? (new Date(init.deleteAt)).getTime() : null,
|
|
||||||
deleteAfter: null,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
if (init.visibleUserIds) {
|
if (init.visibleUserIds) {
|
||||||
misskeyApi('users/show', { userIds: init.visibleUserIds }).then(users => {
|
misskeyApi('users/show', { userIds: init.visibleUserIds }).then(users => {
|
||||||
users.forEach(u => pushVisibleUser(u));
|
users.forEach(u => pushVisibleUser(u));
|
||||||
|
@ -2841,7 +2841,7 @@ type PartialRolePolicyOverride = Partial<{
|
|||||||
}>;
|
}>;
|
||||||
|
|
||||||
// @public (undocumented)
|
// @public (undocumented)
|
||||||
export const permissions: readonly ["read:account", "write:account", "read:blocks", "write:blocks", "read:drive", "write:drive", "read:favorites", "write:favorites", "read:following", "write:following", "read:messaging", "write:messaging", "read:mutes", "write:mutes", "write:notes", "read:notifications", "write:notifications", "read:reactions", "write:reactions", "write:votes", "read:pages", "write:pages", "write:page-likes", "read:page-likes", "read:user-groups", "write:user-groups", "read:channels", "write:channels", "read:gallery", "write:gallery", "read:gallery-likes", "write:gallery-likes", "read:flash", "write:flash", "read:flash-likes", "write:flash-likes", "read:admin:abuse-user-reports", "write:admin:delete-account", "write:admin:delete-all-files-of-a-user", "read:admin:index-stats", "read:admin:table-stats", "read:admin:user-ips", "read:admin:meta", "write:admin:reset-password", "write:admin:resolve-abuse-user-report", "write:admin:send-email", "read:admin:server-info", "read:admin:show-moderation-log", "read:admin:show-user", "write:admin:suspend-user", "write:admin:approve-user", "write:admin:nsfw-user", "write:admin:unnsfw-user", "write:admin:silence-user", "write:admin:unsilence-user", "write:admin:unset-user-avatar", "write:admin:unset-user-banner", "write:admin:unsuspend-user", "write:admin:meta", "write:admin:user-note", "write:admin:roles", "read:admin:roles", "write:admin:relays", "read:admin:relays", "write:admin:invite-codes", "read:admin:invite-codes", "write:admin:announcements", "read:admin:announcements", "write:admin:avatar-decorations", "read:admin:avatar-decorations", "write:admin:federation", "write:admin:account", "read:admin:account", "write:admin:emoji", "read:admin:emoji", "write:admin:queue", "read:admin:queue", "write:admin:promo", "write:admin:drive", "read:admin:drive", "write:admin:ad", "read:admin:ad", "write:invite-codes", "read:invite-codes", "write:clip-favorite", "read:clip-favorite", "read:federation", "write:report-abuse","read:integrations","write:integrations"];
|
export const permissions: readonly ["read:account", "write:account", "read:blocks", "write:blocks", "read:drive", "write:drive", "read:favorites", "write:favorites", "read:following", "write:following", "read:messaging", "write:messaging", "read:mutes", "write:mutes", "write:notes", "read:notifications", "write:notifications", "read:reactions", "write:reactions", "write:votes", "read:pages", "write:pages", "write:page-likes", "read:page-likes", "read:user-groups", "write:user-groups", "read:channels", "write:channels", "read:gallery", "write:gallery", "read:gallery-likes", "write:gallery-likes", "read:flash", "write:flash", "read:flash-likes", "write:flash-likes", "read:admin:abuse-user-reports", "write:admin:delete-account", "write:admin:delete-all-files-of-a-user", "read:admin:index-stats", "read:admin:table-stats", "read:admin:user-ips", "read:admin:meta", "write:admin:reset-password", "write:admin:resolve-abuse-user-report", "write:admin:send-email", "read:admin:server-info", "read:admin:show-moderation-log", "read:admin:show-user", "write:admin:suspend-user", "write:admin:approve-user", "write:admin:nsfw-user", "write:admin:unnsfw-user", "write:admin:silence-user", "write:admin:unsilence-user", "write:admin:unset-user-avatar", "write:admin:unset-user-banner", "write:admin:unsuspend-user", "write:admin:meta", "write:admin:user-note", "write:admin:roles", "read:admin:roles", "write:admin:relays", "read:admin:relays", "write:admin:invite-codes", "read:admin:invite-codes", "write:admin:announcements", "read:admin:announcements", "write:admin:avatar-decorations", "read:admin:avatar-decorations", "write:admin:federation", "write:admin:account", "read:admin:account", "write:admin:emoji", "read:admin:emoji", "write:admin:queue", "read:admin:queue", "write:admin:promo", "write:admin:drive", "read:admin:drive", "write:admin:ad", "read:admin:ad", "write:invite-codes", "read:invite-codes", "write:clip-favorite", "read:clip-favorite", "read:federation", "write:report-abuse"];
|
||||||
|
|
||||||
// @public (undocumented)
|
// @public (undocumented)
|
||||||
type PingResponse = operations['ping']['responses']['200']['content']['application/json'];
|
type PingResponse = operations['ping']['responses']['200']['content']['application/json'];
|
||||||
|
@ -4204,8 +4204,6 @@ export type components = {
|
|||||||
votes: number;
|
votes: number;
|
||||||
}[];
|
}[];
|
||||||
}) | null;
|
}) | null;
|
||||||
/** Format: date-time */
|
|
||||||
deleteAt?: string | null;
|
|
||||||
emojis?: {
|
emojis?: {
|
||||||
[key: string]: string;
|
[key: string]: string;
|
||||||
};
|
};
|
||||||
@ -5287,7 +5285,6 @@ export type operations = {
|
|||||||
tosUrl: string | null;
|
tosUrl: string | null;
|
||||||
uri: string;
|
uri: string;
|
||||||
version: string;
|
version: string;
|
||||||
blockMentionsFromUnfamiliarRemoteUsers: boolean;
|
|
||||||
urlPreviewEnabled: boolean;
|
urlPreviewEnabled: boolean;
|
||||||
urlPreviewTimeout: number;
|
urlPreviewTimeout: number;
|
||||||
urlPreviewMaximumContentLength: number;
|
urlPreviewMaximumContentLength: number;
|
||||||
@ -9804,7 +9801,6 @@ export type operations = {
|
|||||||
perUserHomeTimelineCacheMax?: number;
|
perUserHomeTimelineCacheMax?: number;
|
||||||
perUserListTimelineCacheMax?: number;
|
perUserListTimelineCacheMax?: number;
|
||||||
notesPerOneAd?: number;
|
notesPerOneAd?: number;
|
||||||
blockMentionsFromUnfamiliarRemoteUsers?: boolean;
|
|
||||||
silencedHosts?: string[] | null;
|
silencedHosts?: string[] | null;
|
||||||
mediaSilencedHosts?: string[] | null;
|
mediaSilencedHosts?: string[] | null;
|
||||||
/** @description [Deprecated] Use "urlPreviewSummaryProxyUrl" instead. */
|
/** @description [Deprecated] Use "urlPreviewSummaryProxyUrl" instead. */
|
||||||
@ -21901,10 +21897,6 @@ export type operations = {
|
|||||||
expiresAt?: number | null;
|
expiresAt?: number | null;
|
||||||
expiredAfter?: number | null;
|
expiredAfter?: number | null;
|
||||||
}) | null;
|
}) | null;
|
||||||
scheduledDelete?: ({
|
|
||||||
deleteAt?: number | null;
|
|
||||||
deleteAfter?: number | null;
|
|
||||||
}) | null;
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
Loading…
Reference in New Issue
Block a user