<commit_before>/**
 * @ngdoc service
 * @name fstepApp.BasketService
 * @description
 * # BasketService
 * Service in the fstepApp.
 */
'use strict';

define(['../fstepmodules', 'traversonHal'], function(fstepmodules, TraversonJsonHalAdapter) {

    fstepmodules.service('BasketService', ['$rootScope', '$http', 'fstepProperties', '$q', '$timeout', 'MessageService', 'UserService', 'TabService', 'CommunityService', 'FileService', 'traverson', function($rootScope, $http, fstepProperties, $q, $timeout, MessageService, UserService, TabService, CommunityService, FileService, traverson) {

        var self = this;

        traverson.registerMediaType(TraversonJsonHalAdapter.mediaType, TraversonJsonHalAdapter);
        var rootUri = fstepProperties.URLv2;
        var halAPI = traverson.from(rootUri).jsonHal().useAngularHttp();
        var deleteAPI = traverson.from(rootUri).useAngularHttp();

        /** PRESERVE USER SELECTIONS **/
        this.dbOwnershipFilters = {
            ALL_BASKETS: {id: 0, name: 'All', searchUrl: 'search/findByFilterOnly'},
            MY_BASKETS: {id: 1, name: 'Mine', searchUrl: 'search/findByFilterAndOwner'},
            SHARED_BASKETS: {id: 2, name: 'Shared', searchUrl: 'search/findByFilterAndNotOwner'}
        };

        this.params = {
            explorer: {
                pollingUrl: rootUri + '/databaskets/?sort=name',
                pagingData: {},
                databaskets: undefined,
                items: undefined,
                selectBasketList: undefined,
                selectedDatabasket: undefined,
                selectedItems: [],
                searchText: '',
                displayFilters: false,
                databasketOnMap: {id: undefined},
                selectedOwnershipFilter: self.dbOwnershipFilters.ALL_BASKETS
            },
            community: {
                pollingUrl: rootUri + '/databaskets/?sort=name',
                pagingData: {},
                databaskets: undefined,
                items: undefined,
                selectedDatabasket: undefined,
                selectedItems: undefined,
                searchText: '',
                displayFilters: false,
                itemSearchText: '',
                itemDisplayFilters: false,
                sharedGroups: undefined,
                sharedGroupsSearchText: '',
                sharedGroupsDisplayFilters: false,
                selectedOwnershipFilter: self.dbOwnershipFilters.ALL_BASKETS
            }
        };

        /** END OF PRESERVE USER SELECTIONS **/

        var POLLING_FREQUENCY = 20 * 1000;
        var pollCount = 3;
        var startPolling = true;
        var pollingTimer;

        var pollDatabaskets = function(page) {
            pollingTimer = $timeout(function() {
                halAPI.from(self.params[page].pollingUrl)
                    .newRequest()
                    .getResource()
                    .result
                    .then(function(document) {
                        self.params[page].pagingData._links = document._links;
                        self.params[page].pagingData.page = document.page;

                        $rootScope.$broadcast('poll.baskets', document._embedded.databaskets);
                        pollDatabaskets(page);
                    }, function(error) {
                        error.retriesLeft = pollCount;
                        MessageService.addError('Could not poll Databaskets', error);
                        if (pollCount > 0) {
                            pollCount -= 1;
                            pollDatabaskets(page);
                        }
                    });
            }, POLLING_FREQUENCY);
        };

        this.stopPolling = function() {
            if (pollingTimer) {
                $timeout.cancel(pollingTimer);
            }
            startPolling = true;
        };

        var getDatabaskets = function(page) {
            var deferred = $q.defer();
            halAPI.from(self.params[page].pollingUrl)
                .newRequest()
                .getResource()
                .result
                .then(function(document) {
                    if (startPolling) {
                        pollDatabaskets(page);
                        startPolling = false;
                    }
                    self.params[page].pagingData._links = document._links;
                    self.params[page].pagingData.page = document.page;

                    deferred.resolve(document._embedded.databaskets);
                }, function(error) {
                    MessageService.addError('Could not get Databaskets', error);
                    deferred.reject();
                });

            return deferred.promise;
        };

        this.createDatabasket = function(name, desc) {
            return $q(function(resolve, reject) {
                var databasket = {name: name, description: (desc ? desc : '')};
                halAPI.from(rootUri + '/databaskets/')
                    .newRequest()
                    .post(databasket)
                    .result
                    .then(
                        function(document) {
                            MessageService.addInfo('Databasket created', 'New databasket ' + name + ' created.');
                            resolve(JSON.parse(document.data));
                        }, function(error) {
                            MessageService.addError('Could not create Databasket ' + name, error);
                            reject();
                        });
            });
        };

        this.removeDatabasket = function(databasket) {
            return $q(function(resolve, reject) {
                deleteAPI.from(rootUri + '/databaskets/' + databasket.id)
                    .newRequest()
                    .delete()
                    .result
                    .then(
                        function(document) {
                            if (200 <= document.status && document.status < 300) {
                                MessageService.addInfo('Databasket deleted', 'Databasket ' + databasket.name + ' deleted.');
                                resolve(databasket);
                            } else {
                                MessageService.addError('Could not remove Databasket ' + databasket.name, document);
                                reject();
                            }
                        }, function(error) {
                            MessageService.addError('Could not remove Databasket ' + databasket.name, error);
                            reject();
                        });
            });
        };

        this.updateDatabasket = function(databasket) {
            var newdatabasket = {name: databasket.name, description: databasket.description};
            return $q(function(resolve, reject) {
                halAPI.from(rootUri + '/databaskets/' + databasket.id)
                    .newRequest()
                    .patch(newdatabasket)
                    .result
                    .then(
                        function(document) {
                            MessageService.addInfo('Databasket successfully updated', 'Databasket ' + databasket.name + ' updated.');
                            resolve(JSON.parse(document.data));
                        }, function(error) {
                            MessageService.addError('Could not update Databasket ' + databasket.name, error);
                            reject();
                        });
            });
        };

        var getDatabasket = function(databasket) {
            var deferred = $q.defer();
            halAPI.from(rootUri + '/databaskets/' + databasket.id + '?projection=detailedDatabasket')
                .newRequest()
                .getResource()
                .result
                .then(
                    function(document) {
                        deferred.resolve(document);
                    }, function(error) {
                        MessageService.addError('Could not get Databasket: ' + databasket.name, error);
                        deferred.reject();
                    });
            return deferred.promise;
        };

        this.getDatabasketContents = function(databasket) {
            var deferred = $q.defer();
            halAPI.from(rootUri + '/databaskets/' + databasket.id)
                .newRequest()
                .follow('files')
                .withRequestOptions({
                    qs: {projection: 'detailedFstepFile'}
                })
                .getResource()
                .result
                .then(
                    function(document) {
                        deferred.resolve(document._embedded.fstepFiles);
                    }, function(error) {
                        MessageService.addError('Could not get contents of Databasket ' + databasket.name, error);
                        deferred.reject();
                    });
            return deferred.promise;
        };

        this.refreshDatabaskets = function(page, action, basket) {
            if (self.params[page]) {
                /* Get databasket list */
                getDatabaskets(page).then(function(data) {

                    self.params[page].databaskets = data;

                    /* Select last databasket if created */
                    if (action === "Create") {
                        self.params[page].selectedDatabasket = basket;
                    }

                    /* Clear basket if deleted */
                    if (action === "Remove") {
                        if (basket && self.params[page].selectedDatabasket && basket.id === self.params[page].selectedDatabasket.id) {
                            self.params[page].selectedDatabasket = undefined;
                            self.params[page].items = [];
                        }
                    }

                    /* Update the selected basket */
                    self.refreshSelectedBasket(page);
                });
            }
        };

        /* Fetch a new page */
        this.getDatabasketsPage = function(page, url) {
            if (self.params[page]) {
                self.params[page].pollingUrl = url;

                /* Get databasket list */
                getDatabaskets(page).then(function(data) {
                    self.params[page].databaskets = data;
                });
            }
        };

        this.getDatabasketsByFilter = function(page) {
            if (self.params[page]) {
                var url = rootUri + '/databaskets/' + self.params[page].selectedOwnershipFilter.searchUrl +
                    '?sort=name&filter=' + (self.params[page].searchText ? self.params[page].searchText : '');

                if (self.params[page].selectedOwnershipFilter !== self.dbOwnershipFilters.ALL_BASKETS) {
                    url += '&owner=' + UserService.params.activeUser._links.self.href;
                }
                self.params[page].pollingUrl = url;

                /* Get databasket list */
                getDatabaskets(page).then(function(data) {
                    self.params[page].databaskets = data;
                });
            }
        };

        // search function for explorer page bottombar menu-bars
        this.searchBaskets = function(searchText) {
            var deferred = $q.defer();
            halAPI.from(rootUri + '/databaskets/' + 'search/findByFilterOnly?sort=name&filter=' + searchText)
                .newRequest()
                .getResource()
                .result
                .then(function(document) {
                    deferred.resolve(document._embedded.databaskets);
                }, function(error) {
                    MessageService.addError('Could not get Databaskets', error);
                    deferred.reject();
                });

            return deferred.promise;
        };

        this.refreshSelectedBasket = function(page) {
            if (self.params[page]) {
                /* Get basket contents if selected */
                if (self.params[page].selectedDatabasket) {

                    getDatabasket(self.params[page].selectedDatabasket).then(function(basket) {
                        self.params[page].selectedDatabasket = basket;
                        self.getDatabasketContents(basket).then(function(data) {
                            self.params[page].items = data;
                        });

                        if (page === 'community') {
                            CommunityService.getObjectGroups(basket, 'databasket').then(function(data) {
                                self.params.community.sharedGroups = data;
                            });
                        }
                    });
                }
            }
        };

        this.addToDatabasketFromSearch = function(databasket, searchParams) {
            var deferred = $q.defer();
            halAPI.from(rootUri + '/databaskets/' + databasket.id + '/fromSearch')
                .newRequest()
                .post(searchParams)
                .result
                .then(
                    function(document) {
                        if (200 <= document.status && document.status < 300) {
                            MessageService.addInfo('Files successfully added', 'Files added to ' + databasket.name);
                            deferred.resolve(document);
                        } else {
                            MessageService.addError('Could not add file/s to Databasket ' + databasket.name, document);
                            deferred.reject();
                        }
                    }, function(error) {
                        MessageService.addError('Could not add file/s to Databasket ' + databasket.name, error);
                        deferred.reject();
                });

            return deferred.promise;
        };

        this.addToDatabasket = function(databasket, items) {
            var itemLinks = [];
            var promises = [];
            for (var index in items) {
                promises.push(getBasketItemLink(items[index], itemLinks));
            }

            $q.all(promises).then(function() {
                if (itemLinks.length > 0) {
                    addToBasket(databasket, itemLinks);
                }
            });
        };

        function getBasketItemLink(item, itemLinks) {
            var partialPromise = $q.defer();

            if (item._links && item._links.self) {
                itemLinks.push(item._links.self.href);
                partialPromise.resolve();
            } else {
                FileService.createGeoResultFile(item).then(function(fstepFile) {
                    itemLinks.push(fstepFile._links.self.href);
                    partialPromise.resolve();
                }, function(error) {
                    MessageService.addError('Could not add file to Databasket', error);
                    partialPromise.resolve();
                });
            }
            return partialPromise.promise;
        }

        function addToBasket(databasket, items) {
            self.addItems(databasket, items).then(function() {
                self.refreshDatabaskets("explorer");
            });
        }

        this.addItems = function(databasket, fileLinks) {
            return $q(function(resolve, reject) {

                var itemsArray = [];

                /* Collect links from current items */
                if (databasket.files && databasket.files.length > 0) {
                    for (var item in databasket.files) {
                        itemsArray.push(databasket.files[item]._links.self.href);
                    }
                }

                /* Append links of new items */
                var newItems = fileLinks.filter(function(i) {
                    return itemsArray.indexOf(i) < 0;
                });
                itemsArray.push(newItems);

                /* Set new files object */
                var updatedItems = {"files": itemsArray};

                /* Patch members with updated member list */
                halAPI.from(rootUri + '/databaskets/' + databasket.id)
                    .newRequest()
                    .patch(updatedItems)
                    .result
                    .then(
                        function(document) {
                            if (200 <= document.status && document.status < 300) {
                                MessageService.addInfo('Files successfully added', 'Files added to ' + databasket.name);
                                resolve(document);
                            } else {
                                MessageService.addError('Could not add file/s to Databasket ' + databasket.name, document);
                                reject();
                            }
                        }, function(error) {
                            MessageService.addError('Could not add file/s to Databasket ' + databasket.name, error);
                            reject();
                        });

            });
        };

        this.removeDatabasketItem = function(databasket, files, file) {
            return $q(function(resolve, reject) {

                /* Create array of user links */
                var itemsArray = [];
                for (var item in files) {
                    /* Don't add user to updated list */
                    if (files[item].id !== file.id) {
                        itemsArray.push(files[item]._links.self.href);
                    }
                }

                /* Set list of files to empty array */
                var updatedItems = {"files": itemsArray};

                /* Patch databasket with empty item list */
                halAPI.from(rootUri + '/databaskets/' + databasket.id)
                    .newRequest()
                    .patch(updatedItems)
                    .result
                    .then(
                        function(document) {
                            if (200 <= document.status && document.status < 300) {
                                MessageService.addInfo('File removed from Databasket', 'File ' + file.filename + ' removed from ' + databasket.name);
                                resolve(databasket);
                            } else {
                                MessageService.addError('Could not remove item from Databasket ' + databasket.name, document);
                                reject();
                            }
                        }, function(error) {
                            MessageService.addError('Could not remove item from Databasket ' + databasket.name, error);
                            reject();
                        });
            });
        };

        this.clearDatabasket = function(databasket) {
            return $q(function(resolve, reject) {

                /* Set list of files to empty array */
                var updatedItems = {"files": []};

                /* Patch databasket with empty item list */
                halAPI.from(rootUri + '/databaskets/' + databasket.id)
                    .newRequest()
                    .patch(updatedItems)
                    .result
                    .then(
                        function(document) {
                            if (200 <= document.status && document.status < 300) {
                                MessageService.addInfo('Databasket successfully cleared', 'Databasket ' + databasket.name + ' has been cleared');
                                resolve(databasket);
                            } else {
                                MessageService.addError('Could not clear Databasket ' + databasket.name, document);
                                reject();
                            }
                        }, function(error) {
                            MessageService.addError('Could not clear Databasket ' + databasket.name, error);
                            reject();
                        });
            });
        };

        return this;
    }]);
});
<commit_msg>basket service call fix<commit_after>/**
 * @ngdoc service
 * @name fstepApp.BasketService
 * @description
 * # BasketService
 * Service in the fstepApp.
 */
