Fossil SCM

Merged in [timeline-rss-ticket] changes.

stephan 2013-02-20 18:46 trunk merge
Commit dbaf5209105ee8346acc6742ae48893ec133eb95
+21
--- src/db.c
+++ src/db.c
@@ -1872,10 +1872,31 @@
18721872
return db_int(dflt, "SELECT value FROM vvar WHERE name=%Q", zName);
18731873
}
18741874
void db_lset_int(const char *zName, int value){
18751875
db_multi_exec("REPLACE INTO vvar(name,value) VALUES(%Q,%d)", zName, value);
18761876
}
1877
+
1878
+/*
1879
+** Returns non-0 if the database (which must be open) table identified
1880
+** by zTableName has a column named zColName (case-sensitive), else
1881
+** returns 0.
1882
+*/
1883
+int db_table_has_column( char const *zTableName, char const *zColName ){
1884
+ Stmt q = empty_Stmt;
1885
+ int rc = 0;
1886
+ db_prepare( &q, "PRAGMA table_info(%Q)", zTableName );
1887
+ while(SQLITE_ROW == db_step(&q)){
1888
+ /* Columns: (cid, name, type, notnull, dflt_value, pk) */
1889
+ char const * zCol = db_column_text(&q, 1);
1890
+ if(0==fossil_strcmp(zColName, zCol)){
1891
+ rc = 1;
1892
+ break;
1893
+ }
1894
+ }
1895
+ db_finalize(&q);
1896
+ return rc;
1897
+}
18771898
18781899
/*
18791900
** Record the name of a local repository in the global_config() database.
18801901
** The repository filename %s is recorded as an entry with a "name" field
18811902
** of the following form:
18821903
--- src/db.c
+++ src/db.c
@@ -1872,10 +1872,31 @@
1872 return db_int(dflt, "SELECT value FROM vvar WHERE name=%Q", zName);
1873 }
1874 void db_lset_int(const char *zName, int value){
1875 db_multi_exec("REPLACE INTO vvar(name,value) VALUES(%Q,%d)", zName, value);
1876 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1877
1878 /*
1879 ** Record the name of a local repository in the global_config() database.
1880 ** The repository filename %s is recorded as an entry with a "name" field
1881 ** of the following form:
1882
--- src/db.c
+++ src/db.c
@@ -1872,10 +1872,31 @@
1872 return db_int(dflt, "SELECT value FROM vvar WHERE name=%Q", zName);
1873 }
1874 void db_lset_int(const char *zName, int value){
1875 db_multi_exec("REPLACE INTO vvar(name,value) VALUES(%Q,%d)", zName, value);
1876 }
1877
1878 /*
1879 ** Returns non-0 if the database (which must be open) table identified
1880 ** by zTableName has a column named zColName (case-sensitive), else
1881 ** returns 0.
1882 */
1883 int db_table_has_column( char const *zTableName, char const *zColName ){
1884 Stmt q = empty_Stmt;
1885 int rc = 0;
1886 db_prepare( &q, "PRAGMA table_info(%Q)", zTableName );
1887 while(SQLITE_ROW == db_step(&q)){
1888 /* Columns: (cid, name, type, notnull, dflt_value, pk) */
1889 char const * zCol = db_column_text(&q, 1);
1890 if(0==fossil_strcmp(zColName, zCol)){
1891 rc = 1;
1892 break;
1893 }
1894 }
1895 db_finalize(&q);
1896 return rc;
1897 }
1898
1899 /*
1900 ** Record the name of a local repository in the global_config() database.
1901 ** The repository filename %s is recorded as an entry with a "name" field
1902 ** of the following form:
1903
+21
--- src/db.c
+++ src/db.c
@@ -1872,10 +1872,31 @@
18721872
return db_int(dflt, "SELECT value FROM vvar WHERE name=%Q", zName);
18731873
}
18741874
void db_lset_int(const char *zName, int value){
18751875
db_multi_exec("REPLACE INTO vvar(name,value) VALUES(%Q,%d)", zName, value);
18761876
}
1877
+
1878
+/*
1879
+** Returns non-0 if the database (which must be open) table identified
1880
+** by zTableName has a column named zColName (case-sensitive), else
1881
+** returns 0.
1882
+*/
1883
+int db_table_has_column( char const *zTableName, char const *zColName ){
1884
+ Stmt q = empty_Stmt;
1885
+ int rc = 0;
1886
+ db_prepare( &q, "PRAGMA table_info(%Q)", zTableName );
1887
+ while(SQLITE_ROW == db_step(&q)){
1888
+ /* Columns: (cid, name, type, notnull, dflt_value, pk) */
1889
+ char const * zCol = db_column_text(&q, 1);
1890
+ if(0==fossil_strcmp(zColName, zCol)){
1891
+ rc = 1;
1892
+ break;
1893
+ }
1894
+ }
1895
+ db_finalize(&q);
1896
+ return rc;
1897
+}
18771898
18781899
/*
18791900
** Record the name of a local repository in the global_config() database.
18801901
** The repository filename %s is recorded as an entry with a "name" field
18811902
** of the following form:
18821903
--- src/db.c
+++ src/db.c
@@ -1872,10 +1872,31 @@
1872 return db_int(dflt, "SELECT value FROM vvar WHERE name=%Q", zName);
1873 }
1874 void db_lset_int(const char *zName, int value){
1875 db_multi_exec("REPLACE INTO vvar(name,value) VALUES(%Q,%d)", zName, value);
1876 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1877
1878 /*
1879 ** Record the name of a local repository in the global_config() database.
1880 ** The repository filename %s is recorded as an entry with a "name" field
1881 ** of the following form:
1882
--- src/db.c
+++ src/db.c
@@ -1872,10 +1872,31 @@
1872 return db_int(dflt, "SELECT value FROM vvar WHERE name=%Q", zName);
1873 }
1874 void db_lset_int(const char *zName, int value){
1875 db_multi_exec("REPLACE INTO vvar(name,value) VALUES(%Q,%d)", zName, value);
1876 }
1877
1878 /*
1879 ** Returns non-0 if the database (which must be open) table identified
1880 ** by zTableName has a column named zColName (case-sensitive), else
1881 ** returns 0.
1882 */
1883 int db_table_has_column( char const *zTableName, char const *zColName ){
1884 Stmt q = empty_Stmt;
1885 int rc = 0;
1886 db_prepare( &q, "PRAGMA table_info(%Q)", zTableName );
1887 while(SQLITE_ROW == db_step(&q)){
1888 /* Columns: (cid, name, type, notnull, dflt_value, pk) */
1889 char const * zCol = db_column_text(&q, 1);
1890 if(0==fossil_strcmp(zColName, zCol)){
1891 rc = 1;
1892 break;
1893 }
1894 }
1895 db_finalize(&q);
1896 return rc;
1897 }
1898
1899 /*
1900 ** Record the name of a local repository in the global_config() database.
1901 ** The repository filename %s is recorded as an entry with a "name" field
1902 ** of the following form:
1903
+10 -2
--- src/info.c
+++ src/info.c
@@ -1665,11 +1665,11 @@
16651665
const char *zUuid;
16661666
char zTktName[UUID_SIZE+1];
16671667
Manifest *pTktChng;
16681668
int modPending;
16691669
const char *zModAction;
1670
-
1670
+ char *zTktTitle;
16711671
login_check_credentials();
16721672
if( !g.perm.RdTkt ){ login_needed(); return; }
16731673
rid = name_to_rid_www("name");
16741674
if( rid==0 ){ fossil_redirect_home(); }
16751675
zUuid = db_text("", "SELECT uuid FROM blob WHERE rid=%d", rid);
@@ -1694,10 +1694,13 @@
16941694
}
16951695
if( strcmp(zModAction,"approve")==0 ){
16961696
moderation_approve(rid);
16971697
}
16981698
}
1699
+ zTktTitle = db_table_has_column( "ticket", "title" )
1700
+ ? db_text("(No title)", "SELECT title FROM ticket WHERE tkt_uuid=%Q", zTktName)
1701
+ : 0;
16991702
style_header("Ticket Change Details");
17001703
style_submenu_element("Raw", "Raw", "%R/artifact/%S", zUuid);
17011704
style_submenu_element("History", "History", "%R/tkthistory/%s", zTktName);
17021705
style_submenu_element("Page", "Page", "%R/tktview/%t", zTktName);
17031706
style_submenu_element("Timeline", "Timeline", "%R/tkttimeline/%t", zTktName);
@@ -1718,17 +1721,22 @@
17181721
modPending = moderation_pending(rid);
17191722
if( modPending ){
17201723
@ <span class="modpending">*** Awaiting Moderator Approval ***</span>
17211724
}
17221725
@ <tr><th>Ticket:</th>
1723
- @ <td>%z(href("%R/tktview/%s",zTktName))%s(zTktName)</a></td></tr>
1726
+ @ <td>%z(href("%R/tktview/%s",zTktName))%s(zTktName)</a>
1727
+ if(zTktTitle){
1728
+ @<br>%h(zTktTitle)
1729
+ }
1730
+ @</td></tr>
17241731
@ <tr><th>Date:</th><td>
17251732
hyperlink_to_date(zDate, "</td></tr>");
17261733
@ <tr><th>User:</th><td>
17271734
hyperlink_to_user(pTktChng->zUser, zDate, "</td></tr>");
17281735
@ </table>
17291736
free(zDate);
1737
+ free(zTktTitle);
17301738
17311739
if( g.perm.ModTkt && modPending ){
17321740
@ <div class="section">Moderation</div>
17331741
@ <blockquote>
17341742
@ <form method="POST" action="%R/tinfo/%s(zUuid)">
17351743
--- src/info.c
+++ src/info.c
@@ -1665,11 +1665,11 @@
1665 const char *zUuid;
1666 char zTktName[UUID_SIZE+1];
1667 Manifest *pTktChng;
1668 int modPending;
1669 const char *zModAction;
1670
1671 login_check_credentials();
1672 if( !g.perm.RdTkt ){ login_needed(); return; }
1673 rid = name_to_rid_www("name");
1674 if( rid==0 ){ fossil_redirect_home(); }
1675 zUuid = db_text("", "SELECT uuid FROM blob WHERE rid=%d", rid);
@@ -1694,10 +1694,13 @@
1694 }
1695 if( strcmp(zModAction,"approve")==0 ){
1696 moderation_approve(rid);
1697 }
1698 }
 
 
 
1699 style_header("Ticket Change Details");
1700 style_submenu_element("Raw", "Raw", "%R/artifact/%S", zUuid);
1701 style_submenu_element("History", "History", "%R/tkthistory/%s", zTktName);
1702 style_submenu_element("Page", "Page", "%R/tktview/%t", zTktName);
1703 style_submenu_element("Timeline", "Timeline", "%R/tkttimeline/%t", zTktName);
@@ -1718,17 +1721,22 @@
1718 modPending = moderation_pending(rid);
1719 if( modPending ){
1720 @ <span class="modpending">*** Awaiting Moderator Approval ***</span>
1721 }
1722 @ <tr><th>Ticket:</th>
1723 @ <td>%z(href("%R/tktview/%s",zTktName))%s(zTktName)</a></td></tr>
 
 
 
 
1724 @ <tr><th>Date:</th><td>
1725 hyperlink_to_date(zDate, "</td></tr>");
1726 @ <tr><th>User:</th><td>
1727 hyperlink_to_user(pTktChng->zUser, zDate, "</td></tr>");
1728 @ </table>
1729 free(zDate);
 
1730
1731 if( g.perm.ModTkt && modPending ){
1732 @ <div class="section">Moderation</div>
1733 @ <blockquote>
1734 @ <form method="POST" action="%R/tinfo/%s(zUuid)">
1735
--- src/info.c
+++ src/info.c
@@ -1665,11 +1665,11 @@
1665 const char *zUuid;
1666 char zTktName[UUID_SIZE+1];
1667 Manifest *pTktChng;
1668 int modPending;
1669 const char *zModAction;
1670 char *zTktTitle;
1671 login_check_credentials();
1672 if( !g.perm.RdTkt ){ login_needed(); return; }
1673 rid = name_to_rid_www("name");
1674 if( rid==0 ){ fossil_redirect_home(); }
1675 zUuid = db_text("", "SELECT uuid FROM blob WHERE rid=%d", rid);
@@ -1694,10 +1694,13 @@
1694 }
1695 if( strcmp(zModAction,"approve")==0 ){
1696 moderation_approve(rid);
1697 }
1698 }
1699 zTktTitle = db_table_has_column( "ticket", "title" )
1700 ? db_text("(No title)", "SELECT title FROM ticket WHERE tkt_uuid=%Q", zTktName)
1701 : 0;
1702 style_header("Ticket Change Details");
1703 style_submenu_element("Raw", "Raw", "%R/artifact/%S", zUuid);
1704 style_submenu_element("History", "History", "%R/tkthistory/%s", zTktName);
1705 style_submenu_element("Page", "Page", "%R/tktview/%t", zTktName);
1706 style_submenu_element("Timeline", "Timeline", "%R/tkttimeline/%t", zTktName);
@@ -1718,17 +1721,22 @@
1721 modPending = moderation_pending(rid);
1722 if( modPending ){
1723 @ <span class="modpending">*** Awaiting Moderator Approval ***</span>
1724 }
1725 @ <tr><th>Ticket:</th>
1726 @ <td>%z(href("%R/tktview/%s",zTktName))%s(zTktName)</a>
1727 if(zTktTitle){
1728 @<br>%h(zTktTitle)
1729 }
1730 @</td></tr>
1731 @ <tr><th>Date:</th><td>
1732 hyperlink_to_date(zDate, "</td></tr>");
1733 @ <tr><th>User:</th><td>
1734 hyperlink_to_user(pTktChng->zUser, zDate, "</td></tr>");
1735 @ </table>
1736 free(zDate);
1737 free(zTktTitle);
1738
1739 if( g.perm.ModTkt && modPending ){
1740 @ <div class="section">Moderation</div>
1741 @ <blockquote>
1742 @ <form method="POST" action="%R/tinfo/%s(zUuid)">
1743
+10 -2
--- src/info.c
+++ src/info.c
@@ -1665,11 +1665,11 @@
16651665
const char *zUuid;
16661666
char zTktName[UUID_SIZE+1];
16671667
Manifest *pTktChng;
16681668
int modPending;
16691669
const char *zModAction;
1670
-
1670
+ char *zTktTitle;
16711671
login_check_credentials();
16721672
if( !g.perm.RdTkt ){ login_needed(); return; }
16731673
rid = name_to_rid_www("name");
16741674
if( rid==0 ){ fossil_redirect_home(); }
16751675
zUuid = db_text("", "SELECT uuid FROM blob WHERE rid=%d", rid);
@@ -1694,10 +1694,13 @@
16941694
}
16951695
if( strcmp(zModAction,"approve")==0 ){
16961696
moderation_approve(rid);
16971697
}
16981698
}
1699
+ zTktTitle = db_table_has_column( "ticket", "title" )
1700
+ ? db_text("(No title)", "SELECT title FROM ticket WHERE tkt_uuid=%Q", zTktName)
1701
+ : 0;
16991702
style_header("Ticket Change Details");
17001703
style_submenu_element("Raw", "Raw", "%R/artifact/%S", zUuid);
17011704
style_submenu_element("History", "History", "%R/tkthistory/%s", zTktName);
17021705
style_submenu_element("Page", "Page", "%R/tktview/%t", zTktName);
17031706
style_submenu_element("Timeline", "Timeline", "%R/tkttimeline/%t", zTktName);
@@ -1718,17 +1721,22 @@
17181721
modPending = moderation_pending(rid);
17191722
if( modPending ){
17201723
@ <span class="modpending">*** Awaiting Moderator Approval ***</span>
17211724
}
17221725
@ <tr><th>Ticket:</th>
1723
- @ <td>%z(href("%R/tktview/%s",zTktName))%s(zTktName)</a></td></tr>
1726
+ @ <td>%z(href("%R/tktview/%s",zTktName))%s(zTktName)</a>
1727
+ if(zTktTitle){
1728
+ @<br>%h(zTktTitle)
1729
+ }
1730
+ @</td></tr>
17241731
@ <tr><th>Date:</th><td>
17251732
hyperlink_to_date(zDate, "</td></tr>");
17261733
@ <tr><th>User:</th><td>
17271734
hyperlink_to_user(pTktChng->zUser, zDate, "</td></tr>");
17281735
@ </table>
17291736
free(zDate);
1737
+ free(zTktTitle);
17301738
17311739
if( g.perm.ModTkt && modPending ){
17321740
@ <div class="section">Moderation</div>
17331741
@ <blockquote>
17341742
@ <form method="POST" action="%R/tinfo/%s(zUuid)">
17351743
--- src/info.c
+++ src/info.c
@@ -1665,11 +1665,11 @@
1665 const char *zUuid;
1666 char zTktName[UUID_SIZE+1];
1667 Manifest *pTktChng;
1668 int modPending;
1669 const char *zModAction;
1670
1671 login_check_credentials();
1672 if( !g.perm.RdTkt ){ login_needed(); return; }
1673 rid = name_to_rid_www("name");
1674 if( rid==0 ){ fossil_redirect_home(); }
1675 zUuid = db_text("", "SELECT uuid FROM blob WHERE rid=%d", rid);
@@ -1694,10 +1694,13 @@
1694 }
1695 if( strcmp(zModAction,"approve")==0 ){
1696 moderation_approve(rid);
1697 }
1698 }
 
 
 
1699 style_header("Ticket Change Details");
1700 style_submenu_element("Raw", "Raw", "%R/artifact/%S", zUuid);
1701 style_submenu_element("History", "History", "%R/tkthistory/%s", zTktName);
1702 style_submenu_element("Page", "Page", "%R/tktview/%t", zTktName);
1703 style_submenu_element("Timeline", "Timeline", "%R/tkttimeline/%t", zTktName);
@@ -1718,17 +1721,22 @@
1718 modPending = moderation_pending(rid);
1719 if( modPending ){
1720 @ <span class="modpending">*** Awaiting Moderator Approval ***</span>
1721 }
1722 @ <tr><th>Ticket:</th>
1723 @ <td>%z(href("%R/tktview/%s",zTktName))%s(zTktName)</a></td></tr>
 
 
 
 
1724 @ <tr><th>Date:</th><td>
1725 hyperlink_to_date(zDate, "</td></tr>");
1726 @ <tr><th>User:</th><td>
1727 hyperlink_to_user(pTktChng->zUser, zDate, "</td></tr>");
1728 @ </table>
1729 free(zDate);
 
1730
1731 if( g.perm.ModTkt && modPending ){
1732 @ <div class="section">Moderation</div>
1733 @ <blockquote>
1734 @ <form method="POST" action="%R/tinfo/%s(zUuid)">
1735
--- src/info.c
+++ src/info.c
@@ -1665,11 +1665,11 @@
1665 const char *zUuid;
1666 char zTktName[UUID_SIZE+1];
1667 Manifest *pTktChng;
1668 int modPending;
1669 const char *zModAction;
1670 char *zTktTitle;
1671 login_check_credentials();
1672 if( !g.perm.RdTkt ){ login_needed(); return; }
1673 rid = name_to_rid_www("name");
1674 if( rid==0 ){ fossil_redirect_home(); }
1675 zUuid = db_text("", "SELECT uuid FROM blob WHERE rid=%d", rid);
@@ -1694,10 +1694,13 @@
1694 }
1695 if( strcmp(zModAction,"approve")==0 ){
1696 moderation_approve(rid);
1697 }
1698 }
1699 zTktTitle = db_table_has_column( "ticket", "title" )
1700 ? db_text("(No title)", "SELECT title FROM ticket WHERE tkt_uuid=%Q", zTktName)
1701 : 0;
1702 style_header("Ticket Change Details");
1703 style_submenu_element("Raw", "Raw", "%R/artifact/%S", zUuid);
1704 style_submenu_element("History", "History", "%R/tkthistory/%s", zTktName);
1705 style_submenu_element("Page", "Page", "%R/tktview/%t", zTktName);
1706 style_submenu_element("Timeline", "Timeline", "%R/tkttimeline/%t", zTktName);
@@ -1718,17 +1721,22 @@
1721 modPending = moderation_pending(rid);
1722 if( modPending ){
1723 @ <span class="modpending">*** Awaiting Moderator Approval ***</span>
1724 }
1725 @ <tr><th>Ticket:</th>
1726 @ <td>%z(href("%R/tktview/%s",zTktName))%s(zTktName)</a>
1727 if(zTktTitle){
1728 @<br>%h(zTktTitle)
1729 }
1730 @</td></tr>
1731 @ <tr><th>Date:</th><td>
1732 hyperlink_to_date(zDate, "</td></tr>");
1733 @ <tr><th>User:</th><td>
1734 hyperlink_to_user(pTktChng->zUser, zDate, "</td></tr>");
1735 @ </table>
1736 free(zDate);
1737 free(zTktTitle);
1738
1739 if( g.perm.ModTkt && modPending ){
1740 @ <div class="section">Moderation</div>
1741 @ <blockquote>
1742 @ <form method="POST" action="%R/tinfo/%s(zUuid)">
1743
+56
--- src/rss.c
+++ src/rss.c
@@ -22,18 +22,37 @@
2222
#include "rss.h"
2323
#include <assert.h>
2424
2525
/*
2626
** WEBPAGE: timeline.rss
27
+** URL: /timeline.rss/y=TYPE&n=LIMIT&tkt=UUID&tag=TAG&wiki=NAME&name=FILENAME
28
+**
29
+** Produce an RSS feed of the timeline.
30
+**
31
+** TYPE may be: all, ci (show checkins only), t (show tickets only),
32
+** w (show wiki only). LIMIT is the number of items to show.
33
+**
34
+** tkt=UUID filters for only those events for the specified ticket. tag=TAG
35
+** filters for a tag, and wiki=NAME for a wiki page. Only one may be used.
36
+**
37
+** In addition, name=FILENAME filters for a specific file. This may be
38
+** combined with one of the other filters (useful for looking at a specific
39
+** branch).
2740
*/
41
+
2842
void page_timeline_rss(void){
2943
Stmt q;
3044
int nLine=0;
3145
char *zPubDate, *zProjectName, *zProjectDescr, *zFreeProjectName=0;
3246
Blob bSQL;
3347
const char *zType = PD("y","all"); /* Type of events. All if NULL */
48
+ const char *zTicketUuid = PD("tkt",NULL);
49
+ const char *zTag = PD("tag",NULL);
50
+ const char *zFilename = PD("name",NULL);
51
+ const char *zWiki = PD("wiki",NULL);
3452
int nLimit = atoi(PD("n","20"));
53
+ int nTagId;
3554
const char zSQL1[] =
3655
@ SELECT
3756
@ blob.rid,
3857
@ uuid,
3958
@ event.mtime,
@@ -62,10 +81,11 @@
6281
if( !g.perm.Read ){
6382
if( g.perm.RdTkt && g.perm.RdWiki ){
6483
blob_append(&bSQL, " AND event.type!='ci'", -1);
6584
}else if( g.perm.RdTkt ){
6685
blob_append(&bSQL, " AND event.type=='t'", -1);
86
+
6787
}else{
6888
blob_append(&bSQL, " AND event.type=='w'", -1);
6989
}
7090
}else if( !g.perm.RdWiki ){
7191
if( g.perm.RdTkt ){
@@ -76,10 +96,46 @@
7696
}else if( !g.perm.RdTkt ){
7797
assert( !g.perm.RdTkt &&& g.perm.Read && g.perm.RdWiki );
7898
blob_append(&bSQL, " AND event.type!='t'", -1);
7999
}
80100
}
101
+
102
+ if( zTicketUuid ){
103
+ nTagId = db_int(0, "SELECT tagid FROM tag WHERE tagname GLOB 'tkt-%q*'",
104
+ zTicketUuid);
105
+ if ( nTagId==0 ){
106
+ nTagId = -1;
107
+ }
108
+ }else if( zTag ){
109
+ nTagId = db_int(0, "SELECT tagid FROM tag WHERE tagname GLOB 'sym-%q*'",
110
+ zTag);
111
+ if ( nTagId==0 ){
112
+ nTagId = -1;
113
+ }
114
+ }else if( zWiki ){
115
+ nTagId = db_int(0, "SELECT tagid FROM tag WHERE tagname GLOB 'wiki-%q*'",
116
+ zWiki);
117
+ if ( nTagId==0 ){
118
+ nTagId = -1;
119
+ }
120
+ }else{
121
+ nTagId = 0;
122
+ }
123
+
124
+ if( nTagId==-1 ){
125
+ blob_appendf(&bSQL, " AND 0");
126
+ }else if( nTagId!=0 ){
127
+ blob_appendf(&bSQL, " AND (EXISTS(SELECT 1 FROM tagxref"
128
+ " WHERE tagid=%d AND tagtype>0 AND rid=blob.rid))", nTagId);
129
+ }
130
+
131
+ if( zFilename ){
132
+ blob_appendf(&bSQL,
133
+ " AND (SELECT mlink.fnid FROM mlink WHERE event.objid=mlink.mid) IN (SELECT fnid FROM filename WHERE name=%Q %s)",
134
+ zFilename, filename_collation()
135
+ );
136
+ }
81137
82138
blob_append( &bSQL, " ORDER BY event.mtime DESC", -1 );
83139
84140
cgi_set_content_type("application/rss+xml");
85141
86142
--- src/rss.c
+++ src/rss.c
@@ -22,18 +22,37 @@
22 #include "rss.h"
23 #include <assert.h>
24
25 /*
26 ** WEBPAGE: timeline.rss
 
 
 
 
 
 
 
 
 
 
 
 
 
27 */
 
28 void page_timeline_rss(void){
29 Stmt q;
30 int nLine=0;
31 char *zPubDate, *zProjectName, *zProjectDescr, *zFreeProjectName=0;
32 Blob bSQL;
33 const char *zType = PD("y","all"); /* Type of events. All if NULL */
 
 
 
 
34 int nLimit = atoi(PD("n","20"));
 
35 const char zSQL1[] =
36 @ SELECT
37 @ blob.rid,
38 @ uuid,
39 @ event.mtime,
@@ -62,10 +81,11 @@
62 if( !g.perm.Read ){
63 if( g.perm.RdTkt && g.perm.RdWiki ){
64 blob_append(&bSQL, " AND event.type!='ci'", -1);
65 }else if( g.perm.RdTkt ){
66 blob_append(&bSQL, " AND event.type=='t'", -1);
 
67 }else{
68 blob_append(&bSQL, " AND event.type=='w'", -1);
69 }
70 }else if( !g.perm.RdWiki ){
71 if( g.perm.RdTkt ){
@@ -76,10 +96,46 @@
76 }else if( !g.perm.RdTkt ){
77 assert( !g.perm.RdTkt &&& g.perm.Read && g.perm.RdWiki );
78 blob_append(&bSQL, " AND event.type!='t'", -1);
79 }
80 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
81
82 blob_append( &bSQL, " ORDER BY event.mtime DESC", -1 );
83
84 cgi_set_content_type("application/rss+xml");
85
86
--- src/rss.c
+++ src/rss.c
@@ -22,18 +22,37 @@
22 #include "rss.h"
23 #include <assert.h>
24
25 /*
26 ** WEBPAGE: timeline.rss
27 ** URL: /timeline.rss/y=TYPE&n=LIMIT&tkt=UUID&tag=TAG&wiki=NAME&name=FILENAME
28 **
29 ** Produce an RSS feed of the timeline.
30 **
31 ** TYPE may be: all, ci (show checkins only), t (show tickets only),
32 ** w (show wiki only). LIMIT is the number of items to show.
33 **
34 ** tkt=UUID filters for only those events for the specified ticket. tag=TAG
35 ** filters for a tag, and wiki=NAME for a wiki page. Only one may be used.
36 **
37 ** In addition, name=FILENAME filters for a specific file. This may be
38 ** combined with one of the other filters (useful for looking at a specific
39 ** branch).
40 */
41
42 void page_timeline_rss(void){
43 Stmt q;
44 int nLine=0;
45 char *zPubDate, *zProjectName, *zProjectDescr, *zFreeProjectName=0;
46 Blob bSQL;
47 const char *zType = PD("y","all"); /* Type of events. All if NULL */
48 const char *zTicketUuid = PD("tkt",NULL);
49 const char *zTag = PD("tag",NULL);
50 const char *zFilename = PD("name",NULL);
51 const char *zWiki = PD("wiki",NULL);
52 int nLimit = atoi(PD("n","20"));
53 int nTagId;
54 const char zSQL1[] =
55 @ SELECT
56 @ blob.rid,
57 @ uuid,
58 @ event.mtime,
@@ -62,10 +81,11 @@
81 if( !g.perm.Read ){
82 if( g.perm.RdTkt && g.perm.RdWiki ){
83 blob_append(&bSQL, " AND event.type!='ci'", -1);
84 }else if( g.perm.RdTkt ){
85 blob_append(&bSQL, " AND event.type=='t'", -1);
86
87 }else{
88 blob_append(&bSQL, " AND event.type=='w'", -1);
89 }
90 }else if( !g.perm.RdWiki ){
91 if( g.perm.RdTkt ){
@@ -76,10 +96,46 @@
96 }else if( !g.perm.RdTkt ){
97 assert( !g.perm.RdTkt &&& g.perm.Read && g.perm.RdWiki );
98 blob_append(&bSQL, " AND event.type!='t'", -1);
99 }
100 }
101
102 if( zTicketUuid ){
103 nTagId = db_int(0, "SELECT tagid FROM tag WHERE tagname GLOB 'tkt-%q*'",
104 zTicketUuid);
105 if ( nTagId==0 ){
106 nTagId = -1;
107 }
108 }else if( zTag ){
109 nTagId = db_int(0, "SELECT tagid FROM tag WHERE tagname GLOB 'sym-%q*'",
110 zTag);
111 if ( nTagId==0 ){
112 nTagId = -1;
113 }
114 }else if( zWiki ){
115 nTagId = db_int(0, "SELECT tagid FROM tag WHERE tagname GLOB 'wiki-%q*'",
116 zWiki);
117 if ( nTagId==0 ){
118 nTagId = -1;
119 }
120 }else{
121 nTagId = 0;
122 }
123
124 if( nTagId==-1 ){
125 blob_appendf(&bSQL, " AND 0");
126 }else if( nTagId!=0 ){
127 blob_appendf(&bSQL, " AND (EXISTS(SELECT 1 FROM tagxref"
128 " WHERE tagid=%d AND tagtype>0 AND rid=blob.rid))", nTagId);
129 }
130
131 if( zFilename ){
132 blob_appendf(&bSQL,
133 " AND (SELECT mlink.fnid FROM mlink WHERE event.objid=mlink.mid) IN (SELECT fnid FROM filename WHERE name=%Q %s)",
134 zFilename, filename_collation()
135 );
136 }
137
138 blob_append( &bSQL, " ORDER BY event.mtime DESC", -1 );
139
140 cgi_set_content_type("application/rss+xml");
141
142

Keyboard Shortcuts

Open search /
Next entry (timeline) j
Previous entry (timeline) k
Open focused entry Enter
Show this help ?
Toggle theme Top nav button