//-< BUGDB.CXX >----------------------------------------------------*--------* // GOODS Version 1.0 (c) 1997 GARRET * ? * // (Generic Object Oriented Database System) * /\| * // * / \ * // Created: 27-Mar-99 K.A. Knizhnik * / [] \ * // Last update: 4-Jul-99 K.A. Knizhnik * GARRET * //-------------------------------------------------------------------*--------* // Example of database Web publishing: Bug Tracking Database //-------------------------------------------------------------------*--------* #include "bugdb.h" //#define USE_QUEUE_MANAGER 1 char const* const eCATEGORY_STRING[] = { "", "CRASH", "PROGRAM_HANGS", "UI_DISPLAY", "UI_BEHAVIOR", "CALCULATION", "ERROR_HANDLING", "PERFORMANCE", "LICENSING", "INSTALLATION", "DOCUMENTATION", "ENHANCEMENT", "HOW_TO_QUESTION", NULL }; char const* const eSTATUS_STRING[] = { "", "OPENED", "FIXED", "CLOSED", "PENDING_ENGINEER", "PENDING_USER", "POSTPONED", "IRREPRODUCIBLE", "WITHDRAWN", "AS_DESIGNED", NULL }; char const* const eSEVERITY_STRING[] = { "", "FATAL", "SERIOUS", "MINOR", NULL }; char const* const eFIXING_PRIORITY_STRING[] = { "", "FIX_IMMEDIATELY", "FIX_BEFORE_NEXT_BUILD_RELEASE", "FIX_BEFORE_NEXT_MINOR_RELEASE", "FIX_BEFORE_NEXT_MAJOR_RELEASE", "FIX_IF_POSSIBLE", "OPTIONAL", NULL }; database BugDB; ref root; ref db; //---- SetMember ------------------------------------------ void SetMember::print(void const*) const {} boolean SetMember::select(void const*) const { return False; } void SetMember::selectTrampoline(ref mbr, void const* arg) { ref obj = mbr->obj; select_args* args = (select_args*)arg; if (obj->select(args->condition)) { args->count += 1; obj->print(args->print_arg); } } void SetMember::printTrampoline(ref mbr, void const* arg) { ref obj = mbr->obj; obj->print(arg); } field_descriptor& SetMember::describe_components() { return NO_FIELDS; } REGISTER(SetMember, object, pessimistic_scheme); //- Person ------------------------------------------------ boolean Person::isUser() const { return True; } void Person::changePassword(char const* password) { sPassword = String::create(password); } void Person::changeEmail(char const* e_mail) { sEmailAddress = String::create(e_mail); } void Person::print(void const* arg) const { WWWconnection& con = *(WWWconnection*)arg; con << TAG << ""; } boolean Person::select(void const* pattern) const { SelectPattern* pat = (SelectPattern*)pattern; return (pat->name == NULL || sName->index(pat->name) != -1) && (pat->eMail == NULL || sEmailAddress->index(pat->eMail) != -1); } void Person::unregister(void const* software) const { setSoftware.erase((char*)software); } void Person::exclude(void const* group) const { setGroups.erase((char*)group); } field_descriptor& Person::describe_components() { return FIELD(sName),FIELD(sEmailAddress),FIELD(sPassword), FIELD(setGroups),FIELD(setReportedBugs),FIELD(setSoftware); } Person::Person(char const* name, char const* eMail, char const* password, class_descriptor& desc) : SetMember(desc) { sName = String::create(name); sEmailAddress = String::create(eMail); sPassword = String::create(password); setReportedBugs.initialize(this); setGroups.initialize(this); setSoftware.initialize(this); } REGISTER(Person, SetMember, pessimistic_scheme); //---- Engineer ------------------------------------ Engineer::Engineer(char const* name, char const* eMail, char const* password) : Person(name, eMail, password, self_class) { setAssignedBugs.initialize(this); } boolean Engineer::isUser() const { return False; } void Engineer::unregister(void const* software) const { Person::unregister(software); } field_descriptor& Engineer::describe_components() { return FIELD(setAssignedBugs); } inline boolean isAdministrator(char const* name) { return strcmp(name, "administrator") == 0; } REGISTER(Engineer, Person, pessimistic_scheme); //----- UserGroup ------------------------------- void UserGroup::print(void const* arg) const { WWWconnection& con = *(WWWconnection*)arg; con << TAG << ""; } boolean UserGroup::select(void const* pattern) const { SelectPattern* pat = (SelectPattern*)pattern; int nBugs = pat->minBugs != 0 || pat->maxBugs != INT_MAX ? setBugs.size() : 0; return (pat->name == NULL || sName->index(pat->name) != -1) && nBugs >= pat->minBugs && nBugs <= pat->maxBugs; } void UserGroup::removeUser(void const* arg) const { setUsers.erase((char*)arg); } void UserGroup::removeBug(void const* arg) const { setBugs.erase((char*)arg); } boolean UserGroup::addUser(char const* group, char const* name, ref person) const { if (setUsers.insertUnique(name, person)) { person->setGroups.insert(group, this); return True; } return False; } void UserGroup::addBug(void const* arg) const { char bugId[16]; ref bug = *(ref*)arg; sprintf(bugId, "%d", bug->bugId); setBugs.insertUnique(bugId, bug); } UserGroup::UserGroup(char const* name) : SetMember(self_class) { sName = String::create(name); setBugs.initialize(this); setUsers.initialize(this); } field_descriptor& UserGroup::describe_components() { return FIELD(sName),FIELD(setUsers),FIELD(setBugs); } REGISTER(UserGroup, SetMember, pessimistic_scheme); //------- Version --------------------------------------- void Version::print(void const* arg) const { WWWconnection& con = *(WWWconnection*)arg; con << TAG << ""; } int Version::getVersion() const { return majorVersionNumber*100 + minorVersionNumber; } char* Version::getVersionString() const { static char buf[16]; sprintf(buf, "%d.%02d", majorVersionNumber, minorVersionNumber); return buf; } boolean Version::select(void const* pattern) const { SelectPattern* pat = (SelectPattern*)pattern; return (pat->label == NULL || sLabel->index(pat->label) != -1) && majorVersionNumber >= pat->minMajorVersionNumber && majorVersionNumber <= pat->maxMajorVersionNumber && minorVersionNumber >= pat->minMinorVersionNumber && minorVersionNumber <= pat->maxMinorVersionNumber; } Version::Version(char const* label, int major,int minor, const char* comment) : SetMember(self_class) { sLabel = String::create(label); majorVersionNumber = major; minorVersionNumber = minor; released.setCurrentDate(); sComment = String::create(comment); } field_descriptor& Version::describe_components() { return FIELD(sLabel),FIELD(majorVersionNumber),FIELD(minorVersionNumber), FIELD(released),FIELD(sComment); } REGISTER(Version, SetMember, pessimistic_scheme); //----- Software ------------------------------------- int Software::getLastVersion() const { if (setVersions.empty()) { return 0; } ref lastVersion = setVersions.members->last->obj; return lastVersion->getVersion(); } char* Software::getLastVersionString() const { if (setVersions.empty()) { return ""; } ref lastVersion = setVersions.members->last->obj; return lastVersion->getVersionString(); } boolean Software::attachEngineer(char const* name, ref engineer) const { if (setEngineers.insertUnique(name, engineer)) { char* software = sName->data(); engineer->setSoftware.insert(software, this); delete[] software; return True; } return False; } boolean Software::detachEngineer(char const* name) const { ref engineer = setEngineers.erase(name); if (engineer != NULL) { char* software = sName->data(); engineer->setSoftware.erase(software); delete[] software; return True; } return False; } void Software::detachEngineerCallback(void const* arg) const { detachEngineer((char*)arg); } boolean Software::registerUser(char const* name, ref user) const { if (setUsers.insertUnique(name, user)) { char* software = sName->data(); user->setSoftware.insert(software, this); delete[] software; return True; } return False; } void Software::unregisterUserCallback(void const* arg) const { unregisterUser((char*)arg); } boolean Software::unregisterUser(char const* name) const { ref user = setUsers.erase(name); if (user != NULL) { char* software = sName->data(); user->setSoftware.erase(software); delete[] software; return True; } return False; } void Software::print(void const* arg) const { WWWconnection& con = *(WWWconnection*)arg; con << TAG << ""; } boolean Software::select(void const* pattern) const { SelectPattern* pat = (SelectPattern*)pattern; int nBugs = pat->minBugs != 0 || pat->maxBugs != INT_MAX ? setBugs.size() : 0; int nUsers = pat->minUsers != 0 || pat->maxUsers != INT_MAX ? setUsers.size() : 0; int nEngineers = pat->minEngineers != 0 || pat->maxEngineers != INT_MAX ? setEngineers.size() : 0; return (pat->name == NULL || sName->index(pat->name) != -1) && nBugs >= pat->minBugs && nBugs <= pat->maxBugs && nUsers >= pat->minUsers && nUsers <= pat->maxUsers && nEngineers >= pat->minEngineers && nEngineers <= pat->maxEngineers; } Software::Software(char const* name, ref version) : SetMember(self_class) { sName = String::create(name); pManager = NULL; setEngineers.initialize(this); setVersions.initialize(this); setUsers.initialize(this); setBugs.initialize(this); setVersions.insert(version->getVersionString(), version); } field_descriptor& Software::describe_components() { return FIELD(sName),FIELD(pManager),FIELD(setEngineers), FIELD(setUsers),FIELD(setVersions),FIELD(setBugs); } REGISTER(Software, SetMember, pessimistic_scheme); //----- Report ------------------------------------------- void Report::print(void const* arg) const { WWWconnection& con = *(WWWconnection*)arg; con << TAG << ""; } void Report::update(char const* description, eSTATUS status) { if (sDescription->compare(description) != 0) { sDescription = String::create(description); } this->status = status; } boolean Report::select(void const* pattern) const { SelectPattern* pat = (SelectPattern*)pattern; return (!pat->author || pAuthor->sName->index(pat->author) != -1) && (!pat->createdBefore.isValid() || creationDate <= pat->createdBefore) && (!pat->createdAfter.isValid() || creationDate >= pat->createdAfter) && (pat->status == STATUS_NOT_SPECIFIED || pat->status == status); } Report::Report(int index, char const* description, ref author, eSTATUS status) : SetMember(self_class) { sDescription = String::create(description); this->index = index; this->status = status; pAuthor = author; creationDate.setCurrentDate(); } field_descriptor& Report::describe_components() { return FIELD(pAuthor),FIELD(creationDate),FIELD(status), FIELD(sDescription),FIELD(index); } REGISTER(Report, SetMember, pessimistic_scheme); //--- Bug ----------------------------------------- void Bug::print(void const* arg) const { WWWconnection& con = *(WWWconnection*)arg; con << TAG << ""; } boolean Bug::select(void const* pattern) const { SelectPattern* pat = (SelectPattern*)pattern; int version = pSoftware->getLastVersion(); int majorVersionNumber = version / 100; int minorVersionNumber = version % 100; return (pat->eCategory == CATEGORY_NOT_SPECIFIED || pat->eCategory == eCategory) && (pat->eFixingPriority == PRIORITY_NOT_SPECIFIED || pat->eFixingPriority == eFixingPriority) && (pat->eSeverity == SEVERITY_NOT_SPECIFIED || pat->eSeverity == eSeverity) && (pat->platform==NULL || sHardwarePlatform->index(pat->platform)!=-1) && (pat->os == NULL || sOperatingSystem->index(pat->os) != -1) && (pat->software==NULL || pSoftware->sName->index(pat->software) != -1)&& (pat->summary==NULL || sOneLineSummary->index(pat->summary) != -1) && (pat->assignedTo == NULL || pAssignedTo->sName->index(pat->assignedTo) != -1) && (pat->reportedBy == NULL || pReportedBy->sName->index(pat->reportedBy) != -1) && majorVersionNumber >= pat->minMajorVersionNumber && majorVersionNumber <= pat->maxMajorVersionNumber && minorVersionNumber >= pat->minMinorVersionNumber && minorVersionNumber <= pat->maxMinorVersionNumber; } void Bug::update(char const* summary, eCATEGORY category, eFIXING_PRIORITY fixingPriority, eSEVERITY severity, char const* os, char const* platform, char const* similarBugId, ref similarBug) { if (sOneLineSummary->compare(summary) != 0) { sOneLineSummary = String::create(summary); } if (sHardwarePlatform->compare(platform) != 0) { sHardwarePlatform = String::create(platform); } if (sOperatingSystem->compare(os) != 0) { sOperatingSystem = String::create(os); } eCategory = category; eFixingPriority = fixingPriority; eSeverity = severity; if (similarBug != NULL) { setSimilarBugs.insertUnique(similarBugId, similarBug); } } Bug::Bug(int4 id, char const* summary, eCATEGORY category, eFIXING_PRIORITY fixingPriority, eSEVERITY severity, char const* os, char const* platform, ref reportedByPerson, ref soft, ref version) : SetMember(self_class) { bugId = id; sOneLineSummary = String::create(summary); eCategory = category; eFixingPriority = fixingPriority; eSeverity = severity; sHardwarePlatform = String::create(platform); sOperatingSystem = String::create(os); pAssignedTo = NULL; pReportedBy = reportedByPerson; pVersion = version; pSoftware = soft; setReportHistory.initialize(this); setWorkArounds.initialize(this); setSimilarBugs.initialize(this); nReports = 0; } field_descriptor& Bug::describe_components() { return FIELD(sOneLineSummary),FIELD(bugId),FIELD(eCategory), FIELD(eFixingPriority),FIELD(eSeverity),FIELD(pReportedBy), FIELD(pAssignedTo), FIELD(sHardwarePlatform),FIELD(sOperatingSystem), FIELD(pSoftware), FIELD(pVersion), FIELD(setReportHistory), FIELD(setWorkArounds), FIELD(setSimilarBugs),FIELD(nReports); } REGISTER(Bug, SetMember, pessimistic_scheme); //---- BugTRACKING ------------------------------------- BugTrackingDB::BugTrackingDB(int vers) : object(self_class) { version = vers; setAllPeople.initialize(this); setAllUserGroups.initialize(this); setAllBugs.initialize(this); setAllSoftware.initialize(this); setAllPeople.insert("administrator", NEW Engineer("administrator","","")); } field_descriptor& BugTrackingDB::describe_components() { return FIELD(version), FIELD(setAllPeople), FIELD(setAllUserGroups), FIELD(setAllBugs), FIELD(setAllSoftware); } REGISTER(BugTrackingDB, object, pessimistic_scheme); //----- RootObject ------------------------------------ void RootObject::initialize() const { if (is_abstract_root()) { ref root = this; modify(root)->become(NEW RootObject(BUG_TRACKING_DB_VERSION)); } } boolean RootObject::addBug(char* bugId, ref bug, ref user) const { if (db->setAllBugs.insertUnique(bugId, bug)) { bug->pSoftware->setBugs.insert(bugId, bug); user->setReportedBugs.insert(bugId, bug); user->setGroups.apply(&UserGroup::addBug, &bug); return True; } return False; } void RootObject::assignBug(char const* bugId, ref bug, ref engineer) const { if (engineer != NULL) { engineer->setAssignedBugs.insertUnique(bugId, bug); } if (bug->pAssignedTo != NULL) { bug->pAssignedTo->setAssignedBugs.erase(bugId); } modify(bug)->pAssignedTo = engineer; } void RootObject::deassignBug(char const* bugId, ref bug, ref engineer) const { engineer->setAssignedBugs.erase(bugId); modify(bug)->pAssignedTo = NULL; } boolean RootObject::removePerson(char const* name) const { ref person = db->setAllPeople.erase(name); if (person == NULL) { return False; } person->setGroups.apply(&UserGroup::removeUser, name); if (!person->isUser()) { ref engineer = person; engineer->setAssignedBugs.apply(&Bug::deassign); engineer->setSoftware.apply(&Software::detachEngineerCallback, name); } else { person->setSoftware.apply(&Software::unregisterUserCallback, name); } return True; } boolean RootObject::removeGroup(char const* group) const { ref pGroup = db->setAllUserGroups.erase(group); if (pGroup == NULL) { return False; } pGroup->setUsers.apply(&Person::exclude, group); return True; } boolean RootObject::removeSoftware(char const* software) const { ref pSoftware = db->setAllSoftware.find(software); if (pSoftware == NULL) { return False; } pSoftware->setEngineers.apply(&Engineer::unregister, software); pSoftware->setUsers.apply(&Person::unregister, software); return True; } boolean RootObject::removeBug(char const* bug) const { ref pBug = db->setAllBugs.erase(bug); if (pBug == NULL) { return False; } pBug->pReportedBy->setReportedBugs.erase(bug); pBug->pReportedBy->setGroups.apply(&UserGroup::removeBug, bug); if (pBug->pAssignedTo != NULL) { pBug->pAssignedTo->setAssignedBugs.erase(bug); } return True; } field_descriptor& RootObject::describe_components() { return FIELD(db),FIELD(nBugs); } REGISTER(RootObject, object, pessimistic_exclusive_scheme); //--- HTML specific part ------------------------------------------- #define HTML_HEAD "Content-type: text/html\n\n\ " #define EMPTY_LIST "" void mainMenuReference(WWWconnection& con) { char* myself = con.get("myself"); if (myself != NULL) { con << TAG << "