'use strict';

define(['../fstepmodules', 'traversonHal'], function(fstepmodules, TraversonJsonHalAdapter) {

    fstepmodules.service('BasketService', ['$rootScope', '$http', 'fstepProperties', '$q', '$timeout', 'MessageService', 'UserService', 'TabService', 'CommunityService', 'FileService', 'traverson', function($rootScope, $http, fstepProperties, $q, $timeout, MessageService, UserService, TabService, CommunityService, FileService, traverson) {

        var self = this;

        traverson.registerMediaType(TraversonJsonHalAdapter.mediaType, TraversonJsonHalAdapter);
        var rootUri = fstepProperties.URLv2;
        var halAPI = traverson.from(rootUri).jsonHal().useAngularHttp();
        var deleteAPI = traverson.from(rootUri).useAngularHttp();

        /** PRESERVE USER SELECTIONS **/
        this.dbOwnershipFilters = {
            ALL_BASKETS: {id: 0, name: 'All', searchUrl: 'search/findByFilterOnly'},
            MY_BASKETS: {id: 1, name: 'Mine', searchUrl: 'search/findByFilterAndOwner'},
            SHARED_BASKETS: {id: 2, name: 'Shared', searchUrl: 'search/findByFilterAndNotOwner'}
        };

        this.params = {
            explorer: {
                pollingUrl: rootUri + '/databaskets/?sort=name',
                pagingData: {},
                databaskets: undefined,
                items: undefined,
                selectBasketList: undefined,
                selectedDatabasket: undefined,
                selectedItems: [],
                searchText: '',
                displayFilters: false,
                databasketOnMap: {id: undefined},
                selectedOwnershipFilter: self.dbOwnershipFilters.ALL_BASKETS
            },
            community: {
                pollingUrl: rootUri + '/databaskets/?sort=name',
                pagingData: {},
                databaskets: undefined,
                items: undefined,
                selectedDatabasket: undefined,
                selectedItems: undefined,
                searchText: '',
                displayFilters: false,
                itemSearchText: '',
                itemDisplayFilters: false,
                sharedGroups: undefined,
                sharedGroupsSearchText: '',
                sharedGroupsDisplayFilters: false,
                selectedOwnershipFilter: self.dbOwnershipFilters.ALL_BASKETS
            }
        };

        /** END OF PRESERVE USER SELECTIONS **/

        var POLLING_FREQUENCY = 20 * 1000;
        var pollCount = 3;
        var startPolling = true;
        var pollingTimer;

        var pollDatabaskets = function(page) {
            pollingTimer = $timeout(function() {
                halAPI.from(self.params[page].pollingUrl)
                    .newRequest()
                    .getResource()
                    .result
                    .then(function(document) {
                        self.params[page].pagingData._links = document._links;
                        self.params[page].pagingData.page = document.page;

                        $rootScope.$broadcast('poll.baskets', document._embedded.databaskets);
                        pollDatabaskets(page);
                    }, function(error) {
                        error.retriesLeft = pollCount;
                        MessageService.addError('Could not poll Databaskets', error);
                        if (pollCount > 0) {
                            pollCount -= 1;
                            pollDatabaskets(page);
                        }
                    });
            }, POLLING_FREQUENCY);
        };

        this.stopPolling = function() {
            if (pollingTimer) {
                $timeout.cancel(pollingTimer);
            }
            startPolling = true;
        };

        var getDatabaskets = function(page) {
            var deferred = $q.defer();
            halAPI.from(self.params[page].pollingUrl)
                .newRequest()
                .getResource()
                .result
                .then(function(document) {
                    if (startPolling) {
                        pollDatabaskets(page);
                        startPolling = false;
                    }
                    self.params[page].pagingData._links = document._links;
                    self.params[page].pagingData.page = document.page;

                    deferred.resolve(document._embedded.databaskets);
                }, function(error) {
                    MessageService.addError('Could not get Databaskets', error);
                    deferred.reject();
                });

            return deferred.promise;
        };

        this.createDatabasket = function(name, desc) {
            return $q(function(resolve, reject) {
                var databasket = {name: name, description: (desc ? desc : '')};
                halAPI.from(rootUri + '/databaskets/')
                    .newRequest()
                    .post(databasket)
                    .result
                    .then(
                        function(document) {
                            MessageService.addInfo('Databasket created', 'New databasket ' + name + ' created.');
                            resolve(JSON.parse(document.data));
                        }, function(error) {
                            MessageService.addError('Could not create Databasket ' + name, error);
                            reject();
                        });
            });
        };

        this.removeDatabasket = function(databasket) {
            return $q(function(resolve, reject) {
                deleteAPI.from(rootUri + '/databaskets/' + databasket.id)
                    .newRequest()
                    .delete()
                    .result
                    .then(
                        function(document) {
                            if (200 <= document.status && document.status < 300) {
                                MessageService.addInfo('Databasket deleted', 'Databasket ' + databasket.name + ' deleted.');
                                resolve(databasket);
                            } else {
                                MessageService.addError('Could not remove Databasket ' + databasket.name, document);
                                reject();
                            }
                        }, function(error) {
                            MessageService.addError('Could not remove Databasket ' + databasket.name, error);
                            reject();
                        });
            });
        };

        this.updateDatabasket = function(databasket) {
            var newdatabasket = {name: databasket.name, description: databasket.description};
            return $q(function(resolve, reject) {
                halAPI.from(rootUri + '/databaskets/' + databasket.id)
                    .newRequest()
                    .patch(newdatabasket)
                    .result
                    .then(
                        function(document) {
                            MessageService.addInfo('Databasket successfully updated', 'Databasket ' + databasket.name + ' updated.');
                            resolve(JSON.parse(document.data));
                        }, function(error) {
                            MessageService.addError('Could not update Databasket ' + databasket.name, error);
                            reject();
                        });
            });
        };

        var getDatabasket = function(databasket) {
            var deferred = $q.defer();
            halAPI.from(rootUri + '/databaskets/' + databasket.id + '?projection=detailedDatabasket')
                .newRequest()
                .getResource()
                .result
                .then(
                    function(document) {
                        deferred.resolve(document);
                    }, function(error) {
                        MessageService.addError('Could not get Databasket: ' + databasket.name, error);
                        deferred.reject();
                    });
            return deferred.promise;
        };

        this.getDatabasketContents = function(databasket) {
            var deferred = $q.defer();
            halAPI.from(rootUri + '/databaskets/' + databasket.id)
                .newRequest()
                .follow('files')
                .withRequestOptions({
                    qs: {projection: 'detailedFstepFile'}
                })
                .getResource()
                .result
                .then(
                    function(document) {
                        deferred.resolve(document._embedded.fstepFiles);
                    }, function(error) {
                        MessageService.addError('Could not get contents of Databasket ' + databasket.name, error);
                        deferred.reject();
                    });
            return deferred.promise;
        };

        this.refreshDatabaskets = function(page, action, basket) {
            if (self.params[page]) {
                /* Get databasket list */
                getDatabaskets(page).then(function(data) {

                    self.params[page].databaskets = data;

                    /* Select last databasket if created */
                    if (action === "Create") {
                        self.params[page].selectedDatabasket = basket;
                    }

                    /* Clear basket if deleted */
                    if (action === "Remove") {
                        if (basket && self.params[page].selectedDatabasket && basket.id === self.params[page].selectedDatabasket.id) {
                            self.params[page].selectedDatabasket = undefined;
                            self.params[page].items = [];
                        }
                    }

                    /* Update the selected basket */
                    self.refreshSelectedBasket(page);
                });
            }
        };

        /* Fetch a new page */
        this.getDatabasketsPage = function(page, url) {
            if (self.params[page]) {
                self.params[page].pollingUrl = url;

                /* Get databasket list */
                getDatabaskets(page).then(function(data) {
                    self.params[page].databaskets = data;
                });
            }
        };

        this.getDatabasketsByFilter = function(page) {
            if (self.params[page]) {
                var url = rootUri + '/databaskets/' + self.params[page].selectedOwnershipFilter.searchUrl +
                    '?sort=name&filter=' + (self.params[page].searchText ? self.params[page].searchText : '');

                if (self.params[page].selectedOwnershipFilter !== self.dbOwnershipFilters.ALL_BASKETS) {
                    url += '&owner=' + UserService.params.activeUser._links.self.href;
                }
                self.params[page].pollingUrl = url;

                /* Get databasket list */
                getDatabaskets(page).then(function(data) {
                    self.params[page].databaskets = data;
                });
            }
        };

        // search function for explorer page bottombar menu-bars
        this.searchBaskets = function(searchText) {
            var deferred = $q.defer();
            halAPI.from(rootUri + '/databaskets/' + 'search/findByFilterOnly?sort=name&filter=' + searchText)
                .newRequest()
                .getResource()
                .result
                .then(function(document) {
                    deferred.resolve(document._embedded.databaskets);
                }, function(error) {
                    MessageService.addError('Could not get Databaskets', error);
                    deferred.reject();
                });

            return deferred.promise;
        };

        this.refreshSelectedBasket = function(page) {
            if (self.params[page]) {
                /* Get basket contents if selected */
                if (self.params[page].selectedDatabasket) {

                    getDatabasket(self.params[page].selectedDatabasket).then(function(basket) {
                        self.params[page].selectedDatabasket = basket;
                        self.getDatabasketContents(basket).then(function(data) {
                            self.params[page].items = data;
                        });

                        if (page === 'community') {
                            CommunityService.getObjectGroups(basket, 'databasket').then(function(data) {
                                self.params.community.sharedGroups = data;
                            });
                        }
                    });
                }
            }
        };

        this.addToDatabasketFromSearch = function(databasket, searchParams) {
            var deferred = $q.defer();
            halAPI.from(rootUri + '/databaskets/' + databasket.id + '/fromSearch')
                .newRequest()
                .withRequestOptions({
                    qs: searchParams
                })
                .post()
                .result
                .then(
                    function(document) {
                        if (200 <= document.status && document.status < 300) {
                            MessageService.addInfo('Files successfully added', 'Files added to ' + databasket.name);
                            deferred.resolve(document);
                        } else {
                            MessageService.addError('Could not add file/s to Databasket ' + databasket.name, document);
                            deferred.reject();
                        }
                    }, function(error) {
                        MessageService.addError('Could not add file/s to Databasket ' + databasket.name, error);
                        deferred.reject();
                });

            return deferred.promise;
        };

        this.addToDatabasket = function(databasket, items) {
            var itemLinks = [];
            var promises = [];
            for (var index in items) {
                promises.push(getBasketItemLink(items[index], itemLinks));
            }

            $q.all(promises).then(function() {
                if (itemLinks.length > 0) {
                    addToBasket(databasket, itemLinks);
                }
            });
        };

        function getBasketItemLink(item, itemLinks) {
            var partialPromise = $q.defer();

            if (item._links && item._links.self) {
                itemLinks.push(item._links.self.href);
                partialPromise.resolve();
            } else {
                FileService.createGeoResultFile(item).then(function(fstepFile) {
                    itemLinks.push(fstepFile._links.self.href);
                    partialPromise.resolve();
                }, function(error) {
                    MessageService.addError('Could not add file to Databasket', error);
                    partialPromise.resolve();
                });
            }
            return partialPromise.promise;
        }

        function addToBasket(databasket, items) {
            self.addItems(databasket, items).then(function() {
                self.refreshDatabaskets("explorer");
            });
        }

        this.addItems = function(databasket, fileLinks) {
            return $q(function(resolve, reject) {

                var itemsArray = [];

                /* Collect links from current items */
                if (databasket.files && databasket.files.length > 0) {
                    for (var item in databasket.files) {
                        itemsArray.push(databasket.files[item]._links.self.href);
                    }
                }

                /* Append links of new items */
                var newItems = fileLinks.filter(function(i) {
                    return itemsArray.indexOf(i) < 0;
                });
                itemsArray.push(newItems);

                /* Set new files object */
                var updatedItems = {"files": itemsArray};

                /* Patch members with updated member list */
                halAPI.from(rootUri + '/databaskets/' + databasket.id)
                    .newRequest()
                    .patch(updatedItems)
                    .result
                    .then(
                        function(document) {
                            if (200 <= document.status && document.status < 300) {
                                MessageService.addInfo('Files successfully added', 'Files added to ' + databasket.name);
                                resolve(document);
                            } else {
                                MessageService.addError('Could not add file/s to Databasket ' + databasket.name, document);
                                reject();
                            }
                        }, function(error) {
                            MessageService.addError('Could not add file/s to Databasket ' + databasket.name, error);
                            reject();
                        });

            });
        };

        this.removeDatabasketItem = function(databasket, files, file) {
            return $q(function(resolve, reject) {

                /* Create array of user links */
                var itemsArray = [];
                for (var item in files) {
                    /* Don't add user to updated list */
                    if (files[item].id !== file.id) {
                        itemsArray.push(files[item]._links.self.href);
                    }
                }

                /* Set list of files to empty array */
                var updatedItems = {"files": itemsArray};

                /* Patch databasket with empty item list */
                halAPI.from(rootUri + '/databaskets/' + databasket.id)
                    .newRequest()
                    .patch(updatedItems)
                    .result
                    .then(
                        function(document) {
                            if (200 <= document.status && document.status < 300) {
                                MessageService.addInfo('File removed from Databasket', 'File ' + file.filename + ' removed from ' + databasket.name);
                                resolve(databasket);
                            } else {
                                MessageService.addError('Could not remove item from Databasket ' + databasket.name, document);
                                reject();
                            }
                        }, function(error) {
                            MessageService.addError('Could not remove item from Databasket ' + databasket.name, error);
                            reject();
                        });
            });
        };

        this.clearDatabasket = function(databasket) {
            return $q(function(resolve, reject) {

                /* Set list of files to empty array */
                var updatedItems = {"files": []};

                /* Patch databasket with empty item list */
                halAPI.from(rootUri + '/databaskets/' + databasket.id)
                    .newRequest()
                    .patch(updatedItems)
                    .result
                    .then(
                        function(document) {
                            if (200 <= document.status && document.status < 300) {
                                MessageService.addInfo('Databasket successfully cleared', 'Databasket ' + databasket.name + ' has been cleared');
                                resolve(databasket);
                            } else {
                                MessageService.addError('Could not clear Databasket ' + databasket.name, document);
                                reject();
                            }
                        }, function(error) {
                            MessageService.addError('Could not clear Databasket ' + databasket.name, error);
                            reject();
                        });
            });
        };

        return this;
    }]);
});
<|endoftext|>


