diff --git a/src/app/app.component.html b/src/app/app.component.html index a1e1895949..7ca1ce81ae 100644 --- a/src/app/app.component.html +++ b/src/app/app.component.html @@ -2,4 +2,9 @@ - + + + + + + diff --git a/src/applications/content-entries-app/content-entries-app.module.ts b/src/applications/content-entries-app/content-entries-app.module.ts index 041c2e51d3..03f60a13c5 100644 --- a/src/applications/content-entries-app/content-entries-app.module.ts +++ b/src/applications/content-entries-app/content-entries-app.module.ts @@ -28,7 +28,7 @@ import { EntriesComponentsList } from './entries/entries-components-list'; import { CategoriesStore } from './shared/categories-store.service'; import { EntriesRefineFiltersProvider } from './entries/entries-refine-filters/entries-refine-filters-provider.service'; import { CategoriesPrimeService } from './shared/categories-prime.service'; -import { BulkSchedulingService, BulkAddTagsService, BulkRemoveTagsService, BulkAddCategoriesService, BulkChangeOwnerService } from './entries/bulk-actions/services'; +import { BulkSchedulingService, BulkAccessControlService, BulkAddTagsService, BulkRemoveTagsService, BulkAddCategoriesService, BulkChangeOwnerService, BulkRemoveCategoriesService, BulkDeleteService, BulkDownloadService } from './entries/bulk-actions/services'; import { SharedComponentsList } from './shared/shared-components-list'; @NgModule({ @@ -83,10 +83,14 @@ import { SharedComponentsList } from './shared/shared-components-list'; MetadataProfileStore, EntriesRefineFiltersProvider, BulkSchedulingService, + BulkAccessControlService, BulkAddTagsService, BulkRemoveTagsService, BulkAddCategoriesService, - BulkChangeOwnerService + BulkChangeOwnerService, + BulkRemoveCategoriesService, + BulkDeleteService, + BulkDownloadService ], }) export class ContentEntriesAppModule { diff --git a/src/applications/content-entries-app/entries/bulk-actions/bulk-actions.component.html b/src/applications/content-entries-app/entries/bulk-actions/bulk-actions.component.html index c2272fa7af..a3cf75fe5b 100644 --- a/src/applications/content-entries-app/entries/bulk-actions/bulk-actions.component.html +++ b/src/applications/content-entries-app/entries/bulk-actions/bulk-actions.component.html @@ -10,10 +10,13 @@
+ + +
diff --git a/src/applications/content-entries-app/entries/bulk-actions/bulk-actions.component.ts b/src/applications/content-entries-app/entries/bulk-actions/bulk-actions.component.ts index d03e75cc7b..4fda43ab6f 100644 --- a/src/applications/content-entries-app/entries/bulk-actions/bulk-actions.component.ts +++ b/src/applications/content-entries-app/entries/bulk-actions/bulk-actions.component.ts @@ -5,12 +5,13 @@ import { PopupWidgetComponent } from '@kaltura-ng/kaltura-ui/popup-widget/popup- import { BrowserService } from "app-shared/kmc-shell/providers/browser.service"; import { SchedulingParams } from './services' -import { BulkSchedulingService, BulkAddTagsService, BulkRemoveTagsService, BulkAddCategoriesService, EntryCategoryItem, BulkChangeOwnerService } from './services'; +import { BulkSchedulingService, BulkAccessControlService, BulkAddTagsService, BulkRemoveTagsService, BulkAddCategoriesService, EntryCategoryItem, BulkChangeOwnerService, BulkRemoveCategoriesService, BulkDeleteService, BulkDownloadService } from './services'; import { KalturaMediaEntry } from "kaltura-typescript-client/types/KalturaMediaEntry"; import { BulkActionBaseService } from "./services/bulk-action-base.service"; import { environment } from 'app-environment'; import { KalturaUser } from 'kaltura-typescript-client/types/KalturaUser'; - +import { KalturaMediaType } from 'kaltura-typescript-client/types/KalturaMediaType'; +import { KalturaAccessControl } from 'kaltura-typescript-client/types/KalturaAccessControl'; @Component({ selector: 'kBulkActions', templateUrl: './bulk-actions.component.html', @@ -31,10 +32,14 @@ export class BulkActionsComponent implements OnInit, OnDestroy { constructor(private _appLocalization: AppLocalization, private _browserService : BrowserService, private _bulkSchedulingService: BulkSchedulingService, + private _bulkAccessControlService: BulkAccessControlService, private _bulkAddTagsService: BulkAddTagsService, private _bulkRemoveTagsService: BulkRemoveTagsService, private _bulkAddCategoriesService: BulkAddCategoriesService, - private _bulkChangeOwnerService: BulkChangeOwnerService) { + private _bulkChangeOwnerService: BulkChangeOwnerService, + private _bulkRemoveCategoriesService: BulkRemoveCategoriesService, + private _bulkDownloadService: BulkDownloadService, + private _bulkDeleteService: BulkDeleteService) { } @@ -61,13 +66,18 @@ export class BulkActionsComponent implements OnInit, OnDestroy { this.executeService(this._bulkSchedulingService, schedulingParams); } + // set access control changes + onAccessControlChanged(profile: KalturaAccessControl): void{ + this.executeService(this._bulkAccessControlService, profile); + } + // add tags changed onAddTagsChanged(tags: string[]): void{ this.executeService(this._bulkAddTagsService, tags); } // remove tags changed - onRemoveTagsChanged(tags: string[]): void{ + onRemoveTagsChanged(tags: string[]): void { this.executeService(this._bulkRemoveTagsService, tags); } @@ -76,6 +86,11 @@ export class BulkActionsComponent implements OnInit, OnDestroy { this.executeService(this._bulkAddCategoriesService, categories); } + // remove categories changed + onRemoveCategoriesChanged(categories: number[]): void{ + this.executeService(this._bulkRemoveCategoriesService, categories); + } + // owner changed onOwnerChanged(owners: KalturaUser[]): void{ if (owners && owners.length){ @@ -83,7 +98,56 @@ export class BulkActionsComponent implements OnInit, OnDestroy { } } - private executeService(service: BulkActionBaseService, data: any, reloadEntries: boolean = true ): void{ + // download changed + onDownloadChanged(flavorId: number): void{ + const showSuccessMsg = (result) => { + this._browserService.alert( + { + header: this._appLocalization.get('applications.content.bulkActions.download'), + message: this._appLocalization.get('applications.content.bulkActions.downloadMsg',{0: result && result.email ? result.email : ''}) + } + ); + }; + this.executeService(this._bulkDownloadService, flavorId, false, showSuccessMsg); + } + + // bulk delete + private deleteEntries(): void{ + let msg = ''; + // display entries marked for deletion in the confirmation box if there are up to 10 selected entries. Otherwise, just confirm deletion + if (this.selectedEntries.length > 10){ + msg = `${this._appLocalization.get('applications.content.bulkActions.deleteConfirm')}

${this._appLocalization.get('applications.content.bulkActions.deleteNote')}`; + }else{ + msg = `${this._appLocalization.get('applications.content.bulkActions.deleteConfirm')}

`; + this.selectedEntries.forEach(entry => { + msg += `${this._appLocalization.get('applications.content.entries.entryId', { 0: entry.id })}
`; + }); + msg += `
${this._appLocalization.get('applications.content.bulkActions.deleteNote')}` + } + this._browserService.confirm( + { + header: this._appLocalization.get('applications.content.bulkActions.deleteEntries'), + message: msg, + accept: () => { + setTimeout(()=>{ + this.executeService(this._bulkDeleteService); // need to use a timeout between multiple confirm dialogues (if more than 50 entries are selected) + },0); + } + } + ); + } + + // bulk download initial check + private downloadEntries():void{ + // check for single image selection - immediate download + if (this.selectedEntries.length === 1 && this.selectedEntries[0].mediaType === KalturaMediaType.image){ + this._browserService.openLink(this.selectedEntries[0].downloadUrl + "/file_name/name"); + }else{ + this.openBulkActionWindow("download", 570, 500) + } + } + + private executeService(service: BulkActionBaseService, data: any = {}, reloadEntries: boolean = true, callback?: Function ): void{ this._bulkAction = ""; const execute = () => { @@ -91,6 +155,9 @@ export class BulkActionsComponent implements OnInit, OnDestroy { service.execute(this.selectedEntries, data).subscribe( result => { this._browserService.setAppStatus({isBusy: false, errorMessage: null}); + if (callback){ + callback(result); + } this.onBulkChange.emit({reload: reloadEntries}); }, error => { @@ -117,7 +184,7 @@ export class BulkActionsComponent implements OnInit, OnDestroy { getBulkActionItems(): MenuItem[]{ return [ { label: this._appLocalization.get('applications.content.bulkActions.setScheduling'), command: (event) => { this.openBulkActionWindow("setScheduling", 500, 500) } }, - { label: this._appLocalization.get('applications.content.bulkActions.setAccessControl'), command: (event) => { this.openBulkActionWindow("setAccessControl", 500, 500) } }, + { label: this._appLocalization.get('applications.content.bulkActions.setAccessControl'), command: (event) => { this.openBulkActionWindow("setAccessControl", 500, 550) } }, { label: this._appLocalization.get('applications.content.bulkActions.addRemoveTags'), items: [ { label: this._appLocalization.get('applications.content.bulkActions.addTags'), command: (event) => { this.openBulkActionWindow("addTags", 500, 500) } }, { label: this._appLocalization.get('applications.content.bulkActions.removeTags'), command: (event) => { this.openBulkActionWindow("removeTags", 500, 500) } }] @@ -131,8 +198,8 @@ export class BulkActionsComponent implements OnInit, OnDestroy { { label: this._appLocalization.get('applications.content.bulkActions.addToNewPlaylist'), command: (event) => { this.openBulkActionWindow("addToNewPlaylist", 500, 500) } }] }, { label: this._appLocalization.get('applications.content.bulkActions.changeOwner'), command: (event) => { this.openBulkActionWindow("changeOwner", 500, 500) } }, - { label: this._appLocalization.get('applications.content.bulkActions.download'), command: (event) => { this.openBulkActionWindow("download", 500, 500) } }, - { label: this._appLocalization.get('applications.content.bulkActions.delete'), command: (event) => { this.openBulkActionWindow("delete", 500, 500) } } + { label: this._appLocalization.get('applications.content.bulkActions.download'), command: (event) => { this.downloadEntries() } }, + { label: this._appLocalization.get('applications.content.bulkActions.delete'), command: (event) => { this.deleteEntries() } } ]; } } \ No newline at end of file diff --git a/src/applications/content-entries-app/entries/bulk-actions/components/bulk-access-control/bulk-access-control.component.html b/src/applications/content-entries-app/entries/bulk-actions/components/bulk-access-control/bulk-access-control.component.html new file mode 100644 index 0000000000..293d9aa290 --- /dev/null +++ b/src/applications/content-entries-app/entries/bulk-actions/components/bulk-access-control/bulk-access-control.component.html @@ -0,0 +1,47 @@ + +
+ {{'applications.content.bulkActions.setAccessControl' | translate}} + +
+ +
+
+ {{'applications.content.entryDetails.accessControl.profile' | translate}} + +
+
+ {{'applications.content.entryDetails.accessControl.name' | translate}} + {{selectedProfile.name}} +
+
+ {{'applications.content.entryDetails.accessControl.accessControl' | translate}} + {{selectedProfile.description}} +
+
+ {{'applications.content.entryDetails.accessControl.domains' | translate}} + {{_domainsRestriction}} +
+
+ {{'applications.content.entryDetails.accessControl.countries' | translate}} + {{_countriesRestriction}} +
+
+ {{'applications.content.entryDetails.accessControl.ips' | translate}} + {{_ipRestriction}} +
+
+ {{'applications.content.entryDetails.accessControl.flavours' | translate}} + {{_flavourRestriction}} +
+
+ {{'applications.content.entryDetails.accessControl.advanced' | translate}} + {{_advancedRestriction}} +
+
+
+ +
+ +
+
+
diff --git a/src/applications/content-entries-app/entries/bulk-actions/components/bulk-access-control/bulk-access-control.component.scss b/src/applications/content-entries-app/entries/bulk-actions/components/bulk-access-control/bulk-access-control.component.scss new file mode 100644 index 0000000000..dbf3c23c8a --- /dev/null +++ b/src/applications/content-entries-app/entries/bulk-actions/components/bulk-access-control/bulk-access-control.component.scss @@ -0,0 +1,61 @@ +@import "app-theme/_variables.scss"; + +.kTitle{ + color: $kGrayscale1; + font-size: 24px; + font-weight: 700; + text-align: center; + border-bottom: 1px solid $kGrayscale4; + height: 78px; + line-height: 78px; +} +.kContent{ + display: flex; + flex-direction: column; + height: 550px; + .kLabel{ + display: block; + margin-bottom: 8px; + } + .kAccessControl{ + padding: 12px; + height: 380px; + overflow-y: auto; + overflow-x: hidden; + .kAccessControlDetails{ + padding-left: 12px; + padding-right: 12px; + width: 100%; + .kRow{ + display: flex; + padding-top: 24px; + align-items: center; + } + .kLabels{ + width: 180px; + flex: 0 0 auto; + } + } + } +} +.kFooter{ + position: absolute; + bottom: 0px; + display: flex; + width: 100%; + height: 66px; + border-top: 1px solid $kGrayscale4; + align-items: center; + justify-content: center; +} +:host /deep/ kautocomplete ul.ui-autocomplete-multiple-container.ui-inputtext{ + padding: 0px; + .ui-autocomplete-input-token{ + padding: 0px; + input{ + height: 34px; + padding-left: 4px; + width: 472px; + } + } +} diff --git a/src/applications/content-entries-app/entries/bulk-actions/components/bulk-access-control/bulk-access-control.component.ts b/src/applications/content-entries-app/entries/bulk-actions/components/bulk-access-control/bulk-access-control.component.ts new file mode 100644 index 0000000000..ee8cd0121c --- /dev/null +++ b/src/applications/content-entries-app/entries/bulk-actions/components/bulk-access-control/bulk-access-control.component.ts @@ -0,0 +1,263 @@ +import { Component, OnInit, OnDestroy, AfterViewInit, Input, Output, EventEmitter } from '@angular/core'; +import { ISubscription } from 'rxjs/Subscription'; + +import { KalturaClient } from '@kaltura-ng/kaltura-client'; +import { BrowserService } from 'app-shared/kmc-shell'; +import { AreaBlockerMessage } from '@kaltura-ng/kaltura-ui'; +import { PopupWidgetComponent, PopupWidgetStates } from '@kaltura-ng/kaltura-ui/popup-widget/popup-widget.component'; + + +import { Observable } from 'rxjs/Observable'; +import { BehaviorSubject } from 'rxjs/BehaviorSubject'; +import { SelectItem } from 'primeng/primeng'; + +import { KalturaAccessControl } from 'kaltura-typescript-client/types/KalturaAccessControl'; +import { KalturaSiteRestriction } from 'kaltura-typescript-client/types/KalturaSiteRestriction'; +import { KalturaSiteRestrictionType } from 'kaltura-typescript-client/types/KalturaSiteRestrictionType'; +import { KalturaCountryRestriction } from 'kaltura-typescript-client/types/KalturaCountryRestriction'; +import { KalturaCountryRestrictionType } from 'kaltura-typescript-client/types/KalturaCountryRestrictionType'; +import { KalturaIpAddressRestriction } from 'kaltura-typescript-client/types/KalturaIpAddressRestriction'; +import { KalturaIpAddressRestrictionType } from 'kaltura-typescript-client/types/KalturaIpAddressRestrictionType'; +import { KalturaLimitFlavorsRestriction } from 'kaltura-typescript-client/types/KalturaLimitFlavorsRestriction'; +import { KalturaLimitFlavorsRestrictionType } from 'kaltura-typescript-client/types/KalturaLimitFlavorsRestrictionType'; +import { KalturaSessionRestriction } from 'kaltura-typescript-client/types/KalturaSessionRestriction'; +import { KalturaPreviewRestriction } from 'kaltura-typescript-client/types/KalturaPreviewRestriction'; +import { KalturaFlavorParams } from 'kaltura-typescript-client/types/KalturaFlavorParams'; +import { AccessControlProfileStore, FlavoursStore, AppLocalization, KalturaUtils } from '@kaltura-ng/kaltura-common'; + +import 'rxjs/add/observable/forkJoin'; +import * as R from 'ramda'; + +@Component({ + selector: 'kBulkAccessControl', + templateUrl: './bulk-access-control.component.html', + styleUrls: ['./bulk-access-control.component.scss'] +}) +export class BulkAAccessControl implements OnInit, OnDestroy, AfterViewInit { + + @Input() parentPopupWidget: PopupWidgetComponent; + @Output() accessControlChangedChanged = new EventEmitter(); + + public _loading = false; + public _sectionBlockerMessage: AreaBlockerMessage; + + + public accessControlProfiles: KalturaAccessControl[] = []; + + + private _accessControlProfiles = new BehaviorSubject<{ items: SelectItem[]}>({items: []}); + public _accessControlProfiles$ = this._accessControlProfiles.asObservable(); + + private _selectedProfile: KalturaAccessControl = null; + public set selectedProfile(profile: KalturaAccessControl) { + this._selectedProfile = profile; + this._setRestrictions(); + } + + public get selectedProfile() { + return this._selectedProfile; + } + + public _domainsRestriction: string = ""; + public _countriesRestriction: string = ""; + public _ipRestriction: string = ""; + public _flavourRestriction: string = ""; + public _advancedRestriction: string = ""; + + private _flavourParams: KalturaFlavorParams[] = []; + + private _parentPopupStateChangeSubscribe: ISubscription; + private _confirmClose: boolean = true; + private isDirty = false; + + constructor(private _kalturaServerClient: KalturaClient, private _appLocalization: AppLocalization, private _browserService: BrowserService, private _accessControlProfileStore: AccessControlProfileStore, private _flavoursStore: FlavoursStore) { + } + + ngOnInit() { + this.loadAccessControlProfiles(); + } + + private loadAccessControlProfiles(): void { + this.accessControlProfiles = []; + this.fetchAccessControlProfiles().subscribe( + response => { + let ACProfiles = response[0].items; + if (ACProfiles.length) { + // check if any of the access control profiles is defined as default + const defaultIndex = R.findIndex(R.propEq('isDefault', true))(ACProfiles); + if (defaultIndex > -1) { + // put the default profile at the beginning of the profiles array + const defaultProfile: KalturaAccessControl[] = ACProfiles.splice(defaultIndex, 1); + ACProfiles.splice(0, 0, defaultProfile[0]); + } + let profilesDataProvider: SelectItem[] = []; + ACProfiles.forEach((profile: KalturaAccessControl) => { + profilesDataProvider.push({"label": profile.name, "value": profile}); + if (profile.isDefault === 1) { + this.selectedProfile = profile; + } + }); + if (!this.selectedProfile && profilesDataProvider.length) { + this.selectedProfile = profilesDataProvider[0].value; + } + this._flavourParams = response[1].items; + this._accessControlProfiles.next({items: profilesDataProvider}); + this._loading = false; + } + + }, + error => { + this._loading = false; + this._sectionBlockerMessage = new AreaBlockerMessage( + { + message: error.message, + buttons: [ + { + label: this._appLocalization.get('app.common.retry'), + action: () => { + this.loadAccessControlProfiles(); + } + } + ] + } + ); + this._accessControlProfiles.next({items: []}); + return Observable.throw(error); + } + ); + } + + ngAfterViewInit() { + if (this.parentPopupWidget) { + this._parentPopupStateChangeSubscribe = this.parentPopupWidget.state$ + .subscribe(event => { + if (event.state === PopupWidgetStates.Open) { + this._confirmClose = true; + } + if (event.state === PopupWidgetStates.BeforeClose) { + if (event.context && event.context.allowClose) { + if (this.isDirty && this._confirmClose) { + event.context.allowClose = false; + this._browserService.confirm( + { + header: this._appLocalization.get('applications.content.entryDetails.captions.cancelEdit'), + message: this._appLocalization.get('applications.content.entryDetails.captions.discard'), + accept: () => { + this._confirmClose = false; + this.parentPopupWidget.close(); + } + } + ); + } + } + } + }); + } + } + + ngOnDestroy() { + this._parentPopupStateChangeSubscribe.unsubscribe(); + } + + + public _apply() { + this.accessControlChangedChanged.emit(this.selectedProfile); + this._confirmClose = false; + this.parentPopupWidget.close(); + } + + private fetchAccessControlProfiles(): Observable { + this._loading = true; + this._accessControlProfiles.next({items: []}); + + const getAPProfiles$ = this._accessControlProfileStore.get().cancelOnDestroy(this).monitor('load access control profiles'); + const getFlavours$ = this._flavoursStore.get().cancelOnDestroy(this).monitor('load flavours'); + + return Observable.forkJoin(getAPProfiles$, getFlavours$).cancelOnDestroy(this); + } + + private _setRestrictions() { + + this._domainsRestriction = this._appLocalization.get('applications.content.entryDetails.accessControl.anyDomain'); + this._countriesRestriction = this._appLocalization.get('applications.content.entryDetails.accessControl.anyCountry'); + this._ipRestriction = this._appLocalization.get('applications.content.entryDetails.accessControl.anyIP'); + this._flavourRestriction = this._appLocalization.get('applications.content.entryDetails.accessControl.anyFlavour'); + this._advancedRestriction = ""; + + const restrictions = this.selectedProfile.restrictions; + if (restrictions.length) { + restrictions.forEach(restriction => { + // domains restrictions + if (restriction instanceof KalturaSiteRestriction) { + if (restriction.siteRestrictionType === KalturaSiteRestrictionType.allowSiteList) { + this._domainsRestriction = this._appLocalization.get('applications.content.entryDetails.accessControl.allowDomains', {"0": restriction.siteList}); + } + if (restriction.siteRestrictionType === KalturaSiteRestrictionType.restrictSiteList) { + this._domainsRestriction = this._appLocalization.get('applications.content.entryDetails.accessControl.blockDomains', {"0": restriction.siteList}); + } + } + // countries restrictions + if (restriction instanceof KalturaCountryRestriction) { + if (restriction.countryRestrictionType === KalturaCountryRestrictionType.allowCountryList) { + this._countriesRestriction = this._appLocalization.get('applications.content.entryDetails.accessControl.allowCountries', {"0": this._getCountriesByCode(restriction.countryList)}); + } + if (restriction.countryRestrictionType === KalturaCountryRestrictionType.restrictCountryList) { + this._countriesRestriction = this._appLocalization.get('applications.content.entryDetails.accessControl.blockCountries', {"0": this._getCountriesByCode(restriction.countryList)}); + } + } + // IP restrictions + if (restriction instanceof KalturaIpAddressRestriction) { + if (restriction.ipAddressRestrictionType === KalturaIpAddressRestrictionType.allowList) { + this._ipRestriction = this._appLocalization.get('applications.content.entryDetails.accessControl.allowIPs', {"0": restriction.ipAddressList}); + } + if (restriction.ipAddressRestrictionType === KalturaIpAddressRestrictionType.restrictList) { + this._ipRestriction = this._appLocalization.get('applications.content.entryDetails.accessControl.blockIPs', {"0": restriction.ipAddressList}); + } + } + // Flavour restrictions + if (restriction instanceof KalturaLimitFlavorsRestriction && this._flavourParams.length) { + // convert flavour IDs to flavour names + let flavourIDs = restriction.flavorParamsIds.split(","); + let flavourNames = []; + flavourIDs.forEach(flavourId => { + let flavour: KalturaFlavorParams = R.find(R.propEq('id', parseInt(flavourId)))(this._flavourParams); + if (flavour !== undefined) { + flavourNames.push(flavour.name); + } + }); + + if (restriction.limitFlavorsRestrictionType === KalturaLimitFlavorsRestrictionType.allowList) { + this._flavourRestriction = this._appLocalization.get('applications.content.entryDetails.accessControl.allowFlavours', {"0": flavourNames.join(", ")}); + } + if (restriction.limitFlavorsRestrictionType === KalturaLimitFlavorsRestrictionType.restrictList) { + this._flavourRestriction = this._appLocalization.get('applications.content.entryDetails.accessControl.blockFlavours', {"0": flavourNames.join(", ")}); + } + } + // Advanced restrictions + if (restriction instanceof KalturaSessionRestriction) { + this._advancedRestriction = this._appLocalization.get('applications.content.entryDetails.accessControl.ks'); + } + if (restriction instanceof KalturaPreviewRestriction) { + this._advancedRestriction = this._appLocalization.get('applications.content.entryDetails.accessControl.freePreview', {"0": KalturaUtils.formatTime(restriction.previewLength, true)}); + } + }); + } + } + + private _getCountriesByCode(codesList: string): string { + let countries = []; + const codes = codesList.split(","); + codes.forEach(code => { + const country = this._appLocalization.get('countries.' + code.toLowerCase()); + if (country) { + countries.push(country); + } + }); + return countries.join(", "); + } + + public onChange() { + this.isDirty = true; + } +} + diff --git a/src/applications/content-entries-app/entries/bulk-actions/components/bulk-download/bulk-download.component.html b/src/applications/content-entries-app/entries/bulk-actions/components/bulk-download/bulk-download.component.html new file mode 100644 index 0000000000..081722180b --- /dev/null +++ b/src/applications/content-entries-app/entries/bulk-actions/components/bulk-download/bulk-download.component.html @@ -0,0 +1,21 @@ + +
+ {{'applications.content.bulkActions.download' | translate}} +
+ {{'applications.content.bulkActions.download1Label' | translate}} + {{'applications.content.bulkActions.downloadManyLabel' | translate:_downloadLabel }} + {{'applications.content.bulkActions.downloadFlavor' | translate }} + + {{'applications.content.bulkActions.downloadAudio' | translate }} + {{'applications.content.bulkActions.downloadImage' | translate }} +
+ {{'app.common.note' | translate }} + {{'applications.content.bulkActions.downloadNote' | translate }} +
+ +
+
+ +
+
+
diff --git a/src/applications/content-entries-app/entries/bulk-actions/components/bulk-download/bulk-download.component.scss b/src/applications/content-entries-app/entries/bulk-actions/components/bulk-download/bulk-download.component.scss new file mode 100644 index 0000000000..aa398cb4e1 --- /dev/null +++ b/src/applications/content-entries-app/entries/bulk-actions/components/bulk-download/bulk-download.component.scss @@ -0,0 +1,48 @@ +@import "app-theme/_variables.scss"; + +.kTitle{ + color: $kGrayscale1; + font-size: 24px; + font-weight: 700; + text-align: center; + border-bottom: 1px solid $kGrayscale4; + height: 78px; + line-height: 78px; +} +.kContent{ + display: flex; + flex-direction: column; + height: 500px; + .kLabel{ + display: block; + margin-bottom: 14px; + } + .kSpacer{ + margin-top: 28px; + } + .kDownload{ + padding: 12px; + height: 330px; + overflow-y: auto; + overflow-x: hidden; + } + p-dropdown{ + display: block; + width: 100%; + margin-bottom: 14px; + } +} +.kFooter{ + position: absolute; + bottom: 0px; + display: flex; + width: 100%; + height: 66px; + border-top: 1px solid $kGrayscale4; + align-items: center; + justify-content: center; +} + +:host /deep/ .ui-dropdown{ + width: 100% !important; +} \ No newline at end of file diff --git a/src/applications/content-entries-app/entries/bulk-actions/components/bulk-download/bulk-download.component.ts b/src/applications/content-entries-app/entries/bulk-actions/components/bulk-download/bulk-download.component.ts new file mode 100644 index 0000000000..05fe9da111 --- /dev/null +++ b/src/applications/content-entries-app/entries/bulk-actions/components/bulk-download/bulk-download.component.ts @@ -0,0 +1,131 @@ +import { Component, OnInit, OnDestroy, AfterViewInit, Input, Output, EventEmitter } from '@angular/core'; +import { ISubscription } from 'rxjs/Subscription'; + +import { KalturaClient } from '@kaltura-ng/kaltura-client'; +import { AppLocalization } from '@kaltura-ng/kaltura-common'; +import { BrowserService } from 'app-shared/kmc-shell'; +import { AreaBlockerMessage } from '@kaltura-ng/kaltura-ui'; +import { PopupWidgetComponent, PopupWidgetStates } from '@kaltura-ng/kaltura-ui/popup-widget/popup-widget.component'; +import { KalturaMediaEntry } from "kaltura-typescript-client/types/KalturaMediaEntry"; +import { BulkRemoveCategoriesService } from '../../services/'; +import { KalturaFlavorParams } from 'kaltura-typescript-client/types/KalturaFlavorParams'; +import { FlavorParamsListAction } from 'kaltura-typescript-client/types/FlavorParamsListAction'; +import { KalturaFilterPager } from 'kaltura-typescript-client/types/KalturaFilterPager'; + +import {SelectItem} from 'primeng/primeng'; + +@Component({ + selector: 'kBulkDownload', + templateUrl: './bulk-download.component.html', + styleUrls: ['./bulk-download.component.scss'] +}) +export class BulkDownload implements OnInit, OnDestroy, AfterViewInit { + + @Input() selectedEntries: KalturaMediaEntry[]; + @Input() parentPopupWidget: PopupWidgetComponent; + @Output() downloadChanged = new EventEmitter(); + + public _loading = false; + public _sectionBlockerMessage: AreaBlockerMessage; + + public _flavors: SelectItem[] = []; + public _selectedFlavor: number; + + + private _parentPopupStateChangeSubscribe: ISubscription; + private _confirmClose: boolean = true; + private _downloadLabel = {}; + private _selectionChanged = false; + + constructor(private _kalturaServerClient: KalturaClient, private _appLocalization: AppLocalization, private _browserService: BrowserService, private _bulkRemoveCategoriesService: BulkRemoveCategoriesService) { + } + + ngOnInit() { + this._downloadLabel = {'0': this.selectedEntries.length}; + + // load flavors + this._loading = true; + this._sectionBlockerMessage = null; + + let pager: KalturaFilterPager = new KalturaFilterPager(); + pager.pageSize = 500; + pager.pageIndex = 1; + this._kalturaServerClient.request(new FlavorParamsListAction({ + pager: pager + })).subscribe( + response => { + this._loading = false; + response.objects.forEach(flavor => { + if (flavor instanceof KalturaFlavorParams){ + this._flavors.push({'label': flavor.name, 'value': flavor.id}); + if (flavor.id === 0){ // source + this._selectedFlavor = flavor.id; + } + } + }); + }, + error => { + this._loading = false; + this._sectionBlockerMessage = new AreaBlockerMessage( + { + message: error.message, + buttons: [ + { + label: this._appLocalization.get('app.common.close'), + action: () => { + this._confirmClose = false; + this.parentPopupWidget.close(); + } + } + ] + } + ); + + } + ); + } + + ngAfterViewInit() { + if (this.parentPopupWidget) { + this._parentPopupStateChangeSubscribe = this.parentPopupWidget.state$ + .subscribe(event => { + if (event.state === PopupWidgetStates.Open) { + this._confirmClose = true; + } + if (event.state === PopupWidgetStates.BeforeClose) { + if (event.context && event.context.allowClose) { + if (this._selectionChanged && this._confirmClose) { + event.context.allowClose = false; + this._browserService.confirm( + { + header: this._appLocalization.get('applications.content.entryDetails.captions.cancelEdit'), + message: this._appLocalization.get('applications.content.entryDetails.captions.discard'), + accept: () => { + this._confirmClose = false; + this.parentPopupWidget.close(); + } + } + ); + } + } + } + }); + } + } + + public _onSelectionChanged():void{ + this._selectionChanged = true; + } + + ngOnDestroy() { + this._parentPopupStateChangeSubscribe.unsubscribe(); + } + + + public _apply() { + this.downloadChanged.emit(this._selectedFlavor); + this._confirmClose = false; + this.parentPopupWidget.close(); + } +} + diff --git a/src/applications/content-entries-app/entries/bulk-actions/components/bulk-remove-categories/bulk-remove-categories.component.html b/src/applications/content-entries-app/entries/bulk-actions/components/bulk-remove-categories/bulk-remove-categories.component.html new file mode 100644 index 0000000000..407c2b5b05 --- /dev/null +++ b/src/applications/content-entries-app/entries/bulk-actions/components/bulk-remove-categories/bulk-remove-categories.component.html @@ -0,0 +1,14 @@ + +
+ {{'applications.content.bulkActions.removeFromCategories' | translate}} +
+ {{'applications.content.bulkActions.removeFromCategoriesLabel' | translate}} +
+ +
+
+
+ +
+
+
diff --git a/src/applications/content-entries-app/entries/bulk-actions/components/bulk-remove-categories/bulk-remove-categories.component.scss b/src/applications/content-entries-app/entries/bulk-actions/components/bulk-remove-categories/bulk-remove-categories.component.scss new file mode 100644 index 0000000000..cd5d43d7bd --- /dev/null +++ b/src/applications/content-entries-app/entries/bulk-actions/components/bulk-remove-categories/bulk-remove-categories.component.scss @@ -0,0 +1,45 @@ +@import "app-theme/_variables.scss"; + +.kTitle{ + color: $kGrayscale1; + font-size: 24px; + font-weight: 700; + text-align: center; + border-bottom: 1px solid $kGrayscale4; + height: 78px; + line-height: 78px; +} +.kContent{ + display: flex; + flex-direction: column; + height: 500px; + .kLabel{ + display: block; + margin-bottom: 12px; + } + .kCategory{ + margin-bottom: 12px; + } + .kCategories{ + padding: 12px; + height: 330px; + overflow-y: auto; + overflow-x: hidden; + } +} +.kFooter{ + position: absolute; + bottom: 0px; + display: flex; + width: 100%; + height: 66px; + border-top: 1px solid $kGrayscale4; + align-items: center; + justify-content: center; +} + +:host /deep/ p-checkbox .ui-chkbox-label{ + font-size: 15px; + font-weight: 400; +} + diff --git a/src/applications/content-entries-app/entries/bulk-actions/components/bulk-remove-categories/bulk-remove-categories.component.ts b/src/applications/content-entries-app/entries/bulk-actions/components/bulk-remove-categories/bulk-remove-categories.component.ts new file mode 100644 index 0000000000..9b4d4973c7 --- /dev/null +++ b/src/applications/content-entries-app/entries/bulk-actions/components/bulk-remove-categories/bulk-remove-categories.component.ts @@ -0,0 +1,117 @@ +import { Component, OnInit, OnDestroy, AfterViewInit, Input, Output, EventEmitter } from '@angular/core'; +import { ISubscription } from 'rxjs/Subscription'; + +import { KalturaClient } from '@kaltura-ng/kaltura-client'; +import { AppLocalization } from '@kaltura-ng/kaltura-common'; +import { BrowserService } from 'app-shared/kmc-shell'; +import { AreaBlockerMessage } from '@kaltura-ng/kaltura-ui'; +import { PopupWidgetComponent, PopupWidgetStates } from '@kaltura-ng/kaltura-ui/popup-widget/popup-widget.component'; +import { KalturaMediaEntry } from "kaltura-typescript-client/types/KalturaMediaEntry"; +import { BulkRemoveCategoriesService } from '../../services/'; +import { KalturaCategory } from 'kaltura-typescript-client/types/KalturaCategory'; + +@Component({ + selector: 'kBulkRemoveCategories', + templateUrl: './bulk-remove-categories.component.html', + styleUrls: ['./bulk-remove-categories.component.scss'] +}) +export class BulkRemoveCategories implements OnInit, OnDestroy, AfterViewInit { + + @Input() selectedEntries: KalturaMediaEntry[]; + @Input() parentPopupWidget: PopupWidgetComponent; + @Output() removeCategoriesChanged = new EventEmitter(); + + public _loading = false; + public _sectionBlockerMessage: AreaBlockerMessage; + + public categories: any[] = []; + private categoriesToRemove: string[] = []; + + private _parentPopupStateChangeSubscribe : ISubscription; + private _confirmClose: boolean = true; + + constructor(private _kalturaServerClient: KalturaClient, private _appLocalization: AppLocalization, private _browserService: BrowserService, private _bulkRemoveCategoriesService: BulkRemoveCategoriesService) { + } + + ngOnInit() { + let categories = []; + // load categories + this._loading = true; + this._sectionBlockerMessage = null; + this._bulkRemoveCategoriesService.getCategories(this.selectedEntries).subscribe( + (response : KalturaCategory[]) => { + this._loading = false; + this.categories = []; + response.forEach(category => { + this.categories.push({selected: false, id: category.id, label: category.fullName}); + }); + this.categories.sort(function(a, b) {return (a.label.toLowerCase() > b.label.toLowerCase()) ? 1 : ((b.label.toLowerCase() > a.label.toLowerCase()) ? -1 : 0);} ); + }, + error => { + this._loading = false; + this._sectionBlockerMessage = new AreaBlockerMessage( + { + message: error.message, + buttons: [ + { + label: this._appLocalization.get('app.common.close'), + action: () => { + this._confirmClose = false; + this.parentPopupWidget.close(); + } + } + ] + } + ); + } + ); + } + + ngAfterViewInit(){ + if (this.parentPopupWidget) { + this._parentPopupStateChangeSubscribe = this.parentPopupWidget.state$ + .subscribe(event => { + if (event.state === PopupWidgetStates.Open) { + this._confirmClose = true; + } + if (event.state === PopupWidgetStates.BeforeClose) { + if (event.context && event.context.allowClose){ + if (this.categoriesToRemove.length && this._confirmClose){ + event.context.allowClose = false; + this._browserService.confirm( + { + header: this._appLocalization.get('applications.content.entryDetails.captions.cancelEdit'), + message: this._appLocalization.get('applications.content.entryDetails.captions.discard'), + accept: () => { + this._confirmClose = false; + this.parentPopupWidget.close(); + } + } + ); + } + } + } + }); + } + } + + ngOnDestroy(){ + this._parentPopupStateChangeSubscribe.unsubscribe(); + } + + updateSelectedCategories(){ + this.categoriesToRemove = []; + this.categories.forEach(category=>{ + if (category.selected){ + this.categoriesToRemove.push(category.id); + } + }); + } + + public _apply(){ + this.removeCategoriesChanged.emit(this.categoriesToRemove); + this._confirmClose = false; + this.parentPopupWidget.close(); + } +} + diff --git a/src/applications/content-entries-app/entries/bulk-actions/components/index.ts b/src/applications/content-entries-app/entries/bulk-actions/components/index.ts index d8e5e64441..46a9a9ed6c 100644 --- a/src/applications/content-entries-app/entries/bulk-actions/components/index.ts +++ b/src/applications/content-entries-app/entries/bulk-actions/components/index.ts @@ -1,4 +1,7 @@ export { BulkScheduling } from './bulk-scheduling/bulk-scheduling.component'; +export { BulkAAccessControl } from './bulk-access-control/bulk-access-control.component'; export { BulkAddTags } from './bulk-add-tags/bulk-add-tags.component'; export { BulkRemoveTags } from './bulk-remove-tags/bulk-remove-tags.component'; export { BulkChangeOwner } from './bulk-change-owner/bulk-change-owner.component'; +export { BulkRemoveCategories } from './bulk-remove-categories/bulk-remove-categories.component'; +export { BulkDownload } from './bulk-download/bulk-download.component'; diff --git a/src/applications/content-entries-app/entries/bulk-actions/services/XInternalXAddBulkDownloadAction.ts b/src/applications/content-entries-app/entries/bulk-actions/services/XInternalXAddBulkDownloadAction.ts new file mode 100644 index 0000000000..0c20919b11 --- /dev/null +++ b/src/applications/content-entries-app/entries/bulk-actions/services/XInternalXAddBulkDownloadAction.ts @@ -0,0 +1,43 @@ +import { KalturaRequest } from 'kaltura-typescript-client'; +import { KalturaRequestArgs } from 'kaltura-typescript-client/kaltura-request'; +import { KalturaObjectMetadata } from 'kaltura-typescript-client/kaltura-object-base'; + +export interface XInternalXAddBulkDownloadActionArgs extends KalturaRequestArgs { + entryIds : string; + flavorParamsId? : string; +} + +/** +* Creates new download job for multiple entry ids (comma separated), an email will +* be sent when the job is done This sevice support the following entries: - +* MediaEntry - Video will be converted using the flavor params id - Audio will +* be downloaded as MP3 - Image will be downloaded as Jpeg - MixEntry will be +* flattened using the flavor params id - Other entry types are not supported +* Returns the admin email that the email message will be sent to +**/ +export class XInternalXAddBulkDownloadAction extends KalturaRequest { + + entryIds : string; + flavorParamsId : string; + + constructor(data : XInternalXAddBulkDownloadActionArgs) + { + super(data, {responseType : 's', responseSubType : '', responseConstructor : null }); + } + + protected _getMetadata() : KalturaObjectMetadata + { + const result = super._getMetadata(); + Object.assign( + result.properties, + { + service : { type : 'c', default : 'xinternal' }, + action : { type : 'c', default : 'xAddBulkDownload' }, + entryIds : { type : 's' }, + flavorParamsId : { type : 's' } + } + ); + return result; + } +} + diff --git a/src/applications/content-entries-app/entries/bulk-actions/services/bulk-access-control.service.ts b/src/applications/content-entries-app/entries/bulk-actions/services/bulk-access-control.service.ts new file mode 100644 index 0000000000..7c15141c37 --- /dev/null +++ b/src/applications/content-entries-app/entries/bulk-actions/services/bulk-access-control.service.ts @@ -0,0 +1,47 @@ +import { Injectable } from '@angular/core'; +import { Observable } from 'rxjs/Observable'; +import { KalturaClient } from '@kaltura-ng/kaltura-client'; + +import { KalturaMediaEntry } from 'kaltura-typescript-client/types/KalturaMediaEntry'; +import { KalturaBaseEntry } from 'kaltura-typescript-client/types/KalturaBaseEntry'; +import { BaseEntryUpdateAction } from 'kaltura-typescript-client/types/BaseEntryUpdateAction'; +import { BulkActionBaseService } from './bulk-action-base.service'; +import { KalturaAccessControl } from 'kaltura-typescript-client/types/KalturaAccessControl'; + +@Injectable() +export class BulkAccessControlService extends BulkActionBaseService { + + constructor(_kalturaServerClient: KalturaClient) { + super(_kalturaServerClient); + } + + public execute(selectedEntries: KalturaMediaEntry[], profile : KalturaAccessControl) : Observable<{}>{ + return Observable.create(observer =>{ + + let requests: BaseEntryUpdateAction[] = []; + + selectedEntries.forEach(entry => { + let updatedEntry: KalturaBaseEntry = new KalturaBaseEntry(); + updatedEntry.accessControlId = profile.id; + requests.push(new BaseEntryUpdateAction({ + entryId: entry.id, + baseEntry: updatedEntry + })); + }); + + this.transmit(requests, true).subscribe( + result => { + observer.next({}) + observer.complete(); + }, + error => { + observer.error(error); + } + ); + }); + + + + } + +} diff --git a/src/applications/content-entries-app/entries/bulk-actions/services/bulk-delete.service.ts b/src/applications/content-entries-app/entries/bulk-actions/services/bulk-delete.service.ts new file mode 100644 index 0000000000..9b9cc5f926 --- /dev/null +++ b/src/applications/content-entries-app/entries/bulk-actions/services/bulk-delete.service.ts @@ -0,0 +1,42 @@ +import { Injectable } from '@angular/core'; +import { Observable } from 'rxjs/Observable'; +import { KalturaClient } from '@kaltura-ng/kaltura-client'; + +import { KalturaMediaEntry } from 'kaltura-typescript-client/types/KalturaMediaEntry'; +import { BaseEntryDeleteAction } from 'kaltura-typescript-client/types/BaseEntryDeleteAction'; +import { BulkActionBaseService } from './bulk-action-base.service'; + +@Injectable() +export class BulkDeleteService extends BulkActionBaseService<{}> { + + constructor(_kalturaServerClient: KalturaClient) { + super(_kalturaServerClient); + } + + public execute(selectedEntries: KalturaMediaEntry[]) : Observable<{}>{ + return Observable.create(observer =>{ + + let requests: BaseEntryDeleteAction[] = []; + + selectedEntries.forEach(entry => { + requests.push(new BaseEntryDeleteAction({ + entryId: entry.id + })); + }); + + this.transmit(requests, true).subscribe( + result => { + observer.next({}) + observer.complete(); + }, + error => { + observer.error(error); + } + ); + }); + + + + } + +} diff --git a/src/applications/content-entries-app/entries/bulk-actions/services/bulk-download.service.ts b/src/applications/content-entries-app/entries/bulk-actions/services/bulk-download.service.ts new file mode 100644 index 0000000000..48aea5540c --- /dev/null +++ b/src/applications/content-entries-app/entries/bulk-actions/services/bulk-download.service.ts @@ -0,0 +1,44 @@ +import { Injectable } from '@angular/core'; +import { Observable } from 'rxjs/Observable'; +import { KalturaClient } from '@kaltura-ng/kaltura-client'; + +import { KalturaMediaEntry } from 'kaltura-typescript-client/types/KalturaMediaEntry'; +import { BulkActionBaseService } from './bulk-action-base.service'; +import { XInternalXAddBulkDownloadAction } from './XInternalXAddBulkDownloadAction'; + +@Injectable() +export class BulkDownloadService extends BulkActionBaseService { + + constructor(_kalturaServerClient: KalturaClient) { + super(_kalturaServerClient); + } + + public execute(selectedEntries: KalturaMediaEntry[], flavorId: number) : Observable<{}>{ + return Observable.create(observer =>{ + + let requests: XInternalXAddBulkDownloadAction[] = []; + let entryIds = ""; + + selectedEntries.forEach(entry => { + entryIds += entry.id +","; + }); + if (entryIds.lastIndexOf(",") === entryIds.length - 1) { + entryIds = entryIds.substr(0, entryIds.length - 1); // remove last comma + } + + this._kalturaServerClient.request(new XInternalXAddBulkDownloadAction({ + entryIds: entryIds, + flavorParamsId: flavorId.toString() + })).subscribe( + result => { + observer.next({'email': result}) + observer.complete(); + }, + error => { + observer.error(error); + } + ); + }); + } + +} diff --git a/src/applications/content-entries-app/entries/bulk-actions/services/bulk-remove-categories.service.ts b/src/applications/content-entries-app/entries/bulk-actions/services/bulk-remove-categories.service.ts new file mode 100644 index 0000000000..02ba6616ef --- /dev/null +++ b/src/applications/content-entries-app/entries/bulk-actions/services/bulk-remove-categories.service.ts @@ -0,0 +1,133 @@ +import { Injectable } from '@angular/core'; +import { Observable } from 'rxjs/Observable'; +import { KalturaClient } from '@kaltura-ng/kaltura-client'; + +import { KalturaMediaEntry } from 'kaltura-typescript-client/types/KalturaMediaEntry'; +import { KalturaCategoryEntry } from 'kaltura-typescript-client/types/KalturaCategoryEntry'; +import { BulkActionBaseService } from './bulk-action-base.service'; +import { CategoryEntryAddAction } from "kaltura-typescript-client/types/CategoryEntryAddAction"; +import { CategoryEntryListAction } from 'kaltura-typescript-client/types/CategoryEntryListAction'; + +import { KalturaCategoryEntryFilter } from 'kaltura-typescript-client/types/KalturaCategoryEntryFilter'; +import { KalturaFilterPager } from 'kaltura-typescript-client/types/KalturaFilterPager'; +import { CategoryListAction } from 'kaltura-typescript-client/types/CategoryListAction'; +import { KalturaCategoryFilter } from 'kaltura-typescript-client/types/KalturaCategoryFilter'; +import { KalturaCategory } from 'kaltura-typescript-client/types/KalturaCategory'; +import { CategoryEntryDeleteAction } from 'kaltura-typescript-client/types/CategoryEntryDeleteAction'; + +export interface EntryCategoryItem { + id: number, + fullIdPath: number[], + name: string, + fullNamePath: string[] +} + +@Injectable() +export class BulkRemoveCategoriesService extends BulkActionBaseService { + + private entryCategories: KalturaCategoryEntry[] = []; + + constructor(_kalturaServerClient: KalturaClient) { + super(_kalturaServerClient); + } + + public getCategories(selectedEntries: KalturaMediaEntry[]): Observable { + return Observable.create(observer => { + // load all category entries + const filter: KalturaCategoryEntryFilter = new KalturaCategoryEntryFilter(); + let entriesIds = ""; + selectedEntries.forEach((entry, index) => { + entriesIds += entry.id; + if (index < selectedEntries.length - 1) { + entriesIds += ","; + } + }); + filter.entryIdIn = entriesIds; + + const pager: KalturaFilterPager = new KalturaFilterPager(); + pager.pageIndex = 1; + pager.pageSize = 1000; + + this._kalturaServerClient.request(new CategoryEntryListAction({ + filter: filter, + pager: pager + })).subscribe( + response => { + // got all entry categories - load category details for each entry category + this.entryCategories = response.objects; + let categoriesIds = ""; + this.entryCategories.forEach(category => { + if (categoriesIds.indexOf(category.categoryId.toString()) === -1) { + categoriesIds += category.categoryId + ","; + } + }); + if (categoriesIds.lastIndexOf(",") === categoriesIds.length - 1) { + categoriesIds = categoriesIds.substr(0, categoriesIds.length - 1); // remove last comma + } + const categoriesFilter: KalturaCategoryFilter = new KalturaCategoryFilter(); + categoriesFilter.idIn = categoriesIds; + this._kalturaServerClient.request(new CategoryListAction({ + filter: categoriesFilter, + pager: pager + })).subscribe( + response => { + observer.next(response.objects); + observer.complete(); + }, + error => { + observer.error(error); + } + ); + + }, + error => { + observer.error(error); + } + ); + + }); + + } + + public execute(selectedEntries: KalturaMediaEntry[], categories: number[]): Observable<{}> { + return Observable.create(observer => { + + let requests: CategoryEntryDeleteAction[] = []; + + // send only categories that are set to each entry + selectedEntries.forEach(entry => { + categories.forEach(category => { + if (typeof this.entryCategories.find( (entryCategory: KalturaCategoryEntry) => {return entryCategory.entryId === entry.id && entryCategory.categoryId === category;} ) !== "undefined"){ + requests.push(new CategoryEntryDeleteAction({ + entryId: entry.id, + categoryId: category + })); + } + }); + }); + + this.transmit(requests, true).subscribe( + result => { + observer.next({}) + observer.complete(); + }, + error => { + observer.error(error); + } + ); + + }); + } + + private categoryEntryExists(entry: KalturaMediaEntry, category: EntryCategoryItem, entryCategories: KalturaCategoryEntry[]): boolean { + let found = false; + for (let i = 0; i < entryCategories.length; i++) { + if (entryCategories[i].categoryId === category.id && entryCategories[i].entryId === entry.id) { + found = true; + break; + } + } + return found; + } + +} diff --git a/src/applications/content-entries-app/entries/bulk-actions/services/index.ts b/src/applications/content-entries-app/entries/bulk-actions/services/index.ts index fba0ce5111..e4fcc6cd04 100644 --- a/src/applications/content-entries-app/entries/bulk-actions/services/index.ts +++ b/src/applications/content-entries-app/entries/bulk-actions/services/index.ts @@ -1,5 +1,9 @@ export { BulkSchedulingService, SchedulingParams } from './bulk-scheduling.service'; +export { BulkAccessControlService } from './bulk-access-control.service'; export { BulkAddTagsService } from './bulk-add-tag.service'; export { BulkRemoveTagsService } from './bulk-remove-tag.service'; export { BulkAddCategoriesService, EntryCategoryItem } from './bulk-add-categories.service'; export { BulkChangeOwnerService } from './bulk-change-owner.service'; +export { BulkRemoveCategoriesService } from './bulk-remove-categories.service'; +export { BulkDeleteService } from './bulk-delete.service'; +export { BulkDownloadService } from './bulk-download.service'; \ No newline at end of file diff --git a/src/applications/content-entries-app/entries/entries-components-list.ts b/src/applications/content-entries-app/entries/entries-components-list.ts index 192cb0c610..0cdf539e64 100644 --- a/src/applications/content-entries-app/entries/entries-components-list.ts +++ b/src/applications/content-entries-app/entries/entries-components-list.ts @@ -3,7 +3,7 @@ import { EntriesListComponent } from "./entries-list.component"; import { CategoriesFilterComponent } from './categories-filter/categories-filter.component'; import { CategoriesFilterPrefsComponent } from './categories-filter-preferences/categories-filter-preferences.component'; import { BulkActionsComponent } from './bulk-actions/bulk-actions.component'; -import { BulkScheduling, BulkAddTags, BulkRemoveTags, BulkChangeOwner } from './bulk-actions/components'; +import { BulkScheduling, BulkAddTags, BulkRemoveTags, BulkChangeOwner, BulkRemoveCategories, BulkDownload, BulkAAccessControl } from './bulk-actions/components'; import { MaxEntriesPipe } from './pipes/max-entries.pipe'; import { EntryDurationPipe } from './pipes/entry-duration.pipe'; @@ -17,9 +17,12 @@ export const EntriesComponentsList = [ CategoriesFilterPrefsComponent, BulkActionsComponent, BulkScheduling, + BulkAAccessControl, BulkAddTags, BulkRemoveTags, BulkChangeOwner, + BulkRemoveCategories, + BulkDownload, EntriesRefineFilters, MaxEntriesPipe, EntryDurationPipe, diff --git a/src/applications/content-entries-app/entries/entries-list.component.ts b/src/applications/content-entries-app/entries/entries-list.component.ts index 38174a108d..f185d267c1 100644 --- a/src/applications/content-entries-app/entries/entries-list.component.ts +++ b/src/applications/content-entries-app/entries/entries-list.component.ts @@ -210,8 +210,8 @@ export class EntriesListComponent implements OnInit, OnDestroy { this._reload(); }else{ // this.clearSelection(); - this._msgs = []; - this._msgs.push({severity: 'success', summary: '', detail: this.appLocalization.get('applications.content.bulkActions.updated')}); + // this._msgs = []; + // this._msgs.push({severity: 'success', summary: '', detail: this.appLocalization.get('applications.content.bulkActions.updated')}); } } diff --git a/src/applications/content-entries-app/entries/entries-store/entries-store.service.ts b/src/applications/content-entries-app/entries/entries-store/entries-store.service.ts index 83a7b849d2..46802f69ab 100644 --- a/src/applications/content-entries-app/entries/entries-store/entries-store.service.ts +++ b/src/applications/content-entries-app/entries/entries-store/entries-store.service.ts @@ -90,7 +90,7 @@ export type FilterTypeConstructor = {new(...args : any[]) pageSize: 50, sortBy: 'createdAt', sortDirection: SortDirection.Desc, - fields: 'id,name,thumbnailUrl,mediaType,plays,createdAt,duration,status,startDate,endDate,moderationStatus,tags,categoriesIds' + fields: 'id,name,thumbnailUrl,mediaType,plays,createdAt,duration,status,startDate,endDate,moderationStatus,tags,categoriesIds,downloadUrl' }; private _querySource = new Subject(); private _destoryed: boolean = false; diff --git a/src/i18n/en.json b/src/i18n/en.json index 4b65ab87e2..98ae570a18 100644 --- a/src/i18n/en.json +++ b/src/i18n/en.json @@ -38,7 +38,9 @@ "ok": "OK", "cancel": "Cancel", "retry": "Retry", - "confirm": "Confirm" + "confirm": "Confirm", + "close": "Close", + "note": "Note:" } }, "applications": { @@ -176,18 +178,30 @@ "addRemoveCategories": "Add / Remove Categories", "addToCategories": "Add To Categories", "removeFromCategories": "Remove From Categories", + "removeFromCategoriesLabel": "Remove selected entries from these categories", "addToNewCategoryPlaylist": "Add To New Category / Playlist", "addToNewCategory": "Add To New Category", "addToNewPlaylist": "Add To New Playlist", "changeOwner": "Change Owner", "changeOwnerLabel": "Set a new owner for the selected entries", "download": "Download", + "downloadEntries": "Download selected entries", + "download1Label": "You have selected 1 entry for download.", + "downloadManyLabel": "You have selected {{0}} entries for download.", + "downloadFlavor": "If you have selected to download a video, please choose the required format:", + "downloadAudio": "Audio entries will be delivered in FLV format.", + "downloadImage": "Images will be delivered in their original format.", + "downloadNote": "Downloading other types of entries is not supported and will be ignored.", + "downloadMsg": "Your download request is being processed. A download link will be sent to {{0}} once processing is completed.", "delete": "Delete", "apply": "Apply to all selected entries", "error": "An error occurred during entries update.", "updated": "Entries updated successfully", "note": "Update Note", - "confirm": "Are you sure you want to update {{0}} entries? It could take a while..." + "confirm": "Are you sure you want to update {{0}} entries? It could take a while...", + "deleteEntries": "Delete Entries", + "deleteConfirm": "Are you sure you want to delete the selected entries?", + "deleteNote": "Please note: the selected entries will be permanently deleted from your account." }, "entryDetails": { "sections": { diff --git a/src/shared/kmc-shell/providers/browser.service.ts b/src/shared/kmc-shell/providers/browser.service.ts index 93dbad2244..a734e55c78 100644 --- a/src/shared/kmc-shell/providers/browser.service.ts +++ b/src/shared/kmc-shell/providers/browser.service.ts @@ -72,6 +72,12 @@ export class BrowserService implements IAppStorage { } public confirm(confirmation : Confirmation) { + confirmation.key = "confirm"; + this._onConfirmationFn(confirmation); + } + + public alert(confirmation : Confirmation) { + confirmation.key = "alert"; this._onConfirmationFn(confirmation); }