Back to main menu
"; } con << TAG << ""; } void error(WWWconnection& con, char const* msg) { con << TAG << HTML_HEAD "BUGDB error" "

" << msg << "

"; mainMenuReference(con); } void message(WWWconnection& con, char const* msg) { con << TAG << HTML_HEAD "BUGDB message" "

" << msg << "

"; mainMenuReference(con); } boolean addUserForm(WWWconnection& con) { con << TAG << HTML_HEAD "Enter new user" "" "

Add user

" "
" "" "" "" "" "" "
User name:
E-mail:

" " " "

"; mainMenuReference(con); return True; } boolean addEngineerForm(WWWconnection& con) { con << TAG << HTML_HEAD "Enter new engineer" "" "

Add engineer

" "
" "" "" "" "" "" "
Engineer name:
E-mail:

" " " "

"; mainMenuReference(con); return True; } boolean addGroupForm(WWWconnection& con) { con << TAG << HTML_HEAD "Enter new user group" "" "

Add user group

" "
" "" "" "" "
Group name:

" " " "

"; mainMenuReference(con); return True; } boolean addSoftwareForm(WWWconnection& con) { con << TAG << HTML_HEAD "Enter new software product" "" "

Add software product

" "
" "" "" "" "" "" "" "" "" "" "" "
Software name:
Version number:
Version label:
Version comment:

 " "

