<commit_before>// ==UserScript==
// @name        Be Still, Cody
// @namespace   http://chomperstomp.com
// @version     0.1.0+009
// @description Cut out the useless Chatter
// @author      Christopher McCulloh
// @contributor Chris Corwin
// @match       https://org62.my.salesforce.com/*
// @updateURL   https://raw.githubusercontent.com/cormacmccarthy/be-still-cody/master/headphones.user.js
// @require     http://code.jquery.com/jquery-latest.js
// @grant       none
// ==/UserScript==

// the @require above should take care of this
// var jquery = document.createElement('script');
// jquery.src = "https://code.jquery.com/jquery-latest.js";
// document.getElementsByTagName('head')[0].appendChild(jquery);

// Add dependancies
var addDependancies = function addDependancies() {
	var injectedStyles = [
		"https://maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap.min.css"
		//, "https:// NEED SOME WAY TO MAKE THIS USER-SPECIFIC AT BUILD TIME /headphones.user.css"
	];

	$.each(injectedStyles, function eachInjectedStyles(index, value) {
		$("head").append('<link href="' + value + '"' + ' rel="stylesheet" type="text/css">');
	});

	var injectedScripts = [
		"https://maxcdn.bootstrapcdn.com/bootstrap/3.2.0/js/bootstrap.min.js",
		"https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.8.3/moment.min.js",
		"https://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.7.0/underscore.js"
	];

	$.each(injectedScripts, function eachInjectedScripts(index, value) {
		$("head").append('');
	});
}
addDependancies();

var trashBS = function trashBS() {
	// make tabs easier to access by assigning their text as class names
	$('#tabBar li').each(function eachTabBarLi(i, el) {
		var $el = $(el);
		$el.addClass($el.text().toLowerCase());
	});
	// Trash BS
	['.brandZeronaryFgr',// trash logo
		'#Contract_Tab', '#AdvForecast_Tab', '#Opportunity_Tab', '#Contact_Tab', '#Account_Tab', '#Lead_Tab', '#Campaign_Tab', '#Case_Tab', '#Solution_Tab', '#report_Tab', '#Document_Tab', '#Workspace_Tab', '#ContentSearch_Tab', '#File_Tab', '#phHeader .left', '#bodyCell .links', '#presence_widget', '#tabBar .partner.applications', '#tabBar .sales.central', '#tabBar .companies', '.recElement.todoElement',// trash annoyingly bright yellow box thing
		'#section_header',// trash the amazing-space-eating "hide/show feed" button that for some reason needs its own huge bar. Well, trash the whole bar!
		'#ptBody',// trash pointless redundant egotistical feed header
		'.zen-branding',// trash logo
		'a[href^="javascript:openPopupFocusEscapePounds"]',// remove useless links to help docs
		'.chatterUserStatus',// trash redundant profile pic and link in Chatter
		'.headerContent'// trash pointless huge "salesforce.com" text and invisible header bar
	].forEach(function eachBS(el, i, bs) {
		$(el).remove();
	});
}
trashBS();

