feat(analytics): Google Analytics・同意モード・一部機能のトラッキング実装 (MisskeyIO#784)

This commit is contained in:
あわわわとーにゅ 2024-11-06 01:28:14 +09:00 committed by GitHub
parent 2f4c48bbe6
commit fcfd004c38
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
53 changed files with 805 additions and 113 deletions

View file

@ -43,6 +43,7 @@ import { RoleService } from '@/core/RoleService.js';
import { correctFilename } from '@/misc/correct-filename.js';
import { isMimeImage } from '@/misc/is-mime-image.js';
import { ModerationLogService } from '@/core/ModerationLogService.js';
import { LoggerService } from '@/core/LoggerService.js';
type AddFileArgs = {
/** User who wish to add file */
@ -123,12 +124,13 @@ export class DriveService {
private globalEventService: GlobalEventService,
private queueService: QueueService,
private roleService: RoleService,
private loggerService: LoggerService,
private moderationLogService: ModerationLogService,
private driveChart: DriveChart,
private perUserDriveChart: PerUserDriveChart,
private instanceChart: InstanceChart,
) {
const logger = new Logger('drive', 'blue');
const logger = this.loggerService.getLogger('drive', 'blue');
this.registerLogger = logger.createSubLogger('register', 'yellow');
this.downloaderLogger = logger.createSubLogger('downloader');
this.deleteLogger = logger.createSubLogger('delete');

View file

@ -159,7 +159,7 @@ export class FetchInstanceMetadataService {
throw err.statusCode ?? err.message;
});
this.logger.succ(`Successfuly fetched nodeinfo of ${instance.host}`);
this.logger.succ(`Successfully fetched nodeinfo of ${instance.host}`);
return info as NodeInfo;
} catch (err) {

View file

@ -4,7 +4,7 @@
*/
import { Injectable } from '@nestjs/common';
import Logger from '@/logger.js';
import { rootLogger } from '@/logger.js';
import { bindThis } from '@/decorators.js';
import type { KEYWORD } from 'color-convert/conversions.js';
@ -16,6 +16,6 @@ export class LoggerService {
@bindThis
public getLogger(domain: string, color?: KEYWORD | undefined, store?: boolean) {
return new Logger(domain);
return rootLogger.createSubLogger(domain, color, store);
}
}

View file

@ -257,7 +257,7 @@ export class NoteCreateService implements OnApplicationShutdown {
const policies = await this.roleService.getUserPolicies(user.id);
if (!policies.canCreateContent) {
this.logger.error('Request rejected because user has no permission to create content', { user: user.id, note: data });
this.logger.error('Request rejected because user has no permission to create content', { userId: user.id, note: data });
throw new IdentifiableError('5b1c2b67-50a6-4a8a-a59c-0ede40890de3', 'User has no permission to create content.');
}
@ -265,7 +265,7 @@ export class NoteCreateService implements OnApplicationShutdown {
const sensitiveWords = meta.sensitiveWords;
if (this.utilityService.isKeyWordIncluded(data.cw ?? this.utilityService.concatNoteContentsForKeyWordCheck({ text: data.text, pollChoices: data.poll?.choices }), sensitiveWords)) {
data.visibility = 'home';
this.logger.warn('Visibility changed to home because sensitive words are included', { user: user.id, note: data });
this.logger.warn('Visibility changed to home because sensitive words are included', { userId: user.id, note: data });
} else if (!policies.canPublicNote) {
data.visibility = 'home';
}
@ -281,7 +281,7 @@ export class NoteCreateService implements OnApplicationShutdown {
);
if (hasProhibitedWords) {
this.logger.error('Request rejected because prohibited words are included', { user: user.id, note: data });
this.logger.error('Request rejected because prohibited words are included', { userId: user.id, note: data });
throw new IdentifiableError('689ee33f-f97c-479a-ac49-1b9f8140af99', 'Notes including prohibited words are not allowed.');
}
@ -384,7 +384,7 @@ export class NoteCreateService implements OnApplicationShutdown {
if (process.env.MISSKEY_BLOCK_MENTIONS_FROM_UNFAMILIAR_REMOTE_USERS === 'true' && user.host !== null && willCauseNotification) {
const userEntity = await this.usersRepository.findOneBy({ id: user.id });
if ((userEntity?.followersCount ?? 0) === 0) {
this.logger.error('Request rejected because user has no local followers', { user: user.id, note: data });
this.logger.error('Request rejected because user has no local followers', { userId: user.id, note: data });
throw new IdentifiableError('e11b3a16-f543-4885-8eb1-66cad131dbfd', 'Notes including mentions, replies, or renotes from remote users are not allowed until user has at least one local follower.');
}
}
@ -396,7 +396,7 @@ export class NoteCreateService implements OnApplicationShutdown {
|| (data.visibility === 'specified' && data.visibleUsers?.some(u => u.id !== user.id))
|| (this.isQuote(data) && data.renote.userId !== user.id)
) {
this.logger.error('Request rejected because user has no permission to initiate conversation', { user: user.id, note: data });
this.logger.error('Request rejected because user has no permission to initiate conversation', { userId: user.id, note: data });
throw new IdentifiableError('332dd91b-6a00-430a-ac39-620cf60ad34b', 'Notes including mentions, replies, or renotes are not allowed.');
}
}

View file

@ -50,7 +50,7 @@ export class UserBlockingService implements OnModuleInit {
private apRendererService: ApRendererService,
private loggerService: LoggerService,
) {
this.logger = this.loggerService.getLogger('user-block');
this.logger = this.loggerService.getLogger('user:block');
}
onModuleInit() {

View file

@ -30,9 +30,8 @@ import { AccountMoveService } from '@/core/AccountMoveService.js';
import { UtilityService } from '@/core/UtilityService.js';
import { FanoutTimelineService } from '@/core/FanoutTimelineService.js';
import type { ThinUser } from '@/queue/types.js';
import Logger from '../logger.js';
const logger = new Logger('following/create');
import { LoggerService } from '@/core/LoggerService.js';
import Logger from '@/logger.js';
type Local = MiLocalUser | {
id: MiLocalUser['id'];
@ -50,6 +49,7 @@ type Both = Local | Remote;
@Injectable()
export class UserFollowingService implements OnModuleInit {
private userBlockingService: UserBlockingService;
private readonly logger: Logger;
constructor(
private moduleRef: ModuleRef,
@ -73,6 +73,7 @@ export class UserFollowingService implements OnModuleInit {
private instancesRepository: InstancesRepository,
private cacheService: CacheService,
private loggerService: LoggerService,
private utilityService: UtilityService,
private userEntityService: UserEntityService,
private idService: IdService,
@ -88,6 +89,7 @@ export class UserFollowingService implements OnModuleInit {
private perUserFollowingChart: PerUserFollowingChart,
private instanceChart: InstanceChart,
) {
this.logger = this.loggerService.getLogger('user:following');
}
onModuleInit() {
@ -255,7 +257,7 @@ export class UserFollowingService implements OnModuleInit {
followeeSharedInbox: this.userEntityService.isRemoteUser(followee) ? followee.sharedInbox : null,
}).catch(err => {
if (isDuplicateKeyValueError(err) && this.userEntityService.isRemoteUser(follower) && this.userEntityService.isLocalUser(followee)) {
logger.info(`Insert duplicated ignore. ${follower.id} => ${followee.id}`);
this.logger.info(`Insert duplicated ignore. ${follower.id} => ${followee.id}`);
alreadyFollowed = true;
} else {
throw err;
@ -378,7 +380,7 @@ export class UserFollowingService implements OnModuleInit {
});
if (following === null || !following.follower || !following.followee) {
logger.warn('フォロー解除がリクエストされましたがフォローしていませんでした');
this.logger.warn('フォロー解除がリクエストされましたがフォローしていませんでした');
return;
}

View file

@ -145,8 +145,7 @@ export class ApRequestService {
private httpRequestService: HttpRequestService,
private loggerService: LoggerService,
) {
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
this.logger = this.loggerService?.getLogger('ap-request'); // なぜか TypeError: Cannot read properties of undefined (reading 'getLogger') と言われる
this.logger = this.loggerService.getLogger('ap:request');
}
@bindThis

View file

@ -45,7 +45,7 @@ export class Resolver {
private recursionLimit = 100,
) {
this.history = new Set();
this.logger = this.loggerService.getLogger('ap-resolve');
this.logger = this.loggerService.getLogger('ap:resolve');
}
@bindThis

View file

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