"; mainMenuReference(con); return True; } boolean selectSoftwareForm(WWWconnection& con) { con << TAG << HTML_HEAD "Select software product" "" "

Select software product

" "
" "" "
"; } else { con << TAG << EMPTY_LIST; } con << TAG << "
"; mainMenuReference(con); return True; } boolean removeSoftwareForm(WWWconnection& con) { con << TAG << HTML_HEAD "Remove software product" "" "

Remove software product

" "
" "" "
"; } else { con << TAG << EMPTY_LIST; } con << TAG << "
"; mainMenuReference(con); return True; } boolean selectGroupForm(WWWconnection& con) { con << TAG << HTML_HEAD "Select user group" "" "

Select user group

" "
" "" "
"; } else { con << TAG << EMPTY_LIST; } con << TAG << "
"; mainMenuReference(con); return True; } boolean removeGroupForm(WWWconnection& con) { con << TAG << HTML_HEAD "Remove user group" "" "

Remove user group

" "
" "" "
"; } else { con << TAG << EMPTY_LIST; } con << TAG << "
"; mainMenuReference(con); return True; } boolean selectPersonForm(WWWconnection& con) { con << TAG << HTML_HEAD "Select a person" "" "

Select a person

" "
" "" "
"; } else { con << TAG << EMPTY_LIST; } con << TAG << "
"; mainMenuReference(con); return True; } boolean removePersonForm(WWWconnection& con) { con << TAG << HTML_HEAD "Remove a person" "" "