// Trash BS that loads really slowly
var trashSlowBS = function trashSlowBS() {
	['#presence_widget'].forEach(function eachPresenceWidget(el, i, bs) {
		$(el).remove();
	});

	$('.x-zen-tabMenu').addClass('nav').addClass('nav-pills');

	$('.feedcontainer .feeditemcommentplaceholder input').addClass('feedcontainerFeeditemcommentplaceholderInput');
	$('.feedcontainer .feeditemcommentplaceholder label span').addClass('feedcontainerFeeditemcommentplaceholderLabelSpan');
	$('.feedcontainer .feeditemcommentphoto img').addClass('feedcontainerFeeditemcommentphotoImg');
	$('.mainContentHeader').addClass('zen hidden');
	$('.headerContent').addClass('fade collapse');
	$('.zen-headerTop').addClass('pull-right');
	$('.zen-navViaMenus').addClass('pull-right');

	$('.leftContent ul').addClass('nav').addClass('nav-pills').addClass('nav-stacked');
	$('.selected').addClass('active').removeClass('selected');
	$('.zen-active').addClass('active').removeClass('zen-active');
	$('.zen-assistiveText').addClass('sr-only').removeClass('zen-assistiveText');
	$('.x-zen-assistiveText').addClass('sr-only').removeClass('x-zen-assistiveText');
	$('.brandPrimaryBgr').removeClass('brandPrimaryBgr');
	$('.primaryPalette').removeClass('primaryPalette');
	$('.zen-bodyZen').addClass('panel').addClass('panel-default').removeClass('zen-bodyZen').removeClass('brdPalette').removeClass('brandPrimaryBrd');
	$('.zen-navMenus').addClass('zen');
	$('.zen-bodyInner').addClass('panel-body').removeClass('zen-bodyInner');
	$('.leftContent').addClass('well');
	$('#rightContent').addClass('panel').addClass('panel-default');
	$('#rightContent > div').addClass('panel-body');
	$('html').addClass('fuelux').removeClass('zen');
	$('.zen-page > div > header').addClass('zen well');
	$('.menuButtonRounded').addClass('dropdown').removeClass('menuButtonRounded');
	$('.menuButtonButton').addClass('btn btn-primary dropdown-toggle').removeClass('menuButtonButton');
	$('link[href="/sCSS/33.0/sprites/1423103332000/Theme3/default/gc/zenifiedChatterPageBase.css"').remove();
	$('.feeditem').addClass('panel panel-default').removeClass('feeditem');
	$('.feeditemusericon').parent('a').parent('span').wrap('

');
	$('.feeditemusericon').removeClass('feeditemusericon');
	$('.feeditemcontent').addClass('panel-body').removeClass('feeditemcontent');
	$('.feeditemextras').addClass('well').removeClass('feeditemextras');
	$('.feeditemcomments').removeClass('feeditemcomments');
	$('.feeditemcomment').removeClass('feeditemcomment').addClass('panel panel-info');
	$('.feeditemcommentbody').removeClass('feeditemcommentbody').addClass('panel-body');
	$('.feeditemcommentphoto').addClass('pull-left');
	$('.feeditemcommentplaceholder').addClass('well').removeClass('feeditemcommentplaceholder');
	$('.newCommentContainer').addClass('well');
	$('.headerSearchLeftRoundedCorner').removeClass('headerSearchLeftRoundedCorner');

	window.setTimeout(trashSlowBS, 2000);
}
trashSlowBS();

var attachChatterChanges = function attachChatterChanges() {
	chatter.ext_Feed.muteItem = function muteItem(element, c) {
		// var b = $(element).closest(".cxfeeditem").data('feedItem').feeditemtype;
		var toolbox = chatter.getToolbox();
		toolbox.mask(Ext.fly(element));
		toolbox.post({
			url: "/feeditems/" + c + "/mute",
			success: function toolboxPostSuccess(b, c) {
				$(element)
					.closest('.cxfeeditem')
					.remove();
			}
		});
		chatter.getEventBus()
			.fireEvent("chatter:feed", "onAfterDeleteFeedItem", {
				el: this
			})
	};
}
window.setTimeout(attachChatterChanges, 4500);

var betterMuteButton = function betterMuteButton() {
	$('.feeditem')
		.each(function eachFeedItem(i, el) {
			var $el = $(el);
			if ($el.find('.hideFeedItem')
					.length <= 0) {
				var id = $el[0].id;
				$el.find('.preamblecontainer.displayblock')
					.append('hide');
			}
		});
	$('.hideFeedItem')
		.on('click', function onClickHideFeedItem(e) {
			e.preventDefault();
			chatter.getFeed()
				.muteItem(this, $(this)
					.data('id'));
		});
	window.setTimeout(betterMuteButton, 4500);
}
betterMuteButton();
$('.cxshowmorefeeditemscontainer.showmorefeeditemscontainer a')
	.on('click', function callBetterMuteButton(e) {
		window.setTimeout(betterMuteButton, 4500);
	});

// Add some handy string manipulation stuff to JavaScript itself.
String.prototype.endsWith = function endsWith(value) {
	if (this.length < value.length) {
		return false;
	} else {
		return Boolean(this.substr(this.length - value.length, value.length + 1) === value);
	}
};
String.prototype.contains = function contains(value, caseFlag) {
	if (this.length < value.length) {
		return false;
	} else {
		var regExPattern_value = caseFlag === false ? new RegExp(value, "i") : new RegExp(value);
		return Boolean(this.match(regExPattern_value));
	}
};

String.prototype.beginsWith = function beginsWith(string) {
	return this.indexOf(string) === 0;
};

// Make a jQuery class stripper.
var disableZen = function disableZen(el) {
	prefix = "zen-";
	var $zenElements = $(el);
	$zenElements.each(function disableEachZenElement(i, el) {
		var $thisElement = $(el);

		var oldClassNames = $thisElement.attr("class").split(" ");
		var newClassNames = "";
		$thisElement.attr("data-previous-class-names", $thisElement.attr("class"));
		$.each(oldClassNames, function (index, value) {
			if (value.beginsWith(prefix)) {
				newClassNames = newClassNames + " " + "x-" + value;
				$thisElement.attr( ("data-had-zen-class-" + value), "true");
			}
		});
		el.className = newClassNames;
	});
	return $zenElements;
};
disableZen();

var removeZenPrefix = function removeZenPrefix(el) {
	prefix = "zen-";
	var $zenElements = $(el);
	$zenElements.each(function removeEachZenElement(i, el) {
		var classes = el.className.split(" ").filter(function (c) {
			console.log("c.lastIndexOf( prefix, 0 )", c.lastIndexOf(prefix, 0));
			console.log("c.lastIndexOf( prefix, 0 ) !== 0", c.lastIndexOf(prefix, 0) !== 0);
			return c.lastIndexOf(prefix, 0) !== 0;
		});
		el.className = $.trim(classes.join(" "));
	});
	return $zenElements;
};
removeZenPrefix();
<commit_msg>(master) wait to initialize chatter bound stuff until chatter exists on page<commit_after>// ==UserScript==
// @name        Be Still, Cody
// @namespace   http://chomperstomp.com
// @version     0.1.0+010
// @description Cut out the useless Chatter
// @author      Christopher McCulloh
// @contributor Chris Corwin
// @match       https://org62.my.salesforce.com/*
// @updateURL   https://raw.githubusercontent.com/cormacmccarthy/be-still-cody/master/headphones.user.js
// @require     http://code.jquery.com/jquery-latest.js
// @grant       none
// ==/UserScript==

// the @require above should take care of this
// var jquery = document.createElement('script');
// jquery.src = "https://code.jquery.com/jquery-latest.js";
// document.getElementsByTagName('head')[0].appendChild(jquery);

// Add dependancies
var addDependancies = function addDependancies() {
	var injectedStyles = [
		"https://maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap.min.css"
		//, "https:// NEED SOME WAY TO MAKE THIS USER-SPECIFIC AT BUILD TIME /headphones.user.css"
	];

	$.each(injectedStyles, function eachInjectedStyles(index, value) {
		$("head").append('<link href="' + value + '"' + ' rel="stylesheet" type="text/css">');
	});

	var injectedScripts = [
		"https://maxcdn.bootstrapcdn.com/bootstrap/3.2.0/js/bootstrap.min.js",
		"https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.8.3/moment.min.js",
		"https://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.7.0/underscore.js"
	];

	$.each(injectedScripts, function eachInjectedScripts(index, value) {
		$("head").append('');
	});
}
addDependancies();

var trashBS = function trashBS() {
	// make tabs easier to access by assigning their text as class names
	$('#tabBar li').each(function eachTabBarLi(i, el) {
		var $el = $(el);
		$el.addClass($el.text().toLowerCase());
	});
	// Trash BS
	['.brandZeronaryFgr',// trash logo
		'#Contract_Tab', '#AdvForecast_Tab', '#Opportunity_Tab', '#Contact_Tab', '#Account_Tab', '#Lead_Tab', '#Campaign_Tab', '#Case_Tab', '#Solution_Tab', '#report_Tab', '#Document_Tab', '#Workspace_Tab', '#ContentSearch_Tab', '#File_Tab', '#phHeader .left', '#bodyCell .links', '#presence_widget', '#tabBar .partner.applications', '#tabBar .sales.central', '#tabBar .companies', '.recElement.todoElement',// trash annoyingly bright yellow box thing
		'#section_header',// trash the amazing-space-eating "hide/show feed" button that for some reason needs its own huge bar. Well, trash the whole bar!
		'#ptBody',// trash pointless redundant egotistical feed header
		'.zen-branding',// trash logo
		'a[href^="javascript:openPopupFocusEscapePounds"]',// remove useless links to help docs
		'.chatterUserStatus',// trash redundant profile pic and link in Chatter
		'.headerContent'// trash pointless huge "salesforce.com" text and invisible header bar
	].forEach(function eachBS(el, i, bs) {
		$(el).remove();
	});
}
trashBS();

// Trash BS that loads really slowly
var trashSlowBS = function trashSlowBS() {
	['#presence_widget'].forEach(function eachPresenceWidget(el, i, bs) {
		$(el).remove();
	});

	$('.x-zen-tabMenu').addClass('nav').addClass('nav-pills');

	$('.feedcontainer .feeditemcommentplaceholder input').addClass('feedcontainerFeeditemcommentplaceholderInput');
	$('.feedcontainer .feeditemcommentplaceholder label span').addClass('feedcontainerFeeditemcommentplaceholderLabelSpan');
	$('.feedcontainer .feeditemcommentphoto img').addClass('feedcontainerFeeditemcommentphotoImg');
	$('.mainContentHeader').addClass('zen hidden');
	$('.headerContent').addClass('fade collapse');
	$('.zen-headerTop').addClass('pull-right');
	$('.zen-navViaMenus').addClass('pull-right');

	$('.leftContent ul').addClass('nav').addClass('nav-pills').addClass('nav-stacked');
	$('.selected').addClass('active').removeClass('selected');
	$('.zen-active').addClass('active').removeClass('zen-active');
	$('.zen-assistiveText').addClass('sr-only').removeClass('zen-assistiveText');
	$('.x-zen-assistiveText').addClass('sr-only').removeClass('x-zen-assistiveText');
	$('.brandPrimaryBgr').removeClass('brandPrimaryBgr');
	$('.primaryPalette').removeClass('primaryPalette');
	$('.zen-bodyZen').addClass('panel').addClass('panel-default').removeClass('zen-bodyZen').removeClass('brdPalette').removeClass('brandPrimaryBrd');
	$('.zen-navMenus').addClass('zen');
	$('.zen-bodyInner').addClass('panel-body').removeClass('zen-bodyInner');
	$('.leftContent').addClass('well');
	$('#rightContent').addClass('panel').addClass('panel-default');
	$('#rightContent > div').addClass('panel-body');
	$('html').addClass('fuelux').removeClass('zen');
	$('.zen-page > div > header').addClass('zen well');
	$('.menuButtonRounded').addClass('dropdown').removeClass('menuButtonRounded');
	$('.menuButtonButton').addClass('btn btn-primary dropdown-toggle').removeClass('menuButtonButton');
	$('link[href="/sCSS/33.0/sprites/1423103332000/Theme3/default/gc/zenifiedChatterPageBase.css"').remove();
	$('.feeditem').addClass('panel panel-default').removeClass('feeditem');
	$('.feeditemusericon').parent('a').parent('span').wrap('

');
	$('.feeditemusericon').removeClass('feeditemusericon');
	$('.feeditemcontent').addClass('panel-body').removeClass('feeditemcontent');
	$('.feeditemextras').addClass('well').removeClass('feeditemextras');
	$('.feeditemcomments').removeClass('feeditemcomments');
	$('.feeditemcomment').removeClass('feeditemcomment').addClass('panel panel-info');
	$('.feeditemcommentbody').removeClass('feeditemcommentbody').addClass('panel-body');
	$('.feeditemcommentphoto').addClass('pull-left');
	$('.feeditemcommentplaceholder').addClass('well').removeClass('feeditemcommentplaceholder');
	$('.newCommentContainer').addClass('well');
	$('.headerSearchLeftRoundedCorner').removeClass('headerSearchLeftRoundedCorner');

	window.setTimeout(trashSlowBS, 2000);
}
trashSlowBS();

var betterMuteButton = function betterMuteButton() {
	$('.feeditem')
		.each(function eachFeedItem(i, el) {
			var $el = $(el);
			if ($el.find('.hideFeedItem')
					.length <= 0) {
				var id = $el[0].id;
				$el.find('.preamblecontainer.displayblock')
					.append('hide');
			}
		});
	$('.hideFeedItem')
		.on('click', function onClickHideFeedItem(e) {
			e.preventDefault();
			chatter.getFeed()
				.muteItem(this, $(this)
					.data('id'));
		});
	window.setTimeout(betterMuteButton, 4500);
}

var attachChatterChanges = function attachChatterChanges() {
	if (typeof chatter === "undefined") {
		window.setTimeout(attachChatterChanges, 500);
		console.log("chatter:" + chatter)
		return;
	}

	chatter.ext_Feed.muteItem = function muteItem(element, c) {
		// var b = $(element).closest(".cxfeeditem").data('feedItem').feeditemtype;
		var toolbox = chatter.getToolbox();
		toolbox.mask(Ext.fly(element));
		toolbox.post({
			url: "/feeditems/" + c + "/mute",
			success: function toolboxPostSuccess(b, c) {
				$(element)
					.closest('.cxfeeditem')
					.remove();
			}
		});
		chatter.getEventBus()
			.fireEvent("chatter:feed", "onAfterDeleteFeedItem", {
				el: this
			})
	};

	betterMuteButton();
}
window.setTimeout(attachChatterChanges, 4500);

$('.cxshowmorefeeditemscontainer.showmorefeeditemscontainer a')
	.on('click', function callBetterMuteButton(e) {
		window.setTimeout(betterMuteButton, 4500);
	});

// Add some handy string manipulation stuff to JavaScript itself.
String.prototype.endsWith = function endsWith(value) {
	if (this.length < value.length) {
		return false;
	} else {
		return Boolean(this.substr(this.length - value.length, value.length + 1) === value);
	}
};
String.prototype.contains = function contains(value, caseFlag) {
	if (this.length < value.length) {
		return false;
	} else {
		var regExPattern_value = caseFlag === false ? new RegExp(value, "i") : new RegExp(value);
		return Boolean(this.match(regExPattern_value));
	}
};

String.prototype.beginsWith = function beginsWith(string) {
	return this.indexOf(string) === 0;
};

// Make a jQuery class stripper.
var disableZen = function disableZen(el) {
	prefix = "zen-";
	var $zenElements = $(el);
	$zenElements.each(function disableEachZenElement(i, el) {
		var $thisElement = $(el);

		var oldClassNames = $thisElement.attr("class").split(" ");
		var newClassNames = "";
		$thisElement.attr("data-previous-class-names", $thisElement.attr("class"));
		$.each(oldClassNames, function (index, value) {
			if (value.beginsWith(prefix)) {
				newClassNames = newClassNames + " " + "x-" + value;
				$thisElement.attr( ("data-had-zen-class-" + value), "true");
			}
		});
		el.className = newClassNames;
	});
	return $zenElements;
};
disableZen();

var removeZenPrefix = function removeZenPrefix(el) {
	prefix = "zen-";
	var $zenElements = $(el);
	$zenElements.each(function removeEachZenElement(i, el) {
		var classes = el.className.split(" ").filter(function (c) {
			console.log("c.lastIndexOf( prefix, 0 )", c.lastIndexOf(prefix, 0));
			console.log("c.lastIndexOf( prefix, 0 ) !== 0", c.lastIndexOf(prefix, 0) !== 0);
			return c.lastIndexOf(prefix, 0) !== 0;
		});
		el.className = $.trim(classes.join(" "));
	});
	return $zenElements;
};
removeZenPrefix();
<|endoftext|>


<commit_before>/**
 *
 *    Copyright (c) 2020 Silicon Labs
 *
 *    Licensed 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
 *
 *        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.
 */

/**
 * This module provides queries related to imports and exports of files.
 *
 * @module DB API: package-based queries.
 */
const dbApi = require('./db-api.js')
const env = require('../util/env.js')

/**
 * Imports a single endpoint
 * @param {} db
 * @param {*} sessionId
 * @param {*} endpoint
 * @param {*} endpointTypeRef
 */
function importEndpoint(db, sessionId, endpoint, endpointTypeRef) {
  return dbApi.dbInsert(
    db,
    `
INSERT INTO ENDPOINT (
  SESSION_REF,
  ENDPOINT_TYPE_REF,
  PROFILE,
  ENDPOINT_IDENTIFIER,
  NETWORK_IDENTIFIER
) VALUES (
  ?,
  ?,
  ?,
  ?,
  ?
)
  `,
    [
      sessionId,
      endpointTypeRef,
      endpoint.profileId,
      endpoint.endpointId,
      endpoint.networkId,
    ]
  )
}

/**
 * Extracts endpoints.
 *
 * @param {*} db
 * @param {*} sessionId
 */
function exportEndpoints(db, sessionId, endpointTypes) {
  var endpointTypeIndex = (endpointTypes, endpointTypeRef) => {
    return endpointTypes.findIndex(
      (value) => value.endpointTypeId == endpointTypeRef
    )
  }

  var mapFunction = (x) => {
    return {
      endpointTypeName: x.NAME,
      endpointTypeIndex: endpointTypeIndex(endpointTypes, x.ENDPOINT_TYPE_REF),
      profileId: x.PROFILE,
      endpointId: x.ENDPOINT_IDENTIFIER,
      networkId: x.NETWORK_IDENTIFIER,
    }
  }
  return dbApi
    .dbAll(
      db,
      `
SELECT
  ENDPOINT_TYPE.NAME,
  ENDPOINT.ENDPOINT_TYPE_REF,
  ENDPOINT.PROFILE,
  ENDPOINT.ENDPOINT_IDENTIFIER,
  ENDPOINT.NETWORK_IDENTIFIER
FROM
  ENDPOINT
LEFT JOIN
  ENDPOINT_TYPE
ON
  ENDPOINT.ENDPOINT_TYPE_REF = ENDPOINT_TYPE.ENDPOINT_TYPE_ID
WHERE
  ENDPOINT.SESSION_REF = ?
    `,
      [sessionId]
    )
    .then((rows) => rows.map(mapFunction))
}

/**
 * Extracts raw endpoint types rows.
 *
 * @export
 * @param {*} db
 * @param {*} sessionId
 * @returns promise that resolves into rows in the database table.
 */
function exportEndpointTypes(db, sessionId) {
  var mapFunction = (x) => {
    return {
      endpointTypeId: x.ENDPOINT_TYPE_ID,
      name: x.NAME,
      deviceTypeName: x.DEVICE_TYPE_NAME,
      deviceTypeCode: x.DEVICE_TYPE_CODE,
    }
  }
  return dbApi
    .dbAll(
      db,
      `
SELECT
  ENDPOINT_TYPE.ENDPOINT_TYPE_ID,
  ENDPOINT_TYPE.NAME,
  ENDPOINT_TYPE.DEVICE_TYPE_REF,
  DEVICE_TYPE.CODE AS DEVICE_TYPE_CODE,
  DEVICE_TYPE.NAME AS DEVICE_TYPE_NAME
FROM
  ENDPOINT_TYPE
LEFT JOIN
  DEVICE_TYPE
ON
  ENDPOINT_TYPE.DEVICE_TYPE_REF = DEVICE_TYPE.DEVICE_TYPE_ID
WHERE ENDPOINT_TYPE.SESSION_REF = ? ORDER BY ENDPOINT_TYPE.NAME`,
      [sessionId]
    )
    .then((rows) => rows.map(mapFunction))
}

/**
 * Imports an endpoint type, resolving other data along the way.
 *
 * @param {*} db
 * @param {*} sessionId
 * @param {*} packageId
 * @param {*} endpointType
 * @returns Promise of endpoint insertion.
 */
function importEndpointType(db, sessionId, packageId, endpointType) {
  // Each endpoint has: 'name', 'deviceTypeName', 'deviceTypeCode', 'clusters', 'commands', 'attributes'
  return dbApi.dbInsert(
    db,
    `
INSERT INTO ENDPOINT_TYPE (
  SESSION_REF,
  NAME,
  DEVICE_TYPE_REF
) VALUES(
  ?,
  ?,
  (SELECT DEVICE_TYPE_ID FROM DEVICE_TYPE WHERE CODE = ? AND PACKAGE_REF = ?)
)`,
    [sessionId, endpointType.name, endpointType.deviceTypeCode, packageId]
  )
}

/**
 * Exports packages for externalized form.
 *
 * @param {*} db
 * @param {*} sessionId
 * @returns Promise of a data that is listing all the packages in the session.
 */
function exportPackagesFromSession(db, sessionId) {
  var mapFunction = (x) => {
    return {
      path: x.PATH,
      version: x.VERSION,
      type: x.TYPE,
    }
  }
  return dbApi
    .dbAll(
      db,
      `
SELECT
  PACKAGE.PATH,
  PACKAGE.VERSION,
  PACKAGE.TYPE
FROM PACKAGE
INNER JOIN SESSION_PACKAGE
ON PACKAGE.PACKAGE_ID = SESSION_PACKAGE.PACKAGE_REF
WHERE SESSION_PACKAGE.SESSION_REF = ?`,
      [sessionId]
    )
    .then((rows) => rows.map(mapFunction))
}

/**
 * Exports clusters to an externalized form.
 *
 * @param {*} db
 * @param {*} endpointTypeId
 * @returns Promise that resolves with the data that should go into the external form.
 */
function exportClustersFromEndpointType(db, endpointTypeId) {
  var mapFunction = (x) => {
    return {
      name: x.NAME,
      code: x.CODE,
      mfgCode: x.MANUFACTURER_CODE,
      side: x.SIDE,
      enabled: x.ENABLED,
      endpointClusterId: x.ENDPOINT_TYPE_CLUSTER_ID,
    }
  }

  return dbApi
    .dbAll(
      db,
      `
SELECT
  CLUSTER.CODE,
  CLUSTER.MANUFACTURER_CODE,
  CLUSTER.NAME,
  ENDPOINT_TYPE_CLUSTER.SIDE,
  ENDPOINT_TYPE_CLUSTER.ENABLED,
  ENDPOINT_TYPE_CLUSTER.ENDPOINT_TYPE_CLUSTER_ID
FROM CLUSTER
INNER JOIN ENDPOINT_TYPE_CLUSTER
ON CLUSTER.CLUSTER_ID = ENDPOINT_TYPE_CLUSTER.CLUSTER_REF
WHERE ENDPOINT_TYPE_CLUSTER.ENDPOINT_TYPE_REF = ?`,
      [endpointTypeId]
    )
    .then((rows) => rows.map(mapFunction))
}

/**
 * Imports a single cluster to endpoint type.
 *
 * @param {*} db
 * @param {*} endpointTypeId
 * @param {*} cluster Object populated same way as export method leaves it.
 * @returns Promise of an imported cluster.
 */
function importClusterForEndpointType(db, packageId, endpointTypeId, cluster) {
  return dbApi.dbInsert(
    db,
    `
INSERT INTO ENDPOINT_TYPE_CLUSTER
  (ENDPOINT_TYPE_REF, CLUSTER_REF, SIDE, ENABLED)
VALUES
  (?,
   (SELECT CLUSTER_ID FROM CLUSTER WHERE PACKAGE_REF = ? AND CODE = ? AND ${
     cluster.mfgCode == null
       ? 'MANUFACTURER_CODE IS NULL'
       : 'MANUFACTURER_CODE = ?'
   }),
   ?,
   ?)`,
    cluster.mfgCode == null
      ? [endpointTypeId, packageId, cluster.code, cluster.side, cluster.enabled]
      : [
          endpointTypeId,
          packageId,
          cluster.code,
          cluster.mfgCode,
          cluster.side,
          cluster.enabled,
        ]
  )
}

/**
 * Returns a promise of data for attributes inside an endpoint type.
 *
 * @param {*} db
 * @param {*} endpointTypeId
 * @returns Promise that resolves with the attribute data.
 */
function exportAttributesFromEndpointTypeCluster(
  db,
  endpointTypeId,
  endpointClusterId
) {
  var mapFunction = (x) => {
    return {
      name: x.NAME,
      code: x.CODE,
      mfgCode: x.MANUFACTURER_CODE,
      included: x.INCLUDED,
      storageOption: x.STORAGE_OPTION,
      singleton: x.SINGLETON,
      bounded: x.BOUNDED,
      defaultValue: x.DEFAULT_VALUE,
      reportable: x.INCLUDED_REPORTABLE,
      minInterval: x.MIN_INTERVAL,
      maxInterval: x.MAX_INTERVAL,
      reportableChange: x.REPORTABLE_CHANGE,
    }
  }
  return dbApi
    .dbAll(
      db,
      `
SELECT
  ATTRIBUTE.NAME,
  ATTRIBUTE.CODE,
  ATTRIBUTE.MANUFACTURER_CODE,
  ENDPOINT_TYPE_ATTRIBUTE.INCLUDED,
  ENDPOINT_TYPE_ATTRIBUTE.STORAGE_OPTION,
  ENDPOINT_TYPE_ATTRIBUTE.SINGLETON,
  ENDPOINT_TYPE_ATTRIBUTE.BOUNDED,
  ENDPOINT_TYPE_ATTRIBUTE.DEFAULT_VALUE,
  ENDPOINT_TYPE_ATTRIBUTE.INCLUDED_REPORTABLE,
  ENDPOINT_TYPE_ATTRIBUTE.MIN_INTERVAL,
  ENDPOINT_TYPE_ATTRIBUTE.MAX_INTERVAL,
  ENDPOINT_TYPE_ATTRIBUTE.REPORTABLE_CHANGE
FROM ATTRIBUTE
INNER JOIN ENDPOINT_TYPE_ATTRIBUTE
ON ATTRIBUTE.ATTRIBUTE_ID = ENDPOINT_TYPE_ATTRIBUTE.ATTRIBUTE_REF
WHERE ENDPOINT_TYPE_ATTRIBUTE.ENDPOINT_TYPE_REF = ?
      AND ENDPOINT_TYPE_ATTRIBUTE.ENDPOINT_TYPE_CLUSTER_REF = ?
    `,
      [endpointTypeId, endpointClusterId]
    )
    .then((rows) => rows.map(mapFunction))
}

/**
 * Imports an attribute information of an endpoint type.
 *
 * @param {*} db
 * @param {*} packageId
 * @param {*} endpointTypeId
 * @param {*} endpointClusterId may be null if global attribute
 * @param {*} attribute
 * @returns Promise of an attribute insertion.
 */
function importAttributeForEndpointType(
  db,
  packageId,
  endpointTypeId,
  endpointClusterId,
  attribute
) {
  var arg = [
    endpointTypeId,
    endpointClusterId,
    attribute.code,
    packageId,
    endpointClusterId,
  ]
  if (attribute.mfgCode != null) arg.push(attribute.mfgCode)
  arg.push(
    attribute.included,
    attribute.storageOption,
    attribute.singleton,
    attribute.bounded,
    attribute.defaultValue,
    attribute.reportable,
    attribute.minInterval,
    attribute.maxInterval,
    attribute.reportableChange
  )
  return dbApi.dbInsert(
    db,
    `
INSERT INTO ENDPOINT_TYPE_ATTRIBUTE
( ENDPOINT_TYPE_REF,
  ENDPOINT_TYPE_CLUSTER_REF,
  ATTRIBUTE_REF,
  INCLUDED,
  STORAGE_OPTION,
  SINGLETON,
  BOUNDED,
  DEFAULT_VALUE,
  INCLUDED_REPORTABLE,
  MIN_INTERVAL,
  MAX_INTERVAL,
  REPORTABLE_CHANGE )
VALUES
( ?, ?,
  ( SELECT ATTRIBUTE_ID FROM ATTRIBUTE, ENDPOINT_TYPE_CLUSTER
    WHERE ATTRIBUTE.CODE = ?
    AND ATTRIBUTE.PACKAGE_REF = ?
    AND ENDPOINT_TYPE_CLUSTER.ENDPOINT_TYPE_CLUSTER_ID = ?
    AND ENDPOINT_TYPE_CLUSTER.CLUSTER_REF = ATTRIBUTE.CLUSTER_REF
    AND ${
      attribute.mfgCode == null
        ? 'MANUFACTURER_CODE IS NULL'
        : 'MANUFACTURER_CODE = ?'
    }),
    ?, ?, ?, ?, ?, ?, ?, ?, ?)
  `,
    arg
  )
}

/**
 * Returns a promise of data for commands inside an endpoint type.
 *
 * @param {*} db
 * @param {*} endpointTypeId
 * @returns Promise that resolves with the command data.
 */
function exportCommandsFromEndpointTypeCluster(
  db,
  endpointTypeId,
  endpointClusterId
) {
  var mapFunction = (x) => {
    return {
      name: x.NAME,
      code: x.CODE,
      mfgCode: x.MANUFACTURER_CODE,
      source: x.SOURCE,
      incoming: x.INCOMING,
      outgoing: x.OUTGOING,
    }
  }
  return dbApi
    .dbAll(
      db,
      `
  SELECT
    COMMAND.NAME,
    COMMAND.CODE,
    COMMAND.MANUFACTURER_CODE,
    COMMAND.SOURCE,
    ENDPOINT_TYPE_COMMAND.INCOMING,
    ENDPOINT_TYPE_COMMAND.OUTGOING
  FROM COMMAND
  INNER JOIN ENDPOINT_TYPE_COMMAND
  ON COMMAND.COMMAND_ID = ENDPOINT_TYPE_COMMAND.COMMAND_REF
  WHERE ENDPOINT_TYPE_COMMAND.ENDPOINT_TYPE_REF = ? AND ENDPOINT_TYPE_COMMAND.ENDPOINT_TYPE_CLUSTER_REF = ?
        `,
      [endpointTypeId, endpointClusterId]
    )
    .then((rows) => rows.map(mapFunction))
}

/**
 * Imports a command information of an endpoint type.
 *
 * @param {*} db
 * @param {*} packageId
 * @param {*} endpointTypeId
 * @param {*} endpointClusterId may be null if global command
 * @param {*} command
 * @returns Promise of a command insertion.
 */
function importCommandForEndpointType(
  db,
  packageId,
  endpointTypeId,
  endpointClusterId,
  command
) {
  console.log(command)
  var arg = [
    endpointTypeId,
    endpointClusterId,
    command.code,
    command.source,
    packageId,
    endpointClusterId,
  ]
  if (command.mfgCode != null) arg.push(command.mfgCode)
  arg.push(command.incoming, command.outgoing)
  console.log(command)
  console.log(arg)
  return dbApi.dbInsert(
    db,
    `
INSERT INTO ENDPOINT_TYPE_COMMAND
( ENDPOINT_TYPE_REF,
  ENDPOINT_TYPE_CLUSTER_REF,
  COMMAND_REF,
  INCOMING,
  OUTGOING )
VALUES
  ( ?, ?,
    ( SELECT COMMAND_ID
      FROM COMMAND, ENDPOINT_TYPE_CLUSTER WHERE
        COMMAND.CODE = ?
        AND COMMAND.SOURCE = ?
        AND COMMAND.PACKAGE_REF = ?
        AND ENDPOINT_TYPE_CLUSTER.ENDPOINT_TYPE_CLUSTER_ID = ?
        AND COMMAND.CLUSTER_REF = ENDPOINT_TYPE_CLUSTER.CLUSTER_REF
        AND ${
          command.mfgCode == null
            ? 'MANUFACTURER_CODE IS NULL'
            : 'MANUFACTURER_CODE = ?'
        }),
    ?,
    ?
    )
  `,
    arg
  )
}

exports.exportEndpointTypes = exportEndpointTypes
exports.importEndpointType = importEndpointType

exports.exportClustersFromEndpointType = exportClustersFromEndpointType
exports.importClusterForEndpointType = importClusterForEndpointType

exports.exportPackagesFromSession = exportPackagesFromSession

exports.exportAttributesFromEndpointTypeCluster = exportAttributesFromEndpointTypeCluster
exports.importAttributeForEndpointType = importAttributeForEndpointType

exports.exportCommandsFromEndpointTypeCluster = exportCommandsFromEndpointTypeCluster
exports.importCommandForEndpointType = importCommandForEndpointType

exports.exportEndpoints = exportEndpoints
exports.importEndpoint = importEndpoint
<commit_msg>NOJIRA Remove extraneous logging<commit_after>/**
 *
 *    Copyright (c) 2020 Silicon Labs
 *
 *    Licensed 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
 *
 *        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.
 */

/**
 * This module provides queries related to imports and exports of files.
 *
 * @module DB API: package-based queries.
 */
const dbApi = require('./db-api.js')
const env = require('../util/env.js')

/**
 * Imports a single endpoint
 * @param {} db
 * @param {*} sessionId
 * @param {*} endpoint
 * @param {*} endpointTypeRef
 */
function importEndpoint(db, sessionId, endpoint, endpointTypeRef) {
  return dbApi.dbInsert(
    db,
    `
INSERT INTO ENDPOINT (
  SESSION_REF,
  ENDPOINT_TYPE_REF,
  PROFILE,
  ENDPOINT_IDENTIFIER,
  NETWORK_IDENTIFIER
) VALUES (
  ?,
  ?,
  ?,
  ?,
  ?
)
  `,
    [
      sessionId,
      endpointTypeRef,
      endpoint.profileId,
      endpoint.endpointId,
      endpoint.networkId,
    ]
  )
}

/**
 * Extracts endpoints.
 *
 * @param {*} db
 * @param {*} sessionId
 */
function exportEndpoints(db, sessionId, endpointTypes) {
  var endpointTypeIndex = (endpointTypes, endpointTypeRef) => {
    return endpointTypes.findIndex(
      (value) => value.endpointTypeId == endpointTypeRef
    )
  }

  var mapFunction = (x) => {
    return {
      endpointTypeName: x.NAME,
      endpointTypeIndex: endpointTypeIndex(endpointTypes, x.ENDPOINT_TYPE_REF),
      profileId: x.PROFILE,
      endpointId: x.ENDPOINT_IDENTIFIER,
      networkId: x.NETWORK_IDENTIFIER,
    }
  }
  return dbApi
    .dbAll(
      db,
      `
SELECT
  ENDPOINT_TYPE.NAME,
  ENDPOINT.ENDPOINT_TYPE_REF,
  ENDPOINT.PROFILE,
  ENDPOINT.ENDPOINT_IDENTIFIER,
  ENDPOINT.NETWORK_IDENTIFIER
FROM
  ENDPOINT
LEFT JOIN
  ENDPOINT_TYPE
ON
  ENDPOINT.ENDPOINT_TYPE_REF = ENDPOINT_TYPE.ENDPOINT_TYPE_ID
WHERE
  ENDPOINT.SESSION_REF = ?
    `,
      [sessionId]
    )
    .then((rows) => rows.map(mapFunction))
}

/**
 * Extracts raw endpoint types rows.
 *
 * @export
 * @param {*} db
 * @param {*} sessionId
 * @returns promise that resolves into rows in the database table.
 */
function exportEndpointTypes(db, sessionId) {
  var mapFunction = (x) => {
    return {
      endpointTypeId: x.ENDPOINT_TYPE_ID,
      name: x.NAME,
      deviceTypeName: x.DEVICE_TYPE_NAME,
      deviceTypeCode: x.DEVICE_TYPE_CODE,
    }
  }
  return dbApi
    .dbAll(
      db,
      `
SELECT
  ENDPOINT_TYPE.ENDPOINT_TYPE_ID,
  ENDPOINT_TYPE.NAME,
  ENDPOINT_TYPE.DEVICE_TYPE_REF,
  DEVICE_TYPE.CODE AS DEVICE_TYPE_CODE,
  DEVICE_TYPE.NAME AS DEVICE_TYPE_NAME
FROM
  ENDPOINT_TYPE
LEFT JOIN
  DEVICE_TYPE
ON
  ENDPOINT_TYPE.DEVICE_TYPE_REF = DEVICE_TYPE.DEVICE_TYPE_ID
WHERE ENDPOINT_TYPE.SESSION_REF = ? ORDER BY ENDPOINT_TYPE.NAME`,
      [sessionId]
    )
    .then((rows) => rows.map(mapFunction))
}

/**
 * Imports an endpoint type, resolving other data along the way.
 *
 * @param {*} db
 * @param {*} sessionId
 * @param {*} packageId
 * @param {*} endpointType
 * @returns Promise of endpoint insertion.
 */
function importEndpointType(db, sessionId, packageId, endpointType) {
  // Each endpoint has: 'name', 'deviceTypeName', 'deviceTypeCode', 'clusters', 'commands', 'attributes'
  return dbApi.dbInsert(
    db,
    `
INSERT INTO ENDPOINT_TYPE (
  SESSION_REF,
  NAME,
  DEVICE_TYPE_REF
) VALUES(
  ?,
  ?,
  (SELECT DEVICE_TYPE_ID FROM DEVICE_TYPE WHERE CODE = ? AND PACKAGE_REF = ?)
)`,
    [sessionId, endpointType.name, endpointType.deviceTypeCode, packageId]
  )
}

/**
 * Exports packages for externalized form.
 *
 * @param {*} db
 * @param {*} sessionId
 * @returns Promise of a data that is listing all the packages in the session.
 */
function exportPackagesFromSession(db, sessionId) {
  var mapFunction = (x) => {
    return {
      path: x.PATH,
      version: x.VERSION,
      type: x.TYPE,
    }
  }
  return dbApi
    .dbAll(
      db,
      `
SELECT
  PACKAGE.PATH,
  PACKAGE.VERSION,
  PACKAGE.TYPE
FROM PACKAGE
INNER JOIN SESSION_PACKAGE
ON PACKAGE.PACKAGE_ID = SESSION_PACKAGE.PACKAGE_REF
WHERE SESSION_PACKAGE.SESSION_REF = ?`,
      [sessionId]
    )
    .then((rows) => rows.map(mapFunction))
}

/**
 * Exports clusters to an externalized form.
 *
 * @param {*} db
 * @param {*} endpointTypeId
 * @returns Promise that resolves with the data that should go into the external form.
 */
function exportClustersFromEndpointType(db, endpointTypeId) {
  var mapFunction = (x) => {
    return {
      name: x.NAME,
      code: x.CODE,
      mfgCode: x.MANUFACTURER_CODE,
      side: x.SIDE,
      enabled: x.ENABLED,
      endpointClusterId: x.ENDPOINT_TYPE_CLUSTER_ID,
    }
  }

  return dbApi
    .dbAll(
      db,
      `
SELECT
  CLUSTER.CODE,
  CLUSTER.MANUFACTURER_CODE,
  CLUSTER.NAME,
  ENDPOINT_TYPE_CLUSTER.SIDE,
  ENDPOINT_TYPE_CLUSTER.ENABLED,
  ENDPOINT_TYPE_CLUSTER.ENDPOINT_TYPE_CLUSTER_ID
FROM CLUSTER
INNER JOIN ENDPOINT_TYPE_CLUSTER
ON CLUSTER.CLUSTER_ID = ENDPOINT_TYPE_CLUSTER.CLUSTER_REF
WHERE ENDPOINT_TYPE_CLUSTER.ENDPOINT_TYPE_REF = ?`,
      [endpointTypeId]
    )
    .then((rows) => rows.map(mapFunction))
}

/**
 * Imports a single cluster to endpoint type.
 *
 * @param {*} db
 * @param {*} endpointTypeId
 * @param {*} cluster Object populated same way as export method leaves it.
 * @returns Promise of an imported cluster.
 */
function importClusterForEndpointType(db, packageId, endpointTypeId, cluster) {
  return dbApi.dbInsert(
    db,
    `
INSERT INTO ENDPOINT_TYPE_CLUSTER
  (ENDPOINT_TYPE_REF, CLUSTER_REF, SIDE, ENABLED)
VALUES
  (?,
   (SELECT CLUSTER_ID FROM CLUSTER WHERE PACKAGE_REF = ? AND CODE = ? AND ${
     cluster.mfgCode == null
       ? 'MANUFACTURER_CODE IS NULL'
       : 'MANUFACTURER_CODE = ?'
   }),
   ?,
   ?)`,
    cluster.mfgCode == null
      ? [endpointTypeId, packageId, cluster.code, cluster.side, cluster.enabled]
      : [
          endpointTypeId,
          packageId,
          cluster.code,
          cluster.mfgCode,
          cluster.side,
          cluster.enabled,
        ]
  )
}

/**
 * Returns a promise of data for attributes inside an endpoint type.
 *
 * @param {*} db
 * @param {*} endpointTypeId
 * @returns Promise that resolves with the attribute data.
 */
function exportAttributesFromEndpointTypeCluster(
  db,
  endpointTypeId,
  endpointClusterId
) {
  var mapFunction = (x) => {
    return {
      name: x.NAME,
      code: x.CODE,
      mfgCode: x.MANUFACTURER_CODE,
      included: x.INCLUDED,
      storageOption: x.STORAGE_OPTION,
      singleton: x.SINGLETON,
      bounded: x.BOUNDED,
      defaultValue: x.DEFAULT_VALUE,
      reportable: x.INCLUDED_REPORTABLE,
      minInterval: x.MIN_INTERVAL,
      maxInterval: x.MAX_INTERVAL,
      reportableChange: x.REPORTABLE_CHANGE,
    }
  }
  return dbApi
    .dbAll(
      db,
      `
SELECT
  ATTRIBUTE.NAME,
  ATTRIBUTE.CODE,
  ATTRIBUTE.MANUFACTURER_CODE,
  ENDPOINT_TYPE_ATTRIBUTE.INCLUDED,
  ENDPOINT_TYPE_ATTRIBUTE.STORAGE_OPTION,
  ENDPOINT_TYPE_ATTRIBUTE.SINGLETON,
  ENDPOINT_TYPE_ATTRIBUTE.BOUNDED,
  ENDPOINT_TYPE_ATTRIBUTE.DEFAULT_VALUE,
  ENDPOINT_TYPE_ATTRIBUTE.INCLUDED_REPORTABLE,
  ENDPOINT_TYPE_ATTRIBUTE.MIN_INTERVAL,
  ENDPOINT_TYPE_ATTRIBUTE.MAX_INTERVAL,
  ENDPOINT_TYPE_ATTRIBUTE.REPORTABLE_CHANGE
FROM ATTRIBUTE
INNER JOIN ENDPOINT_TYPE_ATTRIBUTE
ON ATTRIBUTE.ATTRIBUTE_ID = ENDPOINT_TYPE_ATTRIBUTE.ATTRIBUTE_REF
WHERE ENDPOINT_TYPE_ATTRIBUTE.ENDPOINT_TYPE_REF = ?
      AND ENDPOINT_TYPE_ATTRIBUTE.ENDPOINT_TYPE_CLUSTER_REF = ?
    `,
      [endpointTypeId, endpointClusterId]
    )
    .then((rows) => rows.map(mapFunction))
}

/**
 * Imports an attribute information of an endpoint type.
 *
 * @param {*} db
 * @param {*} packageId
 * @param {*} endpointTypeId
 * @param {*} endpointClusterId may be null if global attribute
 * @param {*} attribute
 * @returns Promise of an attribute insertion.
 */
function importAttributeForEndpointType(
  db,
  packageId,
  endpointTypeId,
  endpointClusterId,
  attribute
) {
  var arg = [
    endpointTypeId,
    endpointClusterId,
    attribute.code,
    packageId,
    endpointClusterId,
  ]
  if (attribute.mfgCode != null) arg.push(attribute.mfgCode)
  arg.push(
    attribute.included,
    attribute.storageOption,
    attribute.singleton,
    attribute.bounded,
    attribute.defaultValue,
    attribute.reportable,
    attribute.minInterval,
    attribute.maxInterval,
    attribute.reportableChange
  )
  return dbApi.dbInsert(
    db,
    `
INSERT INTO ENDPOINT_TYPE_ATTRIBUTE
( ENDPOINT_TYPE_REF,
  ENDPOINT_TYPE_CLUSTER_REF,
  ATTRIBUTE_REF,
  INCLUDED,
  STORAGE_OPTION,
  SINGLETON,
  BOUNDED,
  DEFAULT_VALUE,
  INCLUDED_REPORTABLE,
  MIN_INTERVAL,
  MAX_INTERVAL,
  REPORTABLE_CHANGE )
VALUES
( ?, ?,
  ( SELECT ATTRIBUTE_ID FROM ATTRIBUTE, ENDPOINT_TYPE_CLUSTER
    WHERE ATTRIBUTE.CODE = ?
    AND ATTRIBUTE.PACKAGE_REF = ?
    AND ENDPOINT_TYPE_CLUSTER.ENDPOINT_TYPE_CLUSTER_ID = ?
    AND ENDPOINT_TYPE_CLUSTER.CLUSTER_REF = ATTRIBUTE.CLUSTER_REF
    AND ${
      attribute.mfgCode == null
        ? 'MANUFACTURER_CODE IS NULL'
        : 'MANUFACTURER_CODE = ?'
    }),
    ?, ?, ?, ?, ?, ?, ?, ?, ?)
  `,
    arg
  )
}

/**
 * Returns a promise of data for commands inside an endpoint type.
 *
 * @param {*} db
 * @param {*} endpointTypeId
 * @returns Promise that resolves with the command data.
 */
function exportCommandsFromEndpointTypeCluster(
  db,
  endpointTypeId,
  endpointClusterId
) {
  var mapFunction = (x) => {
    return {
      name: x.NAME,
      code: x.CODE,
      mfgCode: x.MANUFACTURER_CODE,
      source: x.SOURCE,
      incoming: x.INCOMING,
      outgoing: x.OUTGOING,
    }
  }
  return dbApi
    .dbAll(
      db,
      `
  SELECT
    COMMAND.NAME,
    COMMAND.CODE,
    COMMAND.MANUFACTURER_CODE,
    COMMAND.SOURCE,
    ENDPOINT_TYPE_COMMAND.INCOMING,
    ENDPOINT_TYPE_COMMAND.OUTGOING
  FROM COMMAND
  INNER JOIN ENDPOINT_TYPE_COMMAND
  ON COMMAND.COMMAND_ID = ENDPOINT_TYPE_COMMAND.COMMAND_REF
  WHERE ENDPOINT_TYPE_COMMAND.ENDPOINT_TYPE_REF = ? AND ENDPOINT_TYPE_COMMAND.ENDPOINT_TYPE_CLUSTER_REF = ?
        `,
      [endpointTypeId, endpointClusterId]
    )
    .then((rows) => rows.map(mapFunction))
}

/**
 * Imports a command information of an endpoint type.
 *
 * @param {*} db
 * @param {*} packageId
 * @param {*} endpointTypeId
 * @param {*} endpointClusterId may be null if global command
 * @param {*} command
 * @returns Promise of a command insertion.
 */
function importCommandForEndpointType(
  db,
  packageId,
  endpointTypeId,
  endpointClusterId,
  command
) {
  var arg = [
    endpointTypeId,
    endpointClusterId,
    command.code,
    command.source,
    packageId,
    endpointClusterId,
  ]
  if (command.mfgCode != null) arg.push(command.mfgCode)
  arg.push(command.incoming, command.outgoing)
  return dbApi.dbInsert(
    db,
    `
INSERT INTO ENDPOINT_TYPE_COMMAND
( ENDPOINT_TYPE_REF,
  ENDPOINT_TYPE_CLUSTER_REF,
  COMMAND_REF,
  INCOMING,
  OUTGOING )
VALUES
  ( ?, ?,
    ( SELECT COMMAND_ID
      FROM COMMAND, ENDPOINT_TYPE_CLUSTER WHERE
        COMMAND.CODE = ?
        AND COMMAND.SOURCE = ?
        AND COMMAND.PACKAGE_REF = ?
        AND ENDPOINT_TYPE_CLUSTER.ENDPOINT_TYPE_CLUSTER_ID = ?
        AND COMMAND.CLUSTER_REF = ENDPOINT_TYPE_CLUSTER.CLUSTER_REF
        AND ${
          command.mfgCode == null
            ? 'MANUFACTURER_CODE IS NULL'
            : 'MANUFACTURER_CODE = ?'
        }),
    ?,
    ?
    )
  `,
    arg
  )
}

exports.exportEndpointTypes = exportEndpointTypes
exports.importEndpointType = importEndpointType

exports.exportClustersFromEndpointType = exportClustersFromEndpointType
exports.importClusterForEndpointType = importClusterForEndpointType

exports.exportPackagesFromSession = exportPackagesFromSession

exports.exportAttributesFromEndpointTypeCluster = exportAttributesFromEndpointTypeCluster
exports.importAttributeForEndpointType = importAttributeForEndpointType

exports.exportCommandsFromEndpointTypeCluster = exportCommandsFromEndpointTypeCluster
exports.importCommandForEndpointType = importCommandForEndpointType

exports.exportEndpoints = exportEndpoints
exports.importEndpoint = importEndpoint
<|endoftext|>


<commit_before>
'use strict';

var EventEmitter = require( 'events' ).EventEmitter;
var util = require( './util' );

/**
 * Single user on the server.
 *
 * @param {Object} data - User data.
 * @param {MumbleClient} client - Mumble client that owns this user.
 */
var User = function( data, client ) {
    this.client = client;
    this._applyProperties( data );
};

User.prototype = Object.create( EventEmitter.prototype );

/**
 * @summary Moves the user to a channel
 *
 * @param {Channel|string} channel - Channel name or a channel object
 */
User.prototype.moveToChannel = function( channel ) {

    // Fetch the channel ID based on the parameter.
    var id;
    if( typeof channel === 'string' ) {
        id = this.client.channelByName( channel ).id;
    } else if( typeof channel === 'object' ) {
        id = channel.id;
    } else {
        return;
    }

    // Send the move message.
    this.client.connection.sendMessage( 'UserState', {
        session: this.session, actor: this.client.user.session, channel_id: id } );
};

/**
 * @summary Change a user's self deafened state. (Obviously) only works on yourself.
 *
 * @param {Boolean} isSelfDeaf - The new self deafened state
 */
User.prototype.setSelfDeaf = function( isSelfDeaf ) {
    this.client.connection.sendMessage( 'UserState', {
        session: this.session, actor: this.client.user.session, self_deaf: isSelfDeaf } );
};

/**
 * @summary Change a user's self muted state. (Obviously) only works on yourself.
 *
 * @param {Boolean} isSelfMute - The new self muted state
 */
User.prototype.setSelfMute = function( isSelfMute ) {
    this.client.connection.sendMessage( 'UserState', {
        session: this.session, actor: this.client.user.session, self_mute: isSelfMute } );
};

/**
 * @summary Attempts to kick the user.
 *
 * @param {string} [reason] - The reason to kick the user for.
 */
User.prototype.kick = function( reason ) {
    this._sendRemoveUser( reason || 'You have been kicked', false );
};

/**
 * @summary Attempts to ban the user.
 *
 * @param {string} [reason] - The reason to ban the user for.
 */
User.prototype.ban = function( reason ) {
    this._sendRemoveUser( reason || 'You have been banned', true );
};

/**
 * @summary Sends a message to the user.
 *
 * @param {string} message - The message to send.
 */
User.prototype.sendMessage = function( message ) {
    this.client.sendMessage( message, { session: [ this.session ] } );
};

/**
 * @summary Returns an output stream for listening to the user audio.
 *
 * @param {Boolean} [noEmptyFrames]
 *      True to cut the output stream during silence. If the output stream
 *      isn't cut it will keep emitting zero-values when the user isn't
 *      talking.
 *
 * @returns {MumbleOutputStream} Output stream.
 */
User.prototype.outputStream = function( noEmptyFrames ) {
    return this.client.connection.outputStream( this.session, noEmptyFrames );
};

/**
 * @summary Returns an input stream for sending audio to the user.
 *
 * @returns {MumbleInputStream} Input stream.
 */
User.prototype.inputStream = function() {
    return this.client.inputStreamForUser( this.session );
};

/**
 * @summary Checks whether the user can talk or not.
 *
 * @returns {Boolean} True if the user can talk.
 */
User.prototype.canTalk = function() {
    return !this.mute && !this.selfMute && !this.suppress;
};

/**
 * @summary Checks whether the user can hear other people.
 *
 * @returns {Boolean} True if the user can hear.
 */
User.prototype.canHear = function() {
    return !this.selfDeaf;
};

/**
 * @summary _true_ when the user is registered on the server.
 *
 * @returns {Boolena} True if the user is registered.
 */
User.prototype.isRegistered = function() {
    return !!this.id;
};

User.prototype._applyProperties = function( data ) {

    /**
     * @summary Session ID
     *
     * @description
     * Session ID is present for all users. The ID specifies the current user
     * session and will change when the user reconnects.
     *
     * @see User#id
     *
     * @name User#session
     * @type Number
     */
    this.session = data.session;

    /**
     * @summary User name
     *
     * @name User#name
     * @type String
     */
    this.name = data.name;

    /**
     * @summary User ID
     *
     * @description
     * User ID is specified only for users who are registered on the server.
     * The user ID won't change when the user reconnects.
     *
     * @see User#session
     *
     * @name User#id
     * @type Number
     */
    this.id = data.user_id;

    /**
     * @summary _true_ when the user is muted by an admin.
     *
     * @name User#mute
     * @type Boolean
     */
    this.mute = data.mute;

    /**
     * @summary _true_ when the user is deafened by an admin.
     *
     * @name User#deaf
     * @type Boolean
     */
    this.deaf = data.deaf;

    /**
     * @summary _true_ when the user is suppressed due to lack of
     * permissions.
     *
     * @description
     * The user will be suppressed by the server if they don't have permissions
     * to speak on the current channel.
     *
     * @name User#suppress
     * @type Boolean
     */
    this.suppress = data.suppress;

    /**
     * @summary _true_ when the user has muted themselves.
     *
     * @name User#selfMute
     * @type Boolean
     */
    this.selfMute = data.self_mute;

    /**
     * @summary _true_ when the user has deafened themselves.
     *
     * @name User#selfDeaf
     * @type Boolean
     */
    this.selfDeaf = data.self_deaf;

    /**
     * @summary The hash of the user certificate
     *
     * @name User#hash
     * @type String
     */
    this.hash = data.hash;

    /**
     * @summary _true_ when the user is recording the conversation.
     *
     * @name User#recording
     * @type Boolean
     */
    this.recording = data.recording;

    /**
     * @summary _true_ when the user is a priority speaker.
     *
     * @name User#prioritySpeaker
     * @type Boolean
     */
    this.prioritySpeaker = data.priority_speaker;

    /**
     * @summary User's current channel.
     *
     * @name User#channel
     * @type Channel
     */
    if( data.channel_id !== null ) {
        this.channel = this.client.channelById( data.channel_id );
    } else { // New users always enter root
        this.channel = this.client.rootChannel;
    }
    this.channel._addUser( this );

    // TODO: Comments, textures
};

/**
 * @summary Emitted when the user disconnects
 *
 * @description
 * Also available through the client `user-disconnect` event.
 *
 * @event User#disconnect
 */

User.prototype._detach = function() {
    this.emit( 'disconnect' );
    this.channel._removeUser( this );
};

/**
 * @summary Emitted when the user moves between channels.
 *
 * @event User#move
 * @param {Channel} oldChannel - The channel where the user was moved from.
 * @param {Channel} newChannel - The channel where the user was moved to.
 * @param {User} actor - The user who moved the channel or undefined for server.
 */

/**
 * @summary Checks whether the user changed channel.
 *
 * @private
 *
 * @param {Object} data - New user data.
 */
User.prototype._checkChangeChannel = function( data ) {

    // Get the two channel instances.
    var newChannel = this.client.channelById( data.channel_id );
    var oldChannel = this.channel;

    // Make sure there is a change in the channel.
    if( newChannel === oldChannel )
        return;

    // Make the channel change and notify listeners.
    this.channel = newChannel;
    oldChannel._removeUser( this );
    newChannel._addUser( this );

    var actor = this.client.userBySession( data.actor );
    this.emit( 'move', oldChannel, newChannel, actor );
};

/**
 * @summary Emitted when the user is muted or unmuted by the server.
 *
 * @description
 * Also available through the client `user-mute` event.
 *
 * @event User#mute
 * @param {Boolean} status
 *      True when the user is muted, false when unmuted.
 */

/**
 * @summary Emitted when the user mutes or unmutes themselves.
 *
 * @description
 * Also available through the client `user-self-mute` event.
 *
 * @event User#self-mute
 * @param {Boolean} status
 *      True when the user mutes themselves. False when unmuting.
 */

/**
 * @summary Emitted when the user deafens or undeafens themselves.
 *
 * @description
 * Also available through the client `user-self-deaf` event.
 *
 * @event User#self-deaf
 * @param {Boolean} status
 *      True when the user deafens themselves. False when undeafening.
 */

/**
 * @summary Emitted when the user is suppressed or unsuppressed.
 *
 * @description
 * Also available through the client `user-suppress` event.
 *
 * @event User#suppress
 * @param {Boolean} status
 *      True when the user is suppressed. False when unsuppressed.
 */

/**
 * @summary Emitted when the user starts or stops recording.
 *
 * @description
 * Also available through the client `user-recording` event.
 *
 * @event User#recording
 * @param {Boolean} status
 *      True when the user starts recording. False when they stop.
 */

/**
 * @summary Emitted when the user gains or loses priority speaker status.
 *
 * @description
 * Also available through the client `user-priority-speaker` event.
 *
 * @event User#priority-speaker
 * @param {Boolean} status
 *      True when the user gains priority speaker status. False when they lose
 *      it.
 */

User.prototype.update = function( data ) {
    var self = this;

    // Check the simple fields.
    [
        'mute', 'selfMute', 'suppress',
        'selfDeaf',
        'recording', 'prioritySpeaker',
    ].forEach( function( f ) {
        self._checkField( data, f );
    } );

    // Channel check
    if( data.channel_id !== null ) {
        this._checkChangeChannel( data );
    }

};

User.prototype._sendRemoveUser = function( reason, ban ) {
    this.client.connection.sendMessage( 'UserRemove', {
        session: this.session,
        actor: this.client.user.session,
        reason: reason,
        ban: ban
    } );
};

User.prototype._checkField = function( data, field ) {

    // Make sure the field has a value.
    var newValue = data[ util.toFieldName( field ) ];
    if( newValue === undefined )
        return;

    // Make sure the new value differs.
    var oldValue = this[ field ];
    if( newValue === oldValue )
        return;

    // All checks succeeded. Store the new value and emit change event.
    this[ field ] = newValue;
    var actor = this.client.userBySession( data.actor );
    this.emit( util.toEventName( field ), newValue, actor );
};

module.exports = User;
<commit_msg>Fix typo<commit_after>
'use strict';

var EventEmitter = require( 'events' ).EventEmitter;
var util = require( './util' );

/**
 * Single user on the server.
 *
 * @param {Object} data - User data.
 * @param {MumbleClient} client - Mumble client that owns this user.
 */
var User = function( data, client ) {
    this.client = client;
    this._applyProperties( data );
};

User.prototype = Object.create( EventEmitter.prototype );

/**
 * @summary Moves the user to a channel
 *
 * @param {Channel|string} channel - Channel name or a channel object
 */
User.prototype.moveToChannel = function( channel ) {

    // Fetch the channel ID based on the parameter.
    var id;
    if( typeof channel === 'string' ) {
        id = this.client.channelByName( channel ).id;
    } else if( typeof channel === 'object' ) {
        id = channel.id;
    } else {
        return;
    }

    // Send the move message.
    this.client.connection.sendMessage( 'UserState', {
        session: this.session, actor: this.client.user.session, channel_id: id } );
};

/**
 * @summary Change a user's self deafened state. (Obviously) only works on yourself.
 *
 * @param {Boolean} isSelfDeaf - The new self deafened state
 */
User.prototype.setSelfDeaf = function( isSelfDeaf ) {
    this.client.connection.sendMessage( 'UserState', {
        session: this.session, actor: this.client.user.session, self_deaf: isSelfDeaf } );
};

/**
 * @summary Change a user's self muted state. (Obviously) only works on yourself.
 *
 * @param {Boolean} isSelfMute - The new self muted state
 */
User.prototype.setSelfMute = function( isSelfMute ) {
    this.client.connection.sendMessage( 'UserState', {
        session: this.session, actor: this.client.user.session, self_mute: isSelfMute } );
};

/**
 * @summary Attempts to kick the user.
 *
 * @param {string} [reason] - The reason to kick the user for.
 */
User.prototype.kick = function( reason ) {
    this._sendRemoveUser( reason || 'You have been kicked', false );
};

/**
 * @summary Attempts to ban the user.
 *
 * @param {string} [reason] - The reason to ban the user for.
 */
User.prototype.ban = function( reason ) {
    this._sendRemoveUser( reason || 'You have been banned', true );
};

/**
 * @summary Sends a message to the user.
 *
 * @param {string} message - The message to send.
 */
User.prototype.sendMessage = function( message ) {
    this.client.sendMessage( message, { session: [ this.session ] } );
};

/**
 * @summary Returns an output stream for listening to the user audio.
 *
 * @param {Boolean} [noEmptyFrames]
 *      True to cut the output stream during silence. If the output stream
 *      isn't cut it will keep emitting zero-values when the user isn't
 *      talking.
 *
 * @returns {MumbleOutputStream} Output stream.
 */
User.prototype.outputStream = function( noEmptyFrames ) {
    return this.client.connection.outputStream( this.session, noEmptyFrames );
};

/**
 * @summary Returns an input stream for sending audio to the user.
 *
 * @returns {MumbleInputStream} Input stream.
 */
User.prototype.inputStream = function() {
    return this.client.inputStreamForUser( this.session );
};

/**
 * @summary Checks whether the user can talk or not.
 *
 * @returns {Boolean} True if the user can talk.
 */
User.prototype.canTalk = function() {
    return !this.mute && !this.selfMute && !this.suppress;
};

/**
 * @summary Checks whether the user can hear other people.
 *
 * @returns {Boolean} True if the user can hear.
 */
User.prototype.canHear = function() {
    return !this.selfDeaf;
};

/**
 * @summary _true_ when the user is registered on the server.
 *
 * @returns {Boolean} _true_ if the user is registered.
 */
User.prototype.isRegistered = function() {
    return !!this.id;
};

User.prototype._applyProperties = function( data ) {

    /**
     * @summary Session ID
     *
     * @description
     * Session ID is present for all users. The ID specifies the current user
     * session and will change when the user reconnects.
     *
     * @see User#id
     *
     * @name User#session
     * @type Number
     */
    this.session = data.session;

    /**
     * @summary User name
     *
     * @name User#name
     * @type String
     */
    this.name = data.name;

    /**
     * @summary User ID
     *
     * @description
     * User ID is specified only for users who are registered on the server.
     * The user ID won't change when the user reconnects.
     *
     * @see User#session
     *
     * @name User#id
     * @type Number
     */
    this.id = data.user_id;

    /**
     * @summary _true_ when the user is muted by an admin.
     *
     * @name User#mute
     * @type Boolean
     */
    this.mute = data.mute;

    /**
     * @summary _true_ when the user is deafened by an admin.
     *
     * @name User#deaf
     * @type Boolean
     */
    this.deaf = data.deaf;

    /**
     * @summary _true_ when the user is suppressed due to lack of
     * permissions.
     *
     * @description
     * The user will be suppressed by the server if they don't have permissions
     * to speak on the current channel.
     *
     * @name User#suppress
     * @type Boolean
     */
    this.suppress = data.suppress;

    /**
     * @summary _true_ when the user has muted themselves.
     *
     * @name User#selfMute
     * @type Boolean
     */
    this.selfMute = data.self_mute;

    /**
     * @summary _true_ when the user has deafened themselves.
     *
     * @name User#selfDeaf
     * @type Boolean
     */
    this.selfDeaf = data.self_deaf;

    /**
     * @summary The hash of the user certificate
     *
     * @name User#hash
     * @type String
     */
    this.hash = data.hash;

    /**
     * @summary _true_ when the user is recording the conversation.
     *
     * @name User#recording
     * @type Boolean
     */
    this.recording = data.recording;

    /**
     * @summary _true_ when the user is a priority speaker.
     *
     * @name User#prioritySpeaker
     * @type Boolean
     */
    this.prioritySpeaker = data.priority_speaker;

    /**
     * @summary User's current channel.
     *
     * @name User#channel
     * @type Channel
     */
    if( data.channel_id !== null ) {
        this.channel = this.client.channelById( data.channel_id );
    } else { // New users always enter root
        this.channel = this.client.rootChannel;
    }
    this.channel._addUser( this );

    // TODO: Comments, textures
};

/**
 * @summary Emitted when the user disconnects
 *
 * @description
 * Also available through the client `user-disconnect` event.
 *
 * @event User#disconnect
 */

User.prototype._detach = function() {
    this.emit( 'disconnect' );
    this.channel._removeUser( this );
};

/**
 * @summary Emitted when the user moves between channels.
 *
 * @event User#move
 * @param {Channel} oldChannel - The channel where the user was moved from.
 * @param {Channel} newChannel - The channel where the user was moved to.
 * @param {User} actor - The user who moved the channel or undefined for server.
 */

/**
 * @summary Checks whether the user changed channel.
 *
 * @private
 *
 * @param {Object} data - New user data.
 */
User.prototype._checkChangeChannel = function( data ) {

    // Get the two channel instances.
    var newChannel = this.client.channelById( data.channel_id );
    var oldChannel = this.channel;

    // Make sure there is a change in the channel.
    if( newChannel === oldChannel )
        return;

    // Make the channel change and notify listeners.
    this.channel = newChannel;
    oldChannel._removeUser( this );
    newChannel._addUser( this );

    var actor = this.client.userBySession( data.actor );
    this.emit( 'move', oldChannel, newChannel, actor );
};

/**
 * @summary Emitted when the user is muted or unmuted by the server.
 *
 * @description
 * Also available through the client `user-mute` event.
 *
 * @event User#mute
 * @param {Boolean} status
 *      True when the user is muted, false when unmuted.
 */

/**
 * @summary Emitted when the user mutes or unmutes themselves.
 *
 * @description
 * Also available through the client `user-self-mute` event.
 *
 * @event User#self-mute
 * @param {Boolean} status
 *      True when the user mutes themselves. False when unmuting.
 */

/**
 * @summary Emitted when the user deafens or undeafens themselves.
 *
 * @description
 * Also available through the client `user-self-deaf` event.
 *
 * @event User#self-deaf
 * @param {Boolean} status
 *      True when the user deafens themselves. False when undeafening.
 */

/**
 * @summary Emitted when the user is suppressed or unsuppressed.
 *
 * @description
 * Also available through the client `user-suppress` event.
 *
 * @event User#suppress
 * @param {Boolean} status
 *      True when the user is suppressed. False when unsuppressed.
 */

/**
 * @summary Emitted when the user starts or stops recording.
 *
 * @description
 * Also available through the client `user-recording` event.
 *
 * @event User#recording
 * @param {Boolean} status
 *      True when the user starts recording. False when they stop.
 */

/**
 * @summary Emitted when the user gains or loses priority speaker status.
 *
 * @description
 * Also available through the client `user-priority-speaker` event.
 *
 * @event User#priority-speaker
 * @param {Boolean} status
 *      True when the user gains priority speaker status. False when they lose
 *      it.
 */

User.prototype.update = function( data ) {
    var self = this;

    // Check the simple fields.
    [
        'mute', 'selfMute', 'suppress',
        'selfDeaf',
        'recording', 'prioritySpeaker',
    ].forEach( function( f ) {
        self._checkField( data, f );
    } );

    // Channel check
    if( data.channel_id !== null ) {
        this._checkChangeChannel( data );
    }

};

User.prototype._sendRemoveUser = function( reason, ban ) {
    this.client.connection.sendMessage( 'UserRemove', {
        session: this.session,
        actor: this.client.user.session,
        reason: reason,
        ban: ban
    } );
};

User.prototype._checkField = function( data, field ) {

    // Make sure the field has a value.
    var newValue = data[ util.toFieldName( field ) ];
    if( newValue === undefined )
        return;

    // Make sure the new value differs.
    var oldValue = this[ field ];
    if( newValue === oldValue )
        return;

    // All checks succeeded. Store the new value and emit change event.
    this[ field ] = newValue;
    var actor = this.client.userBySession( data.actor );
    this.emit( util.toEventName( field ), newValue, actor );
};

module.exports = User;
<|endoftext|>


<commit_before>// ==UserScript==
// @name        Be Still, Cody
// @namespace   http://chomperstomp.com
// @version     0.1.0+005
// @description Cut out the useless Chatter
// @author      Christopher McCulloh
// @contributor Chris Corwin
// @match       https://org62.my.salesforce.com/*
// @updateURL   https://raw.githubusercontent.com/cormacmccarthy/be-still-cody/master/headphones.user.js
// @grant       none
// ==/UserScript==

// Add dependancies
var addDependancies = function addDependancies() {
	var injectedStyles = [
		"https://code.jquery.com/jquery-latest.js"
		, "https://maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap.min.css"
		//, "https:// NEED SOME WAY TO MAKE THIS USER-SPECIFIC AT BUILD TIME /headphones.user.css"
	];

	$.each(injectedStyles, function (index, value) {
		$("head").append('<link href="' + value + '"' + ' rel="stylesheet" type="text/css">');
	});

	var injectedScripts = [
		"https://code.jquery.com/jquery-latest.js",
		"https://maxcdn.bootstrapcdn.com/bootstrap/3.2.0/js/bootstrap.min.js",
		"https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.8.3/moment.min.js",
		"https://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.7.0/underscore.js"
	];

	$.each(injectedScripts, function (index, value) {
		$("head").append('');
	});
}
addDependancies();

var trashBS = function trashBS() {
	// make tabs easier to access by assigning their text as class names
	$('#tabBar li')
		.each(function (i, el) {
			var $el = $(el);
			$el.addClass($el.text()
				.toLowerCase());
		});
	// Trash BS
	['.brandZeronaryFgr',// trash logo
		'#Contract_Tab', '#AdvForecast_Tab', '#Opportunity_Tab', '#Contact_Tab', '#Account_Tab', '#Lead_Tab', '#Campaign_Tab', '#Case_Tab', '#Solution_Tab', '#report_Tab', '#Document_Tab', '#Workspace_Tab', '#ContentSearch_Tab', '#File_Tab', '#phHeader .left', '#bodyCell .links', '#presence_widget', '#tabBar .partner.applications', '#tabBar .sales.central', '#tabBar .companies', '.recElement.todoElement',// trash annoyingly bright yellow box thing
		'#section_header',// trash the amazing-space-eating "hide/show feed" button that for some reason needs its own huge bar. Well, trash the whole bar!
		'#ptBody',// trash pointless redundant egotistical feed header
		'.zen-branding',// trash logo
		'a[href^="javascript:openPopupFocusEscapePounds"]',// remove useless links to help docs
		'.chatterUserStatus',// trash redundant profile pic and link in Chatter
		'.headerContent'// trash pointless huge "salesforce.com" text and invisible header bar
	].forEach(function (el, i, bs) {
		$(el)
			.remove();
	});
}
trashBS();

// Trash BS that loads really slowly
var trashSlowBS = function trashSlowBS() {
	['#presence_widget'].forEach(function (el, i, bs) {
		$(el)
			.remove();
	});

	$('.x-zen-tabMenu').addClass('nav').addClass('nav-pills');

	$('.feedcontainer .feeditemcommentplaceholder input').addClass('feedcontainerFeeditemcommentplaceholderInput');
	$('.feedcontainer .feeditemcommentplaceholder label span').addClass('feedcontainerFeeditemcommentplaceholderLabelSpan');
	$('.feedcontainer .feeditemcommentphoto img').addClass('feedcontainerFeeditemcommentphotoImg');
	$('.mainContentHeader').addClass('zen hidden');
	$('.headerContent').addClass('fade collapse');
	$('.zen-headerTop').addClass('pull-right');
	$('.zen-navViaMenus').addClass('pull-right');

	$('.leftContent ul').addClass('nav').addClass('nav-pills').addClass('nav-stacked');
	$('.selected').addClass('active').removeClass('selected');
	$('.zen-active').addClass('active').removeClass('zen-active');
	$('.zen-assistiveText').addClass('sr-only').removeClass('zen-assistiveText');
	$('.x-zen-assistiveText').addClass('sr-only').removeClass('x-zen-assistiveText');
	$('.brandPrimaryBgr').removeClass('brandPrimaryBgr');
	$('.primaryPalette').removeClass('primaryPalette');
	$('.zen-bodyZen').addClass('panel').addClass('panel-default').removeClass('zen-bodyZen').removeClass('brdPalette').removeClass('brandPrimaryBrd');
	$('.zen-navMenus').addClass('zen');
	$('.zen-bodyInner').addClass('panel-body').removeClass('zen-bodyInner');
	$('.leftContent').addClass('well');
	$('#rightContent').addClass('panel').addClass('panel-default');
	$('#rightContent > div').addClass('panel-body');
	$('html').addClass('fuelux').removeClass('zen');
	$('.zen-page > div > header').addClass('zen well');
	$('.menuButtonRounded').addClass('dropdown').removeClass('menuButtonRounded');
	$('.menuButtonButton').addClass('btn btn-primary dropdown-toggle').removeClass('menuButtonButton');
	$('link[href="/sCSS/33.0/sprites/1423103332000/Theme3/default/gc/zenifiedChatterPageBase.css"').remove();
	$('.feeditem').addClass('panel panel-default').removeClass('feeditem');
	$('.feeditemusericon').parent('a').parent('span').wrap('

');
	$('.feeditemusericon').removeClass('feeditemusericon');
	$('.feeditemcontent').addClass('panel-body').removeClass('feeditemcontent');
	$('.feeditemextras').addClass('well').removeClass('feeditemextras');
	$('.feeditemcomments').removeClass('feeditemcomments');
	$('.feeditemcomment').removeClass('feeditemcomment').addClass('panel panel-info');
	$('.feeditemcommentbody').removeClass('feeditemcommentbody').addClass('panel-body');
	$('.feeditemcommentphoto').addClass('pull-left');
	$('.feeditemcommentplaceholder').addClass('well').removeClass('feeditemcommentplaceholder');
	$('.newCommentContainer').addClass('well');
	$('.headerSearchLeftRoundedCorner').removeClass('headerSearchLeftRoundedCorner');

	window.setTimeout(trashSlowBS, 2000);
}
trashSlowBS();

var attachChatterChanges = function attachChatterChanges() {
	chatter.ext_Feed.muteItem = function (element, c) {
		console.log('here');
		// var b = $(element).closest(".cxfeeditem").data('feedItem').feeditemtype;
		var toolbox = chatter.getToolbox();
		toolbox.mask(Ext.fly(element));
		toolbox.post({
			url: "/feeditems/" + c + "/mute",
			success: function (b, c) {
				$(element)
					.closest('.cxfeeditem')
					.remove();
			}
		});
		chatter.getEventBus()
			.fireEvent("chatter:feed", "onAfterDeleteFeedItem", {
				el: this
			})
	};
}
window.setTimeout(attachChatterChanges, 4500);

var betterMuteButton = function betterMuteButton() {
	$('.feeditem')
		.each(function (i, el) {
			var $el = $(el);
			if ($el.find('.hideFeedItem')
					.length <= 0) {
				var id = $el[0].id;
				$el.find('.preamblecontainer.displayblock')
					.append('hide');
			}
		});
	$('.hideFeedItem')
		.on('click', function (e) {
			e.preventDefault();
			chatter.getFeed()
				.muteItem(this, $(this)
					.data('id'));
		});
	window.setTimeout(betterMuteButton, 4500);
}
betterMuteButton();
$('.cxshowmorefeeditemscontainer.showmorefeeditemscontainer a')
	.on('click', function (e) {
		window.setTimeout(betterMuteButton, 4500);
	});

// Add some handy string manipulation stuff to JavaScript itself.
String.prototype.endsWith = function endsWith(value) {
	if (this.length < value.length) {
		return false;
	} else {
		return Boolean(this.substr(this.length - value.length, value.length + 1) === value);
	}
};
String.prototype.contains = function contains(value, caseFlag) {
	if (this.length < value.length) {
		return false;
	} else {
		var regExPattern_value = caseFlag === false ? new RegExp(value, "i") : new RegExp(value);
		return Boolean(this.match(regExPattern_value));
	}
};

String.prototype.beginsWith = function beginsWith(string) {
	return this.indexOf(string) === 0;
};

// Make a jQuery class stripper.
var disableZen = function disableZen(el) {
	prefix = "zen-";
	var $theseElements = $(el);
	$theseElements.each(function (i, el) {
		var $thisElement = $(el);

		var oldClassNames = $thisElement.attr("class").split(" ");
		var newClassNames = "";
		$thisElement.attr("data-previous-class-names", $thisElement.attr("class"));
		$.each(oldClassNames, function (index, value) {
			if (value.beginsWith(prefix)) {
				newClassNames = newClassNames + " " + "x-" + value;
				$thisElement.attr( ("data-had-zen-class-" + value), "true");
			}
		});
		el.className = newClassNames;
	});
	return $theseElements;
};
disableZen();

var removeZenPrefix = function removeZenPrefix(el) {
	prefix = "zen-";
	var $theseElements = $(el);
	$theseElements.each(function (i, el) {
		var classes = el.className.split(" ").filter(function (c) {
			console.log("c.lastIndexOf( prefix, 0 )", c.lastIndexOf(prefix, 0));
			console.log("c.lastIndexOf( prefix, 0 ) !== 0", c.lastIndexOf(prefix, 0) !== 0);
			return c.lastIndexOf(prefix, 0) !== 0;
		});
		el.className = $.trim(classes.join(" "));
	});
	return $theseElements;
};
removeZenPrefix();
<commit_msg>(master) fix require issues. You can't use jquery to require jquery :P<commit_after>// ==UserScript==
// @name        Be Still, Cody
// @namespace   http://chomperstomp.com
// @version     0.1.0+005
// @description Cut out the useless Chatter
// @author      Christopher McCulloh
// @contributor Chris Corwin
// @match       https://org62.my.salesforce.com/*
// @updateURL   https://raw.githubusercontent.com/cormacmccarthy/be-still-cody/master/headphones.user.js
// @require     http:// code.jquery.com/jquery-latest.js
// @grant       none
// ==/UserScript==

// Add dependancies
var addDependancies = function addDependancies() {
	var injectedStyles = [
		"https://code.jquery.com/jquery-latest.js"
		, "https://maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap.min.css"
		//, "https:// NEED SOME WAY TO MAKE THIS USER-SPECIFIC AT BUILD TIME /headphones.user.css"
	];

	$.each(injectedStyles, function (index, value) {
		$("head").append('<link href="' + value + '"' + ' rel="stylesheet" type="text/css">');
	});

	var injectedScripts = [
		"https://code.jquery.com/jquery-latest.js",
		"https://maxcdn.bootstrapcdn.com/bootstrap/3.2.0/js/bootstrap.min.js",
		"https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.8.3/moment.min.js",
		"https://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.7.0/underscore.js"
	];

	$.each(injectedScripts, function (index, value) {
		$("head").append('');
	});
}
addDependancies();

var trashBS = function trashBS() {
	// make tabs easier to access by assigning their text as class names
	$('#tabBar li')
		.each(function (i, el) {
			var $el = $(el);
			$el.addClass($el.text()
				.toLowerCase());
		});
	// Trash BS
	['.brandZeronaryFgr',// trash logo
		'#Contract_Tab', '#AdvForecast_Tab', '#Opportunity_Tab', '#Contact_Tab', '#Account_Tab', '#Lead_Tab', '#Campaign_Tab', '#Case_Tab', '#Solution_Tab', '#report_Tab', '#Document_Tab', '#Workspace_Tab', '#ContentSearch_Tab', '#File_Tab', '#phHeader .left', '#bodyCell .links', '#presence_widget', '#tabBar .partner.applications', '#tabBar .sales.central', '#tabBar .companies', '.recElement.todoElement',// trash annoyingly bright yellow box thing
		'#section_header',// trash the amazing-space-eating "hide/show feed" button that for some reason needs its own huge bar. Well, trash the whole bar!
		'#ptBody',// trash pointless redundant egotistical feed header
		'.zen-branding',// trash logo
		'a[href^="javascript:openPopupFocusEscapePounds"]',// remove useless links to help docs
		'.chatterUserStatus',// trash redundant profile pic and link in Chatter
		'.headerContent'// trash pointless huge "salesforce.com" text and invisible header bar
	].forEach(function (el, i, bs) {
		$(el)
			.remove();
	});
}
trashBS();

// Trash BS that loads really slowly
var trashSlowBS = function trashSlowBS() {
	['#presence_widget'].forEach(function (el, i, bs) {
		$(el)
			.remove();
	});

	$('.x-zen-tabMenu').addClass('nav').addClass('nav-pills');

	$('.feedcontainer .feeditemcommentplaceholder input').addClass('feedcontainerFeeditemcommentplaceholderInput');
	$('.feedcontainer .feeditemcommentplaceholder label span').addClass('feedcontainerFeeditemcommentplaceholderLabelSpan');
	$('.feedcontainer .feeditemcommentphoto img').addClass('feedcontainerFeeditemcommentphotoImg');
	$('.mainContentHeader').addClass('zen hidden');
	$('.headerContent').addClass('fade collapse');
	$('.zen-headerTop').addClass('pull-right');
	$('.zen-navViaMenus').addClass('pull-right');

	$('.leftContent ul').addClass('nav').addClass('nav-pills').addClass('nav-stacked');
	$('.selected').addClass('active').removeClass('selected');
	$('.zen-active').addClass('active').removeClass('zen-active');
	$('.zen-assistiveText').addClass('sr-only').removeClass('zen-assistiveText');
	$('.x-zen-assistiveText').addClass('sr-only').removeClass('x-zen-assistiveText');
	$('.brandPrimaryBgr').removeClass('brandPrimaryBgr');
	$('.primaryPalette').removeClass('primaryPalette');
	$('.zen-bodyZen').addClass('panel').addClass('panel-default').removeClass('zen-bodyZen').removeClass('brdPalette').removeClass('brandPrimaryBrd');
	$('.zen-navMenus').addClass('zen');
	$('.zen-bodyInner').addClass('panel-body').removeClass('zen-bodyInner');
	$('.leftContent').addClass('well');
	$('#rightContent').addClass('panel').addClass('panel-default');
	$('#rightContent > div').addClass('panel-body');
	$('html').addClass('fuelux').removeClass('zen');
	$('.zen-page > div > header').addClass('zen well');
	$('.menuButtonRounded').addClass('dropdown').removeClass('menuButtonRounded');
	$('.menuButtonButton').addClass('btn btn-primary dropdown-toggle').removeClass('menuButtonButton');
	$('link[href="/sCSS/33.0/sprites/1423103332000/Theme3/default/gc/zenifiedChatterPageBase.css"').remove();
	$('.feeditem').addClass('panel panel-default').removeClass('feeditem');
	$('.feeditemusericon').parent('a').parent('span').wrap('

');
	$('.feeditemusericon').removeClass('feeditemusericon');
	$('.feeditemcontent').addClass('panel-body').removeClass('feeditemcontent');
	$('.feeditemextras').addClass('well').removeClass('feeditemextras');
	$('.feeditemcomments').removeClass('feeditemcomments');
	$('.feeditemcomment').removeClass('feeditemcomment').addClass('panel panel-info');
	$('.feeditemcommentbody').removeClass('feeditemcommentbody').addClass('panel-body');
	$('.feeditemcommentphoto').addClass('pull-left');
	$('.feeditemcommentplaceholder').addClass('well').removeClass('feeditemcommentplaceholder');
	$('.newCommentContainer').addClass('well');
	$('.headerSearchLeftRoundedCorner').removeClass('headerSearchLeftRoundedCorner');

	window.setTimeout(trashSlowBS, 2000);
}
trashSlowBS();

var attachChatterChanges = function attachChatterChanges() {
	chatter.ext_Feed.muteItem = function (element, c) {
		console.log('here');
		// var b = $(element).closest(".cxfeeditem").data('feedItem').feeditemtype;
		var toolbox = chatter.getToolbox();
		toolbox.mask(Ext.fly(element));
		toolbox.post({
			url: "/feeditems/" + c + "/mute",
			success: function (b, c) {
				$(element)
					.closest('.cxfeeditem')
					.remove();
			}
		});
		chatter.getEventBus()
			.fireEvent("chatter:feed", "onAfterDeleteFeedItem", {
				el: this
			})
	};
}
window.setTimeout(attachChatterChanges, 4500);

var betterMuteButton = function betterMuteButton() {
	$('.feeditem')
		.each(function (i, el) {
			var $el = $(el);
			if ($el.find('.hideFeedItem')
					.length <= 0) {
				var id = $el[0].id;
				$el.find('.preamblecontainer.displayblock')
					.append('hide');
			}
		});
	$('.hideFeedItem')
		.on('click', function (e) {
			e.preventDefault();
			chatter.getFeed()
				.muteItem(this, $(this)
					.data('id'));
		});
	window.setTimeout(betterMuteButton, 4500);
}
betterMuteButton();
$('.cxshowmorefeeditemscontainer.showmorefeeditemscontainer a')
	.on('click', function (e) {
		window.setTimeout(betterMuteButton, 4500);
	});

// Add some handy string manipulation stuff to JavaScript itself.
String.prototype.endsWith = function endsWith(value) {
	if (this.length < value.length) {
		return false;
	} else {
		return Boolean(this.substr(this.length - value.length, value.length + 1) === value);
	}
};
String.prototype.contains = function contains(value, caseFlag) {
	if (this.length < value.length) {
		return false;
	} else {
		var regExPattern_value = caseFlag === false ? new RegExp(value, "i") : new RegExp(value);
		return Boolean(this.match(regExPattern_value));
	}
};

String.prototype.beginsWith = function beginsWith(string) {
	return this.indexOf(string) === 0;
};

// Make a jQuery class stripper.
var disableZen = function disableZen(el) {
	prefix = "zen-";
	var $theseElements = $(el);
	$theseElements.each(function (i, el) {
		var $thisElement = $(el);

		var oldClassNames = $thisElement.attr("class").split(" ");
		var newClassNames = "";
		$thisElement.attr("data-previous-class-names", $thisElement.attr("class"));
		$.each(oldClassNames, function (index, value) {
			if (value.beginsWith(prefix)) {
				newClassNames = newClassNames + " " + "x-" + value;
				$thisElement.attr( ("data-had-zen-class-" + value), "true");
			}
		});
		el.className = newClassNames;
	});
	return $theseElements;
};
disableZen();

var removeZenPrefix = function removeZenPrefix(el) {
	prefix = "zen-";
	var $theseElements = $(el);
	$theseElements.each(function (i, el) {
		var classes = el.className.split(" ").filter(function (c) {
			console.log("c.lastIndexOf( prefix, 0 )", c.lastIndexOf(prefix, 0));
			console.log("c.lastIndexOf( prefix, 0 ) !== 0", c.lastIndexOf(prefix, 0) !== 0);
			return c.lastIndexOf(prefix, 0) !== 0;
		});
		el.className = $.trim(classes.join(" "));
	});
	return $theseElements;
};
removeZenPrefix();
<|endoftext|>


<commit_before>/**
 *
 *    Copyright (c) 2020 Silicon Labs
 *
 *    Licensed 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
 *
 *        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.
 */

/**
 * This module provides the REST API to the static zcl queries.
 *
 * @module REST API: static zcl functions
 */

const httpServer = require('../server/http-server.js')

const queryZcl = require('../db/query-zcl.js')
const queryPackage = require('../db/query-package.js')
const dbMapping = require('../db/db-mapping.js')

const itemList = 'zcl-item-list'
const singleItem = 'zcl-item'

// This function builds a function that has the following skeleton.
// This is used to simplify all the logic where we have selectAll and selectById for
// each of the different ZCL entities.
function zclEntityQuery(selectAllFunction, selectByIdFunction) {
  return (db, id, packageId = null) => {
    if (id == 'all') {
      return selectAllFunction(db, packageId)
    } else {
      return selectByIdFunction(db, id, packageId)
    }
  }
}

// For the CLUSTER path, we have special handling to also sideload attributes and commands relevant to that cluster.
function returnZclEntitiesForClusterId(db, clusterId, packageId) {
  return zclEntityQuery(queryZcl.selectAllClusters, queryZcl.selectClusterById)(
    db,
    clusterId,
    packageId
  ).then((x) =>
    zclEntityQuery(
      queryZcl.selectAllAttributes,
      queryZcl.selectAttributesByClusterId
    )(db, clusterId, packageId).then((y) =>
      zclEntityQuery(
        queryZcl.selectAllCommands,
        queryZcl.selectCommandsByClusterId
      )(db, clusterId, packageId).then((z) => {
        return { clusterData: x, attributeData: y, commandData: z }
      })
    )
  )
}

// This is the special merge function used for the CLUSTER path
function mergeZclClusterAttributeCommandData(accumulated, currentValue) {
  return {
    clusterData: [accumulated.clusterData, currentValue.clusterData].flat(1),
    commandData: [accumulated.commandData, currentValue.commandData].flat(1),
    attributeData: [accumulated.attributeData, currentValue.attributeData].flat(
      1
    ),
  }
}
//This maps over each packageId, and runs the query callback.
function reduceAndConcatenateZclEntity(
  db,
  id,
  packageIdArray,
  zclQueryCallback,
  mergeFunction = (accumulated, currentValue) => {
    return [accumulated, currentValue].flat(1)
  },
  defaultValue = []
) {
  var dataArray = packageIdArray.map((packageId) =>
    zclQueryCallback(db, id, packageId)
  )
  return Promise.all(dataArray).then((x) =>
    x.reduce(mergeFunction, defaultValue)
  )
}

function parseForZclData(db, path, id, packageIdArray) {
  switch (path) {
    case 'cluster':
      return reduceAndConcatenateZclEntity(
        db,
        id,
        packageIdArray,
        returnZclEntitiesForClusterId,
        mergeZclClusterAttributeCommandData,
        { clusterData: [], attributeData: [], commandData: [] }
      ).then((data) => {
        return {
          data: data.clusterData,
          attributeData: data.attributeData,
          commandData: data.commandData,
          title: `Cluster: ${id}`,
          type: 'cluster',
        }
      })
      break
    case 'domain':
      return reduceAndConcatenateZclEntity(
        db,
        id,
        packageIdArray,
        zclEntityQuery(queryZcl.selectAllDomains, queryZcl.selectDomainById)
      ).then((data) => {
        return { data: data, title: `Domain: ${id}`, type: 'domain' }
      })
      break
    case 'bitmap':
      return reduceAndConcatenateZclEntity(
        db,
        id,
        packageIdArray,
        zclEntityQuery(queryZcl.selectAllBitmaps, queryZcl.selectBitmapById)
      ).then((x) => {
        return { data: x, title: `Bitmap: ${id}`, type: 'bitmap' }
      })
      break
    case 'enum':
      return reduceAndConcatenateZclEntity(
        db,
        id,
        packageIdArray,
        zclEntityQuery(queryZcl.selectAllEnums, queryZcl.selectEnumById)
      ).then((x) => {
        return { data: x, title: `Enum: ${id}`, type: 'enum' }
      })
      break
    case 'struct':
      return reduceAndConcatenateZclEntity(
        db,
        id,
        packageIdArray,
        zclEntityQuery(queryZcl.selectAllStructs, queryZcl.selectStructById)
      ).then((x) => {
        return { data: x, title: `Struct: ${id}`, type: 'struct' }
      })
      breaks
    case 'deviceType':
      return reduceAndConcatenateZclEntity(
        db,
        id,
        packageIdArray,
        zclEntityQuery(
          queryZcl.selectAllDeviceTypes,
          queryZcl.selectDeviceTypeById
        )
      ).then((x) => {
        return {
          data: x,
          title: `Device type: ${id}`,
          type: 'device_type',
        }
      })
      break
    case 'endpointTypeClusters':
      return queryZcl
        .selectEndpointTypeClustersByEndpointTypeId(db, id)
        .then((x) => {
          return { data: x, type: `endpointTypeClusters` }
        })
      break
    case 'endpointTypeAttributes':
      return queryZcl
        .selectEndpointTypeAttributesByEndpointId(db, id)
        .then((x) => {
          return { data: x, type: `endpointTypeAttributes` }
        })
      break
    case 'endpointTypeCommands':
      return queryZcl
        .selectEndpointTypeCommandsByEndpointId(db, id)
        .then((x) => {
          return { data: x, type: `endpointTypeCommands` }
        })
      break
    case `endpointTypeDeviceTypeClusters`:
      return queryZcl
        .selectDeviceTypeClustersByDeviceTypeRef(db, id)
        .then((x) => {
          return { data: x, type: `deviceTypeClusters` }
        })
      break
    case `endpointTypeDeviceTypeAttributes`:
      return queryZcl
        .selectDeviceTypeAttributesByDeviceTypeRef(db, id)
        .then((x) => {
          return { data: x, type: `deviceTypeAttributes` }
        })
      break
    case `endpointTypeDeviceTypeCommands`:
      return queryZcl
        .selectDeviceTypeCommandsByDeviceTypeRef(db, id)
        .then((x) => {
          return { data: x, type: `deviceTypeCommands` }
        })
      break
    default:
      return { type: 'Unknown' }
  }
}

function processGetEntityRequest(db, path, id, replyId, sessionId, callback) {
  var finalData = {}
  queryPackage
    .getSessionPackages(db, sessionId)
    .then((packageIdArray) => {
      return parseForZclData(db, path, id, packageIdArray)
    })
    .then((finalData) => {
      callback(replyId, finalData)
    })
}

/**
 * API: /get/:entity/:id
 *
 * @export
 * @param {*} app Express instance.
 */
function registerStaticZclApi(db, app) {
  app.get('/get/:entity/:id', (request, response) => {
    const { id, entity } = request.params
    var sessionId = request.session.zapSessionId

    var processReply = (replyId, object) => {
      object.replyId = replyId
      response.status(httpServer.httpCode.ok).json(object)
    }
    var replyId = id === 'all' ? itemList : singleItem
    processGetEntityRequest(db, entity, id, replyId, sessionId, processReply)
  })
}

exports.registerStaticZclApi = registerStaticZclApi
<commit_msg>Minor cleanup<commit_after>/**
 *
 *    Copyright (c) 2020 Silicon Labs
 *
 *    Licensed 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
 *
 *        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.
 */

/**
 * This module provides the REST API to the static zcl queries.
 *
 * @module REST API: static zcl functions
 */

const httpServer = require('../server/http-server.js')

const queryZcl = require('../db/query-zcl.js')
const queryPackage = require('../db/query-package.js')
const dbMapping = require('../db/db-mapping.js')

const itemList = 'zcl-item-list'
const singleItem = 'zcl-item'

// This function builds a function that has the following skeleton.
// This is used to simplify all the logic where we have selectAll and selectById for
// each of the different ZCL entities.
function zclEntityQuery(selectAllFunction, selectByIdFunction) {
  return (db, id, packageId = null) => {
    if (id == 'all') {
      return selectAllFunction(db, packageId)
    } else {
      return selectByIdFunction(db, id, packageId)
    }
  }
}

// For the CLUSTER path, we have special handling to also sideload attributes and commands relevant to that cluster.
function returnZclEntitiesForClusterId(db, clusterId, packageId) {
  return zclEntityQuery(queryZcl.selectAllClusters, queryZcl.selectClusterById)(
    db,
    clusterId,
    packageId
  ).then((x) =>
    zclEntityQuery(
      queryZcl.selectAllAttributes,
      queryZcl.selectAttributesByClusterId
    )(db, clusterId, packageId).then((y) =>
      zclEntityQuery(
        queryZcl.selectAllCommands,
        queryZcl.selectCommandsByClusterId
      )(db, clusterId, packageId).then((z) => {
        return { clusterData: x, attributeData: y, commandData: z }
      })
    )
  )
}

// This is the special merge function used for the CLUSTER path
function mergeZclClusterAttributeCommandData(accumulated, currentValue) {
  return {
    clusterData: [accumulated.clusterData, currentValue.clusterData].flat(1),
    commandData: [accumulated.commandData, currentValue.commandData].flat(1),
    attributeData: [accumulated.attributeData, currentValue.attributeData].flat(
      1
    ),
  }
}
//This maps over each packageId, and runs the query callback.
function reduceAndConcatenateZclEntity(
  db,
  id,
  packageIdArray,
  zclQueryCallback,
  mergeFunction = (accumulated, currentValue) => {
    return [accumulated, currentValue].flat(1)
  },
  defaultValue = []
) {
  var dataArray = packageIdArray.map((packageId) =>
    zclQueryCallback(db, id, packageId)
  )
  return Promise.all(dataArray).then((x) =>
    x.reduce(mergeFunction, defaultValue)
  )
}

function parseForZclData(db, path, id, packageIdArray) {
  switch (path) {
    case 'cluster':
      return reduceAndConcatenateZclEntity(
        db,
        id,
        packageIdArray,
        returnZclEntitiesForClusterId,
        mergeZclClusterAttributeCommandData,
        { clusterData: [], attributeData: [], commandData: [] }
      ).then((data) => {
        return {
          data: data.clusterData,
          attributeData: data.attributeData,
          commandData: data.commandData,
          title: `Cluster: ${id}`,
          type: 'cluster',
        }
      })
      break
    case 'domain':
      return reduceAndConcatenateZclEntity(
        db,
        id,
        packageIdArray,
        zclEntityQuery(queryZcl.selectAllDomains, queryZcl.selectDomainById)
      ).then((data) => {
        return { data: data, title: `Domain: ${id}`, type: 'domain' }
      })
      break
    case 'bitmap':
      return reduceAndConcatenateZclEntity(
        db,
        id,
        packageIdArray,
        zclEntityQuery(queryZcl.selectAllBitmaps, queryZcl.selectBitmapById)
      ).then((x) => {
        return { data: x, title: `Bitmap: ${id}`, type: 'bitmap' }
      })
      break
    case 'enum':
      return reduceAndConcatenateZclEntity(
        db,
        id,
        packageIdArray,
        zclEntityQuery(queryZcl.selectAllEnums, queryZcl.selectEnumById)
      ).then((x) => {
        return { data: x, title: `Enum: ${id}`, type: 'enum' }
      })
      break
    case 'struct':
      return reduceAndConcatenateZclEntity(
        db,
        id,
        packageIdArray,
        zclEntityQuery(queryZcl.selectAllStructs, queryZcl.selectStructById)
      ).then((x) => {
        return { data: x, title: `Struct: ${id}`, type: 'struct' }
      })
      breaks
    case 'deviceType':
      return reduceAndConcatenateZclEntity(
        db,
        id,
        packageIdArray,
        zclEntityQuery(
          queryZcl.selectAllDeviceTypes,
          queryZcl.selectDeviceTypeById
        )
      ).then((x) => {
        return {
          data: x,
          title: `Device type: ${id}`,
          type: 'device_type',
        }
      })
      break
    case 'endpointTypeClusters':
      return queryZcl
        .selectEndpointTypeClustersByEndpointTypeId(db, id)
        .then((x) => {
          return { data: x, type: `endpointTypeClusters` }
        })
      break
    case 'endpointTypeAttributes':
      return queryZcl
        .selectEndpointTypeAttributesByEndpointId(db, id)
        .then((x) => {
          return { data: x, type: `endpointTypeAttributes` }
        })
      break
    case 'endpointTypeCommands':
      return queryZcl
        .selectEndpointTypeCommandsByEndpointId(db, id)
        .then((x) => {
          return { data: x, type: `endpointTypeCommands` }
        })
      break
    case `endpointTypeDeviceTypeClusters`:
      return queryZcl
        .selectDeviceTypeClustersByDeviceTypeRef(db, id)
        .then((x) => {
          return { data: x, type: `deviceTypeClusters` }
        })
      break
    case `endpointTypeDeviceTypeAttributes`:
      return queryZcl
        .selectDeviceTypeAttributesByDeviceTypeRef(db, id)
        .then((x) => {
          return { data: x, type: `deviceTypeAttributes` }
        })
      break
    case `endpointTypeDeviceTypeCommands`:
      return queryZcl
        .selectDeviceTypeCommandsByDeviceTypeRef(db, id)
        .then((x) => {
          return { data: x, type: `deviceTypeCommands` }
        })
      break
    default:
      return { type: 'Unknown' }
  }
}

function processGetEntityRequest(db, path, id, replyId, sessionId, callback) {
  queryPackage
    .getSessionPackages(db, sessionId)
    .then((packageIdArray) => {
      return parseForZclData(db, path, id, packageIdArray)
    })
    .then((finalData) => {
      callback(replyId, finalData)
    })
}

/**
 * API: /get/:entity/:id
 *
 * @export
 * @param {*} app Express instance.
 */
function registerStaticZclApi(db, app) {
  app.get('/get/:entity/:id', (request, response) => {
    const { id, entity } = request.params
    var sessionId = request.session.zapSessionId

    var processReply = (replyId, object) => {
      object.replyId = replyId
      response.status(httpServer.httpCode.ok).json(object)
    }
    var replyId = id === 'all' ? itemList : singleItem
    processGetEntityRequest(db, entity, id, replyId, sessionId, processReply)
  })
}

exports.registerStaticZclApi = registerStaticZclApi
<|endoftext|>