Bugzilla's "Request System": do other issue tracking tools have it? - bugzilla

I've used Bugzilla for many years and one of my favourite features is the "request system" (http://www.bugzilla.org/features/#rs), also known as "flags". The issue can flagged (?) to a user; the user can then accept the request (+) or deny it (-).
I am in the process of re-evaluating our issue tracking tools and I can't seem to find anything other than Bugzilla that has this feature.
So I am wondering:
Does any other product offer similar functionality?
And if not, then is there a way to mimic it (using labels or custom fields or something)?
Your advice is appreciated (FYI: I am currently leaning towards YouTrack).
Alex V. asked for more details about Bugzilla's request system functionality. Here's an example:
An arbitrary list of flags can be created in the admin interface. When editing an issue, they are listed in a row, here's an example:
Next, someone can set the flag and ask for a followup. The screen shot shows me (dcherk) setting the DJiNNInput flag for john#doe.com:
Note that the same flag can be requested multiple times (not shown).
Later, john#doe.com might act on the flag in some way and mark the request as accepted:
Alternatively, john#doe.com might not be able to accept the request. In that case, he would deny it:
Needless to say, all these changes are tracked in the issue history, and can be searched and reported on.

In YouTrack there's no such functionality. What you can do, however, is you can Star the issue for a user as if the if the user did it themselves. They will then receive a notification about it and can either leave the star on the issue, or remove it.
Don't know exactly how those flags work in Bugzilla, so it's is probably not a complete replacement of that feature. If you elaborate on the desired behaviour, I'll let you know how (if possible) to completely mimic it.

FYI:
This is what we ended up doing in YouTrack:
Created two user[*] fields:
Input Requesting (i.e. the person requesting input)
Input Requested (i.e. the user whose input is needed)
The users can always set these fields manually, but we also added the following workflow rules to speed things up:
Rule 1, relates changes to the two field:
rule Input Requested
when Input Requested.changed {
if (Input Requested.isEmpty) {
Input Requesting.clear;
} else {
Input Requesting.add(loggedInUser);
}
}
Rule 2, closed issues do not need any more input:
rule Clear Input Requests When Issue Becomes Closed
when State.becomes({Closed}) {
Input Requested.clear;
Input Requesting.clear;
}
Rule 3, #mentioning sets the fields; replying clears the fields:
rule Input Requested via #mention
when comments.added.isNotEmpty {
var separators = " `!#%^&*()=[]{}:;'\"\\|,<>/?\n\r\t";
var mentionedUsers = "";
var myComment = comments.added.first;
var originalText = myComment.text;
var text = " " + originalText.lowerCase + " ";
var username = "";
var user = loggedInUser;
var index = -1;
index = text.indexOf("#", opts);
while (index != -1) {
index = index + 1;
username = "";
var nextSymbol = text.substring(index, index + 1);
while (!separators.contains(nextSymbol, opts)) {
username = username + nextSymbol;
index = index + 1;
nextSymbol = text.substring(index, index + 1);
}
if (username.endsWith(".", opts)) {
username = username.substringOfLength(username.length - 1, opts);
}
debug("Extracted #username: |" + username + "|");
if (username.isNotEmpty) {
user = project.getUser(username);
if (user != null && !mentionedUsers.contains("#" + user.login + ",", ignoreCase) && (user.isInGroup(permittedGroup.name) || permittedGroup == null || user == reporter) && (myComment.permittedGroup == null || user.isInGroup(myComment.permittedGroup.name))) {
if (Input Requesting.contains(user)) {
Input Requested.remove(loggedInUser);
if (Input Requested.isEmpty) {
Input Requesting.clear;
}
} else {
Input Requested.add(user);
Input Requesting.add(loggedInUser);
}
mentionedUsers = mentionedUsers + "#" + user.login + ",";
}
}
text = text.substringRelative("#" + username, pos: after);
index = text.indexOf("#", opts);
}
}
Hope that helps anyone along the way.

Related

Loading a new window from local files and accessing it's contents

