mud/lib/secure/cmds/players/bug.c
2020-09-06 05:43:07 -07:00

510 lines
18 KiB
C

/* /secure/cmds/player/bug.c
* from the Dead Souls Object Library
* the command interface to the NM IV bug tracking system
* created by Descartes of Borg 950925
*/
#include <lib.h>
#include <daemons.h>
#include <message_class.h>
inherit LIB_DAEMON;
void PreMenu(string str);
static varargs void MainMenu(string str);
static void Assign(string *args);
static void EndAssign(string *args);
static void Complete(string *args);
void EndComplete(int x);
static void Delete(string *args);
static void Report(string *args);
static void EndReport(string type, string data, string file);
varargs static void View(string *args, int print);
static string GetBugString(int id, mapping bugs);
static void create() {
daemon::create();
SetNoClean(1);
}
mixed cmd(string str) {
string *args;
int i;
if( !str || str == "" ) args = ({});
else args = explode(str, " ");
if( !(i = sizeof(args)) ) MainMenu();
else {
string opt;
opt = args[0];
if( i == 1 ) args = ({});
else args = args[1..];
switch(opt) {
case "-a": Assign(args); break;
case "-c": Complete(args); break;
case "-d": Delete(args); break;
case "-r": Report(args); break;
case "-p": View(args, 1); break;
case "-v": View(args); break;
default: return "To report a bug, use \"bug -r\".";
}
}
return 1;
}
void PreMenu(string str) {
if( str == "q" ) {
message("system", "Exiting the bug tracking system.", this_player());
return;
}
MainMenu();
}
varargs static void MainMenu(string str) {
string tmp;
int cols;
if( str && str != "" ) {
switch(str) {
case "a": Assign(({})); return;
case "c": Complete(({})); return;
case "d": Delete(({})); return;
case "r": Report(({})); return;
case "p": View(({}), 1); return;
case "v": View(({})); return;
case "q":
message("system", "Exiting the bug tracking system.",
this_player());
return;
}
}
cols = ((int *)this_player()->GetScreen())[0] || 80;
tmp = center("Dead Souls Bug Tracking System", cols) + "\n\n";
if( creatorp(this_player()) ) {
tmp += "a)ssign bug to creator\n";
tmp += "c)omplete work on a bug\n";
}
if( archp(this_player()) ) tmp += "d)elete a bug from the system\n";
tmp += "r)eport a new bug to the system\n";
tmp += "v)iew an existing bug or a list of existing bugs\n";
tmp += "\nq)uit the bug tracking system\n";
message("system", tmp, this_player());
message("prompt", "Enter your choice: ", this_player());
input_to( (: MainMenu :) );
}
static void Assign(string *args) {
int i;
if( !creatorp(this_player()) ) {
message("system", "Only creators may use the -a option.",
this_player());
return;
}
if( !(i = sizeof(args)) ) {
message("prompt", "Enter in the bug ID: ", this_player());
input_to(function(string str) { Assign(({ str })); });
return;
}
else if( i == 1 ) {
int x;
if( (x = to_int(args[0])) > 0 ) { /* assume a bug id for now */
if( !archp(this_player()) )
Assign( ({ args[0], this_player()->GetCapName() }) );
else {
message("prompt", "Enter the creator to assign it to [" +
this_player()->GetCapName() + "]: ",
this_player());
input_to(function(string str, string id) {
if( !str || str == "" )
str = this_player()->GetCapName();
Assign( ({ str, id }) );
}, args[0]);
}
return;
}
else {
message("prompt", "Enter in the bug ID to assign to " +
capitalize(args[0]) + ": ", this_player());
input_to(function(string id, string str) {
Assign( ({ id, str }) );
}, args[0]);
return;
}
}
else if( i == 2 ) {
message("prompt", "Do you wish to comment? [n]: ", this_player());
input_to(function(string str, string *args) {
if( !str || str == "" ) str = "n";
else str = lower_case(str[0..0]);
if( str == "y" ) {
string file;
message("system", "Enter comments on the bug...",
this_player());
file = DIR_TMP "/" + this_player()->GetKeyName();
rm(file);
this_player()->eventEdit(file, (: EndAssign, args :));
return;
}
else Assign(args + ({ "" }));
}, args);
return;
}
else {
string who, comments;
int x;
if( (x = to_int(args[0])) < 1 ) {
who = args[0];
if( (x = to_int(args[1])) < 1 ) {
message("system", "Invalid bug ID " + x + ".", this_player());
message("prompt", "Hit return: ", this_player());
input_to( (: PreMenu :) );
return;
}
}
else who = args[1];
comments = args[2];
if( !archp(this_player()) && (convert_name(who) !=
this_player()->GetKeyName()) ) {
message("system", "Only arches may assign bugs to other people.",
this_player());
message("prompt", "Hit return: ", this_player());
input_to( (: PreMenu :) );
return;
}
if( !user_exists(convert_name(who)) ) {
message("system", "No such creator: " + who, this_player());
message("prompt", "Hit return: ", this_player());
input_to( (: PreMenu :) );
return;
}
if( !(BUGS_D->eventAssign(x, who)) ) {
message("system", "Failed to assign bug.", this_player());
return;
}
if( comments != "" ) BUGS_D->AddComment(x, comments);
message("system", "Assigned bug to " + who + ".", this_player());
return;
}
}
static void EndAssign(string *args) {
string file, contents;
file = DIR_TMP "/" + this_player()->GetKeyName();
contents = (read_file(file) || "");
rm(file);
Assign(args + ({ contents }));
}
static void Complete(string *args) {
string file;
int x;
if( !sizeof(args) ) {
message("prompt", "Enter the bug ID: ", this_player());
input_to(function(string str) { Complete( ({ str }) ); });
return;
}
else if( !creatorp(this_player()) ) {
message("system", "Invalid command.", this_player());
message("prompt", "Hit return: ", this_player());
input_to( (: PreMenu :) );
return;
}
else if( (x = to_int(args[0])) < 1 ) {
message("system", "Invalid bug ID.", this_player());
message("prompt", "Hit return: ", this_player());
input_to( (: PreMenu :) );
return;
}
message("system", "Enter in your comments:", this_player());
file = DIR_TMP "/" + this_player()->GetKeyName();
if( file_exists(file) ) rm(file);
this_player()->eventEdit(file, (: EndComplete, x :));
}
void EndComplete(int x) {
string file, stuff;
if( previous_object() != this_player(1) ) return;
file = DIR_TMP "/" + this_player()->GetKeyName();
if( !(stuff = read_file(file)) ) {
message("system", "Edit aborted.", this_player());
rm(file);
return;
}
rm(file);
if( !(BUGS_D->eventComplete(x, stuff)) ) {
message("system", "Failed to set the bug completed.", this_player());
return;
}
message("system", "Bug marked completed!", this_player());
}
static void Delete(string *args) {
if( !archp(this_player()) ) {
message("system","You must be an arch to delete bugs.", this_player());
return;
}
if( !sizeof(args) ) {
message("prompt", "Delete which bug? ", this_player());
input_to(function(string str) { Delete( ({ str }) ); });
return;
}
else {
int x;
if( (x = to_int(args[0])) < 1 )
message("system", "Invalid bug ID.", this_player());
else if( !(BUGS_D->eventDelete(x)) )
message("system", "Delete failed.", this_player());
else message("system", "Deletion succeeded.", this_player());
return;
}
}
static void Report(string *args) {
if( archp(this_player()) && sizeof(args) ) {
string data;
string bug;
int x;
data = "Room: " + file_name(environment(this_player()));
bug = implode(args, " ");
if( x = BUGS_D->eventReport(this_player()->GetCapName(),
"approval", bug, data) ) {
BUGS_D->eventAssign(x, query_privs(environment(this_player())));
message("system", "Bug reported.", this_player());
return;
}
else {
message("system", "Error in reporting bug.", this_player());
return;
}
}
else EndReport(0, "Room: " + file_name(environment(this_player())), 0);
}
static void EndReport(string type, string data, string file) {
string tmp;
int x;
if( !type ) {
message("system", "Choose a bug type from among the following:\n",
this_player());
message("system", "\tidea (some nifty idea to add to the game)",
this_player());
message("system", "\ttypo (misspelling, lexigraphical weirdness)",
this_player());
message("system", "\tunexplained behaviour (something "
"contrary to how you would expect it)", this_player());
message("system", "\truntime (one of those nasty error messages)\n",
this_player());
message("system", "\tother\n", this_player());
message("prompt", "Enter type: ", this_player());
input_to( (: EndReport :), data, 0);
return;
}
if( !file ) {
file = DIR_TMP "/" + this_player()->GetKeyName();
rm(file);
message("system", "Enter in a description of the bug. When done, "
"enter a period on a line by itself.", this_player());
this_player()->eventEdit(file, (: EndReport, type, data, file :));
return;
}
if( !(tmp = read_file(file)) ) {
message("system", "Bug report aborted.", this_player());
rm(file);
return;
}
rm(file);
if( type == "runtime" ) {
mapping last_error;
if( last_error = this_player()->GetLastError() )
data += "\n" + master()->standard_trace(last_error) + "\n";
}
if( !(x = BUGS_D->eventReport(this_player()->GetCapName(),
type, tmp, data)) ) {
message("system", "Bug report failed.", this_player());
return;
}
message("system", "Bug reported, thank you! Your tracking id is " +
x + ".", this_player());
}
varargs static void View(string *args, int print) {
mapping bugs;
function f;
f = function() {
message("prompt", "\nHit return: ", this_player());
input_to( (: PreMenu :) );
};
if( !sizeof(args) ) {
message("system", "View:\n\t1) all bugs\n"
"\t2) unassigned bugs only\n"
"\t3) assigned bugs only\n"
"\t4) completed bugs only\n", this_player());
if( creatorp(this_player()) )
message("prompt", "Enter a choice [3]: " , this_player());
else message("prompt", "Enter a choice [1]: ", this_player());
input_to(function(string str, string it_sucks, int print) {
if( !str || str == "" ) {
if( creatorp(this_player()) ) str = "3";
else str = "1";
}
if( str < "1" || str > "4" ) {
message("system", "Invalid selection", this_player());
message("prompt", "Hit return: ", this_player());
input_to( (: PreMenu :) );
return;
}
View( ({ str }), print );
}, "", print);
return;
}
else if( sizeof(args) == 1 && !creatorp(this_player()) ) {
mapping bug;
string tmp = "";
int bug_id;
bugs = BUGS_D->GetBugs();
foreach( bug_id, bug in bugs ) {
if( bug["who"] != this_player()->GetCapName() )
continue;
if( args[0] == "1" || (args[0] == "2" && !bug["assigned"]) ||
(args[0] == "3" && bug["assigned"] && !bug["date fixed"]) ||
(args[0] == "4" && bug["date fixed"]) )
tmp += GetBugString(bug_id, bugs) + "\n*****\n\n";
}
if( tmp == "" ) {
message("system", "No bugs meet your query criteria.",
this_player());
message("prompt", "Hit return: ", this_player());
input_to( (: PreMenu :) );
return;
}
this_player()->eventPage(explode(tmp, "\n"), MSG_SYSTEM, f);
return;
}
else if( sizeof(args) == 1 ) {
message("system", "View:\n\t1) all bugs\n"
"\t2) bugs assigned to me\n"
"\t3) bugs reported by me\n", this_player());
message("prompt", "Enter choice [2]: ", this_player());
input_to(function(string str, string one, int print) {
if( !str || str == "" ) str = "2";
else if( str < "1" || str > "3" ) {
message("system", "Invalid selection.", this_player());
message("prompt", "Hit return: ", this_player());
input_to( (: PreMenu :) );
return;
}
View( ({ one, str }), print );
}, args[0], print);
return;
}
else {
mapping bug;
string nom, tmp = "";
int bug_id;
nom = this_player()->GetKeyName();
bugs = BUGS_D->GetBugs();
if( !creatorp(this_player()) ) {
View( ({ args[0] }), print );
return;
}
else foreach(bug_id, bug in bugs) {
string opt1, opt2;
opt1 = args[0];
opt2 = args[1];
if( opt1 == "1" && opt2 == "1" )
tmp += GetBugString(bug_id, bugs) + "\n*****\n\n";
else {
if( opt2 == "2" && (!bug["assigned"] ||
convert_name(bug["assigned"]) != nom) )
continue;
else if(opt2 == "3" && convert_name(bug["who"]) != nom )
continue;
if( opt1 == "2" && !bug["assigned"] )
tmp += GetBugString(bug_id, bugs) + "\n*****\n\n";
else if( opt1 == "3" && bug["assigned"] && !bug["date fixed"] )
tmp += GetBugString(bug_id, bugs) + "\n*****\n\n";
else if( opt1 == "4" && bug["date fixed"] )
tmp += GetBugString(bug_id, bugs) + "\n*****\n\n";
}
}
if( tmp == "" ) {
message("system", "No bugs match your query.", this_player());
message("prompt", "Hit return: ", this_player());
input_to( (: PreMenu :) );
return;
}
if( print && creatorp(this_player()) ) {
string file;
rm(file = user_path(this_player()->GetKeyName()) + "bugs");
write_file(file, strip_colours(tmp));
}
else this_player()->eventPage(explode(tmp, "\n"), MSG_SYSTEM, f);
return;
}
}
static string GetBugString(int id, mapping bugs) {
string tmp;
tmp = "%^YELLOW%^Bug ID:%^RESET%^ " + id + "\n";
tmp += "%^YELLOW%^Reported by:%^RESET%^ " +
bugs[id]["who"] + "\n";
if( bugs[id]["assigned"] ) {
tmp += "%^YELLOW%^Status: %^RESET%^";
if( !bugs[id]["date fixed"] )
tmp += "assigned to " + bugs[id]["assigned"] + "\n";
else tmp += "completed " + ctime(bugs[id]["date fixed"]) + "\n";
}
else tmp += "%^YELLOW%^Status:%^RESET%^ unassigned\n";
tmp += "%^YELLOW%^Type:%^RESET%^ " + bugs[id]["type"] + "\n";
if( bugs[id]["date fixed"] )
tmp += "%^YELLOW%^Notes:%^RESET%^\n" + bugs[id]["resolution"] + "\n";
if( creatorp(this_player()) )
tmp += "\n%^YELLOW%^Creator info:%^RESET%^\n" + bugs[id]["data"] + "\n";
tmp += "\n%^YELLOW%^Bug info:%^RESET%^\n" + bugs[id]["bug"] + "\n";
return tmp;
}
string GetHelp(){
string tmp;
tmp = "Syntax: bug\n";
if( creatorp(this_player()) ) {
tmp += " bug -a <BUG_ID CREATOR>\n";
tmp += " bug -c <BUG_ID>\n";
}
if( archp(this_player()) ) tmp += " bug -d <BUG_ID>\n";
tmp += " bug -r\n bug -v [1-4] [1-3]\n\n";
tmp += "The command interface to the Dead Souls Bug Tracking System. "
"You can simply type \"bug\" and be prompted for further options, "
"or, if you understand the system, pass command line arguments "
"to the bug command to make things go faster. This system allows "
"players to report bugs or ideas and periodically see what has "
"been done about their report. It also allows creators a way "
"to track bugs which have been reported to them and give feedback "
"to the players who have reported them. It gives admins a way to "
"track and assign mudlib level bugs. The options above correspond "
"to assigning, completing, deleting, reporting, and viewing bugs "
"respectively.\n"
"See also: praise";
return tmp;
}