File

src/services/qrscanresulthandler.service.ts

Index

Properties
Methods

Constructor

constructor(contentService: ContentService, telemetryService: TelemetryService, pageAssembleService: PageAssembleService, frameworkService: FrameworkService, preferences: SharedPreferences, certificateService: CertificateService, commonUtilService: CommonUtilService, telemetryGeneratorService: TelemetryGeneratorService, router: Router, navCtrl: NavController, events: Events, appGlobalService: AppGlobalService, formFrameWorkUtilService: FormAndFrameworkUtilService, navService: NavigationService, popoverCtrl: PopoverController)
Parameters :
Name Type Optional
contentService ContentService No
telemetryService TelemetryService No
pageAssembleService PageAssembleService No
frameworkService FrameworkService No
preferences SharedPreferences No
certificateService CertificateService No
commonUtilService CommonUtilService No
telemetryGeneratorService TelemetryGeneratorService No
router Router No
navCtrl NavController No
events Events No
appGlobalService AppGlobalService No
formFrameWorkUtilService FormAndFrameworkUtilService No
navService NavigationService No
popoverCtrl PopoverController No

Methods

generateEndEvent
generateEndEvent(pageId: string, qrData: string)
Parameters :
Name Type Optional
pageId string No
qrData string No
Returns : void
Private generateImpressionEvent
generateImpressionEvent(source, dialCode)
Parameters :
Name Optional
source No
dialCode No
Returns : void
generateQRScanSuccessInteractEvent
generateQRScanSuccessInteractEvent(scannedData, action, dialCode?, certificate?: literal type)
Parameters :
Name Type Optional
scannedData No
action No
dialCode Yes
certificate literal type Yes
Returns : void
getCorRelationList
getCorRelationList(identifier: string, type: string, scannedData)
Parameters :
Name Type Optional
identifier string No
type string No
scannedData No
Returns : Array<CorrelationData>
handleCertsQR
handleCertsQR(source: string, scannedData: string)
Parameters :
Name Type Optional
source string No
scannedData string No
Returns : void
handleContentId
handleContentId(source: string, scannedData: string)
Parameters :
Name Type Optional
source string No
scannedData string No
Returns : void
handleDialCode
handleDialCode(source: string, scannedData, dialCode: string)
Parameters :
Name Type Optional
source string No
scannedData No
dialCode string No
Returns : void
handleInvalidQRCode
handleInvalidQRCode(source: string, scannedData: string)
Parameters :
Name Type Optional
source string No
scannedData string No
Returns : void
Async handleRcCertsQR
handleRcCertsQR(scannedData)
Parameters :
Name Optional
scannedData No
Returns : any
isContentId
isContentId(scannedData: string)
Parameters :
Name Type Optional
scannedData string No
Returns : boolean
Async manageLearScan
manageLearScan(scannedData)
Parameters :
Name Optional
scannedData No
Returns : any
Async navigateHandler
navigateHandler(scannedData)
Parameters :
Name Optional
scannedData No
Returns : any
navigateToDetailsPage
navigateToDetailsPage(content, corRelationList)
Parameters :
Name Optional
content No
corRelationList No
Returns : void
Async parseDialCode
parseDialCode(scannedData: string)
Parameters :
Name Type Optional
scannedData string No
Returns : Promise<string | undefined>

Properties

Private Static Readonly CORRELATION_TYPE
Type : string
Default value : 'qr'
guestUser
Type : boolean
Default value : false
inAppBrowserRef
Type : any
permittedUsers
Type : []
Default value : [ 'administrator', 'teacher' ]
scannedUrlMap
Type : object
Optional selectedUserType
Type : any
source
Type : string
import { Inject, Injectable } from '@angular/core';
import { TelemetryGeneratorService } from './telemetry-generator.service';
import {
  FrameworkService,
  PageAssembleService,
  Content,
  ContentDetailRequest,
  ContentService,
  CorrelationData,
  TelemetryObject,
  TelemetryService,
  SharedPreferences,
  CertificateService
} from 'sunbird-sdk';
import { EventTopics, RouterLinks, PreferenceKey } from '../app/app.constant';

