Skip to content

Commit

Permalink
WIP
Browse files Browse the repository at this point in the history
  • Loading branch information
penginn-net committed Oct 20, 2024
1 parent d37bade commit 7a7a051
Show file tree
Hide file tree
Showing 24 changed files with 357 additions and 6 deletions.
26 changes: 26 additions & 0 deletions locales/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12024,6 +12024,32 @@ export interface Locale extends ILocale {
*/
"confirm": string;
};
"_searchbility": {
/**
* 検索可能範囲
*/
"tooltip": string;
/**
* が検索できます
*/
"canSearch": string;
/**
* すべてのユーザー
*/
"public": string;
/**
* フォロワーと反応した人
*/
"followersAndReacted": string;
/**
* 反応した人
*/
"reactedOnly": string;
/**
* あなただけ
*/
"private": string;
};
}
declare const locales: {
[lang: string]: Locale;
Expand Down
7 changes: 7 additions & 0 deletions locales/ja-JP.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3214,3 +3214,10 @@ _renoteConfirm:
title: "このノートはリノートしたばかりです"
caption: "リノートしますか?"
confirm: 'リノートする'
_searchbility:
tooltip: "検索可能範囲"
canSearch: "が検索できます"
public: "すべてのユーザー"
followersAndReacted: "フォロワーと反応した人"
reactedOnly: "反応した人"
private: "あなただけ"
20 changes: 20 additions & 0 deletions packages/backend/migration/1729457336777-AddSearchable.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
/*
* SPDX-FileCopyrightText: syuilo and misskey-project, yojo-art team
* SPDX-License-Identifier: AGPL-3.0-only
*/
export class AddSearchable1729457336777 {
name = 'AddSearchable1729457336777';

async up(queryRunner) {
await queryRunner.query('ALTER TABLE "user" ADD "searchableBy" "public"."user_searchableby_enum"');
await queryRunner.query('CREATE TYPE "public"."note_searchableby_enum" AS ENUM(\'public\', \'followersAndReacted\', \'reactedOnly\', \'private\')');
await queryRunner.query('ALTER TABLE "note" ADD "searchableBy" "public"."note_searchableby_enum"');
await queryRunner.query('CREATE INDEX "IDX_3932b42da4cf440203d2013649" ON "user" ("searchableBy") ');
}

async down(queryRunner) {
await queryRunner.query('ALTER TABLE "note" DROP COLUMN "searchableBy"');
await queryRunner.query('DROP TYPE "public"."note_searchableby_enum"');
await queryRunner.query('ALTER TABLE "user" DROP COLUMN "searchableBy"');
}
};
3 changes: 3 additions & 0 deletions packages/backend/src/core/NoteCreateService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ import { isReply } from '@/misc/is-reply.js';
import { trackPromise } from '@/misc/promise-tracker.js';
import { IdentifiableError } from '@/misc/identifiable-error.js';
import { MiNoteSchedule } from '@/models/_.js';
import { searchableTypes } from '../types.js';

type NotificationType = 'reply' | 'renote' | 'quote' | 'mention';

Expand Down Expand Up @@ -146,6 +147,7 @@ type Option = {
disableRightClick?: boolean | null;
cw?: string | null;
visibility?: string | null;
searchableBy: string | null,
visibleUsers?: MinimumUser[] | null;
channel?: MiChannel | null;
apMentions?: MinimumUser[] | null;
Expand Down Expand Up @@ -423,6 +425,7 @@ export class NoteCreateService implements OnApplicationShutdown {
reactionAcceptance: data.reactionAcceptance,
disableRightClick: data.disableRightClick!,
visibility: data.visibility as any,
searchableBy: data.searchableBy as any,
visibleUserIds: data.visibility === 'specified'
? data.visibleUsers
? data.visibleUsers.map(u => u.id)
Expand Down
18 changes: 17 additions & 1 deletion packages/backend/src/core/activitypub/ApAudienceService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import promiseLimit from 'promise-limit';
import type { MiRemoteUser, MiUser } from '@/models/User.js';
import { concat, unique } from '@/misc/prelude/array.js';
import { bindThis } from '@/decorators.js';
import { searchableTypes } from '@/types.js';
import { getApIds } from './type.js';
import { ApPersonService } from './models/ApPersonService.js';
import type { ApObject } from './type.js';
Expand Down Expand Up @@ -72,7 +73,22 @@ export class ApAudienceService {
visibleUsers: mentionedUsers,
};
}

public async parseSearchableBy (actor: MiRemoteUser, searchableBy?: string[]): Promise<string | null> {
if (!searchableBy) {
return null;
}
console.log(searchableBy);
if (searchableBy.includes('https://www.w3.org/ns/activitystreams#Public')) {
return searchableTypes[0];
} else if (actor.followersUri && searchableBy.includes(actor.followersUri)) {
return searchableTypes[1];
} else if (searchableBy.includes(actor.uri)) {
return searchableTypes[2];
} else if (searchableBy.includes('as:Limited') || searchableBy.includes('kmyblue:Limited')) {
return searchableTypes[3];
}
return null;
}
@bindThis
private groupingAudience(ids: string[], actor: MiRemoteUser): GroupedAudience {
const groups: GroupedAudience = {
Expand Down
16 changes: 15 additions & 1 deletion packages/backend/src/core/activitypub/ApRendererService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import type { UsersRepository, UserProfilesRepository, NotesRepository, DriveFil
import { bindThis } from '@/decorators.js';
import { CustomEmojiService } from '@/core/CustomEmojiService.js';
import { IdService } from '@/core/IdService.js';
import { searchableTypes } from '@/types.js';
import { JsonLdService } from './JsonLdService.js';
import { ApMfmService } from './ApMfmService.js';
import { CONTEXT } from './misc/contexts.js';
Expand Down Expand Up @@ -378,7 +379,18 @@ export class ApRendererService {
} else {
to = mentions;
}

let searchableBy: string[]| undefined = [];
if (note.searchableBy === null) {
searchableBy = undefined;
} else if (note.searchableBy === searchableTypes[0]) {
searchableBy = ['https://www.w3.org/ns/activitystreams#Public'];
} else if (note.searchableBy === searchableTypes[1]) {
searchableBy = [`${this.config.url}/users/${note.userId}/followers`];
} else if (note.searchableBy === searchableTypes[2]) {
searchableBy = [`${this.config.url}/users/${note.userId}`];
} else { // if (note.searchableBy === searchableTypes[3])
searchableBy = ['as:Limited', 'kmyblue:Limited'];
}
const mentionedUsers = note.mentions.length > 0 ? await this.usersRepository.findBy({
id: In(note.mentions),
}) : [];
Expand Down Expand Up @@ -462,6 +474,7 @@ export class ApRendererService {
updated: note.updatedAt?.toISOString() ?? undefined,
to,
cc,
...(searchableBy ? { searchableBy: searchableBy } : {}),
inReplyTo,
attachment: files.map(x => this.renderDocument(x)),
sensitive: note.cw != null || files.some(file => file.isSensitive),
Expand Down Expand Up @@ -540,6 +553,7 @@ export class ApRendererService {
manuallyApprovesFollowers: user.isLocked,
discoverable: user.isExplorable,
indexable: user.isIndexable,
searchableBy: [`${this.config.url}/users/${user.id}`],
publicKey: this.renderKey(user, keypair, '#main-key'),
isCat: user.isCat,
attachment: attachment.length ? attachment : undefined,
Expand Down
6 changes: 6 additions & 0 deletions packages/backend/src/core/activitypub/misc/contexts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -544,6 +544,12 @@ const extension_context_definition = {
featured: 'toot:featured',
discoverable: 'toot:discoverable',
indexable: 'toot:indexable',
// Fefibird
fedibird: 'http://fedibird.com/ns#',
searchableBy: {
'@id': 'fedibird:searchableBy',
'@type': '@id',
},
// schema
schema: 'http://schema.org#',
PropertyValue: 'schema:PropertyValue',
Expand Down
4 changes: 4 additions & 0 deletions packages/backend/src/core/activitypub/models/ApNoteService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -208,6 +208,9 @@ export class ApNoteService {
}

const noteAudience = await this.apAudienceService.parseAudience(actor, note.to, note.cc, resolver);
const searchableBy = await this.apAudienceService.parseSearchableBy(actor, note.searchableBy);
this.logger.info(JSON.stringify(note.searchableBy));
this.logger.info(actor.uri);
let visibility = noteAudience.visibility;
const visibleUsers = noteAudience.visibleUsers;

Expand Down Expand Up @@ -341,6 +344,7 @@ export class ApNoteService {
disableRightClick: false,
visibility,
visibleUsers,
searchableBy: searchableBy,
apMentions,
apHashtags,
apEmojis,
Expand Down
15 changes: 13 additions & 2 deletions packages/backend/src/core/activitypub/models/ApPersonService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ import { DriveFileEntityService } from '@/core/entities/DriveFileEntityService.j
import type { AccountMoveService } from '@/core/AccountMoveService.js';
import { checkHttps } from '@/misc/check-https.js';
import { AvatarDecorationService } from '@/core/AvatarDecorationService.js';
import { searchableTypes } from '@/types.js';
import { getApId, getApType, getOneApHrefNullable, isActor, isCollection, isCollectionOrOrderedCollection, isPropertyValue } from '../type.js';
import { extractApHashtags } from './tag.js';
import type { OnModuleInit } from '@nestjs/common';
Expand Down Expand Up @@ -409,6 +410,7 @@ export class ApPersonService implements OnModuleInit {
alsoKnownAs: person.alsoKnownAs,
isExplorable: person.discoverable,
isIndexable: person.indexable ?? true,
searchableBy: this.getSearchableType(tags),
username: person.preferredUsername,
usernameLower: person.preferredUsername?.toLowerCase(),
host,
Expand Down Expand Up @@ -649,10 +651,10 @@ export class ApPersonService implements OnModuleInit {
}
}
const role_policy = await this.roleService.getUserPolicies(exist.id);

this.logger.info(JSON.stringify(tags));
const updates = {
lastFetchedAt: new Date(),
isIndexable: person.indexable ?? true,
searchableBy: this.getSearchableType(tags),
inbox: person.inbox,
sharedInbox: person.sharedInbox ?? person.endpoints?.sharedInbox,
outbox: typeof person.outbox === 'string' ? person.outbox : null,
Expand Down Expand Up @@ -1001,4 +1003,13 @@ export class ApPersonService implements OnModuleInit {

return false;
}

@bindThis
private getSearchableType(tags: string[]): 'public' | 'followersAndReacted' | 'reactedOnly' | 'private' | null {
if (tags.includes('searchable_by_all_users')) return searchableTypes[0];
if (tags.includes('searchable_by_followers_only')) return searchableTypes[1];
if (tags.includes('searchable_by_reacted_users_only')) return searchableTypes[2];
if (tags.includes('searchable_by_nobody')) return searchableTypes[3];
return null;
}
}
1 change: 1 addition & 0 deletions packages/backend/src/core/activitypub/type.ts
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,7 @@ export interface IPost extends IObject {
_misskey_content?: string;
quoteUrl?: string;
_misskey_talk?: boolean;
searchableBy?: string[];
}

export interface IQuestion extends IObject {
Expand Down
1 change: 1 addition & 0 deletions packages/backend/src/core/entities/NoteEntityService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -347,6 +347,7 @@ export class NoteEntityService implements OnModuleInit {
text: text,
cw: note.cw,
visibility: note.visibility,
searchableBy: note.searchableBy,
localOnly: note.localOnly,
reactionAcceptance: note.reactionAcceptance,
visibleUserIds: note.visibility === 'specified' ? note.visibleUserIds : undefined,
Expand Down
2 changes: 2 additions & 0 deletions packages/backend/src/core/entities/UserEntityService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -529,6 +529,8 @@ export class UserEntityService implements OnModuleInit {
}))) : [],
isBot: user.isBot,
isCat: user.isCat,
isIndexable: user.isIndexable,
searchableBy: user.searchableBy,
instance: user.host ? this.federatedInstanceService.federatedInstanceCache.fetch(user.host).then(instance => instance ? {
name: instance.name,
softwareName: instance.softwareName,
Expand Down
15 changes: 14 additions & 1 deletion packages/backend/src/models/Note.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
*/

import { Entity, Index, JoinColumn, Column, PrimaryColumn, ManyToOne } from 'typeorm';
import { noteVisibilities } from '@/types.js';
import { noteVisibilities, searchableTypes } from '@/types.js';
import { id } from './util/id.js';
import { MiUser } from './User.js';
import { MiChannel } from './Channel.js';
Expand Down Expand Up @@ -146,6 +146,19 @@ export class MiNote {
@Column('enum', { enum: noteVisibilities })
public visibility: typeof noteVisibilities[number];

/**
* public ... だれでも
* followers ... フォロワーのみ
* reacted ... 返信かリアクションしたユーザーのみ
* null ... ユーザーのsearchableByを見る
*/
@Column('enum',
{
enum: searchableTypes,
nullable: true,
})
public searchableBy: typeof searchableTypes[number] | null;

@Index({ unique: true })
@Column('varchar', {
length: 512, nullable: true,
Expand Down
14 changes: 14 additions & 0 deletions packages/backend/src/models/User.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
*/

import { Entity, Column, Index, OneToOne, JoinColumn, PrimaryColumn } from 'typeorm';
import { searchableTypes } from '@/types.js';
import { id } from './util/id.js';
import { MiDriveFile } from './DriveFile.js';

Expand Down Expand Up @@ -201,6 +202,19 @@ export class MiUser {
})
public isIndexable: boolean;

/**
* public ... だれでも
* followers ... フォロワーのみ
* reacted ... 返信かリアクションしたユーザーのみ
* null ... isIndexableを見る
*/
@Column('enum',
{
enum: searchableTypes,
nullable: true,
})
public searchableBy: typeof searchableTypes[number] | null;

@Column('boolean', {
default: false,
})
Expand Down
2 changes: 1 addition & 1 deletion packages/backend/src/server/ActivityPubServerService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ export class ActivityPubServerService {
reply.code(401);
return;
}

console.info(JSON.stringify(request));
if (signature.params.headers.indexOf('host') === -1
|| request.headers.host !== this.config.host) {
// Host not specified or not match.
Expand Down
3 changes: 3 additions & 0 deletions packages/backend/src/server/api/endpoints/notes/create.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import { isQuote, isRenote } from '@/misc/is-renote.js';
import { MetaService } from '@/core/MetaService.js';
import { UtilityService } from '@/core/UtilityService.js';
import { IdentifiableError } from '@/misc/identifiable-error.js';
import { searchableTypes } from '@/types.js';
import { ApiError } from '../../error.js';

export const meta = {
Expand Down Expand Up @@ -144,6 +145,7 @@ export const paramDef = {
} },
cw: { type: 'string', nullable: true, minLength: 1, maxLength: 100 },
reactionAcceptance: { type: 'string', nullable: true, enum: [null, 'likeOnly', 'likeOnlyForRemote', 'nonSensitiveOnly', 'nonSensitiveOnlyForLocalLikeOnlyForRemote'], default: null },
searchableBy: { type: 'string', nullable: true, enum: searchableTypes, default: 'public' },
disableRightClick: { type: 'boolean', default: false },
noExtractMentions: { type: 'boolean', default: false },
noExtractHashtags: { type: 'boolean', default: false },
Expand Down Expand Up @@ -388,6 +390,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
localOnly: false,
reactionAcceptance: ps.reactionAcceptance,
disableRightClick: ps.disableRightClick,
searchableBy: ps.searchableBy,
visibility: ps.visibility,
visibleUsers,
channel,
Expand Down
1 change: 1 addition & 0 deletions packages/backend/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ export const mutedNoteReasons = ['word', 'manual', 'spam', 'other'] as const;

export const followingVisibilities = ['public', 'followers', 'private'] as const;
export const followersVisibilities = ['public', 'followers', 'private'] as const;
export const searchableTypes = ['public', 'followersAndReacted', 'reactedOnly', 'private'] as const;

export const moderationLogTypes = [
'updateServerSettings',
Expand Down
3 changes: 3 additions & 0 deletions packages/cherrypick-js/etc/cherrypick-js.api.md
Original file line number Diff line number Diff line change
Expand Up @@ -2678,6 +2678,9 @@ type NotesCreateResponse = operations['notes___create']['responses']['200']['con
// @public (undocumented)
type NotesDeleteRequest = operations['notes___delete']['requestBody']['content']['application/json'];

// @public (undocumented)
export const noteSearchbility: readonly ["public", "followersAndReacted", "reactedOnly", "private"];

// @public (undocumented)
type NotesEventsSearchRequest = operations['notes___events___search']['requestBody']['content']['application/json'];

Expand Down
5 changes: 5 additions & 0 deletions packages/cherrypick-js/src/autogen/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22051,6 +22051,11 @@ export type operations = {
* @enum {string|null}
*/
reactionAcceptance?: null | 'likeOnly' | 'likeOnlyForRemote' | 'nonSensitiveOnly' | 'nonSensitiveOnlyForLocalLikeOnlyForRemote';
/**
* @default public
* @enum {string|null}
*/
searchableBy?: 'public' | 'followersAndReacted' | 'reactedOnly' | 'private';
/** @default false */
disableRightClick?: boolean;
/** @default false */
Expand Down
2 changes: 2 additions & 0 deletions packages/cherrypick-js/src/consts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ export const followingVisibilities = ['public', 'followers', 'private'] as const

export const followersVisibilities = ['public', 'followers', 'private'] as const;

export const noteSearchbility = ['public', 'followersAndReacted', 'reactedOnly', 'private'] as const;

export const permissions = [
'read:account',
'write:account',
Expand Down
Loading

0 comments on commit 7a7a051

Please sign in to comment.