1
1
mirror of https://github.com/kokonect-link/cherrypick synced 2025-01-09 03:13:57 +09:00

Merge branch 'develop' into feat-13070

This commit is contained in:
かっこかり 2024-02-02 13:03:36 +09:00 committed by GitHub
commit c56abec648
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
16 changed files with 109 additions and 105 deletions

View File

@ -1,66 +1,23 @@
name: Deploy test environment
name: deploy-test-environment
on:
push:
#push:
workflow_dispatch:
inputs:
repository:
description: 'Repository to deploy (optional)'
type: string
required: false
branch:
description: 'Branch to deploy (optional)'
branch_or_hash:
description: 'Branch or Commit hash to deploy (optional)'
type: string
required: false
jobs:
deploy-test-environment:
runs-on: ubuntu-latest
steps:
- name: Set environment variable (for tput command & pnpm)
run: |
echo "TERM=xterm" >> $GITHUB_ENV
REPOSITORY=${{ github.event.inputs.repository || github.repository }}
echo "REPOSITORY=$REPOSITORY" >> $GITHUB_ENV
BRANCH=${{ github.event.inputs.branch || github.ref_name }}
echo "BRANCH=$BRANCH" >> $GITHUB_ENV
- name: Checkout
uses: actions/checkout@v4
with:
repository: ${{ env.REPOSITORY }}
ref: ${{ env.BRANCH }}
- name: Get the latest commit SHA
run: |
SHA=$(git log -1 --format="%H")
echo "SHA=$SHA" >> $GITHUB_ENV
- name: Start cloudflare tunnel (quick)
run: |
wget https://github.com/cloudflare/cloudflared/releases/latest/download/cloudflared-linux-amd64.deb
sudo dpkg -i cloudflared-linux-amd64.deb
sudo cloudflared tunnel --metrics localhost:55555 --url localhost:3000 > /dev/null 2>&1 &
sleep 15
TUNNEL_RESPONSE=$(curl http://localhost:55555/quicktunnel)
TUNNEL_DOMAIN=$(echo $TUNNEL_RESPONSE | grep -o '"hostname":"[^"]*' | grep -o '[^"]*$')
echo "::add-mask::$TUNNEL_DOMAIN"
echo "TUNNEL_DOMAIN=$TUNNEL_DOMAIN" >> $GITHUB_ENV
- name: Install misskey
run: |
wget https://raw.githubusercontent.com/joinmisskey/bash-install/v4/misskey-install.sh
wget https://raw.githubusercontent.com/joinmisskey/bash-install/v4/testenv_githubactions.txt
sed -i "s/host=127.0.0.1/host=$TUNNEL_DOMAIN/g" testenv_githubactions.txt
sed -i "s|git_repository=https://github.com/misskey-dev/misskey|git_repository=https://github.com/$REPOSITORY|g" testenv_githubactions.txt
sed -i "s|git_branch=master|git_branch=$BRANCH|g" testenv_githubactions.txt
sudo chmod 555 ./misskey-install.sh
sudo bash -x ./misskey-install.sh -c ./testenv_githubactions.txt
- name: Post tunnel info to Discord
run: |
CURRENT_TIME=$(TZ=Asia/Tokyo date +'%Y-%m-%d %H:%M:%S JST')
COMMIT_URL="https://github.com/$REPOSITORY/commit/$SHA"
curl -X POST -H "Content-Type: application/json" -d "{\"content\": \"==============================\nURL: https://$TUNNEL_DOMAIN\nRepository: $REPOSITORY\nBranch: $BRANCH\nCommit: $COMMIT_URL\nTime: $CURRENT_TIME\n==============================\"}" ${{ secrets.DISCORD_WEBHOOK_URL }}
- name: Wait
run: |
timeout 3600 tail -f /var/log/syslog || true
uses: joinmisskey/misskey-tga/.github/workflows/deploy-test-environment.yml@main
with:
repository: ${{ github.event.inputs.repository }}
branch_or_hash: ${{ github.event.inputs.branch_or_hash }}
secrets:
DISCORD_WEBHOOK_URL: ${{ secrets.DISCORD_WEBHOOK_URL }}

View File

@ -23,7 +23,7 @@ jobs:
private_key: ${{ secrets.DEPLOYBOT_PRIVATE_KEY }}
- name: Slash Command Dispatch
uses: peter-evans/slash-command-dispatch@v3
uses: peter-evans/slash-command-dispatch@v4
env:
TOKEN: ${{ steps.generate_token.outputs.token }}
with:

View File

@ -61,7 +61,7 @@ jobs:
- name: Test
run: pnpm --filter backend test-and-coverage
- name: Upload to Codecov
uses: codecov/codecov-action@v3
uses: codecov/codecov-action@v4
with:
token: ${{ secrets.CODECOV_TOKEN }}
files: ./packages/backend/coverage/coverage-final.json
@ -111,7 +111,7 @@ jobs:
- name: Test
run: pnpm --filter backend test-and-coverage:e2e
- name: Upload to Codecov
uses: codecov/codecov-action@v3
uses: codecov/codecov-action@v4
with:
token: ${{ secrets.CODECOV_TOKEN }}
files: ./packages/backend/coverage/coverage-final.json

View File

@ -53,7 +53,7 @@ jobs:
- name: Test
run: pnpm --filter frontend test-and-coverage
- name: Upload Coverage
uses: codecov/codecov-action@v3
uses: codecov/codecov-action@v4
with:
token: ${{ secrets.CODECOV_TOKEN }}
files: ./packages/frontend/coverage/coverage-final.json

View File

@ -50,7 +50,7 @@ jobs:
CI: true
- name: Upload Coverage
uses: codecov/codecov-action@v3
uses: codecov/codecov-action@v4
with:
token: ${{ secrets.CODECOV_TOKEN }}
files: ./packages/misskey-js/coverage/coverage-final.json

View File

@ -21,6 +21,9 @@
- Feat: [mCaptcha](https://github.com/mCaptcha/mCaptcha)のサポートを追加
- Fix: リストライムラインの「リノートを表示」が正しく機能しない問題を修正
- Feat: Add support for TrueMail
- Fix: リモートユーザーのリアクション一覧がすべて見えてしまうのを修正
* すべてのリモートユーザーのリアクション一覧を見えないようにします
- Enhance: モデレーターはすべてのユーザーのリアクション一覧を見られるように
### Client
- Feat: 新しいゲームを追加
@ -71,6 +74,7 @@
- Fix: ipv4とipv6の両方が利用可能な環境でallowedPrivateNetworksが設定されていた場合プライベートipの検証ができていなかった問題を修正
- Fix: properly handle cc followers
- Fix: ジョブに関する設定の名前を修正 relashionshipJobPerSec -> relationshipJobPerSec
- Fix: コントロールパネル->モデレーション->「誰でも新規登録できるようにする」の初期値をONからOFFに変更 #13122
### Service Worker
- Enhance: オフライン表示のデザインを改善・多言語対応

View File

@ -3,6 +3,6 @@ import { genOpenapiSpec } from './built/server/api/openapi/gen-spec.js'
import { writeFileSync } from "node:fs";
const config = loadConfig();
const spec = genOpenapiSpec(config);
const spec = genOpenapiSpec(config, true);
writeFileSync('./built/api.json', JSON.stringify(spec), 'utf-8');

View File

@ -0,0 +1,16 @@
/*
* SPDX-FileCopyrightText: syuilo and other misskey contributors
* SPDX-License-Identifier: AGPL-3.0-only
*/
export class FixMetaDisableRegistration1706791962000 {
name = 'FixMetaDisableRegistration1706791962000'
async up(queryRunner) {
await queryRunner.query(`alter table meta alter column "disableRegistration" set default true;`);
}
async down(queryRunner) {
await queryRunner.query(`alter table meta alter column "disableRegistration" set default false;`);
}
}

View File

@ -409,7 +409,7 @@ export class UserEntityService implements OnModuleInit {
}),
pinnedPageId: profile!.pinnedPageId,
pinnedPage: profile!.pinnedPageId ? this.pageEntityService.pack(profile!.pinnedPageId, me) : null,
publicReactions: profile!.publicReactions,
publicReactions: this.isLocalUser(user) ? profile!.publicReactions : false, // https://github.com/misskey-dev/misskey/issues/12964
followersVisibility: profile!.followersVisibility,
followingVisibility: profile!.followingVisibility,
twoFactorEnabled: profile!.twoFactorEnabled,

View File

@ -119,6 +119,7 @@ export interface Schema extends OfSchema {
readonly example?: any;
readonly format?: string;
readonly ref?: keyof typeof refs;
readonly selfRef?: boolean;
readonly enum?: ReadonlyArray<string | null>;
readonly default?: (this['type'] extends TypeStringef ? StringDefToType<this['type']> : any) | null;
readonly maxLength?: number;

View File

@ -53,6 +53,7 @@ const sectionBlockSchema = {
type: 'object',
optional: false, nullable: false,
ref: 'PageBlock',
selfRef: true,
},
},
},