import { CommonUtilService } from './common-util.service';
import {
  Environment,
  ImpressionSubtype,
  ImpressionType,
  InteractSubtype,
  InteractType,
  Mode,
  PageId,
  ObjectType,
  CorReleationDataType,
} from './telemetry-constants';
import { NavigationExtras, Router } from '@angular/router';
import { NavController, PopoverController } from '@ionic/angular';
import { Events } from '@app/util/events';
import { AppGlobalService } from './app-global-service.service';
import { FormAndFrameworkUtilService } from './formandframeworkutil.service';
import { ContentUtil } from '@app/util/content-util';
import * as qs from 'qs';
import { NavigationService } from './navigation-handler.service';
import { FormConstants } from '@app/app/form.constants';
import { CertificateVerificationPopoverComponent } from '@app/app/components/popups/certificate-verification/certificate-verification-popup.component';

declare var cordova;

@Injectable()
export class QRScannerResultHandler {
  private static readonly CORRELATION_TYPE = 'qr';
  source: string;
  inAppBrowserRef: any;
  scannedUrlMap: object;
  selectedUserType?: any;
  guestUser: boolean = false;

  permittedUsers = [
    'administrator',
    'teacher'
  ]
  constructor(
    @Inject('CONTENT_SERVICE') private contentService: ContentService,
    @Inject('TELEMETRY_SERVICE') private telemetryService: TelemetryService,
    @Inject('PAGE_ASSEMBLE_SERVICE') private pageAssembleService: PageAssembleService,
    @Inject('FRAMEWORK_SERVICE') private frameworkService: FrameworkService,
    @Inject('SHARED_PREFERENCES') private preferences: SharedPreferences,
    @Inject('CERTIFICATE_SERVICE') private certificateService: CertificateService,
    private commonUtilService: CommonUtilService,
    private telemetryGeneratorService: TelemetryGeneratorService,
    private router: Router,
    private navCtrl: NavController,
    private events: Events,
    private appGlobalService: AppGlobalService,
    private formFrameWorkUtilService: FormAndFrameworkUtilService,
    private navService: NavigationService,
    private popoverCtrl: PopoverController
  ) {
  }

  async parseDialCode(scannedData: string): Promise<string | undefined> {
    const dailCodeRegExpression = await this.formFrameWorkUtilService.getDialcodeRegexFormApi();
    const execArray = (new RegExp(dailCodeRegExpression)).exec(scannedData);
    if (execArray && execArray.groups) {
      try {
        const url: URL = new URL(scannedData);
        const overrideChannelSlug = url.searchParams.get('channel');

        if (overrideChannelSlug) {
          this.frameworkService.searchOrganization({
            filters: {
              slug: overrideChannelSlug,
              isRootOrg: true
            } as any
          }).toPromise().then((result) => {
            const org: any = result.content && result.content[0];

            if (org) {
              this.pageAssembleService.setPageAssembleChannel({
                channelId: org.id
              });

              setTimeout(() => {
                this.events.publish(EventTopics.COURSE_PAGE_ASSEMBLE_CHANNEL_CHANGE);
              }, 500);
            }
          });
        }
      } catch (e) {
        console.error(e);
      }

      this.scannedUrlMap = execArray.groups;
      return execArray.groups[Object.keys(execArray.groups).find((key) => !!execArray.groups[key])];
    }
    return undefined;
  }

  isContentId(scannedData: string): boolean {
    const results = scannedData.split('/');
    const type = results[results.length - 2];
    const action = results[results.length - 3];
    const scope = results[results.length - 4];
    return (type === 'content' && scope === 'public') ||
      (action === 'play' && (type === 'collection' || type === 'content')) ||
      (action === 'explore-course' && type === 'course');
  }