I am setting up a local webpage which shows videos in a HTML5 video tag. I just want to be able to do database search from a PHP request and show the results from which I can click on and show the video I want. The problem I have is that hte videos load WAY faster when loading from a "file:///" link than from the "http://" link. Server works flawlessly when in "HTTP" mode but nothing works in "file:///" mode which is normal as PHP codes only execute on the server side when requested to the server.
I have spent my full day trying soo much stuff. I changed my server to accept CORS, I tried window.open, storing the reference in a variable, local or global but I lose this as soon as I get out of my javascript function. I tried window.open in a function which is called from another function but no matter what I do, the window reference gets lost as soon as I leave the functions, or once the functions have finished. Since my browser is used as my main browser, I do not want to disable the security arround CORS but since my webpage's link comes from "file:///" requesting to "HTTP" on the same computer, CORS blocks me and wants an HTTP request which I can't give.
I have done all the searching for retrieving information from another webpage but I am always stuck with the "same domain" problem. I tried AJAX HTTPRequest, I just have no more solution for this simple problem which finished way more complicated than expected. The initial problem was just my videos not loading fast enough in HTTP mode (The speed difference is extreme, for 10 min videos, I can wait 5-10 seconds to skip through it while as in FILE:/// urls, It's almost instant, no waiting. longer videos of 1h, I can wait up to 20 and 30 seconds while as in file:/// mode, almost instant.) and I had to learn all that Allow cross domains stuff which ended up with no success either. I figure that maybe a few other heads may have better ideas than mine now.
#In my httpd.conf file from Apache
DocumentRoot "e:/mainwebfolder"
Alias "/lp" "d:/whatever"
//////////////////////////////////////
// index.php file that does not contain PHP contents
// window.location.href: file://d:/whatever/index.php
//////////////////////////////////////
<head>
<script src="html/servcom.js" type="text/javascript"></script>
</head>
<video id="vplayer" width="1280" height="720" controls></video>
<div id="search-form">
<input id="srch" name="srch" type="text">
<button class="bbut" onclick="ServInfo('search-results','http://127.0.0.1/lp/html/db.php','mode=s','search-form');">Search</button>
</div>
<div id='search-results'></div>
<script>
var dplay = document.getElementById("vplayer");
ShowVideo('MyVideo.mp4');
function ShowVideo (vidUrl) {
dplay = document.getElementById("vplayer");
dplay.src = vidUrl;
dplay.load;
}
</script>
//////////////////////////////////////
// Now this is in my javascript file servcom.js
//////////////////////////////////////
var win_ref = -1;
function ServInfo(pop_field_id,web_page,params="",form_id="",exec_string = "") {
var sparams = params;
var swpage = web_page;
var eobj = document.getElementById(pop_field_id);
var moreparams = "";
// If we entered extra parameters including form fields,
// add the the "&" before the form field list
if (sparams != "") {moreparams = "&";}
// Get form field values if a form id is specified
if (form_id != "") {
var efrm = document.getElementById(form_id);
sparams += moreparams+GetDivFields(form_id);
}
// Add the question mark if there is any parameters to pass
if (sparams != "") {
sparams = "?"+sparams;
// Add recieving objects reference
sparams += "&srco="+pop_field_id;
}
// If HTML element to populate does not exist, exit
if (typeof(eobj) == "!undefined" || eobj == null) {return;}
win_ref = window.open(swpage+sparams,"_blank");
//////////////////////////////////////
// right here win_ref will never be available once the code from this function has been finished executing although the variable is global. The problem starts here.
//////////////////////////////////////
// Execute a string if a user defined one
if (exec_string != "") {eval(exec_string);}
}
// Build a parameter string with div fields of type text, hidden or password
function GetDivFields(div_id) {
var ediv = document.getElementById(div_id);
var elem = ediv.children;
var retval = "";
var ssep = "";
for (var i = 0; i < elem.length; i++) {
if (elem[i].type == "text" || elem[i].type == "hidden" || elem[i].type == "password") {
retval += ssep+elem[i].name+"="+pURL(elem[i].value);
ssep = "&";
}
if (elem[i].type == "checkbox") {
if (elem[i].checked == true) {
retval += ssep+elem[i].name+"="+elem[i].value;
ssep = "&";
}
}
}
return retval;
}
//////////////////////////////////////
// And this is a brief overview of my db.php page
//////////////////////////////////////
<?php // Search Database code ?>
<div id="output"></div>
<script>
document.getElementById('output').innerHTML = "<?php echo $search_results; ?>";
// I actually want to retrieve the info from this div element once it has been populated from the initial page that called window.open for this page. BUT again. window.opener becomes empty once my initial window.open script finishes.
</script>
Access my newly loaded page's "output" div innerHTML OR loading videos through local HTTP as fast as "FILE:///".
Well, I fanally found a solution. Since this is for local and presentation use only, I could bypass some securities. Basically, doing what we would normally NOT do in a website but all this WITHOUT modifying your webserver config or touching any .htaccess file. Basically, no security restrictions, just a plain old hack that poses no security breaches for your browser or your server.
To be noted:
2 different websites exist (so 2 different folders at very different locations), 1 for developpement and serious releases, one for internal and/or presentation purposes.
Every file is local abd inside the presentation folder.
No PHP code can be ran from a "file:///" link.
Access to the mysql database is done through PHP and server is on Apach24
Reading video locally from a "file:///" link are WAY faster than from an "http://" link
Searching needs to be done in MySQL database frm a "http://" link and results need to be displayed on a webpage opened from a "file:///" link.
No changes must be made in the Browser's configuration so disabling CORS is not a solution.
Bypassing cors with methods proposed by many site won't work because of security reasons or because CORS bypass does not accept "file:///" links
PHP can write files on the server which is where I decided to bypass CORS. Since XML requests through AJAX can be done on the same origin domain an thus, purely in javascript. If a file exists which contains no PHP code AND resides on the same domaine i/e "file:///", the contents can the be read wothout any problems.
So I simply do the following in my db.php file:
$s_mode = "";
$s_text = "";
$sres = "";
if (isset($_REQUEST["srch"])) {$s_text=$_REQUEST["srch"];}
if (isset($_REQUEST["mode"])) {$s_mode=$_REQUEST["mode"];}
if ($s_mode == "s") {
$sres = SearchDB($s_text);
WriteFile("D:/whatever/my_path/dbres.html",$sres);
}
// Writes the contents of the search in a specified file
function WriteFile($faddress,$fcontents) {
$ifile = fopen($faddress,"w");
fwrite($ifile,$fcontents);
fclose($ifile);
}
Now using a normal AJAX request, I do 2 things. I opted to use an iframe with a "display:none" style to not bother seeing another tab openup.
Do the actual request which opens the "cross-doamin" link in the iframe WHICH executes my db.php code. I basically open "http://127.0.0.1/whatever/db.php?param1=data&parma2=data" inside my iframe.
Once my search is done and I have the results, my db.php will save an html file with the results as it's contents in my "file:///" direct location's path so: "D:/whatever/my_path/dbres.html".
I added a new function in my servcom.js. So my new file's contents looks like this:
// Show page info in another page element or window with parameters (for local use only)
function ServInfoLocal(dest_frame,web_page,params="",form_id="") {
var sparams = params;
var swpage = web_page;
var iweb = document.getElementById(dest_frame);
var moreparams = "";
// If we entered extra parameters including form fields,
// add the the "&" before the form field list
if (sparams != "") {moreparams = "&";}
// Get form field values if a form id is specified
if (form_id != "") {
var efrm = document.getElementById(form_id);
sparams += moreparams+GetDivFields(form_id);
}
// If destination frame does not exist, exit
if (typeof(iweb) == "!undefined" || iweb == null) {return;}
// Add the question mark if there is any parameters to pass
if (sparams != "") {sparams = "?"+sparams;}
// Show results in iframe
iweb.src = swpage+sparams;
}
// AJAX simple HTTP GET request
function ServInfo(pop_field_id,web_page,params="",form_id="",append_data_to_output = "",exec_string = "",dont_show_results = "") {
var sparams = params;
var swpage = web_page;
var eobj = document.getElementById(pop_field_id);
var moreparams = "";
// If we entered extra parameters including form fields,
// add the the "&" before the form field list
if (sparams != "") {moreparams = "&";}
// Get form field values if a form id is specified
if (form_id != "") {
var efrm = document.getElementById(form_id);
sparams += moreparams+GetDivFields(form_id);
}
// If HTML element to populate does not exist, exit
if (typeof(eobj) == "!undefined" || eobj == null) {return;}
if (window.XMLHttpRequest) {
// IE7+, Firefox, Chrome, Opera, Safari
xmlhttp = new XMLHttpRequest();
}
else {
// IE6-
xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
}
xmlhttp.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
// Do not show any results if requested
if (dont_show_results == "") {
if (append_data_to_output == "y") {
document.getElementById(pop_field_id).innerHTML += this.responseText;
}
if (append_data_to_output == "") {
document.getElementById(pop_field_id).innerHTML = this.responseText;
}
}
// Execute a string if a user defined one
if (exec_string != "") {
eval(exec_string);
}
}
};
// Add the question mark if there is any parameters to pass
if (sparams != "") {swpage += "?";}
xmlhttp.open("GET",swpage+sparams,true);
xmlhttp.send();
}
// Build a parameter string with div fields of type text, hidden or password
function GetDivFields(div_id) {
var ediv = document.getElementById(div_id);
var elem = ediv.children;
var retval = "";
var ssep = "";
for (var i = 0; i < elem.length; i++) {
if (elem[i].type == "text" || elem[i].type == "hidden" || elem[i].type == "password") {
retval += ssep+elem[i].name+"="+pURL(elem[i].value);
ssep = "&";
}
if (elem[i].type == "checkbox") {
if (elem[i].checked == true) {
retval += ssep+elem[i].name+"="+elem[i].value;
ssep = "&";
}
}
}
return retval;
}
Now, my dbres.html file will contain just the div elements and all the information I need to show up in my "file:///" page from which the search request came from. So I simply have this inside my page:
<div id="search-form" style="color:white;font-weight:bold;">
<input id="srch" name="srch" type="text">
<button class="bbut" onclick="ServInfoLocal('iweb','http://127.0.0.1/whatever/html/db.php','mode=s','search-form');">Search</button>
<button class="bbut" onclick="ServInfo('search-results','dbres.html');">Click here</button>
</div>
<div id="search-results">Results here</div>
<iframe id="iweb" style="display:none;" src=""></iframe>
For now I have 2 buttons, one for the search and one to show the results from my newly created file. Now, I can show my local videos which will load in my video container with "file:///" source directly without passing through http. I'll make my results display automatic which I will be able to do myself from here on.
So, if someone on planet earth wants to be able to do cross-domain searches in a MySQL database from a local file ran directly from the Windows explorer, there's not too many solutions, actually, I found none so here is at least one for who would ever need this solution.
For the curious ones out there, my next step will be to loop my folder until my dbres file is present using another js function. Once my file has been fetched, call another php file which wil destroy the created file and I'll be ready for another database request from my webpage situated in a "file:///" location.