Remove a person

" "
" "" "
"; } else { con << TAG << EMPTY_LIST; } con << TAG << "
"; mainMenuReference(con); return True; } boolean selectBugForm(WWWconnection& con) { con << TAG << HTML_HEAD "Select a bug" "" "

Select a bug

" "
" "" "
"; } else { con << TAG << EMPTY_LIST; } con << TAG << "
"; mainMenuReference(con); return True; } boolean removeBugForm(WWWconnection& con) { con << TAG << HTML_HEAD "Remove a bug" "" "

Remove a bug

" "
" "" "
"; } else { con << TAG << EMPTY_LIST; } con << TAG << "
"; mainMenuReference(con); return True; } boolean changePasswordForm(WWWconnection& con) { con << TAG << HTML_HEAD "Change password" "" "

Change password

" "
" "" "" "" "" "" "" "
New password:
Re-type password:

" " " "" "

"; con << TAG << ""; mainMenuReference(con); return True; } boolean shutdown(WWWconnection& con) { con << TAG << HTML_HEAD "BUGDB message" "

BUGDB server is terminated

"; return False; } boolean userForm(WWWconnection& con); boolean userGroupForm(WWWconnection& con); boolean softwareForm(WWWconnection& con); boolean addUser(WWWconnection& con) { char* name = con.get("name"); ref person = NEW Person(name, con.get("email"), ""); if (!db->setAllPeople.insertUnique(name, person)) { error(con, "Person already exists"); return True; } return userForm(con); } boolean addEngineer(WWWconnection& con) { char* name = con.get("name"); ref person = NEW Engineer(name, con.get("email"), ""); if (!db->setAllPeople.insertUnique(name, person)) { error(con, "Person already exists"); } return userForm(con); } boolean removePerson(WWWconnection& con) { char* name = con.get("name"); if (name == NULL) { error(con, "No person was selected"); return True; } if (!root->removePerson(name)) { error(con, "No such person"); } else { message(con, "Person is removed"); } return True; } boolean addGroup(WWWconnection& con) { char* group = con.get("group"); if (!db->setAllUserGroups.insertUnique(group, NEW UserGroup(group))) { error(con, "Group already exists"); } else { return userGroupForm(con); } return True; } boolean removeGroup(WWWconnection& con) { char* group = con.get("group"); if (group == NULL) { error(con, "No user group was selected"); return True; } if (!root->removeGroup(group)) { error(con, "No such group"); } else { message(con, "User group is removed"); } return True; } boolean addSoftware(WWWconnection& con) { char* software = con.get("software"); int major, minor; char* versionStr = con.get("version"); if (sscanf(versionStr, "%d.%d", &major, &minor) != 2) { error(con, "Bad version number (MAJOR.MINOR expected)"); return True; } ref version = NEW Version(con.get("label"), major, minor, con.get("comment")); if (db->setAllSoftware.insertUnique(software, NEW Software(software, version))) { con.addPair("action", "Select"); return softwareForm(con); } error(con, "Software product already exists"); return True; } boolean removeSoftware(WWWconnection& con) { if (!root->removeSoftware(con.get("software"))) { error(con, "No such software product"); } else { message(con, "Software product is removed"); } return True; } boolean removeBug(WWWconnection& con) { char* bug = con.get("bug"); if (bug == NULL) { error(con, "No bug was selected"); } else { if (!root->removeBug(bug)) { error(con, "No such bug"); } else { message(con, "Bug is removed"); } } return True; } boolean changePassword(WWWconnection& con) { char* password = con.get("password"); char* password2 = con.get("password2"); if (strcmp(password, password2) != 0) { error(con, "Passwords are not equal"); } else { ref person = db->setAllPeople.find(con.get("name")); if (person == NULL) { error(con, "No such person"); } else { modify(person)->changePassword(password); message(con, "Password changed"); } } return True; } boolean changeEmail(WWWconnection& con) { char* email = con.get("email"); ref person = db->setAllPeople.find(con.get("name")); if (person == NULL) { error(con, "No such person"); return True; } else { if (person->sEmailAddress->compare(email) != 0) { modify(person)->changeEmail(email); } } return userForm(con); } boolean login(WWWconnection& con) { char* name = con.get("name"); ref person = db->setAllPeople.find(name); if (person == NULL) { error(con, "No such person"); return True; } if (!person->checkPassword(con.get("password"))) { error(con, "Incorrect password"); return True; } con.addPair("myself", name); return userForm(con); } boolean bugQueryForm(WWWconnection& con) { int i; con << TAG << HTML_HEAD "Query to locate bug" "" "