<commit_before>var base      = require('taskcluster-base');

// Common schema prefix
var SCHEMA_PREFIX_CONST = 'http://schemas.taskcluster.net/purge-cache/v1/';

/** API end-point for version v1/
 *
 * In this API implementation we shall assume the following context:
 * {
 *   publisher:      // publisher from base.Exchanges
 * }
 */
var api = new base.API({
  title:        "Purge Cache API Documentation",
  description: [
    "The purge-cache service, typically available at",
    "`purge-cache.taskcluster.net`, is responsible for publishing a pulse",
    "message for workers, so they can purge cache upon request.",
    "",
    "This document describes the API end-point for publishing the pulse",
    "message. This is mainly intended to be used by tools."
  ].join('\n')
});

// Export API
module.exports = api;

/** Define tasks */
api.declare({
  method:     'post',
  route:      '/purge-cache/:provisionerId/:workerType',
  name:       'purgeCache',
  scopes:     [
    'purge-cache:<provisionerId>/<workerType>:<cacheName>'
  ],
  deferAuth:  true,
  input:      SCHEMA_PREFIX_CONST + 'purge-cache-request.json#',
  title:      "Purge Worker Cache",
  description: [
    "Publish a purge-cache message to purge caches named `cacheName` with",
    "`provisionerId` and `workerType` in the routing-key. Workers should",
    "be listening for this message and purge caches when they see it."
  ].join('\n')
}, async function(req, res) {
  let {provisionerId, workerType} = req.params;
  let {cacheName} = req.body;

  // Authenticate request by providing parameters, and then validate that the
  // requester satisfies all the scopes assigned to the task
  if(!req.satisfies({provisionerId, workerType, cacheName})) {
    return;
  }

  // Publish message
  await this.publisher.purgeCache({provisionerId, workerType, cacheName});

  // Return 204
  res.status(204).send();
});<commit_msg>Added ping<commit_after>var base      = require('taskcluster-base');