Codename One - RegexConstraint to check a valid phone number

In the following code, the RegexConstraint doesn't work, because the phone number results always incorrect. What's wrong? I need to check a mobile phone number (without the country code). For example, the input 3652312453 should be correct, but in the following code it's evaluated as incorrect.
I copied the regex from the discussion linked in the comment: my only requirement is a valid phone number.
(Note: this question is not for generic Java, but only for Codename One. The class "CountryCodePicker" extends the class "Button": I reported it to make it clear that the phone number and the country code are separated)
TextModeLayout tl = new TextModeLayout(1, 1);
Container loginContainer = new Container(tl);
TextComponent phone = new TextComponent().label("PHONE").errorMessage("INVALID-PHONE");
CountryCodePicker countryCode = new CountryCodePicker();
phone.getField().setConstraint(TextArea.PHONENUMBER);
loginContainer.add(phone);
Container loginContainerWithCodePicker = new Container(new BoxLayout(BoxLayout.X_AXIS_NO_GROW));
loginContainerWithCodePicker.add(countryCode).add(loginContainer);
// https://stackoverflow.com/questions/8634139/phone-validation-regex
String phoneRegEx = "/\\(?([0-9]{3})\\)?([ .-]?)([0-9]{3})\\2([0-9]{4})/";
val.addConstraint(phone, new RegexConstraint(phoneRegEx, "NOT-VALID-NUMBER"));
Button loginButton = new Button("LOG-IN");
val.addSubmitButtons(loginButton);
[rant]
Personally I really hate regex as I find it damn unreadable for anything other than trivial validation.
[/rant]
So I would prefer this:
val.addConstraint(phone, new Constraint() {
public boolean isValid(Object value) {
String v = (String)value;
for(int i = 0 ; i < v.length() ; i++) {
char c = v.charAt(i);
if(c >= '0' && c <= '9' || c == '+' || c == '-') {
continue;
}
return false;
}
return true;
}
public String getDefaultFailMessage() {
return "Must be valid phone number";
}
});
However, I'm guessing the reason the regex failed for you is related to the syntax with the slashes:
String phoneRegEx = "^\\(?([0-9]{3})\\)?([ .-]?)([0-9]{3})\\2([0-9]{4})";
The following resource on Oracle's Java 8 Lessons helps me always define the RegEx I need. Take the time to study it and you will be successful, especially since the problem seems to be in the initialization of the Constraint object. I had an issue the day before my post here, and managed to solve it elegantly which is the goal, always.
Use this link
https://docs.oracle.com/javase/tutorial/essential/regex/
Oracle Tutorials: "Lesson: Regular Expressions".

