Source: src/js/views/portals/PortalUsagesView.js

define([
  "jquery",
  "underscore",
  "backbone",
  "collections/SolrResults",
  "collections/Filters",
  "collections/bookkeeper/Usages",
  "views/portals/PortalListView",
  "text!templates/portals/portalList.html",
], function (
  $,
  _,
  Backbone,
  SearchResults,
  Filters,
  Usages,
  PortalListView,
  Template,
) {
  /**
   * @class PortalUsagesView
   * @classdesc A view that shows a list of Portal Usages
   * @classcategory Views/Portals
   * @extends PortalListView
   * @since 2.14.0
   * @constructor
   */
  return PortalListView.extend(
    /** @lends PortalUsagesView.prototype */ {
      /**
       * A reference to the Usages collection that is rendered in this view
       * @type {Usages}
       */
      usagesCollection: null,

      /**
       * Renders this view
       */
      render: function () {
        try {
          //If the "my portals" feature is disabled, exit now
          if (MetacatUI.appModel.get("showMyPortals") === false) {
            return;
          }

          //Insert the template
          this.$el.html(this.template());

          if (!this.usagesCollection) {
            this.usagesCollection = new Usages();
          }

          //When in DataONE Plus Preview mode, search for portals in Solr first,
          // then create Usage models for each portal in Solr.
          if (MetacatUI.appModel.get("dataonePlusPreviewMode")) {
            this.listenTo(this.searchResults, "sync", function () {
              //Create a Usage for each portal found in Solr
              this.searchResults.each(function (searchResult) {
                this.usagesCollection.add({
                  instanceId: searchResult.get("seriesId"),
                  status: "active",
                  quantity: 1,
                  nodeId: searchResult.get("datasource"),
                });
              }, this);

              //Merge the Usages and Search Results
              this.mergeSearchResults();

              //Update the view with info about the corresponding Usage model
              this.showUsageInfo();
            });

            if (MetacatUI.appModel.get("dataonePlusPreviewPortals").length) {
              this.altReposChecked = 0;
              this.altReposToCheck = [];
              this.additionalPortalsToDisplay = [];

              _.each(
                MetacatUI.appModel.get("alternateRepositories"),
                function (altRepo) {
                  var portalsInThisRepo = _.where(
                    MetacatUI.appModel.get("dataonePlusPreviewPortals"),
                    { datasource: altRepo.identifier },
                  );

                  if (portalsInThisRepo.length) {
                    var searchResults = new SearchResults();
                    this.listenToOnce(searchResults, "reset", function () {
                      if (searchResults.length) {
                        this.additionalPortalsToDisplay =
                          this.additionalPortalsToDisplay.concat(
                            searchResults.models,
                          );
                      }

                      if (typeof this.altReposChecked == "number") {
                        this.altReposChecked++;
                        if (this.altReposChecked == this.altReposToCheck) {
                          //Call the PortalListView render function
                          PortalListView.prototype.render.call(this);
                        }
                      }

                      //Create a Usage for each portal found in Solr
                      searchResults.each(function (searchResult) {
                        this.usagesCollection.add({
                          instanceId: searchResult.get("seriesId"),
                          status: "active",
                          quantity: 1,
                          nodeId: searchResult.get("datasource"),
                        });
                      }, this);

                      //Merge the Usages and Search Results
                      this.mergeSearchResults(searchResults);

                      //Update the view with info about the corresponding Usage model
                      this.showUsageInfo();
                    });

                    //Create a Filters() collection
                    var portalFilters = new Filters();
                    portalFilters.mustMatchIds = true;
                    portalFilters.addWritePermissionFilter();
                    portalFilters.add({
                      fields: ["obsoletedBy"],
                      values: ["*"],
                      matchSubstring: false,
                      exclude: true,
                    });
                    portalFilters.add({
                      fields: ["datasource"],
                      values: [altRepo.identifier],
                      matchSubstring: false,
                      exclude: false,
                    });
                    var portalIds = _.pluck(portalsInThisRepo, "seriesId");
                    portalFilters.add({
                      fields: ["seriesId"],
                      values: portalIds,
                      operator: "OR",
                      matchSubstring: false,
                    });

                    searchResults.rows = portalIds.length;
                    searchResults.fields = this.searchFields;

                    searchResults.queryServiceUrl = altRepo.queryServiceUrl;

                    searchResults.setQuery(portalFilters.getQuery());

                    this.altReposToCheck++;

                    //Get the first page of results
                    searchResults.toPage(0);
                  }
                },
                this,
              );

              return;
            }

            //Call the PortalListView render function
            PortalListView.prototype.render.call(this);

            //Don't do anything else in this render function
            return;
          }

          //When the collection has been fetched, redner the Usage list
          this.listenToOnce(
            this.usagesCollection,
            "sync",
            this.getSearchResultsForUsages,
          );

          //Listen to the collection for errors
          this.listenToOnce(this.usagesCollection, "error", this.showError);

          //When the SearchResults are retrieved, merge them with the Usages collection
          this.listenToOnce(this.searchResults, "sync", function () {
            this.mergeSearchResults();

            //Update the view with info about the corresponding Usage model
            this.showUsageInfo();
          });

          //Fetch the collection
          this.usagesCollection.fetch({
            quotaType: "portal",
            subject: MetacatUI.appUserModel.get("username"),
          });
        } catch (e) {
          console.error("Failed to render the PortalUsagesView: ", e);
        }
      },

      /**
       * Using the Usages collection, this function creates Filters that search for
       * the portal objects for those Usages
       * @param {Usages} usages The Usages collection to get search results for
       */
      getSearchResultsForUsages: function (usages) {
        try {
          //Set the number of portals to the number of usages found
          this.numPortals = this.usagesCollection.length;

          var portalIds = this.usagesCollection.pluck("instanceId");

          //If there are no given filters, create a Filter for the seriesId of each portal Usage
          if (!this.filters && portalIds.length) {
            this.filters = new Filters();

            this.filters.mustMatchIds = true;
            this.filters.add({
              fields: ["seriesId"],
              values: portalIds,
              operator: "OR",
              matchSubstring: false,
              exclude: false,
            });

            //Only get Portals that the user is an owner of
            this.filters.addWritePermissionFilter();
          }
          //If the filters set on this view is an array of JSON, add it to a Filters collection
          else if (
            this.filters.length &&
            !Filters.prototype.isPrototypeOf(this.filters)
          ) {
            //Create search filters for finding the portals
            var filters = new Filters();

            filters.add(this.filters);

            this.filters = filters;
          } else {
            this.filters = new Filters();
          }

          this.getSearchResults();
        } catch (e) {
          this.showError();
          console.error(
            "Failed to create search results for the portal list: ",
            e,
          );
        }
      },

      /**
       * Merges the SearchResults collection with the Usages collection
       */
      mergeSearchResults: function (searchResults) {
        if (typeof searchResults == "undefined") {
          var searchResults = this.searchResults;
        }

        this.usagesCollection.mergeCollections(searchResults);

        //If in DataONE Plus Preview mode, total the portal count from Solr and use that as the portal totalUsage
        if (MetacatUI.appModel.get("dataonePlusPreviewMode")) {
          var portalQuotas = MetacatUI.appUserModel.getQuotas("portal");

          if (portalQuotas.length) {
            portalQuotas[0].set("totalUsage", this.usagesCollection.length);
          }
        }
      },

      /**
       * Shows the Usage info for each Portal in this view
       */
      showUsageInfo: function () {
        this.usagesCollection.each(function (usage) {
          //Find the list item HTML element for this Usage
          var listItem = this.$(
            "[data-seriesId='" + usage.get("instanceId") + "']",
          );

          //If a list item is found, update it
          if (listItem.length) {
            //Disable the Edit button if the Usage status is "inactive"
            if (usage.get("status") == "inactive") {
              listItem
                .find(".edit.btn")
                .attr("disabled", "disabled")
                .popover({
                  trigger: "hover focus click",
                  placement: "top",
                  delay: {
                    show: 800,
                  },
                  html: true,
                  content:
                    "To edit this " +
                    MetacatUI.appModel.get("portalTermSingular") +
                    ", contact us at " +
                    "<a href='mailto:" +
                    MetacatUI.appModel.get("emailContact") +
                    "'>" +
                    MetacatUI.appModel.get("emailContact") +
                    "</a>" +
                    " to activate it. It may be deactivated because your " +
                    MetacatUI.appModel.get("dataonePlusName") +
                    " membership has ended.",
                });
            }
          }
        }, this);

        //Add a "Create" button to create a new portal, since we know the total Usage and
        // remaining Quota now.
        this.renderCreateButton();
      },
    },
  );
});