import { IAttachment , IElasticRangeQueryParams , IRestApiResponse , IRootElasticQuery , } from 'superdesk-api' ; import { ASSET_LIST_STYLE , ASSET_SORT_FIELD , ASSET_STATE , ASSET_TYPE_FILTER , IAssetItem , IAssetSearchParams , SORT_ORDER , IUploadAssetModalProps , ISetItem , SET_STATE , IAutoTaggingSearchResult , } from '../interfaces' ; import { superdeskApi } from '../apis' ; import { getStoreSync } from '../store' ; import { loadSets } from '../store/sets/actions' ; import { getSetsById , getAvailableSetsForDesk } from '../store/sets/selectors' ; import { fixItemResponseVersionDates , fixItemVersionDates } from './common' ; import { getApiErrorMessage , isSamsApiError } from '../utils/api' ; import { showModalConnectedToStore } from '../utils/ui' ; import { UploadAssetModal } from '../components/assets/uploadAssetModal' ; const RESOURCE = 'sams/assets' ; const COUNT_RESOURCE = `${ RESOURCE }/counts/` ; const BINARY_RESOURCE = `${ RESOURCE }/binary/` ; const COMPRESSED_BINARY_RESOURCE = `${ RESOURCE }/compressed_binary/` ; const LOCK_ASSET = `${ RESOURCE }/lock` ; const UNLOCK_ASSET = `${ RESOURCE }/unlock` ; export function uploadAsset ( data , onProgress ) { const { gettext } = superdeskApi . localization ; const { notify } = superdeskApi . ui ; return superdeskApi . dataApi . uploadFileWithProgress < IAssetItem > ( '/' + RESOURCE , data , onProgress ) . catch ( ( error ) => { if ( isSamsApiError ( error ) ) { notify . error ( getApiErrorMessage ( error ) ) ; } else { notify . error ( gettext ( 'Failed to upload file.' ) ) ; } return Promise . reject ( error ) ; } ) ; } const GRID_PAGE_SIZE = 25 ; const LIST_PAGE_SIZE = 50 ; function querySearchString ( source , params ) { if ( params . textSearch != null && params . textSearch . length > 0 ) { source . query . bool . must . push ( superdeskApi . elasticsearch . queryString ( { query : params . textSearch , lenient : true , default_operator : 'AND' , } ) ) ; } } function querySetId ( source , params ) { if ( params . setId != null && params . setId . length > 0 ) { source . query . bool . must . push ( superdeskApi . elasticsearch . term ( { field : 'set_id' , value : params . setId , } ) ) ; } } function querySetIds ( source , params ) { if ( params . setIds != null && params . setIds . length > 0 ) { source . query . bool . must . push ( superdeskApi . elasticsearch . terms ( { field : 'set_id' , value : params . setIds , } ) ) ; } } function queryAllAvailableSets ( source , params ) { if ( ! params . setId ?. length && ! params . setIds ?. length ) { const store = getStoreSync ( ) ; const setIds = getAvailableSetsForDesk ( store . getState ( ) ) ; source . query . bool . must . push ( superdeskApi . elasticsearch . terms ( { field : 'set_id' , value : setIds , } ) ) ; } } function queryExcludedAssetIds ( source , params ) { if ( params . excludedAssetIds != null && params . excludedAssetIds . length > 0 ) { source . query . bool . must_not . push ( superdeskApi . elasticsearch . terms ( { field : '_id' , value : params . excludedAssetIds , } ) ) ; } } function queryState ( source , params ) { if ( params . state != null && params . state . length > 0 ) { source . query . bool . must . push ( superdeskApi . elasticsearch . term ( { field : 'state' , value : params . state , } ) ) ; } } function queryStates ( source , params ) { if ( params . states != null && params . states . length > 0 ) { source . query . bool . must . push ( superdeskApi . elasticsearch . terms ( { field : 'state' , value : params . states , } ) ) ; } } function queryName ( source , params ) { if ( params . name != null && params . name . length > 0 ) { source . query . bool . must . push ( superdeskApi . elasticsearch . queryString ( { query : `name:(${ params . name })` , lenient : true , default_operator : 'AND' , } ) ) ; } } function queryFilename ( source , params ) { if ( params . filename != null && params . filename . length > 0 ) { source . query . bool . must . push ( superdeskApi . elasticsearch . queryString ( { query : `filename:(${ params . filename })` , lenient : true , default_operator : 'AND' , } ) ) ; } } function queryDescription ( source , params ) { if ( params . description != null && params . description . length > 0 ) { source . query . bool . must . push ( superdeskApi . elasticsearch . queryString ( { query : `description:(${ params . description })` , lenient : false , default_operator : 'AND' , } ) ) ; } } function queryTags ( source , params ) { if ( params . tags != null && params . tags . length > 0 ) { let taglist = [ ] ; params . tags . forEach ( ( tag ) => { taglist . push ( tag . code ) ; } ) ; source . query . bool . must . push ( superdeskApi . elasticsearch . terms ( { field : 'tags.code' , value : taglist , } ) ) ; } } function queryMimetypes ( source , params ) { if ( params . mimetypes === ASSET_TYPE_FILTER . DOCUMENTS ) { source . query . bool . must_not . push ( superdeskApi . elasticsearch . queryString ( { query : 'mimetype:(image\\/*) OR mimetype:(video\\/*) OR mimetype:(audio\\/*)' , lenient : true , default_operator : 'OR' , } ) ) ; } else if ( params . mimetypes !== ASSET_TYPE_FILTER . ALL ) { let typeString ; switch ( params . mimetypes ) { case ASSET_TYPE_FILTER . IMAGES : typeString = 'image' ; break ; case ASSET_TYPE_FILTER . VIDEOS : typeString = 'video' ; break ; case ASSET_TYPE_FILTER . AUDIO : typeString = 'audio' ; break ; } if ( typeString != null ) { source . query . bool . must . push ( superdeskApi . elasticsearch . queryString ( { query : `mimetype:(${ typeString }\\/*)` , lenient : true , default_operator : 'OR' , } ) ) ; } } } function queryDateRange ( source , params ) { if ( params . dateFrom != null || params . dateTo != null ) { const args = { field : '_updated' } ; if ( params . dateFrom != null ) { args . gte = params . dateFrom . toISOString ( ) ; } if ( params . dateTo != null ) { args . lte = params . dateTo . toISOString ( ) ; } source . query . bool . must . push ( superdeskApi . elasticsearch . range ( args ) ) ; } } function querySizeRange ( source , params ) { if ( params . sizeFrom != null || params . sizeTo != null ) { const args = { field : 'length' } ; if ( params . sizeFrom != null ) { args . gte = params . sizeFrom * 1048576 ; } if ( params . sizeTo != null ) { args . lte = params . sizeTo * 1048576 ; } source . query . bool . must . push ( superdeskApi . elasticsearch . range ( args ) ) ; } } export function queryAssets ( params , listStyle ) { const { gettext } = superdeskApi . localization ; const { notify } = superdeskApi . ui ; const pageSize = listStyle === ASSET_LIST_STYLE . GRID ? GRID_PAGE_SIZE : LIST_PAGE_SIZE ; const source = { query : { bool : { must : [ ] , must_not : [ ] , } , } , size : pageSize , from : ( params . page - 1 ) * pageSize , } ; [ querySearchString , querySetId , querySetIds , queryAllAvailableSets , queryExcludedAssetIds , queryName , queryDescription , queryTags , queryFilename , queryMimetypes , queryState , queryStates , queryDateRange , querySizeRange , ] . forEach ( ( func ) => func ( source , params ) ) ; if ( source . query . bool . must . length === 0 ) { delete source . query . bool . must ; } if ( source . query . bool . must_not . length === 0 ) { delete source . query . bool . must_not ; } if ( Object . keys ( source . query . bool ) . length === 0 ) { delete source . query ; } const sortOrder = params . sortOrder === SORT_ORDER . ASCENDING ? 1 : 0 ; const sort = `[("${ params . sortField }",${ sortOrder })]` ; return superdeskApi . dataApi . queryRawJson < IRestApiResponse < IAssetItem > > ( RESOURCE , { source : JSON . stringify ( source ) , sort : sort , } ) . then ( fixItemResponseVersionDates ) . catch ( ( error ) => { if ( isSamsApiError ( error ) ) { notify . error ( getApiErrorMessage ( error ) ) ; } else { notify . error ( gettext ( 'Failed to query Assets' ) ) ; } return Promise . reject ( error ) ; } ) ; } export function getAssetSearchUrlParams ( ) { const { urlParams } = superdeskApi . browser . location ; const { filterUndefined } = superdeskApi . helpers ; return filterUndefined < IAssetSearchParams > ( { textSearch : urlParams . getString ( 'textSearch' ) , setId : urlParams . getString ( 'setId' ) , name : urlParams . getString ( 'name' ) , description : urlParams . getString ( 'description' ) , tags : urlParams . getStringArray ( 'tags' ) ?. map ( ( tag ) => ( { 'code' : tag , 'name' : tag } ) ) , state : urlParams . getString ( 'state' ) as ASSET_STATE , filename : urlParams . getString ( 'filename' ) , mimetypes : urlParams . getString ( 'mimetypes' , ASSET_TYPE_FILTER . ALL ) as ASSET_TYPE_FILTER , dateFrom : urlParams . getDate ( 'dateFrom' ) , dateTo : urlParams . getDate ( 'dateTo' ) , sizeFrom : urlParams . getNumber ( 'sizeFrom' ) , sizeTo : urlParams . getNumber ( 'sizeTo' ) , sortField : urlParams . getString ( 'sortField' , ASSET_SORT_FIELD . NAME ) as ASSET_SORT_FIELD , sortOrder : urlParams . getString ( 'sortOrder' , SORT_ORDER . ASCENDING ) as SORT_ORDER , } ) ; } export function setAssetSearchUrlParams ( params ) { const { urlParams } = superdeskApi . browser . location ; urlParams . setString ( 'textSearch' , params . textSearch ) ; urlParams . setString ( 'setId' , params . setId ) ; urlParams . setString ( 'name' , params . name ) ; urlParams . setString ( 'description' , params . description ) ; urlParams . setStringArray ( 'tags' , ( params . tags ?? [ ] ) . map ( ( tag ) => ( tag . code ) ) ) ; urlParams . setString ( 'state' , params . state ) ; urlParams . setString ( 'filename' , params . filename ) ; urlParams . setString ( 'mimetypes' , params . mimetypes ) ; urlParams . setDate ( 'dateFrom' , params . dateFrom ) ; urlParams . setDate ( 'dateTo' , params . dateTo ) ; urlParams . setNumber ( 'sizeFrom' , params . sizeFrom ) ; urlParams . setNumber ( 'sizeTo' , params . sizeTo ) ; urlParams . setString ( 'sortField' , params . sortField ) ; urlParams . setString ( 'sortOrder' , params . sortOrder ) ; } export function getAssetsCount ( set_ids ) { const { gettext } = superdeskApi . localization ; const { notify } = superdeskApi . ui ; return superdeskApi . dataApi . queryRawJson < Dictionary < string , number > > ( COUNT_RESOURCE + JSON . stringify ( set_ids ) ) . catch ( ( error ) => { if ( isSamsApiError ( error ) ) { notify . error ( getApiErrorMessage ( error ) ) ; } else { notify . error ( gettext ( 'Failed to get assets counts for sets' ) ) ; } return Promise . reject ( error ) ; } ) ; } export function getAssetById ( assetId ) { const { gettext } = superdeskApi . localization ; const { notify } = superdeskApi . ui ; return superdeskApi . dataApi . findOne < IAssetItem > ( RESOURCE , assetId ) . then ( fixItemVersionDates ) . catch ( ( error ) => { if ( isSamsApiError ( error ) ) { notify . error ( getApiErrorMessage ( error ) ) ; } else { notify . error ( gettext ( `Failed to get asset "${ assetId }"` ) ) ; } return Promise . reject ( error ) ; } ) ; } export function getAssetsByIds ( ids ) { const { gettext } = superdeskApi . localization ; const { notify } = superdeskApi . ui ; return superdeskApi . dataApi . queryRawJson < IRestApiResponse < IAssetItem > > ( RESOURCE , { source : JSON . stringify ( { query : { bool : { must : [ superdeskApi . elasticsearch . terms ( { field : '_id' , value : ids , } ) , ] , } , } , } ) } ) . then ( fixItemResponseVersionDates ) . catch ( ( error ) => { if ( isSamsApiError ( error ) ) { notify . error ( getApiErrorMessage ( error ) ) ; } else { notify . error ( gettext ( 'Failed to get Assets' ) ) ; } return Promise . reject ( error ) ; } ) ; } export function updateAssetMetadata ( originalAsset , originalAttachment , updates ) { const { gettext } = superdeskApi . localization ; const { notify } = superdeskApi . ui ; return Promise . all ( [ superdeskApi . entities . attachment . save ( originalAttachment , { ... originalAttachment , title : updates . name , description : updates . description , internal : updates . state !== ASSET_STATE . PUBLIC , } ) , superdeskApi . dataApi . patch < IAssetItem > ( RESOURCE , originalAsset , updates ) . catch ( ( error ) => { if ( isSamsApiError ( error ) ) { notify . error ( getApiErrorMessage ( error ) ) ; } else { notify . error ( gettext ( 'Failed to update asset.' ) ) ; } return Promise . reject ( error ) ; } ) , ] ) ; } export function showUploadAssetModal ( props ? ) { const { gettext } = superdeskApi . localization ; const { notify } = superdeskApi . ui ; const store = getStoreSync ( ) ; store . dispatch < any > ( loadSets ( ) ) . then ( ( sets ) => { if ( sets . filter ( ( set ) => set . state === SET_STATE . USABLE ) . length === 0 ) { notify . error ( gettext ( 'No usable Sets found. Enable one first' ) ) ; return ; } showModalConnectedToStore < Partial < IUploadAssetModalProps > > ( UploadAssetModal , { modalSize : 'fill' , ... props ?? { } , } ) ; } ) ; } export function getAssetDownloadUrl ( assetId ) { const { server } = superdeskApi . instance . config ; return `${ server . url }/${ BINARY_RESOURCE }/${ assetId }` ; } export function getAssetBinary ( asset ) { const { gettext } = superdeskApi . localization ; const { notify } = superdeskApi . ui ; const { downloadBlob } = superdeskApi . utilities ; return superdeskApi . dataApi . queryRaw < void | Response > ( BINARY_RESOURCE + asset . _id ) . then ( ( res ) => res . arrayBuffer ( ) . then ( ( blob ) => { downloadBlob ( blob , res . headers . get ( 'Content-type' ) ! , asset . filename ) ; } ) ) . catch ( ( error ) => { if ( isSamsApiError ( error ) ) { notify . error ( getApiErrorMessage ( error ) ) ; } else { notify . error ( gettext ( 'Failed to get binary for asset' ) ) ; } return Promise . reject ( error ) ; } ) ; } export function getAssetsCompressedBinary ( asset_ids ) { const { gettext } = superdeskApi . localization ; const { notify } = superdeskApi . ui ; const { downloadBlob } = superdeskApi . utilities ; return superdeskApi . dataApi . queryRaw < void | Response > ( COMPRESSED_BINARY_RESOURCE + JSON . stringify ( asset_ids ) ) . then ( ( res ) => res . arrayBuffer ( ) . then ( ( blob ) => { downloadBlob ( blob , 'application/zip' , 'download' ) ; } ) ) . catch ( ( error ) => { if ( isSamsApiError ( error ) ) { notify . error ( getApiErrorMessage ( error ) ) ; } else { notify . error ( gettext ( 'Failed to get compressed binaries for assets' ) ) ; } return Promise . reject ( error ) ; } ) ; } export function deleteAsset ( item ) { const { gettext } = superdeskApi . localization ; const { notify } = superdeskApi . ui ; return superdeskApi . dataApi . delete < IAssetItem > ( RESOURCE , item ) . then ( ( ) => { notify . success ( gettext ( 'Asset deleted successfully' ) ) ; return Promise . resolve ( ) ; } ) . catch ( ( error ) => { if ( isSamsApiError ( error ) ) { notify . error ( getApiErrorMessage ( error ) ) ; } else if ( error . _message != null ) { notify . error ( gettext ( 'Error: {{message}}' , { message : error . _message } ) ) ; } else { notify . error ( gettext ( 'Failed to delete the Asset' ) ) ; } return Promise . reject ( error ) ; } ) ; } export function updateAsset ( original , updates ) { const { gettext } = superdeskApi . localization ; const { notify } = superdeskApi . ui ; return superdeskApi . dataApi . patch < IAssetItem > ( RESOURCE , original , updates ) . then ( ( asset ) => { notify . success ( gettext ( 'Asset updated successfully' ) ) ; return asset ; } ) . catch ( ( error ) => { if ( isSamsApiError ( error ) ) { notify . error ( getApiErrorMessage ( error ) ) ; } else { notify . error ( gettext ( 'Failed to update the Asset' ) ) ; } return Promise . reject ( error ) ; } ) ; } export function lockAsset ( original , updates ) { const { gettext } = superdeskApi . localization ; const { notify } = superdeskApi . ui ; return superdeskApi . dataApi . patch < IAssetItem > ( LOCK_ASSET , original , updates ) . then ( ( asset ) => { return asset ; } ) . catch ( ( error ) => { if ( isSamsApiError ( error ) ) { notify . error ( getApiErrorMessage ( error ) ) ; } else { notify . error ( gettext ( 'Failed to lock the Asset' ) ) ; } return Promise . reject ( error ) ; } ) ; } export function unlockAsset ( original , updates ) { const { gettext } = superdeskApi . localization ; const { notify } = superdeskApi . ui ; return superdeskApi . dataApi . patch < IAssetItem > ( UNLOCK_ASSET , original , updates ) . then ( ( asset ) => { return asset ; } ) . catch ( ( error ) => { if ( isSamsApiError ( error ) ) { notify . error ( getApiErrorMessage ( error ) ) ; } else { notify . error ( gettext ( 'Failed to unlock the Asset' ) ) ; } return Promise . reject ( error ) ; } ) ; } export function getSetsSync ( ) { const store = getStoreSync ( ) ; return getSetsById ( store . getState ( ) ) ; } export function searchTags ( searchString ) { const { gettext } = superdeskApi . localization ; const { notify } = superdeskApi . ui ; return superdeskApi . dataApi . queryRawJson < IAutoTaggingSearchResult > ( 'sams/assets/tags' , { 'query' : searchString } ) . then ( ( res ) => { return res ; } ) . catch ( ( error ) => { if ( isSamsApiError ( error ) ) { notify . error ( getApiErrorMessage ( error ) ) ; } else { notify . error ( gettext ( 'Failed to get tags' ) ) ; } return Promise . reject ( error ) ; } ) ; }