// Common schema prefix
var SCHEMA_PREFIX_CONST = 'http://schemas.taskcluster.net/purge-cache/v1/';

/** API end-point for version v1/
 *
 * In this API implementation we shall assume the following context:
 * {
 *   publisher:      // publisher from base.Exchanges
 * }
 */
var api = new base.API({
  title:        "Purge Cache API Documentation",
  description: [
    "The purge-cache service, typically available at",
    "`purge-cache.taskcluster.net`, is responsible for publishing a pulse",
    "message for workers, so they can purge cache upon request.",
    "",
    "This document describes the API end-point for publishing the pulse",
    "message. This is mainly intended to be used by tools."
  ].join('\n')
});

// Export API
module.exports = api;

/** Define tasks */
api.declare({
  method:     'post',
  route:      '/purge-cache/:provisionerId/:workerType',
  name:       'purgeCache',
  scopes:     [
    'purge-cache:<provisionerId>/<workerType>:<cacheName>'
  ],
  deferAuth:  true,
  input:      SCHEMA_PREFIX_CONST + 'purge-cache-request.json#',
  title:      "Purge Worker Cache",
  description: [
    "Publish a purge-cache message to purge caches named `cacheName` with",
    "`provisionerId` and `workerType` in the routing-key. Workers should",
    "be listening for this message and purge caches when they see it."
  ].join('\n')
}, async function(req, res) {
  let {provisionerId, workerType} = req.params;
  let {cacheName} = req.body;

  // Authenticate request by providing parameters, and then validate that the
  // requester satisfies all the scopes assigned to the task
  if(!req.satisfies({provisionerId, workerType, cacheName})) {
    return;
  }

  // Publish message
  await this.publisher.purgeCache({provisionerId, workerType, cacheName});

  // Return 204
  res.status(204).send();
});

/** Check that the server is a alive */
api.declare({
  method:   'get',
  route:    '/ping',
  name:     'ping',
  title:    "Ping Server",
  description: [
    "Documented later...",
    "",
    "**Warning** this api end-point is **not stable**."
  ].join('\n')
}, function(req, res) {

  res.status(200).json({
    alive:    true,
    uptime:   process.uptime()
  });
});<|endoftext|>


<commit_before>// ==========================================================================
// Project:   The M-Project - Mobile HTML5 Application Framework
// Copyright: 2010 M-Way Solutions GmbH. All rights reserved.
// Creator:   Dominik
// Date:      02.11.2010
// License:   Dual licensed under the MIT or GPL Version 2 licenses.
//            http://github.com/mwaylabs/The-M-Project/blob/master/MIT-LICENSE
//            http://github.com/mwaylabs/The-M-Project/blob/master/GPL-LICENSE
// ==========================================================================

m_require('../core/foundation/view.js');

/**
 * @class
 *
 * The root object for ButtonViews.
 *
 */
M.ButtonView = M.View.extend({

    /**
     * The type of this object.
     *
     * @property {String}
     */
    type: 'M.ButtonView',

    /**
     * Mapping to value attribute.
     * text property is mixed in when extended.
     */
    //value: this.text,

    /**
     * Renders a button as an input tag. Input is automatically converted by jQuery mobile.
     */
    render: function() {
        var html = '<input type="button" id="' + this.id + '" value="' + this.value + '"/>';
        if(this.renderToDOM) {
            document.write(html);
        } else {
            return html;
        }
    },

    /**
     * Updates the value of the button with DOM access by jQuery.
     */
    renderUpdate: function() {
        $('#' + this.id).attr('value', this.value);
        this.applyTheme();
    },

    /**
     * Triggers rendering engine, e.g. jQuery mobile, to style the button.
     */
    applyTheme: function() {
        $('#' + this.id).button();
    }

});<commit_msg>added inline option<commit_after>// ==========================================================================
// Project:   The M-Project - Mobile HTML5 Application Framework
// Copyright: 2010 M-Way Solutions GmbH. All rights reserved.
// Creator:   Dominik
// Date:      02.11.2010
// License:   Dual licensed under the MIT or GPL Version 2 licenses.
//            http://github.com/mwaylabs/The-M-Project/blob/master/MIT-LICENSE
//            http://github.com/mwaylabs/The-M-Project/blob/master/GPL-LICENSE
// ==========================================================================

m_require('../core/foundation/view.js');

/**
 * @class
 *
 * The root object for ButtonViews.
 *
 */
M.ButtonView = M.View.extend({

    /**
     * The type of this object.
     *
     * @property {String}
     */
    type: 'M.ButtonView',

    /**
     * Mapping to value attribute.
     * text property is mixed in when extended.
     */
    //value: this.text,

    /**
     * Renders a button as an input tag. Input is automatically converted by jQuery mobile.
     */
    render: function() {
        var html = '<input type="button" id="' + this.id + '" value="' + this.value + '" ' + this.style() + ' />';
        if(this.renderToDOM) {
            document.write(html);
        } else {
            return html;
        }
    },

    /**
     * Updates the value of the button with DOM access by jQuery.
     */
    renderUpdate: function() {
        $('#' + this.id).attr('value', this.value);
        this.applyTheme();
    },

    /**
     * Triggers rendering engine, e.g. jQuery mobile, to style the button.
     */
    applyTheme: function() {
        $('#' + this.id).button();
    },

    /**
     * Applies some style-attributes to the label.
     */
    style: function() {
        var html = '';
        if(this.isInline) {
            html += 'data-inline="true"';
        }
        return html;
    }

});

<|endoftext|>


<commit_before>import base from 'taskcluster-base';
import common from './common';
import slugid from 'slugid';
import _ from 'lodash';

/** API end-point for version v1/
 *
 * In this API implementation we shall assume the following context:
 * {
 *   publisher:      // publisher from base.Exchanges
 * }
 */
var api = new base.API({
  title:        "TaskCluster Secrets API Documentation",
  description: [
    "The secrets service, typically available at",
    "`tools.taskcluster.net`, is responsible for managing",
    "secure data in TaskCluster."
  ].join('\n')
});

// Export API
module.exports = api;

/** Define tasks */
api.declare({
  method:      'put',
  route:       '/secrets/:name(*)',
  deferAuth:   true,
  name:        'set',
  input:       common.SCHEMA_PREFIX_CONST + "secret.json#",
  scopes:      [['secrets:set:<name>']],
  title:       'Create New Secret',
  description: 'Set a secret associated with some key.'
}, async function(req, res) {
    let {name} = req.params;
    let {secret, expires} = req.body;
    if (!req.satisfies({name})) {
      return;
    }
    try {
      await this.entity.create({
        name:       name,
        secret:     secret,
        expires:    new Date(expires)
      });
    } catch(e) {
      // If they're trying to re-apply the same secret just respond with okay
      if (e.name == 'EntityAlreadyExistsError') {
        let item = await this.entity.load({name});
        if (!_.isEqual(item.secret, secret) ||
            !_.isEqual(new Date(item.expires), new Date(expires))) {
            res.status(e.statusCode).send(`A resource named ${name} already exists.`);
            return;
        }
      } else {
        throw e;
      }
    }
    res.status(204).send();
});

api.declare({
  method:      'post',
  route:       '/secrets/:name(*)',
  deferAuth:   true,
  name:        'update',
  input:       common.SCHEMA_PREFIX_CONST + "secret.json#",
  scopes:      [['secrets:update:<name>']],
  title:       'Update A Secret',
  description: 'Update a secret associated with some key.'
}, async function(req, res) {
    let {secret, expires} = req.body;
    let {name} = req.params;
    if (!req.satisfies({name})) {
      return;
    }
    let item = await this.entity.load({name}, true);
    if (!item) {
      res.status(404).send(`Can't update, no resource named ${name} found`);
      return;
    }
    await item.modify(function() {
      this.secret = secret;
      this.expires = new Date(expires);
    });
    res.status(204).send();
});

api.declare({
  method:      'delete',
  route:       '/secrets/:name(*)',
  deferAuth:   true,
  name:        'remove',
  scopes:      [['secrets:remove:<name>']],
  title:       'Delete Secret',
  description: 'Delete the secret attached to some key.'
}, async function(req, res) {
  let {name} = req.params;
  if (!req.satisfies({name})) {
    return;
  }
  try {
    await this.entity.remove({name: name});
  } catch(e) {
    if (e.name == 'ResourceNotFoundError') {
      res.status(404).send(`Can't delete, no resource named ${name} found`);
      return;
    } else {
      throw e;
    }
  }
  res.status(204).send();
});

