96ef6308daf70039a985f3d63e483cb2e170627b
chinhli
  Mon Jun 3 17:17:01 2013 -0700
Feature 9142 suggestion form code checkin for preview1
diff --git src/hg/hgUserSuggestion/hgUserSuggestion.c src/hg/hgUserSuggestion/hgUserSuggestion.c
new file mode 100644
index 0000000..91ae3bc
--- /dev/null
+++ src/hg/hgUserSuggestion/hgUserSuggestion.c
@@ -0,0 +1,406 @@
+/* hgUserSuggestion - CGI-script to collect user's suggestion. */
+
+#include "common.h"
+#include "errabort.h"
+#include "hCommon.h"
+#include "jksql.h"
+#include "portable.h"
+#include "cheapcgi.h"
+#include "htmshell.h"
+#include "hdb.h"
+#include "hui.h"
+#include "cart.h"
+#include "hPrint.h"
+#include "dbDb.h"
+#include "web.h"
+#include "hash.h"
+#include "hgConfig.h"
+#include "hgUserSuggestion.h"
+#include "mailViaPipe.h"
+
+/* ---- Global variables. ---- */
+struct cart *cart;	/* The user's ui state. */
+struct hash *oldVars = NULL;
+
+/* ---- Global helper functions ---- */
+char *mailToAddr()
+/* Return the address to send suggestion to  */
+{
+if isEmpty(cfgOption(CFG_SUGGEST_MAILTOADDR))
+    return cloneString("NULL_suggest.mailToAddr");
+else
+    return cloneString(cfgOption(CFG_SUGGEST_MAILTOADDR));
+}
+
+char *mailFromAddr()
+/* Return the bogus sender address to help filter out spam */
+{
+if isEmpty(cfgOption(CFG_SUGGEST_MAILFROMADDR))
+    return cloneString("NULL_suggest.mailFromAddr");
+else
+    return cloneString(cfgOption(CFG_SUGGEST_MAILFROMADDR));
+}
+
+char *filterKeyword()
+/* Return the keyword used to filter out spam  */
+{
+if isEmpty(cfgOption(CFG_FILTERKEYWORD))
+    return cloneString("NULL_suggest.filterKeyword");
+else
+    return cloneString(cfgOption(CFG_FILTERKEYWORD));
+}
+
+char *mailSignature()
+/* Return the signature to be used by outbound mail or NULL. Allocd
+ * here. */
+{
+if isEmpty(cfgOption(CFG_SUGGEST_MAIL_SIGNATURE))
+    return cloneString("NULL_mailSignature");
+else
+    return cloneString(cfgOption(CFG_SUGGEST_MAIL_SIGNATURE));
+}
+
+char *mailReturnAddr()
+/* Return the return addr. to be used by outbound mail or NULL. Allocd
+ * here. */
+{
+if isEmpty(cfgOption(CFG_SUGGEST_MAIL_RETURN_ADDR))
+    return cloneString("NULL_mailReturnAddr");
+else
+    return cloneString(cfgOption(CFG_SUGGEST_MAIL_RETURN_ADDR));
+}
+
+char *browserName()
+/* Return the browser name like 'UCSC Genome Browser' */
+{
+if isEmpty(cfgOption(CFG_SUGGEST_BROWSER_NAME))
+    return cloneString("NULL_browserName");
+else
+    return cloneString(cfgOption(CFG_SUGGEST_BROWSER_NAME));
+}
+
+static char *now()
+/* Return a mysql-formatted time like "2008-05-19 15:33:34". */
+{
+char nowBuf[256];
+time_t curtime;
+curtime = time (NULL); 
+struct tm *theTime = localtime(&curtime);
+strftime(nowBuf, sizeof nowBuf, "%Y-%m-%d %H:%M:%S", theTime);
+return cloneString(nowBuf);
+}
+
+void resetAllSuggFields()
+/* clear all suggestion fields */
+{
+cartRemove(cart, "suggestCfmEmail");
+cartRemove(cart, "suggestDetails");
+cartRemove(cart, "suggestEmail");
+cartRemove(cart, "suggestName");
+cartRemove(cart, "suggestSubject");
+cartRemove(cart, "suggestSummary");
+}
+
+/* javascript functions */
+void printMainForm()
+/* javascript to print mainForm */
+{
+hPrintf(
+    "     <FORM ACTION=\"../cgi-bin/hgUserSuggestion?do.suggestSendMail=1\" METHOD=\"POST\" ENCTYPE=\"multipart/form-data\" NAME=\"mainForm\" onLoad=\"document.forms.mainForm.name.focus()\">\n");
+hPrintf(
+    "     <H2>User Suggestion Form</H2>\n"
+    "     <P> Please use this form to submit ... </P>\n"
+);
+hPrintf(
+    "      <div id=\"suggest\">  \n"
+    "       <label for=\"name\">Your Name:</label><input type=\"text\" name=\"suggestName\" id=\"name\" size=\"50\" /><BR>\n"
+    "       <label for=\"email\">Your Email:</label><input type=\"text\" name=\"suggestEmail\" id=\"email\" size=\"50\" /><BR>   \n"
+    "       <label for=\"confirmEmail\">Re-enter Your Email:</label><input type=\"text\" \n"
+    "          name=\"suggestCfmEmail\" id=\"cfmemail\" size=\"50\" /><BR>   \n");
+hPrintf(
+    "       <label for=\"category\">Category:</label><select name=\"suggestCategory\" id=\"category\">\n"
+    "         <option selected>New feature request</option> \n"
+    "         <option>New utilities request</option>\n"
+    "         <option>New/Update genome request</option>\n"
+    "         <option>New track request</option>\n"
+    "         <option>Others</option>\n"
+    "         </select><BR>\n");
+hPrintf(
+    "       <label for=\"summary\">Summary:</label><input type=\"text\" name=\"suggestSummary\" id=\"summary\" size=\"50\" /><BR>\n"
+    "       <label for=\"details\">Details:</label><BR><textarea name=\"suggestDetails\" id=\"details\" cols=\"100\" rows=\"10\"></textarea><BR>  \n"
+    "     </div>\n");
+hPrintf(
+    "         <p>\n"
+    "           <label for=\"code\">Write CAPTCHA security code below (disabled) > <span id=\"txtCaptchaDiv\" style=\"color:#F00\"></span><BR><!-- this is where the script will place the generated code --> \n"
+    "           <input type=\"hidden\" id=\"txtCaptcha\" /></label><!-- this is where the script will place a copy of the code for validation: this is a hidden field -->\n"
+    "           <input type=\"text\" name=\"txtInput\" id=\"txtInput\" size=\"30\" />\n"
+    "         </p>\n");
+hPrintf(
+    "      <div class=\"formControls\">\n"
+    "        <input id=\"sendButton\" type=\"button\" value=\"Send\" onclick=\"submitform()\"/> \n"
+    "        <input type=\"reset\" name=\"suggestClear\" value=\"Clear\" class=\"largeButton\"> \n"
+    "        <input type=\"cancel\" name=\"Cancel\" value=\"Cancel\" class=\"largeButton\">\n"
+    "      </div>\n"
+    "      \n"
+    "     </FORM>\n\n");
+}
+void printValidateScript()
+/* javascript to validate form inputs */
+{
+hPrintf(  
+    "    <script type=\"text/javascript\">\n"
+    "    function validateMainForm(theform)\n"
+    "    {\n"
+    "    var x=theform.suggestName.value;\n"
+    "    if (x==null || x==\"\")\n"
+    "      {\n"
+    "      alert(\"Name field must be filled out\");\n"
+    "      theform.suggestName.focus() ;\n"
+    "      return false;\n"
+    "      }\n");
+hPrintf(
+    "    if (!validateMailAddr(theform.suggestEmail.value))\n"
+    "      {\n"
+    "      alert(\"Not a valid e-mail address\");\n"
+    "      theform.suggestEmail.focus() ;\n"
+    "      return false;\n"
+    "      }\n"
+    "    var str1 = theform.suggestEmail.value;\n"
+    "    var str2 = theform.suggestCfmEmail.value;\n"
+    "    if (str2==null || str2==\"\")\n"
+    "      {\n"
+    "      alert(\"Please re-enter your email address.\");\n"
+    "      theform.suggestCfmEmail.focus();\n"
+    "      return false;\n"
+    "      }\n"
+    "    if (str1 != str2)\n"
+    "      {\n"
+    "      alert(\"Email addresses do not match, please re-enter.\");\n"
+    "      theform.suggestCfmEmail.focus();\n"
+    "      return false;\n"
+    "      }\n");
+hPrintf(
+    "    var y=theform.suggestSummary.value;\n"
+    "    if (y==null || y==\"\")\n"
+    "      {\n"
+    "      alert(\"Summary field must be filled out\");\n"
+    "      theform.suggestSummary.focus() ;\n"
+    "      return false;\n"
+    "      }          \n"
+    "    var z=theform.suggestDetails.value;\n"
+    "    if (z==null || z==\"\")\n"
+    "      {\n"
+    "      alert(\"Details field must be filled out\");\n"
+    "      theform.suggestDetails.focus() ;\n"
+    "      return false;\n"
+    "      }\n"
+    "    return true; \n"
+    "    }\n\n");
+hPrintf(
+    "    function validateMailAddr(x)\n"
+    "    {\n"
+    "    var atpos=x.indexOf(\"@\");\n"
+    "    var dotpos=x.lastIndexOf(\".\");\n"
+    "    if (atpos<1 || dotpos<atpos+2 || dotpos+2>=x.length)\n"
+    "      {\n"
+    "      return false;\n"
+    "      } \n"
+    "    return true;\n"
+    "    }\n"
+    "    </script><br />\n\n");
+}
+
+void printCheckCaptchaScript()
+/* javascript to check CAPTCHA code */
+{
+hPrintf( 
+    " <script type=\"text/javascript\">\n"
+    "         function checkCaptcha(theform){\n"
+    "                 var why = \"\";\n"
+    "                  \n"
+    "                 if(theform.txtInput.value == \"\"){\n"
+    "                         why += \"- Security code should not be empty.\n\";\n"
+    "                 }\n"
+    "                 if(theform.txtInput.value != \"\"){\n"
+    "                         if(ValidCaptcha(theform.txtInput.value) == false){\n"
+    "                                 why += \"- Security code did not match.\n\";\n"
+    "                         }\n"
+    "                 }\n"
+    "                 if(why != \"\"){\n"
+    "                         alert(why);\n"
+    "                         theform.txtInput.focus() ;\n"
+    "                         return false;\n"
+    "                 }\n"
+    "            return true;\n"
+    "         }\n\n");
+hPrintf(
+    "         var a = Math.ceil(Math.random() * 9)+ '';\n"
+    "         var b = Math.ceil(Math.random() * 9)+ '';\n"
+    "         var c = Math.ceil(Math.random() * 9)+ '';\n"
+    "         var d = Math.ceil(Math.random() * 9)+ '';\n"
+    "         var e = Math.ceil(Math.random() * 9)+ '';\n\n"
+    "         var code = a + b + c + d + e;\n"
+    "         document.getElementById(\"txtCaptcha\").value = code;\n"
+    "         document.getElementById(\"txtCaptchaDiv\").innerHTML = code;\n\n");
+hPrintf(
+    " function ValidCaptcha(){\n"
+    "         var str1 = removeSpaces(document.getElementById('txtCaptcha').value);\n"
+    "         var str2 = removeSpaces(document.getElementById('txtInput').value);\n"
+    "         if (str1 == str2){\n"
+    "                 return true;\n"
+    "         } else {\n"
+    "                 return false;\n"
+    "         }\n"
+    " }\n\n");
+hPrintf(
+    " function removeSpaces(string){\n"
+    "         return string.split(' ').join('');\n"
+    " }\n"
+    " </script><br />\n\n");
+}
+
+void printSubmitFormScript()
+/* javascript to submit form */
+{
+hPrintf(
+    "     <script type=\"text/javascript\">\n"
+    "     function submitform()\n"
+    "     {\n"
+    "      if ( validateMainForm(document.forms[\"mainForm\"]) )\n"
+//    "      if ( validateMainForm(document.forms[\"mainForm\"]) && checkCaptcha(document.forms[\"mainForm\"]))\n"
+    "        {\n"
+    "          document.forms[\"mainForm\"].submit();\n"
+    "        }\n"
+    "     }\n"
+    "     </script>\n\n");
+}
+
+void printSuggestionConfirmed()
+{
+hPrintf(
+    "<h2>Thank you for your suggestion!</h2>");
+hPrintf(
+    "<p>"
+    "Thank you for your suggestion regarding the UCSC Genome Browser.<BR>"
+    "A confirmation mail has send to you containing an unique suggestion ID,<BR>"
+"Please use this ID for all future communications related to this suggestion.</p><BR>");
+hPrintf(
+    "<p><a href=\"hgUserSuggestion\">Click here for more suggestions</a><BR></p>");
+
+} 
+
+void sendSuggestionBack(char *sName, char *sEmail, char *sCategory, char *sSummary, char *sDetails, char *suggestID)
+/* send back the suggestion */
+{
+/* parameters from hg.cong */
+char *mailTo = mailToAddr();
+char *mailFrom=mailFromAddr();
+char *filter=filterKeyword();
+char subject[256];
+char msg[4096]; /* need to make larger */
+safef(msg, sizeof(msg),
+    "SuggestionID:: %s\nUserName:: %s\nUserEmail:: %s\nCategory:: %s\nSummary:: %s\n\n\nDetails::\n%s",
+    suggestID, sName, sEmail, sCategory, sSummary, sDetails);
+
+safef(subject, sizeof(subject),"%s %s", filter, suggestID);   
+int result;
+result = mailViaPipe(mailTo, subject, msg, mailFrom);
+}
+
+void sendConfirmMail(char *emailAddr, char *suggestID)
+/* send user suggestion confirm mail */
+{
+char subject[256];
+char msg[4096];
+char *remoteAddr=getenv("REMOTE_ADDR");
+char brwName[256];
+char returnAddr[256];
+char signature[256];
+safecpy(brwName,sizeof(brwName), browserName());
+safecpy(returnAddr,sizeof(returnAddr), mailReturnAddr());
+safecpy(signature,sizeof(signature), mailSignature());
+
+safef(subject, sizeof(subject),"Thank you for your suggestion to the %s", brwName);
+safef(msg, sizeof(msg),
+    "  Someone (probably you, from IP address %s) submitted a suggestion to the %s.\nThe suggestion has been assigned an ID \"%s\".\nPlease use this ID for all future communications related to ths suggestion.\n\nThanks!\n%s\n%s",
+remoteAddr, brwName, suggestID, signature, returnAddr);
+int result;
+result = mailViaPipe(emailAddr, subject, msg, returnAddr);
+}
+
+void askForSuggest(char *organism, char *db)
+/* Put up the suggestion form. */
+{
+printMainForm();
+printValidateScript();
+printCheckCaptchaScript();
+printSubmitFormScript();
+//cartSaveSession(cart);
+}
+
+void  submitSuggestion()
+/* send the suggestion to ,.. */
+{
+/* parameters from hg.cong */
+char *filter=filterKeyword();
+
+/* values from cart */
+char *sName=cartUsualString(cart,"suggestName","");
+char *sEmail=cartUsualString(cart,"suggestEmail","");
+char *sCategory=cartUsualString(cart,"suggestCategory","");
+char *sSummary=cartUsualString(cart,"suggestSummary","");
+char *sDetails=cartUsualString(cart,"suggestDetails","");
+
+char suggestID[256];
+safef(suggestID, sizeof(suggestID),"%s-%s", sEmail, now());
+char subject[256];
+safef(subject, sizeof(subject),"%s %s", filter, suggestID);
+/* send back the suggestion */
+sendSuggestionBack(sName, sEmail, sCategory, sSummary, sDetails, suggestID);
+/* send confirmation mail to user */
+sendConfirmMail(sEmail,suggestID);
+/* display confirmation page */
+printSuggestionConfirmed();
+cartRemove(cart, "do.suggestSendMail");
+}
+
+void doMiddle(struct cart *theCart)
+/* Write header and body of html page. */
+{
+char *db, *organism;
+
+cart = theCart;
+getDbAndGenome(cart, &db, &organism, oldVars);
+
+    cartWebStart(theCart, db, "User Suggestion");
+
+if (cartVarExists(cart, "do.suggestSendMail"))
+{
+    submitSuggestion();
+    cartRemove(cart, "do.suggestSendMail");
+    return;
+}
+
+    askForSuggest(organism,db);
+    cartWebEnd();
+}
+
+/* Null terminated list of CGI Variables we don't want to save
+ * permanently. */
+char *excludeVars[] = {"Submit", "submit", "Clear", NULL};
+
+int main(int argc, char *argv[])
+/* Process command line. */
+{
+long enteredMainTime = clock1000();
+oldVars = hashNew(10);
+cgiSpoof(&argc, argv);
+
+htmlSetStyleSheet("/style/userAccounts.css");
+htmlSetFormClass("accountScreen");
+cartHtmlShell("User Suggestion",doMiddle, hUserCookie(), excludeVars, oldVars);
+//cartEmptyShell(doMiddle, hUserCookie(), excludeVars, oldVars);
+cgiExitTime("hgUserSuggestion", enteredMainTime);
+return 0;
+}
+