diff options
author | Matěj Cepl <mcepl@redhat.com> | 2011-01-20 15:58:49 +0100 |
---|---|---|
committer | Matěj Cepl <mcepl@redhat.com> | 2011-01-20 15:58:49 +0100 |
commit | 0c0fbbf5492e3a9ec9f8e4a1c9713883d3b350ac (patch) | |
tree | 1cc22de7167f8cd705e361de986515af41c6f200 /lib | |
parent | 1c12d7cfe11a0c9caa9f4c9b378da933fff4bb37 (diff) | |
download | bugzilla-triage-0c0fbbf5492e3a9ec9f8e4a1c9713883d3b350ac.tar.gz |
Just move key libraries to data/ to be made into content scripts.
Diffstat (limited to 'lib')
-rw-r--r-- | lib/bzpage.js | 1087 | ||||
-rw-r--r-- | lib/mozillabzpage.js | 19 | ||||
-rw-r--r-- | lib/rhbzpage.js | 1023 |
3 files changed, 0 insertions, 2129 deletions
diff --git a/lib/bzpage.js b/lib/bzpage.js deleted file mode 100644 index cb539dc..0000000 --- a/lib/bzpage.js +++ /dev/null @@ -1,1087 +0,0 @@ -/*jslint forin: true, rhino: true, onevar: false, browser: true, evil: true, laxbreak: true, undef: true, nomen: true, eqeqeq: true, bitwise: true, maxerr: 1000, immed: false, white: false, plusplus: false, regexp: false, undef: false, strict: true */ -// Released under the MIT/X11 license -// http://www.opensource.org/licenses/mit-license.php -"use strict"; -var util = require("util"); -var passUtils = require("passwords"); -var apiUtils = require("api-utils"); -var selfMod = require("self"); -var clip = require("clipboard"); -var preferences = require("preferences-service"); -var selection = require("selection"); -var prompts = require("prompts"); -var Request = require("request").Request; -var tabs = require("tabs"); -var Color = require("color").Color; - -var bugURL = "https://bugzilla.redhat.com/show_bug.cgi?id="; - -// Shared contstants -var NumberOfFrames = 7; -exports.NumberOfFrames = NumberOfFrames; -var BTSPrefNS = "bugzilla-triage.setting."; -exports.BTSPrefNS = BTSPrefNS; -var BTSPassRealm = "BTSXMLRPCPass"; - -// ============================================ - -var NotLoggedinException = function NotLoggedinException (message) { - this.message = message; - this.name = "NotLoggedinException"; -}; - -NotLoggedinException.prototype.toString = function () { - return this.name + ': "' + this.message + '"'; -}; -exports.NotLoggedinException = NotLoggedinException; - -// ==================================================================================== -// BZPage's methods -var BZPage = function BZPage(win, config) { - // constants - this.SalmonPink = new Color(255, 224, 176); // RGB 255, 224, 176; HSL 36, 2, - // 85 - this.ReporterColor = new Color(255, 255, 166); // RGB 255, 255, 166; HSL 60, 2, - // 83 - - // initialize dynamic properties - var that = this; - this.win = win; - this.doc = win.document; - this.hostname = this.win.location.hostname; - - // First, preflight check ... if we are not logged in, there - // is nothing we can do. - var logoutLink = Array.some(this.doc.links, function (x) { - return x.search === "?logout=1" ; - }); - if (!logoutLink) { - throw new NotLoggedinException("Not logged in"); - } - - // So, now we know we are logged in, so we can get to - // the real work. - this.packages = this.getInstalledPackages(config); - - if ("commentStrings" in config.gJSONData) { - this.commentStrings = config.gJSONData.commentStrings; - } - - this.constantData = {}; - if ("constantData" in config.gJSONData) { - this.constantData = config.gJSONData.constantData; - this.constantData.queryUpstreamBug = JSON.parse( - selfMod.data.load("queryUpstreamBug.json")); - this.constantData.XMLRPCData = JSON.parse( - selfMod.data.load("XMLRPCdata.json")); - } - - if ("CCmaintainer" in this.constantData) { - this.defBugzillaMaintainerArr = this.constantData.CCmaintainer; - } - - if ("suspiciousComponents" in config.gJSONData.configData) { - this.suspiciousComponents = config.gJSONData.configData.suspiciousComponents; - } - - if ("XorgLogAnalysis" in config.gJSONData.configData) { - this.xorglogAnalysis = config.gJSONData.configData.XorgLogAnalysis; - } - - if ("submitsLogging" in config.gJSONData.configData && - config.gJSONData.configData.submitsLogging) { - this.log = config.logger; - this.setUpLogging(); - } - - if ("killNodes" in config.gJSONData.configData && - this.hostname in config.gJSONData.configData.killNodes) { - var killConf = config.gJSONData.configData.killNodes[this.hostname]; - util.killNodes(this.doc, killConf[0], killConf[1]); - } - - this.setConfigurationButton(); - this.submitHandlerInstalled = false; - - this.login = this.getLogin(); - // XML-RPC password - if (this.hostname in this.constantData.XMLRPCData) { - this.password = this.getPassword(this.login); - } - - this.bugNo = util.getBugNo(this.doc.location.toString()); - - // deal with aliases - if (isNaN(parseInt(this.bugNo, 10)) && this.password) { - this.bugNo = this.getRealBugNo(); - } - - this.title = this.doc.getElementById("short_desc_nonedit_display").textContent; - this.CCList = this.getCCList(); - - // Prepare for query buttons - // element ID brElementPlace_location is later used in JSON files - // Stay with this add_comment element even if RH BZ upgrades, this seems - // to be generally much more stable (even with other bugzillas, e.g. b.gnome.org) - // then some getElementById. - var commentArea = this.doc.getElementsByName("add_comment")[0].parentNode; - if (commentArea) { - var brElementPlacer = commentArea.getElementsByTagName("br"); - brElementPlacer = brElementPlacer[0]; - if (brElementPlacer) { - brElementPlacer.setAttribute("id","brElementPlacer_location"); - brElementPlacer.parentNode.insertBefore(this.doc.createElement("br"), - brElementPlacer); - } - } - - this.checkComments(); - this.generateButtons(); -}; - -/** - * In case URL contains alias, not the real bug number, get the real bug no - * from the XML representation. Sets correct value to this.bugNo. - */ -BZPage.prototype.getRealBugNo = function () { - console.log("We have to deal with bug aliased as " + this.bugNo); - var that = this; - // https://bugzilla.redhat.com/show_bug.cgi?ctype=xml&id=serialWacom - Request({ - url: this.win.location.href+"&ctype=xml", - onComplete: function(response) { - if (response.status === 200) { - var xmlRepr = response.xml; - var bugID = parseInt(xmlRepr.getElementsByTagName("bug_id")[0].textContent, 10); - if (isNaN(bugID)) { - throw new Error("Cannot get bug no. even from XML representation!"); - } - that.bugNo = bugID; - console.log("The real bug no. is " + bugID); - } - } - }).get(); -}; - -/** - * - */ -BZPage.prototype.getInstalledPackages = function getInstalledPackages(cfg) { - var installedPackages = {}; - var enabledPackages = []; - - // Collect enabled packages per hostname (plus default ones) - if (cfg.gJSONData && ("commentPackages" in cfg.gJSONData)) { - if ("enabledPackages" in cfg.gJSONData.configData) { - var epObject = cfg.gJSONData.configData.enabledPackages; - if (this.hostname in epObject) { - enabledPackages = enabledPackages.concat(epObject[this.hostname].split(/[,\s]+/)); - } - if ("any" in epObject) { - enabledPackages = enabledPackages.concat(epObject.any.split(/[,\s]+/)); - } - } - - if ((enabledPackages.length === 1) && (enabledPackages[0] === "all")) { - enabledPackages = []; - for (var key in cfg.gJSONData.commentPackages) { - enabledPackages.push(key); - } - } - - enabledPackages.forEach(function (pkg, idx, arr) { - if (pkg in cfg.gJSONData.commentPackages) { - installedPackages[pkg] = cfg.gJSONData.commentPackages[pkg]; - } - }); - } - return installedPackages; -}; - -/** - * Actual execution function - * - * @param cmdLabel String with the name of the command to be executed - * @param cmdParams Object with the appropriate parameters for the command - */ -BZPage.prototype.centralCommandDispatch = function centralCommandDispatch (cmdLabel, cmdParams) { - switch (cmdLabel) { - case "resolution": - case "product": - case "component": - case "version": - case "priority": - this.selectOption(cmdLabel, cmdParams); - break; - case "status": - this.selectOption("bug_status", cmdParams); - break; - case "platform": - this.selectOption("rep_platform", cmdParams); - break; - case "os": - this.selectOption("op_sys", cmdParams); - break; - case "severity": - this.selectOption("bug_severity", cmdParams); - break; - case "target": - this.selectOption("target_milestone", cmdParams); - break; - case "addKeyword": - this.addStuffToTextBox("keywords",cmdParams); - break; - case "removeKeyword": - this.removeStuffFromTextBox("keywords", cmdParams); - break; - case "addWhiteboard": - this.addStuffToTextBox("status_whiteboard",cmdParams); - break; - case "removeWhiteboard": - this.removeStuffFromTextBox("status_whiteboard",cmdParams); - break; - case "assignee": - this.changeAssignee(cmdParams); - break; - case "qacontact": - this.clickMouse("bz_qa_contact_edit_action"); - this.doc.getElementById("qa_contact").value = cmdParams; - break; - case "url": - this.clickMouse("bz_url_edit_action"); - this.doc.getElementById("bug_file_loc").value = cmdParams; - break; - // TODO dependson/blocked doesn't work. Find out why. - case "addDependsOn": - this.clickMouse("dependson_edit_action"); - this.addStuffToTextBox("dependson", cmdParams); - break; - case "removeDependsOn": - this.clickMouse("dependson_edit_action"); - this.removeStuffFromTextBox("dependson", cmdParams); - break; - case "addBlocks": - this.clickMouse("blocked_edit_action"); - this.addStuffToTextBox("blocked", cmdParams); - break; - case "removeBlocks": - this.clickMouse("blocked_edit_action"); - this.removeStuffFromTextBox("blocked", cmdParams); - break; - case "comment": - this.addStuffToTextBox("comment", cmdParams); - break; - case "commentIdx": - var commentText = this.commentStrings[cmdParams]; - this.addStuffToTextBox("comment", commentText); - break; - case "setNeedinfo": - // cmdParams are actually ignored for now; we may in future - // distinguish different actors to be target of needinfo - this.setNeedinfoReporter(); - break; - case "addCC": - this.addToCCList(cmdParams); - break; - case "queryStringOurBugzilla": - this.queryForSelection(); - break; - // TODO flags, see also - - case "commit": - if (cmdParams) { - // Directly commit the form - this.doc.forms.namedItem("changeform").submit(); - } - break; - } -}; - -/** - * Take the ID of the package/id combination, and execute it - * - * @param String combined package + "//" + id combination - * Fetches the command object from this.installedPackages and then - * goes through all commands contained in it, and calls - * this.centralCommandDispatch to execute them. - * - * PROBLEM: according to https://developer.mozilla.org/en/Core_JavaScript_1.5_Reference\ - * /Statements/for...in there is no guaranteed order of execution of - * commands (i.e., key, commentObj[key] pairs) in for..in cycle. - * According to https://developer.mozilla.org/en/Core_JavaScript_1.5_Reference\ - * /Operators/Special_Operators/delete_Operator#Cross-browser_issues it seems that - * everywhere except of Internet Explorer this should work well, but waiting - * impatiently when this bite us. - */ -BZPage.prototype.executeCommand = function executeCommand (cmd) { - var cmdArr = cmd.split("//"); - var commentObj = this.packages[cmdArr[0]][cmdArr[1]]; - - for (var key in commentObj) { - this.centralCommandDispatch(key,commentObj[key]); - } -}; - -/** - * Change assignee of the bug - * - * @param newAssignee String with the email address of new assigneeAElement - * or 'default' if the component's default assignee should be used. - * Value null clears "Reset Assignee to default for component" checkbox - * @return none - */ -BZPage.prototype.changeAssignee = function changeAssignee (newAssignee) { - var defAssigneeButton = null; - // Previous assignee should know what's going on in his bug - this.addToCCList(this.owner); - - // Optional value null - if (newAssignee === null) { - this.doc.getElementById("set_default_assignee").removeAttribute( - "checked"); - return ; - } - - if (this.getDefaultAssignee) { - if (newAssignee === "default") { - var defAss = this.getDefaultAssignee(); - if (defAss) { - newAssignee = defAss; - } else { - return ; - } - } - } - - if (newAssignee) { - this.clickMouse("bz_assignee_edit_action"); - this.doc.getElementById("assigned_to").value = newAssignee; - this.doc.getElementById("set_default_assignee").checked = false; - defAssigneeButton = this.doc.getElementById("setDefaultAssignee_btn"); - if (defAssigneeButton) { - defAssigneeButton.style.display = "none"; - } - } -}; - -/** - * Adds new option to the 'comment_action' scroll down box - * - * @param pkg String package name - * @param cmd String with the name of the command - * If the 'comment_action' scroll down box doesn't exist, this - * function will set up new one. - */ -BZPage.prototype.addToCommentsDropdown = function addToCommentsDropdown (pkg, cmd) { - var select = this.doc.getElementById("comment_action"); - if (!select) { - var that = this; - this.doc.getElementById("comments").innerHTML += - "<div id='make_bugzilla_comment_action'>" + - " <label for='comment_action'>Add Comment: </label>" + - " <select id='comment_action'>" + - " <option value=''>-- Select Comment from List --</option>" + - "</div>"; - select = this.doc.getElementById("comment_action"); - select.addEventListener("change", function (evt) { - var value = ""; - var valueElement = that.doc.getElementById("comment_action"); - if (valueElement) { - var selIdx = valueElement.selectedIndex; - value = valueElement.options[selIdx].value; - console.log("value = " + value); - } else { - return; - } - that.executeCommand(value); - }, false); - } - - var opt = this.doc.createElement("option"); - opt.value = pkg + "//" + cmd; - opt.textContent = this.packages[pkg][cmd].name; - select.appendChild(opt); -}; - -/** - * Create a A element leadink nowhere, but with listener running a callback on the click - * - * @param id String with a id to be added to the element - * @param text String with a string to be added as a textContent of the element - * @param parent Node which is a parent of the object - * @param callback Function to be called after clicking on the link - * @param params Array with parameters of the callback - * @param Boolean breakBefore if there should be a <br> element before. - * @return none - */ -BZPage.prototype.createDeadLink = function createDeadLink (id, text, parent, callback, params, before, covered, accesskey) { - var that = this; - params = util.valToArray(params); - var locParent = {}; - - // Yes, I want != here, not !== - if (covered != null) { - locParent = this.doc.createElement(covered); - parent.appendChild(locParent); - } else { - locParent = parent; - } - - var newAElem = this.doc.createElement("a"); - newAElem.setAttribute("id", id); - if (accesskey) { - newAElem.setAttribute("accesskey", accesskey); - } - newAElem.setAttribute("href", ""); - newAElem.textContent = text; - - newAElem.addEventListener("click", function(evt) { - callback.apply(that, params); - evt.stopPropagation(); - evt.preventDefault(); - }, false); - - if ((before === "br") || (before === true)) { - locParent.appendChild(this.doc.createElement("br")); - } else if (before === "dash") { - locParent.appendChild(this.doc.createTextNode("\u00A0-\u00A0")); - } - - locParent.appendChild(newAElem); -}; - - -/** - * Generic function to add new button to the page. Actually copies new button - * from the old one (in order to have the same look-and-feel, etc. - * - * @param location Object around which the new button will be added - * @param after Boolean before or after location ? - * @param pkg String which package to take the command from - * @param id String which command to take - * @return none - */ -BZPage.prototype.createNewButton = function createNewButton (location, after, pkg, id) { - var that = this; - var cmdObj = this.packages[pkg][id]; - var newId = id + "_btn"; - var label = cmdObj.name; - - // protection against double-firings - if (this.doc.getElementById(newId)) { - console.log("Element with id " + newId + "already exists!"); - return ; - } - - // creation of button might be conditional on existence of data in constantData - if ("ifExist" in cmdObj) { - if (!(cmdObj.ifExist in this.constantData)) { - return ; - } - } - - var newButton = this.doc.createElement("input"); - newButton.setAttribute("id", newId); - newButton.setAttribute("type", "button"); - newButton.value = label; - newButton.addEventListener("click", function(evt) { - that.executeCommand(pkg + "//" + id); - }, false); - - var originalLocation = this.doc.getElementById(location); - - try { - if (after) { - originalLocation.parentNode.insertBefore(newButton, - originalLocation.nextSibling); - originalLocation.parentNode.insertBefore(this.doc - .createTextNode("\u00A0"), newButton); - } else { - originalLocation.parentNode.insertBefore(newButton, originalLocation); - originalLocation.parentNode.insertBefore(this.doc - .createTextNode("\u00A0"), originalLocation); - } - } catch (e) { - if (e instanceof TypeError) { - console.error("cannot find originalLocation element with id " + location); - } else { - throw e; - } - } -}; - -/** - * - */ -BZPage.prototype.generateButtons = function generateButtons () { - var topRowPosition = "topRowPositionID"; - var bottomRowPosition = "commit"; - - // create anchor for the top toolbar - var commentBox = this.doc.getElementById("comment"); - var brElement = this.doc.createElement("br"); - brElement.setAttribute("id",topRowPosition); - commentBox.parentNode.normalize(); - commentBox.parentNode.insertBefore(brElement, commentBox); - - for (var pkg in this.packages) { - for (var cmdIdx in this.packages[pkg]) { - var cmdObj = this.packages[pkg][cmdIdx]; - switch (cmdObj.position) { - case "topRow": - this.createNewButton(topRowPosition, false, pkg, cmdIdx); - break; - case "bottomRow": - this.createNewButton(bottomRowPosition, false, pkg, cmdIdx); - break; - case "dropDown": - this.addToCommentsDropdown(pkg,cmdIdx); - break; - default: // [+-]ID - var firstChr = cmdObj.position.charAt(0); - var newId = cmdObj.position.substr(1); - this.createNewButton(newId, firstChr === "+", pkg, cmdIdx); - break; - } - } - } -}; - -BZPage.prototype.setConfigurationButton = function setConfigurationButton () { - var additionalButtons = this.doc.querySelector("#bugzilla-body *.related_actions"); - var configurationButtonUI = this.doc.createElement("li"); - configurationButtonUI.innerHTML = "\u00A0-\u00A0<a href='' id='configurationButton'>" - + "Triage configuration</a>"; - additionalButtons.appendChild(configurationButtonUI); - this.doc.getElementById("configurationButton").addEventListener( - "click", - function(evt) { - var prfNm = BTSPrefNS+"JSONURL"; - var url = preferences.get(prfNm,""); - - var reply = prompts.prompt("New location of JSON configuration file", url); - if (reply) { - preferences.set(prfNm, reply.trim()); - prompts.alert("For now, you should really restart Firefox!"); - } - - evt.stopPropagation(); - evt.preventDefault(); - }, false); -}; - -/* - * From <a> element diggs out just plain email address - * Note that bugzilla.gnome.org doesn't have mailto: url but - * https://bugzilla.gnome.org/page.cgi?id=describeuser.html&login=mcepl%40redhat.com - * - * @param aElement Element with href attribute or something else - * @return String with the address or null - * - */ -BZPage.prototype.parseMailto = function parseMailto(aElement) { - var emailStr = "", hrefStr = ""; - // use url utils - if (aElement) { - hrefStr = decodeURIComponent(aElement.getAttribute("href")); - emailStr = hrefStr.split(":")[1]; - // - if (emailStr === undefined) { - var params = util.getParamsFromURL("https://" + this.hostname + "/" + hrefStr); - emailStr = decodeURI(params.login); - } - return emailStr; - } - return null; -}; - -/** - * Get the current email of the reporter of the bug. - * - * @return string - */ -BZPage.prototype.getReporter = function getReporter () { - var reporterElement = this.getOptionTableCell("bz_show_bug_column_2", "Reported"); - // RH Bugzilla after upgrade to 3.6.2 moved the information to other column - if (!reporterElement) { - reporterElement = this.getOptionTableCell("bz_show_bug_column_1", "Reported", true); - } - // Maemo calls the label "Reporter" and it doesn't have ids on table columns ... TODO(maemo) - - return this.parseMailto(reporterElement); -}; - -BZPage.prototype.getComponent = function getComponent() { - var elem = this.doc.getElementById("component"); - if (elem) { - return elem.value; - } - return null; -}; - - -BZPage.prototype.commentsWalker = function commentsWalker (fce) { - var comments = this.doc.getElementById("comments").getElementsByClassName( - "bz_comment"); - Array.forEach(comments, function(item) { - fce(item); - }, this); -}; - -/** - * Set background color of all comments made by reporter in ReporterColor color - * - */ -BZPage.prototype.checkComments = function checkComments () { - var that = this; - var reporterRE = new RegExp(this.getReporter()); - this.commentsWalker(function(x) { - var email = that.parseMailto(x.getElementsByClassName("vcard")[0] - .getElementsByTagName("a")[0]); - if (reporterRE.test(email)) { - x.style.backgroundColor = that.ReporterColor.toString(); - } - }); -}; - -BZPage.prototype.collectComments = function collectComments () { - var outStr = ""; - this.commentsWalker(function(x) { - outStr += x.getElementsByTagName("pre")[0].textContent + "\n"; - }); - return outStr.trim(); -}; - - -/** - * Select option with given value on the <SELECT> element with given id. - * - * Also execute change HTMLEvent, so that the form behaves accordingly. - * - * @param id - * @param label - * @return none - * - */ -BZPage.prototype.selectOption = function selectOption (id, label, fireEvent) { - if (!fireEvent) { - fireEvent = true; - } - var sel = this.doc.getElementById(id); - sel.value = label; - if (fireEvent) { - var intEvent = this.doc.createEvent("HTMLEvents"); - intEvent.initEvent("change", true, true); - sel.dispatchEvent(intEvent); - } -}; - -BZPage.prototype.selectOptionByLabel = function selectOptionByLabel(id, label, fireEvent) { - if (!fireEvent) { - fireEvent = true; - } - var sel = this.doc.getElementById(id); - var labelRE = new RegExp(label.trim()); - var ourOption = Array.filter(sel.options, function (op) { - return op.textContent.trim() === label; - }, this); - - if (ourOption[0]) { - sel.value = ourOption[0].value; - } - - if (fireEvent) { - var intEvent = this.doc.createEvent("HTMLEvents"); - intEvent.initEvent("change", true, true); - sel.dispatchEvent(intEvent); - } -}; - -/** - * Send mouse click to the specified element - * - * @param String ID of the element to send mouseclick to - * @return None - */ -BZPage.prototype.clickMouse = function clickMouse (targetID) { - var localEvent = this.doc.createEvent("MouseEvents"); - localEvent.initMouseEvent("click", true, true, this.doc.defaultView, 0, 0, - 0, 0, 0, false, false, false, false, 0, null); - this.doc.getElementById(targetID).dispatchEvent(localEvent); -}; - -/** - * Add object to the text box (comment box or status whiteboard) - * - * @param id String with the id of the element - * @param stuff String/Array to be added to the comment box - * - * @return none - */ -BZPage.prototype.addStuffToTextBox = function addStuffToTextBox (id, stuff) { - var textBox = this.doc.getElementById(id); - if (textBox.tagName.toLowerCase() === "textarea") { - stuff = textBox.value ? "\n\n" + stuff : stuff; - textBox.value += stuff; - } else { - textBox.value = util.addCSVValue(textBox.value,stuff); - } -}; - -/** - * Remove a keyword from the element if it is there - * - * @param id String with the id of the element - * @param stuff String/Array with keyword(s) to be removed - */ -BZPage.prototype.removeStuffFromTextBox = function removeStuffFromTextBox (id, stuff) { - var changedElement = this.getElementById(id); - changedElement.value = util.removeCSVValue(changedElement.value,stuff); -}; - -/** - * generalized hasKeyword ... search in the value of the box with given id - * - * @param id String with ID of the element we want to check - * @param str String to be searched for - * @return Boolean found? - */ -BZPage.prototype.idContainsWord = function idContainsWord (id, str) { - var kwd = ""; - try { - kwd = this.doc.getElementById(id).value; - } catch (e) { - // For those who don't have particular element at all or if it is empty - return false; - } - return (util.isInList(str, kwd.trim().split(/[,\s]+/))); -}; - -/** - * Check for the presence of a keyword - * - * @param str String with the keyword - * @return Boolean - */ -BZPage.prototype.hasKeyword = function hasKeyword (str) { - return (this.idContainsWord('keywords', str)); -}; - -/** - -@return Element with the href attribute containng the information - */ -BZPage.prototype.getOptionTableCell = function getOptionTableCell(tableId, label) { - var cleanLabelRE = /^\s*([^.:]*):?\s*$/; - label = label.trim().replace(cleanLabelRE,"$1").toLowerCase(); - - var rows = this.doc.getElementById(tableId).getElementsByTagName("tr"); - var ourLine = Array.filter(rows, function(row) { - var curLabel = row.getElementsByTagName("td")[0].textContent.toLowerCase(); - curLabel = curLabel.replace(cleanLabelRE,"$1"); - return (curLabel === label); // maybe this could be a RE match instead - }); - - if (ourLine.length > 0) { - return ourLine[0].getElementsByTagName("td")[1]. - getElementsByTagName("a")[0]; - } - return null; -}; - -/** - * Set the bug to NEEDINFO state - * - * Working function. - * @return none - * @todo TODO we may extend this to general setNeedinfo function - * with parameter [reporter|assignee|general-email-address] - */ -BZPage.prototype.setNeedinfoReporter = function setNeedinfoReporter () { - this.clickMouse("needinfo"); - this.selectOption("needinfo_role", "reporter"); -}; - -/** - * - */ -BZPage.prototype.getOwner = function getOwner () { - // TODO(maemo) doesn't work on maemo - var assigneeAElement = this.getOptionTableCell("bz_show_bug_column_1","Assigned To"); - return this.parseMailto(assigneeAElement); -}; - -/** - * Return maintainer which is per default by bugzilla - * (which is not necessarily the one who is default maintainer per component) - * - * @return String with the maintainer's email address - */ -BZPage.prototype.getDefaultBugzillaMaintainer = function getDefaultBugzillaMaintainer (component) { - var address = util.filterByRegexp(this.defBugzillaMaintainerArr, component); - return address; -}; - -/** - * Parse the row with the attachment - * - * @param DOM element to be parsed - * @return array with string name of the attachment, integer its id number, - * string of MIME type, integer of size in kilobytes, and the whole - * element itself - */ -BZPage.prototype.parseAttachmentLine = function(inElem) { - var MIMEtype = ""; - var size = 0; - - // Skip over obsolete attachments - if (inElem.getElementsByClassName("bz_obsolete").length > 0) { - return ( []); - } - - // getting name of the attachment - // TODO probably could use url.URL object - var attName = inElem.getElementsByTagName("b")[0].textContent.trim(); - - var aHrefsArr = inElem.getElementsByTagName("a"); - var aHref = Array.filter(aHrefsArr, function(x) { - return x.textContent.trim() === "Details"; - })[0]; - var id = parseInt(aHref.getAttribute("href").replace( - /^.*attachment.cgi\?id=/, ""), 10); - - // getting MIME type and size - var stringArray = inElem.getElementsByClassName("bz_attach_extra_info")[0].textContent - .replace(/[\n ()]+/g, " ").trim().split(", "); - size = parseInt(stringArray[0], 10); - MIMEtype = stringArray[1].split(" ")[0]; - - return [ attName, id, MIMEtype, size, inElem ]; -}; - -/** - * collect the list of attachments in a structured format - * - * @return Array of arrays, one for each attachments; - * each record has string name of the attachment, integer its id number, - * string of MIME type, integer of size in kilobytes, and the whole - * element itself - */ -BZPage.prototype.getAttachments = function getAttachments () { - var outAtts = []; - var atts = this.doc.getElementById("attachment_table") - .getElementsByTagName("tr"); - for ( var i = 1, ii = atts.length - 1; i < ii; i++) { - outAtts.push(this.parseAttachmentLine(atts[i])); - } - return outAtts; -}; - -/** - * Get login of the currently logged-in user. - * - * @return String with the login name of the currently logged-in user - */ -BZPage.prototype.getLogin = function getLogin () { - var lastLIElement = this.doc.querySelector("#header ul.links li:last-of-type"); - var loginArr = lastLIElement.textContent.split("\n"); - var loginStr = loginArr[loginArr.length - 1].trim(); - return loginStr; -}; - -/** - * returns password from the current storage, or if there isn't - * one, then it will ask user for it. - * - * @return String with the password - */ -BZPage.prototype.getPassword = function getPassword (login) { - var passPrompt = "Enter your Bugzilla password for fixing MIME attachment types"; - var switchPrompt = "Do you want to switch off features requiring password completely?"; - var prefName = BTSPrefNS+"withoutPassowrd"; - var domain = this.win.location.protocol + "//" + this.hostname; - - var pass = passUtils.getPassword(login, domain, BTSPassRealm); - // pass === null means no appropriate password in the storage - if (!preferences.get(prefName,false) && (pass === null)) { - var passwordText = prompts.promptPassword(passPrompt); - if (passwordText && passwordText.length > 0) { - passUtils.setLogin(login, passwordText, domain, - BTSPassRealm); - return passwordText; - } else { - var switchOff = prompts.promptYesNoCancel(switchPrompt); - if (switchOff) { - preferences.set(prefName,true); - } - return null; - } - } else { - return pass; - } -}; - -/** - * - */ -BZPage.prototype.setUpLogging = function setUpLogging () { - // Protection against double-call - if (this.doc.getElementById("generateTSButton")) { - return ; - } - - // For adding additional buttons to the top toolbar - var additionalButtons = this.doc.querySelector("#bugzilla-body *.related_actions"); - var that = this; - - // logging all submits for timesheet - if (!this.submitHandlerInstalled) { - this.doc.forms.namedItem("changeform").addEventListener("submit",function (evt) { - var resp = that.log.addLogRecord(that); - if (resp === null) { - evt.stopPropagation(); - evt.preventDefault(); - } - }, false); - this.submitHandlerInstalled = true; - } - - // (id, text, parent, callback, params, before, covered, accesskey) - this.createDeadLink("generateTSButton", "Generate TS", additionalButtons, - function(evt) { - that.log.createBlankPage.call(that.log, "TimeSheet", - that.log.generateTimeSheet); - }, [], "dash", "li"); - - this.createDeadLink("clearLogs", "Clear TS", additionalButtons, - function(evt) { - that.log.clearStore(this); - }, [], "dash", "li"); - - this.createDeadLink("importTSButton", "Import TS", additionalButtons, - function(evt) { - jsonPaths = prompts.promptFileOpenPicker(that.win); - that.log.importOtherStore(jsonPaths, clearLogAElem); - }, [], "dash", "li"); - - var clearLogAElem = this.doc.getElementById("clearLogs"); - if (this.log.isEmpty()) { - clearLogAElem.style.color = this.log.EmptyLogsColor; - clearLogAElem.style.fontWeight = "normal"; - } else { - clearLogAElem.style.color = this.log.FullLogsColor; - clearLogAElem.style.fontWeight = "bolder"; - } -}; - -BZPage.prototype.getSelectionOrClipboard = function getSelectionOrClipboard () { - var text = selection.text; - if (!text) { - text = clip.get(); - } - return text; -}; - -/** - * Opens a new tab with a query for the given text in the selected component - * - * @param text to be searched for - * @param component String with the component name (maybe latter regexp?) - * @param product (optional) string with the product name, if undefined, - * search in all products - * @return None - * - */ -BZPage.prototype.queryInNewTab = function(text, component, product) { - var urlStr = "https://bugzilla.redhat.com/buglist.cgi?query_format=advanced"; - if (product) { - urlStr += "&product=" + product.trim(); - } - if (component) { - if ("equivalentComponents" in this.constantData) { - var equivCompsArr = this.constantData["equivalentComponents"]. - filter(function (REstr) { - return new RegExp(REstr).test(this.getComponent()); - }, this); - if (equivCompsArr.length > 0) { - component = equivCompsArr[0]; - } - urlStr += "&field0-0-0=component&type0-0-0=regexp&value0-0-0=" - + component.trim(); - } else { - urlStr += "&field0-0-0=component&type0-0-0=substring&value0-0-0=" - + component.trim(); - } - } - - // using more complicated query tables here, because they can be more easily - // edited - // for further investigative searches - if (text) { - text = encodeURIComponent(text.trim()); - var searchText = "&field1-0-0=longdesc&type1-0-0=substring&value1-0-0=" - + text - + "&field1-0-1=attach_data.thedata&type1-0-1=substring&value1-0-1=" - + text - + "&field1-0-2=status_whiteboard&type1-0-2=substring&value1-0-2=" - + text; - urlStr += searchText; - tabs.open({ - url: urlStr, - inBackground: true, - onOpen: function (t) { - tabs.activeTab = t; - } - }); - } -}; - -/** - * Get the text to search for and prepare other things for the real executive - * function this.queryInNewTab, and run it. - */ -BZPage.prototype.queryForSelection = function() { - var text = this.getSelectionOrClipboard(); - if (text) { - this.queryInNewTab(text, this.getComponent()); - } -}; - -/** - * adds a person to the CC list, if it isn't already there - * - * @param who String with email address or "self" if the current user - * of the bugzilla should be added - */ -BZPage.prototype.addToCCList = function addToCCList (who) { - if (!who) { - return ; - } - if (who === "self") { - this.doc.getElementById("addselfcc").checked = true; - } else { - this.clickMouse("cc_edit_area_showhide"); - if (!util.isInList(who, this.CCList)) { - this.addStuffToTextBox("newcc",who); - } - } -}; - -/** - * a collect a list of emails on CC list - * - * @return Array with email addresses as Strings. - */ -BZPage.prototype.getCCList = function getCCList () { - var CCListSelect = this.doc.getElementById("cc"); - var outCCList = []; - if (CCListSelect) { - outCCList = Array.map(CCListSelect.options, function(item) { - return item.value; - }); - } - return outCCList; -}; - -// exports.BZPage = apiUtils.publicConstructor(BZPage); -exports.BZPage = BZPage; diff --git a/lib/mozillabzpage.js b/lib/mozillabzpage.js deleted file mode 100644 index 31f6332..0000000 --- a/lib/mozillabzpage.js +++ /dev/null @@ -1,19 +0,0 @@ -// Released under the MIT/X11 license -// http://www.opensource.org/licenses/mit-license.php -"use strict"; -var utilMod = require("util"); -var apiUtils = require("api-utils"); -var BZPage = require("bzpage").BZPage; - -// ============================================================================ -// MozillaBugzilla object - -var MozillaBugzilla = function MozillaBugzilla (doc, config) { - BZPage.call(this, doc, config); -}; - -MozillaBugzilla.prototype = utilMod.heir(BZPage); -MozillaBugzilla.prototype.constructor = MozillaBugzilla; - -// exports.MozillaBugzilla = apiUtils.publicConstructor(MozillaBugzilla); -exports.MozillaBugzilla = MozillaBugzilla;
\ No newline at end of file diff --git a/lib/rhbzpage.js b/lib/rhbzpage.js deleted file mode 100644 index 10090a7..0000000 --- a/lib/rhbzpage.js +++ /dev/null @@ -1,1023 +0,0 @@ -/*jslint onevar: false, browser: true, evil: true, laxbreak: true, undef: true, nomen: true, eqeqeq: false, bitwise: true, maxerr: 1000, immed: false, white: false, plusplus: false, regexp: false, undef: false */ -// Released under the MIT/X11 license -// http://www.opensource.org/licenses/mit-license.php -"use strict"; -var util = require("util"); -var xrpc = require("xmlrpc"); -var apiUtils = require("api-utils"); -var self = require("self"); -var Color = require("color").Color; -var BZPage = require("bzpage").BZPage; -var Request = require("request").Request; -var url = require("url"); -var timer = require("timer"); -var selection = require("selection"); -var tabs = require("tabs"); -var NumberOfFrames = require("bzpage").NumberOfFrames; -var titleParsedAttachment = "Part of the thread where crash happened"; -// ==================================================================================== -// RHBugzillaPage object - -var RHBugzillaPage = function RHBugzillaPage(win, config) { - // inheritance ... call superobject's constructor - BZPage.call(this, win, config); - - // For identification of graphics card - this.manuChipStrs = [ [ "ATI Radeon", "ATI", "1002" ], - [ "ATI Mobility Radeon", "ATI", "1002" ], - [ "Intel Corporation", "INTEL", "8086" ], [ "NVIDIA", "NV", "10de" ] ]; - - // http://en.wikipedia.org/wiki/HSL_color_space - // when only the value of S is changed - // stupido!!! the string is value in hex for each color - this.RHColor = new Color(158, 41, 43); // RGB 158, 41, 43; HSL 359, 1, 39 - this.FedoraColor = new Color(0, 40, 103); // RGB 0, 40, 103; HSL 359, 1, 39 - this.RawhideColor = new Color(0, 119, 0); // or "green", or RGB 0, 119, 0, or - // HSL - // 120, 0, 23 - this.RHITColor = new Color(102, 0, 102); // RGB 102, 0, 102; HSL 300, 0, 20 - - this.RE = { - Comment: new RegExp("^\\s*#"), // unsused - BlankLine: new RegExp("^\\s*$"), // unused - // new line - // [ 65.631] (--) intel(0): Chipset: "845G" - Chipset: new RegExp("^\\s*\\[?[ 0-9.]*\\]?\\s*\\(--\\) "+ - "([A-Za-z]+)\\([0-9]?\\): Chipset: (.*)$"), - ATIgetID: new RegExp("^.*\\(ChipID = 0x([0-9a-fA-F]+)\\).*$"), - Abrt: new RegExp("^\\s*\\[abrt\\]"), - signalHandler: new RegExp("^\\s*#[0-9]*\\s*<signal handler called>"), - frameNo: new RegExp("^\\s*#([0-9]*)\\s"), - soughtLines: new RegExp("^\\s*(\\[[0-9 .]*\\])?\\s*(\\((EE|WW)\\)|.* [cC]hipsets?: )|\\s*Backtrace") - }; - // END OF CONSTANTS - - var that = this; - this.reqCounter = 0; - this.signaturesCounter = 0; - this.chipMagicInterestingLine = ""; - - this.product = this.doc.getElementById("product").value; - - this.maintCCAddr = null; - if (this.constantData.CCmaintainer) { - this.maintCCAddr = util.filterByRegexp(this.constantData.CCmaintainer, - this.getComponent()); - } - - var ITbutton = this.doc.getElementById("cf_issuetracker"); - this.its = ITbutton ? ITbutton.value.trim() : ""; - - if (!this.constantData.ProfessionalProducts) { - this.constantData.ProfessionalProducts = - JSON.parse(self.data.load("professionalProducts.json")); - } - - // getBadAttachments - this.XorgLogAttList = []; - this.XorgLogAttListIndex = 0; - this.attachments = this.getAttachments(); - this.markBadAttachments(this.attachments); - - this.parsedAttachments = this.attachments.filter(function (att) { - return (new RegExp(titleParsedAttachment).test(att[0])); - }); - - if (this.constantData.defaultAssignee) { - this.setDefaultAssignee(); - } - - // Dig out backtrace protection against double-firing? - this.btSnippet = ""; - - var parseAbrtBacktraces = config.gJSONData.configData.parseAbrtBacktraces; - if (parseAbrtBacktraces && this.RE.Abrt.test(this.title)) { - this.pasteBacktraceInComments(); - } - - // Find out Xorg.0.log attachment URL - this.XorgLogAttList = this.attachments.filter(function (value, index, array) { - // Xorg.0.log must be text, otherwise we cannot parse it - return (/[xX].*log/.test(value[0]) && /text/.test(value[2])); - }); - this.addCheckXorgLogLink(); - - // TODO Get compiz bugs as well - if (this.constantData.PCI_ID_Array && - (this.XorgLogAttList[0]) && - (this.maintCCAddr === "xgl-maint@redhat.com")) { - // Add find chip magic button - var whiteboard_string = this.doc.getElementById("status_whiteboard").value; - if (!/card_/.test(whiteboard_string)) { - this.fillInChipMagic(); - } - } - - // Take care of signature for Fedora bugzappers - if (config.gJSONData.configData.signature.length > 0) { - var signatureFedoraString = config.gJSONData.configData.signature; - this.doc.forms.namedItem("changeform").addEventListener("submit", - function(aEvt) { - if (that.signaturesCounter < 1) { - that.addStuffToTextBox("comment", signatureFedoraString); - that.signaturesCounter += 1; - } - }, false); - } - - this.setBranding(); - - // set default assignee on change of the component - var compElement = this.doc.getElementById("component"); - if (compElement && (compElement.options)) { - this.doc.getElementById("component").addEventListener("change", - function() { - that.changeAssignee("default"); - }, false); - } - -}; // END OF RHBugzillaPage CONSTRUCTOR - -RHBugzillaPage.prototype.toString = function toString () { - return ("[Object RHBugzillaPage]"); -}; - -RHBugzillaPage.prototype = util.heir(BZPage); -RHBugzillaPage.prototype.constructor = RHBugzillaPage; - -/** - * Find default assignee based on the current component - * - * @return String what would be a default assignee if - * we haven't set it up. - */ -RHBugzillaPage.prototype.getDefaultAssignee = function() { - return util.filterByRegexp(this.constantData.defaultAssignee, - this.getComponent()).toLowerCase(); -}; - -/** - * Set default assignee - * - * @return none - * sets this.defaultAssignee property according to defaultAssignee list - */ -RHBugzillaPage.prototype.setDefaultAssignee = function() { - this.defaultAssignee = this.getDefaultAssignee(); - var defAss = this.defaultAssignee; - - // Add setting default assignee - if ((defAss.length > 0) && (defAss !== this.getOwner())) { - this.constantData.defaultAssigneeTrigger = true; - this.createNewButton("bz_assignee_edit_container",true,"rh-common","setDefaultAssignee"); - } -}; - -/** - * Auxiliary function to compute more complicated resolution - */ -RHBugzillaPage.prototype.closeSomeRelease = function() { - // for RAWHIDE close as RAWHIDE, - // if active selection -> CURRENTRELEASE - // and put the release version to - // "Fixed in Version" textbox - // otherwise -> NEXTRELEASE - this.selectOption("bug_status", "CLOSED"); - var text = ""; - var resolution = ""; - - if (selection.text) { - text = selection.text.trim(); - } - if (text.length > 0) { - resolution = "CURRENTRELEASE"; - this.doc.getElementById("cf_fixed_in").value = text; - } else if (this.doc.getElementById("version").value === "rawhide") { - resolution = "RAWHIDE"; - } else { - resolution = "NEXTRELEASE"; - } - this.centralCommandDispatch("resolution", resolution); -}; - -/** - * Additional commands specific for this subclass, overriding superclass one. - */ -RHBugzillaPage.prototype.centralCommandDispatch = function(cmdLabel, cmdParams) { - console.log("cmdLabel = " + cmdLabel + ", cmdParams = " + cmdParams); - switch (cmdLabel) { - // Set up our own commands - case "closeUpstream": - this.addClosingUpstream(); - break; - case "computeResolution": - this.closeSomeRelease(); - break; - case "queryStringUpstreamBugzilla": - this.queryUpstream(); - break; - case "sendBugUpstream": - this.sendBugUpstream(); - break; - case "markTriaged": - this.markBugTriaged(); - break; - case "chipMagic": - var splitArr = cmdParams.split("\t"); - this.fillInWhiteBoard(splitArr[0], splitArr[1]); - break; - // If we don't have it here, call superclass method - default: - BZPage.prototype.centralCommandDispatch.call(this, cmdLabel, cmdParams); - break; - } -}; - -/** - * - * This has to stay in RHBugzillaPage because upstream doesn't have addAttachment - * XML-RPC call yet. - */ -RHBugzillaPage.prototype.addAttachment = function addAttachment(data, callback, param) { - var msg = new xrpc.XMLRPCMessage("bugzilla.addAttachment"); - var that = this; - - msg.addParameter(this.bugNo); - msg.addParameter({ - description: titleParsedAttachment, - filename: "parsed-backtrace.txt", - contenttype: "text/plain", - data: this.win.btoa(data), - nomail: true - }); - msg.addParameter(this.login); - msg.addParameter(this.password); - - Request({ - url: this.constantData.XMLRPCData[this.hostname].url, - onComplete: function(response) { - if (response.status == 200) { - var resp = util.parseXMLfromString(response.text); - var newAttachID = parseInt(resp.params.param.value.array.data.value.int, 10); - console.log("attachID = " + newAttachID); - callback.call(that, param, newAttachID, data.length); - } - }, - content: msg.xml(), - contentType: "text/xml" - }).post(); - this.reqCounter++; -}; - -/* === Bugzilla functions === */ -/** - * - */ -RHBugzillaPage.prototype.pasteBacktraceInComments = function() { - var that = this; - - /* - Let's comment it out, and we'll see if anything breaks. - TODO This paragraph looks suspicous ... what is it? - Does it belong to this function? - var notedLabel = this.doc.querySelector("label[for='newcc']"); - while (notedLabel.firstChild) { - var node = notedLabel.removeChild(notedLabel.firstChild); - notedLabel.parentNode.insertBefore(node, notedLabel); - } - notedLabel.parentNode.removeChild(notedLabel); - */ - - var abrtQueryURL = "https://bugzilla.redhat.com/buglist.cgi?" + - "cmdtype=dorem&remaction=run&namedcmd=all%20NEW%20abrt%20crashes&"+ - "sharer_id=74116"; - - var mainTitle = this.doc - .getElementsByClassName("bz_alias_short_desc_container")[0]; - - var abrtButton = this.doc.createElement("a"); - abrtButton.setAttribute("accesskey", "a"); - abrtButton.setAttribute("href", abrtQueryURL); - abrtButton.textContent = "Abrt bugs"; - mainTitle.appendChild(abrtButton); - - if (this.idContainsWord("cf_devel_whiteboard", 'btparsed')) { - this.addStuffToTextBox('status_whiteboard', 'btparsed'); - } - - if (!(this.isTriaged() || this.idContainsWord("status_whiteboard", - 'btparsed') || (this.parsedAttachments.length > 0))) { - var btAttachments = this.attachments - .filter(function(att, idx, arr) { - return (/File: backtrace/.test(att[0])); - }); - // TODO we need to go through all backtrace attachments, but - // just the first one will do for now, we would need to do async - // parsing - btAttachments.forEach(function(x) { - var attURL = "https://bugzilla.redhat.com/attachment.cgi?id=" - + x[1]; - if ((!this.btSnippet) && - (!this.idContainsWord("status_whiteboard", 'btparsed'))) { - var that = this; - Request({ - url: attURL, - onComplete: function(response) { - if (response.status == 200) { - that.btSnippet = that.parseBacktrace(response.text); - if (that.btSnippet) { - that.addCheckShowLink.call(that,x,that.btSnippet); - } - } - } - }).get(); - } - }, this); - } - // Add "show BT" links - if (this.parsedAttachments.length > 0) { - this.parsedAttachments.forEach(function (att) { - that.addShowParsedBTLink(att); - }, that); - } -}; - -/** - * Open new window with the content of the attachment. - * - * @param id Number of the attachment id - * @return none - */ -RHBugzillaPage.prototype.showAttachment = function showAttachment(id) { - var that = this; - Request({ - url: "https://" + that.hostname + "/attachment.cgi?id=" + id, - onComplete: function (response) { - if (response.status == 200) { - var infoWin = that.win.open("", "Check att. " + id, - "width=640,height=640,status=no,location=no,"+ - "titlebar=no,scrollbars=yes,resizable=yes"+ - "alwaysRaised=yes"); - var doc = infoWin.document; - doc.body.innerHTML = "<pre id='textPre'>"+ - response.text + "</pre>"; - } - } - }).get(); -}; - -/** - * add a link opening a window with the parsed backtrace - * - * @param att Attachment object - */ -RHBugzillaPage.prototype.addShowParsedBTLink = function addShowParsedBTLink(att) { - var elem = att[4].querySelector("td:last-of-type"); - this.createDeadLink("showParsedBacktraceWindow-" + att[1], "showBT", - elem, this.showAttachment, att[1], true); -}; - -/** - * Unfinished ... see above - */ -RHBugzillaPage.prototype.addNewAttachmentRow = function addNewAttachmentRow(origAtt, - newAttId, newAttSize) { - var that = this; - var oldAddBTLink = this.doc.getElementById("attachBacktraceActivator"); - oldAddBTLink.parentNode.removeChild(oldAddBTLink); - var newTRElem = origAtt[4].cloneNode(true); - - // fix number of the attachment - Array.forEach(newTRElem.getElementsByTagName("a"), function (aEl) { - aEl.setAttribute("href", - aEl.getAttribute("href").replace(origAtt[1], newAttId)); - }); - - var aElements = newTRElem.getElementsByTagName("a"); - aElements[0].setAttribute("name","parsed-backtrace.txt"); - aElements[0].getElementsByTagName("b")[0].textContent = titleParsedAttachment; - - var sizeSpan = newTRElem.getElementsByClassName("bz_attach_extra_info")[0]; - sizeSpan.textContent = "(" + (newAttSize / 1024).toFixed(2) + " KB, text/plain)"; - - // aElements[1].textContent = new Date().toString(); TODO we should add eventually, but not pressing - - var vcardSpan = newTRElem.getElementsByClassName("vcard")[0]; - if (vcardSpan !== undefined) { - var vcardSpanClassList = vcardSpan.classList; - if (/@redhat\.com/.test(this.login) && !vcardSpanClassList.contains("redhat_user")) { - vcardSpanClassList.add("redhat_user"); - } - var vcardAElem = vcardSpan.getElementsByTagName("a")[0]; - vcardAElem.setAttribute("title", this.login); - vcardAElem.setAttribute("href", "mailto:" + this.login); - vcardAElem.className = "email"; - vcardAElem.innerHTML="<span class='fn'>" + this.login + "</span>"; - } - - var elem = newTRElem.querySelector("td:last-of-type"); - this.createDeadLink("showBacktrace", "show BT", elem, - this.showAttachment, newAttId, false); - - origAtt[4].parentNode.insertBefore(newTRElem, origAtt[4].nextSibling); -}; - -/** - * Add a link to create a new attachment with a parsed backtrace - * - * @param oldAtt Object with an attachment row - * @param snippet String with parsed backtrace - * @return none - */ -RHBugzillaPage.prototype.addCheckShowLink = function addCheckShowLink(oldAtt, snippet) { - var that = this; - var elem = oldAtt[4].querySelector("td:last-of-type"); - this.createDeadLink("attachBacktraceActivator", "add parsed BT", elem, function(x) { - // pass function and parameters as two separate parameters, the function to be called from - // addAttachment - that.addAttachment.call(that, snippet, this.addNewAttachmentRow, oldAtt); - }, [], true); -}; - -/** - * Make it sailent that the some attachments with bad MIME type are present - * - * @param atts Array of attachments subarrays - * @return none - */ -RHBugzillaPage.prototype.markBadAttachments = function markBadAttachments(atts) { - var that = this; - var badMIMEArray = [ "application/octet-stream", "text/x-log", "undefined" ]; - if (!this.password) { - return ; // User didn't provide password, so whole MIME fixing business - // should be switched off. - } - - var badAttachments = atts.filter(function(att, idx, arr) { - return (util.isInList(att[2], badMIMEArray)); - }); - - if (badAttachments.length > 0) { - var titleElement = this.doc - .getElementsByClassName("bz_alias_short_desc_container")[0]; - titleElement.style.backgroundColor = "olive"; - - this.createDeadLink("fixAllButton", "Fix all", titleElement, function() { - Array.forEach(badAttachments, function(x) { - this.fixAttachById(x[1]); - }, that); - }, [], false, null, "f"); - badAttachments.forEach(function(x, i, a) { - this.addTextLink(x); - }, this); - } -}; - -/** - * Is this bug a RHEL bug? - * - * @return Boolean true if it is a RHEL bug - */ -RHBugzillaPage.prototype.isEnterprise = function() { - var prod = this.product; - var result = this.constantData.ProfessionalProducts.some(function(elem,idx,arr) { - return new RegExp(elem).test(prod); - }); - return result; -}; - -/** - * Find out whether the bug is needed an attention of bugZappers - * - * @return Boolean whether the bug has been triaged or not - */ -RHBugzillaPage.prototype.isTriaged = function() { - return this.hasKeyword("Triaged"); -}; - -/** - * Set branding colours to easily distinguish between Fedora and RHEL bugs - * - * @param brand String with product of the current bug - * @param version String with the version of the bug - * @param its String with the IsueTracker numbers - * @return none - */ -RHBugzillaPage.prototype.setBranding = function() { - var brandColor = {}; - var TriagedColor = {}; - - if (this.isEnterprise()) { - if (this.its && (this.its.length > 0)) { - brandColor = this.RHITColor; - } else { - brandColor = this.RHColor; - } - } else if (new RegExp("Fedora").test(this.product)) { - if (this.doc.getElementById("version").value === "rawhide") { - brandColor = this.RawhideColor; - } else { - brandColor = this.FedoraColor; - } - } - - // Comment each of the following lines to get only partial branding - this.doc.getElementsByTagName("body")[0].style.background = brandColor - .toString() - + " none"; - this.doc.getElementById("titles").style.background = brandColor.toString() - + " none"; - - // Remove "Bug" from the title of the bug page, so we have more space with - // plenty of tabs - var titleElem = this.doc.getElementsByTagName("title")[0]; - - titleElem.textContent = titleElem.textContent.slice(4); - var bodyTitleParent = this.doc.getElementById("summary_alias_container").parentNode; - var bodyTitleElem = bodyTitleParent.getElementsByTagName("b")[0]; - bodyTitleElem.textContent = bodyTitleElem.textContent.slice(4); - - // Make background-color of the body of bug salmon pink - // for security bugs. - if (this.hasKeyword("Security")) { - this.doc.getElementById("bugzilla-body").style.background = this.SalmonPink - .toString() + ' none'; - } - - // Make it visible whether the bug has been triaged - if (this.isTriaged()) { - this.doc.getElementById("bz_field_status").style.background = brandColor - .lightColor().toString() - + " none"; - } - - // we should make visible whether maintCCAddr is in CCList - if (util.isInList(this.maintCCAddr, this.CCList)) { - var ccEditBoxElem = this.doc.getElementById("cc_edit_area_showhide"); - ccEditBoxElem.style.color = "navy"; - ccEditBoxElem.style.fontWeight = "bolder"; - ccEditBoxElem.style.textDecoration = "underline"; - } - - // mark suspicious components - var compElems; - if (this.suspiciousComponents - && util.isInList(this.getComponent(), this.suspiciousComponents) - && (compElems = this.doc - .getElementById("bz_component_edit_container"))) { - compElems.style.background = "red none"; - } -}; - -/** - * Search simple query in the upstream bugzilla appropriate for the component - * - * @return none - */ -RHBugzillaPage.prototype.queryUpstream = function() { - var text = this.getSelectionOrClipboard(); - if (text) { - var queryUpstreamBugsURLArray = this.constantData.queryUpstreamBug; - var searchData = util.filterByRegexp(queryUpstreamBugsURLArray, this.getComponent()); - var urlBase = searchData.url; - text = searchData.searchBy+":"+searchData.fillIn+" "+text.trim(); - if (searchData.fillIn == "$$$") { - text = text.replace("$$$", this.getComponent()); - } - text = encodeURIComponent(text).replace("%20","+"); - tabs.open({ - url: urlBase + text, - inBackground: true, - onOpen: function (tab) { - tabs.activeTab = tab; - } - }); - } -}; - -/** - * Open a tab in the upstream bugzilla to create a new bug - * - * @return none - */ -RHBugzillaPage.prototype.sendBugUpstream = function() { - var that = this; - var urlStr = util.filterByRegexp(JSON.parse(self.data.load("newUpstreamBug.json")), this - .getComponent()); - - tabs.open({ - url: urlStr, - inBackground: true, - onOpen: function (tab) { - var otherDoc = tab.contentDocument; - var otherElems = otherDoc.forms.namedItem("Create").elements; - otherElems.namedItem("short_desc").value = that.doc - .getElementById("short_desc_nonedit_display").textContent - .trim(); - otherElems.namedItem("comment").value = that.collectComments(); - tabs.activeTab = tab; - } - }); -}; - -/** - * Add a link opening selected lines of Xorg.0.log - * - * @return none - */ -RHBugzillaPage.prototype.addCheckXorgLogLink = function addCheckXorgLogLink() { - var that = this; - if (this.xorglogAnalysis) { - this.XorgLogAttList.forEach(function (row) { - var elemS = row[4].getElementsByTagName("td"); - var elem = elemS[elemS.length - 1]; - that.createDeadLink("xorgLogAnalyzeLink", "check", elem, - that.analyzeXorgLog, row[1], "br"); - }); - } -}; - -/** - * Given line to be parsed, find out which chipset it is and fill in the - * whiteboard - * - * @param iLine String with the whole unparsed "interesting line" - * @param driverStr String with the driver name - * @return None - */ -RHBugzillaPage.prototype.fillInWhiteBoard = function(iLine, driverStr) { - var that = this; - - function groupIDs(manStr, cardStrID) { - var outStr = util.filterByRegexp(that.constantData.chipIDsGroupings, - manStr + "," + cardStrID); - if (outStr.length === 0) { - outStr = "UNGROUPED_" + manStr + "/" + cardStrID; - } - return outStr; - } - - /** - * Given PCI IDs for manufacturer and card ID return chipset string - * - * @param manufacturerNo String with manufacturer PCI ID - * @param cardNo String with card PCI ID - * @return Array with chip string and optinoal variants - */ - function checkChipStringFromID(manufacturerNo, cardNo) { - var soughtID = (manufacturerNo + "," + cardNo).toUpperCase(); - var outList = that.constantData.PCI_ID_Array[soughtID]; - if (outList) { - return outList; - } else { - return ""; - } - } - - var outStr = ""; - var cardIDStr = ""; - var cardIDArr = []; - - chipSwitchboard: if (driverStr === "RADEON") { - var cardID = iLine.replace(this.RE.ATIgetID, "$1"); - cardIDArr = checkChipStringFromID("1002", cardID); - if (cardIDArr.length > 0) { - cardIDStr = cardIDArr[0]; - if (cardIDArr[1]) { - optionStr = cardIDArr[1]; - outStr = groupIDs(driverStr, cardIDStr) + "/" + optionStr; - } else { - outStr = groupIDs(driverStr, cardIDStr); - optionStr = ""; - } - } else { - outStr = "**** FULLSTRING: " + iLine; - } - } else { - // Intel Corporation, NVIDIA - cardIDArr = this.manuChipStrs.filter(function(el, ind, arr) { - return new RegExp(el[0], "i").test(iLine); - }); - if (cardIDArr && (cardIDArr.length > 0)) { - cardIDArr = cardIDArr[0]; - } else { - outStr = iLine; - break chipSwitchboard; - } - // cardIDArr [0] = RE, [1] = ("RADEON","INTEL","NOUVEAU"), [2] = manu - // PCIID - iLine = iLine.replace(new RegExp(cardIDArr[0], "i")).trim(); - // nVidia developers opted-out from grouping - if (driverStr === "INTEL") { - outStr = groupIDs(cardIDArr[1], iLine); - } else { - outStr = iLine; - } - } - this.addStuffToTextBox("status_whiteboard", ("card_" + outStr).trim()); - this.doc.getElementById("chipMagic_btn").style.display = "none"; -}; - -/** - * Get attached Xorg.0.log, parse it and find the value of chip. Does not fill - * the whiteboard itself, just adds button to do so,paramList so that slow - * XMLHttpRequest is done in advance. - * - * @return None - */ -RHBugzillaPage.prototype.fillInChipMagic = function fillInChipMagic() { - var that = this; - var XorgLogURL = ""; - var XorgLogAttID = ""; - var XorgLogFound = false; - var attURL = "", interestingLine = ""; - var interestingArray = []; - - if (this.XorgLogAttList.length === 0) { - return; - } - - XorgLogAttID = this.XorgLogAttList[this.XorgLogAttListIndex][1]; - attURL = "https://bugzilla.redhat.com/attachment.cgi?id="+XorgLogAttID; - - // parse Xorg.0.log - Request({ - url: attURL, - onComplete: function (response) { - if (response.status == 200) { - var interestingLineArr = response.text.split("\n"). - filter(function (v,i,a) { - return that.RE.Chipset.test(v); - }); - if (interestingLineArr.length >0) { - // TODO we are parsing only the first found line; is it alright? - interestingArray = that.RE.Chipset.exec(interestingLineArr[0]); - interestingLine = interestingArray[2]. - replace(/[\s"]+/g," ").trim(); - // Persuade createNewButton to have mercy and to actually add - // non-default button - that.constantData.chipMagicTrigger = true; - that.packages["rh-xorg"].chipMagic.chipMagic = interestingLine+"\t"+interestingArray[1] - .toUpperCase(); - that.createNewButton("status_whiteboard", true, "rh-xorg", "chipMagic"); - } - } - } - }).get(); - this.XorgLogAttListIndex++; -}; - -RHBugzillaPage.prototype.analyzeXorgLog = function analyzeXorgLog(attachID) { - var infoWin = this.win.open("", "Check att. " + attachID, - "width=640,height=640,status=no,location=no"); - var doc = infoWin.document; - doc.body.innerHTML = "<pre id='textPre'></pre>"; - // TODO var oldCursor = doc.body.style.cursor; - // doc.body.style.cursor = "wait"; - var preElem = doc.getElementById("textPre"); - - var attURL = "https://bugzilla.redhat.com/attachment.cgi?id=" + attachID; - var that = this; - Request({ - url: attURL, - onComplete: function(response) { - if (response.status == 200) { - var results = response.text.split("\n"). - filter(function(line) { - return (that.RE.soughtLines.test(line)); - }); - results.sort(); - results = util.removeDuplicates(results); - // Remove headers - if (results.length >= 1) { - results.splice(0, 1); - } - if (results.length > 0) { - results.forEach(function(l) { - preElem.innerHTML += l + "\n"; - }); - // Add a summary - preElem.innerHTML += "----------\n" + - results.length + " interesting lines found."; - } else { - preElem.innerHTML += "No matching lines found!"; - } - } - // doc.body.style.cursor = oldCursor; - } - }).get(); -}; - -/** - * Return string with the ID for the external_id SELECT for external bugzilla - * - * @param URLhostname String hostname of the external bugzilla - * @return String with the string for the external_id SELECT - */ -RHBugzillaPage.prototype.getBugzillaName = function getBugzillaName(URLhostname) { - var bugzillaID = ""; - var bzLabelNames = JSON.parse(self.data.load("bugzillalabelNames.json")); - if (bzLabelNames[URLhostname]) { - bugzillaID = bzLabelNames[URLhostname]; - } else { - bugzillaID = ""; - } - return bugzillaID; -}; - -/** - * Callback function for the XMLRPC request - * - * @param ret Object with xmlhttprequest response with attributes: - * + status -- int return code - * + statusText - * + responseHeaders - * + responseText - */ -RHBugzillaPage.prototype.XMLRPCcallback = function XMLRPCcallback() { - var that = this; - this.reqCounter--; - if (this.reqCounter <= 0) { - timer.setTimeout(function () { - that.win.location.reload(true); - }, 1000); - } -}; - -/** - * The worker function -- call XMLRPC to fix MIME type of the particular - * attachment - * - * @param id Integer with the attachment id to be fixed - * @param type String with the new MIME type, optional defaults to "text/plain" - * @param email Boolean whether email should be sent to appropriate person; - * option, defaults to false - * - * updateAttachMimeType($data_ref, $username, $password) - * - * Update the attachment mime type of an attachment. The first argument is a - * data hash containing information on the new MIME type and the attachment id - * that you want to act on. - * - * $data_ref = { "attach_id" => "<Attachment ID>", # Attachment ID to perform - * MIME type change on. "mime_type" => "<New MIME Type Value>", # Legal MIME - * type value that you want to change the attachment to. "nomail" => 0, # - * OPTIONAL Flag that is either 1 or 0 if you want email to be sent or not for - * this change }; - * - */ -RHBugzillaPage.prototype.fixAttachById = function fixAttachById(id, type, email) { - if (type === undefined) { - type = "text/plain"; - } - if (email === undefined) { - email = false; - } - - var that = this; - var msg = new xrpc.XMLRPCMessage("bugzilla.updateAttachMimeType"); - msg.addParameter( { - 'attach_id' : id, - 'mime_type' : type, - 'nomail' : !email - }); - msg.addParameter(this.login); - msg.addParameter(this.password); - - // https://bugzilla.redhat.com/\ - // docs/en/html/api/extensions/compat_xmlrpc/code/webservice.html - // test on https://bugzilla.redhat.com/show_bug.cgi?id=485145 - Request({ - url: this.constantData.XMLRPCData[this.hostname].url, - onComplete: function(response) { - if (response.status == 200) { - that.XMLRPCcallback.call(that); - } - }, - content: msg.xml(), - contentType: "text/xml" - }).post(); - this.reqCounter++; -}; - -/** - * Add a link to the bad attachment for fixing it. - * - * @param - * <TR> DOM jQuery element with a bad attachment - * @return none - */ -RHBugzillaPage.prototype.addTextLink = function addTextLink(row) { - var elemS = row[4].getElementsByTagName("td"); - var elem = elemS[elemS.length - 1]; - this.createDeadLink("addFix2TextLink", "text", elem, - this.fixAttachById, row[1], "br"); -}; - -/** - * Add information about the upstream bug upstream, and closing it. - * - * @param evt Event which called this handler - * @return none - */ -RHBugzillaPage.prototype.addClosingUpstream = function() { - var refs = this.doc.getElementById("external_bugs_table") - .getElementsByTagName("tr"); - - // that's a bad id, if there is a one. :) - var inputBox = this.doc.getElementById("inputbox"); - var externalBugID = 0; - var wholeURL = ""; - - // Fix missing ID on the external_id SELECT - this.doc.getElementsByName("external_id")[0].setAttribute("id", - "external_id"); - - if (inputBox.value.match(/^http.*/)) { - wholeURL= new url.URL(inputBox.value); - externalBugID = util.getBugNo(wholeURL); - if (externalBugID) { - inputBox.value = externalBugID; - } - // get bugzillaName and set the label - var bugzillaName = this.getBugzillaName(wholeURL.host); - this.selectOptionByLabel("external_id", bugzillaName); - } else if (!isNaN(inputBox.value)) { - externalBugID = parseInt(inputBox.value, 10); - var bugzillaHostname = this.doc.getElementById("external_id").value; - wholeURL = bugzillaHostname+"show_bug.cgi?id="+externalBugID; - } else { - // no inputBox.value -- maybe there is an external bug from - // the previous commit? - } - - // It is not good to close bug as UPSTREAM, if there is no reference - // to the upstream bug. - if ((externalBugID > 0) || (refs.length > 2)) { - var msgStr = this.commentStrings.sentUpstreamString; - msgStr = msgStr.replace("§§§", wholeURL); - this.centralCommandDispatch("comment",msgStr); - this.centralCommandDispatch("status", "CLOSED"); - this.centralCommandDispatch("resolution", "UPSTREAM"); - } else { - console.log("No external bug specified among the External References!"); - } -}; - -RHBugzillaPage.prototype.markBugTriaged = function() { - // Now we lie completely, we just set keyword Triaged, - // this is not just plain ASSIGNED, but - // modified according to - // https://fedoraproject.org/wiki/BugZappers/Meetings/Minutes-2009-Oct-27 - // and - // http://meetbot.fedoraproject.org/fedora-meeting/2009-11-24\ - // /fedora-meeting.2009-11-24-15.11.log.html - // and - // http://meetbot.fedoraproject.org/fedora-meeting/2009-11-24\ - // /fedora-meeting.2009-11-24-15.11.log.html - // for F13 and later, ASSIGNED is "add Triaged keyword" (as well) - // for <F13 it is "add both" (ASSIGNED status and Triaged keyword) - var ver = this.doc.getElementById("version").value; - if ((!this.isEnterprise()) && (ver <= 12)) { - this.selectOption("bug_status", "ASSIGNED"); - } - this.addStuffToTextBox("keywords","Triaged"); -}; - -/** - * - */ -RHBugzillaPage.prototype.parseBacktrace = function(ret) { - var splitArray = ret.split("\n"); - var i = 0, ii = splitArray.length; - var outStr = "", curLine = "", numStr = ""; - var lineCounter = 0, endLineNo = 0; - - while (i < ii) { - if (this.RE.signalHandler.test(splitArray[i])) { - break; - } - i++; - } - - if (i < ii) { - lineCounter = parseInt(this.RE.frameNo.exec(splitArray[i])[1], 10); - endLineNo = lineCounter + NumberOfFrames; - curLine = splitArray[i]; - while ((lineCounter < endLineNo) && (curLine.trim().length > 0) - && (i < ii)) { - outStr += curLine + '\n'; - numStr = this.RE.frameNo.exec(curLine); - if (numStr) { - lineCounter = parseInt(numStr[1], 10); - } - i++; - curLine = splitArray[i]; - } - return outStr; - } - return ""; -}; - -// exports.RHBugzillaPage = apiUtils.publicConstructor(RHBugzillaPage); -exports.RHBugzillaPage = RHBugzillaPage; |