diff --git a/.github/workflows/check-misskey-js-version.yml b/.github/workflows/check-misskey-js-version.yml new file mode 100644 index 0000000000..1d74845e47 --- /dev/null +++ b/.github/workflows/check-misskey-js-version.yml @@ -0,0 +1,28 @@ +name: Check CherryPick JS version + +on: + push: + branches: [ develop ] + paths: + - packages/cherrypick-js/package.json + - package.json + pull_request: + branches: [ develop ] + paths: + - packages/cherrypick-js/package.json + - package.json + +jobs: + check-version: + # ルートの package.json と packages/cherrypick-js/package.json のバージョンが一致しているかを確認する + name: Check version + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4.1.1 + - name: Check version + run: | + if [ "$(jq -r '.version' package.json)" != "$(jq -r '.version' packages/cherrypick-js/package.json)" ]; then + echo "Version mismatch!" + exit 1 + fi 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/CHANGELOG.md b/CHANGELOG.md index 08f37b1061..e6f9ae1222 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..ee539ef68b --- /dev/null +++ b/packages/backend/migration/1706791962000-fix-meta-disableRegistration.js @@ -0,0 +1,16 @@ +/* + * SPDX-FileCopyrightText: syuilo and other misskey, cherrypick 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 6b84fd1dc3..b7f7f9fb92 100644 --- a/packages/backend/src/core/entities/UserEntityService.ts +++ b/packages/backend/src/core/entities/UserEntityService.ts @@ -447,7 +447,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 b883274c6d..d940edec7c 100644 --- a/packages/backend/src/misc/json-schema.ts +++ b/packages/backend/src/misc/json-schema.ts @@ -123,6 +123,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 b6fc3fc108..6ac4f6092d 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 f4cb15363d..7255f3aaf9 100644 --- a/packages/backend/src/server/api/endpoints/users/reactions.ts +++ b/packages/backend/src/server/api/endpoints/users/reactions.ts @@ -10,6 +10,9 @@ import { QueryService } from '@/core/QueryService.js'; import { NoteReactionEntityService } from '@/core/entities/NoteReactionEntityService.js'; import { DI } from '@/di-symbols.js'; import { MiNoteReaction } from '@/models/_.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 = { @@ -35,6 +38,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; @@ -63,14 +71,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.notesRepository.createQueryBuilder('note') diff --git a/packages/backend/src/server/api/openapi/gen-spec.ts b/packages/backend/src/server/api/openapi/gen-spec.ts index b9292360fd..4c70a1bbb9 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', @@ -31,7 +31,7 @@ export function genOpenapiSpec(config: Config) { paths: {} as any, components: { - schemas: schemas, + schemas: getSchemas(includeSelfRef), securitySchemes: { bearerAuth: { @@ -57,7 +57,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'; @@ -72,7 +72,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 2bb09b5c48..33cf18194c 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/cherrypick-js/package.json b/packages/cherrypick-js/package.json index f8c3a84cce..c69412d5d1 100644 --- a/packages/cherrypick-js/package.json +++ b/packages/cherrypick-js/package.json @@ -2,7 +2,7 @@ "type": "module", "name": "cherrypick-js", "version": "4.7.0-beta.1", - "basedMisskeyVersion": "2024.2.0-beta.7", + "basedMisskeyVersion": "2024.2.0-beta.8", "description": "CherryPick SDK for JavaScript", "types": "./built/dts/index.d.ts", "exports": { diff --git a/packages/frontend/package.json b/packages/frontend/package.json index 56160ca2a8..0253184cd4 100644 --- a/packages/frontend/package.json +++ b/packages/frontend/package.json @@ -65,7 +65,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", "temml": "0.10.20", "textarea-caret": "3.1.0", @@ -145,6 +145,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/boot/main-boot.ts b/packages/frontend/src/boot/main-boot.ts index 08fe5c7678..e47abfc983 100644 --- a/packages/frontend/src/boot/main-boot.ts +++ b/packages/frontend/src/boot/main-boot.ts @@ -88,13 +88,18 @@ export async function mainBoot() { // ▼南半球 if (month === 7 || month === 8) { const SnowfallEffect = (await import('@/scripts/snowfall-effect.js')).SnowfallEffect; - new SnowfallEffect().render(); + new SnowfallEffect({}).render(); } } else { // ▼北半球 if (month === 12 || month === 1) { const SnowfallEffect = (await import('@/scripts/snowfall-effect.js')).SnowfallEffect; - new SnowfallEffect().render(); + new SnowfallEffect({}).render(); + } else if (month === 3 || month === 4) { + const SakuraEffect = (await import('@/scripts/snowfall-effect.js')).SnowfallEffect; + new SakuraEffect({ + sakura: true, + }).render(); } } } diff --git a/packages/frontend/src/components/MkCode.core.vue b/packages/frontend/src/components/MkCode.core.vue index a6d61ab719..1b312466d3 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 -