uPortal-Project/uportal-home

View on GitHub
web/src/main/webapp/my-app/marketplace/services.js

Summary

Maintainability
C
1 day
Test Coverage
/*
 * Licensed to Apereo under one or more contributor license
 * agreements. See the NOTICE file distributed with this work
 * for additional information regarding copyright ownership.
 * Apereo licenses this file to you under the Apache License,
 * Version 2.0 (the "License"); you may not use this file
 * except in compliance with the License.  You may obtain a
 * copy of the License at the following location:
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */
'use strict';

define(['angular', 'jquery'], function(angular, $) {
    return angular.module('my-app.marketplace.services', [])

    .factory('marketplaceService',
      ['$q', '$http', '$sessionStorage', 'layoutService', '$log',
      'miscService', 'mainService', 'SERVICE_LOC', 'APP_FLAGS',
      function($q, $http, $sessionStorage, layoutService, $log,
          miscService, mainService, SERVICE_LOC, APP_FLAGS) {
        var marketplacePromise;
        // local variables
        var filter = '';
        var fromSearchTerm = '';
        var fromSearchOrBrowse = '';

        // public functions

        var initialFilter = function(theFilter) {
            filter = theFilter;
        };

        var getInitialFilter = function() {
            return filter;
        };

        /**
         * Sets the information about where they came from
         */
        var setFromInfo = function(searchOrBrowse, term) {
          fromSearchTerm = term;
          fromSearchOrBrowse = searchOrBrowse;
        };
        /**
         * Gets the information about where they came from
         */
        var getFromInfo = function() {
          return {term: fromSearchTerm, searchOrBrowse: fromSearchOrBrowse};
        };

        var checkMarketplaceCache = function() {
            var userPromise = mainService.getUser();
            return userPromise.then(function(user) {
                if ($sessionStorage.sessionKey === user.sessionKey &&
                    $sessionStorage.marketplace) {
                  return {
                      portlets: $sessionStorage.marketplace,
                      categories: $sessionStorage.categories,
                  };
                }
                return null;
            });
        };

        var storeMarketplaceInCache = function(data) {
            var userPromise = mainService.getUser();
            userPromise.then(function(user) {
                $sessionStorage.sessionKey = user.sessionKey;
                $sessionStorage.marketplace = data.portlets;
                $sessionStorage.categories = data.categories;
                return user;
            }).catch(function() {
              $log.warn('Could not getUser');
            });
        };

        var getPortlets = function() {
            return checkMarketplaceCache().then(function(data) {
                var successFn;
                var errorFn;
                var defer;

                // first, check the local storage...
                if (data) {
                    defer = $q.defer();
                    defer.resolve(data);
                    return defer.promise;
                }

                // check for outstanding requests that have not yet been cached.

                // Downside of adding caching in getUser() is that the
                // promise in getUser blocks till we get results.  That blocks
                // the call to getMarketplace.  So, they pile up.  Then, when
                // getUser clears, all the getUser promises fire immediately.
                // They all fire so fast that the layout data doesn't make it
                // to cache between calls.
                // So, cache the very first promise locally.
                // Then, if the marketplace promise exists use it again.
                if (marketplacePromise) {
                    return marketplacePromise;
                }

                successFn =function(data) {
                    var result = {};
                    postProcessing(result, data);
                    storeMarketplaceInCache(result);
                    return result;
                };

                errorFn = function(reason) {
                  miscService.redirectUser(
                    reason.status,
                    'marketplace entries call'
                  );
                };

                // no caching...  request from the server
                marketplacePromise = $q.all([$http.get(
                    SERVICE_LOC.base + SERVICE_LOC.marketplace.base +
                    SERVICE_LOC.marketplace.entries, {cache: true}),
                  layoutService.getLayout()]).then(successFn, errorFn);
                return marketplacePromise;
            });
        };

        /**
         *  returns portlet if one exists in user's marketplace,
         *  or goes and gets entry from server
         */
        var getPortlet = function(fname) {
          var successFn;
          var errorFn;
          var defer;
          // first check cache, if there use that (it'll be faster)
          return checkMarketplaceCache().then(function(data) {
            if (data) {
                defer = $q.defer();
                // find portlet and resolve with it if exists
                var portlets = $.grep(data.portlets, function(e) {
                  return e.fname === fname;
                });
                var portlet = portlets ? portlets[0] : null;
                defer.resolve(portlet);
                return defer.promise;
            } else {
              successFn =function(data) {
                var portlet = data[0].data.entry;
                if (portlet) {
                  var layout = data[1];
                  processInLayout(portlet, layout);
                }
                return portlet;
              };

              errorFn = function(reason) {
                miscService.redirectUser(
                  reason.status,
                  'marketplace entry service call'
                );
              };

              return $q.all(
                  [$http.get(
                    SERVICE_LOC.base + SERVICE_LOC.marketplace.base +
                    SERVICE_LOC.marketplace.entry + fname + '.json',
                    {cache: true}),
                  layoutService.getLayout()])
                .then(successFn, errorFn);
            }
          });
        };

        var getUserRating = function(fname) {
            return $http.get(SERVICE_LOC.base + SERVICE_LOC.marketplace.base +
                fname + '/getRating', {cache: true})
              .then(function(result) {
                return result.data.rating;
              });
        };

        var saveRating = function(fname, rating) {
          return $http.post(
              SERVICE_LOC.base + SERVICE_LOC.marketplace.base + fname +
                '/rating/' + rating.rating,
              {},
              {params: {review: rating.review}})
            .success(function(data, status, headers, config) {
              if (APP_FLAGS.debug) {
                $log.log('successfully saved marketplace rating for ' +
                  fname + ' with data ' + rating);
              }
              return data;
            })
            .error(function(data, status, headers, config) {
              if (APP_FLAGS.debug) {
                $log.error('Failed to save marketplace rating for ' +
                  fname + ' with data ' + rating);
              }
              return data;
            });
        };

        // private functions
        var processInLayout = function(portlet, layout) {
          var inLayout = $.grep(layout, function(e) {
            if (APP_FLAGS.useNewLayout) {
              return e === portlet.fname;
            } else {
              return e.fname === portlet.fname;
            }
          }).length;
          if (inLayout > 0) {
            portlet.hasInLayout = true;
          } else {
            portlet.hasInLayout = false;
          }
        };

        var postProcessing = function(result, data) {
            result.portlets = data[0].data.portlets;

            var categories = [];
            var layout = data[1].layout;


            $.each(result.portlets, function(index, cur) {
                // in layout check
                processInLayout(cur, layout);

                // categories building
                var categoriesOfThisPortlet = cur.categories;

                $.each(categoriesOfThisPortlet, function(index, category) {
                    if ($.inArray(category, categories) == -1 &&
                        cur.canAdd == true) {
                      categories.push(category);
                    }
                });
            });

            result.categories = categories.sort();
            result.layout = layout;
        };

        var portletMatchesSearchTerm = function(portlet, searchTerm, opts) {
          if (!searchTerm) {
              return opts && opts.defaultReturn;
          }

          // create local var for searchTerm
          var lowerSearchTerm = searchTerm.toLowerCase();

          // check title
          if (portlet.title.toLowerCase().indexOf(lowerSearchTerm) !== -1) {
            return true;
          }

          if (opts && opts.searchDescription) {
            var desc = portlet.description;
            // check description match
            if (desc &&
                desc.toLowerCase().indexOf(lowerSearchTerm) !== -1) {
              return true;
            }
          }

          // last ditch effort, check keywords
          if (opts && opts.searchKeywords) {
            var keys = portlet.keywords;
            if (keys) {
              for (var i = 0; i < keys.length; i++) {
                if (keys[i].toLowerCase().indexOf(lowerSearchTerm) !== -1) {
                    return true;
                }
              }
            }
          }
          return false;
        };

        var filterPortletsBySearchTerm =
          function(portletList, searchTerm, opts) {
            var matches;

            if (!angular.isArray(portletList)) {
              return null;
            }

            matches = [];
            angular.forEach(portletList, function(portlet) {
              if (portletMatchesSearchTerm(portlet, searchTerm, opts)) {
                matches.push(portlet);
              }
            });
            return matches;
          };

        var getAllRatings = function(fname) {
          return $http.get(
              SERVICE_LOC.base +
              SERVICE_LOC.marketplace.base + fname +
              '/ratings', {cache: true})
            .then(function(result) {
              return result.data.ratings;
            });
        };

        // return list of avaliable functions
        return {
            getPortlet: getPortlet,
            getPortlets: getPortlets,
            initialFilter: initialFilter,
            getInitialFilter: getInitialFilter,
            getUserRating: getUserRating,
            saveRating: saveRating,
            getAllRatings: getAllRatings,
            filterPortletsBySearchTerm: filterPortletsBySearchTerm,
            portletMatchesSearchTerm: portletMatchesSearchTerm,
            setFromInfo: setFromInfo,
            getFromInfo: getFromInfo,
        };
    }]);
});