diff options
author | Matěj Cepl <mcepl@redhat.com> | 2010-06-11 21:03:36 +0200 |
---|---|---|
committer | Matěj Cepl <mcepl@redhat.com> | 2010-06-11 21:03:36 +0200 |
commit | 60961904968ee23a474b85653f9e397d63fc6b7f (patch) | |
tree | 59f443589fb024fc3661f9d6aaa43a5308218fd4 /lib | |
parent | 707982c8d28f29f6e5a16c3044874dc29ddb2738 (diff) | |
download | bugzilla-triage-60961904968ee23a474b85653f9e397d63fc6b7f.tar.gz |
Trying to make the simplest possible inherited objects.
Diffstat (limited to 'lib')
-rw-r--r-- | lib/bzpage.js | 706 | ||||
-rw-r--r-- | lib/puvodni/bzpage.js | 729 | ||||
-rw-r--r-- | lib/puvodni/mozillabzpage.js | 14 | ||||
-rw-r--r-- | lib/puvodni/rhbzpage.js | 941 | ||||
-rw-r--r-- | lib/rhbzpage.js | 921 |
5 files changed, 1697 insertions, 1614 deletions
diff --git a/lib/bzpage.js b/lib/bzpage.js index d155ea5..d150031 100644 --- a/lib/bzpage.js +++ b/lib/bzpage.js @@ -16,7 +16,7 @@ var bugURL = "https://bugzilla.redhat.com/show_bug.cgi?id="; // BZPage's methods var BZPage = exports.BZPage = function BZPage(doc, config) { - console.log("doc = " + doc); + console.log("doc = " + doc.title); console.log("config = " + config); // constants this.SalmonPink = new Color(255, 224, 176); // RGB 255, 224, 176; HSL 36, 2, @@ -25,705 +25,9 @@ var BZPage = exports.BZPage = function BZPage(doc, config) { // 83 // initialize dynamic properties this.doc = doc; - console.log("this.doc = " + this.doc); - - this.submitHandlerInstalled = false; - this.bugNo = util.getBugNo(this.doc.location.toString()); - - var keys = ""; - for (var key in this) { - keys += key + ", "; - } - console.log("keys = " + keys); - - this.reporter = this.getReporter(); - this.product = this.getOptionValue("product"); - this.component = this.getOptionValue("component"); - this.version = this.getVersion(); - this.title = this.doc.getElementById("short_desc_nonedit_display").textContent; - this.CCList = this.getCCList(); - - this.packages = this.getInstalledPackages(); - - if ("commentStrings" in config.gJSONData) { - this.commentStrings = config.gJSONData.commentStrings; - } - - if ("constantData" in config.gJSONData) { - // this is wrong, I shouldn't bother anybody with my Xorg data, and - // I should load it from URL - // var stuff = JSON.parse(self.data.load("chiIDsGroupings.json")); - this.constantData = config.gJSONData.constantData; - } - - if ("CCmaintainer" in config.gJSONData.constantData) { - this.defBugzillaMaintainerArr = config.gJSONData.constantData.CCmaintainer; - } - - if ("submitsLogging" in config.gJSONData.configData && - config.gJSONData.configData.submitsLogging) { - this.log = config.logger; - this.setUpLogging(); - } - - this.generateButtons(); -}; - -/** - * - */ -BZPage.prototype.getInstalledPackages = function getInstalledPackages() { - var installedPackages = {}; - if (config.gJSONData && ("commentPackages" in config.gJSONData)) { - var enabledPackages = jetpack.storage.settings.enabledPacks.split(/[, ]/); - enabledPackages.forEach(function (pkg, idx, arr) { - if (pkg in config.gJSONData.commentPackages) { - installedPackages[pkg] = config.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; - // 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. - */ -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]); - } -}; - -/** - * Add XGL to the CC list - * - * @param evt Event which made this function active - * @return none - */ -BZPage.prototype.changeAssignee = function changeAssignee (newAssignee) { - var defAssigneeButton = null; - this.addToCCList(this.owner); - 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 () { - var value = ""; - var valueElement = that.doc.getElementById("comment_action"); - if (valueElement) { - value = valueElement.getAttribute("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); -}; - -/** - * 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.error("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); - - 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); - } -}; - -/** - * - */ -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; - } - } - } -}; - -/** - * Get the current email of the reporter of the bug. - * - * @return string - */ -BZPage.prototype.getReporter = function getReporter () { - return this.doc - .querySelector("#bz_show_bug_column_2 > table .vcard:first-of-type > a").textContent; -}; - -/** - * Get the current version of the Fedora release ... even if changed meanwhile - * by bug triager. - * - * @return string (integer for released Fedora, float for RHEL, rawhide) - */ -BZPage.prototype.getVersion = function getVersion () { - var verStr = this.getOptionValue("version").toLowerCase(); - var verNo = 0; - if (/rawhide/.test(verStr)) { - verNo = 999; - } else { - verNo = Number(verStr); - } - return verNo; -}; - -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; - this.commentsWalker(function(x) { - var email = x.getElementsByClassName("vcard")[0] - .getElementsByTagName("a")[0].textContent; - if (new RegExp(that.reporter).test(email)) { - x.style.backgroundColor = that.ReporterColor.toString(); - } - }); + console.log("Now we are inside!"); }; -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 label on the <SELECT> element with given id. - * - * Also execute change HTMLEvent, so that the form behaves accordingly. - * - * @param id - * @param label - * @return none - * - * FIXME bugzilla-comments version has this signature: - * selectOption = function selectOption(select, value) { - var doc = select[0].ownerDocument; - select.val(value); - */ -BZPage.prototype.selectOption = function selectOption (id, label) { - var sel = this.doc.getElementById(id); - sel.value = label; - 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 (kwd.trim().indexOf(str) !== -1); -}; - -/** - * 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)); -}; - -/** - * - */ -BZPage.prototype.getOptionValue = function getOptionValue (id) { - // Some special bugs don't have version for example - var element = this.doc.getElementById(id); - if (element) { - return element.value; - } else { - console.log("Failed to find element with id = " + id); - return "#NA"; - } -}; - -/** - * 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 () { - var priorityParent = this.doc.querySelector("label[for~='target_milestone']") - .parentNode.parentNode.parentNode; - var assigneeAElement = priorityParent.querySelector("tr:nth-of-type(1) a.email"); - var assgineeHref = decodeURI(assigneeAElement.getAttribute("href")); - var email = assgineeHref.split(":")[1]; - return email; -}; - -/** - * 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; -}; - -/** - * 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; -}; - -/** - * 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; -}; - -/** - * 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 () { - if (jetpack.storage.settings.BZpassword) { - return jetpack.storage.settings.BZpassword; - } else { - var prompts = Components.classes["@mozilla.org/embedcomp/prompt-service;1"] - .getService(Components.interfaces.nsIPromptService); - var password = { - value : "" - }; // default the password to pass - var check = { - value : true - }; // default the checkbox to true - var result = prompts.promptPassword(null, "Title", "Enter password:", - password, null, check); - // result is true if OK was pressed, false if cancel was pressed. - // password.value is - // set if OK was pressed. The checkbox is not displayed. - if (result) { - var passwordText = password.value; - jetpack.storage.settings.BZpassword = passwordText; - jetpack.storage.simple.sync(); - return passwordText; - } - } - return null; -}; - -/** - * - */ -BZPage.prototype.setUpLogging = function setUpLogging () { - // 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 - // FIXME we should merge in functionality of RHBugzillaPage.submitCallback - // and actually make it working - // Maybe rewriting whole offline capability into a separate object? - if (!this.submitHandlerInstalled) { - console.log("Installing submit callback!"); - this.doc.forms.namedItem("changeform").addEventListener("submit",function (evt) { - console.log("Submit callback!"); - var resp = that.log.addLogRecord(that); - console.log("resp = " + resp); - if (resp === null) { - console.log("Avoiding submitting!"); - // FIXME doesn't work ... still submitting' - evt.stopPropagation(); - evt.preventDefault(); - } - }, false); - this.submitHandlerInstalled = true; - } - - var generateTimeSheetUI = this.doc.createElement("li"); - generateTimeSheetUI.innerHTML = "\u00A0-\u00A0<a href='#' id='generateTSButton'>" - + "Generate timesheet</a>"; - additionalButtons.appendChild(generateTimeSheetUI); - this.doc.getElementById("generateTSButton").addEventListener( - "click", - function(evt) { - that.log.createBlankPage.call(that.log, "TimeSheet", - that.log.generateTimeSheet); - evt.stopPropagation(); - evt.preventDefault(); - }, false); - - var clearLogsUI = this.doc.createElement("li"); - clearLogsUI.innerHTML = "\u00A0-\u00A0<a href='#' id='clearLogs'>" - + "Clear logs</a>"; - additionalButtons.appendChild(clearLogsUI); - var clearLogAElem = this.doc.getElementById("clearLogs"); - clearLogAElem.addEventListener("click", function() { - that.log.store = {}; - jetpack.storage.simple.sync(); - this.style.color = that.log.EmptyLogsColor; - this.style.fontWeight = "normal"; - console.log("this.store wiped out!"); - }, false); - - if (!this.log.store) { - console.log("No this.store defined!"); - this.log.store = {}; - } - - if (this.log.store.length > 0) { - clearLogAElem.style.color = this.log.FullLogsColor; - clearLogAElem.style.fontWeight = "bolder"; - } else { - clearLogAElem.style.color = this.log.EmptyLogsColor; - clearLogAElem.style.fontWeight = "normal"; - } -}; - -/** - * 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"); - outCCList = []; - if (CCListSelect) { - outCCList = Array.map(CCListSelect.options, function(item) { - return item.value; - }); - } - return outCCList; -}; +BZPage.prototype.getBugId = function getBugId () { + return util.getBugNo(this.doc.location.href); +};
\ No newline at end of file diff --git a/lib/puvodni/bzpage.js b/lib/puvodni/bzpage.js new file mode 100644 index 0000000..12b2fb0 --- /dev/null +++ b/lib/puvodni/bzpage.js @@ -0,0 +1,729 @@ +/*jslint 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 */ +/*global jetpack */ +// Released under the MIT/X11 license +// http://www.opensource.org/licenses/mit-license.php +"use strict"; +var util = require("util"); +var simpleStorage = require("simple-storage"); +var Color = require("color").Color; + +var TriagedDistro = 13; +var NumberOfFrames = 7; +var XMLRPCurl = "https://bugzilla.redhat.com/xmlrpc.cgi"; +var bugURL = "https://bugzilla.redhat.com/show_bug.cgi?id="; + +// ==================================================================================== +// BZPage's methods + +var BZPage = exports.BZPage = function BZPage(doc, config) { + console.log("doc = " + doc); + console.log("config = " + 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 + this.doc = doc; + console.log("this.doc = " + this.doc); + + this.submitHandlerInstalled = false; + this.bugNo = util.getBugNo(this.doc.location.toString()); + + var keys = ""; + for (var key in this.prototype) { + keys += key + ", "; + } + console.log("keys = " + keys); + + this.reporter = this.getReporter(); + this.product = this.getOptionValue("product"); + this.component = this.getOptionValue("component"); + this.version = this.getVersion(); + this.title = this.doc.getElementById("short_desc_nonedit_display").textContent; + this.CCList = this.getCCList(); + + this.packages = this.getInstalledPackages(); + + if ("commentStrings" in config.gJSONData) { + this.commentStrings = config.gJSONData.commentStrings; + } + + if ("constantData" in config.gJSONData) { + // this is wrong, I shouldn't bother anybody with my Xorg data, and + // I should load it from URL + // var stuff = JSON.parse(self.data.load("chiIDsGroupings.json")); + this.constantData = config.gJSONData.constantData; + } + + if ("CCmaintainer" in config.gJSONData.constantData) { + this.defBugzillaMaintainerArr = config.gJSONData.constantData.CCmaintainer; + } + + if ("submitsLogging" in config.gJSONData.configData && + config.gJSONData.configData.submitsLogging) { + this.log = config.logger; + this.setUpLogging(); + } + + this.generateButtons(); +}; + +/** + * + */ +BZPage.prototype.getInstalledPackages = function getInstalledPackages() { + var installedPackages = {}; + if (config.gJSONData && ("commentPackages" in config.gJSONData)) { + var enabledPackages = jetpack.storage.settings.enabledPacks.split(/[, ]/); + enabledPackages.forEach(function (pkg, idx, arr) { + if (pkg in config.gJSONData.commentPackages) { + installedPackages[pkg] = config.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; + // 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. + */ +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]); + } +}; + +/** + * Add XGL to the CC list + * + * @param evt Event which made this function active + * @return none + */ +BZPage.prototype.changeAssignee = function changeAssignee (newAssignee) { + var defAssigneeButton = null; + this.addToCCList(this.owner); + 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 () { + var value = ""; + var valueElement = that.doc.getElementById("comment_action"); + if (valueElement) { + value = valueElement.getAttribute("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); +}; + +/** + * 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.error("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); + + 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); + } +}; + +/** + * + */ +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; + } + } + } +}; + +/** + * Get the current email of the reporter of the bug. + * + * @return string + */ +BZPage.prototype.getReporter = function getReporter () { + return this.doc + .querySelector("#bz_show_bug_column_2 > table .vcard:first-of-type > a").textContent; +}; + +/** + * Get the current version of the Fedora release ... even if changed meanwhile + * by bug triager. + * + * @return string (integer for released Fedora, float for RHEL, rawhide) + */ +BZPage.prototype.getVersion = function getVersion () { + var verStr = this.getOptionValue("version").toLowerCase(); + var verNo = 0; + if (/rawhide/.test(verStr)) { + verNo = 999; + } else { + verNo = Number(verStr); + } + return verNo; +}; + +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; + this.commentsWalker(function(x) { + var email = x.getElementsByClassName("vcard")[0] + .getElementsByTagName("a")[0].textContent; + if (new RegExp(that.reporter).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 label on the <SELECT> element with given id. + * + * Also execute change HTMLEvent, so that the form behaves accordingly. + * + * @param id + * @param label + * @return none + * + * FIXME bugzilla-comments version has this signature: + * selectOption = function selectOption(select, value) { + var doc = select[0].ownerDocument; + select.val(value); + */ +BZPage.prototype.selectOption = function selectOption (id, label) { + var sel = this.doc.getElementById(id); + sel.value = label; + 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 (kwd.trim().indexOf(str) !== -1); +}; + +/** + * 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)); +}; + +/** + * + */ +BZPage.prototype.getOptionValue = function getOptionValue (id) { + // Some special bugs don't have version for example + var element = this.doc.getElementById(id); + if (element) { + return element.value; + } else { + console.log("Failed to find element with id = " + id); + return "#NA"; + } +}; + +/** + * 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 () { + var priorityParent = this.doc.querySelector("label[for~='target_milestone']") + .parentNode.parentNode.parentNode; + var assigneeAElement = priorityParent.querySelector("tr:nth-of-type(1) a.email"); + var assgineeHref = decodeURI(assigneeAElement.getAttribute("href")); + var email = assgineeHref.split(":")[1]; + return email; +}; + +/** + * 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; +}; + +/** + * 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; +}; + +/** + * 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; +}; + +/** + * 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 () { + if (jetpack.storage.settings.BZpassword) { + return jetpack.storage.settings.BZpassword; + } else { + var prompts = Components.classes["@mozilla.org/embedcomp/prompt-service;1"] + .getService(Components.interfaces.nsIPromptService); + var password = { + value : "" + }; // default the password to pass + var check = { + value : true + }; // default the checkbox to true + var result = prompts.promptPassword(null, "Title", "Enter password:", + password, null, check); + // result is true if OK was pressed, false if cancel was pressed. + // password.value is + // set if OK was pressed. The checkbox is not displayed. + if (result) { + var passwordText = password.value; + jetpack.storage.settings.BZpassword = passwordText; + jetpack.storage.simple.sync(); + return passwordText; + } + } + return null; +}; + +/** + * + */ +BZPage.prototype.setUpLogging = function setUpLogging () { + // 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 + // FIXME we should merge in functionality of RHBugzillaPage.submitCallback + // and actually make it working + // Maybe rewriting whole offline capability into a separate object? + if (!this.submitHandlerInstalled) { + console.log("Installing submit callback!"); + this.doc.forms.namedItem("changeform").addEventListener("submit",function (evt) { + console.log("Submit callback!"); + var resp = that.log.addLogRecord(that); + console.log("resp = " + resp); + if (resp === null) { + console.log("Avoiding submitting!"); + // FIXME doesn't work ... still submitting' + evt.stopPropagation(); + evt.preventDefault(); + } + }, false); + this.submitHandlerInstalled = true; + } + + var generateTimeSheetUI = this.doc.createElement("li"); + generateTimeSheetUI.innerHTML = "\u00A0-\u00A0<a href='#' id='generateTSButton'>" + + "Generate timesheet</a>"; + additionalButtons.appendChild(generateTimeSheetUI); + this.doc.getElementById("generateTSButton").addEventListener( + "click", + function(evt) { + that.log.createBlankPage.call(that.log, "TimeSheet", + that.log.generateTimeSheet); + evt.stopPropagation(); + evt.preventDefault(); + }, false); + + var clearLogsUI = this.doc.createElement("li"); + clearLogsUI.innerHTML = "\u00A0-\u00A0<a href='#' id='clearLogs'>" + + "Clear logs</a>"; + additionalButtons.appendChild(clearLogsUI); + var clearLogAElem = this.doc.getElementById("clearLogs"); + clearLogAElem.addEventListener("click", function() { + that.log.store = {}; + jetpack.storage.simple.sync(); + this.style.color = that.log.EmptyLogsColor; + this.style.fontWeight = "normal"; + console.log("this.store wiped out!"); + }, false); + + if (!this.log.store) { + console.log("No this.store defined!"); + this.log.store = {}; + } + + if (this.log.store.length > 0) { + clearLogAElem.style.color = this.log.FullLogsColor; + clearLogAElem.style.fontWeight = "bolder"; + } else { + clearLogAElem.style.color = this.log.EmptyLogsColor; + clearLogAElem.style.fontWeight = "normal"; + } +}; + +/** + * 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"); + outCCList = []; + if (CCListSelect) { + outCCList = Array.map(CCListSelect.options, function(item) { + return item.value; + }); + } + return outCCList; +}; diff --git a/lib/puvodni/mozillabzpage.js b/lib/puvodni/mozillabzpage.js new file mode 100644 index 0000000..7efaf16 --- /dev/null +++ b/lib/puvodni/mozillabzpage.js @@ -0,0 +1,14 @@ +// Released under the MIT/X11 license +// http://www.opensource.org/licenses/mit-license.php +"use strict"; +var utilMod = require("util"); + +// ============================================================================ +// MozillaBugzilla object + +exports.MozillaBugzilla = function MozillaBugzilla (doc, config) { + BZPage.call(this, doc, config) +}; + +MozillaBugzilla.prototype = utilMod.heir(BZPage); +MozillaBugzilla.prototype.constructor = MozillaBugzilla; diff --git a/lib/puvodni/rhbzpage.js b/lib/puvodni/rhbzpage.js new file mode 100644 index 0000000..5acc1d3 --- /dev/null +++ b/lib/puvodni/rhbzpage.js @@ -0,0 +1,941 @@ +/*jslint 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 */ +/*global jetpack */ +// 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 xhr = require("xhr"); +var clip = require("clipboard"); +var Color = require("color").Color; +var BZPage = require("bzpage").BZPage; +// var TriagedDistro = 13; +// var NumberOfFrames = 7; +// var XMLRPCurl = "https://bugzilla.redhat.com/xmlrpc.cgi"; +// var bugURL = "https://bugzilla.redhat.com/show_bug.cgi?id="; + +// ==================================================================================== +// RHBugzillaPage object + +var RHBugzillaPage = exports.RHBugzillaPage = function RHBugzillaPage(doc, config) { + // inheritance ... call superobject's constructor + BZPage.call(this, doc, config); + + // For identification of graphics card + var 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") + }; + // END OF CONSTANTS + + var that = this; + this.reqCounter = 0; + this.signaturesCounter = 0; + this.chipMagicInterestingLine = ""; + + this.login = this.getLogin(); + this.password = this.getPassword(); + + var ITbutton = this.doc.getElementById("cf_issuetracker"); + this.its = ITbutton ? ITbutton.value.trim() : ""; + + // Prepare for query buttons + // FIXME getting null for commentArea sometimes + var commentArea = this.doc.getElementById("comment_status_commit"); + if (commentArea) { + var brElementPlacer = commentArea.getElementsByTagName("br"); + console.log("brElementPlacer.length = " + brElementPlacer.length); + brElementPlacer = brElementPlacer[0]; + if (brElementPlacer) { + brElementPlacer.setAttribute("id","brElementPlacer_location"); + brElementPlacer.parentNode.insertBefore(this.doc.createElement("br"), + brElementPlacer); + } + } + + // set default assignee on change of the component + this.doc.getElementById("component").addEventListener("change", + function() { + that.component = that.getOptionValue("component"); + that.changeAssignee("default"); + }, false); + + // getBadAttachments + this.XorgLogAttList = []; + this.XorgLogAttListIndex = 0; + this.attachments = this.getAttachments(); + this.markBadAttachments(); + this.setDefaultAssignee(); + + // Dig out backtrace + this.btSnippet = ""; + + var parseAbrtBacktraces = config.gJSONData.configData.parseAbrtBacktraces; + if (parseAbrtBacktraces && this.RE.Abrt.test(this.title)) { + this.pasteBacktraceInComments(); + } + + // 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() { + if (this.signaturesCounter < 1) { + that.addStuffToTextBox("comment", signatureFedoraString); + this.signaturesCounter += 1; + } + }, false); + } + + this.setBranding(); + this.checkComments(); + + // TODO Get compiz bugs as well + if ((config.gJSONData.configData.PCIIDsURL + && (config.PCI_ID_Array.length > 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(); + } + } +}; // END OF RHBugzillaPage CONSTRUCTOR + +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.component).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 computer 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 + var verNo = this.getVersion(); + this.selectOption("bug_status", "CLOSED"); + var text = ""; + var resolution = ""; + + if (jetpack.selection.text) { + text = jetpack.select.text.trim(); + } + if (text.length > 0) { + resolution = "CURRENTRELEASE"; + this.doc.getElementById("cf_fixed_in").value = text; + } else if (verNo === 999) { + 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 "queryStringOurBugzilla": + this.queryForSelection(); + break; + case "queryUpstreamBugzilla": + 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; + } +}; + + +/* Bugzilla functions. */ + +RHBugzillaPage.prototype.ProfessionalProducts = [ + "Red Hat Enterprise Linux", + "Red Hat Enterprise MRG" +]; + +/** + * + */ +RHBugzillaPage.prototype.pasteBacktraceInComments = function() { + // FIXME 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'))) { + var btAttachments = this.attachments + .filter(function(att, idx, arr) { + return (/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) { + attURL = "https://bugzilla.redhat.com/attachment.cgi?id=" + + x[1]; + if (!this.btSnippet) { + var btRaw = util.loadText(attURL, function(ret) { + this.btSnippet = this.parseBacktrace(ret); + if (this.btSnippet) { + this.addStuffToTextBox("comment", this.btSnippet); + this.addStuffToTextBox("status_whiteboard", + "btparsed"); + } + }, this); + } + }, this); + } +}; + +/** + * + */ +RHBugzillaPage.prototype.markBadAttachments = function() { + var badMIMEArray = [ "application/octet-stream", "text/x-log", "undefined" ]; + + var badAttachments = this.attachments.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"; + titleElement.appendChild(this.createFixAllButton(badAttachments)); + 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.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() { + // First excceptions + if (this.version > 7 && this.version < 12) { + return this.doc.getElementById("bug_status").value.toUpperCase() !== "NEW"; + } else { // and then the rule + 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()) { + console.log("This is an enterprise bug."); + if (this.its && (this.its.length > 0)) { + brandColor = this.RHITColor; + } else { + brandColor = this.RHColor; + } + } else if (new RegExp("Fedora").test(this.product)) { + console.log("This is NOT an enterprise bug."); + if (this.version === 999) { + 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.textContent = "*"+ccEditBoxElem.textContent; + ccEditBoxElem.style.color = "navy"; + ccEditBoxElem.style.fontWeight = "bolder"; + ccEditBoxElem.style.textDecoration = "underline"; + } + + // mark suspicious components + var compElems; + var suspiciousComponents = config.gJSONData.configData.suspiciousComponents; + if (suspiciousComponents + && util.isInList(this.component, suspiciousComponents) + && (compElems = this.doc + .getElementById("bz_component_edit_container"))) { + compElems.style.background = "red none"; + } +}; + +/** + * 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(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 = config.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 = 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").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 () { + var that = this; + var XorgLogURL = ""; + var XorgLogAttID = ""; + var XorgLogFound = false; + var attURL = "", interestingLine = ""; + var interestingArray = []; + + + // 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])); + }); + if (this.XorgLogAttList.length === 0) { + return; + } + + XorgLogAttID = this.XorgLogAttList[this.XorgLogAttListIndex][1]; + attURL = "https://bugzilla.redhat.com/attachment.cgi?id="+XorgLogAttID; + that = this; + + // parse Xorg.0.log + util.loadText(attURL, function(ret){ + var interestingLineArr = ret.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.chipMagicInterestingLine = interestingLine+"\t"+interestingArray[1] + .toUpperCase(); + that.createNewButton("status_whiteboard", true, "rh-xorg", "chipMagic"); + } + }); + this.XorgLogAttListIndex++; +}; + +/** + * 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 + * + */ +RHBugzillaPage.prototype.queryInNewTab = function(text, component, product) { + console.log("queryInNewTab / text = " + text); + console.log("queryInNewTab / component = " + component); + console.log("queryInNewTab / product = " + product); + var url = "https://bugzilla.redhat.com/buglist.cgi?query_format=advanced"; + if (product) { + url += "&product=" + product.trim(); + } + if (component) { + url += "&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; + url += searchText; + jetpack.tabs.open(url); + // Don't do it ... b.m.o is apparently not powerful enough to sustain + // the weight + // of the search + if (false) { + url = "https://bugzilla.mozilla.org/buglist.cgi?query_format=advanced" + + "field0-0-0=product;type0-0-0=regexp;" + + "value0-0-0=thunderbird|firefox|xulrunner" + + searchText.replace("&", ";"); + jetpack.tabs.open(url); + } + } +}; + +/** + * Get the text to search for and prepare other things for the real executive + * function this.queryInNewTab, and run it. + */ +RHBugzillaPage.prototype.queryForSelection = function() { + var text = jetpack.selection.text; + console.log("selection = " + text); + if (!text) { + text = clip.get(); + console.log("clipboard = " + text); + } + console.log("text = " + text); + if (text) { + this.queryInNewTab(text, this.component); + } +}; + +/** + * Search simple query in the upstream bugzilla appropriate for the component. + */ +RHBugzillaPage.prototype.queryUpstream = function() { + console.log("Querying upstream!"); + var text = jetpack.selection.text; + console.log("Selection = |" + text + "|"); + if (!text) { + text = clip.get(); + } + if (text) { + text = encodeURIComponent(text.trim()); + var queryUpstreamBugsURLArray = this.constantData.queryUpstreamBug; + var url = util.filterByRegexp(queryUpstreamBugsURLArray, this.component); + jetpack.tabs.open(url + text); + } +}; + +/** + * + */ +RHBugzillaPage.prototype.sendBugUpstream = function() { + var url = util.filterByRegexp(this.constantData.newUpstreamBug, this + .getOptionValue("component")); + + var ret = jetpack.tabs.open(url); + var that = this; + jetpack.tabs.onReady(function() { + var otherDoc = ret.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(); + ret.focus(); + }); +}; + +/** + * 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 + */ +RHBugzillaPage.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 + 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 ]; +}; + +/** + * Add accesskey to the particular element + * + * @param rootElement Element to which the new text object will be attached + * @param beforeText Text before the accesskey character + * @param accKey what will be the accesskey itself + * @param afterText text after the accesskey character + * @return modified element with the fixed accesskey + */ +RHBugzillaPage.prototype.fixElement = function(elem, beforeText, accKey, afterText) { + elem.setAttribute("accesskey", accKey.toLowerCase()); + elem.innerHTML = beforeText + "<b><u>" + accKey + "</u></b>" + afterText; + return elem; +}; + +/** + * 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(URLhostname) { + var bugzillaID = ""; + if (this.constantData.bugzillalabelNames[URLhostname]) { + bugzillaID = this.constantData.bugzillalabelNames[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.fixingMIMECallBack = function(data, textStatus) { + var that = this; + if (--this.reqCounter <= 0) { + setTimeout(function () { + that.doc.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(id, type, email) { + if (type === undefined) { + type = "text/plain"; + } + if (email === undefined) { + email = false; + } + + 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); + + var req = new XMLHttpRequest(); + var that = this; + req.open("POST", XMLRPCurl, true); + req.overrideMimeType("text/xml"); + req.setRequestHeader("Content-type", "text/xml"); + req.onreadystatechange = function(aEvt) { + if (req.readyState === 4) { + if (req.status === 200) { + console.log("Fixing attachment MIME type success!"); + that.fixingMIMECallBack(); + } else { + console.error("Fixing MIME type attachment failed!"); + } + } + }; + req.send(msg.xml()); + this.reqCounter++; +}; + +/** + * Create a button for fixing all bad attachments. + * + * @param list Array of all bad attachmentss + * @return button fixing all bad Attachments + */ +RHBugzillaPage.prototype.createFixAllButton = function(list) { + if (!XMLRPCMessage) { + return; + } + var that = this; + var elem = this.doc.createElement("a"); + elem.setAttribute("href", ""); + elem.setAttribute("accesskey", "f"); + elem.innerHTML = "<b>F</b>ix all"; + elem.addEventListener("click", function() { + Array.forEach(list, function(x) { + this.fixAttachById(x[1]); + }, that); + }, false); + return elem; +}; + +/** + * 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(row) { + var that = this; + var elemS = row[4].getElementsByTagName("td"); + var elem = elemS[elemS.length - 1]; + elem.innerHTML += "<br/><a href=''>Text</a>"; + elem.addEventListener("click", function(x) { + that.fixAttachById(row[1], "text/plain"); + }, false); +}; + +/** + * 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.*/)) { + var helpAElem = this.doc.createElement("a"); + wholeURL = inputBox.value; + helpAElem.setAttribute("href", wholeURL); + var paramsArr = helpAElem.search.replace(/^\?/, '').split('&'); + // get convert URL parameters to an Object + var params = {}, s = []; + paramsArr.forEach(function(par, idx, arr) { + s = par.split('='); + params[s[0]] = s[1]; + }); + if (params.id) { + externalBugID = parseInt(params.id, 10); + inputBox.value = externalBugID; + } + // get host and bugzillaName + var bugzillaName = this.getBugzillaName(helpAElem.hostname); + this.selectOption("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? + } + + // FIXME THis is not good, we don't have a feedback for other commands, + // not to be run, if this fails. + + // 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.getVersion(); + var assignee = this.getOwner(); + if ((!this.isEnterprise()) && (ver < TriagedDistro)) { + 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; +}; diff --git a/lib/rhbzpage.js b/lib/rhbzpage.js index 7f2a875..468818b 100644 --- a/lib/rhbzpage.js +++ b/lib/rhbzpage.js @@ -18,925 +18,20 @@ var BZPage = require("bzpage").BZPage; // RHBugzillaPage object var RHBugzillaPage = exports.RHBugzillaPage = function RHBugzillaPage(doc, config) { + // inheritance ... call superobject's constructor + BZPage.call(this, doc, config); + // For identification of graphics card var 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") - }; - - // END OF CONSTANTS - - // inheritance ... call superobject's constructor - BZPage.call(this, doc, config); - - var that = this; - this.reqCounter = 0; - this.signaturesCounter = 0; - this.chipMagicInterestingLine = ""; - - this.login = this.getLogin(); - this.password = this.getPassword(); - - var ITbutton = this.doc.getElementById("cf_issuetracker"); - this.its = ITbutton ? ITbutton.value.trim() : ""; + console.log("Now we are outside!"); - // Prepare for query buttons - // FIXME getting null for commentArea sometimes - var commentArea = this.doc.getElementById("comment_status_commit"); - if (commentArea) { - var brElementPlacer = commentArea.getElementsByTagName("br"); - console.log("brElementPlacer.length = " + brElementPlacer.length); - brElementPlacer = brElementPlacer[0]; - if (brElementPlacer) { - brElementPlacer.setAttribute("id","brElementPlacer_location"); - brElementPlacer.parentNode.insertBefore(this.doc.createElement("br"), - brElementPlacer); - } - } - - // set default assignee on change of the component - this.doc.getElementById("component").addEventListener("change", - function() { - that.component = that.getOptionValue("component"); - that.changeAssignee("default"); - }, false); - - // getBadAttachments - this.XorgLogAttList = []; - this.XorgLogAttListIndex = 0; - this.attachments = this.getAttachments(); - this.markBadAttachments(); - this.setDefaultAssignee(); - - // Dig out backtrace - this.btSnippet = ""; - - var parseAbrtBacktraces = config.gJSONData.configData.parseAbrtBacktraces; - if (parseAbrtBacktraces && this.RE.Abrt.test(this.title)) { - this.pasteBacktraceInComments(); - } - - // 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() { - if (this.signaturesCounter < 1) { - that.addStuffToTextBox("comment", signatureFedoraString); - this.signaturesCounter += 1; - } - }, false); - } - - this.setBranding(); - this.checkComments(); - - // TODO Get compiz bugs as well - if ((config.gJSONData.configData.PCIIDsURL - && (config.PCI_ID_Array.length > 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(); - } - } + console.log("location = " + this.doc.location); + this.bugId = this.getBugId(); + console.log("bug number = " + this.bugId); }; // END OF RHBugzillaPage CONSTRUCTOR 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.component).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 computer 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 - var verNo = this.getVersion(); - this.selectOption("bug_status", "CLOSED"); - var text = ""; - var resolution = ""; - - if (jetpack.selection.text) { - text = jetpack.select.text.trim(); - } - if (text.length > 0) { - resolution = "CURRENTRELEASE"; - this.doc.getElementById("cf_fixed_in").value = text; - } else if (verNo === 999) { - 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 "queryStringOurBugzilla": - this.queryForSelection(); - break; - case "queryUpstreamBugzilla": - 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; - } -}; - - -/* Bugzilla functions. */ - -RHBugzillaPage.prototype.ProfessionalProducts = [ - "Red Hat Enterprise Linux", - "Red Hat Enterprise MRG" -]; - -/** - * - */ -RHBugzillaPage.prototype.pasteBacktraceInComments = function() { - // FIXME 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'))) { - var btAttachments = this.attachments - .filter(function(att, idx, arr) { - return (/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) { - attURL = "https://bugzilla.redhat.com/attachment.cgi?id=" - + x[1]; - if (!this.btSnippet) { - var btRaw = util.loadText(attURL, function(ret) { - this.btSnippet = this.parseBacktrace(ret); - if (this.btSnippet) { - this.addStuffToTextBox("comment", this.btSnippet); - this.addStuffToTextBox("status_whiteboard", - "btparsed"); - } - }, this); - } - }, this); - } -}; - -/** - * - */ -RHBugzillaPage.prototype.markBadAttachments = function() { - var badMIMEArray = [ "application/octet-stream", "text/x-log", "undefined" ]; - - var badAttachments = this.attachments.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"; - titleElement.appendChild(this.createFixAllButton(badAttachments)); - 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.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() { - // First excceptions - if (this.version > 7 && this.version < 12) { - return this.doc.getElementById("bug_status").value.toUpperCase() !== "NEW"; - } else { // and then the rule - 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()) { - console.log("This is an enterprise bug."); - if (this.its && (this.its.length > 0)) { - brandColor = this.RHITColor; - } else { - brandColor = this.RHColor; - } - } else if (new RegExp("Fedora").test(this.product)) { - console.log("This is NOT an enterprise bug."); - if (this.version === 999) { - 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.textContent = "*"+ccEditBoxElem.textContent; - ccEditBoxElem.style.color = "navy"; - ccEditBoxElem.style.fontWeight = "bolder"; - ccEditBoxElem.style.textDecoration = "underline"; - } - - // mark suspicious components - var compElems; - var suspiciousComponents = config.gJSONData.configData.suspiciousComponents; - if (suspiciousComponents - && util.isInList(this.component, suspiciousComponents) - && (compElems = this.doc - .getElementById("bz_component_edit_container"))) { - compElems.style.background = "red none"; - } -}; - -/** - * 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(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 = config.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 = 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").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 () { - var that = this; - var XorgLogURL = ""; - var XorgLogAttID = ""; - var XorgLogFound = false; - var attURL = "", interestingLine = ""; - var interestingArray = []; - - - // 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])); - }); - if (this.XorgLogAttList.length === 0) { - return; - } - - XorgLogAttID = this.XorgLogAttList[this.XorgLogAttListIndex][1]; - attURL = "https://bugzilla.redhat.com/attachment.cgi?id="+XorgLogAttID; - that = this; - - // parse Xorg.0.log - util.loadText(attURL, function(ret){ - var interestingLineArr = ret.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.chipMagicInterestingLine = interestingLine+"\t"+interestingArray[1] - .toUpperCase(); - that.createNewButton("status_whiteboard", true, "rh-xorg", "chipMagic"); - } - }); - this.XorgLogAttListIndex++; -}; - -/** - * 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 - * - */ -RHBugzillaPage.prototype.queryInNewTab = function(text, component, product) { - console.log("queryInNewTab / text = " + text); - console.log("queryInNewTab / component = " + component); - console.log("queryInNewTab / product = " + product); - var url = "https://bugzilla.redhat.com/buglist.cgi?query_format=advanced"; - if (product) { - url += "&product=" + product.trim(); - } - if (component) { - url += "&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; - url += searchText; - jetpack.tabs.open(url); - // Don't do it ... b.m.o is apparently not powerful enough to sustain - // the weight - // of the search - if (false) { - url = "https://bugzilla.mozilla.org/buglist.cgi?query_format=advanced" - + "field0-0-0=product;type0-0-0=regexp;" - + "value0-0-0=thunderbird|firefox|xulrunner" - + searchText.replace("&", ";"); - jetpack.tabs.open(url); - } - } -}; - -/** - * Get the text to search for and prepare other things for the real executive - * function this.queryInNewTab, and run it. - */ -RHBugzillaPage.prototype.queryForSelection = function() { - var text = jetpack.selection.text; - console.log("selection = " + text); - if (!text) { - text = clip.get(); - console.log("clipboard = " + text); - } - console.log("text = " + text); - if (text) { - this.queryInNewTab(text, this.component); - } -}; - -/** - * Search simple query in the upstream bugzilla appropriate for the component. - */ -RHBugzillaPage.prototype.queryUpstream = function() { - console.log("Querying upstream!"); - var text = jetpack.selection.text; - console.log("Selection = |" + text + "|"); - if (!text) { - text = clip.get(); - } - if (text) { - text = encodeURIComponent(text.trim()); - var queryUpstreamBugsURLArray = this.constantData.queryUpstreamBug; - var url = util.filterByRegexp(queryUpstreamBugsURLArray, this.component); - jetpack.tabs.open(url + text); - } -}; - -/** - * - */ -RHBugzillaPage.prototype.sendBugUpstream = function() { - var url = util.filterByRegexp(this.constantData.newUpstreamBug, this - .getOptionValue("component")); - - var ret = jetpack.tabs.open(url); - var that = this; - jetpack.tabs.onReady(function() { - var otherDoc = ret.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(); - ret.focus(); - }); -}; - -/** - * 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 - */ -RHBugzillaPage.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 - 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 ]; -}; - -/** - * Add accesskey to the particular element - * - * @param rootElement Element to which the new text object will be attached - * @param beforeText Text before the accesskey character - * @param accKey what will be the accesskey itself - * @param afterText text after the accesskey character - * @return modified element with the fixed accesskey - */ -RHBugzillaPage.prototype.fixElement = function(elem, beforeText, accKey, afterText) { - elem.setAttribute("accesskey", accKey.toLowerCase()); - elem.innerHTML = beforeText + "<b><u>" + accKey + "</u></b>" + afterText; - return elem; -}; - -/** - * 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(URLhostname) { - var bugzillaID = ""; - if (this.constantData.bugzillalabelNames[URLhostname]) { - bugzillaID = this.constantData.bugzillalabelNames[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.fixingMIMECallBack = function(data, textStatus) { - var that = this; - if (--this.reqCounter <= 0) { - setTimeout(function () { - that.doc.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(id, type, email) { - if (type === undefined) { - type = "text/plain"; - } - if (email === undefined) { - email = false; - } - - 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); - - var req = new XMLHttpRequest(); - var that = this; - req.open("POST", XMLRPCurl, true); - req.overrideMimeType("text/xml"); - req.setRequestHeader("Content-type", "text/xml"); - req.onreadystatechange = function(aEvt) { - if (req.readyState === 4) { - if (req.status === 200) { - console.log("Fixing attachment MIME type success!"); - that.fixingMIMECallBack(); - } else { - console.error("Fixing MIME type attachment failed!"); - } - } - }; - req.send(msg.xml()); - this.reqCounter++; -}; - -/** - * Create a button for fixing all bad attachments. - * - * @param list Array of all bad attachmentss - * @return button fixing all bad Attachments - */ -RHBugzillaPage.prototype.createFixAllButton = function(list) { - if (!XMLRPCMessage) { - return; - } - var that = this; - var elem = this.doc.createElement("a"); - elem.setAttribute("href", ""); - elem.setAttribute("accesskey", "f"); - elem.innerHTML = "<b>F</b>ix all"; - elem.addEventListener("click", function() { - Array.forEach(list, function(x) { - this.fixAttachById(x[1]); - }, that); - }, false); - return elem; -}; - -/** - * 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(row) { - var that = this; - var elemS = row[4].getElementsByTagName("td"); - var elem = elemS[elemS.length - 1]; - elem.innerHTML += "<br/><a href=''>Text</a>"; - elem.addEventListener("click", function(x) { - that.fixAttachById(row[1], "text/plain"); - }, false); -}; - -/** - * 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.*/)) { - var helpAElem = this.doc.createElement("a"); - wholeURL = inputBox.value; - helpAElem.setAttribute("href", wholeURL); - var paramsArr = helpAElem.search.replace(/^\?/, '').split('&'); - // get convert URL parameters to an Object - var params = {}, s = []; - paramsArr.forEach(function(par, idx, arr) { - s = par.split('='); - params[s[0]] = s[1]; - }); - if (params.id) { - externalBugID = parseInt(params.id, 10); - inputBox.value = externalBugID; - } - // get host and bugzillaName - var bugzillaName = this.getBugzillaName(helpAElem.hostname); - this.selectOption("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? - } - - // FIXME THis is not good, we don't have a feedback for other commands, - // not to be run, if this fails. - - // 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.getVersion(); - var assignee = this.getOwner(); - if ((!this.isEnterprise()) && (ver < TriagedDistro)) { - 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; -}; +RHBugzillaPage.prototype.constructor = RHBugzillaPage;
\ No newline at end of file |