<commit_before>import uuid = require('uuid/v4')

import {
  DefaultMaxUpstreamResends,
  DefaultNumberOfNotificationsToSchedule,
  FCMPluginProjectSenderId
} from '../../../../assets/data/defaultConfig'

import { Firebase } from '@ionic-native/firebase/ngx'
import { Injectable } from '@angular/core'
import { NotificationGeneratorService } from './notification-generator.service'
import { NotificationService } from './notification.service'
import { Platform } from 'ionic-angular'
import { ScheduleService } from '../schedule/schedule.service'
import { SingleNotification } from '../../../shared/models/notification-handler'
import { StorageKeys } from '../../../shared/enums/storage'
import { StorageService } from '../storage/storage.service'
import { SubjectConfigService } from '../config/subject-config.service'
import { TaskType } from '../../../shared/utilities/task-type'
import { getSeconds } from '../../../shared/utilities/time'

declare var FirebasePlugin

@Injectable()
export class FcmNotificationService extends NotificationService {
  private readonly NOTIFICATION_STORAGE = {
    LAST_NOTIFICATION_UPDATE: StorageKeys.LAST_NOTIFICATION_UPDATE
  }
  upstreamResends: number

  constructor(
    private notifications: NotificationGeneratorService,
    private storage: StorageService,
    private schedule: ScheduleService,
    private config: SubjectConfigService,
    private firebase: Firebase,
    private platform: Platform
  ) {
    super()
  }

  init() {
    FirebasePlugin.setSenderId(
      FCMPluginProjectSenderId,
      () => console.log('[NOTIFICATION SERVICE] Set sender id success'),
      error => {
        console.log(error)
        alert(error)
      }
    )
    FirebasePlugin.getToken(() =>
      console.log('[NOTIFICATION SERVICE] Refresh token success')
    )
  }

  publish(
    limit: number = DefaultNumberOfNotificationsToSchedule
  ): Promise<void[]> {
    this.resetResends()
    return this.config.getParticipantLogin().then(username => {
      if (!username) return Promise.resolve([])
      return this.schedule.getTasks(TaskType.ALL).then(tasks => {
        const fcmNotifications = this.notifications
          .futureNotifications(tasks, limit)
          .map(t => this.format(t, username))
        console.log('NOTIFICATIONS Scheduling FCM notifications')
        console.log(fcmNotifications)
        return Promise.all(
          fcmNotifications
            .map(n => {
              return this.sendNotification(n)
            })
            .concat([this.setLastNotificationUpdate()])
        )
      })
    })
  }

  private sendNotification(notification): Promise<void> {
    FirebasePlugin.upstream(
      notification,
      succ => console.log(succ),
      err => {
        console.log(err)
        if (this.upstreamResends++ < DefaultMaxUpstreamResends)
          this.sendNotification(notification)
      }
    )
    return Promise.resolve()
  }

  private format(notification: SingleNotification, participantLogin: string) {
    const endTime =
      notification.task.timestamp + notification.task.completionWindow
    const diffTime = endTime - notification.timestamp

    const ttl =
      diffTime > 0
        ? getSeconds({ milliseconds: diffTime })
        : getSeconds({ minutes: 10 })

    return {
      eventId: uuid(),
      action: 'SCHEDULE',
      notificationTitle: notification.title,
      notificationMessage: notification.text,
      time: notification.timestamp,
      subjectId: participantLogin,
      ttlSeconds: ttl
    }
  }

  cancel(): Promise<void> {
    return this.config.getParticipantLogin().then(username => {
      if (!username) {
        return Promise.resolve()
      }
      return this.sendNotification({
        eventId: uuid(),
        action: 'CANCEL',
        cancelType: 'all',
        subjectId: username
      })
    })
  }

  permissionCheck(): Promise<void> {
    if (!this.platform.is('ios')) return Promise.resolve()
    return this.firebase.hasPermission().then(data => {
      console.log('permission check')
      this.firebase.logEvent('PushNotificationPermissions', data)
      if (data.isEnabled) {
        return true
      }
      return this.firebase.grantPermission()
    })
  }

  sendTestNotification(): Promise<void> {
    return this.sendNotification(
      this.format(this.notifications.createTestNotification(), '')
    )
  }

  setLastNotificationUpdate(): Promise<void> {
    return this.storage.set(
      this.NOTIFICATION_STORAGE.LAST_NOTIFICATION_UPDATE,
      Date.now()
    )
  }

