wip
This commit is contained in:
@@ -255,20 +255,27 @@ export class ChatService {
|
|||||||
await redisPipeline.exec();
|
await redisPipeline.exec();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
|
public findMyMessageById(userId: MiUser['id'], messageId: MiChatMessage['id']) {
|
||||||
|
return this.chatMessagesRepository.findOneBy({ id: messageId, fromUserId: userId });
|
||||||
|
}
|
||||||
|
|
||||||
@bindThis
|
@bindThis
|
||||||
public async deleteMessage(message: MiChatMessage) {
|
public async deleteMessage(message: MiChatMessage) {
|
||||||
await this.chatMessagesRepository.delete(message.id);
|
await this.chatMessagesRepository.delete(message.id);
|
||||||
|
|
||||||
if (message.toUserId) {
|
if (message.toUserId) {
|
||||||
const fromUser = await this.usersRepository.findOneByOrFail({ id: message.fromUserId });
|
const [fromUser, toUser] = await Promise.all([
|
||||||
const toUser = await this.usersRepository.findOneByOrFail({ id: message.toUserId });
|
this.usersRepository.findOneByOrFail({ id: message.fromUserId }),
|
||||||
|
this.usersRepository.findOneByOrFail({ id: message.toUserId }),
|
||||||
|
]);
|
||||||
|
|
||||||
if (this.userEntityService.isLocalUser(fromUser)) this.globalEventService.publishChatStream(message.fromUserId, message.toUserId, 'deleted', message.id);
|
if (this.userEntityService.isLocalUser(fromUser)) this.globalEventService.publishChatStream(message.fromUserId, message.toUserId, 'deleted', message.id);
|
||||||
if (this.userEntityService.isLocalUser(toUser)) this.globalEventService.publishChatStream(message.toUserId, message.fromUserId, 'deleted', message.id);
|
if (this.userEntityService.isLocalUser(toUser)) this.globalEventService.publishChatStream(message.toUserId, message.fromUserId, 'deleted', message.id);
|
||||||
|
|
||||||
if (this.userEntityService.isLocalUser(fromUser) && this.userEntityService.isRemoteUser(toUser)) {
|
if (this.userEntityService.isLocalUser(fromUser) && this.userEntityService.isRemoteUser(toUser)) {
|
||||||
const activity = this.apRendererService.addContext(this.apRendererService.renderDelete(this.apRendererService.renderTombstone(`${this.config.url}/notes/${message.id}`), fromUser));
|
//const activity = this.apRendererService.addContext(this.apRendererService.renderDelete(this.apRendererService.renderTombstone(`${this.config.url}/notes/${message.id}`), fromUser));
|
||||||
this.queueService.deliver(fromUser, activity, toUser.inbox);
|
//this.queueService.deliver(fromUser, activity, toUser.inbox);
|
||||||
}
|
}
|
||||||
}/* else if (message.toRoomId) {
|
}/* else if (message.toRoomId) {
|
||||||
this.globalEventService.publishRoomChatStream(message.toRoomId, 'deleted', message.id);
|
this.globalEventService.publishRoomChatStream(message.toRoomId, 'deleted', message.id);
|
||||||
|
@@ -397,6 +397,7 @@ export * as 'users/search-by-username-and-host' from './endpoints/users/search-b
|
|||||||
export * as 'users/show' from './endpoints/users/show.js';
|
export * as 'users/show' from './endpoints/users/show.js';
|
||||||
export * as 'users/update-memo' from './endpoints/users/update-memo.js';
|
export * as 'users/update-memo' from './endpoints/users/update-memo.js';
|
||||||
export * as 'chat/messages/create' from './endpoints/chat/messages/create.js';
|
export * as 'chat/messages/create' from './endpoints/chat/messages/create.js';
|
||||||
|
export * as 'chat/messages/delete' from './endpoints/chat/messages/delete.js';
|
||||||
export * as 'chat/messages/timeline' from './endpoints/chat/messages/timeline.js';
|
export * as 'chat/messages/timeline' from './endpoints/chat/messages/timeline.js';
|
||||||
export * as 'chat/history' from './endpoints/chat/history.js';
|
export * as 'chat/history' from './endpoints/chat/history.js';
|
||||||
export * as 'v2/admin/emoji/list' from './endpoints/v2/admin/emoji/list.js';
|
export * as 'v2/admin/emoji/list' from './endpoints/v2/admin/emoji/list.js';
|
||||||
|
@@ -0,0 +1,54 @@
|
|||||||
|
/*
|
||||||
|
* SPDX-FileCopyrightText: syuilo and misskey-project
|
||||||
|
* SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { Inject, Injectable } from '@nestjs/common';
|
||||||
|
import { Endpoint } from '@/server/api/endpoint-base.js';
|
||||||
|
import { DI } from '@/di-symbols.js';
|
||||||
|
import { GetterService } from '@/server/api/GetterService.js';
|
||||||
|
import { ChatService } from '@/core/ChatService.js';
|
||||||
|
import { ChatMessageEntityService } from '@/core/entities/ChatMessageEntityService.js';
|
||||||
|
import { ApiError } from '@/server/api/error.js';
|
||||||
|
|
||||||
|
export const meta = {
|
||||||
|
tags: ['chat'],
|
||||||
|
|
||||||
|
requireCredential: true,
|
||||||
|
|
||||||
|
kind: 'write:chat',
|
||||||
|
|
||||||
|
res: {
|
||||||
|
},
|
||||||
|
|
||||||
|
errors: {
|
||||||
|
noSuchMessage: {
|
||||||
|
message: 'No such message.',
|
||||||
|
code: 'NO_SUCH_MESSAGE',
|
||||||
|
id: '36b67f0e-66a6-414b-83df-992a55294f17',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
} as const;
|
||||||
|
|
||||||
|
export const paramDef = {
|
||||||
|
type: 'object',
|
||||||
|
properties: {
|
||||||
|
messageId: { type: 'string', format: 'misskey:id' },
|
||||||
|
},
|
||||||
|
required: ['messageId'],
|
||||||
|
} as const;
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-disable-line import/no-default-export
|
||||||
|
constructor(
|
||||||
|
private chatService: ChatService,
|
||||||
|
) {
|
||||||
|
super(meta, paramDef, async (ps, me) => {
|
||||||
|
const message = await this.chatService.findMyMessageById(me.id, ps.messageId);
|
||||||
|
if (message == null) {
|
||||||
|
throw new ApiError(meta.errors.noSuchMessage);
|
||||||
|
}
|
||||||
|
await this.chatService.deleteMessage(message);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
@@ -26,15 +26,18 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { computed } from 'vue';
|
import { computed, defineAsyncComponent } from 'vue';
|
||||||
import * as mfm from 'mfm-js';
|
import * as mfm from 'mfm-js';
|
||||||
import * as Misskey from 'misskey-js';
|
import * as Misskey from 'misskey-js';
|
||||||
|
import { url } from '@@/js/config.js';
|
||||||
|
import type { MenuItem } from '@/types/menu.js';
|
||||||
import { extractUrlFromMfm } from '@/utility/extract-url-from-mfm.js';
|
import { extractUrlFromMfm } from '@/utility/extract-url-from-mfm.js';
|
||||||
import MkUrlPreview from '@/components/MkUrlPreview.vue';
|
import MkUrlPreview from '@/components/MkUrlPreview.vue';
|
||||||
import { ensureSignin } from '@/i.js';
|
import { ensureSignin } from '@/i.js';
|
||||||
import { misskeyApi } from '@/utility/misskey-api.js';
|
import { misskeyApi } from '@/utility/misskey-api.js';
|
||||||
import { i18n } from '@/i18n.js';
|
import { i18n } from '@/i18n.js';
|
||||||
import MkFukidashi from '@/components/MkFukidashi.vue';
|
import MkFukidashi from '@/components/MkFukidashi.vue';
|
||||||
|
import * as os from '@/os.js';
|
||||||
|
|
||||||
const $i = ensureSignin();
|
const $i = ensureSignin();
|
||||||
|
|
||||||
@@ -47,10 +50,36 @@ const props = defineProps<{
|
|||||||
const isMe = computed(() => props.message.fromUserId === $i.id);
|
const isMe = computed(() => props.message.fromUserId === $i.id);
|
||||||
const urls = computed(() => props.message.text ? extractUrlFromMfm(mfm.parse(props.message.text)) : []);
|
const urls = computed(() => props.message.text ? extractUrlFromMfm(mfm.parse(props.message.text)) : []);
|
||||||
|
|
||||||
function del(): void {
|
function showMenu(ev: MouseEvent) {
|
||||||
misskeyApi('chat/messages/delete', {
|
const menu: MenuItem[] = [];
|
||||||
messageId: props.message.id,
|
if (isMe.value) {
|
||||||
});
|
menu.push({
|
||||||
|
text: i18n.ts.delete,
|
||||||
|
icon: 'ti ti-trash',
|
||||||
|
danger: true,
|
||||||
|
action: () => {
|
||||||
|
misskeyApi('chat/messages/delete', {
|
||||||
|
messageId: props.message.id,
|
||||||
|
});
|
||||||
|
},
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
menu.push({
|
||||||
|
text: i18n.ts.reportAbuse,
|
||||||
|
icon: 'ti ti-exclamation-circle',
|
||||||
|
action: () => {
|
||||||
|
const localUrl = `${url}/chat/messages/${props.message.id}`;
|
||||||
|
const { dispose } = os.popup(defineAsyncComponent(() => import('@/components/MkAbuseReportWindow.vue')), {
|
||||||
|
user: props.user,
|
||||||
|
initialComment: `${localUrl}\n-----\n`,
|
||||||
|
}, {
|
||||||
|
closed: () => dispose(),
|
||||||
|
});
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
os.popupMenu(menu, ev.currentTarget ?? ev.target);
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
@@ -965,6 +965,12 @@ type ChatMessagesCreateRequest = operations['chat___messages___create']['request
|
|||||||
// @public (undocumented)
|
// @public (undocumented)
|
||||||
type ChatMessagesCreateResponse = operations['chat___messages___create']['responses']['200']['content']['application/json'];
|
type ChatMessagesCreateResponse = operations['chat___messages___create']['responses']['200']['content']['application/json'];
|
||||||
|
|
||||||
|
// @public (undocumented)
|
||||||
|
type ChatMessagesDeleteRequest = operations['chat___messages___delete']['requestBody']['content']['application/json'];
|
||||||
|
|
||||||
|
// @public (undocumented)
|
||||||
|
type ChatMessagesDeleteResponse = operations['chat___messages___delete']['responses']['200']['content']['application/json'];
|
||||||
|
|
||||||
// @public (undocumented)
|
// @public (undocumented)
|
||||||
type ChatMessagesTimelineRequest = operations['chat___messages___timeline']['requestBody']['content']['application/json'];
|
type ChatMessagesTimelineRequest = operations['chat___messages___timeline']['requestBody']['content']['application/json'];
|
||||||
|
|
||||||
@@ -1475,6 +1481,8 @@ declare namespace entities {
|
|||||||
ChatHistoryResponse,
|
ChatHistoryResponse,
|
||||||
ChatMessagesCreateRequest,
|
ChatMessagesCreateRequest,
|
||||||
ChatMessagesCreateResponse,
|
ChatMessagesCreateResponse,
|
||||||
|
ChatMessagesDeleteRequest,
|
||||||
|
ChatMessagesDeleteResponse,
|
||||||
ChatMessagesTimelineRequest,
|
ChatMessagesTimelineRequest,
|
||||||
ChatMessagesTimelineResponse,
|
ChatMessagesTimelineResponse,
|
||||||
ClipsAddNoteRequest,
|
ClipsAddNoteRequest,
|
||||||
|
@@ -1556,6 +1556,17 @@ declare module '../api.js' {
|
|||||||
credential?: string | null,
|
credential?: string | null,
|
||||||
): Promise<SwitchCaseResponseType<E, P>>;
|
): Promise<SwitchCaseResponseType<E, P>>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* No description provided.
|
||||||
|
*
|
||||||
|
* **Credential required**: *Yes* / **Permission**: *write:chat*
|
||||||
|
*/
|
||||||
|
request<E extends 'chat/messages/delete', P extends Endpoints[E]['req']>(
|
||||||
|
endpoint: E,
|
||||||
|
params: P,
|
||||||
|
credential?: string | null,
|
||||||
|
): Promise<SwitchCaseResponseType<E, P>>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* No description provided.
|
* No description provided.
|
||||||
*
|
*
|
||||||
|
@@ -211,6 +211,8 @@ import type {
|
|||||||
ChatHistoryResponse,
|
ChatHistoryResponse,
|
||||||
ChatMessagesCreateRequest,
|
ChatMessagesCreateRequest,
|
||||||
ChatMessagesCreateResponse,
|
ChatMessagesCreateResponse,
|
||||||
|
ChatMessagesDeleteRequest,
|
||||||
|
ChatMessagesDeleteResponse,
|
||||||
ChatMessagesTimelineRequest,
|
ChatMessagesTimelineRequest,
|
||||||
ChatMessagesTimelineResponse,
|
ChatMessagesTimelineResponse,
|
||||||
ClipsAddNoteRequest,
|
ClipsAddNoteRequest,
|
||||||
@@ -734,6 +736,7 @@ export type Endpoints = {
|
|||||||
'charts/users': { req: ChartsUsersRequest; res: ChartsUsersResponse };
|
'charts/users': { req: ChartsUsersRequest; res: ChartsUsersResponse };
|
||||||
'chat/history': { req: ChatHistoryRequest; res: ChatHistoryResponse };
|
'chat/history': { req: ChatHistoryRequest; res: ChatHistoryResponse };
|
||||||
'chat/messages/create': { req: ChatMessagesCreateRequest; res: ChatMessagesCreateResponse };
|
'chat/messages/create': { req: ChatMessagesCreateRequest; res: ChatMessagesCreateResponse };
|
||||||
|
'chat/messages/delete': { req: ChatMessagesDeleteRequest; res: ChatMessagesDeleteResponse };
|
||||||
'chat/messages/timeline': { req: ChatMessagesTimelineRequest; res: ChatMessagesTimelineResponse };
|
'chat/messages/timeline': { req: ChatMessagesTimelineRequest; res: ChatMessagesTimelineResponse };
|
||||||
'clips/add-note': { req: ClipsAddNoteRequest; res: EmptyResponse };
|
'clips/add-note': { req: ClipsAddNoteRequest; res: EmptyResponse };
|
||||||
'clips/create': { req: ClipsCreateRequest; res: ClipsCreateResponse };
|
'clips/create': { req: ClipsCreateRequest; res: ClipsCreateResponse };
|
||||||
|
@@ -214,6 +214,8 @@ export type ChatHistoryRequest = operations['chat___history']['requestBody']['co
|
|||||||
export type ChatHistoryResponse = operations['chat___history']['responses']['200']['content']['application/json'];
|
export type ChatHistoryResponse = operations['chat___history']['responses']['200']['content']['application/json'];
|
||||||
export type ChatMessagesCreateRequest = operations['chat___messages___create']['requestBody']['content']['application/json'];
|
export type ChatMessagesCreateRequest = operations['chat___messages___create']['requestBody']['content']['application/json'];
|
||||||
export type ChatMessagesCreateResponse = operations['chat___messages___create']['responses']['200']['content']['application/json'];
|
export type ChatMessagesCreateResponse = operations['chat___messages___create']['responses']['200']['content']['application/json'];
|
||||||
|
export type ChatMessagesDeleteRequest = operations['chat___messages___delete']['requestBody']['content']['application/json'];
|
||||||
|
export type ChatMessagesDeleteResponse = operations['chat___messages___delete']['responses']['200']['content']['application/json'];
|
||||||
export type ChatMessagesTimelineRequest = operations['chat___messages___timeline']['requestBody']['content']['application/json'];
|
export type ChatMessagesTimelineRequest = operations['chat___messages___timeline']['requestBody']['content']['application/json'];
|
||||||
export type ChatMessagesTimelineResponse = operations['chat___messages___timeline']['responses']['200']['content']['application/json'];
|
export type ChatMessagesTimelineResponse = operations['chat___messages___timeline']['responses']['200']['content']['application/json'];
|
||||||
export type ClipsAddNoteRequest = operations['clips___add-note']['requestBody']['content']['application/json'];
|
export type ClipsAddNoteRequest = operations['clips___add-note']['requestBody']['content']['application/json'];
|
||||||
|
@@ -1376,6 +1376,15 @@ export type paths = {
|
|||||||
*/
|
*/
|
||||||
post: operations['chat___messages___create'];
|
post: operations['chat___messages___create'];
|
||||||
};
|
};
|
||||||
|
'/chat/messages/delete': {
|
||||||
|
/**
|
||||||
|
* chat/messages/delete
|
||||||
|
* @description No description provided.
|
||||||
|
*
|
||||||
|
* **Credential required**: *Yes* / **Permission**: *write:chat*
|
||||||
|
*/
|
||||||
|
post: operations['chat___messages___delete'];
|
||||||
|
};
|
||||||
'/chat/messages/timeline': {
|
'/chat/messages/timeline': {
|
||||||
/**
|
/**
|
||||||
* chat/messages/timeline
|
* chat/messages/timeline
|
||||||
@@ -13844,6 +13853,60 @@ export type operations = {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
/**
|
||||||
|
* chat/messages/delete
|
||||||
|
* @description No description provided.
|
||||||
|
*
|
||||||
|
* **Credential required**: *Yes* / **Permission**: *write:chat*
|
||||||
|
*/
|
||||||
|
chat___messages___delete: {
|
||||||
|
requestBody: {
|
||||||
|
content: {
|
||||||
|
'application/json': {
|
||||||
|
/** Format: misskey:id */
|
||||||
|
messageId: string;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
responses: {
|
||||||
|
/** @description OK (with results) */
|
||||||
|
200: {
|
||||||
|
content: {
|
||||||
|
'application/json': unknown;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
/** @description Client error */
|
||||||
|
400: {
|
||||||
|
content: {
|
||||||
|
'application/json': components['schemas']['Error'];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
/** @description Authentication error */
|
||||||
|
401: {
|
||||||
|
content: {
|
||||||
|
'application/json': components['schemas']['Error'];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
/** @description Forbidden error */
|
||||||
|
403: {
|
||||||
|
content: {
|
||||||
|
'application/json': components['schemas']['Error'];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
/** @description I'm Ai */
|
||||||
|
418: {
|
||||||
|
content: {
|
||||||
|
'application/json': components['schemas']['Error'];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
/** @description Internal server error */
|
||||||
|
500: {
|
||||||
|
content: {
|
||||||
|
'application/json': components['schemas']['Error'];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
/**
|
/**
|
||||||
* chat/messages/timeline
|
* chat/messages/timeline
|
||||||
* @description No description provided.
|
* @description No description provided.
|
||||||
|
Reference in New Issue
Block a user