  handleDialCode(source: string, scannedData, dialCode: string) {
    this.source = source;
    this.generateQRScanSuccessInteractEvent(scannedData, 'SearchResult', dialCode);
    const telemetryObject = new TelemetryObject(dialCode, 'qr', ' ');
    const utmUrl = scannedData.slice(scannedData.indexOf('?') + 1);
    const params: {[param: string]: string} = qs.parse(utmUrl);
    const cData: Array<CorrelationData> = [];

    if (utmUrl !== scannedData) {
      ContentUtil.genrateUTMCData(params).forEach((element) => {
        cData.push(element);
      });
    }
    const corRelationData: CorrelationData[] = [{
      id: CorReleationDataType.SCAN,
      type: CorReleationDataType.ACCESS_TYPE
    }];
    if (cData && cData.length) {
      this.telemetryService.updateCampaignParameters(cData);
      this.telemetryGeneratorService.generateUtmInfoTelemetry(params, PageId.QRCodeScanner, telemetryObject, corRelationData);
    }
    const navigationExtras: NavigationExtras = {
      state: {
        dialCode,
        corRelation: this.getCorRelationList(dialCode, QRScannerResultHandler.CORRELATION_TYPE, scannedData),
        source: this.source,
        shouldGenerateEndTelemetry: true
      }
    };
    this.generateImpressionEvent(this.source, dialCode);
    this.navCtrl.navigateForward([`/${RouterLinks.SEARCH}`], navigationExtras);
  }

  handleContentId(source: string, scannedData: string) {
    this.source = source;
    const results = scannedData.split('/');
    const contentId = results[results.length - 1];
    this.generateQRScanSuccessInteractEvent(scannedData, 'ContentDetail', contentId);
    const utmUrl = scannedData.slice(scannedData.indexOf('?') + 1);
    const params: {[param: string]: string} = qs.parse(utmUrl);
    const cData: CorrelationData[] = [];

    if (utmUrl !== scannedData) {
      ContentUtil.genrateUTMCData(params).forEach((element) => {
       cData.push(element);
     });
   }
    const request: ContentDetailRequest = {
      contentId
    };
    this.contentService.getContentDetails(request).toPromise()
      .then((content: Content) => {
        const corRelationData: CorrelationData[] = [{
          id: CorReleationDataType.SCAN,
          type: CorReleationDataType.ACCESS_TYPE
        }];
        if (cData && cData.length) {
          this.telemetryService.updateCampaignParameters(cData);
          this.telemetryGeneratorService.generateUtmInfoTelemetry(params,
            PageId.QRCodeScanner, ContentUtil.getTelemetryObject(content), corRelationData);
        }

        this.navigateToDetailsPage(content,
          this.getCorRelationList(content.identifier, QRScannerResultHandler.CORRELATION_TYPE, scannedData));
        this.telemetryGeneratorService.generateImpressionTelemetry(
          ImpressionType.VIEW, ImpressionSubtype.QR_CODE_VALID,
          PageId.QRCodeScanner,
          Environment.HOME,
          contentId, ObjectType.QR, ''
        );
      }).catch(() => {
        if (!this.commonUtilService.networkInfo.isNetworkAvailable) {
          this.commonUtilService.showToast('ERROR_NO_INTERNET_MESSAGE');
        } else {
          this.commonUtilService.showToast('UNKNOWN_QR');
          this.telemetryGeneratorService.generateImpressionTelemetry(
            ImpressionType.VIEW, ImpressionSubtype.INVALID_QR_CODE,
            PageId.QRCodeScanner,
            Environment.HOME,
            contentId, ObjectType.QR, ''
          );
        }
      });
  }

