123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234 |
- import 'reflect-metadata'
- import 'newrelic'
- import { Stream } from 'stream'
- import { Logger } from 'winston'
- import * as dayjs from 'dayjs'
- import * as utc from 'dayjs/plugin/utc'
- import { AnalyticsActivity, AnalyticsStoreInterface, Period } from '@standardnotes/analytics'
- import { ContainerConfigLoader } from '../src/Bootstrap/Container'
- import TYPES from '../src/Bootstrap/Types'
- import { Env } from '../src/Bootstrap/Env'
- import { DomainEventPublisherInterface } from '@standardnotes/domain-events'
- import { DomainEventFactoryInterface } from '../src/Domain/Event/DomainEventFactoryInterface'
- import { SettingRepositoryInterface } from '../src/Domain/Setting/SettingRepositoryInterface'
- import { MuteFailedBackupsEmailsOption, MuteFailedCloudBackupsEmailsOption, SettingName } from '@standardnotes/settings'
- import { RoleServiceInterface } from '../src/Domain/Role/RoleServiceInterface'
- import { PermissionName } from '@standardnotes/features'
- import { SettingServiceInterface } from '../src/Domain/Setting/SettingServiceInterface'
- import { AnalyticsEntityRepositoryInterface } from '../src/Domain/Analytics/AnalyticsEntityRepositoryInterface'
- const inputArgs = process.argv.slice(2)
- const backupProvider = inputArgs[0]
- const backupFrequency = inputArgs[1]
- const shouldEmailBackupBeTriggered = async (
- analyticsId: number,
- analyticsStore: AnalyticsStoreInterface,
- ): Promise<boolean> => {
- let periods = [Period.Today, Period.Yesterday]
- if (backupFrequency === 'weekly') {
- periods = [Period.ThisWeek, Period.LastWeek]
- }
- for (const period of periods) {
- const wasUnBackedUpDataCreatedInPeriod = await analyticsStore.wasActivityDone(
- AnalyticsActivity.EmailUnbackedUpData,
- analyticsId,
- period,
- )
- if (wasUnBackedUpDataCreatedInPeriod) {
- return true
- }
- }
- return false
- }
- const requestBackups = async (
- settingRepository: SettingRepositoryInterface,
- roleService: RoleServiceInterface,
- settingService: SettingServiceInterface,
- domainEventFactory: DomainEventFactoryInterface,
- domainEventPublisher: DomainEventPublisherInterface,
- analyticsEntityRepository: AnalyticsEntityRepositoryInterface,
- analyticsStore: AnalyticsStoreInterface,
- logger: Logger,
- ): Promise<void> => {
- let settingName: SettingName,
- permissionName: PermissionName,
- muteEmailsSettingName: SettingName,
- muteEmailsSettingValue: string,
- providerTokenSettingName: SettingName
- switch (backupProvider) {
- case 'email':
- settingName = SettingName.EmailBackupFrequency
- permissionName = PermissionName.DailyEmailBackup
- muteEmailsSettingName = SettingName.MuteFailedBackupsEmails
- muteEmailsSettingValue = MuteFailedBackupsEmailsOption.Muted
- break
- case 'dropbox':
- settingName = SettingName.DropboxBackupFrequency
- permissionName = PermissionName.DailyDropboxBackup
- muteEmailsSettingName = SettingName.MuteFailedCloudBackupsEmails
- muteEmailsSettingValue = MuteFailedCloudBackupsEmailsOption.Muted
- providerTokenSettingName = SettingName.DropboxBackupToken
- break
- case 'one_drive':
- settingName = SettingName.OneDriveBackupFrequency
- permissionName = PermissionName.DailyOneDriveBackup
- muteEmailsSettingName = SettingName.MuteFailedCloudBackupsEmails
- muteEmailsSettingValue = MuteFailedCloudBackupsEmailsOption.Muted
- providerTokenSettingName = SettingName.OneDriveBackupToken
- break
- case 'google_drive':
- settingName = SettingName.GoogleDriveBackupFrequency
- permissionName = PermissionName.DailyGDriveBackup
- muteEmailsSettingName = SettingName.MuteFailedCloudBackupsEmails
- muteEmailsSettingValue = MuteFailedCloudBackupsEmailsOption.Muted
- providerTokenSettingName = SettingName.GoogleDriveBackupToken
- break
- default:
- throw new Error(`Not handled backup provider: ${backupProvider}`)
- }
- const stream = await settingRepository.streamAllByNameAndValue(settingName, backupFrequency)
- return new Promise((resolve, reject) => {
- stream
- .pipe(
- new Stream.Transform({
- objectMode: true,
- transform: async (setting, _encoding, callback) => {
- const userIsPermittedForEmailBackups = await roleService.userHasPermission(
- setting.setting_user_uuid,
- permissionName,
- )
- if (!userIsPermittedForEmailBackups) {
- callback()
- return
- }
- let userHasEmailsMuted = false
- const emailsMutedSetting = await settingRepository.findOneByNameAndUserUuid(
- muteEmailsSettingName,
- setting.setting_user_uuid,
- )
- if (emailsMutedSetting !== null && emailsMutedSetting.value !== null) {
- userHasEmailsMuted = emailsMutedSetting.value === muteEmailsSettingValue
- }
- if (backupProvider === 'email') {
- const analyticsEntity = await analyticsEntityRepository.findOneByUserUuid(setting.setting_user_uuid)
- if (analyticsEntity === null) {
- callback()
- return
- }
- const emailBackupsShouldBeTriggered = await shouldEmailBackupBeTriggered(
- analyticsEntity.id,
- analyticsStore,
- )
- if (!emailBackupsShouldBeTriggered) {
- logger.info(
- `Email backup for user ${setting.setting_user_uuid} should not be triggered due to inactivity. It will be triggered until further changes.`,
- )
- }
- await domainEventPublisher.publish(
- domainEventFactory.createEmailBackupRequestedEvent(
- setting.setting_user_uuid,
- emailsMutedSetting?.uuid as string,
- userHasEmailsMuted,
- ),
- )
- await analyticsStore.markActivity([AnalyticsActivity.EmailBackup], analyticsEntity.id, [
- Period.Today,
- Period.ThisWeek,
- ])
- await analyticsStore.unmarkActivity([AnalyticsActivity.EmailUnbackedUpData], analyticsEntity.id, [
- Period.Today,
- Period.ThisWeek,
- ])
- callback()
- return
- }
- const cloudBackupProviderToken = await settingService.findSettingWithDecryptedValue({
- settingName: providerTokenSettingName,
- userUuid: setting.setting_user_uuid,
- })
- if (cloudBackupProviderToken === null || cloudBackupProviderToken.value === null) {
- callback()
- return
- }
- await domainEventPublisher.publish(
- domainEventFactory.createCloudBackupRequestedEvent(
- backupProvider.toUpperCase() as 'DROPBOX' | 'ONE_DRIVE' | 'GOOGLE_DRIVE',
- cloudBackupProviderToken.value,
- setting.setting_user_uuid,
- emailsMutedSetting?.uuid as string,
- userHasEmailsMuted,
- ),
- )
- callback()
- },
- }),
- )
- .on('finish', resolve)
- .on('error', reject)
- })
- }
- const container = new ContainerConfigLoader()
- void container.load().then((container) => {
- dayjs.extend(utc)
- const env: Env = new Env()
- env.load()
- const logger: Logger = container.get(TYPES.Logger)
- logger.info(`Starting ${backupFrequency} ${backupProvider} backup requesting...`)
- const settingRepository: SettingRepositoryInterface = container.get(TYPES.SettingRepository)
- const roleService: RoleServiceInterface = container.get(TYPES.RoleService)
- const settingService: SettingServiceInterface = container.get(TYPES.SettingService)
- const domainEventFactory: DomainEventFactoryInterface = container.get(TYPES.DomainEventFactory)
- const domainEventPublisher: DomainEventPublisherInterface = container.get(TYPES.DomainEventPublisher)
- const analyticsEntityRepository: AnalyticsEntityRepositoryInterface = container.get(TYPES.AnalyticsEntityRepository)
- const analyticsStore: AnalyticsStoreInterface = container.get(TYPES.AnalyticsStore)
- Promise.resolve(
- requestBackups(
- settingRepository,
- roleService,
- settingService,
- domainEventFactory,
- domainEventPublisher,
- analyticsEntityRepository,
- analyticsStore,
- logger,
- ),
- )
- .then(() => {
- logger.info(`${backupFrequency} ${backupProvider} backup requesting complete`)
- process.exit(0)
- })
- .catch((error) => {
- logger.error(`Could not finish ${backupFrequency} ${backupProvider} backup requesting: ${error.message}`)
- process.exit(1)
- })
- })
|