Bug query

" "
" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "
Description substring:
Category:
Severity:
Fixing priority:
Platform:
OS
Software:
Assigned to:
Reported by:
Major version number:from " " to
Minor version number:from " " to

" " " "" "

"; return True; } boolean bugQuery(WWWconnection& con) { char* p; Bug::SelectPattern pattern; pattern.eCategory = (eCATEGORY)atoi(con.get("category")); pattern.eSeverity = (eSEVERITY)atoi(con.get("severity")); pattern.eFixingPriority = (eFIXING_PRIORITY)atoi(con.get("priority")); pattern.os = con.get("os"); if (*pattern.os == '\0') pattern.os = NULL; pattern.platform = con.get("platform"); if (*pattern.platform == '\0') pattern.platform = NULL; pattern.software = con.get("software"); if (*pattern.software == '\0') pattern.software = NULL; pattern.assignedTo = con.get("engineer"); if (*pattern.assignedTo == '\0') pattern.assignedTo = NULL; pattern.reportedBy = con.get("user"); if (*pattern.reportedBy == '\0') pattern.reportedBy = NULL; pattern.summary = con.get("summary"); if (*pattern.summary == '\0') pattern.summary = NULL; p = con.get("minmajor"); pattern.minMajorVersionNumber = (*p == '\0') ? 0 : atoi(p); p = con.get("maxmajor"); pattern.maxMajorVersionNumber = (*p == '\0') ? INT_MAX : atoi(p); p = con.get("minminor"); pattern.minMinorVersionNumber = (*p == '\0') ? 0 : atoi(p); p = con.get("maxminor"); pattern.maxMinorVersionNumber = (*p == '\0') ? INT_MAX : atoi(p); con << TAG << HTML_HEAD "List of selected bugs" "" "

Selected bugs

" "
" "" "
"; } else { con << TAG << EMPTY_LIST; } con << TAG << "
"; mainMenuReference(con); return True; } boolean userForm(WWWconnection& con) { char* name = con.get("name"); if (name == NULL) { error(con, "No person was selected"); return True; } char* myself = con.get("myself"); if (strcmp(name, "administrator") == 0) { con << TAG << HTML_HEAD "BUGDB Administrator" "" "

Administrator menu

" "" "" "" "" "" ""; return True; } ref person = db->setAllPeople.find(name); if (person == NULL) { error(con, "No such person"); return True; } con << HTML_HEAD "" << name << "" "

" << name << "

" "" "" ""; if (!person->isUser()) { con << TAG << "" "" "" "" "" ""; } else { con << TAG << "" "" "" ""; } con << TAG << "
E-Mail:
sEmailAddress << "\">" "
User groups:" "
" "" ""; } else { con << TAG << EMPTY_LIST; } con << TAG << "
Join group:" "
" "" "" "" ""; } else { con << TAG << EMPTY_LIST; } con << TAG << "
Projects:
" "" "" "" "" " "; } else { con << TAG << EMPTY_LIST; } con << TAG << "
Attach to project:
" "" "" "" ""; } else { con << TAG << EMPTY_LIST; } con << TAG << "
Find a person:
" "" "" "" "
Registered software:
" "" "" "" "" " "; } else { con << TAG << EMPTY_LIST; } con << TAG << "
Register for new software:
" "" "" "" ""; } else { con << TAG << EMPTY_LIST; } con << TAG << "

Reported bugs:
" "

" "" "" "" "
"; } else { con << TAG << EMPTY_LIST; } con << TAG << "

"; if (!person->isUser()) { con << TAG << "

Assigned bugs:
" "

" "" "" "" "
" " " ""; } else { con << TAG << EMPTY_LIST; } con << TAG << "
"; } if (strcmp(name, myself) == 0) { con << TAG << ""; } else { mainMenuReference(con); } return True; } boolean createBugReportForm(WWWconnection& con) { int i; con << TAG << HTML_HEAD "Bug" "" "

Bug

" "
" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "
Summary:
Category:
Severity:
Priority:
Software:
Version:
Platform:
OS:

" " 

"; mainMenuReference(con); return True; } boolean bugForm(WWWconnection& con); boolean createBugReport(WWWconnection& con) { ref myself = db->setAllPeople.find(con.get("myself")); if (myself == NULL) { error(con, "Author unknown"); return True; } ref soft = db->setAllSoftware.find(con.get("software")); if (soft == NULL) { error(con, "No such software product"); return True; } ref version = soft->setVersions.find(con.get("version")); if (version == NULL) { error(con, "No such software product version"); return True; } char* bugId = con.get("bug"); ref bug = NEW Bug(atoi(bugId), con.get("summary"), (eCATEGORY)atoi(con.get("category")), (eFIXING_PRIORITY)atoi(con.get("priority")), (eSEVERITY)atoi(con.get("severity")), con.get("os"), con.get("platform"), myself, soft, version); root->addBug(bugId, bug, myself); con.addPair("action", "Select"); return bugForm(con); } boolean bugForm(WWWconnection& con) { int i; char* bugId = con.get("bug"); if (bugId == NULL) { error(con, "No bug was selected"); return True; } char* myself = con.get("myself"); if (strcmp(con.get("action"), "Remove") == 0) { ref bug = db->setAllBugs.find(con.get("relatedbug")); if (bug == NULL) { error(con, "No such bug"); return True; } bug->setSimilarBugs.erase(bugId); con.addPair("bug", bugId); return bugForm(con); } ref bug = db->setAllBugs.find(bugId); if (bug == NULL) { error(con, "No such bug"); return True; } ref person = db->setAllPeople.find(myself); if (person == NULL) { error(con, "No such user"); return True; } if (strcmp(con.get("action"), "Remove") == 0) { root->deassignBug(bugId, bug, person); con.addPair("name", myself); return userForm(con); } boolean IamUser = person->isUser(); con << TAG << HTML_HEAD "Bug in " << bug->pSoftware->sName << " v. " << bug->pVersion->getVersionString() << "" "" "

Bug in " << bug->pSoftware->sName << " v. " << bug->pVersion->getVersionString() << "