View File

@ -9,6 +9,9 @@ import { Endpoint } from '@/server/api/endpoint-base.js';
import { QueryService } from '@/core/QueryService.js';
import { NoteReactionEntityService } from '@/core/entities/NoteReactionEntityService.js';
import { DI } from '@/di-symbols.js';
import { CacheService } from '@/core/CacheService.js';
import { UserEntityService } from '@/core/entities/UserEntityService.js';
import { RoleService } from '@/core/RoleService.js';
import { ApiError } from '../../error.js';
export const meta = {
@ -34,6 +37,11 @@ export const meta = {
code: 'REACTIONS_NOT_PUBLIC',
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;
@ -59,14 +67,24 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
@Inject(DI.noteReactionsRepository)
private noteReactionsRepository: NoteReactionsRepository,
private cacheService: CacheService,
private userEntityService: UserEntityService,
private noteReactionEntityService: NoteReactionEntityService,
private queryService: QueryService,
private roleService: RoleService,
) {
super(meta, paramDef, async (ps, me) => {
const profile = await this.userProfilesRepository.findOneByOrFail({ userId: ps.userId });
const iAmModerator = me ? await this.roleService.isModerator(me) : false; // Moderators can see reactions of all users
if (!iAmModerator) {
const user = await this.cacheService.findUserById(ps.userId);
if (this.userEntityService.isRemoteUser(user)) {
throw new ApiError(meta.errors.isRemoteUser);
}
if ((me == null || me.id !== ps.userId) && !profile.publicReactions) {
throw new ApiError(meta.errors.reactionsNotPublic);
const profile = await this.userProfilesRepository.findOneByOrFail({ userId: ps.userId });
if ((me == null || me.id !== ps.userId) && !profile.publicReactions) {
throw new ApiError(meta.errors.reactionsNotPublic);
}
}
const query = this.queryService.makePaginationQuery(this.noteReactionsRepository.createQueryBuilder('reaction'),

View File

@ -6,9 +6,9 @@
import type { Config } from '@/config.js';
import endpoints, { IEndpoint } from '../endpoints.js';
import { errors as basicErrors } from './errors.js';
import { schemas, convertSchemaToOpenApiSchema } from './schemas.js';
import { getSchemas, convertSchemaToOpenApiSchema } from './schemas.js';
export function genOpenapiSpec(config: Config) {
export function genOpenapiSpec(config: Config, includeSelfRef = false) {
const spec = {
openapi: '3.1.0',
@ -30,7 +30,7 @@ export function genOpenapiSpec(config: Config) {
paths: {} as any,
components: {
schemas: schemas,
schemas: getSchemas(includeSelfRef),
securitySchemes: {
bearerAuth: {
@ -56,7 +56,7 @@ export function genOpenapiSpec(config: Config) {
}
}
const resSchema = endpoint.meta.res ? convertSchemaToOpenApiSchema(endpoint.meta.res, 'res') : {};
const resSchema = endpoint.meta.res ? convertSchemaToOpenApiSchema(endpoint.meta.res, 'res', includeSelfRef) : {};
let desc = (endpoint.meta.description ? endpoint.meta.description : 'No description provided.') + '\n\n';
@ -71,7 +71,7 @@ export function genOpenapiSpec(config: Config) {
}
const requestType = endpoint.meta.requireFile ? 'multipart/form-data' : 'application/json';
const schema = { ...convertSchemaToOpenApiSchema(endpoint.params, 'param') };
const schema = { ...convertSchemaToOpenApiSchema(endpoint.params, 'param', false) };
if (endpoint.meta.requireFile) {
schema.properties = {

View File

@ -6,10 +6,10 @@
import type { Schema } from '@/misc/json-schema.js';
import { refs } from '@/misc/json-schema.js';
export function convertSchemaToOpenApiSchema(schema: Schema, type: 'param' | 'res') {
export function convertSchemaToOpenApiSchema(schema: Schema, type: 'param' | 'res', includeSelfRef: boolean): any {
// optional, nullable, refはスキーマ定義に含まれないので分離しておく
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const { optional, nullable, ref, ...res }: any = schema;
const { optional, nullable, ref, selfRef, ...res }: any = schema;
if (schema.type === 'object' && schema.properties) {
if (type === 'res') {
@ -21,20 +21,20 @@ export function convertSchemaToOpenApiSchema(schema: Schema, type: 'param' | 're
}
for (const k of Object.keys(schema.properties)) {
res.properties[k] = convertSchemaToOpenApiSchema(schema.properties[k], type);
res.properties[k] = convertSchemaToOpenApiSchema(schema.properties[k], type, includeSelfRef);
}
}
if (schema.type === 'array' && schema.items) {
res.items = convertSchemaToOpenApiSchema(schema.items, type);
res.items = convertSchemaToOpenApiSchema(schema.items, type, includeSelfRef);
}
for (const o of ['anyOf', 'oneOf', 'allOf'] as const) {
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
if (o in schema) res[o] = schema[o]!.map(schema => convertSchemaToOpenApiSchema(schema, type));
if (o in schema) res[o] = schema[o]!.map(schema => convertSchemaToOpenApiSchema(schema, type, includeSelfRef));
}
if (type === 'res' && schema.ref) {
if (type === 'res' && schema.ref && (!schema.selfRef || includeSelfRef)) {
const $ref = `#/components/schemas/${schema.ref}`;
if (schema.nullable || schema.optional) {
res.allOf = [{ $ref }];
@ -54,35 +54,37 @@ export function convertSchemaToOpenApiSchema(schema: Schema, type: 'param' | 're
return res;
}
export const schemas = {
Error: {
type: 'object',
properties: {
error: {
type: 'object',
description: 'An error object.',
properties: {
code: {
type: 'string',
description: 'An error code. Unique within the endpoint.',
},
message: {
type: 'string',
description: 'An error message.',
},
id: {
type: 'string',
format: 'uuid',
description: 'An error ID. This ID is static.',
export function getSchemas(includeSelfRef: boolean) {
return {
Error: {
type: 'object',
properties: {
error: {
type: 'object',
description: 'An error object.',
properties: {
code: {
type: 'string',
description: 'An error code. Unique within the endpoint.',
},
message: {
type: 'string',
description: 'An error message.',
},
id: {
type: 'string',
format: 'uuid',
description: 'An error ID. This ID is static.',
},
},
required: ['code', 'id', 'message'],
},
required: ['code', 'id', 'message'],
},
required: ['error'],
},
required: ['error'],
},
...Object.fromEntries(
Object.entries(refs).map(([key, schema]) => [key, convertSchemaToOpenApiSchema(schema, 'res')]),
),
};
...Object.fromEntries(
Object.entries(refs).map(([key, schema]) => [key, convertSchemaToOpenApiSchema(schema, 'res', includeSelfRef)]),
),
};
}

View File

@ -263,7 +263,12 @@ const translation = ref<Misskey.entities.NotesTranslateResponse | null>(null);
const translating = ref(false);
const showTicker = (defaultStore.state.instanceTicker === 'always') || (defaultStore.state.instanceTicker === 'remote' && appearNote.value.user.instance);
const canRenote = computed(() => ['public', 'home'].includes(appearNote.value.visibility) || (appearNote.value.visibility === 'followers' && appearNote.value.userId === $i?.id));
const renoteCollapsed = ref(defaultStore.state.collapseRenotes && isRenote && (($i && ($i.id === note.value.userId || $i.id === appearNote.value.userId)) ?? (appearNote.value.myReaction != null)));
const renoteCollapsed = ref(
defaultStore.state.collapseRenotes && isRenote && (
($i && ($i.id === note.value.userId || $i.id === appearNote.value.userId)) || // `||` must be `||`! See https://github.com/misskey-dev/misskey/issues/13131
(appearNote.value.myReaction != null)
)
);
/* Overload FunctionLint
function checkMute(noteToCheck: Misskey.entities.Note, mutedWords: Array<string | string[]> | undefined | null, checkOnly: true): boolean;

View File

@ -96,7 +96,7 @@ const headerTabs = computed(() => user.value ? [{
key: 'achievements',
title: i18n.ts.achievements,
icon: 'ti ti-medal',
}] : []), ...($i && ($i.id === user.value.id)) || user.value.publicReactions ? [{
}] : []), ...($i && ($i.id === user.value.id || $i.isAdmin || $i.isModerator)) || user.value.publicReactions ? [{
key: 'reactions',
title: i18n.ts.reaction,
icon: 'ti ti-mood-happy',