mirror of
https://git.joinsharkey.org/Sharkey/Sharkey.git
synced 2024-12-02 12:03:08 +02:00
Compare commits
No commits in common. "78975ddcc83d2c1c6ac4b7738a2266142e26f098" and "15665d1533802f78c7f5b197f5255405765cb8e3" have entirely different histories.
78975ddcc8
...
15665d1533
23 changed files with 104 additions and 202 deletions
|
@ -1026,7 +1026,6 @@ remindMeLater: "Maybe later"
|
||||||
didYouLikeMisskey: "Have you taken a liking to Sharkey?"
|
didYouLikeMisskey: "Have you taken a liking to Sharkey?"
|
||||||
pleaseDonate: "{host} uses the free software, Sharkey. We would highly appreciate your donations so development of Sharkey can continue!"
|
pleaseDonate: "{host} uses the free software, Sharkey. We would highly appreciate your donations so development of Sharkey can continue!"
|
||||||
pleaseDonateInstance: "You can also support {host} directly by donating to your instance administration."
|
pleaseDonateInstance: "You can also support {host} directly by donating to your instance administration."
|
||||||
correspondingSourceIsAvailable: "The corresponding source code is available from {anchor}."
|
|
||||||
roles: "Roles"
|
roles: "Roles"
|
||||||
role: "Role"
|
role: "Role"
|
||||||
noRole: "Role not found"
|
noRole: "Role not found"
|
||||||
|
@ -1215,12 +1214,6 @@ confirmShowRepliesAll: "This operation is irreversible. Would you really like to
|
||||||
confirmHideRepliesAll: "This operation is irreversible. Would you really like to hide replies to others from everyone you follow in your timeline?"
|
confirmHideRepliesAll: "This operation is irreversible. Would you really like to hide replies to others from everyone you follow in your timeline?"
|
||||||
externalServices: "External Services"
|
externalServices: "External Services"
|
||||||
sourceCode: "Source code"
|
sourceCode: "Source code"
|
||||||
sourceCodeIsNotYetProvided: "The source code is not yet available. Please contact your administrator to fix this issue."
|
|
||||||
repositoryUrl: "Repository URL"
|
|
||||||
repositoryUrlDescription: "If there is a repository where the source code is publicly available, enter its URL. If you are using Sharkey as-is (without any changes to the source code), enter https://activitypub.software/TransFem-org/Sharkey/."
|
|
||||||
repositoryUrlOrTarballRequired: "If you don't have a public repository, you'll need to provide a tarball instead. See .config/example.yml for details."
|
|
||||||
feedback: "Feedback"
|
|
||||||
feedbackUrl: "Feedback URL"
|
|
||||||
impressum: "Impressum"
|
impressum: "Impressum"
|
||||||
impressumUrl: "Impressum URL"
|
impressumUrl: "Impressum URL"
|
||||||
impressumDescription: "In some countries, like germany, the inclusion of operator contact information (an Impressum) is legally required for commercial websites."
|
impressumDescription: "In some countries, like germany, the inclusion of operator contact information (an Impressum) is legally required for commercial websites."
|
||||||
|
@ -1815,12 +1808,8 @@ _aboutMisskey:
|
||||||
contributors: "Main contributors"
|
contributors: "Main contributors"
|
||||||
allContributors: "All contributors"
|
allContributors: "All contributors"
|
||||||
source: "Source code"
|
source: "Source code"
|
||||||
original: "Misskey original"
|
|
||||||
original_sharkey: "Sharkey original"
|
|
||||||
thisIsModifiedVersion: "{name} uses a modified version of the original Sharkey"
|
|
||||||
translation: "Translate Sharkey"
|
translation: "Translate Sharkey"
|
||||||
donate: "Donate to Misskey"
|
donate: "Donate to Sharkey"
|
||||||
donate_sharkey: "Donate to Sharkey"
|
|
||||||
morePatrons: "We also appreciate the support of many other helpers not listed here. Thank you! 🥰"
|
morePatrons: "We also appreciate the support of many other helpers not listed here. Thank you! 🥰"
|
||||||
patrons: "Patrons"
|
patrons: "Patrons"
|
||||||
projectMembers: "Project members"
|
projectMembers: "Project members"
|
||||||
|
@ -2345,7 +2334,6 @@ _notification:
|
||||||
reactedBySomeUsers: "{n} users reacted"
|
reactedBySomeUsers: "{n} users reacted"
|
||||||
renotedBySomeUsers: "Boosted by {n} users"
|
renotedBySomeUsers: "Boosted by {n} users"
|
||||||
followedBySomeUsers: "Followed by {n} users"
|
followedBySomeUsers: "Followed by {n} users"
|
||||||
edited: "Note got edited"
|
|
||||||
_types:
|
_types:
|
||||||
all: "All"
|
all: "All"
|
||||||
note: "New notes"
|
note: "New notes"
|
||||||
|
|
18
locales/index.d.ts
vendored
18
locales/index.d.ts
vendored
|
@ -7059,29 +7059,21 @@ export interface Locale extends ILocale {
|
||||||
*/
|
*/
|
||||||
"source": string;
|
"source": string;
|
||||||
/**
|
/**
|
||||||
* Misskey オリジナル
|
* オリジナル
|
||||||
*/
|
*/
|
||||||
"original": string;
|
"original": string;
|
||||||
/**
|
/**
|
||||||
* Sharkey オリジナル
|
* {name}はオリジナルのMisskeyを改変したバージョンを使用しています。
|
||||||
*/
|
|
||||||
"original_sharkey": string;
|
|
||||||
/**
|
|
||||||
* {name}はオリジナルのSharkeyを改変したバージョンを使用しています。
|
|
||||||
*/
|
*/
|
||||||
"thisIsModifiedVersion": ParameterizedString<"name">;
|
"thisIsModifiedVersion": ParameterizedString<"name">;
|
||||||
/**
|
/**
|
||||||
* Sharkeyを翻訳
|
* Sharkeyを翻訳
|
||||||
*/
|
*/
|
||||||
"translation": string;
|
"translation": string;
|
||||||
/**
|
|
||||||
* Misskeyに寄付
|
|
||||||
*/
|
|
||||||
"donate": string;
|
|
||||||
/**
|
/**
|
||||||
* Sharkeyに寄付
|
* Sharkeyに寄付
|
||||||
*/
|
*/
|
||||||
"donate_sharkey": string;
|
"donate": string;
|
||||||
/**
|
/**
|
||||||
* 他にも多くの方が支援してくれています。ありがとうございます🥰
|
* 他にも多くの方が支援してくれています。ありがとうございます🥰
|
||||||
*/
|
*/
|
||||||
|
@ -9056,10 +9048,6 @@ export interface Locale extends ILocale {
|
||||||
* アンケートの結果が出ました
|
* アンケートの結果が出ました
|
||||||
*/
|
*/
|
||||||
"pollEnded": string;
|
"pollEnded": string;
|
||||||
/**
|
|
||||||
* 投稿が編集されました
|
|
||||||
*/
|
|
||||||
"edited": string;
|
|
||||||
/**
|
/**
|
||||||
* 新しい投稿
|
* 新しい投稿
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -1839,12 +1839,10 @@ _aboutMisskey:
|
||||||
contributors: "主なコントリビューター"
|
contributors: "主なコントリビューター"
|
||||||
allContributors: "全てのコントリビューター"
|
allContributors: "全てのコントリビューター"
|
||||||
source: "ソースコード"
|
source: "ソースコード"
|
||||||
original: "Misskey オリジナル"
|
original: "オリジナル"
|
||||||
original_sharkey: "Sharkey オリジナル"
|
thisIsModifiedVersion: "{name}はオリジナルのMisskeyを改変したバージョンを使用しています。"
|
||||||
thisIsModifiedVersion: "{name}はオリジナルのSharkeyを改変したバージョンを使用しています。"
|
|
||||||
translation: "Sharkeyを翻訳"
|
translation: "Sharkeyを翻訳"
|
||||||
donate: "Misskeyに寄付"
|
donate: "Sharkeyに寄付"
|
||||||
donate_sharkey: "Sharkeyに寄付"
|
|
||||||
morePatrons: "他にも多くの方が支援してくれています。ありがとうございます🥰"
|
morePatrons: "他にも多くの方が支援してくれています。ありがとうございます🥰"
|
||||||
patrons: "支援者"
|
patrons: "支援者"
|
||||||
projectMembers: "プロジェクトメンバー"
|
projectMembers: "プロジェクトメンバー"
|
||||||
|
@ -2391,7 +2389,6 @@ _notification:
|
||||||
youReceivedFollowRequest: "フォローリクエストが来ました"
|
youReceivedFollowRequest: "フォローリクエストが来ました"
|
||||||
yourFollowRequestAccepted: "フォローリクエストが承認されました"
|
yourFollowRequestAccepted: "フォローリクエストが承認されました"
|
||||||
pollEnded: "アンケートの結果が出ました"
|
pollEnded: "アンケートの結果が出ました"
|
||||||
edited: "投稿が編集されました"
|
|
||||||
newNote: "新しい投稿"
|
newNote: "新しい投稿"
|
||||||
unreadAntennaNote: "アンテナ {name}"
|
unreadAntennaNote: "アンテナ {name}"
|
||||||
roleAssigned: "ロールが付与されました"
|
roleAssigned: "ロールが付与されました"
|
||||||
|
|
|
@ -96,7 +96,6 @@ export interface MainEventTypes {
|
||||||
announcementCreated: {
|
announcementCreated: {
|
||||||
announcement: Packed<'Announcement'>;
|
announcement: Packed<'Announcement'>;
|
||||||
};
|
};
|
||||||
edited: Packed<'Note'>;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface DriveEventTypes {
|
export interface DriveEventTypes {
|
||||||
|
|
|
@ -52,7 +52,7 @@ import { isReply } from '@/misc/is-reply.js';
|
||||||
import { trackPromise } from '@/misc/promise-tracker.js';
|
import { trackPromise } from '@/misc/promise-tracker.js';
|
||||||
import { isUserRelated } from '@/misc/is-user-related.js';
|
import { isUserRelated } from '@/misc/is-user-related.js';
|
||||||
|
|
||||||
type NotificationType = 'reply' | 'renote' | 'quote' | 'mention' | 'edited';
|
type NotificationType = 'reply' | 'renote' | 'quote' | 'mention';
|
||||||
|
|
||||||
class NotificationManager {
|
class NotificationManager {
|
||||||
private notifier: { id: MiUser['id']; };
|
private notifier: { id: MiUser['id']; };
|
||||||
|
@ -586,7 +586,7 @@ export class NoteEditService implements OnApplicationShutdown {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Pack the note
|
// Pack the note
|
||||||
const noteObj = await this.noteEntityService.pack(note, null, { skipHide: true, withReactionAndUserPairCache: true });
|
const noteObj = await this.noteEntityService.pack(note, null, { skipHide: true });
|
||||||
if (data.poll != null) {
|
if (data.poll != null) {
|
||||||
this.globalEventService.publishNoteStream(note.id, 'updated', {
|
this.globalEventService.publishNoteStream(note.id, 'updated', {
|
||||||
cw: note.cw,
|
cw: note.cw,
|
||||||
|
@ -612,7 +612,7 @@ export class NoteEditService implements OnApplicationShutdown {
|
||||||
|
|
||||||
const nm = new NotificationManager(this.mutingsRepository, this.notificationService, user, note);
|
const nm = new NotificationManager(this.mutingsRepository, this.notificationService, user, note);
|
||||||
|
|
||||||
//await this.createMentionedEvents(mentionedUsers, note, nm);
|
await this.createMentionedEvents(mentionedUsers, note, nm);
|
||||||
|
|
||||||
// If has in reply to note
|
// If has in reply to note
|
||||||
if (data.reply) {
|
if (data.reply) {
|
||||||
|
@ -634,12 +634,12 @@ export class NoteEditService implements OnApplicationShutdown {
|
||||||
const muted = isUserRelated(note, userIdsWhoMeMuting);
|
const muted = isUserRelated(note, userIdsWhoMeMuting);
|
||||||
|
|
||||||
if (!isThreadMuted && !muted) {
|
if (!isThreadMuted && !muted) {
|
||||||
nm.push(data.reply.userId, 'edited');
|
nm.push(data.reply.userId, 'reply');
|
||||||
this.globalEventService.publishMainStream(data.reply.userId, 'edited', noteObj);
|
this.globalEventService.publishMainStream(data.reply.userId, 'reply', noteObj);
|
||||||
|
|
||||||
const webhooks = (await this.webhookService.getActiveWebhooks()).filter(x => x.userId === data.reply!.userId && x.on.includes('edited'));
|
const webhooks = (await this.webhookService.getActiveWebhooks()).filter(x => x.userId === data.reply!.userId && x.on.includes('reply'));
|
||||||
for (const webhook of webhooks) {
|
for (const webhook of webhooks) {
|
||||||
this.queueService.webhookDeliver(webhook, 'edited', {
|
this.queueService.webhookDeliver(webhook, 'reply', {
|
||||||
note: noteObj,
|
note: noteObj,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -647,6 +647,45 @@ export class NoteEditService implements OnApplicationShutdown {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If it is renote
|
||||||
|
if (data.renote) {
|
||||||
|
const type = this.isQuote(data) ? 'quote' : 'renote';
|
||||||
|
|
||||||
|
// Notify
|
||||||
|
if (data.renote.userHost === null) {
|
||||||
|
const isThreadMuted = await this.noteThreadMutingsRepository.exists({
|
||||||
|
where: {
|
||||||
|
userId: data.renote.userId,
|
||||||
|
threadId: data.renote.threadId ?? data.renote.id,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const [
|
||||||
|
userIdsWhoMeMuting,
|
||||||
|
] = data.renote.userId ? await Promise.all([
|
||||||
|
this.cacheService.userMutingsCache.fetch(data.renote.userId),
|
||||||
|
]) : [new Set<string>()];
|
||||||
|
|
||||||
|
const muted = isUserRelated(note, userIdsWhoMeMuting);
|
||||||
|
|
||||||
|
if (!isThreadMuted && !muted) {
|
||||||
|
nm.push(data.renote.userId, type);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Publish event
|
||||||
|
if ((user.id !== data.renote.userId) && data.renote.userHost === null) {
|
||||||
|
this.globalEventService.publishMainStream(data.renote.userId, 'renote', noteObj);
|
||||||
|
|
||||||
|
const webhooks = (await this.webhookService.getActiveWebhooks()).filter(x => x.userId === data.renote!.userId && x.on.includes('renote'));
|
||||||
|
for (const webhook of webhooks) {
|
||||||
|
this.queueService.webhookDeliver(webhook, 'renote', {
|
||||||
|
note: noteObj,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
nm.notify();
|
nm.notify();
|
||||||
|
|
||||||
//#region AP deliver
|
//#region AP deliver
|
||||||
|
@ -741,17 +780,17 @@ export class NoteEditService implements OnApplicationShutdown {
|
||||||
detail: true,
|
detail: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
this.globalEventService.publishMainStream(u.id, 'edited', detailPackedNote);
|
this.globalEventService.publishMainStream(u.id, 'mention', detailPackedNote);
|
||||||
|
|
||||||
const webhooks = (await this.webhookService.getActiveWebhooks()).filter(x => x.userId === u.id && x.on.includes('edited'));
|
const webhooks = (await this.webhookService.getActiveWebhooks()).filter(x => x.userId === u.id && x.on.includes('mention'));
|
||||||
for (const webhook of webhooks) {
|
for (const webhook of webhooks) {
|
||||||
this.queueService.webhookDeliver(webhook, 'edited', {
|
this.queueService.webhookDeliver(webhook, 'mention', {
|
||||||
note: detailPackedNote,
|
note: detailPackedNote,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create notification
|
// Create notification
|
||||||
nm.push(u.id, 'edited');
|
nm.push(u.id, 'mention');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -20,8 +20,8 @@ import type { OnModuleInit } from '@nestjs/common';
|
||||||
import type { UserEntityService } from './UserEntityService.js';
|
import type { UserEntityService } from './UserEntityService.js';
|
||||||
import type { NoteEntityService } from './NoteEntityService.js';
|
import type { NoteEntityService } from './NoteEntityService.js';
|
||||||
|
|
||||||
const NOTE_REQUIRED_NOTIFICATION_TYPES = new Set(['note', 'mention', 'reply', 'renote', 'quote', 'reaction', 'pollEnded', 'edited'] as (typeof notificationTypes[number])[]);
|
const NOTE_REQUIRED_NOTIFICATION_TYPES = new Set(['note', 'mention', 'reply', 'renote', 'quote', 'reaction', 'pollEnded'] as (typeof notificationTypes[number])[]);
|
||||||
const NOTE_REQUIRED_GROUPED_NOTIFICATION_TYPES = new Set(['note', 'mention', 'reply', 'renote', 'renote:grouped', 'quote', 'reaction', 'reaction:grouped', 'pollEnded', 'edited']);
|
const NOTE_REQUIRED_GROUPED_NOTIFICATION_TYPES = new Set(['note', 'mention', 'reply', 'renote', 'renote:grouped', 'quote', 'reaction', 'reaction:grouped', 'pollEnded']);
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class NotificationEntityService implements OnModuleInit {
|
export class NotificationEntityService implements OnModuleInit {
|
||||||
|
|
|
@ -107,12 +107,6 @@ export type MiNotification = {
|
||||||
type: 'test';
|
type: 'test';
|
||||||
id: string;
|
id: string;
|
||||||
createdAt: string;
|
createdAt: string;
|
||||||
} | {
|
|
||||||
type: 'edited';
|
|
||||||
id: string;
|
|
||||||
createdAt: string;
|
|
||||||
notifierId: MiUser['id'];
|
|
||||||
noteId: MiNote['id'];
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export type MiGroupedNotification = MiNotification | {
|
export type MiGroupedNotification = MiNotification | {
|
||||||
|
|
|
@ -7,7 +7,7 @@ import { PrimaryColumn, Entity, Index, JoinColumn, Column, ManyToOne } from 'typ
|
||||||
import { id } from './util/id.js';
|
import { id } from './util/id.js';
|
||||||
import { MiUser } from './User.js';
|
import { MiUser } from './User.js';
|
||||||
|
|
||||||
export const webhookEventTypes = ['mention', 'unfollow', 'follow', 'followed', 'note', 'reply', 'renote', 'reaction', 'edited'] as const;
|
export const webhookEventTypes = ['mention', 'unfollow', 'follow', 'followed', 'note', 'reply', 'renote', 'reaction'] as const;
|
||||||
|
|
||||||
@Entity('webhook')
|
@Entity('webhook')
|
||||||
export class MiWebhook {
|
export class MiWebhook {
|
||||||
|
|
|
@ -318,31 +318,6 @@ export const packedNotificationSchema = {
|
||||||
optional: false, nullable: false,
|
optional: false, nullable: false,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}, {
|
|
||||||
type: 'object',
|
|
||||||
properties: {
|
|
||||||
...baseSchema.properties,
|
|
||||||
type: {
|
|
||||||
type: 'string',
|
|
||||||
optional: false, nullable: false,
|
|
||||||
enum: ['edited'],
|
|
||||||
},
|
|
||||||
user: {
|
|
||||||
type: 'object',
|
|
||||||
ref: 'UserLite',
|
|
||||||
optional: false, nullable: false,
|
|
||||||
},
|
|
||||||
userId: {
|
|
||||||
type: 'string',
|
|
||||||
optional: false, nullable: false,
|
|
||||||
format: 'id',
|
|
||||||
},
|
|
||||||
note: {
|
|
||||||
type: 'object',
|
|
||||||
ref: 'Note',
|
|
||||||
optional: false, nullable: false,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}, {
|
}, {
|
||||||
type: 'object',
|
type: 'object',
|
||||||
properties: {
|
properties: {
|
||||||
|
|
|
@ -164,7 +164,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
||||||
groupedNotifications = groupedNotifications.slice(0, ps.limit);
|
groupedNotifications = groupedNotifications.slice(0, ps.limit);
|
||||||
|
|
||||||
const noteIds = groupedNotifications
|
const noteIds = groupedNotifications
|
||||||
.filter((notification): notification is FilterUnionByProperty<MiNotification, 'type', 'mention' | 'reply' | 'quote' | 'edited'> => ['mention', 'reply', 'quote', 'edited'].includes(notification.type))
|
.filter((notification): notification is FilterUnionByProperty<MiNotification, 'type', 'mention' | 'reply' | 'quote'> => ['mention', 'reply', 'quote'].includes(notification.type))
|
||||||
.map(notification => notification.noteId!);
|
.map(notification => notification.noteId!);
|
||||||
|
|
||||||
if (noteIds.length > 0) {
|
if (noteIds.length > 0) {
|
||||||
|
|
|
@ -113,7 +113,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
||||||
}
|
}
|
||||||
|
|
||||||
const noteIds = notifications
|
const noteIds = notifications
|
||||||
.filter((notification): notification is FilterUnionByProperty<MiNotification, 'type', 'mention' | 'reply' | 'quote' | 'edited'> => ['mention', 'reply', 'quote', 'edited'].includes(notification.type))
|
.filter((notification): notification is FilterUnionByProperty<MiNotification, 'type', 'mention' | 'reply' | 'quote'> => ['mention', 'reply', 'quote'].includes(notification.type))
|
||||||
.map(notification => notification.noteId);
|
.map(notification => notification.noteId);
|
||||||
|
|
||||||
if (noteIds.length > 0) {
|
if (noteIds.length > 0) {
|
||||||
|
|
|
@ -20,7 +20,7 @@ export function genOpenapiSpec(config: Config, includeSelfRef = false) {
|
||||||
|
|
||||||
externalDocs: {
|
externalDocs: {
|
||||||
description: 'Repository',
|
description: 'Repository',
|
||||||
url: 'https://activitypub.software/TransFem-org/Sharkey',
|
url: 'https://github.com/misskey-dev/misskey',
|
||||||
},
|
},
|
||||||
|
|
||||||
servers: [{
|
servers: [{
|
||||||
|
@ -98,7 +98,7 @@ export function genOpenapiSpec(config: Config, includeSelfRef = false) {
|
||||||
description: desc,
|
description: desc,
|
||||||
externalDocs: {
|
externalDocs: {
|
||||||
description: 'Source code',
|
description: 'Source code',
|
||||||
url: `https://activitypub.software/TransFem-org/Sharkey/-/tree/develop/packages/backend/src/server/api/endpoints/${endpoint.name}.ts`,
|
url: `https://github.com/misskey-dev/misskey/blob/develop/packages/backend/src/server/api/endpoints/${endpoint.name}.ts`,
|
||||||
},
|
},
|
||||||
...(endpoint.meta.tags ? {
|
...(endpoint.meta.tags ? {
|
||||||
tags: [endpoint.meta.tags[0]],
|
tags: [endpoint.meta.tags[0]],
|
||||||
|
|
|
@ -235,7 +235,7 @@ export async function mainBoot() {
|
||||||
|
|
||||||
fetchInstance().then(() => {
|
fetchInstance().then(() => {
|
||||||
const modifiedVersionMustProminentlyOfferInAgplV3Section13Read = miLocalStorage.getItem('modifiedVersionMustProminentlyOfferInAgplV3Section13Read');
|
const modifiedVersionMustProminentlyOfferInAgplV3Section13Read = miLocalStorage.getItem('modifiedVersionMustProminentlyOfferInAgplV3Section13Read');
|
||||||
if (modifiedVersionMustProminentlyOfferInAgplV3Section13Read !== 'true' && instance.repositoryUrl !== 'https://activitypub.software/TransFem-org/Sharkey/') {
|
if (modifiedVersionMustProminentlyOfferInAgplV3Section13Read !== 'true' && instance.repositoryUrl !== 'https://github.com/misskey-dev/misskey') {
|
||||||
popup(defineAsyncComponent(() => import('@/components/MkSourceCodeAvailablePopup.vue')), {}, {}, 'closed');
|
popup(defineAsyncComponent(() => import('@/components/MkSourceCodeAvailablePopup.vue')), {}, {}, 'closed');
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
@ -6,7 +6,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
<template>
|
<template>
|
||||||
<div :class="$style.root">
|
<div :class="$style.root">
|
||||||
<div :class="$style.head">
|
<div :class="$style.head">
|
||||||
<MkAvatar v-if="['pollEnded', 'note', 'edited'].includes(notification.type) && notification.note" :class="$style.icon" :user="notification.note.user" link preview/>
|
<MkAvatar v-if="['pollEnded', 'note'].includes(notification.type) && notification.note" :class="$style.icon" :user="notification.note.user" link preview/>
|
||||||
<MkAvatar v-else-if="['roleAssigned', 'achievementEarned'].includes(notification.type)" :class="$style.icon" :user="$i" link preview/>
|
<MkAvatar v-else-if="['roleAssigned', 'achievementEarned'].includes(notification.type)" :class="$style.icon" :user="$i" link preview/>
|
||||||
<div v-else-if="notification.type === 'reaction:grouped'" :class="[$style.icon, $style.icon_reactionGroup]"><i class="ph-smiley ph-bold ph-lg" style="line-height: 1;"></i></div>
|
<div v-else-if="notification.type === 'reaction:grouped'" :class="[$style.icon, $style.icon_reactionGroup]"><i class="ph-smiley ph-bold ph-lg" style="line-height: 1;"></i></div>
|
||||||
<div v-else-if="notification.type === 'renote:grouped'" :class="[$style.icon, $style.icon_renoteGroup]"><i class="ph-rocket-launch ph-bold ph-lg" style="line-height: 1;"></i></div>
|
<div v-else-if="notification.type === 'renote:grouped'" :class="[$style.icon, $style.icon_renoteGroup]"><i class="ph-rocket-launch ph-bold ph-lg" style="line-height: 1;"></i></div>
|
||||||
|
@ -25,9 +25,8 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
[$style.t_pollEnded]: notification.type === 'pollEnded',
|
[$style.t_pollEnded]: notification.type === 'pollEnded',
|
||||||
[$style.t_achievementEarned]: notification.type === 'achievementEarned',
|
[$style.t_achievementEarned]: notification.type === 'achievementEarned',
|
||||||
[$style.t_roleAssigned]: notification.type === 'roleAssigned' && notification.role.iconUrl == null,
|
[$style.t_roleAssigned]: notification.type === 'roleAssigned' && notification.role.iconUrl == null,
|
||||||
[$style.t_pollEnded]: notification.type === 'edited',
|
|
||||||
}]"
|
}]"
|
||||||
> <!-- we re-use t_pollEnded for "edited" instead of making an identical style -->
|
>
|
||||||
<i v-if="notification.type === 'follow'" class="ph-plus ph-bold ph-lg"></i>
|
<i v-if="notification.type === 'follow'" class="ph-plus ph-bold ph-lg"></i>
|
||||||
<i v-else-if="notification.type === 'receiveFollowRequest'" class="ph-clock ph-bold ph-lg"></i>
|
<i v-else-if="notification.type === 'receiveFollowRequest'" class="ph-clock ph-bold ph-lg"></i>
|
||||||
<i v-else-if="notification.type === 'followRequestAccepted'" class="ph-check ph-bold ph-lg"></i>
|
<i v-else-if="notification.type === 'followRequestAccepted'" class="ph-check ph-bold ph-lg"></i>
|
||||||
|
@ -41,7 +40,6 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
<img v-if="notification.role.iconUrl" style="height: 1.3em; vertical-align: -22%;" :src="notification.role.iconUrl" alt=""/>
|
<img v-if="notification.role.iconUrl" style="height: 1.3em; vertical-align: -22%;" :src="notification.role.iconUrl" alt=""/>
|
||||||
<i v-else class="ph-seal-check ph-bold ph-lg"></i>
|
<i v-else class="ph-seal-check ph-bold ph-lg"></i>
|
||||||
</template>
|
</template>
|
||||||
<i v-else-if="notification.type === 'edited'" class="ph-pencil ph-bold ph-lg"></i>
|
|
||||||
<!-- notification.reaction が null になることはまずないが、ここでoptional chaining使うと一部ブラウザで刺さるので念の為 -->
|
<!-- notification.reaction が null になることはまずないが、ここでoptional chaining使うと一部ブラウザで刺さるので念の為 -->
|
||||||
<MkReactionIcon
|
<MkReactionIcon
|
||||||
v-else-if="notification.type === 'reaction'"
|
v-else-if="notification.type === 'reaction'"
|
||||||
|
@ -63,7 +61,6 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
<span v-else-if="notification.type === 'reaction:grouped'">{{ i18n.tsx._notification.reactedBySomeUsers({ n: notification.reactions.length }) }}</span>
|
<span v-else-if="notification.type === 'reaction:grouped'">{{ i18n.tsx._notification.reactedBySomeUsers({ n: notification.reactions.length }) }}</span>
|
||||||
<span v-else-if="notification.type === 'renote:grouped'">{{ i18n.tsx._notification.renotedBySomeUsers({ n: notification.users.length }) }}</span>
|
<span v-else-if="notification.type === 'renote:grouped'">{{ i18n.tsx._notification.renotedBySomeUsers({ n: notification.users.length }) }}</span>
|
||||||
<span v-else-if="notification.type === 'app'">{{ notification.header }}</span>
|
<span v-else-if="notification.type === 'app'">{{ notification.header }}</span>
|
||||||
<span v-else-if="notification.type === 'edited'">{{ i18n.ts._notification.edited }}</span>
|
|
||||||
<MkTime v-if="withTime" :time="notification.createdAt" :class="$style.headerTime"/>
|
<MkTime v-if="withTime" :time="notification.createdAt" :class="$style.headerTime"/>
|
||||||
</header>
|
</header>
|
||||||
<div>
|
<div>
|
||||||
|
@ -134,12 +131,6 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
<MkAvatar :class="$style.reactionsItemAvatar" :user="user" link preview/>
|
<MkAvatar :class="$style.reactionsItemAvatar" :user="user" link preview/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<MkA v-else-if="notification.type === 'edited'" :class="$style.text" :to="notePage(notification.note)" :title="getNoteSummary(notification.note)">
|
|
||||||
<i class="ph-quotes ph-bold ph-lg" :class="$style.quote"></i>
|
|
||||||
<Mfm :text="getNoteSummary(notification.note)" :plain="true" :nowrap="true" :author="notification.note.user"/>
|
|
||||||
<i class="ph-quotes ph-bold ph-lg" :class="$style.quote"></i>
|
|
||||||
</MkA>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -71,7 +71,6 @@ function close() {
|
||||||
width: calc(100% - (var(--margin) * 2));
|
width: calc(100% - (var(--margin) * 2));
|
||||||
max-width: 500px;
|
max-width: 500px;
|
||||||
display: flex;
|
display: flex;
|
||||||
backdrop-filter: var(--blur, blur(15px));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.icon {
|
.icon {
|
||||||
|
|
|
@ -27,39 +27,6 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
<div v-if="$i != null" style="text-align: center;">
|
<div v-if="$i != null" style="text-align: center;">
|
||||||
<MkButton primary rounded inline @click="iLoveMisskey">I <Mfm text="$[jelly ❤]"/> #Sharkey</MkButton>
|
<MkButton primary rounded inline @click="iLoveMisskey">I <Mfm text="$[jelly ❤]"/> #Sharkey</MkButton>
|
||||||
</div>
|
</div>
|
||||||
<FormSection v-if="instance.repositoryUrl !== 'https://activitypub.software/TransFem-org/Sharkey/'">
|
|
||||||
<div class="_gaps_s">
|
|
||||||
<MkInfo>
|
|
||||||
{{ i18n.tsx._aboutMisskey.thisIsModifiedVersion({ name: instance.name }) }}
|
|
||||||
</MkInfo>
|
|
||||||
<FormLink v-if="instance.repositoryUrl" :to="instance.repositoryUrl" external>
|
|
||||||
<template #icon><i class="ph-code ph-bold ph-lg"></i></template>
|
|
||||||
{{ i18n.ts._aboutMisskey.source }}
|
|
||||||
</FormLink>
|
|
||||||
<FormLink v-if="instance.providesTarball" :to="`/tarball/sharkey-${version}.tar.gz`" external>
|
|
||||||
<template #icon><i class="ph-download ph-bold ph-lg"></i></template>
|
|
||||||
{{ i18n.ts._aboutMisskey.source }}
|
|
||||||
<template #suffix>Tarball</template>
|
|
||||||
</FormLink>
|
|
||||||
<MkInfo v-if="!instance.repositoryUrl && !instance.providesTarball" warn>
|
|
||||||
{{ i18n.ts.sourceCodeIsNotYetProvided }}
|
|
||||||
</MkInfo>
|
|
||||||
</div>
|
|
||||||
</FormSection>
|
|
||||||
<FormSection>
|
|
||||||
<div class="_gaps_s">
|
|
||||||
<FormLink to="https://activitypub.software/TransFem-org/Sharkey/" external>
|
|
||||||
<template #icon><i class="ph-code ph-bold ph-lg"></i></template>
|
|
||||||
{{ i18n.ts._aboutMisskey.source }} ({{ i18n.ts._aboutMisskey.original_sharkey }})
|
|
||||||
<template #suffix>GitLab</template>
|
|
||||||
</FormLink>
|
|
||||||
<FormLink to="https://ko-fi.com/transfem" external>
|
|
||||||
<template #icon><i class="ph-piggy-bank ph-bold ph-lg"></i></template>
|
|
||||||
{{ i18n.ts._aboutMisskey.donate_sharkey }}
|
|
||||||
<template #suffix>Ko-Fi</template>
|
|
||||||
</FormLink>
|
|
||||||
</div>
|
|
||||||
</FormSection>
|
|
||||||
<FormSection>
|
<FormSection>
|
||||||
<div class="_gaps_s">
|
<div class="_gaps_s">
|
||||||
<FormLink to="https://github.com/misskey-dev/misskey" external>
|
<FormLink to="https://github.com/misskey-dev/misskey" external>
|
||||||
|
@ -74,6 +41,31 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
</FormLink>
|
</FormLink>
|
||||||
</div>
|
</div>
|
||||||
</FormSection>
|
</FormSection>
|
||||||
|
<FormSection v-if="instance.repositoryUrl !== 'https://github.com/misskey-dev/misskey'">
|
||||||
|
<div class="_gaps_s">
|
||||||
|
<MkInfo>
|
||||||
|
{{ i18n.tsx._aboutMisskey.thisIsModifiedVersion({ name: instance.name }) }}
|
||||||
|
</MkInfo>
|
||||||
|
<FormLink v-if="instance.repositoryUrl" :to="instance.repositoryUrl" external>
|
||||||
|
<template #icon><i class="ph-code ph-bold ph-lg"></i></template>
|
||||||
|
{{ i18n.ts._aboutMisskey.source }}
|
||||||
|
<template #suffix>GitLab</template>
|
||||||
|
</FormLink>
|
||||||
|
<FormLink to="https://ko-fi.com/transfem" external>
|
||||||
|
<template #icon><i class="ph-piggy-bank ph-bold ph-lg"></i></template>
|
||||||
|
{{ i18n.ts._aboutMisskey.donate }}
|
||||||
|
<template #suffix>Ko-Fi</template>
|
||||||
|
</FormLink>
|
||||||
|
<FormLink v-if="instance.providesTarball" :to="`/tarball/sharkey-${version}.tar.gz`" external>
|
||||||
|
<template #icon><i class="ph-download ph-bold ph-lg"></i></template>
|
||||||
|
{{ i18n.ts._aboutMisskey.source }}
|
||||||
|
<template #suffix>Tarball</template>
|
||||||
|
</FormLink>
|
||||||
|
<MkInfo v-if="!instance.repositoryUrl && !instance.providesTarball" warn>
|
||||||
|
{{ i18n.ts.sourceCodeIsNotYetProvided }}
|
||||||
|
</MkInfo>
|
||||||
|
</div>
|
||||||
|
</FormSection>
|
||||||
<FormSection>
|
<FormSection>
|
||||||
<template #label>{{ i18n.ts._aboutMisskey.projectMembers }}</template>
|
<template #label>{{ i18n.ts._aboutMisskey.projectMembers }}</template>
|
||||||
<div :class="$style.contributors" style="margin-bottom: 8px;">
|
<div :class="$style.contributors" style="margin-bottom: 8px;">
|
||||||
|
|
|
@ -3,26 +3,21 @@
|
||||||
* SPDX-License-Identifier: AGPL-3.0-only
|
* SPDX-License-Identifier: AGPL-3.0-only
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
const enRegex1 = /(?<=n)a/gi;
|
||||||
|
const enRegex2 = /(?<=morn)ing/gi;
|
||||||
|
const enRegex3 = /(?<=every)one/gi;
|
||||||
const koRegex1 = /[나-낳]/g;
|
const koRegex1 = /[나-낳]/g;
|
||||||
const koRegex2 = /(다$)|(다(?=\.))|(다(?= ))|(다(?=!))|(다(?=\?))/gm;
|
const koRegex2 = /(다$)|(다(?=\.))|(다(?= ))|(다(?=!))|(다(?=\?))/gm;
|
||||||
const koRegex3 = /(야(?=\?))|(야$)|(야(?= ))/gm;
|
const koRegex3 = /(야(?=\?))|(야$)|(야(?= ))/gm;
|
||||||
|
|
||||||
function ifAfter(prefix, fn) {
|
|
||||||
const preLen = prefix.length;
|
|
||||||
const regex = new RegExp(prefix,'i');
|
|
||||||
return (x,pos,string) => {
|
|
||||||
return pos > 0 && string.substring(pos-preLen,pos).match(regex) ? fn(x) : x;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function nyaize(text: string): string {
|
export function nyaize(text: string): string {
|
||||||
return text
|
return text
|
||||||
// ja-JP
|
// ja-JP
|
||||||
.replaceAll('な', 'にゃ').replaceAll('ナ', 'ニャ').replaceAll('ナ', 'ニャ')
|
.replaceAll('な', 'にゃ').replaceAll('ナ', 'ニャ').replaceAll('ナ', 'ニャ')
|
||||||
// en-US
|
// en-US
|
||||||
.replace(/a/gi, ifAfter('n', x => x === 'A' ? 'YA' : 'ya'))
|
.replace(enRegex1, x => x === 'A' ? 'YA' : 'ya')
|
||||||
.replace(/ing/gi, ifAfter('morn', x => x === 'ING' ? 'YAN' : 'yan'))
|
.replace(enRegex2, x => x === 'ING' ? 'YAN' : 'yan')
|
||||||
.replace(/one/gi, ifAfter('every', x => x === 'ONE' ? 'NYAN' : 'nyan'))
|
.replace(enRegex3, x => x === 'ONE' ? 'NYAN' : 'nyan')
|
||||||
// ko-KR
|
// ko-KR
|
||||||
.replace(koRegex1, match => String.fromCharCode(
|
.replace(koRegex1, match => String.fromCharCode(
|
||||||
match.charCodeAt(0)! + '냐'.charCodeAt(0) - '나'.charCodeAt(0),
|
match.charCodeAt(0)! + '냐'.charCodeAt(0) - '나'.charCodeAt(0),
|
||||||
|
|
|
@ -1,32 +0,0 @@
|
||||||
import { describe, test, assert, afterEach } from 'vitest';
|
|
||||||
import { nyaize } from '@/scripts/nyaize.js';
|
|
||||||
|
|
||||||
function runTests(cases) {
|
|
||||||
for (const c of cases) {
|
|
||||||
const [input,expected] = c;
|
|
||||||
const got = nyaize(input);
|
|
||||||
assert.strictEqual(got, expected);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
describe('nyaize', () => {
|
|
||||||
test('ja-JP', () => {
|
|
||||||
runTests([
|
|
||||||
['きれいな','きれいにゃ'],
|
|
||||||
['ナナナ', 'ニャニャニャ'],
|
|
||||||
['ナナ','ニャニャ'],
|
|
||||||
]);
|
|
||||||
});
|
|
||||||
test('en-US', () => {
|
|
||||||
runTests([
|
|
||||||
['bar','bar'],
|
|
||||||
['banana','banyanya'],
|
|
||||||
['booting','booting'],
|
|
||||||
['morning','mornyan'],
|
|
||||||
['mmmorning','mmmornyan'],
|
|
||||||
['someone','someone'],
|
|
||||||
['everyone','everynyan'],
|
|
||||||
['foreveryone','foreverynyan'],
|
|
||||||
]);
|
|
||||||
});
|
|
||||||
});
|
|
|
@ -4273,17 +4273,6 @@ export type components = {
|
||||||
body: string;
|
body: string;
|
||||||
header: string;
|
header: string;
|
||||||
icon: string;
|
icon: string;
|
||||||
} | {
|
|
||||||
/** Format: id */
|
|
||||||
id: string;
|
|
||||||
/** Format: date-time */
|
|
||||||
createdAt: string;
|
|
||||||
/** @enum {string} */
|
|
||||||
type: 'edited';
|
|
||||||
user: components['schemas']['UserLite'];
|
|
||||||
/** Format: id */
|
|
||||||
userId: string;
|
|
||||||
note: components['schemas']['Note'];
|
|
||||||
} | {
|
} | {
|
||||||
/** Format: id */
|
/** Format: id */
|
||||||
id: string;
|
id: string;
|
||||||
|
@ -19522,7 +19511,7 @@ export type operations = {
|
||||||
url: string;
|
url: string;
|
||||||
/** @default */
|
/** @default */
|
||||||
secret?: string;
|
secret?: string;
|
||||||
on: ('mention' | 'unfollow' | 'follow' | 'followed' | 'note' | 'reply' | 'renote' | 'reaction' | 'edited')[];
|
on: ('mention' | 'unfollow' | 'follow' | 'followed' | 'note' | 'reply' | 'renote' | 'reaction')[];
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
@ -19536,7 +19525,7 @@ export type operations = {
|
||||||
/** Format: misskey:id */
|
/** Format: misskey:id */
|
||||||
userId: string;
|
userId: string;
|
||||||
name: string;
|
name: string;
|
||||||
on: ('mention' | 'unfollow' | 'follow' | 'followed' | 'note' | 'reply' | 'renote' | 'reaction' | 'edited')[];
|
on: ('mention' | 'unfollow' | 'follow' | 'followed' | 'note' | 'reply' | 'renote' | 'reaction')[];
|
||||||
url: string;
|
url: string;
|
||||||
secret: string;
|
secret: string;
|
||||||
active: boolean;
|
active: boolean;
|
||||||
|
@ -19595,7 +19584,7 @@ export type operations = {
|
||||||
/** Format: misskey:id */
|
/** Format: misskey:id */
|
||||||
userId: string;
|
userId: string;
|
||||||
name: string;
|
name: string;
|
||||||
on: ('mention' | 'unfollow' | 'follow' | 'followed' | 'note' | 'reply' | 'renote' | 'reaction' | 'edited')[];
|
on: ('mention' | 'unfollow' | 'follow' | 'followed' | 'note' | 'reply' | 'renote' | 'reaction')[];
|
||||||
url: string;
|
url: string;
|
||||||
secret: string;
|
secret: string;
|
||||||
active: boolean;
|
active: boolean;
|
||||||
|
@ -19662,7 +19651,7 @@ export type operations = {
|
||||||
/** Format: misskey:id */
|
/** Format: misskey:id */
|
||||||
userId: string;
|
userId: string;
|
||||||
name: string;
|
name: string;
|
||||||
on: ('mention' | 'unfollow' | 'follow' | 'followed' | 'note' | 'reply' | 'renote' | 'reaction' | 'edited')[];
|
on: ('mention' | 'unfollow' | 'follow' | 'followed' | 'note' | 'reply' | 'renote' | 'reaction')[];
|
||||||
url: string;
|
url: string;
|
||||||
secret: string;
|
secret: string;
|
||||||
active: boolean;
|
active: boolean;
|
||||||
|
@ -19720,7 +19709,7 @@ export type operations = {
|
||||||
url: string;
|
url: string;
|
||||||
/** @default */
|
/** @default */
|
||||||
secret?: string;
|
secret?: string;
|
||||||
on: ('mention' | 'unfollow' | 'follow' | 'followed' | 'note' | 'reply' | 'renote' | 'reaction' | 'edited')[];
|
on: ('mention' | 'unfollow' | 'follow' | 'followed' | 'note' | 'reply' | 'renote' | 'reaction')[];
|
||||||
active: boolean;
|
active: boolean;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
export const notificationTypes = ['note', 'follow', 'mention', 'reply', 'renote', 'quote', 'reaction', 'pollVote', 'pollEnded', 'receiveFollowRequest', 'followRequestAccepted', 'groupInvited', 'app', 'roleAssigned', 'achievementEarned', 'edited'] as const;
|
export const notificationTypes = ['note', 'follow', 'mention', 'reply', 'renote', 'quote', 'reaction', 'pollVote', 'pollEnded', 'receiveFollowRequest', 'followRequestAccepted', 'groupInvited', 'app', 'roleAssigned', 'achievementEarned'] as const;
|
||||||
|
|
||||||
export const noteVisibilities = ['public', 'home', 'followers', 'specified'] as const;
|
export const noteVisibilities = ['public', 'home', 'followers', 'specified'] as const;
|
||||||
|
|
||||||
|
|
|
@ -56,7 +56,6 @@ export type Channels = {
|
||||||
readAntenna: (payload: Antenna) => void;
|
readAntenna: (payload: Antenna) => void;
|
||||||
receiveFollowRequest: (payload: User) => void;
|
receiveFollowRequest: (payload: User) => void;
|
||||||
announcementCreated: (payload: AnnouncementCreated) => void;
|
announcementCreated: (payload: AnnouncementCreated) => void;
|
||||||
edited: (payload: Note) => void;
|
|
||||||
};
|
};
|
||||||
receives: null;
|
receives: null;
|
||||||
};
|
};
|
||||||
|
|
|
@ -232,14 +232,6 @@ async function composeNotification(data: PushNotificationDataMap[keyof PushNotif
|
||||||
data,
|
data,
|
||||||
}];
|
}];
|
||||||
|
|
||||||
case 'edited':
|
|
||||||
return [t('_notification.edited', { name: getUserName(data.body.user) }), {
|
|
||||||
body: data.body.note.text ?? '',
|
|
||||||
icon: data.body.user.avatarUrl,
|
|
||||||
badge: iconUrl('messages'),
|
|
||||||
data,
|
|
||||||
}];
|
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
|
@ -133,9 +133,6 @@ globalThis.addEventListener('notificationclick', (ev: ServiceWorkerGlobalScopeEv
|
||||||
case 'showFollowRequests':
|
case 'showFollowRequests':
|
||||||
client = await swos.openClient('push', '/my/follow-requests', loginId);
|
client = await swos.openClient('push', '/my/follow-requests', loginId);
|
||||||
break;
|
break;
|
||||||
case 'edited':
|
|
||||||
if ('note' in data.body) client = await swos.openPost({ reply: data.body.note }, loginId);
|
|
||||||
break;
|
|
||||||
default:
|
default:
|
||||||
switch (data.body.type) {
|
switch (data.body.type) {
|
||||||
case 'receiveFollowRequest':
|
case 'receiveFollowRequest':
|
||||||
|
|
Loading…
Reference in a new issue