" "
" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "
Summary:sOneLineSummary << "\">
Category:
Severity:
Priority:
Platform:sHardwarePlatform << "\">
OS:sOperatingSystem << "\">
Assigned to:
Similar with:

"; if (!IamUser) { con << TAG << " " ""; } con << TAG << "

" "" "" "" "Report history:

" " "; if (isAdministrator(myself)) { con << TAG << " "; } } else { con << TAG << EMPTY_LIST "
"; } con << TAG << "

"; con << TAG << "

" "" "" "" "Work arounds:

" " "; if (isAdministrator(myself)) { con << TAG << " "; } } else { con << TAG << EMPTY_LIST "
"; } con << TAG << "

"; if (bug->setSimilarBugs.size() != 0) { con << TAG << "

" "" "" "" "Similar bugs:
"; if (isAdministrator(myself)) { con << TAG << " "; } con << TAG << "

"; } con << TAG << "

" "

    "; if (IamUser) { if (bug->pAssignedTo != NULL) { con << TAG << "
  • Assigned to pAssignedTo->sEmailAddress << "\">" << bug->pAssignedTo->sName << ""; } con << TAG << "
  • Reported by pReportedBy->sEmailAddress << "\">" << bug->pReportedBy->sName << ""; } else { if (bug->pAssignedTo != NULL) { con << TAG << "
  • Assigned to " << bug->pAssignedTo->sName << ""; } con << TAG << "
  • Reported by " << bug->pReportedBy->sName << ""; } mainMenuReference(con); return True; } boolean updateBug(WWWconnection& con) { char* bugId = con.get("bug"); ref bug = db->setAllBugs.find(bugId); if (bug == NULL) { error(con, "No such bug"); return True; } char* similar = con.get("similar"); ref similarBug; if (*similar != '\0') { similarBug = db->setAllBugs.find(similar); } char* name = con.get("name"); if ((bug->pAssignedTo == NULL && *name != 0) || (bug->pAssignedTo != NULL && bug->pAssignedTo->sName->compare(name) != 0)) { ref engineer = NULL; if (*name != '\0') { engineer = db->setAllPeople.find(name); if (engineer == NULL || engineer->isUser()) { error(con, "No such engineer"); return True; } } root->assignBug(bugId, bug, engineer); } modify(bug)->update(con.get("summary"), (eCATEGORY)atoi(con.get("category")), (eFIXING_PRIORITY)atoi(con.get("priority")), (eSEVERITY)atoi(con.get("severity")), con.get("os"), con.get("platform"), similar, similarBug); return bugForm(con); } boolean addReportForm(WWWconnection& con) { char* bugId = con.get("bug"); ref bug = db->setAllBugs.find(bugId); if (bug == NULL) { error(con, "No such bug"); return True; } con << TAG << HTML_HEAD "Bug report" "" "

    Bug report

    " "
    " "" "" "Status:  

    " "Bug description:

    " "

    " " " "

    "; mainMenuReference(con); return True; } boolean addReport(WWWconnection& con) { ref bug = db->setAllBugs.find(con.get("bug")); if (bug == NULL) { error(con, "No such bug"); return True; } ref author = db->setAllPeople.find(con.get("myself")); char* index = con.get("index"); ref report = NEW Report(atoi(index), con.get("description"), author, (eSTATUS)atoi(con.get("status"))); bug->setReportHistory.insertUnique(index, report); con.addPair("action", "Select"); return bugForm(con); } boolean addWorkAroundForm(WWWconnection& con) { char* bugId = con.get("bug"); ref bug = db->setAllBugs.find(bugId); if (bug == NULL) { error(con, "No such bug"); return True; } con << TAG << HTML_HEAD "Work around" "" "

    Work around

    " "
    " "" "" "Status:  

    " "Description:

    " "

    " " " "

    "; mainMenuReference(con); return True; } boolean addWorkAround(WWWconnection& con) { ref bug = db->setAllBugs.find(con.get("bug")); if (bug == NULL) { error(con, "No such bug"); return True; } ref author = db->setAllPeople.find(con.get("myself")); char* index = con.get("index"); ref report = NEW Report(atoi(index), con.get("description"), author, (eSTATUS)atoi(con.get("status"))); bug->setWorkArounds.insertUnique(index, report); con.addPair("action", "Select"); return bugForm(con); } boolean updateReportForm(WWWconnection& con) { if (strcmp(con.get("action"), "Add") == 0) { return addReportForm(con); } char* bugId = con.get("bug"); ref bug = db->setAllBugs.find(bugId); if (bug == NULL) { error(con, "No such bug"); return True; } char* report = con.get("report"); if (report == NULL) { error(con, "No report was selected"); return True; } if (strcmp(con.get("action"), "Remove") == 0) { if (bug->setReportHistory.erase(report) == NULL) { error(con, "No such report"); return True; } con.addPair("action", "Select"); return bugForm(con); } ref pReport = bug->setReportHistory.find(report); if (pReport == NULL) { error(con, "No such report"); return True; } char* date = pReport->creationDate.asString(); char* myself = con.get("myself"); ref person = db->setAllPeople.find(myself); if (person == NULL) { error(con, "No such person"); return True; } con << TAG << HTML_HEAD "Bug report from " << date << "" "" "

    Bug report from " << date << "

    " "
    " "" "" "" "Created by " << pReport->pAuthor->sName << "

    " "Status:

    " "Bug description:
    " "

    "; if (!person->isUser()) { con << TAG << " " ""; } con << TAG << "

    "; mainMenuReference(con); return True; } boolean updateWorkAroundForm(WWWconnection& con) { if (strcmp(con.get("action"), "Add") == 0) { return addWorkAroundForm(con); } char* bugId = con.get("bug"); ref bug = db->setAllBugs.find(bugId); if (bug == NULL) { error(con, "No such bug"); return True; } char* workaround = con.get("workaround"); if (workaround == NULL) { error(con, "No report was selected"); return True; } if (strcmp(con.get("action"), "Remove") == 0) { if (bug->setWorkArounds.erase(workaround) == NULL) { error(con, "No such work around"); return True; } con.addPair("action", "Select"); return bugForm(con); } ref report = bug->setWorkArounds.find(workaround); if (report == NULL) { error(con, "No such work around"); return True; } char* date = report->creationDate.asString(); char* myself = con.get("myself"); ref person = db->setAllPeople.find(myself); if (person == NULL) { error(con, "No such person"); return True; } con << TAG << HTML_HEAD "Work around " << date << "" "" "

    Work around " << date << "

    " "
    " "" "" "Created by " << report->pAuthor->sName << "

    " "Status:

    " "Bug description:
    " "

    "; if (!person->isUser()) { con << TAG << " " ""; } con << TAG << "

    "; mainMenuReference(con); return True; } boolean updateReport(WWWconnection& con) { ref bug = db->setAllBugs.find(con.get("bug")); if (bug == NULL) { error(con, "No such bug"); return True; } ref report = bug->setReportHistory.find(con.get("report")); if (report == NULL) { error(con, "No such report"); return True; } modify(report)->update(con.get("description"), (eSTATUS)atoi(con.get("status"))); con.addPair("action", "Select"); return bugForm(con); } boolean updateWorkAround(WWWconnection& con) { ref bug = db->setAllBugs.find(con.get("bug")); if (bug == NULL) { error(con, "No such bug"); return True; } ref report = bug->setWorkArounds.find(con.get("workaround")); if (report == NULL) { error(con, "No such workaround"); return True; } modify(report)->update(con.get("description"), (eSTATUS)atoi(con.get("status"))); con.addPair("action", "Select"); return bugForm(con); } boolean attachToProject(WWWconnection& con) { char* name = con.get("name"); ref person = db->setAllPeople.find(name); if (person == NULL || person->isUser()) { error(con, "No such engineer"); } else { ref soft = db->setAllSoftware.find(con.get("software")); if (soft == NULL) { error(con, "No such software product"); } else { if (!soft->attachEngineer(name, person)) { error(con, "Engineer already attached to the project"); } else { return userForm(con); } } } return True; } boolean registerSoftware(WWWconnection& con) { char* name = con.get("name"); ref person = db->setAllPeople.find(name); if (person == NULL) { error(con, "No such person"); } else { ref soft = db->setAllSoftware.find(con.get("software")); if (soft == NULL) { error(con, "No such software product"); } else { if (!soft->registerUser(name, person)) { error(con, "User already registered"); } else { return userForm(con); } } } return True; } boolean joinGroup(WWWconnection& con) { char* groupName = con.get("group"); ref group = db->setAllUserGroups.find(groupName); if (group == NULL) { error(con, "No such group"); } else { char* name = con.get("name"); ref person = db->setAllPeople.find(name); if (person == NULL) { error(con, "No such person"); } else { if (!group->addUser(groupName, name, person)) { error(con, "Person is already in group"); } else { return userForm(con); } } } return True; } boolean findPerson(WWWconnection& con) { ref person = db->setAllPeople.find(con.get("name")); if (person == NULL) { error(con, "No such person"); return True; } return userForm(con); } boolean softwareForm(WWWconnection& con) { char* software = con.get("software"); if (software == NULL) { error(con, "No software product was selected"); return True; } ref soft = db->setAllSoftware.find(software); if (soft == NULL) { error(con, "No such software product"); return True; } if (strcmp(con.get("action"), "Detach") == 0) { if (!soft->detachEngineer(con.get("name"))) { error(con, "No such person"); return True; } return userForm(con); } if (strcmp(con.get("action"), "Unregister") == 0) { if (!soft->unregisterUser(con.get("name"))) { error(con, "No such person"); return True; } return userForm(con); } char* myself = con.get("myself"); ref person = db->setAllPeople.find(myself); if (person == NULL) { error(con, "No such person"); return True; } boolean IamUser = person->isUser(); con << TAG << HTML_HEAD "" << software << "" "" "

    " << software << "

    " "
    " "" "" "" ""; if (!soft->setVersions.empty()) { ref lastVersion = soft->setVersions.members->last->obj; con << TAG << "" "" "" "" "" ""; } else { con << TAG << "" "" "" "" "" ""; } con << TAG << "
    Manager: manager = soft->pManager; if (manager != NULL) { con << manager; } con << TAG << "\">
    Current version:getVersionString() << "\">
    Current version label:sLabel << "\">
    Current version comment:sComment << "\">
    Current version:
    Current version label:
    Current version comment:

    "; if (!IamUser) { con << TAG << " "; } con << TAG << "

    " "" "" "" "" "" "" "
    Engineers:
    " "" ""; if (!IamUser) { con << TAG << ""; } } else { con << TAG << EMPTY_LIST; } con << TAG << "
    Users:
    " "" ""; if (!IamUser) { con << TAG << ""; } } else { con << TAG << EMPTY_LIST; } con << TAG << "
    Bugs:
    " "" ""; } else { con << TAG << EMPTY_LIST; } con << TAG << "
    Versions:" "
    " "" ""; } else { con << TAG << EMPTY_LIST; } con << TAG << "
    "; mainMenuReference(con); return True; } boolean updateSoftware(WWWconnection& con) { ref soft = db->setAllSoftware.find(con.get("software")); if (soft == NULL) { error(con, "No such software product"); return True; } char* manager = con.get("manager"); if (soft->pManager == NULL || soft->pManager->sName->compare(manager)!=0) { if (*manager != '\0') { ref person = db->setAllPeople.find(manager); if (person == NULL) { error(con, "No such person"); return True; } modify(soft)->pManager = person; } else if (soft->pManager != NULL) { modify(soft)->pManager = NULL; } } char* lastVersion = soft->getLastVersionString(); char* currentVersion = con.get("version"); char* label = con.get("label"); char* comment = con.get("comment"); if (strcmp(lastVersion, currentVersion) != 0) { int major, minor; if (sscanf(currentVersion, "%d.%d", &major, &minor) != 2) { error(con, "Bad version number (MAJOR.MINOR expected)"); return True; } if (!soft->setVersions.insertUnique(currentVersion, NEW Version(label, major, minor, comment))) { error(con, "Version already exist"); return True; } } else if (*currentVersion != '\0') { ref pLastVersion = soft->setVersions.members->last->obj; if (pLastVersion->sComment->compare(comment) != 0) { modify(pLastVersion)->sComment = String::create(comment); } if (pLastVersion->sLabel->compare(label) != 0) { modify(pLastVersion)->sLabel = String::create(label); } } con.addPair("name", con.get("myself")); return userForm(con); } boolean userGroupForm(WWWconnection& con) { char* groupName = con.get("group"); if (groupName == NULL) { error(con, "No user group was selected"); return True; } ref group = db->setAllUserGroups.find(groupName); if (group == NULL) { error(con, "No such user group"); return True; } char* myself = con.get("myself"); ref person = db->setAllPeople.find(myself); if (person == NULL) { error(con, "No such person"); return True; } con << TAG << HTML_HEAD "User group " << groupName << "" "" "

    User group " << groupName << "

    " "Users:
    " "
    " "" ""; if (!person->isUser()) { con << TAG << "
    "; } } else { con << TAG << EMPTY_LIST; } con << TAG << "

    Bugs:
    " "

    " "" "
    "; } else { con << TAG << EMPTY_LIST; } con << TAG << "
    "; mainMenuReference(con); return True; } boolean versionForm(WWWconnection& con) { char* software = con.get("software"); char* myself = con.get("myself"); ref soft = db->setAllSoftware.find(software); if (soft == NULL) { error(con, "No such software product"); return True; } char* versionString = con.get("version"); ref version = soft->setVersions.find(versionString); if (version == NULL) { error(con, "No such version"); return True; } ref person = db->setAllPeople.find(myself); if (person == NULL) { error(con, "No such person"); return True; } con << TAG << HTML_HEAD "" << software << " v. " << versionString << "" "" "

    " << software << " v. " << versionString << "

    " "
    " "" "" "" "" "" "" "" "" "" ""; if (!person->isUser()) { con << TAG << "
    Released:" << version->released.asString() << "
    Label:sLabel << "\">
    Comment:sComment << "\">

    "; if (isAdministrator(myself)) { con << TAG << " "; } con << TAG << " "; } con << TAG << "

    "; mainMenuReference(con); return True; } boolean updateVersion(WWWconnection& con) { char* software = con.get("software"); ref soft = db->setAllSoftware.find(software); if (soft == NULL) { error(con, "No such software product"); return True; } if (strcmp(con.get("action"), "Remove") == 0) { if (soft->setVersions.erase(con.get("version")) == NULL) { error(con, "No such version"); return True; } con.addPair("action", "Select"); return softwareForm(con); } ref version = soft->setVersions.find(con.get("version")); if (version == NULL) { error(con, "No such version"); return True; } char* comment = con.get("comment"); char* label = con.get("label"); if (version->sComment->compare(comment) != 0) { modify(version)->sComment = String::create(comment); } if (version->sLabel->compare(label) != 0) { modify(version)->sLabel = String::create(label); } return versionForm(con); } WWWapi::dispatcher dispatchTable[] = { {"addUserForm", addUserForm}, {"addEngineerForm", addEngineerForm}, {"addGroupForm", addGroupForm}, {"addSoftwareForm", addSoftwareForm}, {"selectSoftwareForm", selectSoftwareForm}, {"removeSoftwareForm", removeSoftwareForm}, {"selectGroupForm", selectGroupForm}, {"removeGroupForm", removeGroupForm}, {"selectPersonForm", selectPersonForm}, {"removePersonForm", removePersonForm}, {"selectBugForm", selectBugForm}, {"removeBugForm", removeBugForm}, {"changePasswordForm", changePasswordForm}, {"shutdown", shutdown}, {"userForm", userForm}, {"userGroupForm", userGroupForm}, {"softwareForm", softwareForm}, {"addUser", addUser}, {"addEngineer", addEngineer}, {"removePerson", removePerson}, {"addGroup", addGroup}, {"removeGroup", removeGroup}, {"addSoftware", addSoftware}, {"removeSoftware", removeSoftware}, {"removeBug", removeBug}, {"changePassword", changePassword}, {"changeEmail", changeEmail}, {"login", login}, {"bugQueryForm", bugQueryForm}, {"bugQuery", bugQuery}, {"userForm", userForm}, {"createBugReportForm", createBugReportForm}, {"bugForm", bugForm}, {"createBugReport", createBugReport}, {"bugForm", bugForm}, {"updateBug", updateBug}, {"updateReportForm", updateReportForm}, {"updateWorkAroundForm", updateWorkAroundForm}, {"addReportForm", addReportForm}, {"addReport", addReport}, {"addWorkAroundForm", addWorkAroundForm}, {"addWorkAround", addWorkAround}, {"updateReport", updateReport}, {"updateWorkAround", updateWorkAround}, {"attachToProject", attachToProject}, {"registerSoftware", registerSoftware}, {"joinGroup", joinGroup}, {"findPerson", findPerson}, {"softwareForm", softwareForm}, {"updateSoftware", updateSoftware}, {"userGroupForm", userGroupForm}, {"versionForm", versionForm}, {"updateVersion", updateVersion} }; #ifdef USE_EXTERNAL_HTTP_SERVER CGIapi wwwServer(itemsof(dispatchTable), dispatchTable); char* defaultAddress = "localhost:6101"; socket_t::socket_domain domain = socket_t::sock_local_domain; #else #ifdef USE_QUEUE_MANAGER HTTPapi wwwServer(itemsof(dispatchTable), dispatchTable, true); #else HTTPapi wwwServer(itemsof(dispatchTable), dispatchTable, false); #endif char* defaultAddress = "localhost:80"; socket_t::socket_domain domain = socket_t::sock_global_domain; #endif int main(int argc, char* argv[]) { task::initialize(task::huge_stack); char* address = (argc > 1) ? argv[1] : defaultAddress; if (!wwwServer.open(address, domain)) { console::output("Failed to open WWW session\n"); return EXIT_FAILURE; } if (!BugDB.open("bugdb.cfg")) { console::output("Failed to open database\n"); return EXIT_FAILURE; } WWWconnection con; BugDB.get_root(root); root->initialize(); db = root->db; #ifdef USE_QUEUE_MANAGER QueueManager mgr(wwwServer); #else while (wwwServer.connect(con) && wwwServer.serve(con)); #endif BugDB.close(); console::output("End of session\n"); return EXIT_SUCCESS; }