Check-in [b3ee50c946]
Not logged in
Overview

SHA1 Hash:b3ee50c9463214942d0af7055f4a06e2353f631c
Date: 2008-07-15 19:03:42
User: drh
Comment:Implement history display for tickets.
Timelines: ancestors | descendants | both | trunk
Other Links: files | ZIP archive | manifest

Tags And Properties
Changes
[hide diffs]

Modified src/info.c from [de0ea7fc4a] to [737ba1d6c6].

@@ -793,10 +793,95 @@
   blob_reset(&content);
   style_footer();
 }
 
 /*
+** Return TRUE if the given BLOB contains a newline character.
+*/
+static int contains_newline(Blob *p){
+  const char *z = blob_str(p);
+  while( *z ){
+    if( *z=='\n' ) return 1;
+    z++;
+  }
+  return 0;
+}
+
+/*
+** WEBPAGE: tinfo
+** URL: /tinfo?name=UUID
+**
+** Show the details of a ticket change control artifact.
+*/
+void tinfo_page(void){
+  int rid;
+  Blob content;
+  char *zDate;
+  int i;
+  const char *zUuid;
+  char zTktName[20];
+  const char *z;
+  Manifest m;
+
+  login_check_credentials();
+  if( !g.okRdTkt ){ login_needed(); return; }
+  rid = name_to_rid(PD("name","0"));
+  if( rid==0 ){ fossil_redirect_home(); }
+  zUuid = db_text("", "SELECT uuid FROM blob WHERE rid=%d", rid);
+  if( g.okAdmin ){
+    if( db_exists("SELECT 1 FROM shun WHERE uuid='%s'", zUuid) ){
+      style_submenu_element("Unshun","Unshun", "%s/shun?uuid=%s&sub=1",
+            g.zTop, zUuid);
+    }else{
+      style_submenu_element("Shun","Shun", "%s/shun?shun=%s#addshun",
+            g.zTop, zUuid);
+    }
+  }
+  content_get(rid, &content);
+  if( manifest_parse(&m, &content)==0 ){
+    fossil_redirect_home();
+  }
+  if( m.type!=CFTYPE_TICKET ){
+    fossil_redirect_home();
+  }
+  style_header("Ticket Change Details");
+  zDate = db_text(0, "SELECT datetime(%.12f)", m.rDate);
+  memcpy(zTktName, m.zTicketUuid, 10);
+  zTktName[10] = 0;
+  @ <h2>Changes to ticket <a href="%s(m.zTicketUuid)">%s(zTktName)</a></h2>
+  @
+  @ <p>By %h(m.zUser) on %s(zDate).  See also:
+  @ <a href="%s(g.zTop)/artifact/%T(zUuid)">artifact content</a>, and
+  @ <a href="%s(g.zTop)/tkthistory/%s(m.zTicketUuid)">ticket history</a>
+  @ </p>
+  @
+  @ <ol>
+  free(zDate);
+  for(i=0; i<m.nField; i++){
+    Blob val;
+    z = m.aField[i].zName;
+    blob_set(&val, m.aField[i].zValue);
+    if( z[0]=='+' ){
+      @ <li><p>Appended to %h(&z[1]):</p><blockquote>
+      wiki_convert(&val, 0, 0);
+      @ </blockquote></li>
+    }else if( blob_size(&val)<=50 && contains_newline(&val) ){
+      @ <li><p>Change %h(z) to:</p><blockquote>
+      wiki_convert(&val, 0, 0);
+      @ </blockquote></li>
+    }else{
+      @ <li><p>Change %h(z) to "%h(blob_str(&val))"</p></li>
+    }
+    blob_reset(&val);
+  }
+  manifest_clear(&m);
+  @ </ol>
+  style_footer();
+}
+
+
+/*
 ** WEBPAGE: info
 ** URL: info/UUID
 **
 ** The argument is a UUID which might be a baseline or a file or
 ** a ticket changes or a wiki editor or something else.
@@ -831,10 +916,14 @@
     finfo_page();
   }else
   if( db_exists("SELECT 1 FROM tagxref JOIN tag USING(tagid)"
                 " WHERE rid=%d AND tagname LIKE 'wiki-%%'", rid) ){
     winfo_page();
+  }else
+  if( db_exists("SELECT 1 FROM tagxref JOIN tag USING(tagid)"
+                " WHERE rid=%d AND tagname LIKE 'tkt-%%'", rid) ){
+    tinfo_page();
   }else
   {
     artifact_page();
   }
 }

Modified src/manifest.c from [b69e148aae] to [5e75594729].

@@ -893,23 +893,53 @@
     );
     free(zComment);
   }
   if( m.type==CFTYPE_TICKET ){
     char *zTag;
-    char *zComment;
+    Blob comment;
+    int i;
 
     ticket_insert(&m, 1, 1);
     zTag = mprintf("tkt-%s", m.zTicketUuid);
     tag_insert(zTag, 1, 0, rid, m.rDate, rid);
     free(zTag);
-    zComment = mprintf("Changes to ticket [%.10s]", m.zTicketUuid);
+    blob_zero(&comment);
+    if( m.nField==1 ){
+      if( m.aField[0].zName[0]=='+' ){
+        blob_appendf(&comment,
+          "Appended to %h in ticket [%.10s]",
+          &m.aField[0].zName[1], m.zTicketUuid
+        );
+      }else if( strlen(m.aField[0].zValue)<40 ){
+        blob_appendf(&comment,
+          "Changed %h to \"%h\" in ticket [%.10s]",
+          m.aField[0].zName, m.aField[0].zValue, m.zTicketUuid
+        );
+      }else{
+        blob_appendf(&comment,
+          "Changed %h in ticket [%.10s]",
+          m.aField[0].zName, m.zTicketUuid
+        );
+      }
+    }else{
+      const char *z;
+      const char *zSep = " ";
+      blob_appendf(&comment, "%d changes to ticket [%.10s]:",
+                            m.nField, m.zTicketUuid);
+      for(i=0; i<m.nField; i++){
+        z = m.aField[i].zName;
+        if( z[0]=='+' ) z++;
+        blob_appendf(&comment, "%s%h", zSep, z);
+        zSep = ", ";
+      }
+    }
     db_multi_exec(
       "REPLACE INTO event(type,mtime,objid,user,comment)"
       "VALUES('t',%.17g,%d,%Q,%Q)",
-      m.rDate, rid, m.zUser, zComment
+      m.rDate, rid, m.zUser, blob_str(&comment)
     );
-    free(zComment);
+    blob_reset(&comment);
   }
   db_end_transaction(0);
   manifest_clear(&m);
   return 1;
 }

Modified src/tkt.c from [486a2a67ca] to [6ac9641c6a].

@@ -304,10 +304,14 @@
   if( !g.okRdTkt ){ login_needed(); return; }
   if( g.okWrTkt ){
     style_submenu_element("Edit", "Edit The Ticket", "%s/tktedit?name=%T",
         g.zTop, PD("name",""));
   }
+  if( g.okHistory ){
+    style_submenu_element("History", "History Of This Ticket",
+        "%s/tkthistory/%T", g.zTop, PD("name",""));
+  }
   style_header("View Ticket");
   ticket_init();
   initializeVariablesFromDb();
   zScript = ticket_viewpage_code();
   Th_Render(zScript);
@@ -546,6 +550,43 @@
                      "containing all required fields");
       return zErr;
     }
   }
   return 0;
+}
+
+/*
+** WEBPAGE: tkthistory
+** URL: /tkthistory?name=TICKETUUID
+**
+** Show the complete change history for a single ticket
+*/
+void tkthistory_page(void){
+  Stmt q;
+  char *zTitle;
+  char *zSQL;
+  const char *zUuid;
+  int tagid;
+
+  login_check_credentials();
+  if( !g.okHistory || !g.okRdTkt ){ login_needed(); return; }
+  zUuid = PD("name","");
+  zTitle = mprintf("History Of Ticket %h", zUuid);
+  style_header(zTitle);
+  free(zTitle);
+
+  tagid = db_int(0, "SELECT tagid FROM tag WHERE tagname GLOB 'tkt-%q*'",zUuid);
+  if( tagid==0 ){
+    @ No such ticket: %h(zUuid)
+    style_footer();
+    return;
+  }
+  zSQL = mprintf("%s AND event.objid IN "
+                 "  (SELECT rid FROM tagxref WHERE tagid=%d) "
+                 "ORDER BY mtime DESC",
+                 timeline_query_for_www(), tagid);
+  db_prepare(&q, zSQL);
+  free(zSQL);
+  www_print_timeline(&q);
+  db_finalize(&q);
+  style_footer();
 }