Angularfire $save array

I'm trying to save a collection of data after i have updated an entry in the array.
// Edit a post
$scope.editMe = function(message) {
if($scope.textBoxMessage = "What good did you do today?"){
$scope.textBoxMessage = "Here you can edit your post by entering a new message and pressing edit on the affected post" + "\n \n" + "Your post:" + "\n" + message.post;
}
else{
$scope.message.post="hello"; //$scope.newMessage
$scope.messages.$save(2);
}
}
Ones a user have entered some text in a textfield i want to replace that with the already stored data. This by overwriting message.data with sometext. Since i read in data like this:
var list = fbutil.syncArray('posts/'+user.uid);
i also tried to simply say:
message.post = $scope.newMessage;
list.$save()
Neither of these two methods work but i'm sure it's a minor mistake.
ED:
According to angularFire api, visit: https://www.firebase.com/docs/web/libraries/angular/api.html#angularfire-firebasearray-save-recordorindex
list[2].post = "hello";
list.$save(2);
should work but i have had no luck.
Okay here is how i solved it:
The problem had more to do with the if else statement then with the server code itself. The $scope.textBoxMessage is always true no matter what and this is what bothered me. Even if i say if($scope.textBoxMessage = "hi") it will be true.
I'm not sure why this is the case but feel free to comment if you have any suggestions.
This is how i solved it:
// Edit a post
$scope.editMe = function(message) {
if($scope.newMessage == null){
$scope.textBoxMessage = "Here you can edit your post by entering a new message and pressing edit on the affected post" + "\n \n" + "Your post:" + "\n" + message.post;
}
else{
message.post = $scope.newMessage;
list.$save(message);
$scope.textBoxMessage = chatmessage;
$scope.newMessage = null;
}
}