api.declare({
  method:      'get',
  route:       '/secrets/:name(*)',
  deferAuth:   true,
  name:        'get',
  output:      common.SCHEMA_PREFIX_CONST + "secret.json#",
  scopes:      [['secrets:get:<name>']],
  title:       'Read Secret',
  description: 'Read the secret attached to some key.'
}, async function(req, res) {
  let {name} = req.params;
  if (!req.satisfies({name})) {
    return;
  }
  let item = undefined;
  try {
    item = await this.entity.load({name});
  } catch (e) {
    if (e.name == 'ResourceNotFoundError') {
      res.status(404).send(`No resource named ${name} found`);
      return;
    } else {
      throw e;
    }
  }
  if (item.isExpired()) {
    res.status(410).send('The requested resource has expired.');
  } else {
    res.status(200).json(item.json());
  }
});

/** Check that the server is a alive */
api.declare({
  method:   'get',
  route:    '/ping',
  name:     'ping',
  title:    "Ping Server",
  description: [
    "Documented later...",
    "",
    "**Warning** this api end-point is **not stable**."
  ].join('\n')
}, function(req, res) {

  res.status(200).json({
    alive:    true,
    uptime:   process.uptime()
  });
});
<commit_msg>remove spurious comment<commit_after>import base from 'taskcluster-base';
import common from './common';
import slugid from 'slugid';
import _ from 'lodash';

/** API end-point for version v1/
 *
 * In this API implementation we shall assume the following context:
 * {
 *   publisher:      // publisher from base.Exchanges
 * }
 */
var api = new base.API({
  title:        "TaskCluster Secrets API Documentation",
  description: [
    "The secrets service, typically available at",
    "`tools.taskcluster.net`, is responsible for managing",
    "secure data in TaskCluster."
  ].join('\n')
});

// Export API
module.exports = api;

api.declare({
  method:      'put',
  route:       '/secrets/:name(*)',
  deferAuth:   true,
  name:        'set',
  input:       common.SCHEMA_PREFIX_CONST + "secret.json#",
  scopes:      [['secrets:set:<name>']],
  title:       'Create New Secret',
  description: 'Set a secret associated with some key.'
}, async function(req, res) {
    let {name} = req.params;
    let {secret, expires} = req.body;
    if (!req.satisfies({name})) {
      return;
    }
    try {
      await this.entity.create({
        name:       name,
        secret:     secret,
        expires:    new Date(expires)
      });
    } catch(e) {
      // If they're trying to re-apply the same secret just respond with okay
      if (e.name == 'EntityAlreadyExistsError') {
        let item = await this.entity.load({name});
        if (!_.isEqual(item.secret, secret) ||
            !_.isEqual(new Date(item.expires), new Date(expires))) {
            res.status(e.statusCode).send(`A resource named ${name} already exists.`);
            return;
        }
      } else {
        throw e;
      }
    }
    res.status(204).send();
});

api.declare({
  method:      'post',
  route:       '/secrets/:name(*)',
  deferAuth:   true,
  name:        'update',
  input:       common.SCHEMA_PREFIX_CONST + "secret.json#",
  scopes:      [['secrets:update:<name>']],
  title:       'Update A Secret',
  description: 'Update a secret associated with some key.'
}, async function(req, res) {
    let {secret, expires} = req.body;
    let {name} = req.params;
    if (!req.satisfies({name})) {
      return;
    }
    let item = await this.entity.load({name}, true);
    if (!item) {
      res.status(404).send(`Can't update, no resource named ${name} found`);
      return;
    }
    await item.modify(function() {
      this.secret = secret;
      this.expires = new Date(expires);
    });
    res.status(204).send();
});

api.declare({
  method:      'delete',
  route:       '/secrets/:name(*)',
  deferAuth:   true,
  name:        'remove',
  scopes:      [['secrets:remove:<name>']],
  title:       'Delete Secret',
  description: 'Delete the secret attached to some key.'
}, async function(req, res) {
  let {name} = req.params;
  if (!req.satisfies({name})) {
    return;
  }
  try {
    await this.entity.remove({name: name});
  } catch(e) {
    if (e.name == 'ResourceNotFoundError') {
      res.status(404).send(`Can't delete, no resource named ${name} found`);
      return;
    } else {
      throw e;
    }
  }
  res.status(204).send();
});

api.declare({
  method:      'get',
  route:       '/secrets/:name(*)',
  deferAuth:   true,
  name:        'get',
  output:      common.SCHEMA_PREFIX_CONST + "secret.json#",
  scopes:      [['secrets:get:<name>']],
  title:       'Read Secret',
  description: 'Read the secret attached to some key.'
}, async function(req, res) {
  let {name} = req.params;
  if (!req.satisfies({name})) {
    return;
  }
  let item = undefined;
  try {
    item = await this.entity.load({name});
  } catch (e) {
    if (e.name == 'ResourceNotFoundError') {
      res.status(404).send(`No resource named ${name} found`);
      return;
    } else {
      throw e;
    }
  }
  if (item.isExpired()) {
    res.status(410).send('The requested resource has expired.');
  } else {
    res.status(200).json(item.json());
  }
});

/** Check that the server is a alive */
api.declare({
  method:   'get',
  route:    '/ping',
  name:     'ping',
  title:    "Ping Server",
  description: [
    "Documented later...",
    "",
    "**Warning** this api end-point is **not stable**."
  ].join('\n')
}, function(req, res) {

  res.status(200).json({
    alive:    true,
    uptime:   process.uptime()
  });
});
<|endoftext|>


<commit_before>var _ = require('underscore')._;

var api = function(dbot) {
    var api = {
        'resolveUser': function(server, nick, useLowerCase) {
            var knownUsers = this.getServerUsers(server);
            var user = nick;

            if(!useLowerCase) {
                if(!_.include(knownUsers.users, nick) && _.has(knownUsers.aliases, nick)) {
                    user = knownUsers.aliases[nick];
                }
            } else {
                // this is retarded
                user = user.toLowerCase();
                var resolvedUser = _.find(knownUsers.users, function(nick) {
                    var toMatch = new RegExp(_.escape(user), "i");
                    return nick.match(toMatch) !== null;
                }, this);

                if(!resolvedUser) {
                    resolvedUser = _.find(knownUsers.aliases, function(nick, alias) {
                        var toMatch = new RegExp(_.escape(user), "i");
                        return alias.match(toMatch) !== null;
                    }, this);
                    user = knownUsers.aliases[resolvedUser];
                } else {
                    user = resolvedUser;
                }
            }

            return user;
        },

        'isKnownUser': function(server, nick) {
            var knownUsers = this.getServerUsers(server);
            return (_.include(knownUsers.users, nick) || _.has(knownUsers.aliases, nick));
        },

        'isPrimaryUser': function(server, nick) {
            var knownUsers = this.getServerUsers(server);
            return _.include(knownUsers.users, nick);
        },

        'getAliases': function(server, nick) {
            var knownUsers = this.getServerUsers(server);
            return _.chain(knownUsers.aliases)
                .keys()
                .filter(function(user) {
                    return knownUsers.aliases[user] == nick;
                }, this)
                .value();
        },

        'isOnline': function(server, user, channel, useLowerCase) {
            var user = this.api.resolveUser(server, user, useLowerCase);
            var possiNicks = [user].concat(this.api.getAliases(server, user));
            var onlineNicks = dbot.instance.connections[server].channels[channel].nicks;

            return _.any(onlineNicks, function(nick) {
                nick = nick.name;
                return _.include(possiNicks, nick);
            }, this);
        }
    };

    return api;
};

exports.fetch = function(dbot) {
    return api(dbot);
};
<commit_msg>no idea how that was doing that but now it is fixed<commit_after>var _ = require('underscore')._;

var api = function(dbot) {
    var api = {
        'resolveUser': function(server, nick, useLowerCase) {
            var knownUsers = this.getServerUsers(server);
            var user = nick;

            if(!useLowerCase) {
                if(!_.include(knownUsers.users, nick) && _.has(knownUsers.aliases, nick)) {
                    user = knownUsers.aliases[nick];
                }
            } else {
                // this is retarded
                user = user.toLowerCase();
                var resolvedUser = _.find(knownUsers.users, function(nick) {
                    var toMatch = new RegExp(user, "i");
                    return nick.match(toMatch) !== null;
                }, this);

                if(!resolvedUser) {
                    resolvedUser = _.find(knownUsers.aliases, function(nick, alias) {
                        var toMatch = new RegExp(user, "i");
                        return alias.match(toMatch) !== null;
                    }, this);
                    user = knownUsers.aliases[resolvedUser];
                } else {
                    user = resolvedUser;
                }
            }

            return user;
        },

        'isKnownUser': function(server, nick) {
            var knownUsers = this.getServerUsers(server);
            return (_.include(knownUsers.users, nick) || _.has(knownUsers.aliases, nick));
        },

        'isPrimaryUser': function(server, nick) {
            var knownUsers = this.getServerUsers(server);
            return _.include(knownUsers.users, nick);
        },

        'getAliases': function(server, nick) {
            var knownUsers = this.getServerUsers(server);
            return _.chain(knownUsers.aliases)
                .keys()
                .filter(function(user) {
                    return knownUsers.aliases[user] == nick;
                }, this)
                .value();
        },

        'isOnline': function(server, user, channel, useLowerCase) {
            var user = this.api.resolveUser(server, user, useLowerCase);
            var possiNicks = [user].concat(this.api.getAliases(server, user));
            var onlineNicks = dbot.instance.connections[server].channels[channel].nicks;

            return _.any(onlineNicks, function(nick) {
                nick = nick.name;
                return _.include(possiNicks, nick);
            }, this);
        }
    };

    return api;
};

