Fossil SCM
Add the /forum page with search and a list of recent threads.
Commit
05105248a1568220b61c85cbb271f9b08af570fa3f1f7e8b1a473b4bab92fa04
Parent
b3c1ba372e76871…
2 files changed
+51
+14
-4
+51
| --- src/forum.c | ||
| +++ src/forum.c | ||
| @@ -883,5 +883,56 @@ | ||
| 883 | 883 | @ </div> |
| 884 | 884 | } |
| 885 | 885 | @ </form> |
| 886 | 886 | style_footer(); |
| 887 | 887 | } |
| 888 | + | |
| 889 | +/* | |
| 890 | +** WEBPAGE: forum | |
| 891 | +** | |
| 892 | +** The main page for the forum feature. Show a list of recent forum | |
| 893 | +** threads. Also show a search box at the top if search is enabled, | |
| 894 | +** and a button for creating a new thread, if enabled. | |
| 895 | +*/ | |
| 896 | +void forum_main_page(void){ | |
| 897 | + Stmt q; | |
| 898 | + int iLimit, iOfst; | |
| 899 | + login_check_credentials(); | |
| 900 | + sqlite3_int64 iNow = time(NULL); | |
| 901 | + if( !g.perm.RdForum ){ | |
| 902 | + login_needed(g.anon.RdForum); | |
| 903 | + return; | |
| 904 | + } | |
| 905 | + style_header("Forum"); | |
| 906 | + if( g.perm.WrForum ){ | |
| 907 | + style_submenu_element("New Message","%R/forumnew"); | |
| 908 | + } | |
| 909 | + if( search_screen(SRCH_FORUM, 0) ){ | |
| 910 | + style_submenu_element("Recent Threads","%R/forum"); | |
| 911 | + style_footer(); | |
| 912 | + return; | |
| 913 | + } | |
| 914 | + iLimit = 50; | |
| 915 | + iOfst = 0; | |
| 916 | + @ <h1>Recent Threads</h1> | |
| 917 | + @ <div class='fileage'><table width="100%%"> | |
| 918 | + db_prepare(&q, | |
| 919 | + "SELECT julianday('now') - max(fmtime)," | |
| 920 | + " (SELECT uuid FROM blob WHERE rid=fpid)," | |
| 921 | + " (SELECT substr(comment,instr(comment,':')+2)" | |
| 922 | + " FROM event WHERE objid=fpid)" | |
| 923 | + " FROM forumpost" | |
| 924 | + " GROUP BY froot ORDER BY 1 LIMIT %d OFFSET %d", | |
| 925 | + iLimit, iOfst | |
| 926 | + ); | |
| 927 | + while( db_step(&q)==SQLITE_ROW ){ | |
| 928 | + char *zAge = human_readable_age(db_column_double(&q,0)); | |
| 929 | + const char *zUuid = db_column_text(&q, 1); | |
| 930 | + const char *zTitle = db_column_text(&q, 2); | |
| 931 | + @ <tr><td>%h(zAge) ago</td> | |
| 932 | + @ <td>%z(href("%R/forumpost/%S",zUuid))%h(zTitle)</a> | |
| 933 | + @ </tr> | |
| 934 | + fossil_free(zAge); | |
| 935 | + } | |
| 936 | + @ </table></div> | |
| 937 | + style_footer(); | |
| 938 | +} | |
| 888 | 939 |
| --- src/forum.c | |
| +++ src/forum.c | |
| @@ -883,5 +883,56 @@ | |
| 883 | @ </div> |
| 884 | } |
| 885 | @ </form> |
| 886 | style_footer(); |
| 887 | } |
| 888 |
| --- src/forum.c | |
| +++ src/forum.c | |
| @@ -883,5 +883,56 @@ | |
| 883 | @ </div> |
| 884 | } |
| 885 | @ </form> |
| 886 | style_footer(); |
| 887 | } |
| 888 | |
| 889 | /* |
| 890 | ** WEBPAGE: forum |
| 891 | ** |
| 892 | ** The main page for the forum feature. Show a list of recent forum |
| 893 | ** threads. Also show a search box at the top if search is enabled, |
| 894 | ** and a button for creating a new thread, if enabled. |
| 895 | */ |
| 896 | void forum_main_page(void){ |
| 897 | Stmt q; |
| 898 | int iLimit, iOfst; |
| 899 | login_check_credentials(); |
| 900 | sqlite3_int64 iNow = time(NULL); |
| 901 | if( !g.perm.RdForum ){ |
| 902 | login_needed(g.anon.RdForum); |
| 903 | return; |
| 904 | } |
| 905 | style_header("Forum"); |
| 906 | if( g.perm.WrForum ){ |
| 907 | style_submenu_element("New Message","%R/forumnew"); |
| 908 | } |
| 909 | if( search_screen(SRCH_FORUM, 0) ){ |
| 910 | style_submenu_element("Recent Threads","%R/forum"); |
| 911 | style_footer(); |
| 912 | return; |
| 913 | } |
| 914 | iLimit = 50; |
| 915 | iOfst = 0; |
| 916 | @ <h1>Recent Threads</h1> |
| 917 | @ <div class='fileage'><table width="100%%"> |
| 918 | db_prepare(&q, |
| 919 | "SELECT julianday('now') - max(fmtime)," |
| 920 | " (SELECT uuid FROM blob WHERE rid=fpid)," |
| 921 | " (SELECT substr(comment,instr(comment,':')+2)" |
| 922 | " FROM event WHERE objid=fpid)" |
| 923 | " FROM forumpost" |
| 924 | " GROUP BY froot ORDER BY 1 LIMIT %d OFFSET %d", |
| 925 | iLimit, iOfst |
| 926 | ); |
| 927 | while( db_step(&q)==SQLITE_ROW ){ |
| 928 | char *zAge = human_readable_age(db_column_double(&q,0)); |
| 929 | const char *zUuid = db_column_text(&q, 1); |
| 930 | const char *zTitle = db_column_text(&q, 2); |
| 931 | @ <tr><td>%h(zAge) ago</td> |
| 932 | @ <td>%z(href("%R/forumpost/%S",zUuid))%h(zTitle)</a> |
| 933 | @ </tr> |
| 934 | fossil_free(zAge); |
| 935 | } |
| 936 | @ </table></div> |
| 937 | style_footer(); |
| 938 | } |
| 939 |
+14
-4
| --- src/search.c | ||
| +++ src/search.c | ||
| @@ -1066,20 +1066,27 @@ | ||
| 1066 | 1066 | ** |
| 1067 | 1067 | ** This routine automatically restricts srchFlag according to user |
| 1068 | 1068 | ** permissions and the server configuration. The entry box is shown |
| 1069 | 1069 | ** disabled if srchFlags is 0 after these restrictions are applied. |
| 1070 | 1070 | ** |
| 1071 | -** If useYparam is true, then this routine also looks at the y= query | |
| 1072 | -** parameter for further search restrictions. | |
| 1071 | +** The mFlags value controls options: | |
| 1072 | +** | |
| 1073 | +** 0x01 If the y= query parameter is present, use it as an addition | |
| 1074 | +** restriction what to search. | |
| 1075 | +** | |
| 1076 | +** 0x02 Show nothing if search is disabled. | |
| 1077 | +** | |
| 1078 | +** Return true if there are search results. | |
| 1073 | 1079 | */ |
| 1074 | -void search_screen(unsigned srchFlags, int useYparam){ | |
| 1080 | +int search_screen(unsigned srchFlags, int mFlags){ | |
| 1075 | 1081 | const char *zType = 0; |
| 1076 | 1082 | const char *zClass = 0; |
| 1077 | 1083 | const char *zDisable1; |
| 1078 | 1084 | const char *zDisable2; |
| 1079 | 1085 | const char *zPattern; |
| 1080 | 1086 | int fDebug = PB("debug"); |
| 1087 | + int haveResult = 0; | |
| 1081 | 1088 | srchFlags = search_restrict(srchFlags); |
| 1082 | 1089 | switch( srchFlags ){ |
| 1083 | 1090 | case SRCH_CKIN: zType = " Check-ins"; zClass = "Ckin"; break; |
| 1084 | 1091 | case SRCH_DOC: zType = " Docs"; zClass = "Doc"; break; |
| 1085 | 1092 | case SRCH_TKT: zType = " Tickets"; zClass = "Tkt"; break; |
| @@ -1086,10 +1093,11 @@ | ||
| 1086 | 1093 | case SRCH_WIKI: zType = " Wiki"; zClass = "Wiki"; break; |
| 1087 | 1094 | case SRCH_TECHNOTE: zType = " Tech Notes"; zClass = "Note"; break; |
| 1088 | 1095 | case SRCH_FORUM: zType = " Forum"; zClass = "Frm"; break; |
| 1089 | 1096 | } |
| 1090 | 1097 | if( srchFlags==0 ){ |
| 1098 | + if( mFlags & 0x02 ) return 0; | |
| 1091 | 1099 | zDisable1 = " disabled"; |
| 1092 | 1100 | zDisable2 = " disabled"; |
| 1093 | 1101 | zPattern = ""; |
| 1094 | 1102 | }else{ |
| 1095 | 1103 | zDisable1 = ""; /* Was: " autofocus" */ |
| @@ -1101,11 +1109,11 @@ | ||
| 1101 | 1109 | @ <div class='searchForm searchForm%s(zClass)'> |
| 1102 | 1110 | }else{ |
| 1103 | 1111 | @ <div class='searchForm'> |
| 1104 | 1112 | } |
| 1105 | 1113 | @ <input type="text" name="s" size="40" value="%h(zPattern)"%s(zDisable1)> |
| 1106 | - if( useYparam && (srchFlags & (srchFlags-1))!=0 && useYparam ){ | |
| 1114 | + if( (mFlags & 0x01)!=0 && (srchFlags & (srchFlags-1))!=0 ){ | |
| 1107 | 1115 | static const struct { char *z; char *zNm; unsigned m; } aY[] = { |
| 1108 | 1116 | { "all", "All", SRCH_ALL }, |
| 1109 | 1117 | { "c", "Check-ins", SRCH_CKIN }, |
| 1110 | 1118 | { "d", "Docs", SRCH_DOC }, |
| 1111 | 1119 | { "t", "Tickets", SRCH_TKT }, |
| @@ -1146,11 +1154,13 @@ | ||
| 1146 | 1154 | } |
| 1147 | 1155 | if( search_run_and_output(zPattern, srchFlags, fDebug)==0 ){ |
| 1148 | 1156 | @ <p class='searchEmpty'>No matches for: <span>%h(zPattern)</span></p> |
| 1149 | 1157 | } |
| 1150 | 1158 | @ </div> |
| 1159 | + haveResult = 1; | |
| 1151 | 1160 | } |
| 1161 | + return haveResult; | |
| 1152 | 1162 | } |
| 1153 | 1163 | |
| 1154 | 1164 | /* |
| 1155 | 1165 | ** WEBPAGE: search |
| 1156 | 1166 | ** |
| 1157 | 1167 |
| --- src/search.c | |
| +++ src/search.c | |
| @@ -1066,20 +1066,27 @@ | |
| 1066 | ** |
| 1067 | ** This routine automatically restricts srchFlag according to user |
| 1068 | ** permissions and the server configuration. The entry box is shown |
| 1069 | ** disabled if srchFlags is 0 after these restrictions are applied. |
| 1070 | ** |
| 1071 | ** If useYparam is true, then this routine also looks at the y= query |
| 1072 | ** parameter for further search restrictions. |
| 1073 | */ |
| 1074 | void search_screen(unsigned srchFlags, int useYparam){ |
| 1075 | const char *zType = 0; |
| 1076 | const char *zClass = 0; |
| 1077 | const char *zDisable1; |
| 1078 | const char *zDisable2; |
| 1079 | const char *zPattern; |
| 1080 | int fDebug = PB("debug"); |
| 1081 | srchFlags = search_restrict(srchFlags); |
| 1082 | switch( srchFlags ){ |
| 1083 | case SRCH_CKIN: zType = " Check-ins"; zClass = "Ckin"; break; |
| 1084 | case SRCH_DOC: zType = " Docs"; zClass = "Doc"; break; |
| 1085 | case SRCH_TKT: zType = " Tickets"; zClass = "Tkt"; break; |
| @@ -1086,10 +1093,11 @@ | |
| 1086 | case SRCH_WIKI: zType = " Wiki"; zClass = "Wiki"; break; |
| 1087 | case SRCH_TECHNOTE: zType = " Tech Notes"; zClass = "Note"; break; |
| 1088 | case SRCH_FORUM: zType = " Forum"; zClass = "Frm"; break; |
| 1089 | } |
| 1090 | if( srchFlags==0 ){ |
| 1091 | zDisable1 = " disabled"; |
| 1092 | zDisable2 = " disabled"; |
| 1093 | zPattern = ""; |
| 1094 | }else{ |
| 1095 | zDisable1 = ""; /* Was: " autofocus" */ |
| @@ -1101,11 +1109,11 @@ | |
| 1101 | @ <div class='searchForm searchForm%s(zClass)'> |
| 1102 | }else{ |
| 1103 | @ <div class='searchForm'> |
| 1104 | } |
| 1105 | @ <input type="text" name="s" size="40" value="%h(zPattern)"%s(zDisable1)> |
| 1106 | if( useYparam && (srchFlags & (srchFlags-1))!=0 && useYparam ){ |
| 1107 | static const struct { char *z; char *zNm; unsigned m; } aY[] = { |
| 1108 | { "all", "All", SRCH_ALL }, |
| 1109 | { "c", "Check-ins", SRCH_CKIN }, |
| 1110 | { "d", "Docs", SRCH_DOC }, |
| 1111 | { "t", "Tickets", SRCH_TKT }, |
| @@ -1146,11 +1154,13 @@ | |
| 1146 | } |
| 1147 | if( search_run_and_output(zPattern, srchFlags, fDebug)==0 ){ |
| 1148 | @ <p class='searchEmpty'>No matches for: <span>%h(zPattern)</span></p> |
| 1149 | } |
| 1150 | @ </div> |
| 1151 | } |
| 1152 | } |
| 1153 | |
| 1154 | /* |
| 1155 | ** WEBPAGE: search |
| 1156 | ** |
| 1157 |
| --- src/search.c | |
| +++ src/search.c | |
| @@ -1066,20 +1066,27 @@ | |
| 1066 | ** |
| 1067 | ** This routine automatically restricts srchFlag according to user |
| 1068 | ** permissions and the server configuration. The entry box is shown |
| 1069 | ** disabled if srchFlags is 0 after these restrictions are applied. |
| 1070 | ** |
| 1071 | ** The mFlags value controls options: |
| 1072 | ** |
| 1073 | ** 0x01 If the y= query parameter is present, use it as an addition |
| 1074 | ** restriction what to search. |
| 1075 | ** |
| 1076 | ** 0x02 Show nothing if search is disabled. |
| 1077 | ** |
| 1078 | ** Return true if there are search results. |
| 1079 | */ |
| 1080 | int search_screen(unsigned srchFlags, int mFlags){ |
| 1081 | const char *zType = 0; |
| 1082 | const char *zClass = 0; |
| 1083 | const char *zDisable1; |
| 1084 | const char *zDisable2; |
| 1085 | const char *zPattern; |
| 1086 | int fDebug = PB("debug"); |
| 1087 | int haveResult = 0; |
| 1088 | srchFlags = search_restrict(srchFlags); |
| 1089 | switch( srchFlags ){ |
| 1090 | case SRCH_CKIN: zType = " Check-ins"; zClass = "Ckin"; break; |
| 1091 | case SRCH_DOC: zType = " Docs"; zClass = "Doc"; break; |
| 1092 | case SRCH_TKT: zType = " Tickets"; zClass = "Tkt"; break; |
| @@ -1086,10 +1093,11 @@ | |
| 1093 | case SRCH_WIKI: zType = " Wiki"; zClass = "Wiki"; break; |
| 1094 | case SRCH_TECHNOTE: zType = " Tech Notes"; zClass = "Note"; break; |
| 1095 | case SRCH_FORUM: zType = " Forum"; zClass = "Frm"; break; |
| 1096 | } |
| 1097 | if( srchFlags==0 ){ |
| 1098 | if( mFlags & 0x02 ) return 0; |
| 1099 | zDisable1 = " disabled"; |
| 1100 | zDisable2 = " disabled"; |
| 1101 | zPattern = ""; |
| 1102 | }else{ |
| 1103 | zDisable1 = ""; /* Was: " autofocus" */ |
| @@ -1101,11 +1109,11 @@ | |
| 1109 | @ <div class='searchForm searchForm%s(zClass)'> |
| 1110 | }else{ |
| 1111 | @ <div class='searchForm'> |
| 1112 | } |
| 1113 | @ <input type="text" name="s" size="40" value="%h(zPattern)"%s(zDisable1)> |
| 1114 | if( (mFlags & 0x01)!=0 && (srchFlags & (srchFlags-1))!=0 ){ |
| 1115 | static const struct { char *z; char *zNm; unsigned m; } aY[] = { |
| 1116 | { "all", "All", SRCH_ALL }, |
| 1117 | { "c", "Check-ins", SRCH_CKIN }, |
| 1118 | { "d", "Docs", SRCH_DOC }, |
| 1119 | { "t", "Tickets", SRCH_TKT }, |
| @@ -1146,11 +1154,13 @@ | |
| 1154 | } |
| 1155 | if( search_run_and_output(zPattern, srchFlags, fDebug)==0 ){ |
| 1156 | @ <p class='searchEmpty'>No matches for: <span>%h(zPattern)</span></p> |
| 1157 | } |
| 1158 | @ </div> |
| 1159 | haveResult = 1; |
| 1160 | } |
| 1161 | return haveResult; |
| 1162 | } |
| 1163 | |
| 1164 | /* |
| 1165 | ** WEBPAGE: search |
| 1166 | ** |
| 1167 |