Merge branch 'develop' into enh-14794
This commit is contained in:
commit
dd4e3726ab
|
@ -1,12 +1,14 @@
|
||||||
## Unreleased
|
## 2024.10.2
|
||||||
|
|
||||||
### General
|
### General
|
||||||
- Feat: コンテンツの表示にログインを必須にできるように
|
- Feat: コンテンツの表示にログインを必須にできるように
|
||||||
|
- Feat: 過去のノートを非公開化/フォロワーのみ表示可能にできるように
|
||||||
|
|
||||||
### Client
|
### Client
|
||||||
- Enhance: Bull DashboardでRelationship Queueの状態も確認できるように
|
- Enhance: Bull DashboardでRelationship Queueの状態も確認できるように
|
||||||
(Cherry-picked from https://github.com/MisskeyIO/misskey/pull/751)
|
(Cherry-picked from https://github.com/MisskeyIO/misskey/pull/751)
|
||||||
- Enhance: ドライブでソートができるように
|
- Enhance: ドライブでソートができるように
|
||||||
|
- Enhance: 「単なるラッキー」の取得条件を変更
|
||||||
- Enhance: 投稿フォームでEscキーを押したときIME入力中ならフォームを閉じないように( #10866 )
|
- Enhance: 投稿フォームでEscキーを押したときIME入力中ならフォームを閉じないように( #10866 )
|
||||||
- Enhance: 投稿フォームの設定メニューを改良
|
- Enhance: 投稿フォームの設定メニューを改良
|
||||||
- 投稿フォームをリセットできるように
|
- 投稿フォームをリセットできるように
|
||||||
|
@ -17,8 +19,8 @@
|
||||||
- Fix: デッキのタイムラインカラムで「センシティブなファイルを含むノートを表示」設定が使用できなかった問題を修正
|
- Fix: デッキのタイムラインカラムで「センシティブなファイルを含むノートを表示」設定が使用できなかった問題を修正
|
||||||
|
|
||||||
### Server
|
### Server
|
||||||
-
|
- Fix: Nested proxy requestsを検出した際にブロックするように
|
||||||
|
[ghsa-gq5q-c77c-v236](https://github.com/misskey-dev/misskey/security/advisories/ghsa-gq5q-c77c-v236)
|
||||||
|
|
||||||
## 2024.10.1
|
## 2024.10.1
|
||||||
|
|
||||||
|
|
|
@ -3806,6 +3806,18 @@ export interface Locale extends ILocale {
|
||||||
* 1ヶ月
|
* 1ヶ月
|
||||||
*/
|
*/
|
||||||
"oneMonth": string;
|
"oneMonth": string;
|
||||||
|
/**
|
||||||
|
* 3ヶ月
|
||||||
|
*/
|
||||||
|
"threeMonths": string;
|
||||||
|
/**
|
||||||
|
* 1年
|
||||||
|
*/
|
||||||
|
"oneYear": string;
|
||||||
|
/**
|
||||||
|
* 3日
|
||||||
|
*/
|
||||||
|
"threeDays": string;
|
||||||
/**
|
/**
|
||||||
* 反映されるまで時間がかかる場合があります。
|
* 反映されるまで時間がかかる場合があります。
|
||||||
*/
|
*/
|
||||||
|
@ -5212,7 +5224,7 @@ export interface Locale extends ILocale {
|
||||||
*/
|
*/
|
||||||
"requireSigninToViewContents": string;
|
"requireSigninToViewContents": string;
|
||||||
/**
|
/**
|
||||||
* あなたが作成した全てのノートなどのコンテンツを表示するのにログインを必須にします。クローラーから情報を収集されるのを防ぐ効果が期待できます。
|
* あなたが作成した全てのノートなどのコンテンツを表示するのにログインを必須にします。クローラーに情報が収集されるのを防ぐ効果が期待できます。
|
||||||
*/
|
*/
|
||||||
"requireSigninToViewContentsDescription1": string;
|
"requireSigninToViewContentsDescription1": string;
|
||||||
/**
|
/**
|
||||||
|
@ -5223,6 +5235,34 @@ export interface Locale extends ILocale {
|
||||||
* リモートサーバーに連合されたコンテンツでは、これらの制限が適用されない場合があります。
|
* リモートサーバーに連合されたコンテンツでは、これらの制限が適用されない場合があります。
|
||||||
*/
|
*/
|
||||||
"requireSigninToViewContentsDescription3": string;
|
"requireSigninToViewContentsDescription3": string;
|
||||||
|
/**
|
||||||
|
* 過去のノートをフォロワーのみ表示可能にする
|
||||||
|
*/
|
||||||
|
"makeNotesFollowersOnlyBefore": string;
|
||||||
|
/**
|
||||||
|
* この機能が有効になっている間、設定された日時より過去、または設定された時間を経過しているノートがフォロワーのみ表示可能になります。無効に戻すと、ノートの公開状態も元に戻ります。
|
||||||
|
*/
|
||||||
|
"makeNotesFollowersOnlyBeforeDescription": string;
|
||||||
|
/**
|
||||||
|
* 過去のノートを非公開化する
|
||||||
|
*/
|
||||||
|
"makeNotesHiddenBefore": string;
|
||||||
|
/**
|
||||||
|
* この機能が有効になっている間、設定された日時より過去、または設定された時間を経過しているノートが自分のみ表示可能(非公開化)になります。無効に戻すと、ノートの公開状態も元に戻ります。
|
||||||
|
*/
|
||||||
|
"makeNotesHiddenBeforeDescription": string;
|
||||||
|
/**
|
||||||
|
* リモートサーバーに連合されたノートには効果が及ばない場合があります。
|
||||||
|
*/
|
||||||
|
"mayNotEffectForFederatedNotes": string;
|
||||||
|
/**
|
||||||
|
* 指定した時間を経過しているノート
|
||||||
|
*/
|
||||||
|
"notesHavePassedSpecifiedPeriod": string;
|
||||||
|
/**
|
||||||
|
* 指定した日時より前のノート
|
||||||
|
*/
|
||||||
|
"notesOlderThanSpecifiedDateAndTime": string;
|
||||||
};
|
};
|
||||||
"_abuseUserReport": {
|
"_abuseUserReport": {
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -947,6 +947,9 @@ oneHour: "1時間"
|
||||||
oneDay: "1日"
|
oneDay: "1日"
|
||||||
oneWeek: "1週間"
|
oneWeek: "1週間"
|
||||||
oneMonth: "1ヶ月"
|
oneMonth: "1ヶ月"
|
||||||
|
threeMonths: "3ヶ月"
|
||||||
|
oneYear: "1年"
|
||||||
|
threeDays: "3日"
|
||||||
reflectMayTakeTime: "反映されるまで時間がかかる場合があります。"
|
reflectMayTakeTime: "反映されるまで時間がかかる場合があります。"
|
||||||
failedToFetchAccountInformation: "アカウント情報の取得に失敗しました"
|
failedToFetchAccountInformation: "アカウント情報の取得に失敗しました"
|
||||||
rateLimitExceeded: "レート制限を超えました"
|
rateLimitExceeded: "レート制限を超えました"
|
||||||
|
@ -1300,9 +1303,16 @@ reset: "リセット"
|
||||||
|
|
||||||
_accountSettings:
|
_accountSettings:
|
||||||
requireSigninToViewContents: "コンテンツの表示にログインを必須にする"
|
requireSigninToViewContents: "コンテンツの表示にログインを必須にする"
|
||||||
requireSigninToViewContentsDescription1: "あなたが作成した全てのノートなどのコンテンツを表示するのにログインを必須にします。クローラーから情報を収集されるのを防ぐ効果が期待できます。"
|
requireSigninToViewContentsDescription1: "あなたが作成した全てのノートなどのコンテンツを表示するのにログインを必須にします。クローラーに情報が収集されるのを防ぐ効果が期待できます。"
|
||||||
requireSigninToViewContentsDescription2: "URLプレビュー(OGP)、Webページへの埋め込み、ノートの引用に対応していないサーバーからの表示も不可になります。"
|
requireSigninToViewContentsDescription2: "URLプレビュー(OGP)、Webページへの埋め込み、ノートの引用に対応していないサーバーからの表示も不可になります。"
|
||||||
requireSigninToViewContentsDescription3: "リモートサーバーに連合されたコンテンツでは、これらの制限が適用されない場合があります。"
|
requireSigninToViewContentsDescription3: "リモートサーバーに連合されたコンテンツでは、これらの制限が適用されない場合があります。"
|
||||||
|
makeNotesFollowersOnlyBefore: "過去のノートをフォロワーのみ表示可能にする"
|
||||||
|
makeNotesFollowersOnlyBeforeDescription: "この機能が有効になっている間、設定された日時より過去、または設定された時間を経過しているノートがフォロワーのみ表示可能になります。無効に戻すと、ノートの公開状態も元に戻ります。"
|
||||||
|
makeNotesHiddenBefore: "過去のノートを非公開化する"
|
||||||
|
makeNotesHiddenBeforeDescription: "この機能が有効になっている間、設定された日時より過去、または設定された時間を経過しているノートが自分のみ表示可能(非公開化)になります。無効に戻すと、ノートの公開状態も元に戻ります。"
|
||||||
|
mayNotEffectForFederatedNotes: "リモートサーバーに連合されたノートには効果が及ばない場合があります。"
|
||||||
|
notesHavePassedSpecifiedPeriod: "指定した時間を経過しているノート"
|
||||||
|
notesOlderThanSpecifiedDateAndTime: "指定した日時より前のノート"
|
||||||
|
|
||||||
_abuseUserReport:
|
_abuseUserReport:
|
||||||
forward: "転送"
|
forward: "転送"
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "misskey",
|
"name": "misskey",
|
||||||
"version": "2024.10.1",
|
"version": "2024.10.2-alpha.0",
|
||||||
"codename": "nasubi",
|
"codename": "nasubi",
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
|
|
|
@ -0,0 +1,18 @@
|
||||||
|
/*
|
||||||
|
* SPDX-FileCopyrightText: syuilo and misskey-project
|
||||||
|
* SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
*/
|
||||||
|
|
||||||
|
export class MakeNotesHiddenBefore1729486255072 {
|
||||||
|
name = 'MakeNotesHiddenBefore1729486255072'
|
||||||
|
|
||||||
|
async up(queryRunner) {
|
||||||
|
await queryRunner.query(`ALTER TABLE "user" ADD "makeNotesFollowersOnlyBefore" integer`);
|
||||||
|
await queryRunner.query(`ALTER TABLE "user" ADD "makeNotesHiddenBefore" integer`);
|
||||||
|
}
|
||||||
|
|
||||||
|
async down(queryRunner) {
|
||||||
|
await queryRunner.query(`ALTER TABLE "user" DROP COLUMN "makeNotesHiddenBefore"`);
|
||||||
|
await queryRunner.query(`ALTER TABLE "user" DROP COLUMN "makeNotesFollowersOnlyBefore"`);
|
||||||
|
}
|
||||||
|
}
|
|
@ -84,6 +84,8 @@ function generateDummyUser(override?: Partial<MiUser>): MiUser {
|
||||||
isHibernated: false,
|
isHibernated: false,
|
||||||
isDeleted: false,
|
isDeleted: false,
|
||||||
requireSigninToViewContents: false,
|
requireSigninToViewContents: false,
|
||||||
|
makeNotesFollowersOnlyBefore: null,
|
||||||
|
makeNotesHiddenBefore: null,
|
||||||
emojis: [],
|
emojis: [],
|
||||||
score: 0,
|
score: 0,
|
||||||
host: null,
|
host: null,
|
||||||
|
|
|
@ -496,6 +496,8 @@ export class ApRendererService {
|
||||||
_misskey_summary: profile.description,
|
_misskey_summary: profile.description,
|
||||||
_misskey_followedMessage: profile.followedMessage,
|
_misskey_followedMessage: profile.followedMessage,
|
||||||
_misskey_requireSigninToViewContents: user.requireSigninToViewContents,
|
_misskey_requireSigninToViewContents: user.requireSigninToViewContents,
|
||||||
|
_misskey_makeNotesFollowersOnlyBefore: user.makeNotesFollowersOnlyBefore,
|
||||||
|
_misskey_makeNotesHiddenBefore: user.makeNotesHiddenBefore,
|
||||||
icon: avatar ? this.renderImage(avatar) : null,
|
icon: avatar ? this.renderImage(avatar) : null,
|
||||||
image: banner ? this.renderImage(banner) : null,
|
image: banner ? this.renderImage(banner) : null,
|
||||||
tag,
|
tag,
|
||||||
|
|
|
@ -556,6 +556,8 @@ const extension_context_definition = {
|
||||||
'_misskey_summary': 'misskey:_misskey_summary',
|
'_misskey_summary': 'misskey:_misskey_summary',
|
||||||
'_misskey_followedMessage': 'misskey:_misskey_followedMessage',
|
'_misskey_followedMessage': 'misskey:_misskey_followedMessage',
|
||||||
'_misskey_requireSigninToViewContents': 'misskey:_misskey_requireSigninToViewContents',
|
'_misskey_requireSigninToViewContents': 'misskey:_misskey_requireSigninToViewContents',
|
||||||
|
'_misskey_makeNotesFollowersOnlyBefore': 'misskey:_misskey_makeNotesFollowersOnlyBefore',
|
||||||
|
'_misskey_makeNotesHiddenBefore': 'misskey:_misskey_makeNotesHiddenBefore',
|
||||||
'isCat': 'misskey:isCat',
|
'isCat': 'misskey:isCat',
|
||||||
// vcard
|
// vcard
|
||||||
vcard: 'http://www.w3.org/2006/vcard/ns#',
|
vcard: 'http://www.w3.org/2006/vcard/ns#',
|
||||||
|
|
|
@ -357,6 +357,8 @@ export class ApPersonService implements OnModuleInit {
|
||||||
isBot,
|
isBot,
|
||||||
isCat: (person as any).isCat === true,
|
isCat: (person as any).isCat === true,
|
||||||
requireSigninToViewContents: (person as any).requireSigninToViewContents === true,
|
requireSigninToViewContents: (person as any).requireSigninToViewContents === true,
|
||||||
|
makeNotesFollowersOnlyBefore: (person as any).makeNotesFollowersOnlyBefore ?? null,
|
||||||
|
makeNotesHiddenBefore: (person as any).makeNotesHiddenBefore ?? null,
|
||||||
emojis,
|
emojis,
|
||||||
})) as MiRemoteUser;
|
})) as MiRemoteUser;
|
||||||
|
|
||||||
|
|
|
@ -15,6 +15,8 @@ export interface IObject {
|
||||||
_misskey_summary?: string;
|
_misskey_summary?: string;
|
||||||
_misskey_followedMessage?: string | null;
|
_misskey_followedMessage?: string | null;
|
||||||
_misskey_requireSigninToViewContents?: boolean;
|
_misskey_requireSigninToViewContents?: boolean;
|
||||||
|
_misskey_makeNotesFollowersOnlyBefore?: number | null;
|
||||||
|
_misskey_makeNotesHiddenBefore?: number | null;
|
||||||
published?: string;
|
published?: string;
|
||||||
cc?: ApObject;
|
cc?: ApObject;
|
||||||
to?: ApObject;
|
to?: ApObject;
|
||||||
|
|
|
@ -102,34 +102,62 @@ export class NoteEntityService implements OnModuleInit {
|
||||||
}
|
}
|
||||||
|
|
||||||
@bindThis
|
@bindThis
|
||||||
private async hideNote(packedNote: Packed<'Note'>, meId: MiUser['id'] | null) {
|
private async hideNote(packedNote: Packed<'Note'>, meId: MiUser['id'] | null): Promise<void> {
|
||||||
|
// FIXME: このvisibility変更処理が当関数にあるのは若干不自然かもしれない(関数名を treatVisibility とかに変える手もある)
|
||||||
|
if (packedNote.visibility === 'public' || packedNote.visibility === 'home') {
|
||||||
|
const followersOnlyBefore = packedNote.user.makeNotesFollowersOnlyBefore;
|
||||||
|
if ((followersOnlyBefore != null)
|
||||||
|
&& (
|
||||||
|
(followersOnlyBefore <= 0 && (Date.now() - new Date(packedNote.createdAt).getTime() > 0 - (followersOnlyBefore * 1000)))
|
||||||
|
|| (followersOnlyBefore > 0 && (new Date(packedNote.createdAt).getTime() < followersOnlyBefore * 1000))
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
packedNote.visibility = 'followers';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (meId === packedNote.userId) return;
|
||||||
|
|
||||||
// TODO: isVisibleForMe を使うようにしても良さそう(型違うけど)
|
// TODO: isVisibleForMe を使うようにしても良さそう(型違うけど)
|
||||||
let hide = false;
|
let hide = false;
|
||||||
|
|
||||||
|
if (packedNote.user.requireSigninToViewContents && meId == null) {
|
||||||
|
hide = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!hide) {
|
||||||
|
const hiddenBefore = packedNote.user.makeNotesHiddenBefore;
|
||||||
|
if ((hiddenBefore != null)
|
||||||
|
&& (
|
||||||
|
(hiddenBefore <= 0 && (Date.now() - new Date(packedNote.createdAt).getTime() > 0 - (hiddenBefore * 1000)))
|
||||||
|
|| (hiddenBefore > 0 && (new Date(packedNote.createdAt).getTime() < hiddenBefore * 1000))
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
hide = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// visibility が specified かつ自分が指定されていなかったら非表示
|
// visibility が specified かつ自分が指定されていなかったら非表示
|
||||||
|
if (!hide) {
|
||||||
if (packedNote.visibility === 'specified') {
|
if (packedNote.visibility === 'specified') {
|
||||||
if (meId == null) {
|
if (meId == null) {
|
||||||
hide = true;
|
hide = true;
|
||||||
} else if (meId === packedNote.userId) {
|
|
||||||
hide = false;
|
|
||||||
} else {
|
} else {
|
||||||
// 指定されているかどうか
|
// 指定されているかどうか
|
||||||
const specified = packedNote.visibleUserIds!.some(id => meId === id);
|
const specified = packedNote.visibleUserIds!.some(id => meId === id);
|
||||||
|
|
||||||
if (specified) {
|
if (!specified) {
|
||||||
hide = false;
|
|
||||||
} else {
|
|
||||||
hide = true;
|
hide = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// visibility が followers かつ自分が投稿者のフォロワーでなかったら非表示
|
// visibility が followers かつ自分が投稿者のフォロワーでなかったら非表示
|
||||||
|
if (!hide) {
|
||||||
if (packedNote.visibility === 'followers') {
|
if (packedNote.visibility === 'followers') {
|
||||||
if (meId == null) {
|
if (meId == null) {
|
||||||
hide = true;
|
hide = true;
|
||||||
} else if (meId === packedNote.userId) {
|
|
||||||
hide = false;
|
|
||||||
} else if (packedNote.reply && (meId === packedNote.reply.userId)) {
|
} else if (packedNote.reply && (meId === packedNote.reply.userId)) {
|
||||||
// 自分の投稿に対するリプライ
|
// 自分の投稿に対するリプライ
|
||||||
hide = false;
|
hide = false;
|
||||||
|
@ -138,6 +166,7 @@ export class NoteEntityService implements OnModuleInit {
|
||||||
hide = false;
|
hide = false;
|
||||||
} else {
|
} else {
|
||||||
// フォロワーかどうか
|
// フォロワーかどうか
|
||||||
|
// TODO: 当関数呼び出しごとにクエリが走るのは重そうだからなんとかする
|
||||||
const isFollowing = await this.followingsRepository.exists({
|
const isFollowing = await this.followingsRepository.exists({
|
||||||
where: {
|
where: {
|
||||||
followeeId: packedNote.userId,
|
followeeId: packedNote.userId,
|
||||||
|
@ -148,9 +177,6 @@ export class NoteEntityService implements OnModuleInit {
|
||||||
hide = !isFollowing;
|
hide = !isFollowing;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (packedNote.user.requireSigninToViewContents && meId == null) {
|
|
||||||
hide = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (hide) {
|
if (hide) {
|
||||||
|
@ -161,6 +187,7 @@ export class NoteEntityService implements OnModuleInit {
|
||||||
packedNote.poll = undefined;
|
packedNote.poll = undefined;
|
||||||
packedNote.cw = null;
|
packedNote.cw = null;
|
||||||
packedNote.isHidden = true;
|
packedNote.isHidden = true;
|
||||||
|
// TODO: hiddenReason みたいなのを提供しても良さそう
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -491,6 +491,8 @@ export class UserEntityService implements OnModuleInit {
|
||||||
isBot: user.isBot,
|
isBot: user.isBot,
|
||||||
isCat: user.isCat,
|
isCat: user.isCat,
|
||||||
requireSigninToViewContents: user.requireSigninToViewContents === false ? undefined : true,
|
requireSigninToViewContents: user.requireSigninToViewContents === false ? undefined : true,
|
||||||
|
makeNotesFollowersOnlyBefore: user.makeNotesFollowersOnlyBefore ?? undefined,
|
||||||
|
makeNotesHiddenBefore: user.makeNotesHiddenBefore ?? undefined,
|
||||||
instance: user.host ? this.federatedInstanceService.federatedInstanceCache.fetch(user.host).then(instance => instance ? {
|
instance: user.host ? this.federatedInstanceService.federatedInstanceCache.fetch(user.host).then(instance => instance ? {
|
||||||
name: instance.name,
|
name: instance.name,
|
||||||
softwareName: instance.softwareName,
|
softwareName: instance.softwareName,
|
||||||
|
|
|
@ -207,6 +207,18 @@ export class MiUser {
|
||||||
})
|
})
|
||||||
public requireSigninToViewContents: boolean;
|
public requireSigninToViewContents: boolean;
|
||||||
|
|
||||||
|
// in sec, マイナスで相対時間
|
||||||
|
@Column('integer', {
|
||||||
|
nullable: true,
|
||||||
|
})
|
||||||
|
public makeNotesFollowersOnlyBefore: number | null;
|
||||||
|
|
||||||
|
// in sec, マイナスで相対時間
|
||||||
|
@Column('integer', {
|
||||||
|
nullable: true,
|
||||||
|
})
|
||||||
|
public makeNotesHiddenBefore: number | null;
|
||||||
|
|
||||||
// アカウントが削除されたかどうかのフラグだが、完全に削除される際は物理削除なので実質削除されるまでの「削除が進行しているかどうか」のフラグ
|
// アカウントが削除されたかどうかのフラグだが、完全に削除される際は物理削除なので実質削除されるまでの「削除が進行しているかどうか」のフラグ
|
||||||
@Column('boolean', {
|
@Column('boolean', {
|
||||||
default: false,
|
default: false,
|
||||||
|
|
|
@ -119,6 +119,14 @@ export const packedUserLiteSchema = {
|
||||||
type: 'boolean',
|
type: 'boolean',
|
||||||
nullable: false, optional: true,
|
nullable: false, optional: true,
|
||||||
},
|
},
|
||||||
|
makeNotesFollowersOnlyBefore: {
|
||||||
|
type: 'number',
|
||||||
|
nullable: true, optional: true,
|
||||||
|
},
|
||||||
|
makeNotesHiddenBefore: {
|
||||||
|
type: 'number',
|
||||||
|
nullable: true, optional: true,
|
||||||
|
},
|
||||||
instance: {
|
instance: {
|
||||||
type: 'object',
|
type: 'object',
|
||||||
nullable: false, optional: true,
|
nullable: false, optional: true,
|
||||||
|
|
|
@ -319,6 +319,12 @@ export class FileServerService {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!request.headers['user-agent']) {
|
||||||
|
throw new StatusError('User-Agent is required', 400, 'User-Agent is required');
|
||||||
|
} else if (request.headers['user-agent'].toLowerCase().indexOf('misskey/') !== -1) {
|
||||||
|
throw new StatusError('Refusing to proxy a request from another proxy', 403, 'Proxy is recursive');
|
||||||
|
}
|
||||||
|
|
||||||
// Create temp file
|
// Create temp file
|
||||||
const file = await this.getStreamAndTypeFromUrl(url);
|
const file = await this.getStreamAndTypeFromUrl(url);
|
||||||
if (file === '404') {
|
if (file === '404') {
|
||||||
|
|
|
@ -180,6 +180,8 @@ export const paramDef = {
|
||||||
noCrawle: { type: 'boolean' },
|
noCrawle: { type: 'boolean' },
|
||||||
preventAiLearning: { type: 'boolean' },
|
preventAiLearning: { type: 'boolean' },
|
||||||
requireSigninToViewContents: { type: 'boolean' },
|
requireSigninToViewContents: { type: 'boolean' },
|
||||||
|
makeNotesFollowersOnlyBefore: { type: 'integer', nullable: true },
|
||||||
|
makeNotesHiddenBefore: { type: 'integer', nullable: true },
|
||||||
isBot: { type: 'boolean' },
|
isBot: { type: 'boolean' },
|
||||||
isCat: { type: 'boolean' },
|
isCat: { type: 'boolean' },
|
||||||
injectFeaturedNote: { type: 'boolean' },
|
injectFeaturedNote: { type: 'boolean' },
|
||||||
|
@ -336,6 +338,8 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
||||||
if (typeof ps.noCrawle === 'boolean') profileUpdates.noCrawle = ps.noCrawle;
|
if (typeof ps.noCrawle === 'boolean') profileUpdates.noCrawle = ps.noCrawle;
|
||||||
if (typeof ps.preventAiLearning === 'boolean') profileUpdates.preventAiLearning = ps.preventAiLearning;
|
if (typeof ps.preventAiLearning === 'boolean') profileUpdates.preventAiLearning = ps.preventAiLearning;
|
||||||
if (typeof ps.requireSigninToViewContents === 'boolean') updates.requireSigninToViewContents = ps.requireSigninToViewContents;
|
if (typeof ps.requireSigninToViewContents === 'boolean') updates.requireSigninToViewContents = ps.requireSigninToViewContents;
|
||||||
|
if ((typeof ps.makeNotesFollowersOnlyBefore === 'number') || (ps.makeNotesFollowersOnlyBefore === null)) updates.makeNotesFollowersOnlyBefore = ps.makeNotesFollowersOnlyBefore;
|
||||||
|
if ((typeof ps.makeNotesHiddenBefore === 'number') || (ps.makeNotesHiddenBefore === null)) updates.makeNotesHiddenBefore = ps.makeNotesHiddenBefore;
|
||||||
if (typeof ps.isCat === 'boolean') updates.isCat = ps.isCat;
|
if (typeof ps.isCat === 'boolean') updates.isCat = ps.isCat;
|
||||||
if (typeof ps.injectFeaturedNote === 'boolean') profileUpdates.injectFeaturedNote = ps.injectFeaturedNote;
|
if (typeof ps.injectFeaturedNote === 'boolean') profileUpdates.injectFeaturedNote = ps.injectFeaturedNote;
|
||||||
if (typeof ps.receiveAnnouncementEmail === 'boolean') profileUpdates.receiveAnnouncementEmail = ps.receiveAnnouncementEmail;
|
if (typeof ps.receiveAnnouncementEmail === 'boolean') profileUpdates.receiveAnnouncementEmail = ps.receiveAnnouncementEmail;
|
||||||
|
|
|
@ -231,11 +231,41 @@ export async function mainBoot() {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!claimedAchievements.includes('justPlainLucky')) {
|
if (!claimedAchievements.includes('justPlainLucky')) {
|
||||||
window.setInterval(() => {
|
let justPlainLuckyTimer: number | null = null;
|
||||||
|
let lastVisibilityChangedAt = Date.now();
|
||||||
|
|
||||||
|
function claimPlainLucky() {
|
||||||
|
if (document.visibilityState !== 'visible') {
|
||||||
|
if (justPlainLuckyTimer != null) window.clearTimeout(justPlainLuckyTimer);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (Math.floor(Math.random() * 20000) === 0) {
|
if (Math.floor(Math.random() * 20000) === 0) {
|
||||||
claimAchievement('justPlainLucky');
|
claimAchievement('justPlainLucky');
|
||||||
|
} else {
|
||||||
|
justPlainLuckyTimer = window.setTimeout(claimPlainLucky, 1000 * 10);
|
||||||
}
|
}
|
||||||
}, 1000 * 10);
|
}
|
||||||
|
|
||||||
|
window.addEventListener('visibilitychange', () => {
|
||||||
|
const now = Date.now();
|
||||||
|
|
||||||
|
if (document.visibilityState === 'visible') {
|
||||||
|
// タブを高速で切り替えたら取得処理が何度も走るのを防ぐ
|
||||||
|
if ((now - lastVisibilityChangedAt) < 1000 * 10) {
|
||||||
|
justPlainLuckyTimer = window.setTimeout(claimPlainLucky, 1000 * 10);
|
||||||
|
} else {
|
||||||
|
claimPlainLucky();
|
||||||
|
}
|
||||||
|
} else if (justPlainLuckyTimer != null) {
|
||||||
|
window.clearTimeout(justPlainLuckyTimer);
|
||||||
|
justPlainLuckyTimer = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
lastVisibilityChangedAt = now;
|
||||||
|
}, { passive: true });
|
||||||
|
|
||||||
|
claimPlainLucky();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!claimedAchievements.includes('client30min')) {
|
if (!claimedAchievements.includes('client30min')) {
|
||||||
|
|
|
@ -46,7 +46,7 @@ import type { MenuItem } from '@/types/menu.js';
|
||||||
import * as os from '@/os.js';
|
import * as os from '@/os.js';
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
modelValue: string | null;
|
modelValue: string | number | null;
|
||||||
required?: boolean;
|
required?: boolean;
|
||||||
readonly?: boolean;
|
readonly?: boolean;
|
||||||
disabled?: boolean;
|
disabled?: boolean;
|
||||||
|
|
|
@ -45,17 +45,89 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
</MkSwitch>
|
</MkSwitch>
|
||||||
|
|
||||||
<FormSection>
|
<FormSection>
|
||||||
<template #label>{{ i18n.ts.lockdown }}</template>
|
<template #label>{{ i18n.ts.lockdown }}<span class="_beta">{{ i18n.ts.beta }}</span></template>
|
||||||
|
|
||||||
<div class="_gaps_m">
|
<div class="_gaps_m">
|
||||||
<MkSwitch v-model="requireSigninToViewContents" @update:modelValue="save()">
|
<MkSwitch v-model="requireSigninToViewContents" @update:modelValue="save()">
|
||||||
{{ i18n.ts._accountSettings.requireSigninToViewContents }}<span class="_beta">{{ i18n.ts.beta }}</span>
|
{{ i18n.ts._accountSettings.requireSigninToViewContents }}
|
||||||
<template #caption>
|
<template #caption>
|
||||||
<div>{{ i18n.ts._accountSettings.requireSigninToViewContentsDescription1 }}</div>
|
<div>{{ i18n.ts._accountSettings.requireSigninToViewContentsDescription1 }}</div>
|
||||||
<div><i class="ti ti-alert-triangle" style="color: var(--MI_THEME-warn);"></i> {{ i18n.ts._accountSettings.requireSigninToViewContentsDescription2 }}</div>
|
<div><i class="ti ti-alert-triangle" style="color: var(--MI_THEME-warn);"></i> {{ i18n.ts._accountSettings.requireSigninToViewContentsDescription2 }}</div>
|
||||||
<div><i class="ti ti-alert-triangle" style="color: var(--MI_THEME-warn);"></i> {{ i18n.ts._accountSettings.requireSigninToViewContentsDescription3 }}</div>
|
<div><i class="ti ti-alert-triangle" style="color: var(--MI_THEME-warn);"></i> {{ i18n.ts._accountSettings.requireSigninToViewContentsDescription3 }}</div>
|
||||||
</template>
|
</template>
|
||||||
</MkSwitch>
|
</MkSwitch>
|
||||||
|
|
||||||
|
<FormSlot>
|
||||||
|
<template #label>{{ i18n.ts._accountSettings.makeNotesFollowersOnlyBefore }}</template>
|
||||||
|
|
||||||
|
<div class="_gaps_s">
|
||||||
|
<MkSelect :modelValue="makeNotesFollowersOnlyBefore_type" @update:modelValue="makeNotesFollowersOnlyBefore = $event === 'relative' ? -604800 : $event === 'absolute' ? Math.floor(Date.now() / 1000) : null">
|
||||||
|
<option :value="null">{{ i18n.ts.none }}</option>
|
||||||
|
<option value="relative">{{ i18n.ts._accountSettings.notesHavePassedSpecifiedPeriod }}</option>
|
||||||
|
<option value="absolute">{{ i18n.ts._accountSettings.notesOlderThanSpecifiedDateAndTime }}</option>
|
||||||
|
</MkSelect>
|
||||||
|
|
||||||
|
<MkSelect v-if="makeNotesFollowersOnlyBefore_type === 'relative'" v-model="makeNotesFollowersOnlyBefore">
|
||||||
|
<option :value="-3600">{{ i18n.ts.oneHour }}</option>
|
||||||
|
<option :value="-86400">{{ i18n.ts.oneDay }}</option>
|
||||||
|
<option :value="-259200">{{ i18n.ts.threeDays }}</option>
|
||||||
|
<option :value="-604800">{{ i18n.ts.oneWeek }}</option>
|
||||||
|
<option :value="-2592000">{{ i18n.ts.oneMonth }}</option>
|
||||||
|
<option :value="-7776000">{{ i18n.ts.threeMonths }}</option>
|
||||||
|
<option :value="-31104000">{{ i18n.ts.oneYear }}</option>
|
||||||
|
</MkSelect>
|
||||||
|
|
||||||
|
<MkInput
|
||||||
|
v-if="makeNotesFollowersOnlyBefore_type === 'absolute'"
|
||||||
|
:modelValue="formatDateTimeString(new Date(makeNotesFollowersOnlyBefore * 1000), 'yyyy-MM-dd')"
|
||||||
|
type="date"
|
||||||
|
:manualSave="true"
|
||||||
|
@update:modelValue="makeNotesFollowersOnlyBefore = Math.floor(new Date($event).getTime() / 1000)"
|
||||||
|
>
|
||||||
|
</MkInput>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<template #caption>
|
||||||
|
<div>{{ i18n.ts._accountSettings.makeNotesFollowersOnlyBeforeDescription }}</div>
|
||||||
|
<div><i class="ti ti-alert-triangle" style="color: var(--MI_THEME-warn);"></i> {{ i18n.ts._accountSettings.mayNotEffectForFederatedNotes }}</div>
|
||||||
|
</template>
|
||||||
|
</FormSlot>
|
||||||
|
|
||||||
|
<FormSlot>
|
||||||
|
<template #label>{{ i18n.ts._accountSettings.makeNotesHiddenBefore }}</template>
|
||||||
|
|
||||||
|
<div class="_gaps_s">
|
||||||
|
<MkSelect :modelValue="makeNotesHiddenBefore_type" @update:modelValue="makeNotesHiddenBefore = $event === 'relative' ? -604800 : $event === 'absolute' ? Math.floor(Date.now() / 1000) : null">
|
||||||
|
<option :value="null">{{ i18n.ts.none }}</option>
|
||||||
|
<option value="relative">{{ i18n.ts._accountSettings.notesHavePassedSpecifiedPeriod }}</option>
|
||||||
|
<option value="absolute">{{ i18n.ts._accountSettings.notesOlderThanSpecifiedDateAndTime }}</option>
|
||||||
|
</MkSelect>
|
||||||
|
|
||||||
|
<MkSelect v-if="makeNotesHiddenBefore_type === 'relative'" v-model="makeNotesHiddenBefore">
|
||||||
|
<option :value="-3600">{{ i18n.ts.oneHour }}</option>
|
||||||
|
<option :value="-86400">{{ i18n.ts.oneDay }}</option>
|
||||||
|
<option :value="-259200">{{ i18n.ts.threeDays }}</option>
|
||||||
|
<option :value="-604800">{{ i18n.ts.oneWeek }}</option>
|
||||||
|
<option :value="-2592000">{{ i18n.ts.oneMonth }}</option>
|
||||||
|
<option :value="-7776000">{{ i18n.ts.threeMonths }}</option>
|
||||||
|
<option :value="-31104000">{{ i18n.ts.oneYear }}</option>
|
||||||
|
</MkSelect>
|
||||||
|
|
||||||
|
<MkInput
|
||||||
|
v-if="makeNotesHiddenBefore_type === 'absolute'"
|
||||||
|
:modelValue="formatDateTimeString(new Date(makeNotesHiddenBefore * 1000), 'yyyy-MM-dd')"
|
||||||
|
type="date"
|
||||||
|
:manualSave="true"
|
||||||
|
@update:modelValue="makeNotesHiddenBefore = Math.floor(new Date($event).getTime() / 1000)"
|
||||||
|
>
|
||||||
|
</MkInput>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<template #caption>
|
||||||
|
<div>{{ i18n.ts._accountSettings.makeNotesHiddenBeforeDescription }}</div>
|
||||||
|
<div><i class="ti ti-alert-triangle" style="color: var(--MI_THEME-warn);"></i> {{ i18n.ts._accountSettings.mayNotEffectForFederatedNotes }}</div>
|
||||||
|
</template>
|
||||||
|
</FormSlot>
|
||||||
</div>
|
</div>
|
||||||
</FormSection>
|
</FormSection>
|
||||||
|
|
||||||
|
@ -87,7 +159,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { ref, computed } from 'vue';
|
import { ref, computed, watch } from 'vue';
|
||||||
import MkSwitch from '@/components/MkSwitch.vue';
|
import MkSwitch from '@/components/MkSwitch.vue';
|
||||||
import MkSelect from '@/components/MkSelect.vue';
|
import MkSelect from '@/components/MkSelect.vue';
|
||||||
import FormSection from '@/components/form/section.vue';
|
import FormSection from '@/components/form/section.vue';
|
||||||
|
@ -97,6 +169,9 @@ import { defaultStore } from '@/store.js';
|
||||||
import { i18n } from '@/i18n.js';
|
import { i18n } from '@/i18n.js';
|
||||||
import { signinRequired } from '@/account.js';
|
import { signinRequired } from '@/account.js';
|
||||||
import { definePageMetadata } from '@/scripts/page-metadata.js';
|
import { definePageMetadata } from '@/scripts/page-metadata.js';
|
||||||
|
import FormSlot from '@/components/form/slot.vue';
|
||||||
|
import { formatDateTimeString } from '@/scripts/format-time-string.js';
|
||||||
|
import MkInput from '@/components/MkInput.vue';
|
||||||
|
|
||||||
const $i = signinRequired();
|
const $i = signinRequired();
|
||||||
|
|
||||||
|
@ -106,6 +181,8 @@ const noCrawle = ref($i.noCrawle);
|
||||||
const preventAiLearning = ref($i.preventAiLearning);
|
const preventAiLearning = ref($i.preventAiLearning);
|
||||||
const isExplorable = ref($i.isExplorable);
|
const isExplorable = ref($i.isExplorable);
|
||||||
const requireSigninToViewContents = ref($i.requireSigninToViewContents ?? false);
|
const requireSigninToViewContents = ref($i.requireSigninToViewContents ?? false);
|
||||||
|
const makeNotesFollowersOnlyBefore = ref($i.makeNotesFollowersOnlyBefore ?? null);
|
||||||
|
const makeNotesHiddenBefore = ref($i.makeNotesHiddenBefore ?? null);
|
||||||
const hideOnlineStatus = ref($i.hideOnlineStatus);
|
const hideOnlineStatus = ref($i.hideOnlineStatus);
|
||||||
const publicReactions = ref($i.publicReactions);
|
const publicReactions = ref($i.publicReactions);
|
||||||
const followingVisibility = ref($i.followingVisibility);
|
const followingVisibility = ref($i.followingVisibility);
|
||||||
|
@ -116,6 +193,30 @@ const defaultNoteLocalOnly = computed(defaultStore.makeGetterSetter('defaultNote
|
||||||
const rememberNoteVisibility = computed(defaultStore.makeGetterSetter('rememberNoteVisibility'));
|
const rememberNoteVisibility = computed(defaultStore.makeGetterSetter('rememberNoteVisibility'));
|
||||||
const keepCw = computed(defaultStore.makeGetterSetter('keepCw'));
|
const keepCw = computed(defaultStore.makeGetterSetter('keepCw'));
|
||||||
|
|
||||||
|
const makeNotesFollowersOnlyBefore_type = computed(() => {
|
||||||
|
if (makeNotesFollowersOnlyBefore.value == null) {
|
||||||
|
return null;
|
||||||
|
} else if (makeNotesFollowersOnlyBefore.value >= 0) {
|
||||||
|
return 'absolute';
|
||||||
|
} else {
|
||||||
|
return 'relative';
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const makeNotesHiddenBefore_type = computed(() => {
|
||||||
|
if (makeNotesHiddenBefore.value == null) {
|
||||||
|
return null;
|
||||||
|
} else if (makeNotesHiddenBefore.value >= 0) {
|
||||||
|
return 'absolute';
|
||||||
|
} else {
|
||||||
|
return 'relative';
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
watch([makeNotesFollowersOnlyBefore, makeNotesHiddenBefore], () => {
|
||||||
|
save();
|
||||||
|
});
|
||||||
|
|
||||||
function save() {
|
function save() {
|
||||||
misskeyApi('i/update', {
|
misskeyApi('i/update', {
|
||||||
isLocked: !!isLocked.value,
|
isLocked: !!isLocked.value,
|
||||||
|
@ -124,6 +225,8 @@ function save() {
|
||||||
preventAiLearning: !!preventAiLearning.value,
|
preventAiLearning: !!preventAiLearning.value,
|
||||||
isExplorable: !!isExplorable.value,
|
isExplorable: !!isExplorable.value,
|
||||||
requireSigninToViewContents: !!requireSigninToViewContents.value,
|
requireSigninToViewContents: !!requireSigninToViewContents.value,
|
||||||
|
makeNotesFollowersOnlyBefore: makeNotesFollowersOnlyBefore.value,
|
||||||
|
makeNotesHiddenBefore: makeNotesHiddenBefore.value,
|
||||||
hideOnlineStatus: !!hideOnlineStatus.value,
|
hideOnlineStatus: !!hideOnlineStatus.value,
|
||||||
publicReactions: !!publicReactions.value,
|
publicReactions: !!publicReactions.value,
|
||||||
followingVisibility: followingVisibility.value,
|
followingVisibility: followingVisibility.value,
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
{
|
{
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"name": "misskey-js",
|
"name": "misskey-js",
|
||||||
"version": "2024.10.1",
|
"version": "2024.10.2-alpha.0",
|
||||||
"description": "Misskey SDK for JavaScript",
|
"description": "Misskey SDK for JavaScript",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"main": "./built/index.js",
|
"main": "./built/index.js",
|
||||||
|
|
|
@ -3737,6 +3737,8 @@ export type components = {
|
||||||
isBot?: boolean;
|
isBot?: boolean;
|
||||||
isCat?: boolean;
|
isCat?: boolean;
|
||||||
requireSigninToViewContents?: boolean;
|
requireSigninToViewContents?: boolean;
|
||||||
|
makeNotesFollowersOnlyBefore?: number | null;
|
||||||
|
makeNotesHiddenBefore?: number | null;
|
||||||
instance?: {
|
instance?: {
|
||||||
name: string | null;
|
name: string | null;
|
||||||
softwareName: string | null;
|
softwareName: string | null;
|
||||||
|
@ -19846,6 +19848,8 @@ export type operations = {
|
||||||
noCrawle?: boolean;
|
noCrawle?: boolean;
|
||||||
preventAiLearning?: boolean;
|
preventAiLearning?: boolean;
|
||||||
requireSigninToViewContents?: boolean;
|
requireSigninToViewContents?: boolean;
|
||||||
|
makeNotesFollowersOnlyBefore?: number | null;
|
||||||
|
makeNotesHiddenBefore?: number | null;
|
||||||
isBot?: boolean;
|
isBot?: boolean;
|
||||||
isCat?: boolean;
|
isCat?: boolean;
|
||||||
injectFeaturedNote?: boolean;
|
injectFeaturedNote?: boolean;
|
||||||
|
|
Loading…
Reference in New Issue