exports.fetch = function(dbot) {
    return api(dbot);
};
<|endoftext|>


<commit_before>/**
 * Helper "class" for accessing MediaWiki API and handling cookie-based session
 */
module.exports = (function() {
	// introspect package.json to get module version
	var VERSION = require('../package').version;

	// @see https://github.com/mikeal/request
	var request = require('request').defaults({jar: true});

	// import deferred-js
	// @see https://github.com/heavylifters/deferred-js
	var Deferred = require('./deferred/deferred').Deferred;

	// wait x ms between HTTP requests
	var QUEUE_DELAY = 50;

	var api = function(options) {
		this.protocol = options.protocol || 'http';
		this.port = options.port || (this.protocol === 'https' ? 443 : 80);
		this.server = options.server;
		this.path = options.path;
		this.proxy = options.proxy;

		this.debug = options.debug;

		// requests queue
		this.queue = [];
		this.queueItemId = 0;

		if (this.protocol === 'https') {
			this.http = require('https');
		} else {
			this.http = require('http');
		}
		this.formatUrl = require('url').format;

		this.userAgent = 'nodemw v' + VERSION + ' (node.js ' + process.version + '; ' + process.platform + ' ' + process.arch + ')';
		this.version = VERSION;
	};

	var doRequest = function(params, callback, method, promise) {
		var self = this,
			// store requested action - will be used when parsing a response
			actionName = params.action,
			// "request" options
			options = {
				method: method || 'GET',
				proxy: this.proxy || false,
				headers: {
					'User-Agent': this.userAgent
				}
			};

		// HTTP request parameters
		params = params || {};

		// force JSON format
		params.format = 'json';

		// handle uploads
		if (method === 'UPLOAD') {
			options.method = 'POST';

			var CRLF = "\r\n",
				postBody = [],
				boundary = 'nodemw' + Math.random().toString().substr(2);

			// encode each field
			Object.keys(params).forEach(function(fieldName) {
				var value = params[fieldName];

				postBody.push("--" + boundary);
				postBody.push(CRLF);

				if (typeof value === 'string') {
					// properly encode UTF8 in binary-safe POST data
					postBody.push("Content-Disposition: form-data; name=\"" + fieldName + "\"");
					postBody.push(CRLF);
					postBody.push(CRLF);
					postBody.push(new Buffer(value, 'utf8'));
				}
				else {
					// send attachment
					postBody.push("Content-Disposition: form-data; name=\"" + fieldName + "\"; filename=\"foo\"");
					postBody.push(CRLF);
					postBody.push(CRLF);
					postBody.push(value);
				}

				postBody.push(CRLF);
			});

			postBody.push("--" + boundary + "--");

			// encode post data
			options.headers['content-type'] = 'multipart/form-data; boundary=' + boundary;
			options.body = postBody;

			params = {};
		}

		// form an URL to API
		options.url = this.formatUrl({
			protocol: this.protocol,
			port: this.port,
			hostname: this.server,
			pathname: this.path + '/api.php',
			query: (options.method === 'GET') ? params : {}
		});

		// POST all parameters (avoid "request string too long" errors)
		if (method === 'POST') {
			options.form = params;
		}

		request(options, function(error, response, body) {
			if (error) {
				throw 'Request to API failed: ' + error;
			}

			if (response.statusCode !== 200) {
				console.log(new Error().stack);
				throw 'Request to API failed: HTTP status code was ' + response.statusCode;
			}

			// parse response
			var data,
				info,
				next;

			try {
				data = JSON.parse(body);
				info = data && data[actionName];
				next = data && data['query-continue'] && data['query-continue'][params.list];
			}
			catch(e) {
				throw 'Error parsing JSON response: ' + body;
			}

			if (data && !data.error) {
				if (typeof callback === 'function') {
					callback && callback(info, next, data);
				}
				promise.resolve({
					info: info,
					next: next,
					data: data
				});
			}
			else {
				throw 'Error returned by API: ' + data.error.info;
			}
		});

		return promise;
	};

	// add a function to the queue
	var addToQueue = function(fn) {
		var promise = new Deferred();

		// add to the queue
		this.queue.push({
			id: this.queueItemId++,
			fn: fn,
			promise: promise
		});

		// try to process this item (maybe this queue is inactive right now)
		processQueue.apply(this);

		return promise;
	};

	// process the first item in the queue and schedule next check
	var processQueue = function() {
		var self = this,
			item;

		// is queue running? this function will be called via setTimeout
		if (this.queueBusy === true) {
			return;
		}

		// get an item to process
		item = this.queue.shift();

		// the queue is empty
		if (typeof item === 'undefined') {
			return;
		}

		if (typeof item.fn !== 'function') {
			throw new Error('addToQueue() not provided with a function!');
		}

		this.queueBusy = true;

		item.promise.then(function(res) {
			// schedule next queue check
			setTimeout(function() {
				self.queueBusy = false;
				processQueue.apply(self);
			}, QUEUE_DELAY);

			return res;
		});

		// call the function and pass promise it should reject / resolve
		item.fn.call(this, item.promise);
	};

	// public interface
	api.prototype = {
		log: function(obj) {
			if (this.debug) {
				console.log(obj);
			}
		},

		// adds request to the queue and returns a promise
		call: function(params, callback, method) {
			var self = this;

			// add a request to the queue
			return addToQueue.call(this, function(promise) {
				doRequest.apply(self, [params, callback, method, promise]);
			});
		},

		// fetch an external resource
		fetchUrl: function(url, encoding) {
			var self = this;
			encoding = encoding || 'utf-8';

			// add a request to the queue
			return addToQueue.call(this, function(promise) {
				self.log('Fetching ' + url + '...');

				request({
					url: url,
					encoding: (encoding === 'binary') ? null : encoding
				}, function (error, response, body) {
					if (!error && response.statusCode === 200) {
						self.log('Fetched ' + (body.length/1024).toFixed(2) + 'kB');
						promise.resolve(body);
					}
					else {
						throw new Error('fetchUrl failed with ' + error);
					}
				});
			});
		}
	};

	return api;
}());
<commit_msg>create a new cookie jar for each api instance<commit_after>/**
 * Helper "class" for accessing MediaWiki API and handling cookie-based session
 */
module.exports = (function() {
	// introspect package.json to get module version
	var VERSION = require('../package').version;

	// @see https://github.com/mikeal/request
	var request = require('request');

	// import deferred-js
	// @see https://github.com/heavylifters/deferred-js
	var Deferred = require('./deferred/deferred').Deferred;

	// wait x ms between HTTP requests
	var QUEUE_DELAY = 50;

	var api = function(options) {
		this.protocol = options.protocol || 'http';
		this.port = options.port || (this.protocol === 'https' ? 443 : 80);
		this.server = options.server;
		this.path = options.path;
		this.proxy = options.proxy;
		this.jar = request.jar(); // create new cookie jar for each instance

		this.debug = options.debug;

		// requests queue
		this.queue = [];
		this.queueItemId = 0;

		if (this.protocol === 'https') {
			this.http = require('https');
		} else {
			this.http = require('http');
		}
		this.formatUrl = require('url').format;

		this.userAgent = 'nodemw v' + VERSION + ' (node.js ' + process.version + '; ' + process.platform + ' ' + process.arch + ')';
		this.version = VERSION;
	};

	var doRequest = function(params, callback, method, promise) {
		var self = this,
			// store requested action - will be used when parsing a response
			actionName = params.action,
			// "request" options
			options = {
				method: method || 'GET',
				proxy: this.proxy || false,
				jar: this.jar,
				headers: {
					'User-Agent': this.userAgent
				}
			};

		// HTTP request parameters
		params = params || {};

		// force JSON format
		params.format = 'json';

		// handle uploads
		if (method === 'UPLOAD') {
			options.method = 'POST';

			var CRLF = "\r\n",
				postBody = [],
				boundary = 'nodemw' + Math.random().toString().substr(2);

			// encode each field
			Object.keys(params).forEach(function(fieldName) {
				var value = params[fieldName];

				postBody.push("--" + boundary);
				postBody.push(CRLF);

				if (typeof value === 'string') {
					// properly encode UTF8 in binary-safe POST data
					postBody.push("Content-Disposition: form-data; name=\"" + fieldName + "\"");
					postBody.push(CRLF);
					postBody.push(CRLF);
					postBody.push(new Buffer(value, 'utf8'));
				}
				else {
					// send attachment
					postBody.push("Content-Disposition: form-data; name=\"" + fieldName + "\"; filename=\"foo\"");
					postBody.push(CRLF);
					postBody.push(CRLF);
					postBody.push(value);
				}

				postBody.push(CRLF);
			});

			postBody.push("--" + boundary + "--");

			// encode post data
			options.headers['content-type'] = 'multipart/form-data; boundary=' + boundary;
			options.body = postBody;

			params = {};
		}

		// form an URL to API
		options.url = this.formatUrl({
			protocol: this.protocol,
			port: this.port,
			hostname: this.server,
			pathname: this.path + '/api.php',
			query: (options.method === 'GET') ? params : {}
		});

		// POST all parameters (avoid "request string too long" errors)
		if (method === 'POST') {
			options.form = params;
		}

		request(options, function(error, response, body) {
			if (error) {
				throw 'Request to API failed: ' + error;
			}

			if (response.statusCode !== 200) {
				console.log(new Error().stack);
				throw 'Request to API failed: HTTP status code was ' + response.statusCode;
			}

			// parse response
			var data,
				info,
				next;

			try {
				data = JSON.parse(body);
				info = data && data[actionName];
				next = data && data['query-continue'] && data['query-continue'][params.list];
			}
			catch(e) {
				throw 'Error parsing JSON response: ' + body;
			}

			if (data && !data.error) {
				if (typeof callback === 'function') {
					callback && callback(info, next, data);
				}
				promise.resolve({
					info: info,
					next: next,
					data: data
				});
			}
			else {
				throw 'Error returned by API: ' + data.error.info;
			}
		});

		return promise;
	};

	// add a function to the queue
	var addToQueue = function(fn) {
		var promise = new Deferred();

		// add to the queue
		this.queue.push({
			id: this.queueItemId++,
			fn: fn,
			promise: promise
		});

		// try to process this item (maybe this queue is inactive right now)
		processQueue.apply(this);

		return promise;
	};

	// process the first item in the queue and schedule next check
	var processQueue = function() {
		var self = this,
			item;

		// is queue running? this function will be called via setTimeout
		if (this.queueBusy === true) {
			return;
		}

		// get an item to process
		item = this.queue.shift();

		// the queue is empty
		if (typeof item === 'undefined') {
			return;
		}

		if (typeof item.fn !== 'function') {
			throw new Error('addToQueue() not provided with a function!');
		}

		this.queueBusy = true;

		item.promise.then(function(res) {
			// schedule next queue check
			setTimeout(function() {
				self.queueBusy = false;
				processQueue.apply(self);
			}, QUEUE_DELAY);

			return res;
		});

		// call the function and pass promise it should reject / resolve
		item.fn.call(this, item.promise);
	};

	// public interface
	api.prototype = {
		log: function(obj) {
			if (this.debug) {
				console.log(obj);
			}
		},

		// adds request to the queue and returns a promise
		call: function(params, callback, method) {
			var self = this;

			// add a request to the queue
			return addToQueue.call(this, function(promise) {
				doRequest.apply(self, [params, callback, method, promise]);
			});
		},

		// fetch an external resource
		fetchUrl: function(url, encoding) {
			var self = this;
			encoding = encoding || 'utf-8';

			// add a request to the queue
			return addToQueue.call(this, function(promise) {
				self.log('Fetching ' + url + '...');

				request({
					url: url,
					encoding: (encoding === 'binary') ? null : encoding
				}, function (error, response, body) {
					if (!error && response.statusCode === 200) {
						self.log('Fetched ' + (body.length/1024).toFixed(2) + 'kB');
						promise.resolve(body);
					}
					else {
						throw new Error('fetchUrl failed with ' + error);
					}
				});
			});
		}
	};

	return api;
}());
<|endoftext|>