Arrays and if statements. How to check if value is in array? *javascript*

So I have a program that sends emails. The user has a list of emails that cannot be sent to. These are in arrays and I need to use a if statement to determine if what the user entered in is in the array of emails. I tried the in function which didnt work but Im probably just using it wrong. I tried for loops and if statements inside. But that didnt work either. Here is a snapshot of the code Im using to help you get the idea of what im trying to do.
function test2(){
var safe = [1]
safe[1] = "lol"
safe[2] = "yay"
var entry = "lol"
Logger.log("entry: " + entry)
for(i = 0; i < safe.length; i++){
if(entry == safe[i]){
Logger.log("positive")
}else{
Logger.log("negative")
}
}
}
Here is what I tried with the in function to show you if I did it wrong
function test(){
var safe = [1]
safe[1] = "lol"
safe[2] = "yay"
var entry = "losl"
Logger.log("entry: " + entry)
if(entry in safe){
Logger.log("came positive")
}else{
Logger.log("came negative")
}
Logger.log(safe)
}
array.indexOf(element) > -1 usually does the trick for these situations!
To expand upon this:
if (array.indexOf(emailToSendTo) < 0) {
// send
}
Alternatively, check this cool thing out:
emailsToSend = emailsToSend.filter(function(x) {
// basically, this returns "yes" if it's not found in that other array.
return arrayOfBadEmails.indexOf(x) < 0;
})
What this does is it filters the list of emailsToSend, making sure that it's not a bad email. There's probably an even more elegant solution, but this is neat.

