diff --git a/.github/workflows/deploy-test-environment.yml b/.github/workflows/deploy-test-environment.yml index cd7a8f328e..acfe7dec2d 100644 --- a/.github/workflows/deploy-test-environment.yml +++ b/.github/workflows/deploy-test-environment.yml @@ -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 }} diff --git a/.github/workflows/ok-to-test.yml b/.github/workflows/ok-to-test.yml index c02b980e4d..8362c006eb 100644 --- a/.github/workflows/ok-to-test.yml +++ b/.github/workflows/ok-to-test.yml @@ -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: diff --git a/.github/workflows/test-backend.yml b/.github/workflows/test-backend.yml index a6c12e2824..199443fca8 100644 --- a/.github/workflows/test-backend.yml +++ b/.github/workflows/test-backend.yml @@ -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 diff --git a/.github/workflows/test-frontend.yml b/.github/workflows/test-frontend.yml index 3fb880fac2..caa3fceef5 100644 --- a/.github/workflows/test-frontend.yml +++ b/.github/workflows/test-frontend.yml @@ -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 diff --git a/.github/workflows/test-misskey-js.yml b/.github/workflows/test-misskey-js.yml index 10c7ccf4d3..70ef45692a 100644 --- a/.github/workflows/test-misskey-js.yml +++ b/.github/workflows/test-misskey-js.yml @@ -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 diff --git a/CHANGELOG.md b/CHANGELOG.md index 9bfb12d25e..8f6cf2071b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -21,6 +21,9 @@ - Feat: [mCaptcha](https://github.com/mCaptcha/mCaptcha)のサポートを追加 - Fix: リストライムラインの「リノートを表示」が正しく機能しない問題を修正 - Feat: Add support for TrueMail +- Fix: リモートユーザーのリアクション一覧がすべて見えてしまうのを修正 + * すべてのリモートユーザーのリアクション一覧を見えないようにします +- Enhance: モデレーターはすべてのユーザーのリアクション一覧を見られるように ### Client - Feat: 新しいゲームを追加 @@ -58,6 +61,7 @@ - Fix: プラグインで`Plugin:register_note_post_interruptor`を使用すると、ノートが投稿できなくなる問題を修正 - Enhance: ページ遷移時にPlayerを閉じるように - Fix: iOSで大きな画像を変換してアップロードできない問題を修正 +- Fix: 「アニメーション画像を再生しない」もしくは「データセーバー(アイコン)」を有効にしていても、アイコンデコレーションのアニメーションが停止されない問題を修正 ### Server - Enhance: 連合先のレートリミットに引っかかった際にリトライするようになりました @@ -71,6 +75,7 @@ - Fix: ipv4とipv6の両方が利用可能な環境でallowedPrivateNetworksが設定されていた場合プライベートipの検証ができていなかった問題を修正 - Fix: properly handle cc followers - Fix: ジョブに関する設定の名前を修正 relashionshipJobPerSec -> relationshipJobPerSec +- Fix: コントロールパネル->モデレーション->「誰でも新規登録できるようにする」の初期値をONからOFFに変更 #13122 ### Service Worker - Enhance: オフライン表示のデザインを改善・多言語対応 diff --git a/packages/backend/generate_api_json.js b/packages/backend/generate_api_json.js index 5819c60a5f..4079b3bb0a 100644 --- a/packages/backend/generate_api_json.js +++ b/packages/backend/generate_api_json.js @@ -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'); \ No newline at end of file diff --git a/packages/backend/migration/1706791962000-fix-meta-disableRegistration.js b/packages/backend/migration/1706791962000-fix-meta-disableRegistration.js new file mode 100644 index 0000000000..05469d5765 --- /dev/null +++ b/packages/backend/migration/1706791962000-fix-meta-disableRegistration.js @@ -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;`); + } +} diff --git a/packages/backend/src/core/entities/UserEntityService.ts b/packages/backend/src/core/entities/UserEntityService.ts index a09369409b..9d73dc607d 100644 --- a/packages/backend/src/core/entities/UserEntityService.ts +++ b/packages/backend/src/core/entities/UserEntityService.ts @@ -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, diff --git a/packages/backend/src/misc/json-schema.ts b/packages/backend/src/misc/json-schema.ts index d1d1f4d098..92b739099c 100644 --- a/packages/backend/src/misc/json-schema.ts +++ b/packages/backend/src/misc/json-schema.ts @@ -121,6 +121,7 @@ export interface Schema extends OfSchema { readonly example?: any; readonly format?: string; readonly ref?: keyof typeof refs; + readonly selfRef?: boolean; readonly enum?: ReadonlyArray; readonly default?: (this['type'] extends TypeStringef ? StringDefToType : any) | null; readonly maxLength?: number; diff --git a/packages/backend/src/models/json-schema/page.ts b/packages/backend/src/models/json-schema/page.ts index 402db76e52..e4d844645e 100644 --- a/packages/backend/src/models/json-schema/page.ts +++ b/packages/backend/src/models/json-schema/page.ts @@ -53,6 +53,7 @@ const sectionBlockSchema = { type: 'object', optional: false, nullable: false, ref: 'PageBlock', + selfRef: true, }, }, }, diff --git a/packages/backend/src/server/api/endpoints/users/reactions.ts b/packages/backend/src/server/api/endpoints/users/reactions.ts index 372ab80c4c..69a842dbfb 100644 --- a/packages/backend/src/server/api/endpoints/users/reactions.ts +++ b/packages/backend/src/server/api/endpoints/users/reactions.ts @@ -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 { // 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'), diff --git a/packages/backend/src/server/api/openapi/gen-spec.ts b/packages/backend/src/server/api/openapi/gen-spec.ts index 971a6116bf..5dbd4a01e1 100644 --- a/packages/backend/src/server/api/openapi/gen-spec.ts +++ b/packages/backend/src/server/api/openapi/gen-spec.ts @@ -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 = { diff --git a/packages/backend/src/server/api/openapi/schemas.ts b/packages/backend/src/server/api/openapi/schemas.ts index a862a7b742..61ce913b74 100644 --- a/packages/backend/src/server/api/openapi/schemas.ts +++ b/packages/backend/src/server/api/openapi/schemas.ts @@ -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)]), + ), + }; +} diff --git a/packages/frontend/package.json b/packages/frontend/package.json index c0cfc4a160..5197765ee3 100644 --- a/packages/frontend/package.json +++ b/packages/frontend/package.json @@ -61,7 +61,7 @@ "rollup": "4.9.6", "sanitize-html": "2.11.0", "sass": "1.70.0", - "shiki": "0.14.7", + "shiki": "1.0.0-beta.3", "strict-event-emitter-types": "2.0.0", "textarea-caret": "3.1.0", "three": "0.160.1", @@ -135,6 +135,7 @@ "vite-plugin-turbosnap": "1.0.3", "vitest": "0.34.6", "vitest-fetch-mock": "0.2.2", + "vue-component-type-helpers": "^1.8.27", "vue-eslint-parser": "9.4.2", "vue-tsc": "1.8.27" } diff --git a/packages/frontend/src/components/MkAutocomplete.vue b/packages/frontend/src/components/MkAutocomplete.vue index 9d03eab2cb..a428d85c76 100644 --- a/packages/frontend/src/components/MkAutocomplete.vue +++ b/packages/frontend/src/components/MkAutocomplete.vue @@ -431,7 +431,7 @@ function applySelect() { function chooseUser() { props.close(); - os.selectUser().then(user => { + os.selectUser({ includeSelf: true }).then(user => { complete('user', user); props.textarea.focus(); }); diff --git a/packages/frontend/src/components/MkChartLegend.vue b/packages/frontend/src/components/MkChartLegend.vue index 110eeca5db..d2b06675ba 100644 --- a/packages/frontend/src/components/MkChartLegend.vue +++ b/packages/frontend/src/components/MkChartLegend.vue @@ -30,9 +30,9 @@ function onClick(item: LegendItem) { if (chart.value == null) return; if (type.value === 'pie' || type.value === 'doughnut') { // Pie and doughnut charts only have a single dataset and visibility is per item - if (item.index) chart.value.toggleDataVisibility(item.index); + if (item.index != null) chart.value.toggleDataVisibility(item.index); } else { - if (item.datasetIndex) chart.value.setDatasetVisibility(item.datasetIndex, !chart.value.isDatasetVisible(item.datasetIndex)); + if (item.datasetIndex != null) chart.value.setDatasetVisibility(item.datasetIndex, !chart.value.isDatasetVisible(item.datasetIndex)); } chart.value.update(); } diff --git a/packages/frontend/src/components/MkCode.core.vue b/packages/frontend/src/components/MkCode.core.vue index 8fca3bb15f..c655ff416e 100644 --- a/packages/frontend/src/components/MkCode.core.vue +++ b/packages/frontend/src/components/MkCode.core.vue @@ -5,13 +5,13 @@ SPDX-License-Identifier: AGPL-3.0-only -