  handleCertsQR(source: string, scannedData: string) {
    this.generateQRScanSuccessInteractEvent(scannedData, 'OpenBrowser', undefined, {
      certificateId: scannedData.split('/certs/')[1], scannedFrom: 'mobileApp'
    });
    this.telemetryService.buildContext().subscribe(context => {
      scannedData = scannedData + '?clientId=android&context=' + encodeURIComponent(JSON.stringify(context));
      this.inAppBrowserRef = cordova.InAppBrowser.open(scannedData, '_blank', 'zoom=no');
      this.inAppBrowserRef.addEventListener('loadstart', (event) => {
        if (event.url) {
          if (event.url.includes('explore-course')) {
            this.inAppBrowserRef.close();
            this.events.publish('return_course');
          }
        }
      });
    });
  }

  async handleRcCertsQR(scannedData){
    let encodedData, verifyCertReq;
    this.generateQRScanSuccessInteractEvent(scannedData, 'OpenBrowser', undefined, {
      certificateId: scannedData.split('/certs/')[1], scannedFrom: 'mobileApp'
    });
    if(scannedData.includes('data=')){
      try {
        encodedData = await this.certificateService.getEncodedData(scannedData.split('data=')[1])
      } catch(e) {
        console.error(e)
      }
    }
    verifyCertReq = {
      certificateId: scannedData.split('certs/')[1].split('?')[0],
      certificateData: encodedData,
      schemaName: 'certificate',
    }
    this.certificateService.verifyCertificate(verifyCertReq).toPromise()
    .then(async (res) => {
      if(res.verified) {
        const qrAlert = await this.popoverCtrl.create({
          component: CertificateVerificationPopoverComponent,
          componentProps: {
              certificateData: res.certificateData,
              actionsButtons: [
                  {
                      // btntext: this.translateMessage('OKAY'),
                      btntext: 'OKAY',
                      btnClass: 'sb-btn sb-btn-sm  sb-btn-tertiary'
                  }
              ],
          },
          cssClass: 'sb-popover',
        });
        await qrAlert.present();
      } else {
        this.commonUtilService.afterOnBoardQRErrorAlert('INVALID_QR', 'CERTIFICATE_VERIFICATION_FAIL', this.source, scannedData);
      }
    }).catch((err) => {
      console.log('handleCertsQR mobile err', err)
    })
  }

  handleInvalidQRCode(source: string, scannedData: string) {
    this.source = source;
    this.generateQRScanSuccessInteractEvent(scannedData, 'UNKNOWN');
    this.generateEndEvent(this.source, scannedData);
  }

  getCorRelationList(identifier: string, type: string, scannedData): Array<CorrelationData> {
    const corRelationList: Array<CorrelationData> = new Array<CorrelationData>();
    corRelationList.push({id: identifier, type});
    corRelationList.push({
      id: ContentUtil.extractBaseUrl(scannedData),
      type: CorReleationDataType.SOURCE
    });
    return corRelationList;
  }

  navigateToDetailsPage(content, corRelationList) {
    const navigationExtras: NavigationExtras = {
      state: {
        content,
        corRelation: corRelationList,
        source: this.source,
        shouldGenerateEndTelemetry: true
      }
    };

    this.navService.navigateToDetailPage(
      content,
      navigationExtras.state
    );
  }

  generateQRScanSuccessInteractEvent(scannedData, action, dialCode?, certificate?:
    { certificateId: string, scannedFrom: 'mobileApp' | 'genericApp' }) {
    const values = new Map();
    values['networkAvailable'] = this.commonUtilService.networkInfo.isNetworkAvailable ? 'Y' : 'N';
    values['scannedData'] = scannedData;
    values['action'] = action;
    values['compatibile'] = (action === 'OpenBrowser' || action === 'SearchResult' || action === 'ContentDetail') ? 1 : 0;
    if (this.scannedUrlMap) {
      values['dialCodeType'] = this.scannedUrlMap['sunbird'] ? 'standard' : 'non-standard';
    }
    let telemetryObject: TelemetryObject;

    if (dialCode) {
      telemetryObject = new TelemetryObject(dialCode, 'qr', undefined);
    }
    if (certificate) {
      values['scannedFrom'] = certificate.scannedFrom;
      telemetryObject = new TelemetryObject(certificate.certificateId, 'certificate', undefined);
    }

    const corRelationList: Array<CorrelationData> = [{
      id: ContentUtil.extractBaseUrl(scannedData),
      type: CorReleationDataType.SOURCE
    }];

    this.telemetryGeneratorService.generateInteractTelemetry(
      InteractType.OTHER,
      InteractSubtype.QRCodeScanSuccess,
      Environment.HOME,
      PageId.QRCodeScanner, telemetryObject,
      values,
      undefined,
      corRelationList
    );
  }

