02d1ed6ad2 2008-02-02 stephan: /* 02d1ed6ad2 2008-02-02 stephan: ** Copyright (c) 2007 D. Richard Hipp 2ab3a2f603 2008-02-03 stephan: ** Copyright (c) 2008 Stephan Beal 02d1ed6ad2 2008-02-02 stephan: ** 02d1ed6ad2 2008-02-02 stephan: ** This program is free software; you can redistribute it and/or 02d1ed6ad2 2008-02-02 stephan: ** modify it under the terms of the GNU General Public 02d1ed6ad2 2008-02-02 stephan: ** License as published by the Free Software Foundation; either 02d1ed6ad2 2008-02-02 stephan: ** version 2 of the License, or (at your option) any later version. 02d1ed6ad2 2008-02-02 stephan: ** 02d1ed6ad2 2008-02-02 stephan: ** This program is distributed in the hope that it will be useful, 02d1ed6ad2 2008-02-02 stephan: ** but WITHOUT ANY WARRANTY; without even the implied warranty of 02d1ed6ad2 2008-02-02 stephan: ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 02d1ed6ad2 2008-02-02 stephan: ** General Public License for more details. 02d1ed6ad2 2008-02-02 stephan: ** 02d1ed6ad2 2008-02-02 stephan: ** You should have received a copy of the GNU General Public 02d1ed6ad2 2008-02-02 stephan: ** License along with this library; if not, write to the 02d1ed6ad2 2008-02-02 stephan: ** Free Software Foundation, Inc., 59 Temple Place - Suite 330, 02d1ed6ad2 2008-02-02 stephan: ** Boston, MA 02111-1307, USA. 02d1ed6ad2 2008-02-02 stephan: ** 02d1ed6ad2 2008-02-02 stephan: ** Author contact information: 02d1ed6ad2 2008-02-02 stephan: ** drh@hwaci.com 02d1ed6ad2 2008-02-02 stephan: ** http://www.hwaci.com/drh/ 02d1ed6ad2 2008-02-02 stephan: ** 02d1ed6ad2 2008-02-02 stephan: ******************************************************************************* 02d1ed6ad2 2008-02-02 stephan: ** 02d1ed6ad2 2008-02-02 stephan: ** Implementation of the Tag View page 02d1ed6ad2 2008-02-02 stephan: */ 02d1ed6ad2 2008-02-02 stephan: #include <assert.h> 02d1ed6ad2 2008-02-02 stephan: #include "config.h" 02d1ed6ad2 2008-02-02 stephan: #include "tagview.h" 02d1ed6ad2 2008-02-02 stephan: 02d1ed6ad2 2008-02-02 stephan: 02d1ed6ad2 2008-02-02 stephan: /* 02d1ed6ad2 2008-02-02 stephan: ** Output a single entry for a menu generated using an HTML table. 02d1ed6ad2 2008-02-02 stephan: ** If zLink is not NULL or an empty string, then it is the page that 02d1ed6ad2 2008-02-02 stephan: ** the menu entry will hyperlink to. If zLink is NULL or "", then 02d1ed6ad2 2008-02-02 stephan: ** the menu entry has no hyperlink - it is disabled. 02d1ed6ad2 2008-02-02 stephan: */ 02d1ed6ad2 2008-02-02 stephan: void tagview_menu_entry( 02d1ed6ad2 2008-02-02 stephan: const char *zTitle, 02d1ed6ad2 2008-02-02 stephan: const char *zLink, 02d1ed6ad2 2008-02-02 stephan: const char *zDesc 02d1ed6ad2 2008-02-02 stephan: ){ 02d1ed6ad2 2008-02-02 stephan: @ <tr><td valign="top" align="right"> 02d1ed6ad2 2008-02-02 stephan: if( zLink && zLink[0] ){ 2ab3a2f603 2008-02-03 stephan: @ <a href="%s(g.zBaseURL)/%s(zLink)">%h(zTitle)</a> 02d1ed6ad2 2008-02-02 stephan: }else{ 02d1ed6ad2 2008-02-02 stephan: @ %h(zTitle) 02d1ed6ad2 2008-02-02 stephan: } 02d1ed6ad2 2008-02-02 stephan: @ </td><td valign="top">%h(zDesc)</td></tr> 02d1ed6ad2 2008-02-02 stephan: } 02d1ed6ad2 2008-02-02 stephan: 2ab3a2f603 2008-02-03 stephan: static void tagview_page_list_tags( char const * like ) 2ab3a2f603 2008-02-03 stephan: { 02d1ed6ad2 2008-02-02 stephan: Stmt st; 2ab3a2f603 2008-02-03 stephan: char * likeclause = 0; 2ab3a2f603 2008-02-03 stephan: const int limit = 10; 2ab3a2f603 2008-02-03 stephan: char * limitstr = 0; 2ab3a2f603 2008-02-03 stephan: if( like && strlen(like) ) 2ab3a2f603 2008-02-03 stephan: { 2ab3a2f603 2008-02-03 stephan: likeclause = mprintf( "AND t.tagname LIKE '%%%%%q%%%%'", like ); 2ab3a2f603 2008-02-03 stephan: @ <h2>Tags matching [%s(likeclause)]:</h2> 02d1ed6ad2 2008-02-02 stephan: } 2ab3a2f603 2008-02-03 stephan: else 2ab3a2f603 2008-02-03 stephan: { 2ab3a2f603 2008-02-03 stephan: limitstr = mprintf( "LIMIT %d", limit ); 2ab3a2f603 2008-02-03 stephan: @ <h2>%d(limit) most recent tags:</h2> 2ab3a2f603 2008-02-03 stephan: } 02d1ed6ad2 2008-02-02 stephan: @ <table cellpadding='4px' border='1'><tbody> 2ab3a2f603 2008-02-03 stephan: @ <tr> 2ab3a2f603 2008-02-03 stephan: @ <th>Tag ID</th> 2ab3a2f603 2008-02-03 stephan: @ <th>Tag name</th> 2ab3a2f603 2008-02-03 stephan: @ <th>Timestamp</th> 2ab3a2f603 2008-02-03 stephan: @ <th>Version</th> 2ab3a2f603 2008-02-03 stephan: @ </tr> 2ab3a2f603 2008-02-03 stephan: char * sql = mprintf( 2ab3a2f603 2008-02-03 stephan: "SELECT t.tagid, t.tagname, DATETIME(tx.mtime), b.uuid " 2ab3a2f603 2008-02-03 stephan: "FROM tag t, tagxref tx, blob b " 2ab3a2f603 2008-02-03 stephan: "WHERE (t.tagid=tx.tagid) and (tx.srcid=b.rid) " 2ab3a2f603 2008-02-03 stephan: "AND (tx.tagtype != 0) %s " 2ab3a2f603 2008-02-03 stephan: "ORDER BY tx.mtime DESC %s", 2ab3a2f603 2008-02-03 stephan: likeclause ? likeclause : " ", 2ab3a2f603 2008-02-03 stephan: limitstr ? limitstr : " " 2ab3a2f603 2008-02-03 stephan: ); 2ab3a2f603 2008-02-03 stephan: db_prepare( &st, sql ); 2ab3a2f603 2008-02-03 stephan: if( likeclause ) free( likeclause ); 2ab3a2f603 2008-02-03 stephan: free( sql ); 10437374a7 2008-02-02 drh: while( SQLITE_ROW == db_step(&st) ){ 2ab3a2f603 2008-02-03 stephan: int tagid = db_column_int( &st, 0 ); 2ab3a2f603 2008-02-03 stephan: char const * tagname = db_column_text( &st, 1 ); 2ab3a2f603 2008-02-03 stephan: char const * tagtime = db_column_text( &st, 2 ); 2ab3a2f603 2008-02-03 stephan: char const * uuid = db_column_text( &st, 3 ); 10437374a7 2008-02-02 drh: const int offset = 10; 10437374a7 2008-02-02 drh: char shortname[offset+1]; 10437374a7 2008-02-02 drh: shortname[offset] = '\0'; 10437374a7 2008-02-02 drh: memcpy( shortname, uuid, offset ); 10437374a7 2008-02-02 drh: @ <tr> 2ab3a2f603 2008-02-03 stephan: @ <td><tt> 2ab3a2f603 2008-02-03 stephan: @ <a href='%s(g.zBaseURL)/tagview?tagid=%d(tagid)'>%d(tagid)</a> 2ab3a2f603 2008-02-03 stephan: @ </tt></td> 2ab3a2f603 2008-02-03 stephan: @ <td><tt><a href='%s(g.zBaseURL)/tagview/%q(tagname)'>%s(tagname)</a></tt></td> 10437374a7 2008-02-02 drh: @ <td align='center'><tt>%s(tagtime)</tt></td> 10437374a7 2008-02-02 drh: @ <td><tt> 2ab3a2f603 2008-02-03 stephan: @ <a href='%s(g.zBaseURL)/vinfo/%s(uuid)'><strong>%s(shortname)</strong>%s(uuid+offset)</a> 2ab3a2f603 2008-02-03 stephan: @ </tt></td></tr> 02d1ed6ad2 2008-02-02 stephan: } 02d1ed6ad2 2008-02-02 stephan: db_finalize( &st ); 02d1ed6ad2 2008-02-02 stephan: @ </tbody></table> 02d1ed6ad2 2008-02-02 stephan: @ <hr/>TODOs include: 02d1ed6ad2 2008-02-02 stephan: @ <ul> 02d1ed6ad2 2008-02-02 stephan: @ <li>Page through long tags lists.</li> 2ab3a2f603 2008-02-03 stephan: @ <li>Refactor the internal report routines to be reusable.</li> 02d1ed6ad2 2008-02-02 stephan: @ <li>Allow different sorting.</li> 2ab3a2f603 2008-02-03 stephan: @ <li>Selectively filter out wiki/ticket/baseline</li> 02d1ed6ad2 2008-02-02 stephan: @ <li>?</li> 02d1ed6ad2 2008-02-02 stephan: @ </ul> 2ab3a2f603 2008-02-03 stephan: 2ab3a2f603 2008-02-03 stephan: } 2ab3a2f603 2008-02-03 stephan: 2ab3a2f603 2008-02-03 stephan: static void tagview_page_search_miniform(void){ 2ab3a2f603 2008-02-03 stephan: char const * like = P("like"); 2ab3a2f603 2008-02-03 stephan: @ <div style='font-size:smaller'> 2ab3a2f603 2008-02-03 stephan: @ <form action='/tagview' method='post'> 2ab3a2f603 2008-02-03 stephan: @ Search for tags: 2ab3a2f603 2008-02-03 stephan: @ <input type='text' name='like' value='%s((like?like:""))' size='10'/> 2ab3a2f603 2008-02-03 stephan: @ <input type='submit'/> 2ab3a2f603 2008-02-03 stephan: @ </form> 2ab3a2f603 2008-02-03 stephan: @ </div> 2ab3a2f603 2008-02-03 stephan: } 2ab3a2f603 2008-02-03 stephan: 2ab3a2f603 2008-02-03 stephan: 2ab3a2f603 2008-02-03 stephan: static void tagview_page_default(void){ 2ab3a2f603 2008-02-03 stephan: tagview_page_list_tags( 0 ); 2ab3a2f603 2008-02-03 stephan: } 2ab3a2f603 2008-02-03 stephan: 2ab3a2f603 2008-02-03 stephan: static void tagview_page_tag_by_id( int tagid ) 2ab3a2f603 2008-02-03 stephan: { 2ab3a2f603 2008-02-03 stephan: Stmt st; 2ab3a2f603 2008-02-03 stephan: char * sql = mprintf( 2ab3a2f603 2008-02-03 stephan: "SELECT DISTINCT (t.tagname), DATETIME(tx.mtime), b.uuid " 2ab3a2f603 2008-02-03 stephan: "FROM tag t, tagxref tx, blob b " 2ab3a2f603 2008-02-03 stephan: "WHERE (t.tagid=%d) AND (t.tagid=tx.tagid) AND (tx.srcid=b.rid) " 2ab3a2f603 2008-02-03 stephan: "ORDER BY tx.mtime DESC", 2ab3a2f603 2008-02-03 stephan: tagid); 2ab3a2f603 2008-02-03 stephan: db_prepare( &st, sql ); 2ab3a2f603 2008-02-03 stephan: free( sql ); 2ab3a2f603 2008-02-03 stephan: @ <h2>Tag ID %d(tagid):</h2> 2ab3a2f603 2008-02-03 stephan: @ <table cellpadding='4px' border='1'><tbody> 2ab3a2f603 2008-02-03 stephan: @ <tr><th>Tag name</th><th>Timestamp</th><th>Version</th></tr> 2ab3a2f603 2008-02-03 stephan: while( SQLITE_ROW == db_step(&st) ) 2ab3a2f603 2008-02-03 stephan: { 2ab3a2f603 2008-02-03 stephan: char const * tagname = db_column_text( &st, 0 ); 2ab3a2f603 2008-02-03 stephan: char const * tagtime = db_column_text( &st, 1 ); 2ab3a2f603 2008-02-03 stephan: char const * uuid = db_column_text( &st, 2 ); 2ab3a2f603 2008-02-03 stephan: const int offset = 10; 2ab3a2f603 2008-02-03 stephan: char shortname[offset+1]; 2ab3a2f603 2008-02-03 stephan: shortname[offset] = '\0'; 2ab3a2f603 2008-02-03 stephan: memcpy( shortname, uuid, offset ); 2ab3a2f603 2008-02-03 stephan: @ <tr> 2ab3a2f603 2008-02-03 stephan: @ <td><tt><a href='%s(g.zBaseURL)/tagview/%q(tagname)'>%s(tagname)</a></tt></td> 2ab3a2f603 2008-02-03 stephan: @ <td align='center'><tt>%s(tagtime)</tt></td> 2ab3a2f603 2008-02-03 stephan: @ <td><tt> 2ab3a2f603 2008-02-03 stephan: @ <a href='%s(g.zBaseURL)/vinfo/%s(uuid)'><strong>%s(shortname)</strong>%s(uuid+offset)</a> 2ab3a2f603 2008-02-03 stephan: @ </tt></td></tr> 2ab3a2f603 2008-02-03 stephan: } 2ab3a2f603 2008-02-03 stephan: @ </tbody></table> 2ab3a2f603 2008-02-03 stephan: db_finalize( &st ); 2ab3a2f603 2008-02-03 stephan: } 2ab3a2f603 2008-02-03 stephan: 2ab3a2f603 2008-02-03 stephan: static void tagview_page_tag_by_name( char const * tagname ) 2ab3a2f603 2008-02-03 stephan: { 2ab3a2f603 2008-02-03 stephan: Stmt st; 2ab3a2f603 2008-02-03 stephan: char * sql = mprintf( 2ab3a2f603 2008-02-03 stephan: "SELECT DISTINCT t.tagid, DATETIME(tx.mtime), b.uuid " 2ab3a2f603 2008-02-03 stephan: "FROM tag t, tagxref tx, blob b " 2ab3a2f603 2008-02-03 stephan: "WHERE (t.tagname='%q') AND (t.tagid=tx.tagid) AND (tx.srcid=b.rid) " 2ab3a2f603 2008-02-03 stephan: "ORDER BY tx.mtime DESC", 2ab3a2f603 2008-02-03 stephan: tagname); 2ab3a2f603 2008-02-03 stephan: db_prepare( &st, sql ); 2ab3a2f603 2008-02-03 stephan: free( sql ); 2ab3a2f603 2008-02-03 stephan: @ <h2>Tag '%s(tagname)':</h2> 2ab3a2f603 2008-02-03 stephan: @ <table cellpadding='4px' border='1'><tbody> 2ab3a2f603 2008-02-03 stephan: @ <tr><th>Tag ID</th><th>Timestamp</th><th>Version</th></tr> 2ab3a2f603 2008-02-03 stephan: while( SQLITE_ROW == db_step(&st) ) 2ab3a2f603 2008-02-03 stephan: { 2ab3a2f603 2008-02-03 stephan: int tagid = db_column_int( &st, 0 ); 2ab3a2f603 2008-02-03 stephan: char const * tagtime = db_column_text( &st, 1 ); 2ab3a2f603 2008-02-03 stephan: char const * uuid = db_column_text( &st, 2 ); 2ab3a2f603 2008-02-03 stephan: const int offset = 10; 2ab3a2f603 2008-02-03 stephan: char shortname[offset+1]; 2ab3a2f603 2008-02-03 stephan: shortname[offset] = '\0'; 2ab3a2f603 2008-02-03 stephan: memcpy( shortname, uuid, offset ); 2ab3a2f603 2008-02-03 stephan: @ <tr> 2ab3a2f603 2008-02-03 stephan: @ <td><tt><a href='%s(g.zBaseURL)/tagview?tagid=%d(tagid)'>%d(tagid)</a></tt></td> 2ab3a2f603 2008-02-03 stephan: @ <td align='center'><tt>%s(tagtime)</tt></td> 2ab3a2f603 2008-02-03 stephan: @ <td><tt> 2ab3a2f603 2008-02-03 stephan: @ <a href='%s(g.zBaseURL)/vinfo/%s(uuid)'><strong>%s(shortname)</strong>%s(uuid+offset)</a> 2ab3a2f603 2008-02-03 stephan: @ </tt></td></tr> 2ab3a2f603 2008-02-03 stephan: } 2ab3a2f603 2008-02-03 stephan: @ </tbody></table> 2ab3a2f603 2008-02-03 stephan: db_finalize( &st ); 02d1ed6ad2 2008-02-02 stephan: } 02d1ed6ad2 2008-02-02 stephan: 2ab3a2f603 2008-02-03 stephan: 2ab3a2f603 2008-02-03 stephan: /* 2ab3a2f603 2008-02-03 stephan: ** WEBPAGE: /tagview 2ab3a2f603 2008-02-03 stephan: */ 2ab3a2f603 2008-02-03 stephan: void tagview_page(void){ 2ab3a2f603 2008-02-03 stephan: 2ab3a2f603 2008-02-03 stephan: login_check_credentials(); 2ab3a2f603 2008-02-03 stephan: if( !g.okSetup ){ 2ab3a2f603 2008-02-03 stephan: login_needed(); 2ab3a2f603 2008-02-03 stephan: } 2ab3a2f603 2008-02-03 stephan: style_header("Tags"); 2ab3a2f603 2008-02-03 stephan: tagview_page_search_miniform(); 2ab3a2f603 2008-02-03 stephan: @ <hr/> 2ab3a2f603 2008-02-03 stephan: char const * check = 0; 2ab3a2f603 2008-02-03 stephan: if( 0 != (check = P("tagid")) ) 2ab3a2f603 2008-02-03 stephan: { 2ab3a2f603 2008-02-03 stephan: tagview_page_tag_by_id( atoi(check) ); 2ab3a2f603 2008-02-03 stephan: } 2ab3a2f603 2008-02-03 stephan: else if( 0 != (check = P("like")) ) 2ab3a2f603 2008-02-03 stephan: { 2ab3a2f603 2008-02-03 stephan: tagview_page_list_tags( check ); 2ab3a2f603 2008-02-03 stephan: } 2ab3a2f603 2008-02-03 stephan: else if( 0 != (check = P("name")) ) 2ab3a2f603 2008-02-03 stephan: { 2ab3a2f603 2008-02-03 stephan: tagview_page_tag_by_name( check ); 2ab3a2f603 2008-02-03 stephan: } 2ab3a2f603 2008-02-03 stephan: else 2ab3a2f603 2008-02-03 stephan: { 2ab3a2f603 2008-02-03 stephan: tagview_page_default(); 2ab3a2f603 2008-02-03 stephan: } 10437374a7 2008-02-02 drh: style_footer(); 10437374a7 2008-02-02 drh: }