<commit_before>#!/usr/bin/env node

function api(opt){
	if (!(this instanceof api)) return new api(opt);
	return this;
};

/* * * entity operations * * */

// create a relation
api.prototype.ent_create = function(data, fn){
	var self = this;
	return this;
};

// retrieve a relation
api.prototype.ent_get = function(id, fn){
	var self = this;
	return this;
};

// update a relation
api.prototype.ent_update = function(id, data, fn){
	var self = this;
	return this;
};

// delete a relation and all relations
api.prototype.ent_delete = function(id, fn){
	var self = this;
	return this;
};

// merge n entities
api.prototype.ent_merge = function(ids, fn){
	var self = this;
	return this;
};

// split entity into two (and create horcrux)
api.prototype.ent_split = function(id, a, b, fn){
	var self = this;
	return this;
};

// automagically upsert entity
api.prototype.ent_magic = function(data, fn){
	var self = this;
	return this;
};

/* * * relation operations * * */

// create relation
api.prototype.rel_create = function(data, fn){
	var self = this;
	return this;
};

// retrieve relation
api.prototype.rel_get = function(id, fn){
	var self = this;
	return this;
};

// update a relation
api.prototype.rel_update = function(id, data, fn){
	var self = this;
	return this;
};

// delete a relation
api.prototype.rel_delete = function(id, fn){
	var self = this;
	return this;
};

/* * * meta * * */

api.prototype.ent_types = function(id, fn){
	var self = this;
	return this;
};

api.prototype.rel_types = function(id, fn){
	var self = this;
	return this;
};

/* * * query * * */

api.prototype.rel_ents = function(id, fn){
	var self = this;
	return this;
};

module.exports = api;
<commit_msg>implemented api<commit_after>#!/usr/bin/env node

var validator = require("validator");
var moment = require("moment");
var debug = require("debug")("api");

function api(opt, db){

	if (!(this instanceof api)) return new api(opt, db);
	var self = this;

	self.opt = opt;
	self.db = db;

	// wait for db
	self.ready = false;
	self.db.on('ready',function() {
		debug("database ready");

		// ensure indexes
		self.db.collection("entities").ensureIndex("name", {"background": true});
		self.db.collection("entities").ensureIndex("aliases", {"background": true});
		self.db.collection("entities").ensureIndex("type", {"background": true});
		self.db.collection("entities").ensureIndex("tags", {"background": true});
		self.db.collection("entities").ensureIndex("relations", {"background": true});

		self.ready = true;
	});

	self.db.on('error',function(err) {
		debug("database error: %s", err);
	});

	return this;
};

/* * * helpers * * */

/* * * sanity checks * * */

