/*
# site-monitor/views/listSiteMonitors.js Copyright 2021 cPanel, L.L.C.
# All rights reserved.
# copyright@cpanel.net http://cpanel.net
# This code is subject to the cPanel license. Unauthorized copying is prohibited
*/
/* global define */
/** @namespace cpanel.siteMonitor.views.listSiteMonitors */
define(
[
"angular",
"cjt/util/locale",
"app/models/monitor-state.enum",
"app/models/monitor-type.enum",
"app/models/monitor",
"app/services/sites",
"app/services/monitoring",
"app/services/contacts",
"app/services/sitesCache",
"app/services/batch",
"cjt/services/alertService",
"app/directives/itemListerDirective",
"app/directives/siteItemListDirective",
"cjt/services/cpanel/componentSettingSaverService",
"cjt/services/viewNavigationApi",
"app/services/dataStore",
],
function(angular, LOCALE, MonitorState, MonitorType, Monitor) {
"use strict";
var app = angular.module("cpanel.siteMonitor.listSiteMonitors", [
"cpanel.siteMonitor.siteItemListDirective",
"cpanel.siteMonitor.itemListerDirective",
"cpanel.siteMonitor.monitoringService",
"cpanel.siteMonitor.batchService",
"cpanel.siteMonitor.contactsService",
"cjt2.services.viewNavigationApi",
"cjt2.services.alert",
"cpanel.siteMonitor.dataStoreService",
"cpanel.siteMonitor.sitesCacheService",
]);
/**
* View Controller for Domain Listing
*
* @module listSites
*
* @param {Object} $scope angular scope
* @param {Object} $locale angular location Object
* @param {Array} sitesAPI api to fetch sites.
* @param {Object} ITEM_LISTER_CONSTANTS event constants for actions
*
*/
var COMPONENT_NAME = "siteMonitor.listView";
var controller = app.controller(
"listSiteMonitors",
[
"$scope",
"$location",
"$filter",
"$timeout",
"componentSettingSaverService",
"initialSites",
"viewNavigationApi",
"dataStore",
"sitesCache",
"sites",
"batch",
"monitoring",
"alertService",
"contacts",
"ITEM_LISTER_CONSTANTS",
"PAGE",
function(
$scope,
$location,
$filter,
$timeout,
$CSSS,
initialSites,
viewNavigationApi,
dataStore,
sitesCache,
sitesService,
batch,
monitoringAPI,
alertService,
contacts,
ITEM_LISTER_CONSTANTS,
PAGE) {
var LIST_DOMAIN_EVENTS = {
HIDE_ASSOCIATED: "hideAssociatedSubdomains",
SHOW_ASSOCIATED: "showAssociatedSubdomains"
};
var associatedDomainsExist;
$scope.LOCALE = LOCALE;
$scope.disableBtn = false;
/**
* Handles item buttons clicks.
*
* @method _itemChangeRequested
* @param {Event} event
* @param {*} parameters
*/
function _itemChangeRequested(event, parameters) {
switch(parameters.actionType) {
case 'enable_multiple':
$scope.disableBtn = true;
var sites = parameters.items;
var queue = sites.map(function(site) {
return { url: site.domain, fullUrl: "https://" + site.domain + "/", domain: site.domain };
});
dataStore.save("post-subscribe", queue);
// TODO: Move this to the store callback this once the subscribe flow is in place
_batchEnable(queue)
.then(function(results) {
_fetchAndRefresh()
});
break;
case 'disable_multiple':
$scope.disableBtn = true;
var sites = parameters.items;
// filter out calls to remove monitors that don't exist
var queue = sites.filter(function(site) {
if (site.monitors.length) { return true }
}).map(function(site) {
var monitor = site.monitors[0];
return { url: monitor.url(), id: monitor.id, domain: site.domain };
});
dataStore.save("post-unsubscribe", queue);
// TODO: Move this to the store callback this once the unsubscribe flow is in place
_batchDisable(queue)
.then(function() {
_fetchAndRefresh()
});
break;
case 'enable':
$scope.disableBtn = true;
var site = parameters.item;
var queue = [ site ].map(function(site) {
return { url : site.domain, fullUrl: "https://" + site.domain + "/" , domain: site.domain};
});
dataStore.save("post-subscribe", queue);
// TODO: Move this to the store callback this once the subscribe flow is in place
_batchEnable(queue)
.then(function() {
_fetchAndRefresh()
});
break;
case 'disable':
$scope.disableBtn = true;
var site = parameters.item;
var monitor = site.monitors[0];
var queue = [
{ url: monitor.url(), id: monitor.id, domain: site.domain },
];
dataStore.save("post-unsubscribe", queue);
// TODO: Move this to the store callback this once the unsubscribe flow is in place
_batchDisable(queue)
.then(function() {
_fetchAndRefresh();
});
break;
case 'manage':
// TODO
break;
}
}
/**
* Fetches updated sites and broadcasts event to refresh UI
*
* @method _fetchAndRefresh
*/
function _fetchAndRefresh() {
sitesService.get({refresh: true}).then(function(sites) {
$scope.disableBtn = false;
_updateFiltered();
//_updateAssociated(sites);
$scope.$broadcast(ITEM_LISTER_CONSTANTS.MONITOR_CHANGE_EVENT, sites );
});
}
/**
* Disable the monitors a few at a time so we don't flood the server or
* consume too much browser memory.
* @param { { url: string, id: string }[] } orders
* @returns
*/
function _batchDisable(orders) {
var status = {
error: [],
success: [],
};
return batch
.uniform(
orders, 2,
function removeMonitor(order) {
var monitor = sitesCache.findMonitor(order.domain, order.url);
if (monitor) {
monitor.state = MonitorState.Removing;
$scope.$applyAsync();
}
return monitoringAPI.disable(order.id, order.url);
},
function identity(order) {
return order.url;
},
function removeMonitorDone(order, error) {
var monitor = sitesCache.findMonitor(order.domain, order.url);
if (error) {
if (monitor) {
monitor.state = MonitorState.Error;
}
alertService.add({
type: "danger",
message: LOCALE.maketext("Failed to remove the monitor [_1] with the error: [_2]", monitor.url(), error),
closeable: true,
replace: false,
});
status.error.push(monitor);
} else {
if (monitor) {
monitor.state = MonitorState.Ready;
$scope.$applyAsync();
}
status.success.push(monitor);
}
}
)
.then(function(responses) {
if (status.success.length > 0 && status.error.length > 0) {
alertService.success({
message: LOCALE.maketext("The system successfully removed some of the requested monitors."),
replace: false
});
} else if (status.success.length > 0 && status.error.length === 0) {
alertService.success({
message: LOCALE.maketext("The system successfully removed the requested monitors."),
replace: false
});
}
});
}
/**
* Enable the monitors a few at a time so we don't flood the server or
* consume too much browser memory.
* @param { { url: string}[] } orders
* @returns
*/
function _batchEnable(orders) {
// Create placholder monitor rows
orders.forEach(function(order) {
var site = sitesCache.findByDomainName(order.domain);
if (site) {
var newMonitor = Monitor.parseItem({
url: order.fullUrl,
name: order.url,
type: MonitorType.https,
state: MonitorState.None,
});
site.addMonitor(newMonitor);
}
});
return contacts
.getStoreEmailAddress()
.then(
function(storeEmail) {
// CONSIDER: We should consider using the contacts email if the store one is not available.
if (!storeEmail) {
var message = LOCALE.maketext("The system could not find the an email address to use when setting up your monitors.");
alertService.add({
type: "danger",
message: message,
closeable: true,
replace: false,
});
throw new Error(message);
}
var status = {
error: [],
success: [],
};
return batch
.uniform(
orders, 2,
function createMonitor(order) {
var monitor = sitesCache.findMonitor(order.domain, order.fullUrl);
monitor.state = MonitorState.Creating;
$scope.$applyAsync();
return monitoringAPI.enable(order.url, null, [ storeEmail ]);
},
function identity(order) {
return order.url;
},
function createMonitorDone(order, error) {
var monitor = sitesCache.findMonitor(order.domain, order.fullUrl);
if (error) {
monitor.state = MonitorState.Error;
alertService.add({
type: "danger",
message: LOCALE.maketext("Failed to create the monitor [_1] with the error: [_2]", monitor.url, error),
closeable: true,
replace: false,
});
status.error.push(monitor);
} else {
monitor.state = MonitorState.Ready;
status.success.push(monitor);
}
$scope.$applyAsync();
}
)
.then(function(responses) {
if (status.success.length > 0 && status.error.length > 0) {
alertService.success({
message: LOCALE.maketext("The system successfully created some of the requested monitors."),
replace: false
});
} else if (status.success.length > 0 && status.error.length === 0) {
alertService.success({
message: LOCALE.maketext("The system successfully created the requested monitors."),
replace: false
});
}
});
}
);
}
/**
* Update the flag use to check if there are associated domains.
*
* QUESTION: Do we need this???
*
* @method _updateAssociated
* @param {Sites} sites
*/
function _updateAssociated(sites) {
associatedDomainsExist = sites.some(function(site) {
if (site.associatedAddonDomain) {
return true;
}
return false;
});
}
/**
* Handles other item events like changing selection.
*
* @method _itemListerUpdated
* @param {Event} event
* @param {*} parameters
*/
function _itemListerUpdated(event, parameters) {
// DOESN'T DO ANYTHING BESIDES CAUSE A CONSOLE ERROR ATM, UNCOMMENTED LINE THAT CALLS THIS
$scope.currentSearchFilterValue = parameters.meta.filterValue;
}
/**
* On updating of the show associated addon domains checkbox, refilter sites
*
* @private
* @method _filterAssociatedDomains
* @param {*} event
*/
function _filterAssociatedDomains(domain) {
if ($scope.showAssociatedSubdomains) {
return true;
}
if (!domain.associatedAddonDomain) {
return true;
}
return false;
}
var lastFiltered = true;
/**
* Reapply the filters based on new input from the user.
*
* @private
* @method _updateFiltered
*/
function _updateFiltered() {
var filteredSites = $filter("filter")(sitesCache.get(), _filterAssociatedDomains);
lastFiltered = $scope.showAssociatedSubdomains;
$scope.filteredSites = filteredSites;
}
/**
* Show and hide the associated subdomains for a domain.
*
* @scope
* @method toggleShowAssociatedSubdomains
*/
$scope.toggleShowAssociatedSubdomains = function toggleShowAssociatedSubdomains() {
$scope.showAssociatedSubdomains = !$scope.showAssociatedSubdomains;
$CSSS.set(COMPONENT_NAME, { showAssociatedSubdomains: $scope.showAssociatedSubdomains });
_updateFiltered();
_updateConfiguration();
}
/**
* Gets the list of sites to show in the view.
*
* @scope
* @method getSites
* @returns
*/
$scope.getSites = function getSites() {
if (lastFiltered !== $scope.showAssociatedSubdomains) {
_updateFiltered();
}
return $scope.filteredSites;
}
/**
* Updates the configuration array passed to the child component
*
* @method _updateConfiguration
* @private
* @returns
*/
function _updateConfiguration() {
// remove all items from config
$scope.configuration.splice(0);
if (!associatedDomainsExist) {
return;
}
if ($scope.showAssociatedSubdomains) {
$scope.configuration.push({
label: LOCALE.maketext("Hide Associated Subdomains"),
event: LIST_DOMAIN_EVENTS.HIDE_ASSOCIATED
});
} else {
$scope.configuration.push({
label: LOCALE.maketext("Show Associated Subdomains"),
event: LIST_DOMAIN_EVENTS.SHOW_ASSOCIATED
});
}
}
$scope.configuration = [];
_updateConfiguration();
$scope.$on(ITEM_LISTER_CONSTANTS.ITEM_CLICKED_EVENT, _itemChangeRequested);
//$scope.$on(ITEM_LISTER_CONSTANTS.ITEM_SELECT_EVENT, _itemListerUpdated);
$scope.$on(LIST_DOMAIN_EVENTS.SHOW_ASSOCIATED, $scope.toggleShowAssociatedSubdomains);
$scope.$on(LIST_DOMAIN_EVENTS.HIDE_ASSOCIATED, $scope.toggleShowAssociatedSubdomains);
$scope.showAssociatedSubdomains = false;
$scope.headers = [
{
field: "batchSelect",
class: "batch-select-column",
sortable: false,
label: null
},
{
field: "domain",
sortable: true,
class: "domain-column",
label: LOCALE.maketext("Site")
},
{
field: "documentRoot",
class: "docroot-column",
sortable: true,
label: LOCALE.maketext("Document Root"),
hiddenInSmall: true
},
{
field: "monitors",
class: "monitors-column",
sortable: true,
label: LOCALE.maketext("Monitors"),
hiddenInSmall: true
},
{
field: "actions",
class: "actions-column",
label: LOCALE.maketext("Actions"),
hiddenInSmall: true
}
];
$CSSS.register(COMPONENT_NAME)
.then(function _savedStateLoaded(config) {
if (config && $scope.showAssociatedSubdomains !== config.showAssociatedSubdomains) {
$scope.showAssociatedSubdomains = config.showAssociatedSubdomains;
_updateFiltered();
_updateConfiguration();
}
});
$scope.$on("$destroy", function() {
$CSSS.unregister(COMPONENT_NAME);
});
if (initialSites instanceof Error) {
alertService.add({
type: "danger",
message: initialSites.message,
closeable: true,
replace: true,
});
$scope.filteredSites = [];
} else {
$scope.filteredSites = initialSites;
}
}
]
);
return controller;
}
);
Back to Directory