  getLastNotificationUpdate() {
    return this.storage.get(this.NOTIFICATION_STORAGE.LAST_NOTIFICATION_UPDATE)<commit_msg>fix(notificationService): permission check<commit_after>import uuid = require('uuid/v4')

import {
  DefaultMaxUpstreamResends,
  DefaultNumberOfNotificationsToSchedule,
  FCMPluginProjectSenderId
} from '../../../../assets/data/defaultConfig'

import { Firebase } from '@ionic-native/firebase/ngx'
import { Injectable } from '@angular/core'
import { NotificationGeneratorService } from './notification-generator.service'
import { NotificationService } from './notification.service'
import { Platform } from 'ionic-angular'
import { ScheduleService } from '../schedule/schedule.service'
import { SingleNotification } from '../../../shared/models/notification-handler'
import { StorageKeys } from '../../../shared/enums/storage'
import { StorageService } from '../storage/storage.service'
import { SubjectConfigService } from '../config/subject-config.service'
import { TaskType } from '../../../shared/utilities/task-type'
import { getSeconds } from '../../../shared/utilities/time'

declare var FirebasePlugin

@Injectable()
export class FcmNotificationService extends NotificationService {
  private readonly NOTIFICATION_STORAGE = {
    LAST_NOTIFICATION_UPDATE: StorageKeys.LAST_NOTIFICATION_UPDATE
  }
  upstreamResends: number

  constructor(
    private notifications: NotificationGeneratorService,
    private storage: StorageService,
    private schedule: ScheduleService,
    private config: SubjectConfigService,
    private firebase: Firebase,
    private platform: Platform
  ) {
    super()
  }

  init() {
    FirebasePlugin.setSenderId(
      FCMPluginProjectSenderId,
      () => console.log('[NOTIFICATION SERVICE] Set sender id success'),
      error => {
        console.log(error)
        alert(error)
      }
    )
    FirebasePlugin.getToken(() =>
      console.log('[NOTIFICATION SERVICE] Refresh token success')
    )
  }

  publish(
    limit: number = DefaultNumberOfNotificationsToSchedule
  ): Promise<void[]> {
    this.resetResends()
    return this.config.getParticipantLogin().then(username => {
      if (!username) return Promise.resolve([])
      return this.schedule.getTasks(TaskType.ALL).then(tasks => {
        const fcmNotifications = this.notifications
          .futureNotifications(tasks, limit)
          .map(t => this.format(t, username))
        console.log('NOTIFICATIONS Scheduling FCM notifications')
        console.log(fcmNotifications)
        return Promise.all(
          fcmNotifications
            .map(n => {
              return this.sendNotification(n)
            })
            .concat([this.setLastNotificationUpdate()])
        )
      })
    })
  }

  private sendNotification(notification): Promise<void> {
    FirebasePlugin.upstream(
      notification,
      succ => console.log(succ),
      err => {
        console.log(err)
        if (this.upstreamResends++ < DefaultMaxUpstreamResends)
          this.sendNotification(notification)
      }
    )
    return Promise.resolve()
  }

  private format(notification: SingleNotification, participantLogin: string) {
    const endTime =
      notification.task.timestamp + notification.task.completionWindow
    const diffTime = endTime - notification.timestamp

    const ttl =
      diffTime > 0
        ? getSeconds({ milliseconds: diffTime })
        : getSeconds({ minutes: 10 })

    return {
      eventId: uuid(),
      action: 'SCHEDULE',
      notificationTitle: notification.title,
      notificationMessage: notification.text,
      time: notification.timestamp,
      subjectId: participantLogin,
      ttlSeconds: ttl
    }
  }

  cancel(): Promise<void> {
    return this.config.getParticipantLogin().then(username => {
      if (!username) {
        return Promise.resolve()
      }
      return this.sendNotification({
        eventId: uuid(),
        action: 'CANCEL',
        cancelType: 'all',
        subjectId: username
      })
    })
  }

  permissionCheck(): Promise<void> {
    if (!this.platform.is('ios')) return Promise.resolve()
    return this.firebase
      .hasPermission()
      .then(res => (res.isEnabled ? true : this.firebase.grantPermission()))
  }

  sendTestNotification(): Promise<void> {
    return this.sendNotification(
      this.format(this.notifications.createTestNotification(), '')
    )
  }

  setLastNotificationUpdate(): Promise<void> {
    return this.storage.set(
      this.NOTIFICATION_STORAGE.LAST_NOTIFICATION_UPDATE,
      Date.now()
    )
  }

  getLastNotificationUpdate() {
    return this.storage.get(this.NOTIFICATION_STORAGE.LAST_NOTIFICATION_UPDATE)
{'fraction_non_alphanumeric': 0.11666666666666667, 'fraction_numerical': 0.0008714596949891067, 'mean_word_length': 3.085892300845572, 'pattern_counts': {'":': 0, '<': 17, '<?xml version=': 0, '>': 39, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5541571', 'n_tokens_mistral': 2535, 'n_tokens_neox': 2486, 'n_words': 492}