mirror of
https://github.com/misskey-dev/misskey.git
synced 2024-12-23 00:29:22 +09:00
Compare commits
30 Commits
f90dcc9577
...
dda7928f22
Author | SHA1 | Date | |
---|---|---|---|
|
dda7928f22 | ||
|
e8bf6285cb | ||
|
074b7b0bee | ||
|
020c191e2c | ||
|
dac3b1f405 | ||
|
fa271cf84e | ||
|
9a7162a199 | ||
|
8842c56956 | ||
|
38c0ce7634 | ||
|
ed39b8c485 | ||
|
2004d5e2f8 | ||
|
5257591c16 | ||
|
97f96ab92d | ||
|
04616ff996 | ||
|
0949c0e0cd | ||
|
f4ea906516 | ||
|
8d41e3c8e4 | ||
|
17da05ca54 | ||
|
7074f80ea2 | ||
|
2f2a0e3c5e | ||
|
69bf40341d | ||
|
985d582166 | ||
|
d88193a16e | ||
|
8b7ae92b78 | ||
|
699cbd0d77 | ||
|
dabe38a991 | ||
|
eec885e2f5 | ||
|
34c201ff01 | ||
|
630bee0cc4 | ||
|
4ad43bca42 |
@ -1,11 +1,14 @@
|
|||||||
## 2024.11.1
|
## 2024.11.1
|
||||||
|
|
||||||
### General
|
### General
|
||||||
-
|
- Enhance: リアクションの一覧の公開設定が連合されるように
|
||||||
|
|
||||||
### Client
|
### Client
|
||||||
- Fix: 画面サイズが変わった際にナビゲーションバーが自動で折りたたまれない問題を修正
|
- Fix: 画面サイズが変わった際にナビゲーションバーが自動で折りたたまれない問題を修正
|
||||||
- Fix: サーバー情報メニューに区切り線が不足していたのを修正
|
- Fix: サーバー情報メニューに区切り線が不足していたのを修正
|
||||||
|
- Fix: ノートがログインしているユーザーしか見れない場合にログインダイアログを閉じるとその後の動線がなくなる問題を修正
|
||||||
|
- Fix: 公開範囲がホームのノートの埋め込みウィジェットが読み込まれない問題を修正
|
||||||
|
(Cherry-picked from https://activitypub.software/TransFem-org/Sharkey/-/merge_requests/803)
|
||||||
|
|
||||||
### Server
|
### Server
|
||||||
- Fix: ユーザーのプロフィール画面をアドレス入力などで直接表示した際に概要タブの描画に失敗する問題の修正( #15032 )
|
- Fix: ユーザーのプロフィール画面をアドレス入力などで直接表示した際に概要タブの描画に失敗する問題の修正( #15032 )
|
||||||
|
@ -0,0 +1,16 @@
|
|||||||
|
/*
|
||||||
|
* SPDX-FileCopyrightText: syuilo and misskey-project
|
||||||
|
* SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
*/
|
||||||
|
|
||||||
|
export class RemotePublicReactionsSetFalse1723208290742 {
|
||||||
|
name = 'RemotePublicReactionsSetFalse1723208290742'
|
||||||
|
|
||||||
|
async up(queryRunner) {
|
||||||
|
await queryRunner.query(`UPDATE "user_profile" SET "publicReactions" = FALSE WHERE "userHost" IS NOT NULL`);
|
||||||
|
}
|
||||||
|
|
||||||
|
async down(queryRunner) {
|
||||||
|
// no valid down migration
|
||||||
|
}
|
||||||
|
}
|
@ -472,6 +472,13 @@ export class ApRendererService {
|
|||||||
|
|
||||||
const hashtagTags = user.tags.map(tag => this.renderHashtag(tag));
|
const hashtagTags = user.tags.map(tag => this.renderHashtag(tag));
|
||||||
|
|
||||||
|
const likedId = `${id}/liked`;
|
||||||
|
const liked = this.renderOrderedCollection(
|
||||||
|
likedId,
|
||||||
|
undefined,
|
||||||
|
profile.publicReactions ? `${likedId}?page=true` : undefined,
|
||||||
|
);
|
||||||
|
|
||||||
const tag = [
|
const tag = [
|
||||||
...apemojis,
|
...apemojis,
|
||||||
...hashtagTags,
|
...hashtagTags,
|
||||||
@ -486,6 +493,7 @@ export class ApRendererService {
|
|||||||
outbox: `${id}/outbox`,
|
outbox: `${id}/outbox`,
|
||||||
followers: `${id}/followers`,
|
followers: `${id}/followers`,
|
||||||
following: `${id}/following`,
|
following: `${id}/following`,
|
||||||
|
liked,
|
||||||
featured: `${id}/collections/featured`,
|
featured: `${id}/collections/featured`,
|
||||||
sharedInbox: `${this.config.url}/inbox`,
|
sharedInbox: `${this.config.url}/inbox`,
|
||||||
endpoints: { sharedInbox: `${this.config.url}/inbox` },
|
endpoints: { sharedInbox: `${this.config.url}/inbox` },
|
||||||
@ -670,7 +678,7 @@ export class ApRendererService {
|
|||||||
* @param orderedItems attached objects (optional)
|
* @param orderedItems attached objects (optional)
|
||||||
*/
|
*/
|
||||||
@bindThis
|
@bindThis
|
||||||
public renderOrderedCollection(id: string, totalItems: number, first?: string, last?: string, orderedItems?: IObject[]) {
|
public renderOrderedCollection(id: string, totalItems?: number, first?: string, last?: string, orderedItems?: IObject[]) {
|
||||||
const page: any = {
|
const page: any = {
|
||||||
id,
|
id,
|
||||||
type: 'OrderedCollection',
|
type: 'OrderedCollection',
|
||||||
|
@ -321,17 +321,17 @@ export class ApPersonService implements OnModuleInit {
|
|||||||
|
|
||||||
const isBot = getApType(object) === 'Service' || getApType(object) === 'Application';
|
const isBot = getApType(object) === 'Service' || getApType(object) === 'Application';
|
||||||
|
|
||||||
const [followingVisibility, followersVisibility] = await Promise.all(
|
const [publicReactions, followingIsPublic, followersIsPublic] = await Promise.all(
|
||||||
[
|
[
|
||||||
|
this.isPublicCollection(person.liked, resolver),
|
||||||
this.isPublicCollection(person.following, resolver),
|
this.isPublicCollection(person.following, resolver),
|
||||||
this.isPublicCollection(person.followers, resolver),
|
this.isPublicCollection(person.followers, resolver),
|
||||||
].map((p): Promise<'public' | 'private'> => p
|
].map((p): Promise<boolean> => p
|
||||||
.then(isPublic => isPublic ? 'public' : 'private')
|
|
||||||
.catch(err => {
|
.catch(err => {
|
||||||
if (!(err instanceof StatusError) || err.isRetryable) {
|
if (!(err instanceof StatusError) || err.isRetryable) {
|
||||||
this.logger.error('error occurred while fetching following/followers collection', { stack: err });
|
this.logger.error('error occurred while fetching actor collection', { stack: err });
|
||||||
}
|
}
|
||||||
return 'private';
|
return false;
|
||||||
}),
|
}),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
@ -411,8 +411,9 @@ export class ApPersonService implements OnModuleInit {
|
|||||||
followedMessage: person._misskey_followedMessage != null ? truncate(person._misskey_followedMessage, 256) : null,
|
followedMessage: person._misskey_followedMessage != null ? truncate(person._misskey_followedMessage, 256) : null,
|
||||||
url,
|
url,
|
||||||
fields,
|
fields,
|
||||||
followingVisibility,
|
publicReactions,
|
||||||
followersVisibility,
|
followingVisibility: followingIsPublic ? 'public' : 'private',
|
||||||
|
followersVisibility: followersIsPublic ? 'public' : 'private',
|
||||||
birthday: bday?.[0] ?? null,
|
birthday: bday?.[0] ?? null,
|
||||||
location: person['vcard:Address'] ?? null,
|
location: person['vcard:Address'] ?? null,
|
||||||
userHost: host,
|
userHost: host,
|
||||||
@ -522,19 +523,19 @@ export class ApPersonService implements OnModuleInit {
|
|||||||
|
|
||||||
const tags = extractApHashtags(person.tag).map(normalizeForSearch).splice(0, 32);
|
const tags = extractApHashtags(person.tag).map(normalizeForSearch).splice(0, 32);
|
||||||
|
|
||||||
const [followingVisibility, followersVisibility] = await Promise.all(
|
const [publicReactions, followingIsPublic, followersIsPublic] = await Promise.all(
|
||||||
[
|
[
|
||||||
|
this.isPublicCollection(person.liked, resolver),
|
||||||
this.isPublicCollection(person.following, resolver),
|
this.isPublicCollection(person.following, resolver),
|
||||||
this.isPublicCollection(person.followers, resolver),
|
this.isPublicCollection(person.followers, resolver),
|
||||||
].map((p): Promise<'public' | 'private' | undefined> => p
|
].map((p): Promise<boolean | undefined> => p
|
||||||
.then(isPublic => isPublic ? 'public' : 'private')
|
|
||||||
.catch(err => {
|
.catch(err => {
|
||||||
if (!(err instanceof StatusError) || err.isRetryable) {
|
if (!(err instanceof StatusError) || err.isRetryable) {
|
||||||
this.logger.error('error occurred while fetching following/followers collection', { stack: err });
|
this.logger.error('error occurred while fetching actor collection', { stack: err });
|
||||||
// Do not update the visibiility on transient errors.
|
// Do not update the visibiility on transient errors.
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
return 'private';
|
return false;
|
||||||
}),
|
}),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
@ -618,8 +619,9 @@ export class ApPersonService implements OnModuleInit {
|
|||||||
fields,
|
fields,
|
||||||
description: _description,
|
description: _description,
|
||||||
followedMessage: person._misskey_followedMessage != null ? truncate(person._misskey_followedMessage, 256) : null,
|
followedMessage: person._misskey_followedMessage != null ? truncate(person._misskey_followedMessage, 256) : null,
|
||||||
followingVisibility,
|
publicReactions,
|
||||||
followersVisibility,
|
followingVisibility: followingIsPublic ? 'public' : followingIsPublic === false ? 'private' : undefined,
|
||||||
|
followersVisibility: followersIsPublic ? 'public' : followersIsPublic === false ? 'private' : undefined,
|
||||||
birthday: bday?.[0] ?? null,
|
birthday: bday?.[0] ?? null,
|
||||||
location: person['vcard:Address'] ?? null,
|
location: person['vcard:Address'] ?? null,
|
||||||
});
|
});
|
||||||
|
@ -103,14 +103,14 @@ export interface IActivity extends IObject {
|
|||||||
|
|
||||||
export interface ICollection extends IObject {
|
export interface ICollection extends IObject {
|
||||||
type: 'Collection';
|
type: 'Collection';
|
||||||
totalItems: number;
|
totalItems?: number;
|
||||||
first?: IObject | string;
|
first?: IObject | string;
|
||||||
items?: ApObject;
|
items?: ApObject;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IOrderedCollection extends IObject {
|
export interface IOrderedCollection extends IObject {
|
||||||
type: 'OrderedCollection';
|
type: 'OrderedCollection';
|
||||||
totalItems: number;
|
totalItems?: number;
|
||||||
first?: IObject | string;
|
first?: IObject | string;
|
||||||
orderedItems?: ApObject;
|
orderedItems?: ApObject;
|
||||||
}
|
}
|
||||||
@ -190,6 +190,7 @@ export interface IActor extends IObject {
|
|||||||
following?: string | ICollection | IOrderedCollection;
|
following?: string | ICollection | IOrderedCollection;
|
||||||
featured?: string | IOrderedCollection;
|
featured?: string | IOrderedCollection;
|
||||||
outbox: string | IOrderedCollection;
|
outbox: string | IOrderedCollection;
|
||||||
|
liked?: string | ICollection | IOrderedCollection;
|
||||||
endpoints?: {
|
endpoints?: {
|
||||||
sharedInbox?: string;
|
sharedInbox?: string;
|
||||||
};
|
};
|
||||||
|
@ -545,7 +545,7 @@ export class UserEntityService implements OnModuleInit {
|
|||||||
}),
|
}),
|
||||||
pinnedPageId: profile!.pinnedPageId,
|
pinnedPageId: profile!.pinnedPageId,
|
||||||
pinnedPage: profile!.pinnedPageId ? this.pageEntityService.pack(profile!.pinnedPageId, me) : null,
|
pinnedPage: profile!.pinnedPageId ? this.pageEntityService.pack(profile!.pinnedPageId, me) : null,
|
||||||
publicReactions: this.isLocalUser(user) ? profile!.publicReactions : false, // https://github.com/misskey-dev/misskey/issues/12964
|
publicReactions: profile!.publicReactions,
|
||||||
followersVisibility: profile!.followersVisibility,
|
followersVisibility: profile!.followersVisibility,
|
||||||
followingVisibility: profile!.followingVisibility,
|
followingVisibility: profile!.followingVisibility,
|
||||||
roles: this.roleService.getUserRoles(user.id).then(roles => roles.filter(role => role.isPublic).sort((a, b) => b.displayOrder - a.displayOrder).map(role => ({
|
roles: this.roleService.getUserRoles(user.id).then(roles => roles.filter(role => role.isPublic).sort((a, b) => b.displayOrder - a.displayOrder).map(role => ({
|
||||||
|
@ -352,6 +352,98 @@ export class ActivityPubServerService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
|
private async liked(
|
||||||
|
request: FastifyRequest<{ Params: { user: string; }; Querystring: { cursor?: string; page?: string; }; }>,
|
||||||
|
reply: FastifyReply,
|
||||||
|
) {
|
||||||
|
const userId = request.params.user;
|
||||||
|
|
||||||
|
const cursor = request.query.cursor;
|
||||||
|
if (cursor != null && typeof cursor !== 'string') {
|
||||||
|
reply.code(400);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const page = request.query.page === 'true';
|
||||||
|
|
||||||
|
const user = await this.usersRepository.findOneBy({
|
||||||
|
id: userId,
|
||||||
|
host: IsNull(),
|
||||||
|
});
|
||||||
|
|
||||||
|
if (user == null) {
|
||||||
|
reply.code(404);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const profile = await this.userProfilesRepository.findOneByOrFail({ userId: user.id });
|
||||||
|
|
||||||
|
if (!profile.publicReactions) {
|
||||||
|
reply.code(403);
|
||||||
|
reply.header('Cache-Control', 'public, max-age=30');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const limit = 10;
|
||||||
|
const partOf = `${this.config.url}/users/${userId}/liked`;
|
||||||
|
|
||||||
|
if (page) {
|
||||||
|
const query = this.noteReactionsRepository.createQueryBuilder('reaction')
|
||||||
|
.andWhere('reaction.userId = :userId', { userId: user.id });
|
||||||
|
|
||||||
|
// カーソルが指定されている場合
|
||||||
|
if (cursor) {
|
||||||
|
query.andWhere('reaction.id < :id', { id: cursor });
|
||||||
|
}
|
||||||
|
|
||||||
|
const reactions = await query
|
||||||
|
.limit(limit + 1)
|
||||||
|
.orderBy('reaction.id', 'DESC')
|
||||||
|
.innerJoinAndSelect('reaction.note', 'note')
|
||||||
|
.leftJoinAndSelect('note.user', 'noteUser')
|
||||||
|
.andWhere(new Brackets(qb => {
|
||||||
|
qb
|
||||||
|
.where('note.visibility = \'public\'')
|
||||||
|
.orWhere('note.visibility = \'home\'');
|
||||||
|
}))
|
||||||
|
.andWhere('note.localOnly = FALSE')
|
||||||
|
.andWhere('noteUser.isSuspended = FALSE')
|
||||||
|
.getMany();
|
||||||
|
|
||||||
|
// 「次のページ」があるかどうか
|
||||||
|
const inStock = reactions.length === limit + 1;
|
||||||
|
if (inStock) reactions.pop();
|
||||||
|
|
||||||
|
const reactedNotes = await Promise.all(reactions.map(({ note }) => note!.uri || this.apRendererService.renderNote(note!, false)));
|
||||||
|
const rendered = this.apRendererService.renderOrderedCollectionPage(
|
||||||
|
`${partOf}?${url.query({
|
||||||
|
page: 'true',
|
||||||
|
cursor,
|
||||||
|
})}`,
|
||||||
|
undefined, reactedNotes, partOf,
|
||||||
|
undefined,
|
||||||
|
inStock ? `${partOf}?${url.query({
|
||||||
|
page: 'true',
|
||||||
|
cursor: reactions.at(-1)!.id,
|
||||||
|
})}` : undefined,
|
||||||
|
);
|
||||||
|
|
||||||
|
this.setResponseType(request, reply);
|
||||||
|
return (this.apRendererService.addContext(rendered));
|
||||||
|
} else {
|
||||||
|
// index page
|
||||||
|
const rendered = this.apRendererService.renderOrderedCollection(
|
||||||
|
partOf,
|
||||||
|
undefined,
|
||||||
|
`${partOf}?page=true`,
|
||||||
|
);
|
||||||
|
reply.header('Cache-Control', 'public, max-age=180');
|
||||||
|
this.setResponseType(request, reply);
|
||||||
|
return (this.apRendererService.addContext(rendered));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@bindThis
|
@bindThis
|
||||||
private async featured(request: FastifyRequest<{ Params: { user: string; }; }>, reply: FastifyReply) {
|
private async featured(request: FastifyRequest<{ Params: { user: string; }; }>, reply: FastifyReply) {
|
||||||
const userId = request.params.user;
|
const userId = request.params.user;
|
||||||
@ -629,6 +721,12 @@ export class ActivityPubServerService {
|
|||||||
Querystring: { cursor?: string; page?: string; };
|
Querystring: { cursor?: string; page?: string; };
|
||||||
}>('/users/:user/following', async (request, reply) => await this.following(request, reply));
|
}>('/users/:user/following', async (request, reply) => await this.following(request, reply));
|
||||||
|
|
||||||
|
// liked
|
||||||
|
fastify.get<{
|
||||||
|
Params: { user: string; };
|
||||||
|
Querystring: { cursor?: string; page?: string; };
|
||||||
|
}>('/users/:user/liked', async (request, reply) => await this.liked(request, reply));
|
||||||
|
|
||||||
// featured
|
// featured
|
||||||
fastify.get<{ Params: { user: string; }; }>('/users/:user/collections/featured', async (request, reply) => await this.featured(request, reply));
|
fastify.get<{ Params: { user: string; }; }>('/users/:user/collections/featured', async (request, reply) => await this.featured(request, reply));
|
||||||
|
|
||||||
|
@ -10,7 +10,6 @@ import { QueryService } from '@/core/QueryService.js';
|
|||||||
import { NoteReactionEntityService } from '@/core/entities/NoteReactionEntityService.js';
|
import { NoteReactionEntityService } from '@/core/entities/NoteReactionEntityService.js';
|
||||||
import { DI } from '@/di-symbols.js';
|
import { DI } from '@/di-symbols.js';
|
||||||
import { CacheService } from '@/core/CacheService.js';
|
import { CacheService } from '@/core/CacheService.js';
|
||||||
import { UserEntityService } from '@/core/entities/UserEntityService.js';
|
|
||||||
import { RoleService } from '@/core/RoleService.js';
|
import { RoleService } from '@/core/RoleService.js';
|
||||||
import { isUserRelated } from '@/misc/is-user-related.js';
|
import { isUserRelated } from '@/misc/is-user-related.js';
|
||||||
import { ApiError } from '../../error.js';
|
import { ApiError } from '../../error.js';
|
||||||
@ -38,11 +37,6 @@ export const meta = {
|
|||||||
code: 'REACTIONS_NOT_PUBLIC',
|
code: 'REACTIONS_NOT_PUBLIC',
|
||||||
id: '673a7dd2-6924-1093-e0c0-e68456ceae5c',
|
id: '673a7dd2-6924-1093-e0c0-e68456ceae5c',
|
||||||
},
|
},
|
||||||
isRemoteUser: {
|
|
||||||
message: 'Currently unavailable to display reactions of remote users. See https://github.com/misskey-dev/misskey/issues/12964',
|
|
||||||
code: 'IS_REMOTE_USER',
|
|
||||||
id: '6b95fa98-8cf9-2350-e284-f0ffdb54a805',
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
} as const;
|
} as const;
|
||||||
|
|
||||||
@ -69,7 +63,6 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
|||||||
private noteReactionsRepository: NoteReactionsRepository,
|
private noteReactionsRepository: NoteReactionsRepository,
|
||||||
|
|
||||||
private cacheService: CacheService,
|
private cacheService: CacheService,
|
||||||
private userEntityService: UserEntityService,
|
|
||||||
private noteReactionEntityService: NoteReactionEntityService,
|
private noteReactionEntityService: NoteReactionEntityService,
|
||||||
private queryService: QueryService,
|
private queryService: QueryService,
|
||||||
private roleService: RoleService,
|
private roleService: RoleService,
|
||||||
@ -78,11 +71,6 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
|||||||
const userIdsWhoBlockingMe = me ? await this.cacheService.userBlockedCache.fetch(me.id) : new Set<string>();
|
const userIdsWhoBlockingMe = me ? await this.cacheService.userBlockedCache.fetch(me.id) : new Set<string>();
|
||||||
const iAmModerator = me ? await this.roleService.isModerator(me) : false; // Moderators can see reactions of all users
|
const iAmModerator = me ? await this.roleService.isModerator(me) : false; // Moderators can see reactions of all users
|
||||||
if (!iAmModerator) {
|
if (!iAmModerator) {
|
||||||
const user = await this.cacheService.findUserById(ps.userId);
|
|
||||||
if (this.userEntityService.isRemoteUser(user)) {
|
|
||||||
throw new ApiError(meta.errors.isRemoteUser);
|
|
||||||
}
|
|
||||||
|
|
||||||
const profile = await this.userProfilesRepository.findOneByOrFail({ userId: ps.userId });
|
const profile = await this.userProfilesRepository.findOneByOrFail({ userId: ps.userId });
|
||||||
if ((me == null || me.id !== ps.userId) && !profile.publicReactions) {
|
if ((me == null || me.id !== ps.userId) && !profile.publicReactions) {
|
||||||
throw new ApiError(meta.errors.reactionsNotPublic);
|
throw new ApiError(meta.errors.reactionsNotPublic);
|
||||||
|
@ -871,7 +871,7 @@ export class ClientServerService {
|
|||||||
});
|
});
|
||||||
|
|
||||||
if (note == null) return;
|
if (note == null) return;
|
||||||
if (note.visibility !== 'public') return;
|
if (['specified', 'followers'].includes(note.visibility)) return;
|
||||||
if (note.userHost != null) return;
|
if (note.userHost != null) return;
|
||||||
|
|
||||||
const _note = await this.noteEntityService.pack(note, null, { detail: true });
|
const _note = await this.noteEntityService.pack(note, null, { detail: true });
|
||||||
|
@ -43,12 +43,11 @@ describe('User', () => {
|
|||||||
'uri',
|
'uri',
|
||||||
'createdAt',
|
'createdAt',
|
||||||
'lastFetchedAt',
|
'lastFetchedAt',
|
||||||
'publicReactions',
|
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('ffVisibility is federated', () => {
|
describe('ff/reactions visibility is federated', () => {
|
||||||
let alice: LoginUser, bob: LoginUser;
|
let alice: LoginUser, bob: LoginUser;
|
||||||
let bobInA: Misskey.entities.UserDetailedNotMe, aliceInB: Misskey.entities.UserDetailedNotMe;
|
let bobInA: Misskey.entities.UserDetailedNotMe, aliceInB: Misskey.entities.UserDetailedNotMe;
|
||||||
|
|
||||||
@ -78,6 +77,7 @@ describe('User', () => {
|
|||||||
])) {
|
])) {
|
||||||
strictEqual(user.followersVisibility, 'public');
|
strictEqual(user.followersVisibility, 'public');
|
||||||
strictEqual(user.followingVisibility, 'public');
|
strictEqual(user.followingVisibility, 'public');
|
||||||
|
strictEqual(user.publicReactions, true);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -113,6 +113,22 @@ describe('User', () => {
|
|||||||
strictEqual(user.followingVisibility, 'private');
|
strictEqual(user.followingVisibility, 'private');
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test.skip('Setting false for publicReactions is federated', async () => {
|
||||||
|
await Promise.all([
|
||||||
|
alice.client.request('i/update', { publicReactions: false }),
|
||||||
|
bob.client.request('i/update', { publicReactions: false }),
|
||||||
|
]);
|
||||||
|
await sleep();
|
||||||
|
|
||||||
|
for (const user of await Promise.all([
|
||||||
|
alice.client.request('users/show', { userId: bobInA.id }),
|
||||||
|
bob.client.request('users/show', { userId: aliceInB.id }),
|
||||||
|
])) {
|
||||||
|
strictEqual(user.publicReactions, false);
|
||||||
|
strictEqual(user.publicReactions, false);
|
||||||
|
}
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('isCat is federated', () => {
|
describe('isCat is federated', () => {
|
||||||
|
@ -213,7 +213,7 @@ describe('ActivityPub', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
describe('Collection visibility', () => {
|
describe('Collection visibility', () => {
|
||||||
test('Public following/followers', async () => {
|
test('Public following/followers/reactions', async () => {
|
||||||
const actor = createRandomActor();
|
const actor = createRandomActor();
|
||||||
actor.following = {
|
actor.following = {
|
||||||
id: `${actor.id}/following`,
|
id: `${actor.id}/following`,
|
||||||
@ -222,6 +222,12 @@ describe('ActivityPub', () => {
|
|||||||
first: `${actor.id}/following?page=1`,
|
first: `${actor.id}/following?page=1`,
|
||||||
};
|
};
|
||||||
actor.followers = `${actor.id}/followers`;
|
actor.followers = `${actor.id}/followers`;
|
||||||
|
actor.liked = {
|
||||||
|
id: `${actor.id}/following`,
|
||||||
|
type: 'OrderedCollection',
|
||||||
|
totalItems: 0,
|
||||||
|
orderedItems: [],
|
||||||
|
};
|
||||||
|
|
||||||
resolver.register(actor.id, actor);
|
resolver.register(actor.id, actor);
|
||||||
resolver.register(actor.followers, {
|
resolver.register(actor.followers, {
|
||||||
@ -236,9 +242,10 @@ describe('ActivityPub', () => {
|
|||||||
|
|
||||||
assert.deepStrictEqual(userProfile.followingVisibility, 'public');
|
assert.deepStrictEqual(userProfile.followingVisibility, 'public');
|
||||||
assert.deepStrictEqual(userProfile.followersVisibility, 'public');
|
assert.deepStrictEqual(userProfile.followersVisibility, 'public');
|
||||||
|
assert.deepStrictEqual(userProfile.publicReactions, true);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('Private following/followers', async () => {
|
test('Private following/followers/reactions', async () => {
|
||||||
const actor = createRandomActor();
|
const actor = createRandomActor();
|
||||||
actor.following = {
|
actor.following = {
|
||||||
id: `${actor.id}/following`,
|
id: `${actor.id}/following`,
|
||||||
@ -247,6 +254,7 @@ describe('ActivityPub', () => {
|
|||||||
// first: …
|
// first: …
|
||||||
};
|
};
|
||||||
actor.followers = `${actor.id}/followers`;
|
actor.followers = `${actor.id}/followers`;
|
||||||
|
// actor.liked = …;
|
||||||
|
|
||||||
resolver.register(actor.id, actor);
|
resolver.register(actor.id, actor);
|
||||||
//resolver.register(actor.followers, { … });
|
//resolver.register(actor.followers, { … });
|
||||||
@ -256,6 +264,7 @@ describe('ActivityPub', () => {
|
|||||||
|
|
||||||
assert.deepStrictEqual(userProfile.followingVisibility, 'private');
|
assert.deepStrictEqual(userProfile.followingVisibility, 'private');
|
||||||
assert.deepStrictEqual(userProfile.followersVisibility, 'private');
|
assert.deepStrictEqual(userProfile.followersVisibility, 'private');
|
||||||
|
assert.deepStrictEqual(userProfile.publicReactions, false);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -384,6 +384,7 @@ const patrons = [
|
|||||||
'こまつぶり',
|
'こまつぶり',
|
||||||
'まゆつな空高',
|
'まゆつな空高',
|
||||||
'asata',
|
'asata',
|
||||||
|
'ruru',
|
||||||
];
|
];
|
||||||
|
|
||||||
const thereIsTreasure = ref($i && !claimedAchievements.includes('foundTreasure'));
|
const thereIsTreasure = ref($i && !claimedAchievements.includes('foundTreasure'));
|
||||||
|
@ -117,5 +117,6 @@ definePageMetadata(() => ({
|
|||||||
border-radius: var(--MI-radius);
|
border-radius: var(--MI-radius);
|
||||||
background-color: var(--MI_THEME-panel);
|
background-color: var(--MI_THEME-panel);
|
||||||
overflow-x: scroll;
|
overflow-x: scroll;
|
||||||
|
white-space: nowrap;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
@ -50,6 +50,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { computed, watch, ref } from 'vue';
|
import { computed, watch, ref } from 'vue';
|
||||||
import * as Misskey from 'misskey-js';
|
import * as Misskey from 'misskey-js';
|
||||||
|
import { host } from '@@/js/config.js';
|
||||||
import type { Paging } from '@/components/MkPagination.vue';
|
import type { Paging } from '@/components/MkPagination.vue';
|
||||||
import MkNoteDetailed from '@/components/MkNoteDetailed.vue';
|
import MkNoteDetailed from '@/components/MkNoteDetailed.vue';
|
||||||
import MkNotes from '@/components/MkNotes.vue';
|
import MkNotes from '@/components/MkNotes.vue';
|
||||||
@ -140,7 +141,12 @@ function fetchNote() {
|
|||||||
}).catch(err => {
|
}).catch(err => {
|
||||||
if (err.id === '8e75455b-738c-471d-9f80-62693f33372e') {
|
if (err.id === '8e75455b-738c-471d-9f80-62693f33372e') {
|
||||||
pleaseLogin({
|
pleaseLogin({
|
||||||
|
path: '/',
|
||||||
message: i18n.ts.thisContentsAreMarkedAsSigninRequiredByAuthor,
|
message: i18n.ts.thisContentsAreMarkedAsSigninRequiredByAuthor,
|
||||||
|
openOnRemote: {
|
||||||
|
type: 'lookup',
|
||||||
|
url: `https://${host}/notes/${props.noteId}`,
|
||||||
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
error.value = err;
|
error.value = err;
|
||||||
|
Loading…
Reference in New Issue
Block a user