feat: google analytics (#15451)

* wip backend

* wip frontend

* build misskey-js

* implement control panel

* fix

* introduce analytics wrapper

* spdx

* Update analytics.ts

* Update common.ts

* wip

* wip

* wip

* wip

* wip

* Update CHANGELOG.md

---------

Co-authored-by: kakkokari-gtyih <67428053+kakkokari-gtyih@users.noreply.github.com>
This commit is contained in:
syuilo
2025-02-25 20:51:23 +09:00
committed by GitHub
parent 20cc6d3049
commit 2b6638e160
15 changed files with 327 additions and 16 deletions

View File

@@ -0,0 +1,16 @@
/*
* SPDX-FileCopyrightText: syuilo and misskey-project
* SPDX-License-Identifier: AGPL-3.0-only
*/
export class GoogleAnalytics1739006797620 {
name = 'GoogleAnalytics1739006797620'
async up(queryRunner) {
await queryRunner.query(`ALTER TABLE "meta" ADD "googleAnalyticsMeasurementId" character varying(64)`);
}
async down(queryRunner) {
await queryRunner.query(`ALTER TABLE "meta" DROP COLUMN "googleAnalyticsMeasurementId"`);
}
}

View File

@@ -97,6 +97,7 @@ export class MetaEntityService {
enableTurnstile: instance.enableTurnstile,
turnstileSiteKey: instance.turnstileSiteKey,
enableTestcaptcha: instance.enableTestcaptcha,
googleAnalyticsMeasurementId: instance.googleAnalyticsMeasurementId,
swPublickey: instance.swPublicKey,
themeColor: instance.themeColor,
mascotImageUrl: instance.mascotImageUrl ?? '/assets/ai.png',

View File

@@ -658,4 +658,10 @@ export class MiMeta {
default: '{}',
})
public federationHosts: string[];
@Column('varchar', {
length: 64,
nullable: true,
})
public googleAnalyticsMeasurementId: string | null;
}

View File

@@ -119,6 +119,10 @@ export const packedMetaLiteSchema = {
type: 'boolean',
optional: false, nullable: false,
},
googleAnalyticsMeasurementId: {
type: 'string',
optional: false, nullable: true,
},
swPublickey: {
type: 'string',
optional: false, nullable: true,

View File

@@ -73,6 +73,10 @@ export const meta = {
type: 'boolean',
optional: false, nullable: false,
},
googleAnalyticsMeasurementId: {
type: 'string',
optional: false, nullable: true,
},
swPublickey: {
type: 'string',
optional: false, nullable: true,
@@ -572,6 +576,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
enableTurnstile: instance.enableTurnstile,
turnstileSiteKey: instance.turnstileSiteKey,
enableTestcaptcha: instance.enableTestcaptcha,
googleAnalyticsMeasurementId: instance.googleAnalyticsMeasurementId,
swPublickey: instance.swPublicKey,
themeColor: instance.themeColor,
mascotImageUrl: instance.mascotImageUrl,

View File

@@ -84,6 +84,7 @@ export const paramDef = {
turnstileSiteKey: { type: 'string', nullable: true },
turnstileSecretKey: { type: 'string', nullable: true },
enableTestcaptcha: { type: 'boolean' },
googleAnalyticsMeasurementId: { type: 'string', nullable: true },
sensitiveMediaDetection: { type: 'string', enum: ['none', 'all', 'local', 'remote'] },
sensitiveMediaDetectionSensitivity: { type: 'string', enum: ['medium', 'low', 'high', 'veryLow', 'veryHigh'] },
setSensitiveFlagAutomatically: { type: 'boolean' },
@@ -371,6 +372,12 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
set.enableTestcaptcha = ps.enableTestcaptcha;
}
if (ps.googleAnalyticsMeasurementId !== undefined) {
// 空文字列をnullにしたいので??は使わない
// eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing
set.googleAnalyticsMeasurementId = ps.googleAnalyticsMeasurementId || null;
}
if (ps.sensitiveMediaDetection !== undefined) {
set.sensitiveMediaDetection = ps.sensitiveMediaDetection;
}