  generateEndEvent(pageId: string, qrData: string) {
    if (pageId) {
      const telemetryObject = new TelemetryObject(qrData, QRScannerResultHandler.CORRELATION_TYPE, undefined);

      this.telemetryGeneratorService.generateEndTelemetry(
        QRScannerResultHandler.CORRELATION_TYPE,
        Mode.PLAY,
        pageId,
        Environment.HOME,
        telemetryObject
      );
    }
  }

  private generateImpressionEvent(source, dialCode) {
    const corRelationList: Array<CorrelationData> = [];
    corRelationList.push({id: dialCode, type: CorReleationDataType.QR});
    this.telemetryGeneratorService.generateImpressionTelemetry(
      ImpressionType.PAGE_REQUEST, '',
      PageId.QR_BOOK_RESULT,
      source ? Environment.ONBOARDING : Environment.HOME, '', '', '',
      undefined,
      corRelationList);
  }

  async manageLearScan(scannedData) {
    this.selectedUserType = await this.preferences.getString(PreferenceKey.SELECTED_USER_TYPE).toPromise();
    if (scannedData.includes('/create-project/') && this.permittedUsers.includes(this.selectedUserType.toLowerCase()) ) {
      this.navigateHandler(scannedData);
      return;
    }
    if (!this.appGlobalService.isUserLoggedIn()) {
      this.commonUtilService.showToast("FRMELEMNTS_MSG_PLEASE_LOGIN_HT_OTHER");
      return;
    }
    if ((scannedData.includes('/create-observation/')) && this.permittedUsers.includes(this.selectedUserType.toLowerCase()) ) {
      this.navigateHandler(scannedData);
      return;
    } else {
      this.commonUtilService.showToast('FRMELEMNTS_MSG_CONTENT_NOT_AVAILABLE_FOR_ROLE');
    }
  }
  async navigateHandler(scannedData) {
    const deepLinkUrlConfig: { name: string, code: string, pattern: string, route: string, priority?: number, params?: {} }[] =
      await this.formFrameWorkUtilService.getFormFields(FormConstants.DEEPLINK_CONFIG);
    let matchedDeeplinkConfig: { name: string, code: string, pattern: string, route: string, priority?: number } = null;
    let urlMatch;
    deepLinkUrlConfig.forEach(config => {
      const urlRegexMatch = scannedData.match(new RegExp(config.pattern));
      if (!!urlRegexMatch && (!matchedDeeplinkConfig)) {
        if (config.code === 'profile' && !this.appGlobalService.isUserLoggedIn()) {
          config.route = 'tabs/guest-profile';
        }
        matchedDeeplinkConfig = config;
        urlMatch = urlRegexMatch;
      }
    });
    if (!matchedDeeplinkConfig) {
      return;
    }
    let identifier;
    if (urlMatch && urlMatch.groups && Object.keys(urlMatch.groups).length) {
      identifier = urlMatch.groups.quizId || urlMatch.groups.content_id || urlMatch.groups.course_id;
    }
    let extras = {};
    const route = matchedDeeplinkConfig.route;
    extras = {
      state: {
        data: urlMatch.groups
      }
    };
    this.navCtrl.navigateForward([route], extras);
  }

  
}

results matching ""

    No results matching ""