Skip to content

Commit

Permalink
feat(export): New export logic to prevent KS usage in email (#461)
Browse files Browse the repository at this point in the history
* AWS export fix

* updated design + support report name and export date

* url cleanup + additional error handling

* use valueSeparator for name split

* do not use valueSeparator for name split

* updated clientlib and export baseUrl parameter

* typo fix

* enable getting export route from config + error handling
  • Loading branch information
amirch1 authored Sep 27, 2021
1 parent e1dec40 commit 1354324
Show file tree
Hide file tree
Showing 13 changed files with 211 additions and 7 deletions.
Binary file not shown.
6 changes: 3 additions & 3 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@
"echarts": "^4.2.1",
"jquery": "^3.5.1",
"jsnlog": "^2.29.0",
"kaltura-ngx-client": "file:libs/kaltura-ngx-client-12.0.0-v20210421-080207.tgz",
"kaltura-ngx-client": "file:libs/kaltura-ngx-client-12.0.0-v20210924-085014.tgz",
"moment": "^2.24.0",
"ng-carousel-iuno": "^0.3.0",
"ngx-echarts": "^4.2.1",
Expand Down Expand Up @@ -75,4 +75,4 @@
"tslint": "~5.9.1",
"typescript": "3.8.3"
}
}
}
8 changes: 8 additions & 0 deletions src/app/app-routing/app-routing.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,14 @@ const routes: Routes = [
path: 'entry',
loadChildren: () => import('../modules/entry/entry.module').then(m => m.EntryModule)
},
{
path: 'export/:id',
loadChildren: () => import('../modules/export/export.module').then(m => m.ExportModule)
},
{
path: 'export',
loadChildren: () => import('../modules/export/export.module').then(m => m.ExportModule)
},
{
path: 'category/:id',
loadChildren: () => import('../modules/category/category.module').then(m => m.CategoryModule)
Expand Down
14 changes: 14 additions & 0 deletions src/app/modules/export/export.component.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<div data-aid="report-group-entry" class="kMain">
<k-area-blocker [showLoader]="_downloadingReport" [message]="_blockerMessage">
<div class="kReportView kContent">
<div *ngIf="!_invalidLink" class="kExportContent">
<span class="kTitle" [innerHTML]="'app.exportReports.reportReady' | translate: { reportName: _reportName } "></span>
<span class="kTitle">{{'app.exportReports.exportDate' | translate: {exportDate: _exportDate} }}</span>
<button type="button" class="kButtonBranded" pButton [label]="'app.exportReports.download' | translate" [disabled]="_downloadingReport" (click)="_downloadReport()"></button>
</div>
<div *ngIf="_invalidLink" class="kExportContent">
<span class="kTitle">{{'app.exportReports.errorMessage' | translate }}</span>
</div>
</div>
</k-area-blocker>
</div>
21 changes: 21 additions & 0 deletions src/app/modules/export/export.component.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
.kExportContent {
display: flex;
width: 100%;
background: white;
flex-direction: column;
align-items: center;
justify-content: center;
height: calc(100vh - 52px);
position: relative;
margin-top: 24px;
.kTitle {
margin-top: 8px;
margin-bottom: 8px;
color: black;
font-size: 16px;
}
button {
margin-top: 12px;
}
}

102 changes: 102 additions & 0 deletions src/app/modules/export/export.component.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
import {Component, OnDestroy, OnInit} from '@angular/core';
import {ActivatedRoute, Router} from '@angular/router';
import {cancelOnDestroy} from '@kaltura-ng/kaltura-common';
import {AreaBlockerMessage} from '@kaltura-ng/kaltura-ui';
import {AuthService, BrowserService, ErrorsManagerService, NavigationDrillDownService} from 'shared/services';
import {TranslateService} from '@ngx-translate/core';
import {HttpClient, HttpHeaders} from "@angular/common/http";
import {analyticsConfig, buildCDNUrl} from "configuration/analytics-config";
import {DateFilterUtils} from "shared/components/date-filter/date-filter-utils";

@Component({
selector: 'app-export',
templateUrl: './export.component.html',
styleUrls: ['./export.component.scss'],
})
export class ExportComponent implements OnInit, OnDestroy {
public _downloadingReport = false;
public _blockerMessage: AreaBlockerMessage = null;
public _reportId = '';
public _reportName = '';
public _exportDate = '';
public _invalidLink = false;

constructor(private _route: ActivatedRoute,
private _http: HttpClient,
private _translate: TranslateService,
private _errorsManager: ErrorsManagerService,
private _browserService: BrowserService,
private _authService: AuthService) {
}

ngOnInit() {
this._route.params
.pipe(cancelOnDestroy(this))
.subscribe(params => {
const queryParams = params && params.id ? params.id.split('|') : [];
if (queryParams.length > 0) {
this._reportId = queryParams[0];
this._reportName = queryParams.length > 1 ? queryParams[1] : '';
const dateFormat = analyticsConfig.dateFormat === 'month-day-year' ? 'MMMM DD, YYYY' : 'DD MMMM, YYYY';
const date = queryParams.length > 2 ? queryParams[2] : '';
this._exportDate = DateFilterUtils.getMomentDate(parseInt(date)).format(dateFormat);
if (window.parent && window.parent.history) {
window.parent.history.replaceState(null, null, window.parent.location.pathname);
}
} else {
this._invalidLink = true;
}
});
}

ngOnDestroy() {
}

public _downloadReport(): void {
this._downloadingReport = true;
this._blockerMessage = null;

const url = buildCDNUrl(`/api_v3/index.php/service/report/action/serve/id/${this._reportId}/ks/${this._authService.ks}`);
const httpOptions = {
headers: new HttpHeaders({
'Accept': 'text/html, application/xhtml+xml, */*',
'Content-Type': 'application/x-www-form-urlencoded'
}),
responseType: 'text'
};

this._http.post(url, {}, httpOptions as any).subscribe(
result => {
this._downloadingReport = false;
if (result.toString() === "") {
const actions = {
'close': () => {
this._blockerMessage = null;
}
};
this._blockerMessage = new AreaBlockerMessage({
message: this._translate.instant('app.exportReports.reportNotFound'),
buttons: [{
label: this._translate.instant('app.common.close'),
action: () => this._blockerMessage = null
}]
});
} else {
this._browserService.download(result, `${this._reportId}.csv`, 'text/csv');
}
},
error => {
this._downloadingReport = false;
const actions = {
'close': () => {
this._blockerMessage = null;
},
'retry': () => {
this._downloadReport();
}
};
this._blockerMessage = this._errorsManager.getErrorMessage(error, actions);
});

}
}
25 changes: 25 additions & 0 deletions src/app/modules/export/export.module.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { RouterModule } from '@angular/router';
import { TranslateModule } from '@ngx-translate/core';
import { routing } from './export.routes';
import { ExportComponent } from './export.component';
import { AreaBlockerModule } from '@kaltura-ng/kaltura-ui';
import { ButtonModule } from 'primeng/button';

@NgModule({
imports: [
CommonModule,
TranslateModule,
AreaBlockerModule,
ButtonModule,
RouterModule.forChild(routing)
],
declarations: [
ExportComponent
],
exports: [],
providers: []
})
export class ExportModule {
}
12 changes: 12 additions & 0 deletions src/app/modules/export/export.routes.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { Route } from '@angular/router';
import { ExportComponent } from './export.component';

export const routing: Route[] = [
{
path: '', component: ExportComponent,
children: [
{ path: 'export', redirectTo: 'export/:id', pathMatch: 'full' },
{ path: 'export/:id', component: ExportComponent }
]
}
];
15 changes: 14 additions & 1 deletion src/app/shared/components/export-csv/export-csv.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,13 @@ import { DateFilterUtils } from 'shared/components/date-filter/date-filter-utils
import { cancelOnDestroy } from '@kaltura-ng/kaltura-common';
import { finalize } from 'rxjs/operators';
import { ExportItem } from 'shared/components/export-csv/export-config-base.service';
import { KalturaLogger } from "@kaltura-ng/kaltura-logger";

@Component({
selector: 'app-export-csv',
templateUrl: './export-csv.component.html',
styleUrls: ['./export-csv.component.scss'],
providers: [KalturaLogger.createLogger('ExportCSV'),]
})
export class ExportCsvComponent implements OnDestroy {
@Input() name = 'default';
Expand Down Expand Up @@ -61,6 +63,7 @@ export class ExportCsvComponent implements OnDestroy {
constructor(private _reportService: ReportService,
private _translate: TranslateService,
private _browserService: BrowserService,
private _logger: KalturaLogger,
private _kalturaClient: KalturaClient) {
}

Expand Down Expand Up @@ -210,7 +213,17 @@ export class ExportCsvComponent implements OnDestroy {
}
});

const exportAction = new ReportExportToCsvAction({ params: new KalturaReportExportParams({ timeZoneOffset, reportsItemsGroup, reportItems }) });
let baseUrl = '';
try {
const origin = window.parent && window.parent.location && window.parent.location.origin ? window.parent.location.origin : window.location.origin;
const isKMC = window.parent && typeof window.parent['kmcng'] === 'object';
const exportRoute = analyticsConfig.kalturaServer.exportRoute ? analyticsConfig.kalturaServer.exportRoute : isKMC ? '/index.php/kmcng/analytics/export?id=' : '/userreports/downloadreport?report_id=';
baseUrl = encodeURIComponent(`${origin}${exportRoute}`);
} catch (e) {
this._logger.error('Error accessing parent window location', e);
}

const exportAction = new ReportExportToCsvAction({ params: new KalturaReportExportParams({ timeZoneOffset, reportsItemsGroup, reportItems, baseUrl }) });

this._exportingCsv = true;

Expand Down
6 changes: 5 additions & 1 deletion src/assets/i18n/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -109,12 +109,12 @@
"exportCsv": "Export",
"exportReports": "Export Reports",
"exportReport": "Export Report",
"reportReady": "Your report is ready!",
"na": "N/A",
"noMsg": "No Message",
"noResults": "No Data Found",
"noResultsRegion": "No Data for this Region",
"exporting": "Preparing Report",
"reportReady": "Your report is ready!",
"reportFail": "Report preparation failed.",
"downloadCsv": "Download Report",
"tryAgain": "Try Again",
Expand All @@ -137,6 +137,10 @@
},
"exportReports": {
"exportReports": "Export Reports",
"download": "Download Report",
"exportDate": "Exported {{exportDate}}",
"reportReady": "Your <b>{{reportName}}</b> report is ready for download",
"reportNotFound": "Report expired. Please export it again.",
"successMessage": "We are preparing your report. We will send it to your email address shortly.",
"errorMessage": "There was an error processing your export request, please try again or contact Kaltura support."
},
Expand Down
1 change: 1 addition & 0 deletions src/configuration/analytics-config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ export interface AnalyticsConfig {
uri?: string,
previewUIConf?: number,
previewUIConfV7?: number,
exportRoute?: string
};
cdnServers?: {
serverUri?: string,
Expand Down
4 changes: 4 additions & 0 deletions src/configuration/host-routing-mapping.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,10 @@ export function mapRoutes(kmcRoute: string, queryParams: { [key: string]: string
case '/analytics/entry':
analyticsRoute = `/entry${idPostfix}`;
break;
case 'export':
case '/analytics/export':
analyticsRoute = `/export${idPostfix}`;
break;
case 'category':
case '/analytics/category':
analyticsRoute = `/category${idPostfix}`;
Expand Down

0 comments on commit 1354324

Please sign in to comment.