Kentico Global Events (ObjectEvents) Causes Loop

I'm using ObjectEvents to give ActivityPoints to current user based on fields user filled.
Now for example if user register and fill FirstName I will give 10 points to user.
The problem is that I'm handling ObjectEvents.Update.After and inside it I'm updating userSettings.This causes a unlimited loop and application stops working.
is there any work around?
this is the code block:
var className = e.Object.TypeInfo.ObjectClassName;
DataClassInfo dci = DataClassInfoProvider.GetDataClass(className);
if (dci != null)
{
var fi = new FormInfo(dci.ClassFormDefinition);
if (fi != null)
{
var stopProccess = true;
var fields = new List<FormFieldInfo>();
foreach (var changedColumn in e.Object.ChangedColumns())
{
var field = fi.GetFormField(changedColumn);
var activityPointMacro = ValidationHelper.GetString(field.Settings["ActivityPointMacro"], "");
if (!string.IsNullOrEmpty(activityPointMacro))
{
fields.Add(field);
stopProccess = false;
}
}
if (!stopProccess)
{
var contextResolver = CMSContext.CurrentResolver.CreateContextChild();
foreach (FormCategoryInfo info in fi.ItemsList.OfType<FormCategoryInfo>())
{
contextResolver.SetNamedSourceData(info.CategoryName, info);
}
EditingFormControl data = new EditingFormControl();
foreach (FormFieldInfo info2 in fi.ItemsList.OfType<FormFieldInfo>())
{
contextResolver.SetNamedSourceData(info2.Name, data);
}
foreach (var field in fields)
{
{
var activityPointMacro = ValidationHelper.GetString(field.Settings["ActivityPointMacro"], "");
var activityPoint =
ValidationHelper.GetInteger(contextResolver.ResolveMacros(activityPointMacro), 0);
CMSContext.CurrentUser.UserSettings.UserActivityPoints += activityPoint;
CMSContext.CurrentUser.UserSettings.Update();
}
}
}
}
}
If you just need to give points for user fields then you could just use ObjectEvents.Update.Before, check fields are not empty and assign points. But i can see from the code, you want to have something more complex bulit over macro expressions. So I have a few suggestions for you.
1) ObjectEvents.Update.Before instead of ObjectEvents.Update.After still may be a good idea. Ideally you set your additional values and all is set during one update.
2) Watch only the class names you need
3) Always prefer Provider.SetInfo methods over info.Update(). In case of user settings it's best to set whole user info, so UserInfoProvider.SetUserInfo. Provider methods may add some additional important logic.
4) The code seems like it'll add the points with every update of a user
5) if you are still running into a loop, you need to flag somehow, that some part of code should not be executed again. The best way is to use RequestStockHelper class - add a bool value with a specificname like "PointsProcessed".

Resources