kahuna/public/js/services/api/collections-api.js (146 lines of code) (raw):

import angular from 'angular'; import {mediaApi} from './media-api'; import {imageAccessor} from '../image-accessor'; import {async} from '../../util/async'; export var collectionsApi = angular.module('kahuna.services.api.collections', [ mediaApi.name, imageAccessor.name, async.name ]); collectionsApi.factory('collections', ['$rootScope', '$q', 'mediaApi', 'imageAccessor', 'apiPoll', function ($rootScope, $q, mediaApi, imageAccessor, apiPoll) { const collectionsRoot = mediaApi.root.follow('collections'); // TODO: Rx? let collections; function getCollections() { // TODO: do we want to memoize? what if we want to reload? if (! collections) { collections = collectionsRoot.follow('collections').get(); } return collections; } function removeCollection(collection) { return collection.perform('delete'); } function addCollection(newCollectionPath) { return collectionsRoot.post({data: newCollectionPath}); } function addChildTo(node, childName) { return node.perform('add-child', {body: {data: childName}}).then(childResource => { const updatedChildren = [childResource].concat(node.data.children).sort((a, b) => { if (a.data.basename.toLowerCase() < b.data.basename.toLowerCase()) { return -1; } if (a.data.basename.toLowerCase() > b.data.basename.toLowerCase()) { return 1; } return 0; }); node.data.children = updatedChildren; return updatedChildren; }); } function isDeletable(node) { return node.getAction('remove').then(angular.isDefined); } function removeFromList(child, list) { return child.perform('remove').then(() => { // Mutating the array p_q const i = list.indexOf(child); list.splice(i, 1); }); } /* * @param Array<string> imageIds * @param Array<string> collectionPath */ function addToCollectionUsingImageIds(imageIds, path) { // TODO: This isn't the most efficient way of doing this, but because we get the image data // from the drop data, this was the easiest way to do it without turning the JSON string // into a Resource object. const promises = imageIds.map(id => mediaApi.find(id) .then(image => addCollectionToImage(image, path)) ); return $q.all(promises); } function addToCollectionUsingImageResources(images, path) { const promises = images.map(image => addCollectionToImage(image, path) ).toJS(); return $q.all(promises); } function addCollectionToImage(image, path) { return image.perform('add-collection', {body: {data: path}}) .then(collectionAdded => apiPoll(() => untilNewCollectionAppears(image, collectionAdded) )) .then(newImage => { $rootScope.$emit('images-updated', [newImage]); }); } function untilNewCollectionAppears(image, collectionAdded) { return image.get().then( (apiImage) => { const apiCollections = imageAccessor.getCollectionsIds(apiImage); if (collectionAdded.data && apiCollections.indexOf(collectionAdded.data.pathId) > -1) { return apiImage; } else { return $q.reject(); } }); } function collectionsEquals(collectionsA, collectionsB) { return angular.equals( collectionsA.sort(), collectionsB.sort() ); } function getCollectionsIdsFromCollection(imageCollections) { return imageCollections.data.map(col => col.pathId); } function untilCollectionsEqual(image, expectedCollections) { return image.get().then(apiImage => { const apiCollections = imageAccessor.getCollectionsIds(apiImage); if (collectionsEquals(apiCollections, expectedCollections)) { return apiImage; } else { return $q.reject(); } }); } function removeImageFromCollection(collection, image) { return collection.perform('remove') .then(newImageCollections => apiPoll(() => untilCollectionsEqual(image, getCollectionsIdsFromCollection(newImageCollections)) )) .then(newImage => { $rootScope.$emit('images-updated', [newImage]); return newImage; }); } function filterCollectionResource(image, collectionToMatch){ return image.data.collections.filter(collection => { return collection.data && collection.data.pathId === collectionToMatch; }); } function getCollectionToRemove(image, collection) { const filteredCollections = filterCollectionResource(image, collection); if (filteredCollections.length > 0){ return filteredCollections[0]; } } function batchRemove(images, collection) { const promises = images.map(image => { const collectionToRemove = getCollectionToRemove(image, collection); if (collectionToRemove) { return removeImageFromCollection(collectionToRemove, image); } else { //if image doesn't have the chosen collection it returns the image return image; } }).toJS(); return $q.all(promises); } return { getCollections, removeCollection, addCollection, addChildTo, isDeletable, removeFromList, addToCollectionUsingImageIds, addToCollectionUsingImageResources, addCollectionToImage, removeImageFromCollection, batchRemove }; }]);