diff --git a/locales/de-DE.yml b/locales/de-DE.yml index 83b254b2d5..fd25ba0289 100644 --- a/locales/de-DE.yml +++ b/locales/de-DE.yml @@ -973,6 +973,7 @@ neverShow: "Nicht wieder anzeigen" remindMeLater: "Vielleicht später" didYouLikeMisskey: "Gefällt dir Sharkey?" pleaseDonate: "Sharkey ist die kostenlose Software, die von {host} verwendet wird. Wir würden uns über Spenden freuen, damit dessen Entwicklung weitergeführt werden kann!" +pleaseDonateInstance: "Du kannst {host} auch direkt unterstützen, indem du an deine Instanz Administration spendest." roles: "Rollen" role: "Rolle" noRole: "Rolle nicht gefunden" @@ -1150,6 +1151,8 @@ impressumDescription: "In manchen Ländern, wie Deutschland und dessen Umgebung, privacyPolicy: "Datenschutzerklärung" privacyPolicyUrl: "Datenschutzerklärungs-URL" tosAndPrivacyPolicy: "Nutzungsbedingungen und Datenschutzerklärung" +donation: "Spenden" +donationUrl: "Spenden-URL" avatarDecorations: "Profilbilddekoration" attach: "Anbringen" detach: "Entfernen" diff --git a/locales/en-US.yml b/locales/en-US.yml index 0affe133ed..7a28ce1095 100644 --- a/locales/en-US.yml +++ b/locales/en-US.yml @@ -1014,6 +1014,7 @@ neverShow: "Don't show again" remindMeLater: "Maybe later" didYouLikeMisskey: "Have you taken a liking to Sharkey?" pleaseDonate: "{host} uses the free software, Sharkey. We would highly appreciate your donations so development of Sharkey can continue!" +pleaseDonateInstance: "You can also support {host} directly by donating to your instance administration." roles: "Roles" role: "Role" noRole: "Role not found" @@ -1200,6 +1201,8 @@ impressumDescription: "In some countries, like germany, the inclusion of operato privacyPolicy: "Privacy Policy" privacyPolicyUrl: "Privacy Policy URL" tosAndPrivacyPolicy: "Terms of Service and Privacy Policy" +donation: "Donate" +donationUrl: "Donation URL" avatarDecorations: "Avatar decorations" attach: "Attach" detach: "Remove" diff --git a/locales/index.d.ts b/locales/index.d.ts index 1ec9ed64e0..28b3a94444 100644 --- a/locales/index.d.ts +++ b/locales/index.d.ts @@ -1023,6 +1023,7 @@ export interface Locale { "remindMeLater": string; "didYouLikeMisskey": string; "pleaseDonate": string; + "pleaseDonateInstance": string; "roles": string; "role": string; "noRole": string; @@ -1209,6 +1210,8 @@ export interface Locale { "privacyPolicy": string; "privacyPolicyUrl": string; "tosAndPrivacyPolicy": string; + "donation": string; + "donationUrl": string; "avatarDecorations": string; "attach": string; "detach": string; diff --git a/locales/ja-JP.yml b/locales/ja-JP.yml index 4a4feed061..e6f9dc6b96 100644 --- a/locales/ja-JP.yml +++ b/locales/ja-JP.yml @@ -1020,6 +1020,7 @@ neverShow: "今後表示しない" remindMeLater: "また後で" didYouLikeMisskey: "Sharkeyを気に入っていただけましたか?" pleaseDonate: "Sharkeyは{host}が使用している無料のソフトウェアです。これからも開発を続けられるように、ぜひ寄付をお願いします!" +pleaseDonateInstance: "インスタンス管理への寄付によって{host}を直接サポートすることもできます。" roles: "ロール" role: "ロール" noRole: "ロールはありません" @@ -1206,6 +1207,8 @@ impressumDescription: "ドイツなどの一部の国と地域では表示が義 privacyPolicy: "プライバシーポリシー" privacyPolicyUrl: "プライバシーポリシーURL" tosAndPrivacyPolicy: "利用規約・プライバシーポリシー" +donation: "寄付する" +donationUrl: "寄付URL" avatarDecorations: "アイコンデコレーション" attach: "付ける" detach: "外す" @@ -2541,7 +2544,7 @@ _dataRequest: warn: "データのリクエストは3日ごとにしかできない。" text: "データのダウンロードが完了すると、このアカウントに登録されているEメールアドレスにEメールが送信されます。" button: "リクエスト" - + _dataSaver: _media: title: "メディアの読み込み" diff --git a/packages/backend/migration/1704744370000-add-donation-url.js b/packages/backend/migration/1704744370000-add-donation-url.js new file mode 100644 index 0000000000..c953b13cc9 --- /dev/null +++ b/packages/backend/migration/1704744370000-add-donation-url.js @@ -0,0 +1,10 @@ +export class AddDonationUrl1704744370000 { + name = 'AddDonationUrl1704744370000' + + async up(queryRunner) { + await queryRunner.query(`ALTER TABLE "meta" ADD "donationUrl" character varying(1024)`); + } + async down(queryRunner) { + await queryRunner.query(`ALTER TABLE "meta" DROP COLUMN "donationUrl"`); + } +} diff --git a/packages/backend/src/models/Meta.ts b/packages/backend/src/models/Meta.ts index e7f7458c19..6d5c4b3746 100644 --- a/packages/backend/src/models/Meta.ts +++ b/packages/backend/src/models/Meta.ts @@ -385,6 +385,12 @@ export class MiMeta { }) public privacyPolicyUrl: string | null; + @Column('varchar', { + length: 1024, + nullable: true, + }) + public donationUrl: string | null; + @Column('varchar', { length: 8192, nullable: true, diff --git a/packages/backend/src/server/NodeinfoServerService.ts b/packages/backend/src/server/NodeinfoServerService.ts index 31479269b9..a3e3c39ecc 100644 --- a/packages/backend/src/server/NodeinfoServerService.ts +++ b/packages/backend/src/server/NodeinfoServerService.ts @@ -108,6 +108,7 @@ export class NodeinfoServerService { tosUrl: meta.termsOfServiceUrl, privacyPolicyUrl: meta.privacyPolicyUrl, impressumUrl: meta.impressumUrl, + donationUrl: meta.donationUrl, repositoryUrl: meta.repositoryUrl, feedbackUrl: meta.feedbackUrl, disableRegistration: meta.disableRegistration, diff --git a/packages/backend/src/server/api/endpoints/admin/meta.ts b/packages/backend/src/server/api/endpoints/admin/meta.ts index 66b6799ed1..9fe997f889 100644 --- a/packages/backend/src/server/api/endpoints/admin/meta.ts +++ b/packages/backend/src/server/api/endpoints/admin/meta.ts @@ -415,6 +415,10 @@ export const meta = { type: 'string', optional: false, nullable: true, }, + donationUrl: { + type: 'string', + optional: false, nullable: true, + }, maintainerEmail: { type: 'string', optional: false, nullable: true, @@ -498,6 +502,7 @@ export default class extends Endpoint { // eslint- repositoryUrl: instance.repositoryUrl, feedbackUrl: instance.feedbackUrl, impressumUrl: instance.impressumUrl, + donationUrl: instance.donationUrl, privacyPolicyUrl: instance.privacyPolicyUrl, disableRegistration: instance.disableRegistration, emailRequiredForSignup: instance.emailRequiredForSignup, diff --git a/packages/backend/src/server/api/endpoints/admin/update-meta.ts b/packages/backend/src/server/api/endpoints/admin/update-meta.ts index 05d2cd61ca..786a628d60 100644 --- a/packages/backend/src/server/api/endpoints/admin/update-meta.ts +++ b/packages/backend/src/server/api/endpoints/admin/update-meta.ts @@ -105,6 +105,7 @@ export const paramDef = { repositoryUrl: { type: 'string' }, feedbackUrl: { type: 'string' }, impressumUrl: { type: 'string', nullable: true }, + donationUrl: { type: 'string', nullable: true }, privacyPolicyUrl: { type: 'string', nullable: true }, useObjectStorage: { type: 'boolean' }, objectStorageBaseUrl: { type: 'string', nullable: true }, @@ -406,6 +407,10 @@ export default class extends Endpoint { // eslint- set.impressumUrl = ps.impressumUrl; } + if (ps.donationUrl !== undefined) { + set.donationUrl = ps.donationUrl; + } + if (ps.privacyPolicyUrl !== undefined) { set.privacyPolicyUrl = ps.privacyPolicyUrl; } diff --git a/packages/backend/src/server/api/endpoints/meta.ts b/packages/backend/src/server/api/endpoints/meta.ts index 9d2ae8369c..af779aa850 100644 --- a/packages/backend/src/server/api/endpoints/meta.ts +++ b/packages/backend/src/server/api/endpoints/meta.ts @@ -291,6 +291,10 @@ export const meta = { type: 'string', optional: false, nullable: true, }, + donationUrl: { + type: 'string', + optional: false, nullable: true, + }, logoImageUrl: { type: 'string', optional: false, nullable: true, @@ -365,6 +369,7 @@ export default class extends Endpoint { // eslint- repositoryUrl: instance.repositoryUrl, feedbackUrl: instance.feedbackUrl, impressumUrl: instance.impressumUrl, + donationUrl: instance.donationUrl, privacyPolicyUrl: instance.privacyPolicyUrl, disableRegistration: instance.disableRegistration, emailRequiredForSignup: instance.emailRequiredForSignup, diff --git a/packages/frontend/src/components/MkDonation.vue b/packages/frontend/src/components/MkDonation.vue index a77ff42f94..92e4f14bbe 100644 --- a/packages/frontend/src/components/MkDonation.vue +++ b/packages/frontend/src/components/MkDonation.vue @@ -26,6 +26,16 @@ SPDX-License-Identifier: AGPL-3.0-only {{ i18n.ts.learnMore }} +
+ + + +
+ {{ i18n.ts.learnMore }} +
+
{{ i18n.ts.remindMeLater }} {{ i18n.ts.neverShow }} diff --git a/packages/frontend/src/components/MkVisitorDashboard.vue b/packages/frontend/src/components/MkVisitorDashboard.vue index 9f4fc00938..8f15fa93a6 100644 --- a/packages/frontend/src/components/MkVisitorDashboard.vue +++ b/packages/frontend/src/components/MkVisitorDashboard.vue @@ -123,7 +123,13 @@ function showMenu(ev) { action: () => { window.open(instance.privacyPolicyUrl, '_blank', 'noopener'); }, - } : undefined, (!instance.impressumUrl && !instance.tosUrl && !instance.privacyPolicyUrl) ? undefined : { type: 'divider' }, { + } : undefined, (instance.donationUrl) ? { + text: i18n.ts.donation, + icon: 'ph-hand-coins ph-bold ph-lg', + action: () => { + window.open(instance.donationUrl, '_blank', 'noopener'); + }, + } : undefined, (!instance.impressumUrl && !instance.tosUrl && !instance.privacyPolicyUrl && !instance.donationUrl) ? undefined : { type: 'divider' }, { text: i18n.ts.help, icon: 'ph-question ph-bold ph-lg', action: () => { diff --git a/packages/frontend/src/pages/about.vue b/packages/frontend/src/pages/about.vue index 8209515065..024f2dc746 100644 --- a/packages/frontend/src/pages/about.vue +++ b/packages/frontend/src/pages/about.vue @@ -57,6 +57,7 @@ SPDX-License-Identifier: AGPL-3.0-only {{ i18n.ts.termsOfService }} {{ i18n.ts.privacyPolicy }} + {{ i18n.ts.donation }}
diff --git a/packages/frontend/src/pages/admin/settings.vue b/packages/frontend/src/pages/admin/settings.vue index d08bfac74a..f11d37ab23 100644 --- a/packages/frontend/src/pages/admin/settings.vue +++ b/packages/frontend/src/pages/admin/settings.vue @@ -40,6 +40,11 @@ SPDX-License-Identifier: AGPL-3.0-only + + + + + @@ -170,6 +175,7 @@ const description = ref(null); const maintainerName = ref(null); const maintainerEmail = ref(null); const impressumUrl = ref(null); +const donationUrl = ref(null); const pinnedUsers = ref(''); const cacheRemoteFiles = ref(false); const cacheRemoteSensitiveFiles = ref(false); @@ -192,6 +198,7 @@ async function init(): Promise { maintainerName.value = meta.maintainerName; maintainerEmail.value = meta.maintainerEmail; impressumUrl.value = meta.impressumUrl; + donationUrl.value = meta.donationUrl; pinnedUsers.value = meta.pinnedUsers.join('\n'); cacheRemoteFiles.value = meta.cacheRemoteFiles; cacheRemoteSensitiveFiles.value = meta.cacheRemoteSensitiveFiles; @@ -215,6 +222,7 @@ async function save(): void { maintainerName: maintainerName.value, maintainerEmail: maintainerEmail.value, impressumUrl: impressumUrl.value, + donationUrl: donationUrl.value, pinnedUsers: pinnedUsers.value.split('\n'), cacheRemoteFiles: cacheRemoteFiles.value, cacheRemoteSensitiveFiles: cacheRemoteSensitiveFiles.value, diff --git a/packages/frontend/src/ui/_common_/common.ts b/packages/frontend/src/ui/_common_/common.ts index e7f24228b6..6e2f8b7e46 100644 --- a/packages/frontend/src/ui/_common_/common.ts +++ b/packages/frontend/src/ui/_common_/common.ts @@ -102,7 +102,13 @@ export function openInstanceMenu(ev: MouseEvent) { action: () => { window.open(instance.privacyPolicyUrl, '_blank', 'noopener'); }, - } : undefined, (!instance.impressumUrl && !instance.tosUrl && !instance.privacyPolicyUrl) ? undefined : { type: 'divider' }, { + } : undefined, (instance.donationUrl) ? { + text: i18n.ts.donation, + icon: 'ph-hand-coins ph-bold ph-lg', + action: () => { + window.open(instance.donationUrl, '_blank', 'noopener'); + }, + } : undefined, (!instance.impressumUrl && !instance.tosUrl && !instance.privacyPolicyUrl && !instance.donationUrl) ? undefined : { type: 'divider' }, { text: i18n.ts.help, icon: 'ph-question ph-bold ph-lg', action: () => { diff --git a/packages/misskey-js/src/autogen/types.ts b/packages/misskey-js/src/autogen/types.ts index 0e068e5267..f881c5db62 100644 --- a/packages/misskey-js/src/autogen/types.ts +++ b/packages/misskey-js/src/autogen/types.ts @@ -4631,6 +4631,7 @@ export type operations = { description: string | null; disableRegistration: boolean; impressumUrl: string | null; + donationUrl: string | null; maintainerEmail: string | null; maintainerName: string | null; name: string | null; @@ -8650,6 +8651,7 @@ export type operations = { repositoryUrl?: string; feedbackUrl?: string; impressumUrl?: string | null; + donationUrl?: string | null; privacyPolicyUrl?: string | null; useObjectStorage?: boolean; objectStorageBaseUrl?: string | null; @@ -19400,6 +19402,7 @@ export type operations = { }; backgroundImageUrl: string | null; impressumUrl: string | null; + donationUrl: string | null; logoImageUrl: string | null; privacyPolicyUrl: string | null; serverRules: string[];