// ✓ check entity
api.prototype.ent_check = function(data, fn){
	var self = this;

	// entity prototype
	var ent = {
		name: null,
		created: (new Date()),
		updated: (new Date()),
		type: null,
		tags: [],
		aliases: [],
		data: {},
		sources: []
	};

	// check created
	if (data.hasOwnProperty("created")){
		if (!(data.created instanceof Date)) return fn(new Error("created is not a Date object"));
		ent.created = data.created;
	};

	// check name
	if (!data.hasOwnProperty("name") || typeof data.name !== "string" || data.name === "") return fn(new Error("name is not a string"));
	ent.name = data.name;

	// check type
	if (!data.hasOwnProperty("type") || typeof data.type !== "string" || data.type === "") return fn(new Error("type is not a string"));
	ent.type = data.type;

	// check tags
	if (data.hasOwnProperty("tags") && data.tags) {
		if (typeof data.tags === "string") data.tags = data.tags.split(/([\,\;]|\s+#)/g);
		if (!(data.tags instanceof Array)) return fn(new Error("tags is not an array"));
		data.tags.map(function(tag){
			// fix tags to trimmed lower case
			return tag.toLowerCase().replace(/\s+/g,'-').replace(/[\s_\-\.]+/g,'-').replace(/^\-+|\-+$/g,'').replace(/ä/g,'ae').replace(/ö/g,'oe').replace(/ü/g,'ue').replace(/ß/g,'ss').replace(/ß/g,'ss').toLowerCase(); // fixme: make this nicer and use linebreaks
		}).filter(function(tag){
			// filter still-invalid tags
			return /^[a-z0-9\-]$/.test(tag);
		}).map(function(tag){
			// add to object prototype
			ent.tags.push(tag);
		});
	}

	// check aliases
	if (data.hasOwnProperty("aliases") && data.aliases) {
		if (!(data.aliases instanceof Array)) return fn(new Error("alsiases is not an array"));
		data.aliases.filter(function(alias){
			return ((typeof alias === "string") && alias !== "");
		}).map(function(alias){
			ent.aliases.push(alias);
		});
	};

	// transfer data
	if (data.hasOwnProperty("data") && (typeof data.data === "object")){
		Object.keys(data.data).forEach(function(k){
			ent.data[k] = data.data[k];
		});
	};

	// transfer sources
	if (data.hasOwnProperty("sources") && (data.sources instanceof Array)){
		ent.sources = data.sources.map(function(source){
			if (!source.hasOwnProperty("created") || (!(source.created instanceof Date))) source.created = new Date();
			if (!source.hasOwnProperty("updated") || (!(source.updated instanceof Date))) source.updated = new Date();
			if (!source.hasOwnProperty("remark") || typeof source.remark !== "string") source.remark = "";
			return source;
		}).filter(function(source){
			return (source && source.hasOwnProperty("url") && validator.isURL(source.url, {protocols: ["http","https"], require_tld: true, require_protocol: true, allow_underscores: false}));
		});
	};

	fn(null, ent);

	return this;
};

// ✓ check relation
api.prototype.rel_check = function(data, fn){
	var self = this;

	// relation prototype
	var rel = {
		created: (new Date()),
		updated: (new Date()),
		type: null,
		weight: 0,
		entities: [],
		tags: [],
		sources: [],
		data: {}
	};

	// check entities
	if (!data.hasOwnProperties("entities") || !(data.entities instanceof Array)) return fn(new Error("entities must not be empty"));
	data.entities = data.entities.map(function(entity){
		return entity.toString();
	}).filter(function(entity){
		return ((typeof entity === "string") && /^[a-f0-9]{24}$/.test(entity));
	});
	if (data.entities.length !== 2) return fn(new Error("entities must contain 2 elements"));
	data.entities.map(function(entity){
		rel.entities.push(self.db.ObjectId(entity));
	});

	// check weight
	if (data.hasOwnProperty("weight") && (typeof data.weight === "number")) rel.weight = data.weight;

	// check created
	if (data.hasOwnProperty("created")){
		if (!(data.created instanceof Date)) return fn(new Error("created is not a Date object"));
		rel.created = data.created;
	};

	// check type
	if (!data.hasOwnProperty("type") || typeof data.type !== "string" || data.type === "") return fn(new Error("type is not a string"));
	rel.type = data.type;

	// check tags
	if (data.hasOwnProperty("tags") && data.tags) {
		if (typeof data.tags === "string") data.tags = data.tags.split(/([\,\;]|\s+#)/g);
		if (!(data.tags instanceof Array)) return fn(new Error("tags is not an array"));
		data.tags.map(function(tag){
			// fix tags to trimmed lower case
			return tag.toLowerCase().replace(/\s+/g,'-').replace(/[\s_\-\.]+/g,'-').replace(/^\-+|\-+$/g,'').replace(/ä/g,'ae').replace(/ö/g,'oe').replace(/ü/g,'ue').replace(/ß/g,'ss').replace(/ß/g,'ss').toLowerCase(); // fixme: make this nicer and use linebreaks
		}).filter(function(tag){
			// filter still-invalid tags
			return /^[a-z0-9\-]$/.test(tag);
		}).map(function(tag){
			// add to object prototype
			rel.tags.push(tag);
		});
	}

	// transfer data
	if (data.hasOwnProperty("data") && (typeof data.data === "object")){
		Object.keys(data.data).forEach(function(k){
			rel.data[k] = data.data[k];
		});
	};

	// transfer sources
	if (data.hasOwnProperty("sources") && (data.sources instanceof Array)){
		rel.sources = data.sources.map(function(source){
			if (!source.hasOwnProperty("created") || (!(source.created instanceof Date))) source.created = new Date();
			if (!source.hasOwnProperty("updated") || (!(source.updated instanceof Date))) source.updated = new Date();
			if (!source.hasOwnProperty("remark") || typeof source.remark !== "string") source.remark = "";
			return source;
		}).filter(function(source){
			return (source && source.hasOwnProperty("url") && validator.isURL(source.url, {protocols: ["http","https"], require_tld: true, require_protocol: true, allow_underscores: false}));
		});
	};

	fn(null, rel);

	return this;

};

/* * * entity operations * * */

// ✓ create an entity
api.prototype.ent_create = function(data, fn){
	debug("create entity");
	var self = this;
	self.ent_check(data, function(err, data){
		if (err) return fn(err);
		self.db.collection("entities").save(data, function(err, result){
			if (err) return fn(err);
			debug("entity created: %s", result._id);
			fn(null, result._id);
		});
	});
	return this;
};

// ✓ retrieve an entity
api.prototype.ent_get = function(id, fn){
	debug("get entity %s", id);
	var self = this;
	self.db.collection("entities").findOne({_id: self.db.ObjectId(id)}, function(err, result){
		if (!err) debug("got entity %s", id);
		fn(err, result);
	});
	return this;
};

// ✓ delete an entity and all relations
api.prototype.ent_delete = function(id, fn){
	debug("delete entity %s", id);
	var self = this;
	self.db.collection("entities").remove({_id: self.db.ObjectId(id)}, true, function(err, result){
		if (!err) debug("deleted entity %s", id);
		// FIXME: remove relations
		fn(err, result);
	});
	return this;
};

// ✓ update an entity
api.prototype.ent_update = function(id, data, fn){
	debug("update entity: %s", result._id);
	var self = this;
	self.ent_check(data, function(err, data){
		if (err) return fn(err);
		self.db.collection("entities").update({_id: self.db.ObjectId(id)}, data, {upsert: true}, function(err, result){
			if (err) return fn(err);
			debug("entity updated: %s", result._id);
			fn(null, result._id);
		});
	});
	return this;
};

// merge n entities
api.prototype.ent_merge = function(ids, data, fn){
	var self = this;
	//FIXME: implement this
	return this;
};

// split entity into two (and create horcrux)
api.prototype.ent_split = function(id, a, b, fn){
	var self = this;
	//FIXME: implement this too
	return this;
};

// ✓ automagically merge entity versions
api.prototype.ent_upmerge = function(id, data, fn){
	debug("upmerge entity %s", id);
	var self = this;
	self.ent_get(id, function(err, a){
		if (err) return fn(err);
		self.ent_check(data, function(err, b){
			if (err) return fn(err);

			// transfer creation date
			b.created = a.created;

			// if name changed, push old name to aliases
			if (b.name !== a.name && b.aliases.indexOf(a.name) < 0) b.aliases.push(a.name);

			// transfer aliases
			a.aliases.forEach(function(alias){
				if (b.aliases.indexOf(alias) < 0) b.aliases.push(alias);
			});

			// transfer type
			b.type = a.type;

			// transfer tags
			a.tags.forEach(function(tag){
				if (b.tags.indexOf(tag) < 0) b.tags.push(tag);
			});

			// transfer data
			Object.keys(a.data).forEach(function(k){
				if (!(b.data.hasOwnProperty(k))) b.data[k] = a.data[k];
			});

			// transfer sources
			a.sources.forEach(function(source){
				if (b.sources.filter(function(s){
					return (s.url === source.url);
				}).length === 0) b.sources.push(source);
			});

			self.ent_update(id, b, function(err, result){

				if (err) return fn(err);

				debug("upmerged entity %s", id);
				fn(null, result);

			});
		});
	});
	return this;
};

/* * * relation operations * * */

// ✓ create relation
api.prototype.rel_create = function(data, fn){
	debug("create relation");
	var self = this;
	self.rel_check(data, function(err, data){
		if (err) return fn(err);
		self.db.collection("relations").save(data, function(err, result){
			if (err) return fn(err);
			debug("relation created: %s", result._id);
			fn(null, result._id);
		});
	});
	return this;
};

// ✓ cretrieve relation
api.prototype.rel_get = function(id, fn){
	debug("get relation %s", id);
	var self = this;
	self.db.collection("relations").findOne({_id: self.db.ObjectId(id)}, function(err, result){
		if (!err) debug("got relation %s", id);
		fn(err, result);
	});
	return this;
};

// ✓ delete a relation
api.prototype.rel_delete = function(id, fn){
	debug("delete relation %s", id);
	var self = this;
	self.db.collection("relations").remove({_id: self.db.ObjectId(id)}, true, function(err, result){
		if (!err) debug("deleted relation %s", id);
		fn(err, result);
	});
	return this;
};

// ✓ update a relation
api.prototype.rel_update = function(id, data, fn){
	debug("update relation %s", id);
	var self = this;
	self.rel_check(data, function(err, data){
		if (err) return fn(err);
		self.db.collection("relations").update({_id: self.db.ObjectId(id)}, data, {upsert: true}, function(err, result){
			if (err) return fn(err);
			debug("relation updated: %s", result._id);
			fn(null, result._id);
		});
	});
	return this;
};

// ✓ automagically merge relation versions
api.prototype.rel_upmerge = function(id, data, fn){
	debug("upmerge relation %s", id);
	var self = this;
	self.rel_get(id, function(err, a){
		if (err) return fn(err);
		self.rel_check(data, function(err, b){
			if (err) return fn(err);

			// transfer creation date
			b.created = a.created;

			// transfer type
			b.type = a.type;

			// transfer tags
			a.tags.forEach(function(tag){
				if (b.tags.indexOf(tag) < 0) b.tags.push(tag);
			});

			// transfer data
			Object.keys(a.data).forEach(function(k){
				if (!(b.data.hasOwnProperty(k))) b.data[k] = a.data[k];
			});

			// transfer sources
			a.sources.forEach(function(source){
				if (b.sources.filter(function(s){
					return (s.url === source.url);
				}).length === 0) b.sources.push(source);
			});

			self.rel_update(id, b, function(err, result){

				if (err) return fn(err);

				debug("upmerged relation %s", id);
				fn(null, result);

			});
		});
	});
	return this;
};

/* * * meta * * */

// ✓ entity types
api.prototype.ent_types = function(fn){
	var self = this;
	self.db.collection("entities").distinct("type", function(err, result){
		if (err) return fn(err);
		fn(null, result);
	});
	return this;
};

// ✓ entity tags
api.prototype.ent_tags = function(fn){
	var self = this;
	self.db.collection("entities").distinct("tags", function(err, result){
		if (err) return fn(err);
		fn(null, result);
	});
	return this;
};

// ✓ relation types
api.prototype.rel_types = function(fn){
	var self = this;
	self.db.collection("relations").distinct("type", function(err, result){
		if (err) return fn(err);
		fn(null, result);
	});
	return this;
};

// ✓ relation tags
api.prototype.rel_tags = function(fn){
	var self = this;
	self.db.collection("relations").distinct("tags", function(err, result){
		if (err) return fn(err);
		fn(null, result);
	});
	return this;
};

/* * * query * * */

// ✓ get all relations for an entity
api.prototype.rel_ents = function(id, fn){
	var self = this;
	self.db.find({"entities": { "$in": self.db.ObjectId(id) }}, function(err, result){
		if (err) return fn(err);
		fn(null, result);
	});
	return this;
};

module.exports = api;
<|endoftext|>


<commit_before>// external
import fetch from "isomorphic-unfetch";

// internal
import cfg from "../config";

const githubClient = (api, token) => endpoint =>
  fetch(`${api}${endpoint}`, {
    headers: {
      Authorization: `Bearer ${token}`
    }
  }).then(res => res.json());

const gh = githubClient(cfg.GITHUB_API, cfg.GITHUB_TOKEN);

const user = endpoint => gh(`/users/${cfg.GITHUB_OWNER}${endpoint}`);
const repo = endpoint =>
  gh(`/repos/${cfg.GITHUB_OWNER}/${cfg.GITHUB_REPO}${endpoint}`);

export const getIssue = id => repo(`/issues/${id}`);
export const getIssues = (label = "") => repo(`/issues?labels=${label}`);
export const getLabels = () => repo(`/labels`);
export const getComments = id => repo(`/issues/${id}/comments`);
export const getLatestRepos = () => user(`/repos?per_page=6&sort=updated`);
export const getLatestSongs = () => forRecentSongs(5);
<commit_msg>remove unused func<commit_after>// external
import fetch from "isomorphic-unfetch";

// internal
import cfg from "../config";

const githubClient = (api, token) => endpoint =>
  fetch(`${api}${endpoint}`, {
    headers: {
      Authorization: `Bearer ${token}`
    }
  }).then(res => res.json());

const gh = githubClient(cfg.GITHUB_API, cfg.GITHUB_TOKEN);

const user = endpoint => gh(`/users/${cfg.GITHUB_OWNER}${endpoint}`);
const repo = endpoint =>
  gh(`/repos/${cfg.GITHUB_OWNER}/${cfg.GITHUB_REPO}${endpoint}`);

export const getIssue = id => repo(`/issues/${id}`);
export const getIssues = (label = "") => repo(`/issues?labels=${label}`);
export const getLabels = () => repo(`/labels`);
export const getComments = id => repo(`/issues/${id}/comments`);
export const getLatestRepos = () => user(`/repos?per_page=6&sort=updated`);
<|endoftext|>