Fossil SCM

fossil-scm / src / setup.c
Source Blame History 2572 lines
dbda8d6… drh 1 /*
c19f34c… drh 2 ** Copyright (c) 2007 D. Richard Hipp
dbda8d6… drh 3 **
dbda8d6… drh 4 ** This program is free software; you can redistribute it and/or
c06edd2… drh 5 ** modify it under the terms of the Simplified BSD License (also
c06edd2… drh 6 ** known as the "2-Clause License" or "FreeBSD License".)
ccf50f0… drh 7 **
dbda8d6… drh 8 ** This program is distributed in the hope that it will be useful,
c06edd2… drh 9 ** but without any warranty; without even the implied warranty of
c06edd2… drh 10 ** merchantability or fitness for a particular purpose.
dbda8d6… drh 11 **
dbda8d6… drh 12 ** Author contact information:
dbda8d6… drh 13 ** [email protected]
dbda8d6… drh 14 ** http://www.hwaci.com/drh/
dbda8d6… drh 15 **
dbda8d6… drh 16 *******************************************************************************
dbda8d6… drh 17 **
dbda8d6… drh 18 ** Implementation of the Setup page
dbda8d6… drh 19 */
dbda8d6… drh 20 #include "config.h"
c30cd93… jan.nijtmans 21 #include <assert.h>
dbda8d6… drh 22 #include "setup.h"
dbda8d6… drh 23
3cb9ba4… andygoth 24 /*
7383450… drh 25 ** Increment the "cfgcnt" variable, so that ETags will know that
7383450… drh 26 ** the configuration has changed.
7383450… drh 27 */
7383450… drh 28 void setup_incr_cfgcnt(void){
7383450… drh 29 static int once = 1;
7383450… drh 30 if( once ){
7383450… drh 31 once = 0;
f741baa… drh 32 db_unprotect(PROTECT_CONFIG);
7383450… drh 33 db_multi_exec("UPDATE config SET value=value+1 WHERE name='cfgcnt'");
7383450… drh 34 if( db_changes()==0 ){
7383450… drh 35 db_multi_exec("INSERT INTO config(name,value) VALUES('cfgcnt',1)");
7383450… drh 36 }
f741baa… drh 37 db_protect_pop();
7383450… drh 38 }
7383450… drh 39 }
7383450… drh 40
7383450… drh 41 /*
dbda8d6… drh 42 ** Output a single entry for a menu generated using an HTML table.
b0feaa6… drh 43 ** If zLink is neither NULL nor an empty string, then it is the page that
dbda8d6… drh 44 ** the menu entry will hyperlink to. If zLink is NULL or "", then
dbda8d6… drh 45 ** the menu entry has no hyperlink - it is disabled.
dbda8d6… drh 46 */
d0305b3… aku 47 void setup_menu_entry(
dbda8d6… drh 48 const char *zTitle,
dbda8d6… drh 49 const char *zLink,
b0feaa6… drh 50 const char *zDesc /* Caution! Rendered using %s. May contain raw HTML. */
dbda8d6… drh 51 ){
d0305b3… aku 52 @ <tr><td valign="top" align="right">
dbda8d6… drh 53 if( zLink && zLink[0] ){
b28badb… drh 54 @ <a href="%s(zLink)"><nobr>%h(zTitle)</nobr></a>
dbda8d6… drh 55 }else{
b0feaa6… drh 56 @ <nobr>%h(zTitle)</nobr>
dbda8d6… drh 57 }
b0feaa6… drh 58 @ </td><td width="5"></td><td valign="top">%s(zDesc)</td></tr>
dbda8d6… drh 59 }
dbda8d6… drh 60
c6b2332… drh 61
c6b2332… drh 62
dbda8d6… drh 63 /*
7ab0328… drh 64 ** WEBPAGE: setup
7ab0328… drh 65 **
7d034d3… wyoung 66 ** Main menu for the administrative pages. Requires Admin or Setup
7d034d3… wyoung 67 ** privileges. Links to sub-pages only usable by Setup users are
7d034d3… wyoung 68 ** shown only to Setup users.
dbda8d6… drh 69 */
dbda8d6… drh 70 void setup_page(void){
7d034d3… wyoung 71 int setup_user = 0;
d0305b3… aku 72 login_check_credentials();
7d034d3… wyoung 73 if( !g.perm.Admin ){
653dd40… drh 74 login_needed(0);
766bec0… drh 75 }
7d034d3… wyoung 76 setup_user = g.perm.Setup;
766bec0… drh 77
112c713… drh 78 style_set_current_feature("setup");
766bec0… drh 79 style_header("Server Administration");
65870e8… drh 80
65870e8… drh 81 /* Make sure the header contains <base href="...">. Issue a warning
65870e8… drh 82 ** if it does not. */
65870e8… drh 83 if( !cgi_header_contains("<base href=") ){
65870e8… drh 84 @ <p class="generalError"><b>Configuration Error:</b> Please add
a4e7b86… drh 85 @ <tt>&lt;base href="$secureurl/$current_page"&gt;</tt> after
7001228… drh 86 @ <tt>&lt;head&gt;</tt> in the
7001228… drh 87 @ <a href="setup_skinedit?w=2">HTML header</a>!</p>
65870e8… drh 88 }
c6b2332… drh 89
c6b2332… drh 90 #if !defined(_WIN32)
c6b2332… drh 91 /* Check for /dev/null and /dev/urandom. We want both devices to be present,
c6b2332… drh 92 ** but they are sometimes omitted (by mistake) from chroot jails. */
c6b2332… drh 93 if( access("/dev/null", R_OK|W_OK) ){
c6b2332… drh 94 @ <p class="generalError">WARNING: Device "/dev/null" is not available
c6b2332… drh 95 @ for reading and writing.</p>
c6b2332… drh 96 }
c6b2332… drh 97 if( access("/dev/urandom", R_OK) ){
c6b2332… drh 98 @ <p class="generalError">WARNING: Device "/dev/urandom" is not available
c6b2332… drh 99 @ for reading. This means that the pseudo-random number generator used
c6b2332… drh 100 @ by SQLite will be poorly seeded.</p>
c6b2332… drh 101 }
c6b2332… drh 102 #endif
ca833ff… drh 103
ca833ff… drh 104 @ <table border="0" cellspacing="3">
d0305b3… aku 105 setup_menu_entry("Users", "setup_ulist",
d0305b3… aku 106 "Grant privileges to individual users.");
7d034d3… wyoung 107 if( setup_user ){
7d034d3… wyoung 108 setup_menu_entry("Access", "setup_access",
7d034d3… wyoung 109 "Control access settings.");
7d034d3… wyoung 110 setup_menu_entry("Configuration", "setup_config",
7d034d3… wyoung 111 "Configure the WWW components of the repository");
7d034d3… wyoung 112 }
0268307… drh 113 setup_menu_entry("Security-Audit", "secaudit0",
0268307… drh 114 "Analyze the current configuration for security problems");
7d034d3… wyoung 115 if( setup_user ){
df337eb… drh 116 setup_menu_entry("Robot-Defense", "setup_robot",
df337eb… drh 117 "Settings for configure defense against robots");
7d034d3… wyoung 118 setup_menu_entry("Settings", "setup_settings",
7d034d3… wyoung 119 "Web interface to the \"fossil settings\" command");
cd8c5df… wyoung 120 }
cd8c5df… wyoung 121 setup_menu_entry("Timeline", "setup_timeline",
cd8c5df… wyoung 122 "Timeline display preferences");
6ce705b… drh 123 setup_menu_entry("Tarballs and ZIPs", "setup_download",
6ce705b… drh 124 "Preferences for auto-generated tarballs and ZIP files");
cd8c5df… wyoung 125 if( setup_user ){
7d034d3… wyoung 126 setup_menu_entry("Login-Group", "setup_login_group",
7d034d3… wyoung 127 "Manage single sign-on between this repository and others"
7d034d3… wyoung 128 " on the same server");
7d034d3… wyoung 129 setup_menu_entry("Tickets", "tktsetup",
7d034d3… wyoung 130 "Configure the trouble-ticketing system for this repository");
bf09c3b… drh 131 setup_menu_entry("Wiki", "setup_wiki",
bf09c3b… drh 132 "Configure the wiki for this repository");
bb189a1… drh 133 setup_menu_entry("Interwiki Map", "intermap",
bb189a1… drh 134 "Mapping keywords for interwiki links");
15bc20f… drh 135 setup_menu_entry("Chat", "setup_chat",
15bc20f… drh 136 "Configure the chatroom");
673dc38… stephan 137 setup_menu_entry("Forum", "setup_forum",
673dc38… stephan 138 "Forum config and metrics");
7d034d3… wyoung 139 }
ca833ff… drh 140 setup_menu_entry("Search","srchsetup",
ca833ff… drh 141 "Configure the built-in search engine");
8131f1c… drh 142 setup_menu_entry("URL Aliases", "waliassetup",
8131f1c… drh 143 "Configure URL aliases");
7d034d3… wyoung 144 if( setup_user ){
7d034d3… wyoung 145 setup_menu_entry("Notification", "setup_notification",
7d034d3… wyoung 146 "Automatic notifications of changes via outbound email");
6ce705b… drh 147 #if 0 /* Disabled for now. Does this even work? */
7d034d3… wyoung 148 setup_menu_entry("Transfers", "xfersetup",
7d034d3… wyoung 149 "Configure the transfer system for this repository");
6ce705b… drh 150 #endif
7d034d3… wyoung 151 }
33cc83f… drh 152 setup_menu_entry("Skins", "setup_skin_admin",
106c090… drh 153 "Select and/or modify the web interface \"skins\"");
ba418ee… drh 154 setup_menu_entry("Moderation", "setup_modreq",
ba418ee… drh 155 "Enable/Disable requiring moderator approval of Wiki and/or Ticket"
c89a694… mistachkin 156 " changes and attachments.");
257318c… drh 157 setup_menu_entry("Ad-Unit", "setup_adunit",
257318c… drh 158 "Edit HTML text for an ad unit inserted after the menu bar");
a53beaa… drh 159 setup_menu_entry("URLs & Checkouts", "urllist",
a53beaa… drh 160 "Show URLs used to access this repo and known check-outs");
7d034d3… wyoung 161 if( setup_user ){
7d034d3… wyoung 162 setup_menu_entry("Web-Cache", "cachestat",
7d034d3… wyoung 163 "View the status of the expensive-page cache");
7d034d3… wyoung 164 }
257318c… drh 165 setup_menu_entry("Logo", "setup_logo",
257318c… drh 166 "Change the logo and background images for the server");
a48474b… drh 167 setup_menu_entry("Shunned", "shun",
a48474b… drh 168 "Show artifacts that are shunned by this repository");
b28badb… drh 169 setup_menu_entry("Log Files", "setup-logmenu",
b28badb… drh 170 "A menu of available log files");
ab4c1e2… drh 171 setup_menu_entry("Unversioned Files", "uvlist?byage=1",
ab4c1e2… drh 172 "Show all unversioned files held");
3967d04… drh 173 setup_menu_entry("Stats", "stat",
3967d04… drh 174 "Repository Status Reports");
9fa6808… drh 175 setup_menu_entry("Sitemap", "sitemap",
9fa6808… drh 176 "Links to miscellaneous pages");
7d034d3… wyoung 177 if( setup_user ){
7d034d3… wyoung 178 setup_menu_entry("SQL", "admin_sql",
7d034d3… wyoung 179 "Enter raw SQL commands");
7d034d3… wyoung 180 setup_menu_entry("TH1", "admin_th1",
7d034d3… wyoung 181 "Enter raw TH1 commands");
7d034d3… wyoung 182 }
7d034d3… wyoung 183 @ </table>
7d034d3… wyoung 184
b28badb… drh 185 style_finish_page();
b28badb… drh 186 }
b28badb… drh 187
b28badb… drh 188
b28badb… drh 189 /*
b28badb… drh 190 ** WEBPAGE: setup-logmenu
b28badb… drh 191 **
25f43cc… stephan 192 ** Show a menu of available log renderings accessible to an administrator,
b28badb… drh 193 ** together with a succinct explanation of each.
b28badb… drh 194 **
b28badb… drh 195 ** This page is only accessible by administrators.
b28badb… drh 196 */
b28badb… drh 197 void setup_logmenu_page(void){
b28badb… drh 198 Blob desc;
b0feaa6… drh 199 int bErrLog; /* True if Error Log enabled */
b28badb… drh 200 blob_init(&desc, 0, 0);
b28badb… drh 201
b28badb… drh 202 /* Administrator access only */
b28badb… drh 203 login_check_credentials();
b28badb… drh 204 if( !g.perm.Admin ){
b28badb… drh 205 login_needed(0);
b28badb… drh 206 return;
b28badb… drh 207 }
b28badb… drh 208 style_header("Log Menu");
b28badb… drh 209 @ <table border="0" cellspacing="3">
2771bea… jkosche 210
bdf12f4… drh 211 if( db_get_boolean("admin-log",1)==0 ){
767509f… drh 212 blob_appendf(&desc,
767509f… drh 213 "The admin log records configuration changes to the repository.\n"
767509f… drh 214 "<b>Disabled</b>: Turn on the "
767509f… drh 215 " <a href='%R/setup_settings'>admin-log setting</a> to enable."
767509f… drh 216 );
767509f… drh 217 setup_menu_entry("Admin Log", 0, blob_str(&desc));
767509f… drh 218 blob_reset(&desc);
767509f… drh 219 }else{
767509f… drh 220 setup_menu_entry("Admin Log", "admin_log",
767509f… drh 221 "The admin log records configuration changes to the repository\n"
767509f… drh 222 "in the \"admin_log\" table.\n"
767509f… drh 223 );
767509f… drh 224 }
c675484… drh 225 setup_menu_entry("Xfer Log", "rcvfromlist",
767509f… drh 226 "The artifact log records when new content is added in the\n"
767509f… drh 227 "\"rcvfrom\" table.\n"
767509f… drh 228 );
bdf12f4… drh 229 if( db_get_boolean("access-log",1) ){
767509f… drh 230 setup_menu_entry("User Log", "user_log",
767509f… drh 231 "Login attempts recorded in the \"accesslog\" table."
767509f… drh 232 );
767509f… drh 233 }else{
767509f… drh 234 blob_appendf(&desc,
767509f… drh 235 "Login attempts recorded in the \"accesslog\" table.\n"
767509f… drh 236 "<b>Disabled</b>: Turn on the "
767509f… drh 237 "<a href='%R/setup_settings'>access-log setting</a> to enable."
767509f… drh 238 );
767509f… drh 239 setup_menu_entry("User Log", 0, blob_str(&desc));
767509f… drh 240 blob_reset(&desc);
767509f… drh 241 }
b28badb… drh 242
b28badb… drh 243 blob_appendf(&desc,
767509f… drh 244 "A separate text file to which warning and error\n"
b28badb… drh 245 "messages are appended. A single error log can and often is shared\n"
b28badb… drh 246 "across multiple repositories.\n"
b28badb… drh 247 );
b28badb… drh 248 if( g.zErrlog==0 || fossil_strcmp(g.zErrlog,"-")==0 ){
767509f… drh 249 blob_appendf(&desc,"<b>Disabled</b>: "
767509f… drh 250 "To enable the error log ");
b0feaa6… drh 251 if( fossil_strcmp(g.zCmdName, "cgi")==0 ){
b0feaa6… drh 252 blob_appendf(&desc,
b0feaa6… drh 253 "make an entry like \"errorlog: <i>FILENAME</i>\""
b0feaa6… drh 254 " in the CGI script at %h",
b0feaa6… drh 255 P("SCRIPT_FILENAME")
b0feaa6… drh 256 );
b0feaa6… drh 257 }else{
b0feaa6… drh 258 blob_appendf(&desc,
bd0d442… drh 259 " add the \"--errorlog <i>FILENAME</i>\" option to the\n"
f38866e… drh 260 "\"%h %h\" command that launched the server.",
b0feaa6… drh 261 g.argv[0], g.zCmdName
b0feaa6… drh 262 );
b0feaa6… drh 263 }
b0feaa6… drh 264 bErrLog = 0;
b28badb… drh 265 }else{
767509f… drh 266 blob_appendf(&desc,"In this repository, the error log is the file "
b28badb… drh 267 "named \"%s\".", g.zErrlog);
b0feaa6… drh 268 bErrLog = 1;
b0feaa6… drh 269 }
b0feaa6… drh 270 setup_menu_entry("Error Log", bErrLog ? "errorlog" : 0, blob_str(&desc));
b0feaa6… drh 271 blob_reset(&desc);
b28badb… drh 272
b28badb… drh 273 @ </table>
0a5d0e1… drh 274 style_finish_page();
0a5d0e1… drh 275 }
0a5d0e1… drh 276
dbda8d6… drh 277 /*
dbda8d6… drh 278 ** Generate a checkbox for an attribute.
dbda8d6… drh 279 */
d4e9df1… drh 280 void onoff_attribute(
dbda8d6… drh 281 const char *zLabel, /* The text label on the checkbox */
0a5d0e1… drh 282 const char *zVar, /* The corresponding row in the CONFIG table */
dbda8d6… drh 283 const char *zQParm, /* The query parameter */
0a5d0e1… drh 284 int dfltVal, /* Default value if CONFIG table entry does not exist */
10d8abc… jan.nijtmans 285 int disabled /* 1 if disabled */
dbda8d6… drh 286 ){
dbda8d6… drh 287 const char *zQ = P(zQParm);
671e7c3… drh 288 int iVal = db_get_boolean(zVar, dfltVal);
3cba68a… jan.nijtmans 289 if( zQ==0 && !disabled && P("submit") ){
dbda8d6… drh 290 zQ = "off";
dbda8d6… drh 291 }
dbda8d6… drh 292 if( zQ ){
32ad9a1… drh 293 int iQ = fossil_strcmp(zQ,"on")==0 || atoi(zQ);
920ace1… drh 294 if( iQ!=iVal && cgi_csrf_safe(2) ){
f741baa… drh 295 db_protect_only(PROTECT_NONE);
0a5d0e1… drh 296 db_set(zVar/*works-like:"x"*/, iQ ? "1" : "0", 0);
f741baa… drh 297 db_protect_pop();
0ba0e5e… drh 298 setup_incr_cfgcnt();
f3455a5… drh 299 admin_log("Set option [%q] to [%q].",
f3455a5… drh 300 zVar, iQ ? "on" : "off");
dbda8d6… drh 301 iVal = iQ;
dbda8d6… drh 302 }
dbda8d6… drh 303 }
7dd07b2… drh 304 @ <label><input type="checkbox" name="%s(zQParm)" \
ecab8f4… drh 305 @ aria-label="%h(zLabel[0]?zLabel:zQParm)" \
dbda8d6… drh 306 if( iVal ){
7dd07b2… drh 307 @ checked="checked" \
10d8abc… jan.nijtmans 308 }
10d8abc… jan.nijtmans 309 if( disabled ){
7dd07b2… drh 310 @ disabled="disabled" \
dbda8d6… drh 311 }
f5482a0… wyoung 312 @ > <b>%s(zLabel)</b></label>
dbda8d6… drh 313 }
dbda8d6… drh 314
dbda8d6… drh 315 /*
dbda8d6… drh 316 ** Generate an entry box for an attribute.
dbda8d6… drh 317 */
ac3f1f2… drh 318 void entry_attribute(
dbda8d6… drh 319 const char *zLabel, /* The text label on the entry box */
dbda8d6… drh 320 int width, /* Width of the entry box */
0a5d0e1… drh 321 const char *zVar, /* The corresponding row in the CONFIG table */
f3455a5… drh 322 const char *zQParm, /* The query parameter */
0a5d0e1… drh 323 const char *zDflt, /* Default value if CONFIG table entry does not exist */
f3455a5… drh 324 int disabled /* 1 if disabled */
f3455a5… drh 325 ){
f3455a5… drh 326 const char *zVal = db_get(zVar, zDflt);
f3455a5… drh 327 const char *zQ = P(zQParm);
920ace1… drh 328 if( zQ && fossil_strcmp(zQ,zVal)!=0 && cgi_csrf_safe(2) ){
f3455a5… drh 329 const int nZQ = (int)strlen(zQ);
0ba0e5e… drh 330 setup_incr_cfgcnt();
f741baa… drh 331 db_protect_only(PROTECT_NONE);
0a5d0e1… drh 332 db_set(zVar/*works-like:"x"*/, zQ, 0);
f741baa… drh 333 db_protect_pop();
f3455a5… drh 334 admin_log("Set entry_attribute %Q to: %.*s%s",
f3455a5… drh 335 zVar, 20, zQ, (nZQ>20 ? "..." : ""));
f3455a5… drh 336 zVal = zQ;
f3455a5… drh 337 }
7dd07b2… drh 338 @ <input aria-label="%h(zLabel[0]?zLabel:zQParm)" type="text" \
7dd07b2… drh 339 @ id="%s(zQParm)" name="%s(zQParm)" value="%h(zVal)" size="%d(width)" \
f3455a5… drh 340 if( disabled ){
b77f1aa… drh 341 @ disabled="disabled" \
f3455a5… drh 342 }
f5482a0… wyoung 343 @ > <b>%s(zLabel)</b>
f3455a5… drh 344 }
f3455a5… drh 345
f3455a5… drh 346 /*
f3455a5… drh 347 ** Generate a text box for an attribute.
f3455a5… drh 348 */
106c090… drh 349 const char *textarea_attribute(
f3455a5… drh 350 const char *zLabel, /* The text label on the textarea */
f3455a5… drh 351 int rows, /* Rows in the textarea */
f3455a5… drh 352 int cols, /* Columns in the textarea */
0a5d0e1… drh 353 const char *zVar, /* The corresponding row in the CONFIG table */
f3455a5… drh 354 const char *zQP, /* The query parameter */
0a5d0e1… drh 355 const char *zDflt, /* Default value if CONFIG table entry does not exist */
f3455a5… drh 356 int disabled /* 1 if the textarea should not be editable */
f3455a5… drh 357 ){
5b456cf… jan.nijtmans 358 const char *z = db_get(zVar, zDflt);
f3455a5… drh 359 const char *zQ = P(zQP);
920ace1… drh 360 if( zQ && !disabled && fossil_strcmp(zQ,z)!=0 && cgi_csrf_safe(2) ){
f3455a5… drh 361 const int nZQ = (int)strlen(zQ);
f741baa… drh 362 db_protect_only(PROTECT_NONE);
0a5d0e1… drh 363 db_set(zVar/*works-like:"x"*/, zQ, 0);
f741baa… drh 364 db_protect_pop();
0ba0e5e… drh 365 setup_incr_cfgcnt();
f3455a5… drh 366 admin_log("Set textarea_attribute %Q to: %.*s%s",
f3455a5… drh 367 zVar, 20, zQ, (nZQ>20 ? "..." : ""));
f3455a5… drh 368 z = zQ;
f3455a5… drh 369 }
f3455a5… drh 370 if( rows>0 && cols>0 ){
7dd07b2… drh 371 @ <textarea id="id%s(zQP)" name="%s(zQP)" rows="%d(rows)" \
7dd07b2… drh 372 @ aria-label="%h(zLabel[0]?zLabel:zQP)" \
f3455a5… drh 373 if( disabled ){
7dd07b2… drh 374 @ disabled="disabled" \
f3455a5… drh 375 }
f3455a5… drh 376 @ cols="%d(cols)">%h(z)</textarea>
7dd07b2… drh 377 if( *zLabel ){
f3455a5… drh 378 @ <span class="textareaLabel">%s(zLabel)</span>
f3455a5… drh 379 }
f3455a5… drh 380 }
106c090… drh 381 return z;
f3455a5… drh 382 }
f3455a5… drh 383
f3455a5… drh 384 /*
f3455a5… drh 385 ** Generate a text box for an attribute.
f3455a5… drh 386 */
ccf50f0… drh 387 void multiple_choice_attribute(
f3455a5… drh 388 const char *zLabel, /* The text label on the menu */
0a5d0e1… drh 389 const char *zVar, /* The corresponding row in the CONFIG table */
f3455a5… drh 390 const char *zQP, /* The query parameter */
0a5d0e1… drh 391 const char *zDflt, /* Default value if CONFIG table entry does not exist */
f3455a5… drh 392 int nChoice, /* Number of choices */
4aba9ea… drh 393 const char *const *azChoice /* Choices in pairs (VAR value, Display) */
f3455a5… drh 394 ){
5b456cf… jan.nijtmans 395 const char *z = db_get(zVar, zDflt);
f3455a5… drh 396 const char *zQ = P(zQP);
f3455a5… drh 397 int i;
920ace1… drh 398 if( zQ && fossil_strcmp(zQ,z)!=0 && cgi_csrf_safe(2) ){
f3455a5… drh 399 const int nZQ = (int)strlen(zQ);
95e7351… drh 400 db_unprotect(PROTECT_ALL);
0a5d0e1… drh 401 db_set(zVar/*works-like:"x"*/, zQ, 0);
0ba0e5e… drh 402 setup_incr_cfgcnt();
95e7351… drh 403 db_protect_pop();
f3455a5… drh 404 admin_log("Set multiple_choice_attribute %Q to: %.*s%s",
f3455a5… drh 405 zVar, 20, zQ, (nZQ>20 ? "..." : ""));
f3455a5… drh 406 z = zQ;
f3455a5… drh 407 }
7dd07b2… drh 408 @ <select aria-label="%h(zLabel)" size="1" name="%s(zQP)" id="id%s(zQP)">
3587e45… drh 409 for(i=0; i<nChoice*2; i+=2){
3587e45… drh 410 const char *zSel = fossil_strcmp(azChoice[i],z)==0 ? " selected" : "";
3587e45… drh 411 @ <option value="%h(azChoice[i])"%s(zSel)>%h(azChoice[i+1])</option>
3587e45… drh 412 }
3587e45… drh 413 @ </select> <b>%h(zLabel)</b>
3587e45… drh 414 }
3587e45… drh 415
df337eb… drh 416 /*
df337eb… drh 417 ** Insert code into the current page that allows the user to configure
df337eb… drh 418 ** auto-hyperlink related robot defense settings.
df337eb… drh 419 */
df337eb… drh 420 static void addAutoHyperlinkSettings(void){
df337eb… drh 421 static const char *const azDefenseOpts[] = {
df337eb… drh 422 "0", "Off",
df337eb… drh 423 "2", "UserAgent only",
df337eb… drh 424 "1", "UserAgent and Javascript",
df337eb… drh 425 };
df337eb… drh 426 multiple_choice_attribute(
df337eb… drh 427 "Enable hyperlinks base on User-Agent and/or Javascript",
df337eb… drh 428 "auto-hyperlink", "autohyperlink", "1",
df337eb… drh 429 count(azDefenseOpts)/2, azDefenseOpts);
58a48e3… drh 430 @ <br>
f5482a0… wyoung 431 entry_attribute("Delay in milliseconds before enabling hyperlinks", 5,
f5482a0… wyoung 432 "auto-hyperlink-delay", "ah-delay", "50", 0);
f5482a0… wyoung 433 @ <br>
f5482a0… wyoung 434 onoff_attribute("Also require a mouse event before enabling hyperlinks",
f5482a0… wyoung 435 "auto-hyperlink-mouseover", "ahmo", 0, 0);
58a48e3… drh 436 @ <p>Enable hyperlinks (the equivalent of the "h" permission) for all users,
58a48e3… drh 437 @ including user "nobody" if the request appears to be from a human.
58a48e3… drh 438 @ Disabling hyperlinks helps prevent robots from walking your site and
58a48e3… drh 439 @ soaking up all your CPU and bandwidth.
58a48e3… drh 440 @ If this setting is "UserAgent only" (2) then the
58a48e3… drh 441 @ UserAgent string is the only factor considered. If the value of this
58a48e3… drh 442 @ setting is "UserAgent And Javascript" (1) then Javascript is added that
58a48e3… drh 443 @ runs after the page loads and fills in the href= values of &lt;a&gt;
58a48e3… drh 444 @ elements. In either case, &lt;a&gt; tags are not generated if the
58a48e3… drh 445 @ UserAgent string indicates that the client is a robot.
58a48e3… drh 446 @ (Property: "auto-hyperlink")</p>
58a48e3… drh 447 @
df337eb… drh 448 @ <p>For maximum robot defense, "Delay" should be at least 50 milliseconds
df337eb… drh 449 @ and "require a mouse event" should be turned on. These values only come
df337eb… drh 450 @ into play when the main auto-hyperlink settings is 2 ("UserAgent and
58a48e3… drh 451 @ Javascript").
58a48e3… drh 452 @ (Properties: "auto-hyperlink-delay" and "auto-hyperlink-mouseover")</p>
df337eb… drh 453 @
df337eb… drh 454 @ <p>To see if Javascript-base hyperlink enabling mechanism is working,
58a48e3… drh 455 @ visit the <a href="%R/test-env">/test-env</a> page from a separate
58a48e3… drh 456 @ web browser that is not logged in, even as "anonymous" and verify
df337eb… drh 457 @ that the "g.jsHref" value is "1".</p>
df337eb… drh 458 }
df337eb… drh 459
df337eb… drh 460 /*
df337eb… drh 461 ** WEBPAGE: setup_robot
df337eb… drh 462 **
df337eb… drh 463 ** Settings associated with defense against robots. Requires setup privilege.
df337eb… drh 464 */
df337eb… drh 465 void setup_robots(void){
df337eb… drh 466 login_check_credentials();
df337eb… drh 467 if( !g.perm.Setup ){
df337eb… drh 468 login_needed(0);
df337eb… drh 469 return;
df337eb… drh 470 }
df337eb… drh 471 style_set_current_feature("setup");
df337eb… drh 472 style_header("Robot Defense Settings");
df337eb… drh 473 db_begin_transaction();
df337eb… drh 474 @ <p>A Fossil website can have billions of pages in its tree, even for a
df337eb… drh 475 @ modest project. Many of those pages (examples: diffs and tarballs)
df337eb… drh 476 @ might be expensive to compute. A robot that tries to walk the entire
df337eb… drh 477 @ website can present a crippling CPU and bandwidth load.
df337eb… drh 478 @
4d198d0… drh 479 @ <p>The settings on this page are intended to help administrators
4d198d0… drh 480 @ defend against abusive robots.
df337eb… drh 481 @
df337eb… drh 482 @ <form action="%R/setup_robot" method="post"><div>
df337eb… drh 483 login_insert_csrf_secret();
f5482a0… wyoung 484 @ <input type="submit" name="submit" value="Apply Changes"></p>
f5482a0… wyoung 485 @ <hr>
86b6ef7… drh 486 @ <p><b>Do not allow robots access to these pages.</b><br>
86b6ef7… drh 487 @ If the page name matches the GLOB pattern of this setting, and the
16b3309… drh 488 @ users is "nobody", and the client has not previously passed a captcha
16b3309… drh 489 @ test to show that it is not a robot, then the page is not displayed.
33d3bf3… km 490 @ A captcha test is rendered instead.
4d198d0… drh 491 @ The default value for this setting is:
16b3309… drh 492 @ <p>
16b3309… drh 493 @ &emsp;&emsp;&emsp;<tt>%h(robot_restrict_default())</tt>
16b3309… drh 494 @ <p>
4231598… drh 495 @ Usually the tag should exactly match the page name. Exceptions:
4231598… drh 496 @ <ul>
4231598… drh 497 @ <li> The "diff" tag covers all diffing pages such as /vdiff,
4231598… drh 498 @ /fdiff, and /vpatch.
4231598… drh 499 @ <li> The "annotate" tag covers /annotate and also /blame and
4231598… drh 500 @ /praise.
4231598… drh 501 @ <li> The "zip" covers itself and also /tarball and /sqlar.
4231598… drh 502 @ <li> If a tag has an "X" character appended (ex: "timelineX")
4231598… drh 503 @ then it only applies if query parameters are such that
4231598… drh 504 @ the page is expensive and/or unusual.
4231598… drh 505 @ <li> The "ext" tag covers all extensions, but a tag like
4231598… drh 506 @ "ext/PATH" only covers the specific extension at PATH.
4231598… drh 507 @ </ul>
db69c47… drh 508 @ To disable robot restrictions, change this setting to "off".
4231598… drh 509 @ (Property: <a href="%R/help/robot-restrict">robot-restrict</a>)
16b3309… drh 510 @ <br>
16b3309… drh 511 textarea_attribute("", 2, 80,
16b3309… drh 512 "robot-restrict", "rbrestrict", robot_restrict_default(), 0);
16b3309… drh 513
4d198d0… drh 514 @ <p><b>Exception #1</b><br>
4d198d0… drh 515 @ If "zipX" appears in the robot-restrict list above, then tarballs,
4d198d0… drh 516 @ ZIP-archives, and SQL-archives may be downloaded by robots if
4d198d0… drh 517 @ the check-in is a leaf (robot-zip-leaf):<br>
4d198d0… drh 518 onoff_attribute("Allow tarballs for leaf check-ins",
4d198d0… drh 519 "robot-zip-leaf", "rzleaf", 0, 0);
4d198d0… drh 520
4d198d0… drh 521 @ <p><b>Exception #2</b><br>
4d198d0… drh 522 @ If "zipX" appears in the robot-restrict list above, then tarballs,
4d198d0… drh 523 @ ZIP-archives, and SQL-archives may be downloaded by robots if
4d198d0… drh 524 @ the check-in has one or more tags that match the following
4d198d0… drh 525 @ list of GLOB patterns: (robot-zip-tag)<br>
4d198d0… drh 526 textarea_attribute("", 2, 80,
4d198d0… drh 527 "robot-zip-tag", "rztag", "", 0);
4d198d0… drh 528
4d198d0… drh 529 @ <p><b>Exception #3</b><br>
4d198d0… drh 530 @ If the request URI matches any of the following
4d198d0… drh 531 @ <a href="%R/re_rules">regular expressions</a> (one per line), then the
4d198d0… drh 532 @ request is exempt from anti-robot defenses.
4d198d0… drh 533 @ The regular expression is matched against the REQUEST_URI with the
86b6ef7… drh 534 @ SCRIPT_NAME prefix removed, and with QUERY_STRING appended following
86b6ef7… drh 535 @ a "?" if QUERY_STRING exists. (Property: robot-exception)<br>
86b6ef7… drh 536 textarea_attribute("", 3, 80,
86b6ef7… drh 537 "robot-exception", "rbexcept", "", 0);
de66eea… drh 538 @ <hr>
df337eb… drh 539 addAutoHyperlinkSettings();
7d2b47a… drh 540
7d2b47a… drh 541 @ <hr>
7d2b47a… drh 542 entry_attribute("Anonymous Login Validity", 11, "anon-cookie-lifespan",
7d2b47a… drh 543 "anoncookls", "840", 0);
7d2b47a… drh 544 @ <p>The number of minutes for which an anonymous login cookie is valid.
7d2b47a… drh 545 @ Set to zero to disable anonymous login.
7d2b47a… drh 546 @ (property: anon-cookie-lifespan)
a72e9e1… drh 547
a72e9e1… drh 548 @ <hr>
a72e9e1… drh 549 entry_attribute("Server Load Average Limit", 11, "max-loadavg", "mxldavg",
a72e9e1… drh 550 "0.0", 0);
a72e9e1… drh 551 @ <p>Some expensive operations (such as computing tarballs, zip archives,
a72e9e1… drh 552 @ or annotation/blame pages) are prohibited if the load average on the host
a72e9e1… drh 553 @ computer is too large. Set the threshold for disallowing expensive
a72e9e1… drh 554 @ computations here. Set this to 0.0 to disable the load average limit.
a72e9e1… drh 555 @ This limit is only enforced on Unix servers. On Linux systems,
a72e9e1… drh 556 @ access to the /proc virtual filesystem is required, which means this limit
a72e9e1… drh 557 @ might not work inside a chroot() jail.
a72e9e1… drh 558 @ (Property: "max-loadavg")</p>
16b3309… drh 559 @
f5482a0… wyoung 560 @ <hr>
f5482a0… wyoung 561 @ <p><input type="submit" name="submit" value="Apply Changes"></p>
df337eb… drh 562 @ </div></form>
df337eb… drh 563 db_end_transaction(0);
df337eb… drh 564 style_finish_page();
df337eb… drh 565 }
3587e45… drh 566
3587e45… drh 567 /*
3587e45… drh 568 ** WEBPAGE: setup_access
7ab0328… drh 569 **
7d034d3… wyoung 570 ** The access-control settings page. Requires Setup privileges.
3587e45… drh 571 */
3587e45… drh 572 void setup_access(void){
70a94d0… jan.nijtmans 573 static const char *const azRedirectOpts[] = {
4aba9ea… drh 574 "0", "Off",
4aba9ea… drh 575 "1", "Login Page Only",
4aba9ea… drh 576 "2", "All Pages"
4aba9ea… drh 577 };
3587e45… drh 578 login_check_credentials();
3587e45… drh 579 if( !g.perm.Setup ){
653dd40… drh 580 login_needed(0);
653dd40… drh 581 return;
3587e45… drh 582 }
3587e45… drh 583
112c713… drh 584 style_set_current_feature("setup");
3587e45… drh 585 style_header("Access Control Settings");
e1962ef… drh 586 db_begin_transaction();
a40e8a0… drh 587 @ <form action="%R/setup_access" method="post"><div>
3587e45… drh 588 login_insert_csrf_secret();
f5482a0… wyoung 589 @ <input type="submit" name="submit" value="Apply Changes"></p>
f5482a0… wyoung 590 @ <hr>
4aba9ea… drh 591 multiple_choice_attribute("Redirect to HTTPS",
4aba9ea… drh 592 "redirect-to-https", "redirhttps", "0",
4aba9ea… drh 593 count(azRedirectOpts)/2, azRedirectOpts);
70a94d0… jan.nijtmans 594 @ <p>Force the use of HTTPS by redirecting to HTTPS when an
4aba9ea… drh 595 @ unencrypted request is received. This feature can be enabled
4aba9ea… drh 596 @ for the Login page only, or for all pages.
4aba9ea… drh 597 @ <p>Further details: When enabled, this option causes the $secureurl TH1
a4e7b86… drh 598 @ variable is set to an "https:" variant of $baseurl. Otherwise,
4aba9ea… drh 599 @ $secureurl is just an alias for $baseurl.
4aba9ea… drh 600 @ (Property: "redirect-to-https". "0" for off, "1" for Login page only,
4aba9ea… drh 601 @ "2" otherwise.)
f5482a0… wyoung 602 @ <hr>
3587e45… drh 603 onoff_attribute("Require password for local access",
3587e45… drh 604 "localauth", "localauth", 0, 0);
3587e45… drh 605 @ <p>When enabled, the password sign-in is always required for
3587e45… drh 606 @ web access. When disabled, unrestricted web access from 127.0.0.1
1fee037… drh 607 @ is allowed for the <a href="%R/help/ui">fossil ui</a> command or
1fee037… drh 608 @ from the <a href="%R/help/server">fossil server</a>,
1fee037… drh 609 @ <a href="%R/help/http">fossil http</a> commands when the
3587e45… drh 610 @ "--localauth" command line options is used, or from the
1fee037… drh 611 @ <a href="%R/help/cgi">fossil cgi</a> if a line containing
f7a3c6d… drh 612 @ the word "localauth" appears in the CGI script.
f7a3c6d… drh 613 @
f7a3c6d… drh 614 @ <p>A password is always required if any one or more
f7a3c6d… drh 615 @ of the following are true:
f7a3c6d… drh 616 @ <ol>
f7a3c6d… drh 617 @ <li> This button is checked
f7a3c6d… drh 618 @ <li> The inbound TCP/IP connection is not from 127.0.0.1
f7a3c6d… drh 619 @ <li> The server is started using either of the
1fee037… drh 620 @ <a href="%R/help/server">fossil server</a> or
1fee037… drh 621 @ <a href="%R/help/server">fossil http</a> commands
f7a3c6d… drh 622 @ without the "--localauth" option.
f7a3c6d… drh 623 @ <li> The server is started from CGI without the "localauth" keyword
f7a3c6d… drh 624 @ in the CGI script.
f7a3c6d… drh 625 @ </ol>
3ca935e… drh 626 @ (Property: "localauth")
4d32db8… drh 627 @
f5482a0… wyoung 628 @ <hr>
caf286d… drh 629 onoff_attribute("Enable /test-env",
10d8abc… jan.nijtmans 630 "test_env_enable", "test_env_enable", 0, 0);
4d32db8… drh 631 @ <p>When enabled, the %h(g.zBaseURL)/test_env URL is available to all
4d32db8… drh 632 @ users. When disabled (the default) only users Admin and Setup can visit
4d32db8… drh 633 @ the /test_env page.
3ca935e… drh 634 @ (Property: "test_env_enable")
3ca935e… drh 635 @ </p>
3ca935e… drh 636 @
f5482a0… wyoung 637 @ <hr>
86619b9… drh 638 onoff_attribute("Enable /artifact_stats",
86619b9… drh 639 "artifact_stats_enable", "artifact_stats_enable", 0, 0);
86619b9… drh 640 @ <p>When enabled, the %h(g.zBaseURL)/artifact_stats URL is available to all
86619b9… drh 641 @ users. When disabled (the default) only users with check-in privilege may
86619b9… drh 642 @ access the /artifact_stats page.
86619b9… drh 643 @ (Property: "artifact_stats_enable")
86619b9… drh 644 @ </p>
86619b9… drh 645 @
f5482a0… wyoung 646 @ <hr>
6454153… drh 647 onoff_attribute("Allow REMOTE_USER authentication",
10d8abc… jan.nijtmans 648 "remote_user_ok", "remote_user_ok", 0, 0);
6454153… drh 649 @ <p>When enabled, if the REMOTE_USER environment variable is set to the
6454153… drh 650 @ login name of a valid user and no other login credentials are available,
6454153… drh 651 @ then the REMOTE_USER is accepted as an authenticated user.
3ca935e… drh 652 @ (Property: "remote_user_ok")
313ba5c… drh 653 @ </p>
313ba5c… drh 654 @
f5482a0… wyoung 655 @ <hr>
315cf24… drh 656 onoff_attribute("Allow HTTP_AUTHENTICATION authentication",
315cf24… drh 657 "http_authentication_ok", "http_authentication_ok", 0, 0);
315cf24… drh 658 @ <p>When enabled, allow the use of the HTTP_AUTHENTICATION environment
315cf24… drh 659 @ variable or the "Authentication:" HTTP header to find the username and
7dd07b2… drh 660 @ password. This is another way of supporting Basic Authentication.
3ca935e… drh 661 @ (Property: "http_authentication_ok")
3243e63… drh 662 @ </p>
4d32db8… drh 663 @
f5482a0… wyoung 664 @ <hr>
10d8abc… jan.nijtmans 665 entry_attribute("Login expiration time", 6, "cookie-expire", "cex",
10d8abc… jan.nijtmans 666 "8766", 0);
dbda8d6… drh 667 @ <p>The number of hours for which a login is valid. This must be a
97f68e6… mistachkin 668 @ positive number. The default is 8766 hours which is approximately equal
3ca935e… drh 669 @ to a year.
3ca935e… drh 670 @ (Property: "cookie-expire")</p>
dbdc160… aku 671
f5482a0… wyoung 672 @ <hr>
dbdc160… aku 673 entry_attribute("Download packet limit", 10, "max-download", "mxdwn",
10d8abc… jan.nijtmans 674 "5000000", 0);
dbdc160… aku 675 @ <p>Fossil tries to limit out-bound sync, clone, and pull packets
dbdc160… aku 676 @ to this many bytes, uncompressed. If the client requires more data
dbdc160… aku 677 @ than this, then the client will issue multiple HTTP requests.
6454153… drh 678 @ Values below 1 million are not recommended. 5 million is a
3ca935e… drh 679 @ reasonable number. (Property: "max-download")</p>
769c90a… drh 680
f5482a0… wyoung 681 @ <hr>
769c90a… drh 682 entry_attribute("Download time limit", 11, "max-download-time", "mxdwnt",
10d8abc… jan.nijtmans 683 "30", 0);
769c90a… drh 684
769c90a… drh 685 @ <p>Fossil tries to spend less than this many seconds gathering
769c90a… drh 686 @ the out-bound data of sync, clone, and pull packets.
769c90a… drh 687 @ If the client request takes longer, a partial reply is given similar
3ca935e… drh 688 @ to the download packet limit. 30s is a reasonable default.
3ca935e… drh 689 @ (Property: "max-download-time")</p>
5e26a1b… drh 690
e5c0543… drh 691 @ <a id="slal"></a>
f5482a0… wyoung 692 @ <hr>
5e26a1b… drh 693 entry_attribute("Server Load Average Limit", 11, "max-loadavg", "mxldavg",
5e26a1b… drh 694 "0.0", 0);
5e26a1b… drh 695 @ <p>Some expensive operations (such as computing tarballs, zip archives,
5e26a1b… drh 696 @ or annotation/blame pages) are prohibited if the load average on the host
5e26a1b… drh 697 @ computer is too large. Set the threshold for disallowing expensive
5e26a1b… drh 698 @ computations here. Set this to 0.0 to disable the load average limit.
5e26a1b… drh 699 @ This limit is only enforced on Unix servers. On Linux systems,
5e26a1b… drh 700 @ access to the /proc virtual filesystem is required, which means this limit
3ca935e… drh 701 @ might not work inside a chroot() jail.
3ca935e… drh 702 @ (Property: "max-loadavg")</p>
3ca935e… drh 703
df337eb… drh 704 /* Add the auto-hyperlink settings controls. These same controls
df337eb… drh 705 ** are also accessible from the /setup_robot page.
df337eb… drh 706 */
f5482a0… wyoung 707 @ <hr>
df337eb… drh 708 addAutoHyperlinkSettings();
df337eb… drh 709
f5482a0… wyoung 710 @ <hr>
82b8587… drh 711 onoff_attribute("Require a CAPTCHA if not logged in",
10d8abc… jan.nijtmans 712 "require-captcha", "reqcapt", 1, 0);
82b8587… drh 713 @ <p>Require a CAPTCHA for edit operations (appending, creating, or
82b8587… drh 714 @ editing wiki or tickets or adding attachments to wiki or tickets)
3ca935e… drh 715 @ for users who are not logged in. (Property: "require-captcha")</p>
82b8587… drh 716
f5482a0… wyoung 717 @ <hr>
79ef961… drh 718 entry_attribute("Public pages", 30, "public-pages",
10d8abc… jan.nijtmans 719 "pubpage", "", 0);
79ef961… drh 720 @ <p>A comma-separated list of glob patterns for pages that are accessible
79ef961… drh 721 @ without needing a login and using the privileges given by the
275da70… danield 722 @ "Default privileges" setting below.
0c37445… drh 723 @
0c37445… drh 724 @ <p>Example use case: Set this field to "/doc/trunk/www/*" and set
0c37445… drh 725 @ the "Default privileges" to include the "o" privilege
0c37445… drh 726 @ to give anonymous users read-only permission to the
79ef961… drh 727 @ latest version of the embedded documentation in the www/ folder without
79ef961… drh 728 @ allowing them to see the rest of the source code.
3ca935e… drh 729 @ (Property: "public-pages")
98cc520… drh 730 @ </p>
9039a6a… drh 731
f5482a0… wyoung 732 @ <hr>
9039a6a… drh 733 onoff_attribute("Allow users to register themselves",
c00e912… drh 734 "self-register", "selfreg", 0, 0);
c00e912… drh 735 @ <p>Allow users to register themselves on the /register webpage.
c00e912… drh 736 @ A self-registration creates a new entry in the USER table and
c00e912… drh 737 @ perhaps also in the SUBSCRIBER table if email notification is
c00e912… drh 738 @ enabled.
c00e912… drh 739 @ (Property: "self-register")</p>
c00e912… drh 740
f5482a0… wyoung 741 @ <hr>
07bfe3f… drh 742 onoff_attribute("Allow users to reset their own passwords",
07bfe3f… drh 743 "self-pw-reset", "selfpw", 0, 0);
07bfe3f… drh 744 @ <p>Allow users to request that an email contains a hyperlink to a
07bfe3f… drh 745 @ password reset page be sent to their email address of record. This
07bfe3f… drh 746 @ enables forgetful users to recover their forgotten passwords without
07bfe3f… drh 747 @ administrator intervention.
07bfe3f… drh 748 @ (Property: "self-pw-reset")</p>
07bfe3f… drh 749
f5482a0… wyoung 750 @ <hr>
c00e912… drh 751 onoff_attribute("Email verification required for self-registration",
c00e912… drh 752 "selfreg-verify", "sfverify", 0, 0);
c00e912… drh 753 @ <p>If enabled, self-registration creates a new entry in the USER table
c00e912… drh 754 @ with only capabilities "7". The default user capabilities are not
c00e912… drh 755 @ added until the email address associated with the self-registration
c00e912… drh 756 @ has been verified. This setting only makes sense if
c00e912… drh 757 @ email notifications are enabled.
c00e912… drh 758 @ (Property: "selfreg-verify")</p>
c00e912… drh 759
f5482a0… wyoung 760 @ <hr>
c00e912… drh 761 onoff_attribute("Allow anonymous subscriptions",
c00e912… drh 762 "anon-subscribe", "anonsub", 1, 0);
c00e912… drh 763 @ <p>If disabled, email notification subscriptions are only allowed
c00e912… drh 764 @ for users with a login. If Nobody or Anonymous visit the /subscribe
c00e912… drh 765 @ page, they are redirected to /register or /login.
c00e912… drh 766 @ (Property: "anon-subscribe")</p>
c00e912… drh 767
f5482a0… wyoung 768 @ <hr>
c00e912… drh 769 entry_attribute("Authorized subscription email addresses", 35,
c00e912… drh 770 "auth-sub-email", "asemail", "", 0);
c00e912… drh 771 @ <p>This is a comma-separated list of GLOB patterns that specify
c00e912… drh 772 @ email addresses that are authorized to subscriptions. If blank
c00e912… drh 773 @ (the usual case), then any email address can be used to self-register.
c00e912… drh 774 @ This setting is used to limit subscriptions to members of a particular
c00e912… drh 775 @ organization or group based on their email address.
c00e912… drh 776 @ (Property: "auth-sub-email")</p>
c00e912… drh 777
f5482a0… wyoung 778 @ <hr>
a257fde… drh 779 entry_attribute("Default privileges", 10, "default-perms",
10d8abc… jan.nijtmans 780 "defaultperms", "u", 0);
79ef961… drh 781 @ <p>Permissions given to users that... <ul><li>register themselves using
79ef961… drh 782 @ the self-registration procedure (if enabled), or <li>access "public"
79ef961… drh 783 @ pages identified by the public-pages glob pattern above, or <li>
79ef961… drh 784 @ are users newly created by the administrator.</ul>
99fcc43… drh 785 @ <p>Recommended value: "u" for Reader.
99fcc43… drh 786 @ <a href="%R/setup_ucap_list">Capability Key</a>.
3ca935e… drh 787 @ (Property: "default-perms")
9039a6a… drh 788 @ </p>
6454153… drh 789
f5482a0… wyoung 790 @ <hr>
6454153… drh 791 onoff_attribute("Show javascript button to fill in CAPTCHA",
10d8abc… jan.nijtmans 792 "auto-captcha", "autocaptcha", 0, 0);
6454153… drh 793 @ <p>When enabled, a button appears on the login screen for user
6454153… drh 794 @ "anonymous" that will automatically fill in the CAPTCHA password.
13920cd… drh 795 @ This is less secure than forcing the user to do it manually, but is
6454153… drh 796 @ probably secure enough and it is certainly more convenient for
3ca935e… drh 797 @ anonymous users. (Property: "auto-captcha")</p>
caf286d… drh 798
caf286d… drh 799 @ <hr>
7d2b47a… drh 800 entry_attribute("Anonymous Login Validity", 11, "anon-cookie-lifespan",
7d2b47a… drh 801 "anoncookls", "840", 0);
7d2b47a… drh 802 @ <p>The number of minutes for which an anonymous login cookie is valid.
7d2b47a… drh 803 @ Set to zero to disable anonymous logins.
7d2b47a… drh 804 @ (property: anon-cookie-lifespan)
7d2b47a… drh 805
7d2b47a… drh 806 @ <hr>
f5482a0… wyoung 807 @ <p><input type="submit" name="submit" value="Apply Changes"></p>
3243e63… drh 808 @ </div></form>
d0305b3… aku 809 db_end_transaction(0);
112c713… drh 810 style_finish_page();
a257fde… drh 811 }
a257fde… drh 812
a257fde… drh 813 /*
a257fde… drh 814 ** WEBPAGE: setup_login_group
7ab0328… drh 815 **
7ab0328… drh 816 ** Change how the current repository participates in a login
7ab0328… drh 817 ** group.
a257fde… drh 818 */
a257fde… drh 819 void setup_login_group(void){
a257fde… drh 820 const char *zGroup;
a257fde… drh 821 char *zErrMsg = 0;
4420efd… drh 822 Stmt q;
a257fde… drh 823 Blob fullName;
a257fde… drh 824 char *zSelfRepo;
a257fde… drh 825 const char *zRepo = PD("repo", "");
a257fde… drh 826 const char *zLogin = PD("login", "");
a257fde… drh 827 const char *zPw = PD("pw", "");
a257fde… drh 828 const char *zNewName = PD("newname", "New Login Group");
a257fde… drh 829
a257fde… drh 830 login_check_credentials();
b344d3c… drh 831 if( !g.perm.Setup ){
653dd40… drh 832 login_needed(0);
653dd40… drh 833 return;
a257fde… drh 834 }
135ed93… drh 835 file_canonical_name(g.zRepositoryName, &fullName, 0);
49b0ff1… drh 836 zSelfRepo = fossil_strdup(blob_str(&fullName));
a257fde… drh 837 blob_reset(&fullName);
a257fde… drh 838 if( P("join")!=0 ){
c3ba504… drh 839 login_group_join(zRepo, 1, zLogin, zPw, zNewName, &zErrMsg);
a257fde… drh 840 }else if( P("leave") ){
a257fde… drh 841 login_group_leave(&zErrMsg);
acfaf4e… drh 842 }else if( P("rotate") ){
acfaf4e… drh 843 captcha_secret_rotate();
a257fde… drh 844 }
112c713… drh 845 style_set_current_feature("setup");
a257fde… drh 846 style_header("Login Group Configuration");
a257fde… drh 847 if( zErrMsg ){
a257fde… drh 848 @ <p class="generalError">%s(zErrMsg)</p>
a257fde… drh 849 }
a257fde… drh 850 zGroup = login_group_name();
a257fde… drh 851 if( zGroup==0 ){
a257fde… drh 852 @ <p>This repository (in the file named "%h(zSelfRepo)")
a257fde… drh 853 @ is not currently part of any login-group.
a257fde… drh 854 @ To join a login group, fill out the form below.</p>
a257fde… drh 855 @
a40e8a0… drh 856 @ <form action="%R/setup_login_group" method="post"><div>
a257fde… drh 857 login_insert_csrf_secret();
7a8938a… drh 858 @ <blockquote><table border="0">
7a8938a… drh 859 @
7dd07b2… drh 860 @ <tr><th align="right" id="rfigtj">Repository filename \
7dd07b2… drh 861 @ in group to join:</th>
7dd07b2… drh 862 @ <td width="5"></td><td>
7dd07b2… drh 863 @ <input aria-labelledby="rfigtj" type="text" size="50" \
7dd07b2… drh 864 @ value="%h(zRepo)" name="repo"></td></tr>
7dd07b2… drh 865 @
7dd07b2… drh 866 @ <tr><th align="right" id="lotar">Login on the above repo:</th>
7dd07b2… drh 867 @ <td width="5"></td><td>
7dd07b2… drh 868 @ <input aria-labelledby="lotar" type="text" size="20" \
7dd07b2… drh 869 @ value="%h(zLogin)" name="login"></td></tr>
7dd07b2… drh 870 @
7dd07b2… drh 871 @ <tr><th align="right" id="lgpw">Password:</th>
7dd07b2… drh 872 @ <td width="5"></td><td>
7dd07b2… drh 873 @ <input aria-labelledby="lgpw" type="password" size="20" name="pw">\
7dd07b2… drh 874 @ </td></tr>
7dd07b2… drh 875 @
7dd07b2… drh 876 @ <tr><th align="right" id="nolg">Name of login-group:</th>
7dd07b2… drh 877 @ <td width="5"></td><td>
7dd07b2… drh 878 @ <input aria-labelledby="nolg" type="text" size="30" \
7dd07b2… drh 879 @ value="%h(zNewName)" name="newname">
a257fde… drh 880 @ (only used if creating a new login-group).</td></tr>
a257fde… drh 881 @
a257fde… drh 882 @ <tr><td colspan="3" align="center">
a257fde… drh 883 @ <input type="submit" value="Join" name="join"></td></tr>
7a8938a… drh 884 @ </table></blockquote></div></form>
a257fde… drh 885 }else{
a257fde… drh 886 int n = 0;
a257fde… drh 887 @ <p>This repository (in the file "%h(zSelfRepo)")
a257fde… drh 888 @ is currently part of the "<b>%h(zGroup)</b>" login group.
a257fde… drh 889 @ Other repositories in that group are:</p>
a257fde… drh 890 @ <table border="0" cellspacing="4">
a257fde… drh 891 @ <tr><td colspan="2"><th align="left">Project Name<td>
a257fde… drh 892 @ <th align="left">Repository File</tr>
a257fde… drh 893 db_prepare(&q,
a257fde… drh 894 "SELECT value,"
a257fde… drh 895 " (SELECT value FROM config"
a257fde… drh 896 " WHERE name=('peer-name-' || substr(x.name,11)))"
a257fde… drh 897 " FROM config AS x"
a257fde… drh 898 " WHERE name GLOB 'peer-repo-*'"
a257fde… drh 899 " ORDER BY value"
a257fde… drh 900 );
a257fde… drh 901 while( db_step(&q)==SQLITE_ROW ){
a257fde… drh 902 const char *zRepo = db_column_text(&q, 0);
a257fde… drh 903 const char *zTitle = db_column_text(&q, 1);
a257fde… drh 904 n++;
a257fde… drh 905 @ <tr><td align="right">%d(n).</td><td width="4">
a257fde… drh 906 @ <td>%h(zTitle)<td width="10"><td>%h(zRepo)</tr>
a257fde… drh 907 }
a257fde… drh 908 db_finalize(&q);
a257fde… drh 909 @ </table>
a257fde… drh 910 @
a40e8a0… drh 911 @ <p><form action="%R/setup_login_group" method="post"><div>
a257fde… drh 912 login_insert_csrf_secret();
acfaf4e… drh 913 @ <p>To leave this login group press:
a257fde… drh 914 @ <input type="submit" value="Leave Login Group" name="leave">
404f155… drh 915 @ <p>Setting a common captcha-secret on all repositories in the login-group
404f155… drh 916 @ allows anonymous logins for one repository in the login group to be used
404f155… drh 917 @ by all other repositories of the group within the same domain. Warning:
404f155… drh 918 @ If a captcha dialog was painted before setting the common captcha-secret
404f155… drh 919 @ and the "Speak password for 'anonymous'" button is pressed afterwards,
404f155… drh 920 @ the spoken text will be incorrect.
404f155… drh 921 @ <input type="submit" name="rotate" value="Set common captcha-secret">
a257fde… drh 922 @ </form></p>
4420efd… drh 923 }
4420efd… drh 924 @ <hr><h2>Implementation Details</h2>
4420efd… drh 925 @ <p>The following are fields from the CONFIG table related to login-groups.
4420efd… drh 926 @ </p>
4420efd… drh 927 @ <table border='1' cellspacing="0" cellpadding="4"\
4420efd… drh 928 @ class='sortable' data-column-types='ttt' data-init-sort='1'>
4420efd… drh 929 @ <thead><tr>
4420efd… drh 930 @ <th>Config.Name<th>Config.Value<th>Config.mtime</tr>
4420efd… drh 931 @ </thead><tbody>
4420efd… drh 932 db_prepare(&q, "SELECT name, value, datetime(mtime,'unixepoch') FROM config"
4420efd… drh 933 " WHERE name GLOB 'peer-*'"
4420efd… drh 934 " OR name GLOB 'project-*'"
4420efd… drh 935 " OR name GLOB 'login-group-*'"
4420efd… drh 936 " ORDER BY name");
4420efd… drh 937 while( db_step(&q)==SQLITE_ROW ){
4420efd… drh 938 @ <tr><td>%h(db_column_text(&q,0))</td>
4420efd… drh 939 @ <td>%h(db_column_text(&q,1))</td>
4420efd… drh 940 @ <td>%h(db_column_text(&q,2))</td></tr>
4420efd… drh 941 }
4420efd… drh 942 db_finalize(&q);
4420efd… drh 943 @ </tbody></table>
5bb4cee… drh 944 @ <h2>Interpretation</h2>
5bb4cee… drh 945 @ <ul>
5bb4cee… drh 946 @ <li><p><b>login-group-code</b> &rarr;
5bb4cee… drh 947 @ A random code assigned to each login-group. The login-group-code is
5bb4cee… drh 948 @ a unique identifier for the login-group.
5bb4cee… drh 949 @
5bb4cee… drh 950 @ <li><p><b>login-group-name</b> &rarr;
5bb4cee… drh 951 @ The human-readable name of the login-group.
5bb4cee… drh 952 @
5bb4cee… drh 953 @ <li><p><b>project-code</b> &rarr;
5bb4cee… drh 954 @ A random code assigned to each project. The project-code is
5bb4cee… drh 955 @ a unique identifier for the project. Multiple repositories can share
5bb4cee… drh 956 @ the same project-code. When two or more repositories have the same
5bb4cee… drh 957 @ project code, that mean those repositories are clones of each other.
5bb4cee… drh 958 @ Repositories are only able to sync if they share the same project-code.
5bb4cee… drh 959 @
5bb4cee… drh 960 @ <li><p><b>project-description</b> &rarr;
5bb4cee… drh 961 @ A description of project in this repository. This is a verbose form
5bb4cee… drh 962 @ of project-name. This description can be edited in the second entry
5bb4cee… drh 963 @ box on the <a href="./setup_config">Setup/Configuration page</a>.
5bb4cee… drh 964 @
5bb4cee… drh 965 @ <li><p><b>project-name</b> &rarr;
5bb4cee… drh 966 @ The human-readable name for the project. The project-name can be
25f43cc… stephan 967 @ modified in the first entry on the
5bb4cee… drh 968 @ <a href="./setup_config">Setup/Configuration page</a>.
5bb4cee… drh 969 @
5bb4cee… drh 970 @ <li><p><b>peer-repo-<i>CODE</i></b> &rarr;
5bb4cee… drh 971 @ <i>CODE</i> is 16-character prefix of the project-code for another
5bb4cee… drh 972 @ repository that is part of the same login-group. The value is the
5bb4cee… drh 973 @ filename for the peer repository.
5bb4cee… drh 974 @
5bb4cee… drh 975 @ <li><p><b>peer-name-<i>CODE</i></b> &rarr;
5bb4cee… drh 976 @ <i>CODE</i> is 16-character prefix of the project-code for another
5bb4cee… drh 977 @ repository that is part of the same login-group. The value is
5bb4cee… drh 978 @ project-name value for the other repository.
5bb4cee… drh 979 @ </ul>
4420efd… drh 980 style_table_sorter();
112c713… drh 981 style_finish_page();
d0305b3… aku 982 }
d0305b3… aku 983
d0305b3… aku 984 /*
d0305b3… aku 985 ** WEBPAGE: setup_timeline
7ab0328… drh 986 **
7ab0328… drh 987 ** Edit administrative settings controlling the display of
7ab0328… drh 988 ** timelines.
c7c81df… drh 989 */
c7c81df… drh 990 void setup_timeline(void){
41c3c19… drh 991 double tmDiff;
41c3c19… drh 992 char zTmDiff[20];
214899a… jan.nijtmans 993 static const char *const azTimeFormats[] = {
403d937… drh 994 "0", "HH:MM",
403d937… drh 995 "1", "HH:MM:SS",
feef2d1… stephan 996 "2", "YYYY-MM-DD HH:MM",
e5176d9… drh 997 "3", "YYMMDD HH:MM",
e5176d9… drh 998 "4", "(off)"
e5176d9… drh 999 };
6ce705b… drh 1000 static const char *const azLeafMark[] = {
6ce705b… drh 1001 "0", "No",
6ce705b… drh 1002 "1", "Yes",
6ce705b… drh 1003 "2", "Yes - with emphasis",
6ce705b… drh 1004 };
c7c81df… drh 1005 login_check_credentials();
cd8c5df… wyoung 1006 if( !g.perm.Admin ){
653dd40… drh 1007 login_needed(0);
653dd40… drh 1008 return;
c7c81df… drh 1009 }
c7c81df… drh 1010
112c713… drh 1011 style_set_current_feature("setup");
c7c81df… drh 1012 style_header("Timeline Display Preferences");
e1962ef… drh 1013 db_begin_transaction();
a40e8a0… drh 1014 @ <form action="%R/setup_timeline" method="post"><div>
0be5482… drh 1015 login_insert_csrf_secret();
f5482a0… wyoung 1016 @ <p><input type="submit" name="submit" value="Apply Changes"></p>
f5482a0… wyoung 1017
f5482a0… wyoung 1018 @ <hr>
90e928d… drh 1019 onoff_attribute("Plaintext comments on timelines",
10d8abc… jan.nijtmans 1020 "timeline-plaintext", "tpt", 0, 0);
90e928d… drh 1021 @ <p>In timeline displays, check-in comments are displayed literally,
3ca935e… drh 1022 @ without any wiki or HTML interpretation. Use CSS to change
3ca935e… drh 1023 @ display formatting features such as fonts and line-wrapping behavior.
3ca935e… drh 1024 @ (Property: "timeline-plaintext")</p>
9610121… drh 1025
f5482a0… wyoung 1026 @ <hr>
8af0255… drh 1027 onoff_attribute("Truncate comment at first blank line (Git-style)",
9610121… drh 1028 "timeline-truncate-at-blank", "ttb", 0, 0);
9610121… drh 1029 @ <p>In timeline displays, check-in comments are displayed only through
8af0255… drh 1030 @ the first blank line. This is the traditional way to display comments
8af0255… drh 1031 @ in Git repositories (Property: "timeline-truncate-at-blank")</p>
8af0255… drh 1032
f5482a0… wyoung 1033 @ <hr>
8af0255… drh 1034 onoff_attribute("Break comments at newline characters",
8af0255… drh 1035 "timeline-hard-newlines", "thnl", 0, 0);
8af0255… drh 1036 @ <p>In timeline displays, newline characters in check-in comments force
8af0255… drh 1037 @ a line break on the display.
8af0255… drh 1038 @ (Property: "timeline-hard-newlines")</p>
620e1e0… drh 1039
620e1e0… drh 1040 @ <hr>
620e1e0… drh 1041 onoff_attribute("Do not adjust user-selected background colors",
620e1e0… drh 1042 "raw-bgcolor", "rbgc", 0, 0);
620e1e0… drh 1043 @ <p>Fossil normally attempts to adjust the saturation and intensity of
620e1e0… drh 1044 @ user-specified background colors on check-ins and branches so that the
620e1e0… drh 1045 @ foreground text is easily readable on all skins. Enable this setting
620e1e0… drh 1046 @ to omit that adjustment and use exactly the background color specified
620e1e0… drh 1047 @ by users.
620e1e0… drh 1048 @ (Property: "raw-bgcolor")</p>
f5482a0… wyoung 1049
f5482a0… wyoung 1050 @ <hr>
d23b8ba… drh 1051 onoff_attribute("Use Universal Coordinated Time (UTC)",
10d8abc… jan.nijtmans 1052 "timeline-utc", "utc", 1, 0);
d23b8ba… drh 1053 @ <p>Show times as UTC (also sometimes called Greenwich Mean Time (GMT) or
41c3c19… drh 1054 @ Zulu) instead of in local time. On this server, local time is currently
41c3c19… drh 1055 tmDiff = db_double(0.0, "SELECT julianday('now')");
3ba9a4d… jan.nijtmans 1056 tmDiff = db_double(0.0,
41c3c19… drh 1057 "SELECT (julianday(%.17g,'localtime')-julianday(%.17g))*24.0",
41c3c19… drh 1058 tmDiff, tmDiff);
41c3c19… drh 1059 sqlite3_snprintf(sizeof(zTmDiff), zTmDiff, "%.1f", tmDiff);
41c3c19… drh 1060 if( strcmp(zTmDiff, "0.0")==0 ){
41c3c19… drh 1061 @ the same as UTC and so this setting will make no difference in
41c3c19… drh 1062 @ the display.</p>
41c3c19… drh 1063 }else if( tmDiff<0.0 ){
41c3c19… drh 1064 sqlite3_snprintf(sizeof(zTmDiff), zTmDiff, "%.1f", -tmDiff);
41c3c19… drh 1065 @ %s(zTmDiff) hours behind UTC.</p>
41c3c19… drh 1066 }else{
41c3c19… drh 1067 @ %s(zTmDiff) hours ahead of UTC.</p>
41c3c19… drh 1068 }
3ca935e… drh 1069 @ <p>(Property: "timeline-utc")
895eac4… drh 1070
f5482a0… wyoung 1071 @ <hr>
895eac4… drh 1072 multiple_choice_attribute("Style", "timeline-default-style",
895eac4… drh 1073 "tdss", "0", N_TIMELINE_VIEW_STYLE, timeline_view_styles);
895eac4… drh 1074 @ <p>The default timeline viewing style, for when the user has not
895eac4… drh 1075 @ specified an alternative. (Property: "timeline-default-style")</p>
895eac4… drh 1076
f5482a0… wyoung 1077 @ <hr>
8efc4d5… drh 1078 entry_attribute("Default Number Of Rows", 6, "timeline-default-length",
8efc4d5… drh 1079 "tldl", "50", 0);
8efc4d5… drh 1080 @ <p>The maximum number of rows to show on a timeline in the absence
8efc4d5… drh 1081 @ of a user display preference cookie setting or an explicit n= query
8efc4d5… drh 1082 @ parameter. (Property: "timeline-default-length")</p>
8efc4d5… drh 1083
f5482a0… wyoung 1084 @ <hr>
e5176d9… drh 1085 multiple_choice_attribute("Per-Item Time Format", "timeline-date-format",
3cb9ba4… andygoth 1086 "tdf", "0", count(azTimeFormats)/2, azTimeFormats);
403d937… drh 1087 @ <p>If the "HH:MM" or "HH:MM:SS" format is selected, then the date is shown
7001228… drh 1088 @ in a separate box (using CSS class "timelineDate") whenever the date
7001228… drh 1089 @ changes. With the "YYYY-MM-DD&nbsp;HH:MM" and "YYMMDD ..." formats,
7001228… drh 1090 @ the complete date and time is shown on every timeline entry using the
ccf50f0… drh 1091 @ CSS class "timelineTime". (Property: "timeline-date-format")</p>
6ce705b… drh 1092
6ce705b… drh 1093 @ <hr>
6ce705b… drh 1094 multiple_choice_attribute("Leaf Markings", "timeline-mark-leaves",
6ce705b… drh 1095 "tml", "1", count(azLeafMark)/2, azLeafMark);
6ce705b… drh 1096 @ <p>Should timeline entries for leaf check-ins be identified in the
6ce705b… drh 1097 @ detail section. (Property: "timeline-mark-leaves")</p>
f5482a0… wyoung 1098
f5482a0… wyoung 1099 @ <hr>
6454153… drh 1100 entry_attribute("Max timeline comment length", 6,
10d8abc… jan.nijtmans 1101 "timeline-max-comment", "tmc", "0", 0);
c7c81df… drh 1102 @ <p>The maximum length of a comment to be displayed in a timeline.
3ca935e… drh 1103 @ "0" there is no length limit.
3ca935e… drh 1104 @ (Property: "timeline-max-comment")</p>
3ca935e… drh 1105
f5482a0… wyoung 1106 @ <hr>
6908832… drh 1107 entry_attribute("Tooltip dwell time (milliseconds)", 6,
6908832… drh 1108 "timeline-dwelltime", "tdt", "100", 0);
6908832… drh 1109 @ <br>
6908832… drh 1110 entry_attribute("Tooltip close time (milliseconds)", 6,
6908832… drh 1111 "timeline-closetime", "tct", "250", 0);
6908832… drh 1112 @ <p>The <strong>dwell time</strong> defines how long the mouse pointer
6908832… drh 1113 @ should be stationary above an object of the graph before a tooltip
6908832… drh 1114 @ appears.<br>
6908832… drh 1115 @ The <strong>close time</strong> defines how long the mouse pointer
6908832… drh 1116 @ can be away from an object before a tooltip is closed.</p>
6908832… drh 1117 @ <p>Set <strong>dwell time</strong> to "0" to disable tooltips.<br>
6908832… drh 1118 @ Set <strong>close time</strong> to "0" to keep tooltips visible until
6908832… drh 1119 @ the mouse is clicked elsewhere.<p>
6908832… drh 1120 @ <p>(Properties: "timeline-dwelltime", "timeline-closetime")</p>
6908832… drh 1121
f5482a0… wyoung 1122 @ <hr>
647424d… drh 1123 onoff_attribute("Timestamp hyperlinks to /info",
647424d… drh 1124 "timeline-tslink-info", "ttlti", 0, 0);
647424d… drh 1125 @ <p>The hyperlink on the timestamp associated with each timeline entry,
647424d… drh 1126 @ on the far left-hand side of the screen, normally targets another
647424d… drh 1127 @ /timeline page that shows the entry in context. However, if this
647424d… drh 1128 @ option is turned on, that hyperlink targets the /info page showing
647424d… drh 1129 @ the details of the entry.
647424d… drh 1130 @ <p>The /timeline link is the default since it is often useful to
647424d… drh 1131 @ see an entry in context, and because that link is not otherwise
647424d… drh 1132 @ accessible on the timeline. The /info link is also accessible by
647424d… drh 1133 @ double-clicking the timeline node or by clicking on the hash that
c8021e9… stephan 1134 @ follows "check-in:" in the supplemental information section on the
647424d… drh 1135 @ right of the entry.
647424d… drh 1136 @ <p>(Properties: "timeline-tslink-info")
647424d… drh 1137
f5482a0… wyoung 1138 @ <hr>
f5482a0… wyoung 1139 @ <p><input type="submit" name="submit" value="Apply Changes"></p>
b48f789… drh 1140 @ </div></form>
b48f789… drh 1141 db_end_transaction(0);
112c713… drh 1142 style_finish_page();
b48f789… drh 1143 }
b48f789… drh 1144
b48f789… drh 1145 /*
b48f789… drh 1146 ** WEBPAGE: setup_settings
7ab0328… drh 1147 **
26eef7f… rberteig 1148 ** Change or view miscellaneous settings. Part of the
7d034d3… wyoung 1149 ** /setup pages requiring Setup privileges.
b48f789… drh 1150 */
b48f789… drh 1151 void setup_settings(void){
f74f701… drh 1152 int nSetting;
f74f701… drh 1153 int i;
32f8da0… drh 1154 Setting const *pSet;
74a5e10… drh 1155 int bIfChng = P("all")==0;
f74f701… drh 1156 const Setting *aSetting = setting_info(&nSetting);
b48f789… drh 1157
b48f789… drh 1158 login_check_credentials();
b344d3c… drh 1159 if( !g.perm.Setup ){
653dd40… drh 1160 login_needed(0);
653dd40… drh 1161 return;
b48f789… drh 1162 }
3243e63… drh 1163
112c713… drh 1164 style_set_current_feature("setup");
b48f789… drh 1165 style_header("Settings");
0ab0079… stephan 1166 if(!g.repositoryOpen){
0ab0079… stephan 1167 /* Provide read-only access to versioned settings,
0ab0079… stephan 1168 but only if no repo file was explicitly provided. */
0ab0079… stephan 1169 db_open_local(0);
0ab0079… stephan 1170 }
e1962ef… drh 1171 db_begin_transaction();
74a5e10… drh 1172 if( bIfChng ){
74a5e10… drh 1173 @ <p>Only settings whose value is different from the default are shown.
74a5e10… drh 1174 @ Click the "All" button above to set all settings.
74a5e10… drh 1175 }
f74f701… drh 1176 @ <p>Settings marked with (v) are "versionable" and will be overridden
f74f701… drh 1177 @ by the contents of managed files named
f74f701… drh 1178 @ "<tt>.fossil-settings/</tt><i>SETTING-NAME</i>".
f74f701… drh 1179 @ If the file for a versionable setting exists, the value cannot be
f5482a0… wyoung 1180 @ changed on this screen.</p><hr><p>
f74f701… drh 1181 @
a40e8a0… drh 1182 @ <form action="%R/setup_settings" method="post"><div>
74a5e10… drh 1183 if( bIfChng ){
74a5e10… drh 1184 style_submenu_element("All", "%R/setup_settings?all");
f60bd4a… drh 1185 }else{
74a5e10… drh 1186 @ <input type="hidden" name="all" value="1">
74a5e10… drh 1187 style_submenu_element("Changes-Only", "%R/setup_settings");
f60bd4a… drh 1188 }
b48f789… drh 1189 @ <table border="0"><tr><td valign="top">
b48f789… drh 1190 login_insert_csrf_secret();
f74f701… drh 1191 for(i=0, pSet=aSetting; i<nSetting; i++, pSet++){
9b2d565… mistachkin 1192 if( pSet->width==0 ){
9b2d565… mistachkin 1193 int hasVersionableValue = pSet->versionable &&
dfc0f1b… drh 1194 (db_get_versioned(pSet->name, NULL, NULL)!=0);
bff93fc… drh 1195 if( bIfChng && setting_has_default_value(pSet, db_get(pSet->name,0)) ){
bff93fc… drh 1196 continue;
3ba0763… drh 1197 }
45953a4… stephan 1198 onoff_attribute("", pSet->name,
0a5d0e1… drh 1199 pSet->var!=0 ? pSet->var : pSet->name /*works-like:"x"*/,
45953a4… stephan 1200 is_truth(pSet->def), hasVersionableValue);
c64f28d… drh 1201 @ <a href='%R/help/%s(pSet->name)'>%h(pSet->name)</a>
45953a4… stephan 1202 if( pSet->versionable ){
f5482a0… wyoung 1203 @ (v)<br>
45953a4… stephan 1204 } else {
f5482a0… wyoung 1205 @ <br>
45953a4… stephan 1206 }
45953a4… stephan 1207 }
45953a4… stephan 1208 }
f5482a0… wyoung 1209 @ <br><input type="submit" name="submit" value="Apply Changes">
45953a4… stephan 1210 @ </td><td style="width:50px;"></td><td valign="top">
c1ca100… ashepilko 1211 @ <table>
45953a4… stephan 1212 for(i=0, pSet=aSetting; i<nSetting; i++, pSet++){
45953a4… stephan 1213 if( pSet->width>0 && !pSet->forceTextArea ){
45953a4… stephan 1214 int hasVersionableValue = pSet->versionable &&
dfc0f1b… drh 1215 (db_get_versioned(pSet->name, NULL, NULL)!=0);
bff93fc… drh 1216 if( bIfChng && setting_has_default_value(pSet, db_get(pSet->name,0)) ){
bff93fc… drh 1217 continue;
f60bd4a… drh 1218 }
c1ca100… ashepilko 1219 @ <tr><td>
c64f28d… drh 1220 @ <a href='%R/help/%s(pSet->name)'>%h(pSet->name)</a>
45953a4… stephan 1221 if( pSet->versionable ){
c1ca100… ashepilko 1222 @ (v)
45953a4… stephan 1223 } else {
c1ca100… ashepilko 1224 @
45953a4… stephan 1225 }
c1ca100… ashepilko 1226 @</td><td>
c1ca100… ashepilko 1227 entry_attribute("", /*pSet->width*/ 25, pSet->name,
0a5d0e1… drh 1228 pSet->var!=0 ? pSet->var : pSet->name /*works-like:"x"*/,
c1ca100… ashepilko 1229 (char*)pSet->def, hasVersionableValue);
c1ca100… ashepilko 1230 @</td></tr>
45953a4… stephan 1231 }
45953a4… stephan 1232 }
c1ca100… ashepilko 1233 @</table>
45953a4… stephan 1234 @ </td><td style="width:50px;"></td><td valign="top">
45953a4… stephan 1235 for(i=0, pSet=aSetting; i<nSetting; i++, pSet++){
45953a4… stephan 1236 if( pSet->width>0 && pSet->forceTextArea ){
dfc0f1b… drh 1237 int hasVersionableValue = db_get_versioned(pSet->name, NULL, NULL)!=0;
bff93fc… drh 1238 if( bIfChng && setting_has_default_value(pSet, db_get(pSet->name,0)) ){
bff93fc… drh 1239 continue;
f60bd4a… drh 1240 }
c64f28d… drh 1241 @ <a href='%R/help/%s(pSet->name)'>%s(pSet->name)</a>
45953a4… stephan 1242 if( pSet->versionable ){
f5482a0… wyoung 1243 @ (v)<br>
45953a4… stephan 1244 } else {
f5482a0… wyoung 1245 @ <br>
45953a4… stephan 1246 }
45953a4… stephan 1247 textarea_attribute("", /*rows*/ 2, /*cols*/ 35, pSet->name,
0a5d0e1… drh 1248 pSet->var!=0 ? pSet->var : pSet->name /*works-like:"x"*/,
45953a4… stephan 1249 (char*)pSet->def, hasVersionableValue);
f5482a0… wyoung 1250 @<br>
5a48a9b… drh 1251 }
5a48a9b… drh 1252 }
5a48a9b… drh 1253 @ </td></tr></table>
5a48a9b… drh 1254 @ </div></form>
5a48a9b… drh 1255 db_end_transaction(0);
112c713… drh 1256 style_finish_page();
5a48a9b… drh 1257 }
aac9093… drh 1258
aac9093… drh 1259 /*
1f6ae1e… drh 1260 ** SETTING: mainmenu width=70 block-text keep-empty
aac9093… drh 1261 **
aac9093… drh 1262 ** The mainmenu setting specifies the entries on the main menu
aac9093… drh 1263 ** for many skins. The mainmenu should be a TCL list. Each set
aac9093… drh 1264 ** of four consecutive values defines a single main menu item:
aac9093… drh 1265 **
aac9093… drh 1266 ** * The first term is text that appears on the menu.
aac9093… drh 1267 **
aac9093… drh 1268 ** * The second term is a hyperlink to take when a user clicks on the
aac9093… drh 1269 ** entry. Hyperlinks that start with "/" are relative to the
aac9093… drh 1270 ** repository root.
aac9093… drh 1271 **
aac9093… drh 1272 ** * The third term is an argument to the TH1 "capexpr" command.
9993c43… danshearer 1273 ** If capexpr evaluates to true, then the entry is shown. If not,
aac9093… drh 1274 ** the entry is omitted. "*" is always true. "{}" is never true.
aac9093… drh 1275 **
2a88f7b… stephan 1276 ** * The fourth term is a list of extra class names to apply to the
2a88f7b… stephan 1277 ** new menu entry. Some skins use classes "desktoponly" and
2a88f7b… stephan 1278 ** "wideonly" to only show the entries when the web browser
2a88f7b… stephan 1279 ** screen is wide or very wide, respectively.
aac9093… drh 1280 **
aac9093… drh 1281 ** Some custom skins might not use this property. Whether the property
aac9093… drh 1282 ** is used or not a choice made by the skin designer. Some skins may add
aac9093… drh 1283 ** extra choices (such as the hamburger button) to the menu.
aac9093… drh 1284 */
aac9093… drh 1285 /*
aac9093… drh 1286 ** SETTING: sitemap-extra width=70 block-text
aac9093… drh 1287 **
aac9093… drh 1288 ** The sitemap-extra setting defines extra links to appear on the
aac9093… drh 1289 ** /sitemap web page as sub-items of the "Home Page" entry before the
aac9093… drh 1290 ** "Documentation Search" entry (if any). For skins that use the /sitemap
aac9093… drh 1291 ** page to construct a hamburger menu dropdown, new entries added here
aac9093… drh 1292 ** will appear on the hamburger menu.
aac9093… drh 1293 **
aac9093… drh 1294 ** This setting should be a TCL list divided into triples. Each
aac9093… drh 1295 ** triple defines a new entry:
aac9093… drh 1296 **
aac9093… drh 1297 ** * The first term is the display name of the /sitemap entry
aac9093… drh 1298 **
aac9093… drh 1299 ** * The second term is a hyperlink to take when a user clicks on the
aac9093… drh 1300 ** entry. Hyperlinks that start with "/" are relative to the
aac9093… drh 1301 ** repository root.
aac9093… drh 1302 **
aac9093… drh 1303 ** * The third term is an argument to the TH1 "capexpr" command.
9993c43… danshearer 1304 ** If capexpr evaluates to true, then the entry is shown. If not,
aac9093… drh 1305 ** the entry is omitted. "*" is always true.
aac9093… drh 1306 **
aac9093… drh 1307 ** The default value is blank, meaning no added entries.
aac9093… drh 1308 */
aac9093… drh 1309
c7c81df… drh 1310
c7c81df… drh 1311 /*
c7c81df… drh 1312 ** WEBPAGE: setup_config
7ab0328… drh 1313 **
7d034d3… wyoung 1314 ** The "Admin/Configuration" page. Requires Setup privilege.
c7c81df… drh 1315 */
c7c81df… drh 1316 void setup_config(void){
c7c81df… drh 1317 login_check_credentials();
b344d3c… drh 1318 if( !g.perm.Setup ){
653dd40… drh 1319 login_needed(0);
653dd40… drh 1320 return;
c7c81df… drh 1321 }
c7c81df… drh 1322
112c713… drh 1323 style_set_current_feature("setup");
c7c81df… drh 1324 style_header("WWW Configuration");
e1962ef… drh 1325 db_begin_transaction();
a40e8a0… drh 1326 @ <form action="%R/setup_config" method="post"><div>
0be5482… drh 1327 login_insert_csrf_secret();
f5482a0… wyoung 1328 @ <input type="submit" name="submit" value="Apply Changes"></p>
f5482a0… wyoung 1329 @ <hr>
10d8abc… jan.nijtmans 1330 entry_attribute("Project Name", 60, "project-name", "pn", "", 0);
3ca935e… drh 1331 @ <p>A brief project name so visitors know what this site is about.
49e112c… drh 1332 @ The project name will also be used as the RSS feed title.
3ca935e… drh 1333 @ (Property: "project-name")
fe76ad5… drh 1334 @ </p>
f5482a0… wyoung 1335 @ <hr>
65870e8… drh 1336 textarea_attribute("Project Description", 3, 80,
10d8abc… jan.nijtmans 1337 "project-description", "pd", "", 0);
c7c81df… drh 1338 @ <p>Describe your project. This will be used in page headers for search
2771bea… jkosche 1339 @ engines, the repository listing and a short RSS description.
3ca935e… drh 1340 @ (Property: "project-description")</p>
f5482a0… wyoung 1341 @ <hr>
7e993c7… drh 1342 entry_attribute("Canonical Server URL", 40, "email-url",
7e993c7… drh 1343 "eurl", "", 0);
6d5d5f0… stephan 1344 @ <p>This is the URL used to access this repository as a server.
7e993c7… drh 1345 @ Other repositories use this URL to clone or sync against this repository.
7e993c7… drh 1346 @ This is also the basename for hyperlinks included in email alert text.
7e993c7… drh 1347 @ Omit the trailing "/".
7e993c7… drh 1348 @ If this repo will not be set up as a persistent server and will not
7e993c7… drh 1349 @ be sending email alerts, then leave this entry blank.
7e993c7… drh 1350 @ Suggested value: "%h(g.zBaseURL)"
7e993c7… drh 1351 @ (Property: "email-url")</p>
7e993c7… drh 1352 @ <hr>
10d8abc… jan.nijtmans 1353 entry_attribute("Index Page", 60, "index-page", "idxpg", "/home", 0);
c7c81df… drh 1354 @ <p>Enter the pathname of the page to display when the "Home" menu
c7c81df… drh 1355 @ option is selected and when no pathname is
c7c81df… drh 1356 @ specified in the URL. For example, if you visit the url:</p>
c7c81df… drh 1357 @
3243e63… drh 1358 @ <blockquote><p>%h(g.zBaseURL)</p></blockquote>
c7c81df… drh 1359 @
c7c81df… drh 1360 @ <p>And you have specified an index page of "/home" the above will
c7c81df… drh 1361 @ automatically redirect to:</p>
c7c81df… drh 1362 @
3243e63… drh 1363 @ <blockquote><p>%h(g.zBaseURL)/home</p></blockquote>
4348111… drh 1364 @
4348111… drh 1365 @ <p>The default "/home" page displays a Wiki page with the same name
4348111… drh 1366 @ as the Project Name specified above. Some sites prefer to redirect
b32461f… danshearer 1367 @ to a documentation page (ex: "/doc/trunk/index.wiki") or to "/timeline".</p>
106c090… drh 1368 @
106c090… drh 1369 @ <p>Note: To avoid a redirect loop or other problems, this entry must
106c090… drh 1370 @ begin with "/" and it must specify a valid page. For example,
106c090… drh 1371 @ "<b>/home</b>" will work but "<b>home</b>" will not, since it omits the
106c090… drh 1372 @ leading "/".</p>
3ca935e… drh 1373 @ <p>(Property: "index-page")
6898b3e… drh 1374 @ <hr>
5f22712… drh 1375 @ <p>The main menu for the web interface
5f22712… drh 1376 @ <p>
aac9093… drh 1377 @
5f22712… drh 1378 @ <p>This setting should be a TCL list. Each set of four consecutive
5f22712… drh 1379 @ values defines a single main menu item:
5f22712… drh 1380 @ <ol>
5f22712… drh 1381 @ <li> The first term is text that appears on the menu.
5f22712… drh 1382 @ <li> The second term is a hyperlink to take when a user clicks on the
5f22712… drh 1383 @ entry. Hyperlinks that start with "/" are relative to the
5f22712… drh 1384 @ repository root.
5f22712… drh 1385 @ <li> The third term is an argument to the TH1 "capexpr" command.
9993c43… danshearer 1386 @ If capexpr evaluates to true, then the entry is shown. If not,
5f22712… drh 1387 @ the entry is omitted. "*" is always true. "{}" is never true.
f8c42ab… stephan 1388 @ <li> The fourth term is a list of extra class names to apply to the new
2a88f7b… stephan 1389 @ menu entry. Some skins use classes "desktoponly" and "wideonly"
5f22712… drh 1390 @ to only show the entries when the web browser screen is wide or
5f22712… drh 1391 @ very wide, respectively.
5f22712… drh 1392 @ </ol>
5f22712… drh 1393 @
aac9093… drh 1394 @ <p>Some custom skins might not use this property. Whether the property
aac9093… drh 1395 @ is used or not a choice made by the skin designer. Some skins may add extra
5f22712… drh 1396 @ choices (such as the hamburger button) to the menu that are not shown
5f22712… drh 1397 @ on this list. (Property: mainmenu)
5f22712… drh 1398 @ <p>
8af3d42… stephan 1399 if(P("resetMenu")!=0){
8af3d42… stephan 1400 db_unset("mainmenu", 0);
8af3d42… stephan 1401 cgi_delete_parameter("mmenu");
8af3d42… stephan 1402 }
275da70… danield 1403 textarea_attribute("Main Menu", 12, 80,
5f22712… drh 1404 "mainmenu", "mmenu", style_default_mainmenu(), 0);
8af3d42… stephan 1405 @ </p>
8af3d42… stephan 1406 @ <p><input type='checkbox' id='cbResetMenu' name='resetMenu' value='1'>
8af3d42… stephan 1407 @ <label for='cbResetMenu'>Reset menu to default value</label>
8af3d42… stephan 1408 @ </p>
5f22712… drh 1409 @ <hr>
aa5beb8… drh 1410 @ <p>Extra links to appear on the <a href="%R/sitemap">/sitemap</a> page,
aa5beb8… drh 1411 @ as sub-items of the "Home Page" entry, appearing before the
aa5beb8… drh 1412 @ "Documentation Search" entry (if any). In skins that use the /sitemap
aa5beb8… drh 1413 @ page to construct a hamburger menu dropdown, new entries added here
aa5beb8… drh 1414 @ will appear on the hamburger menu.
aa5beb8… drh 1415 @
aa5beb8… drh 1416 @ <p>This setting should be a TCL list divided into triples. Each
aa5beb8… drh 1417 @ triple defines a new entry:
aa5beb8… drh 1418 @ <ol>
aa5beb8… drh 1419 @ <li> The first term is the display name of the /sitemap entry
aa5beb8… drh 1420 @ <li> The second term is a hyperlink to take when a user clicks on the
aa5beb8… drh 1421 @ entry. Hyperlinks that start with "/" are relative to the
aa5beb8… drh 1422 @ repository root.
aa5beb8… drh 1423 @ <li> The third term is an argument to the TH1 "capexpr" command.
9993c43… danshearer 1424 @ If capexpr evaluates to true, then the entry is shown. If not,
aa5beb8… drh 1425 @ the entry is omitted. "*" is always true.
aa5beb8… drh 1426 @ </ol>
aa5beb8… drh 1427 @
aa5beb8… drh 1428 @ <p>The default value is blank, meaning no added entries.
aa5beb8… drh 1429 @ (Property: sitemap-extra)
aa5beb8… drh 1430 @ <p>
275da70… danield 1431 textarea_attribute("Custom Sitemap Entries", 8, 80,
aa5beb8… drh 1432 "sitemap-extra", "smextra", "", 0);
9cc36d2… drh 1433 @ <hr>
6ce705b… drh 1434 @ <p><input type="submit" name="submit" value="Apply Changes"></p>
6ce705b… drh 1435 @ </div></form>
6ce705b… drh 1436 db_end_transaction(0);
6ce705b… drh 1437 style_finish_page();
6ce705b… drh 1438 }
6ce705b… drh 1439
6ce705b… drh 1440 /*
6ce705b… drh 1441 ** WEBPAGE: setup_download
6ce705b… drh 1442 **
6ce705b… drh 1443 ** The "Admin/Download" page. Requires Setup privilege.
6ce705b… drh 1444 */
6ce705b… drh 1445 void setup_download(void){
6ce705b… drh 1446 login_check_credentials();
6ce705b… drh 1447 if( !g.perm.Setup ){
6ce705b… drh 1448 login_needed(0);
6ce705b… drh 1449 return;
6ce705b… drh 1450 }
6ce705b… drh 1451
6ce705b… drh 1452 style_set_current_feature("setup");
6ce705b… drh 1453 style_header("Tarball and ZIP Downloads");
6ce705b… drh 1454 db_begin_transaction();
6ce705b… drh 1455 @ <form action="%R/setup_download" method="post"><div>
6ce705b… drh 1456 login_insert_csrf_secret();
6ce705b… drh 1457 @ <input type="submit" name="submit" value="Apply Changes"></p>
6ce705b… drh 1458 @ <hr>
6ce705b… drh 1459 entry_attribute("Tarball and ZIP Name Prefix", 20, "short-project-name",
6ce705b… drh 1460 "spn", "", 0);
6ce705b… drh 1461 @ <p>This is used as a prefix for the names of generated tarballs and
6ce705b… drh 1462 @ ZIP archive. Keep this prefix brief and use only lower-case ASCII
6ce705b… drh 1463 @ characters, digits, "_", "-" in the name. If this setting is blank,
6ce705b… drh 1464 @ then the full <a href='%R/help/project-name'>project-name</a> setting
6ce705b… drh 1465 @ is used instead.
6ce705b… drh 1466 @ (Property: "short-project-name")
6ce705b… drh 1467 @ </p>
6ce705b… drh 1468 @ <hr>
6ce705b… drh 1469 @ <p><b>Configuration for the <a href="%R/download">/download</a> page.</b>
6ce705b… drh 1470 @ <p>The value is a TCL list divided into groups of four tokens:
9cc36d2… drh 1471 @ <ol>
6ce705b… drh 1472 @ <li> Maximum number of matches (COUNT).
6ce705b… drh 1473 @ <li> Tag to match using glob (TAG).
6ce705b… drh 1474 @ <li> Maximum age of check-ins to match (MAX_AGE).
6ce705b… drh 1475 @ <li> Comment to apply to matches (COMMENT).
9cc36d2… drh 1476 @ </ol>
6ce705b… drh 1477 @ Each 4-tuple will match zero or more check-ins. The /download page
6ce705b… drh 1478 @ displays the union of matches from all 4-tuples.
6ce705b… drh 1479 @ See the <a href="%R/help/suggested-downloads">suggested-downloads</a>
6ce705b… drh 1480 @ setting documentation for further detail.
6ce705b… drh 1481 @ <p>
6ce705b… drh 1482 @ The /download page is omitted from the <a href="%R/sitemap">/sitemap</a>
6ce705b… drh 1483 @ if the first token is "0" or "off" or "no". The default value
6ce705b… drh 1484 @ for this setting is "off".
6ce705b… drh 1485 @ (Property: <a href="%R/help/suggested-downloads">suggested-downloads</a>)
6ce705b… drh 1486 @ <p>
6ce705b… drh 1487 textarea_attribute("", 4, 80,
6ce705b… drh 1488 "suggested-downloads", "sgtrlst", "off", 0);
25f43cc… stephan 1489 @ <hr>
25f43cc… stephan 1490 @ <p><input type="submit" name="submit" value="Apply Changes"></p>
25f43cc… stephan 1491 @ </div></form>
25f43cc… stephan 1492 db_end_transaction(0);
25f43cc… stephan 1493 style_finish_page();
25f43cc… stephan 1494 }
25f43cc… stephan 1495
25f43cc… stephan 1496 /*
bf09c3b… drh 1497 ** WEBPAGE: setup_wiki
bf09c3b… drh 1498 **
bf09c3b… drh 1499 ** The "Admin/Wiki" page. Requires Setup privilege.
bf09c3b… drh 1500 */
bf09c3b… drh 1501 void setup_wiki(void){
bf09c3b… drh 1502 login_check_credentials();
bf09c3b… drh 1503 if( !g.perm.Setup ){
bf09c3b… drh 1504 login_needed(0);
bf09c3b… drh 1505 return;
bf09c3b… drh 1506 }
bf09c3b… drh 1507
112c713… drh 1508 style_set_current_feature("setup");
bf09c3b… drh 1509 style_header("Wiki Configuration");
e1962ef… drh 1510 db_begin_transaction();
a40e8a0… drh 1511 @ <form action="%R/setup_wiki" method="post"><div>
bf09c3b… drh 1512 login_insert_csrf_secret();
f5482a0… wyoung 1513 @ <input type="submit" name="submit" value="Apply Changes"></p>
f5482a0… wyoung 1514 @ <hr>
25f43cc… stephan 1515 onoff_attribute("Associate Wiki Pages With Branches, Tags, Tickets, or Checkins",
5602385… drh 1516 "wiki-about", "wiki-about", 1, 0);
5602385… drh 1517 @ <p>
25f43cc… stephan 1518 @ Associate wiki pages with branches, tags, tickets, or checkins, based on
25f43cc… stephan 1519 @ the wiki page name. Wiki pages that begin with "branch/", "checkin/",
25f43cc… stephan 1520 @ "tag/" or "ticket" and which continue with the name of an existing branch,
25f43cc… stephan 1521 @ check-in, tag or ticket are treated specially when this feature is enabled.
5602385… drh 1522 @ <ul>
5602385… drh 1523 @ <li> <b>branch/</b><i>branch-name</i>
bc36fdc… danield 1524 @ <li> <b>checkin/</b><i>full-check-in-hash</i>
5602385… drh 1525 @ <li> <b>tag/</b><i>tag-name</i>
25f43cc… stephan 1526 @ <li> <b>ticket/</b><i>full-ticket-hash</i>
5602385… drh 1527 @ </ul>
5602385… drh 1528 @ (Property: "wiki-about")</p>
f5482a0… wyoung 1529 @ <hr>
89b6dda… drh 1530 entry_attribute("Allow Unsafe HTML In Markdown", 6,
89b6dda… drh 1531 "safe-html", "safe-html", "", 0);
89b6dda… drh 1532 @ <p>Allow "unsafe" HTML (ex: &lt;script&gt;, &lt;form&gt;, etc) to be
89b6dda… drh 1533 @ generated by <a href="%R/md_rules">Markdown-formatted</a> documents.
89b6dda… drh 1534 @ This setting is a string where each character indicates a "type" of
89b6dda… drh 1535 @ document in which to allow unsafe HTML:
89b6dda… drh 1536 @ <ul>
89b6dda… drh 1537 @ <li> <b>b</b> &rarr; checked-in files, embedded documentation
89b6dda… drh 1538 @ <li> <b>f</b> &rarr; forum posts
89b6dda… drh 1539 @ <li> <b>t</b> &rarr; tickets
89b6dda… drh 1540 @ <li> <b>w</b> &rarr; wiki pages
89b6dda… drh 1541 @ </ul>
89b6dda… drh 1542 @ Include letters for each type of document for which unsafe HTML should
89b6dda… drh 1543 @ be allowed. For example, to allow unsafe HTML only for checked-in files,
89b6dda… drh 1544 @ make this setting be just "<b>b</b>". To allow unsafe HTML anywhere except
89b6dda… drh 1545 @ in forum posts, make this setting be "<b>btw</b>". The default is an
89b6dda… drh 1546 @ empty string which means that Fossil never allows Markdown documents
89b6dda… drh 1547 @ to generate unsafe HTML.
89b6dda… drh 1548 @ (Property: "safe-html")</p>
f5482a0… wyoung 1549 @ <hr>
f4dc114… drh 1550 @ The current interwiki tag map is as follows:
f4dc114… drh 1551 interwiki_append_map_table(cgi_output_blob());
f4dc114… drh 1552 @ <p>Visit <a href="./intermap">%R/intermap</a> for details or to
f4dc114… drh 1553 @ modify the interwiki tag map.
f5482a0… wyoung 1554 @ <hr>
106c090… drh 1555 onoff_attribute("Use HTML as wiki markup language",
106c090… drh 1556 "wiki-use-html", "wiki-use-html", 0, 0);
106c090… drh 1557 @ <p>Use HTML as the wiki markup language. Wiki links will still be parsed
19f2753… stephan 1558 @ but all other wiki formatting will be ignored.</p>
106c090… drh 1559 @ <p><strong>CAUTION:</strong> when
106c090… drh 1560 @ enabling, <i>all</i> HTML tags and attributes are accepted in the wiki.
106c090… drh 1561 @ No sanitization is done. This means that it is very possible for malicious
106c090… drh 1562 @ users to inject dangerous HTML, CSS and JavaScript code into your wiki.</p>
106c090… drh 1563 @ <p>This should <strong>only</strong> be enabled when wiki editing is limited
4d1ac68… drh 1564 @ to trusted users. It should <strong>not</strong> be used on a publicly
106c090… drh 1565 @ editable wiki.</p>
3ca935e… drh 1566 @ (Property: "wiki-use-html")
f5482a0… wyoung 1567 @ <hr>
f5482a0… wyoung 1568 @ <p><input type="submit" name="submit" value="Apply Changes"></p>
15bc20f… drh 1569 @ </div></form>
15bc20f… drh 1570 db_end_transaction(0);
15bc20f… drh 1571 style_finish_page();
15bc20f… drh 1572 }
15bc20f… drh 1573
15bc20f… drh 1574 /*
15bc20f… drh 1575 ** WEBPAGE: setup_chat
15bc20f… drh 1576 **
15bc20f… drh 1577 ** The "Admin/Chat" page. Requires Setup privilege.
15bc20f… drh 1578 */
15bc20f… drh 1579 void setup_chat(void){
d8e6994… drh 1580 static const char *const azAlerts[] = {
d8e6994… drh 1581 "alerts/plunk.wav", "Plunk",
d8e6994… drh 1582 "alerts/bflat3.wav", "Tone-1",
35b0781… drh 1583 "alerts/bflat2.wav", "Tone-2",
35b0781… drh 1584 "alerts/bloop.wav", "Bloop",
d8e6994… drh 1585 };
d8e6994… drh 1586
15bc20f… drh 1587 login_check_credentials();
15bc20f… drh 1588 if( !g.perm.Setup ){
15bc20f… drh 1589 login_needed(0);
15bc20f… drh 1590 return;
15bc20f… drh 1591 }
15bc20f… drh 1592
15bc20f… drh 1593 style_set_current_feature("setup");
15bc20f… drh 1594 style_header("Chat Configuration");
15bc20f… drh 1595 db_begin_transaction();
43af043… drh 1596 if( P("rbldchatidx") && cgi_csrf_safe(2) ){
43af043… drh 1597 chat_rebuild_index(1);
43af043… drh 1598 }
15bc20f… drh 1599 @ <form action="%R/setup_chat" method="post"><div>
15bc20f… drh 1600 login_insert_csrf_secret();
f5482a0… wyoung 1601 @ <input type="submit" name="submit" value="Apply Changes"></p>
f5482a0… wyoung 1602 @ <hr>
15bc20f… drh 1603 entry_attribute("Initial Chat History Size", 10,
15bc20f… drh 1604 "chat-initial-history", "chatih", "50", 0);
15bc20f… drh 1605 @ <p>When /chat first starts up, it preloads up to this many historical
15bc20f… drh 1606 @ messages.
15bc20f… drh 1607 @ (Property: "chat-initial-history")</p>
f5482a0… wyoung 1608 @ <hr>
15bc20f… drh 1609 entry_attribute("Minimum Number Of Historical Messages To Retain", 10,
15bc20f… drh 1610 "chat-keep-count", "chatkc", "50", 0);
15bc20f… drh 1611 @ <p>The chat subsystem purges older messages. But it will always retain
15bc20f… drh 1612 @ the N most recent messages where N is the value of this setting.
15bc20f… drh 1613 @ (Property: "chat-keep-count")</p>
f5482a0… wyoung 1614 @ <hr>
15bc20f… drh 1615 entry_attribute("Maximum Message Age In Days", 10,
15bc20f… drh 1616 "chat-keep-days", "chatkd", "7", 0);
15bc20f… drh 1617 @ <p>Chat message are removed after N days, where N is the value of
15bc20f… drh 1618 @ this setting. N may be fractional. So, for example, to only keep
15bc20f… drh 1619 @ an historical record of chat messages for 12 hours, set this value
15bc20f… drh 1620 @ to 0.5.
15bc20f… drh 1621 @ (Property: "chat-keep-days")</p>
f5482a0… wyoung 1622 @ <hr>
8363e7b… drh 1623 entry_attribute("Chat Polling Timeout", 10,
8363e7b… drh 1624 "chat-poll-timeout", "chatpt", "420", 0);
8363e7b… drh 1625 @ <p>New chat content is downloaded using the "long poll" technique.
8363e7b… drh 1626 @ HTTP requests are made to /chat-poll which blocks waiting on new
8363e7b… drh 1627 @ content to arrive. But the /chat-poll cannot block forever. It
8363e7b… drh 1628 @ eventual must give up and return an empty message set. This setting
8363e7b… drh 1629 @ determines how long /chat-poll will wait before giving up. The
8363e7b… drh 1630 @ default setting of approximately 7 minutes works well on many systems.
8363e7b… drh 1631 @ Shorter delays might be required on installations that use proxies
8363e7b… drh 1632 @ or web-servers with short timeouts. For best efficiency, this value
8363e7b… drh 1633 @ should be larger rather than smaller.
d8e6994… drh 1634 @ (Property: "chat-poll-timeout")</p>
f5482a0… wyoung 1635 @ <hr>
e9d7cf3… drh 1636 entry_attribute("Chat Timeline Robot Username", 15,
1f5474e… drh 1637 "chat-timeline-user", "chatrobot", "", 0);
1f5474e… drh 1638 @ <p>If this setting is not an empty string, then any changes that appear
1f5474e… drh 1639 @ on the timeline are announced in the chatroom under the username
c3ed243… drh 1640 @ supplied. The username does not need to actually exist in the USER table.
c3ed243… drh 1641 @ Suggested username: "chat-robot".
1f5474e… drh 1642 @ (Property: "chat-timeline-user")</p>
f5482a0… wyoung 1643 @ <hr>
d8e6994… drh 1644
d8e6994… drh 1645 multiple_choice_attribute("Alert sound",
d8e6994… drh 1646 "chat-alert-sound", "snd", azAlerts[0],
d8e6994… drh 1647 count(azAlerts)/2, azAlerts);
d8e6994… drh 1648 @ <p>The sound used in the client-side chat to indicate that a new
d8e6994… drh 1649 @ chat message has arrived.
d8e6994… drh 1650 @ (Property: "chat-alert-sound")</p>
43af043… drh 1651
d8e6994… drh 1652 @ <hr/>
43af043… drh 1653 @ <p><input type="submit" name="submit" value="Apply Changes">
43af043… drh 1654 @ <input type="submit" name="rbldchatidx"\
43af043… drh 1655 @ value="Rebuild Full-Text Search Index"></p>
7ab0328… drh 1656 @ </div></form>
d5504f9… drh 1657
d5504f9… drh 1658 /* Validate the chat FTS search index */
d5504f9… drh 1659 if( db_table_exists("repository","chatfts1") ){
d5504f9… drh 1660 char *zMissing;
d5504f9… drh 1661 zMissing = db_text(0,
d5504f9… drh 1662 "SELECT group_concat(rowid,', ') FROM chat"
d5504f9… drh 1663 " WHERE rowid NOT IN (SELECT rowid FROM chatfts1_docsize)"
d5504f9… drh 1664 );
d5504f9… drh 1665 if( zMissing && zMissing[0] ){
d5504f9… drh 1666 @ <p><b>WARNING:</b> The following chat messages are missing
d5504f9… drh 1667 @ from the full-text index. Press the "Rebuild Full-Text Search Index"
d5504f9… drh 1668 @ button above to fix this.</p>
d5504f9… drh 1669 @ <p>%h(zMissing)</p>
d5504f9… drh 1670 }
d5504f9… drh 1671 fossil_free(zMissing);
d5504f9… drh 1672 }
d5504f9… drh 1673
7ab0328… drh 1674 db_end_transaction(0);
baa40a0… drh 1675 @ <script nonce="%h(style_nonce())">
baa40a0… drh 1676 @ (function(){
baa40a0… drh 1677 @ var w = document.getElementById('idsnd');
baa40a0… drh 1678 @ w.onchange = function(){
baa40a0… drh 1679 @ var audio = new Audio('%s(g.zBaseURL)/builtin/' + w.value);
baa40a0… drh 1680 @ audio.currentTime = 0;
baa40a0… drh 1681 @ audio.play();
baa40a0… drh 1682 @ }
baa40a0… drh 1683 @ })();
baa40a0… drh 1684 @ </script>
112c713… drh 1685 style_finish_page();
7ab0328… drh 1686 }
7ab0328… drh 1687
7ab0328… drh 1688 /*
7ab0328… drh 1689 ** WEBPAGE: setup_modreq
7ab0328… drh 1690 **
7ab0328… drh 1691 ** Admin page for setting up moderation of tickets and wiki.
7ab0328… drh 1692 */
7ab0328… drh 1693 void setup_modreq(void){
7ab0328… drh 1694 login_check_credentials();
6242e24… wyoung 1695 if( !g.perm.Admin ){
7ab0328… drh 1696 login_needed(0);
7ab0328… drh 1697 return;
7ab0328… drh 1698 }
7ab0328… drh 1699
112c713… drh 1700 style_set_current_feature("setup");
ba418ee… drh 1701 style_header("Moderator For Wiki And Tickets");
e1962ef… drh 1702 db_begin_transaction();
ba418ee… drh 1703 @ <form action="%R/setup_modreq" method="post"><div>
ba418ee… drh 1704 login_insert_csrf_secret();
f5482a0… wyoung 1705 @ <hr>
ba418ee… drh 1706 onoff_attribute("Moderate ticket changes",
10d8abc… jan.nijtmans 1707 "modreq-tkt", "modreq-tkt", 0, 0);
ba418ee… drh 1708 @ <p>When enabled, any change to tickets is subject to the approval
8fdb682… drh 1709 @ by a ticket moderator - a user with the "q" or Mod-Tkt privilege.
ba418ee… drh 1710 @ Ticket changes enter the system and are shown locally, but are not
3ba9a4d… jan.nijtmans 1711 @ synced until they are approved. The moderator has the option to
ba418ee… drh 1712 @ delete the change rather than approve it. Ticket changes made by
2530ee0… stephan 1713 @ a user who has the Mod-Tkt privilege are never subject to
3ca935e… drh 1714 @ moderation. (Property: "modreq-tkt")
ba418ee… drh 1715 @
f5482a0… wyoung 1716 @ <hr>
ba418ee… drh 1717 onoff_attribute("Moderate wiki changes",
10d8abc… jan.nijtmans 1718 "modreq-wiki", "modreq-wiki", 0, 0);
ba418ee… drh 1719 @ <p>When enabled, any change to wiki is subject to the approval
8fdb682… drh 1720 @ by a wiki moderator - a user with the "l" or Mod-Wiki privilege.
ba418ee… drh 1721 @ Wiki changes enter the system and are shown locally, but are not
3ba9a4d… jan.nijtmans 1722 @ synced until they are approved. The moderator has the option to
ba418ee… drh 1723 @ delete the change rather than approve it. Wiki changes made by
ba418ee… drh 1724 @ a user who has the Mod-Wiki privilege are never subject to
3ca935e… drh 1725 @ moderation. (Property: "modreq-wiki")
ba418ee… drh 1726 @ </p>
3ba9a4d… jan.nijtmans 1727
f5482a0… wyoung 1728 @ <hr>
f5482a0… wyoung 1729 @ <p><input type="submit" name="submit" value="Apply Changes"></p>
ba418ee… drh 1730 @ </div></form>
ba418ee… drh 1731 db_end_transaction(0);
112c713… drh 1732 style_finish_page();
ba418ee… drh 1733
e33fc88… drh 1734 }
e33fc88… drh 1735
e33fc88… drh 1736 /*
e33fc88… drh 1737 ** WEBPAGE: setup_adunit
7ab0328… drh 1738 **
7ab0328… drh 1739 ** Administrative page for configuring and controlling ad units
7ab0328… drh 1740 ** and how they are displayed.
e33fc88… drh 1741 */
e33fc88… drh 1742 void setup_adunit(void){
e33fc88… drh 1743 login_check_credentials();
257318c… drh 1744 if( !g.perm.Admin ){
653dd40… drh 1745 login_needed(0);
653dd40… drh 1746 return;
e33fc88… drh 1747 }
e1962ef… drh 1748 db_begin_transaction();
920ace1… drh 1749 if( P("clear")!=0 && cgi_csrf_safe(2) ){
f741baa… drh 1750 db_unprotect(PROTECT_CONFIG);
e33fc88… drh 1751 db_multi_exec("DELETE FROM config WHERE name GLOB 'adunit*'");
f741baa… drh 1752 db_protect_pop();
869e27e… drh 1753 cgi_replace_parameter("adunit","");
48dca1b… drh 1754 cgi_replace_parameter("adright","");
0ba0e5e… drh 1755 setup_incr_cfgcnt();
e33fc88… drh 1756 }
65870e8… drh 1757
112c713… drh 1758 style_set_current_feature("setup");
e33fc88… drh 1759 style_header("Edit Ad Unit");
a40e8a0… drh 1760 @ <form action="%R/setup_adunit" method="post"><div>
e33fc88… drh 1761 login_insert_csrf_secret();
f5482a0… wyoung 1762 @ <b>Banner Ad-Unit:</b><br>
ff78d6d… drh 1763 textarea_attribute("", 6, 80, "adunit", "adunit", "", 0);
f5482a0… wyoung 1764 @ <br>
f5482a0… wyoung 1765 @ <b>Right-Column Ad-Unit:</b><br>
ff78d6d… drh 1766 textarea_attribute("", 6, 80, "adunit-right", "adright", "", 0);
f5482a0… wyoung 1767 @ <br>
e33fc88… drh 1768 onoff_attribute("Omit ads to administrator",
10d8abc… jan.nijtmans 1769 "adunit-omit-if-admin", "oia", 0, 0);
f5482a0… wyoung 1770 @ <br>
e33fc88… drh 1771 onoff_attribute("Omit ads to logged-in users",
10d8abc… jan.nijtmans 1772 "adunit-omit-if-user", "oiu", 0, 0);
f5482a0… wyoung 1773 @ <br>
48d8af2… drh 1774 onoff_attribute("Temporarily disable all ads",
48d8af2… drh 1775 "adunit-disable", "oall", 0, 0);
f5482a0… wyoung 1776 @ <br>
f5482a0… wyoung 1777 @ <input type="submit" name="submit" value="Apply Changes">
f5482a0… wyoung 1778 @ <input type="submit" name="clear" value="Delete Ad-Unit">
e33fc88… drh 1779 @ </div></form>
f5482a0… wyoung 1780 @ <hr>
ff78d6d… drh 1781 @ <b>Ad-Unit Notes:</b><ul>
ff78d6d… drh 1782 @ <li>Leave both Ad-Units blank to disable all advertising.
ff78d6d… drh 1783 @ <li>The "Banner Ad-Unit" is used for wide pages.
ff78d6d… drh 1784 @ <li>The "Right-Column Ad-Unit" is used on pages with tall, narrow content.
7001228… drh 1785 @ <li>If the "Right-Column Ad-Unit" is blank, the "Banner Ad-Unit" is
7001228… drh 1786 @ used on all pages.
23895c7… jan.nijtmans 1787 @ <li>Properties: "adunit", "adunit-right", "adunit-omit-if-admin", and
3ca935e… drh 1788 @ "adunit-omit-if-user".
106c090… drh 1789 @ <li>Suggested <a href="setup_skinedit?w=0">CSS</a> changes:
ff78d6d… drh 1790 @ <blockquote><pre>
ff78d6d… drh 1791 @ div.adunit_banner {
ff78d6d… drh 1792 @ margin: auto;
bc6355e… drh 1793 @ width: 100%%;
ff78d6d… drh 1794 @ }
ff78d6d… drh 1795 @ div.adunit_right {
ff78d6d… drh 1796 @ float: right;
ff78d6d… drh 1797 @ }
ff78d6d… drh 1798 @ div.adunit_right_container {
ff78d6d… drh 1799 @ min-height: <i>height-of-right-column-ad-unit</i>;
ff78d6d… drh 1800 @ }
ff78d6d… drh 1801 @ </pre></blockquote>
ff78d6d… drh 1802 @ <li>For a place-holder Ad-Unit for testing, Copy/Paste the following
ff78d6d… drh 1803 @ with appropriate adjustments to "width:" and "height:".
ff78d6d… drh 1804 @ <blockquote><pre>
ff78d6d… drh 1805 @ &lt;div style='
ff78d6d… drh 1806 @ margin: 0 auto;
ff78d6d… drh 1807 @ width: 600px;
ff78d6d… drh 1808 @ height: 90px;
ff78d6d… drh 1809 @ border: 1px solid #f11;
ff78d6d… drh 1810 @ background-color: #fcc;
ff78d6d… drh 1811 @ '&gt;Demo Ad&lt;/div&gt;
ff78d6d… drh 1812 @ </pre></blockquote>
ff78d6d… drh 1813 @ </li>
112c713… drh 1814 style_finish_page();
4348111… drh 1815 db_end_transaction(0);
4348111… drh 1816 }
4348111… drh 1817
4348111… drh 1818 /*
4348111… drh 1819 ** WEBPAGE: setup_logo
7ab0328… drh 1820 **
37262b8… mistachkin 1821 ** Administrative page for changing the logo, background, and icon images.
4348111… drh 1822 */
4348111… drh 1823 void setup_logo(void){
daff9d2… joel 1824 const char *zLogoMtime = db_get_mtime("logo-image", 0, 0);
6239845… drh 1825 const char *zLogoMime = db_get("logo-mimetype","image/gif");
6239845… drh 1826 const char *aLogoImg = P("logoim");
6239845… drh 1827 int szLogoImg = atoi(PD("logoim:bytes","0"));
daff9d2… joel 1828 const char *zBgMtime = db_get_mtime("background-image", 0, 0);
6239845… drh 1829 const char *zBgMime = db_get("background-mimetype","image/gif");
6239845… drh 1830 const char *aBgImg = P("bgim");
6239845… drh 1831 int szBgImg = atoi(PD("bgim:bytes","0"));
37262b8… mistachkin 1832 const char *zIconMtime = db_get_mtime("icon-image", 0, 0);
37262b8… mistachkin 1833 const char *zIconMime = db_get("icon-mimetype","image/gif");
37262b8… mistachkin 1834 const char *aIconImg = P("iconim");
37262b8… mistachkin 1835 int szIconImg = atoi(PD("iconim:bytes","0"));
6239845… drh 1836 if( szLogoImg>0 ){
6239845… drh 1837 zLogoMime = PD("logoim:mimetype","image/gif");
6239845… drh 1838 }
6239845… drh 1839 if( szBgImg>0 ){
6239845… drh 1840 zBgMime = PD("bgim:mimetype","image/gif");
37262b8… mistachkin 1841 }
37262b8… mistachkin 1842 if( szIconImg>0 ){
37262b8… mistachkin 1843 zIconMime = PD("iconim:mimetype","image/gif");
257318c… drh 1844 }
4348111… drh 1845 login_check_credentials();
257318c… drh 1846 if( !g.perm.Admin ){
653dd40… drh 1847 login_needed(0);
653dd40… drh 1848 return;
4348111… drh 1849 }
e1962ef… drh 1850 db_begin_transaction();
920ace1… drh 1851 if( !cgi_csrf_safe(2) ){
047802a… drh 1852 /* Allow no state changes if not safe from CSRF */
047802a… drh 1853 }else if( P("setlogo")!=0 && zLogoMime && zLogoMime[0] && szLogoImg>0 ){
1654456… drh 1854 Blob img;
1654456… drh 1855 Stmt ins;
6239845… drh 1856 blob_init(&img, aLogoImg, szLogoImg);
f273832… mistachkin 1857 db_unprotect(PROTECT_CONFIG);
1654456… drh 1858 db_prepare(&ins,
1654456… drh 1859 "REPLACE INTO config(name,value,mtime)"
1654456… drh 1860 " VALUES('logo-image',:bytes,now())"
1654456… drh 1861 );
1654456… drh 1862 db_bind_blob(&ins, ":bytes", &img);
1654456… drh 1863 db_step(&ins);
1654456… drh 1864 db_finalize(&ins);
1654456… drh 1865 db_multi_exec(
1654456… drh 1866 "REPLACE INTO config(name,value,mtime) VALUES('logo-mimetype',%Q,now())",
6239845… drh 1867 zLogoMime
6239845… drh 1868 );
f273832… mistachkin 1869 db_protect_pop();
6239845… drh 1870 db_end_transaction(0);
6239845… drh 1871 cgi_redirect("setup_logo");
6239845… drh 1872 }else if( P("clrlogo")!=0 ){
f273832… mistachkin 1873 db_unprotect(PROTECT_CONFIG);
6239845… drh 1874 db_multi_exec(
6239845… drh 1875 "DELETE FROM config WHERE name IN "
6239845… drh 1876 "('logo-image','logo-mimetype')"
6239845… drh 1877 );
f273832… mistachkin 1878 db_protect_pop();
6239845… drh 1879 db_end_transaction(0);
6239845… drh 1880 cgi_redirect("setup_logo");
6239845… drh 1881 }else if( P("setbg")!=0 && zBgMime && zBgMime[0] && szBgImg>0 ){
6239845… drh 1882 Blob img;
6239845… drh 1883 Stmt ins;
6239845… drh 1884 blob_init(&img, aBgImg, szBgImg);
f741baa… drh 1885 db_unprotect(PROTECT_CONFIG);
6239845… drh 1886 db_prepare(&ins,
6239845… drh 1887 "REPLACE INTO config(name,value,mtime)"
6239845… drh 1888 " VALUES('background-image',:bytes,now())"
6239845… drh 1889 );
6239845… drh 1890 db_bind_blob(&ins, ":bytes", &img);
6239845… drh 1891 db_step(&ins);
6239845… drh 1892 db_finalize(&ins);
6239845… drh 1893 db_multi_exec(
6239845… drh 1894 "REPLACE INTO config(name,value,mtime)"
6239845… drh 1895 " VALUES('background-mimetype',%Q,now())",
6239845… drh 1896 zBgMime
6239845… drh 1897 );
f741baa… drh 1898 db_protect_pop();
6239845… drh 1899 db_end_transaction(0);
6239845… drh 1900 cgi_redirect("setup_logo");
6239845… drh 1901 }else if( P("clrbg")!=0 ){
f741baa… drh 1902 db_unprotect(PROTECT_CONFIG);
6239845… drh 1903 db_multi_exec(
6239845… drh 1904 "DELETE FROM config WHERE name IN "
6239845… drh 1905 "('background-image','background-mimetype')"
6239845… drh 1906 );
f273832… mistachkin 1907 db_protect_pop();
37262b8… mistachkin 1908 db_end_transaction(0);
37262b8… mistachkin 1909 cgi_redirect("setup_logo");
37262b8… mistachkin 1910 }else if( P("seticon")!=0 && zIconMime && zIconMime[0] && szIconImg>0 ){
37262b8… mistachkin 1911 Blob img;
37262b8… mistachkin 1912 Stmt ins;
37262b8… mistachkin 1913 blob_init(&img, aIconImg, szIconImg);
f741baa… drh 1914 db_unprotect(PROTECT_CONFIG);
37262b8… mistachkin 1915 db_prepare(&ins,
37262b8… mistachkin 1916 "REPLACE INTO config(name,value,mtime)"
37262b8… mistachkin 1917 " VALUES('icon-image',:bytes,now())"
37262b8… mistachkin 1918 );
37262b8… mistachkin 1919 db_bind_blob(&ins, ":bytes", &img);
37262b8… mistachkin 1920 db_step(&ins);
37262b8… mistachkin 1921 db_finalize(&ins);
37262b8… mistachkin 1922 db_multi_exec(
37262b8… mistachkin 1923 "REPLACE INTO config(name,value,mtime)"
37262b8… mistachkin 1924 " VALUES('icon-mimetype',%Q,now())",
37262b8… mistachkin 1925 zIconMime
37262b8… mistachkin 1926 );
f741baa… drh 1927 db_protect_pop();
37262b8… mistachkin 1928 db_end_transaction(0);
37262b8… mistachkin 1929 cgi_redirect("setup_logo");
37262b8… mistachkin 1930 }else if( P("clricon")!=0 ){
f273832… mistachkin 1931 db_unprotect(PROTECT_CONFIG);
37262b8… mistachkin 1932 db_multi_exec(
37262b8… mistachkin 1933 "DELETE FROM config WHERE name IN "
37262b8… mistachkin 1934 "('icon-image','icon-mimetype')"
37262b8… mistachkin 1935 );
f273832… mistachkin 1936 db_protect_pop();
1942d58… drh 1937 db_end_transaction(0);
1942d58… drh 1938 cgi_redirect("setup_logo");
1942d58… drh 1939 }
112c713… drh 1940 style_set_current_feature("setup");
6239845… drh 1941 style_header("Edit Project Logo And Background");
6239845… drh 1942 @ <p>The current project logo has a MIME-Type of <b>%h(zLogoMime)</b>
6239845… drh 1943 @ and looks like this:</p>
f5482a0… wyoung 1944 @ <blockquote><p>
f5482a0… wyoung 1945 @ <img src="%R/logo/%z(zLogoMtime)" alt="logo" border="1">
6239845… drh 1946 @ </p></blockquote>
6454153… drh 1947 @
a40e8a0… drh 1948 @ <form action="%R/setup_logo" method="post"
6239845… drh 1949 @ enctype="multipart/form-data"><div>
4348111… drh 1950 @ <p>The logo is accessible to all users at this URL:
4348111… drh 1951 @ <a href="%s(g.zBaseURL)/logo">%s(g.zBaseURL)/logo</a>.
007d0a9… drh 1952 @ The logo may or may not appear on each
106c090… drh 1953 @ page depending on the <a href="setup_skinedit?w=0">CSS</a> and
106c090… drh 1954 @ <a href="setup_skinedit?w=2">header setup</a>.
6239845… drh 1955 @ To change the logo image, use the following form:</p>
4348111… drh 1956 login_insert_csrf_secret();
4348111… drh 1957 @ Logo Image file:
f5482a0… wyoung 1958 @ <input type="file" name="logoim" size="60" accept="image/*">
6239845… drh 1959 @ <p align="center">
f5482a0… wyoung 1960 @ <input type="submit" name="setlogo" value="Change Logo">
f5482a0… wyoung 1961 @ <input type="submit" name="clrlogo" value="Revert To Default"></p>
3ca935e… drh 1962 @ <p>(Properties: "logo-image" and "logo-mimetype")
6239845… drh 1963 @ </div></form>
f5482a0… wyoung 1964 @ <hr>
6239845… drh 1965 @
6239845… drh 1966 @ <p>The current background image has a MIME-Type of <b>%h(zBgMime)</b>
6239845… drh 1967 @ and looks like this:</p>
a40e8a0… drh 1968 @ <blockquote><p><img src="%R/background/%z(zBgMtime)" \
f5482a0… wyoung 1969 @ alt="background" border=1>
6239845… drh 1970 @ </p></blockquote>
6239845… drh 1971 @
a40e8a0… drh 1972 @ <form action="%R/setup_logo" method="post"
6239845… drh 1973 @ enctype="multipart/form-data"><div>
6239845… drh 1974 @ <p>The background image is accessible to all users at this URL:
6239845… drh 1975 @ <a href="%s(g.zBaseURL)/background">%s(g.zBaseURL)/background</a>.
6239845… drh 1976 @ The background image may or may not appear on each
106c090… drh 1977 @ page depending on the <a href="setup_skinedit?w=0">CSS</a> and
106c090… drh 1978 @ <a href="setup_skinedit?w=2">header setup</a>.
6239845… drh 1979 @ To change the background image, use the following form:</p>
6239845… drh 1980 login_insert_csrf_secret();
6239845… drh 1981 @ Background image file:
f5482a0… wyoung 1982 @ <input type="file" name="bgim" size="60" accept="image/*">
3ca935e… drh 1983 @ <p align="center">
f5482a0… wyoung 1984 @ <input type="submit" name="setbg" value="Change Background">
f5482a0… wyoung 1985 @ <input type="submit" name="clrbg" value="Revert To Default"></p>
3ca935e… drh 1986 @ </div></form>
3ca935e… drh 1987 @ <p>(Properties: "background-image" and "background-mimetype")
f5482a0… wyoung 1988 @ <hr>
37262b8… mistachkin 1989 @
37262b8… mistachkin 1990 @ <p>The current icon image has a MIME-Type of <b>%h(zIconMime)</b>
37262b8… mistachkin 1991 @ and looks like this:</p>
a40e8a0… drh 1992 @ <blockquote><p><img src="%R/favicon.ico/%z(zIconMtime)" \
f5482a0… wyoung 1993 @ alt="icon" border=1>
37262b8… mistachkin 1994 @ </p></blockquote>
37262b8… mistachkin 1995 @
a40e8a0… drh 1996 @ <form action="%R/setup_logo" method="post"
37262b8… mistachkin 1997 @ enctype="multipart/form-data"><div>
37262b8… mistachkin 1998 @ <p>The icon image is accessible to all users at this URL:
37262b8… mistachkin 1999 @ <a href="%s(g.zBaseURL)/favicon.ico">%s(g.zBaseURL)/favicon.ico</a>.
37262b8… mistachkin 2000 @ The icon image may or may not appear on each
37262b8… mistachkin 2001 @ page depending on the web browser in use and the MIME-Types that it
37262b8… mistachkin 2002 @ supports for icon images.
37262b8… mistachkin 2003 @ To change the icon image, use the following form:</p>
37262b8… mistachkin 2004 login_insert_csrf_secret();
37262b8… mistachkin 2005 @ Icon image file:
f5482a0… wyoung 2006 @ <input type="file" name="iconim" size="60" accept="image/*">
37262b8… mistachkin 2007 @ <p align="center">
f5482a0… wyoung 2008 @ <input type="submit" name="seticon" value="Change Icon">
f5482a0… wyoung 2009 @ <input type="submit" name="clricon" value="Revert To Default"></p>
37262b8… mistachkin 2010 @ </div></form>
37262b8… mistachkin 2011 @ <p>(Properties: "icon-image" and "icon-mimetype")
f5482a0… wyoung 2012 @ <hr>
3243e63… drh 2013 @
6239845… drh 2014 @ <p><span class="note">Note:</span> Your browser has probably cached these
6239845… drh 2015 @ images, so you may need to press the Reload button before changes will
6239845… drh 2016 @ take effect. </p>
112c713… drh 2017 style_finish_page();
4348111… drh 2018 db_end_transaction(0);
98f29f2… drh 2019 }
98f29f2… drh 2020
98f29f2… drh 2021 /*
98f29f2… drh 2022 ** Prevent the RAW SQL feature from being used to ATTACH a different
98f29f2… drh 2023 ** database and query it.
98f29f2… drh 2024 **
98f29f2… drh 2025 ** Actually, the RAW SQL feature only does a single statement per request.
98f29f2… drh 2026 ** So it is not possible to ATTACH and then do a separate query. This
98f29f2… drh 2027 ** routine is not strictly necessary, therefore. But it does not hurt
98f29f2… drh 2028 ** to be paranoid.
98f29f2… drh 2029 */
98f29f2… drh 2030 int raw_sql_query_authorizer(
98f29f2… drh 2031 void *pError,
98f29f2… drh 2032 int code,
98f29f2… drh 2033 const char *zArg1,
98f29f2… drh 2034 const char *zArg2,
98f29f2… drh 2035 const char *zArg3,
98f29f2… drh 2036 const char *zArg4
98f29f2… drh 2037 ){
98f29f2… drh 2038 if( code==SQLITE_ATTACH ){
98f29f2… drh 2039 return SQLITE_DENY;
98f29f2… drh 2040 }
98f29f2… drh 2041 return SQLITE_OK;
ca0faa8… drh 2042 }
ca0faa8… drh 2043
ca0faa8… drh 2044
ca0faa8… drh 2045 /*
ca0faa8… drh 2046 ** WEBPAGE: admin_sql
ca0faa8… drh 2047 **
ca0faa8… drh 2048 ** Run raw SQL commands against the database file using the web interface.
7d034d3… wyoung 2049 ** Requires Setup privileges.
ca0faa8… drh 2050 */
ca0faa8… drh 2051 void sql_page(void){
047802a… drh 2052 const char *zQ;
ca0faa8… drh 2053 int go = P("go")!=0;
ca0faa8… drh 2054 login_check_credentials();
ca0faa8… drh 2055 if( !g.perm.Setup ){
653dd40… drh 2056 login_needed(0);
653dd40… drh 2057 return;
ca0faa8… drh 2058 }
93f514c… stephan 2059 add_content_sql_commands(g.db);
920ace1… drh 2060 zQ = cgi_csrf_safe(2) ? P("q") : 0;
112c713… drh 2061 style_set_current_feature("setup");
ca0faa8… drh 2062 style_header("Raw SQL Commands");
ca0faa8… drh 2063 @ <p><b>Caution:</b> There are no restrictions on the SQL that can be
ca0faa8… drh 2064 @ run by this page. You can do serious and irrepairable damage to the
ca0faa8… drh 2065 @ repository. Proceed with extreme caution.</p>
ca0faa8… drh 2066 @
6a67931… drh 2067 #if 0
565d1b0… m.ramakers 2068 @ <p>Only the first statement in the entry box will be run.
98f29f2… drh 2069 @ Any subsequent statements will be silently ignored.</p>
98f29f2… drh 2070 @
06aec61… drh 2071 @ <p>Database names:<ul><li>repository
a5dc533… jan.nijtmans 2072 if( g.zConfigDbName ){
06aec61… drh 2073 @ <li>configdb
ca0faa8… drh 2074 }
ca0faa8… drh 2075 if( g.localOpen ){
06aec61… drh 2076 @ <li>localdb
ca0faa8… drh 2077 }
ca0faa8… drh 2078 @ </ul></p>
6a67931… drh 2079 #endif
6a67931… drh 2080
6a67931… drh 2081 if( P("configtab") ){
6a67931… drh 2082 /* If the user presses the "CONFIG Table Query" button, populate the
6a67931… drh 2083 ** query text with a pre-packaged query against the CONFIG table */
6a67931… drh 2084 zQ = "SELECT\n"
7001228… drh 2085 " CASE WHEN length(name)<50 THEN name ELSE printf('%.50s...',name)"
7001228… drh 2086 " END AS name,\n"
6a67931… drh 2087 " CASE WHEN typeof(value)<>'blob' AND length(value)<80 THEN value\n"
6a67931… drh 2088 " ELSE '...' END AS value,\n"
6a67931… drh 2089 " datetime(mtime, 'unixepoch') AS mtime\n"
6a67931… drh 2090 "FROM config\n"
6a67931… drh 2091 "-- ORDER BY mtime DESC; -- optional";
6a67931… drh 2092 go = 1;
6a67931… drh 2093 }
ca0faa8… drh 2094 @
a40e8a0… drh 2095 @ <form method="post" action="%R/admin_sql">
ca0faa8… drh 2096 login_insert_csrf_secret();
f5482a0… wyoung 2097 @ SQL:<br>
f5482a0… wyoung 2098 @ <textarea name="q" rows="8" cols="80">%h(zQ)</textarea><br>
ca0faa8… drh 2099 @ <input type="submit" name="go" value="Run SQL">
ca0faa8… drh 2100 @ <input type="submit" name="schema" value="Show Schema">
ca0faa8… drh 2101 @ <input type="submit" name="tablelist" value="List Tables">
6a67931… drh 2102 @ <input type="submit" name="configtab" value="CONFIG Table Query">
ca0faa8… drh 2103 @ </form>
ca0faa8… drh 2104 if( P("schema") ){
ca0faa8… drh 2105 zQ = sqlite3_mprintf(
e654b30… mistachkin 2106 "SELECT sql FROM repository.sqlite_schema"
7001228… drh 2107 " WHERE sql IS NOT NULL ORDER BY name");
ca0faa8… drh 2108 go = 1;
ca0faa8… drh 2109 }else if( P("tablelist") ){
6325f81… drh 2110 zQ = sqlite3_mprintf("SELECT*FROM pragma_table_list ORDER BY schema, name");
ca0faa8… drh 2111 go = 1;
ca0faa8… drh 2112 }
920ace1… drh 2113 if( go && cgi_csrf_safe(2) ){
ca0faa8… drh 2114 sqlite3_stmt *pStmt;
ca0faa8… drh 2115 int rc;
ca0faa8… drh 2116 const char *zTail;
ca0faa8… drh 2117 int nCol;
ca0faa8… drh 2118 int nRow = 0;
ca0faa8… drh 2119 int i;
f5482a0… wyoung 2120 @ <hr>
98f29f2… drh 2121 sqlite3_set_authorizer(g.db, raw_sql_query_authorizer, 0);
6325f81… drh 2122 search_sql_setup(g.db);
ca0faa8… drh 2123 rc = sqlite3_prepare_v2(g.db, zQ, -1, &pStmt, &zTail);
ca0faa8… drh 2124 if( rc!=SQLITE_OK ){
ca0faa8… drh 2125 @ <div class="generalError">%h(sqlite3_errmsg(g.db))</div>
ca0faa8… drh 2126 sqlite3_finalize(pStmt);
ca0faa8… drh 2127 }else if( pStmt==0 ){
ca0faa8… drh 2128 /* No-op */
ca0faa8… drh 2129 }else if( (nCol = sqlite3_column_count(pStmt))==0 ){
ca0faa8… drh 2130 sqlite3_step(pStmt);
ca0faa8… drh 2131 rc = sqlite3_finalize(pStmt);
ca0faa8… drh 2132 if( rc ){
ca0faa8… drh 2133 @ <div class="generalError">%h(sqlite3_errmsg(g.db))</div>
ca0faa8… drh 2134 }
ca0faa8… drh 2135 }else{
6325f81… drh 2136 @ <table border="1" cellpadding="4" cellspacing="0">
ca0faa8… drh 2137 while( sqlite3_step(pStmt)==SQLITE_ROW ){
ca0faa8… drh 2138 if( nRow==0 ){
ca0faa8… drh 2139 @ <tr>
ca0faa8… drh 2140 for(i=0; i<nCol; i++){
ca0faa8… drh 2141 @ <th>%h(sqlite3_column_name(pStmt, i))</th>
ca0faa8… drh 2142 }
ca0faa8… drh 2143 @ </tr>
ca0faa8… drh 2144 }
ca0faa8… drh 2145 nRow++;
ca0faa8… drh 2146 @ <tr>
ca0faa8… drh 2147 for(i=0; i<nCol; i++){
ca0faa8… drh 2148 switch( sqlite3_column_type(pStmt, i) ){
ca0faa8… drh 2149 case SQLITE_INTEGER:
ca0faa8… drh 2150 case SQLITE_FLOAT: {
ca0faa8… drh 2151 @ <td align="right" valign="top">
ca0faa8… drh 2152 @ %s(sqlite3_column_text(pStmt, i))</td>
ca0faa8… drh 2153 break;
ca0faa8… drh 2154 }
ca0faa8… drh 2155 case SQLITE_NULL: {
ca0faa8… drh 2156 @ <td valign="top" align="center"><i>NULL</i></td>
ca0faa8… drh 2157 break;
ca0faa8… drh 2158 }
ca0faa8… drh 2159 case SQLITE_TEXT: {
ca0faa8… drh 2160 const char *zText = (const char*)sqlite3_column_text(pStmt, i);
ca0faa8… drh 2161 @ <td align="left" valign="top"
ca0faa8… drh 2162 @ style="white-space:pre;">%h(zText)</td>
ca0faa8… drh 2163 break;
ca0faa8… drh 2164 }
ca0faa8… drh 2165 case SQLITE_BLOB: {
ca0faa8… drh 2166 @ <td valign="top" align="center">
ca0faa8… drh 2167 @ <i>%d(sqlite3_column_bytes(pStmt, i))-byte BLOB</i></td>
ca0faa8… drh 2168 break;
ca0faa8… drh 2169 }
ca0faa8… drh 2170 }
ca0faa8… drh 2171 }
ca0faa8… drh 2172 @ </tr>
ca0faa8… drh 2173 }
ca0faa8… drh 2174 sqlite3_finalize(pStmt);
ca0faa8… drh 2175 @ </table>
ca0faa8… drh 2176 }
ca0faa8… drh 2177 }
112c713… drh 2178 style_finish_page();
e356f18… drh 2179 }
e356f18… drh 2180
e356f18… drh 2181
e356f18… drh 2182 /*
e356f18… drh 2183 ** WEBPAGE: admin_th1
e356f18… drh 2184 **
e356f18… drh 2185 ** Run raw TH1 commands using the web interface. If Tcl integration was
e356f18… drh 2186 ** enabled at compile-time and the "tcl" setting is enabled, Tcl commands
7ab0328… drh 2187 ** may be run as well. Requires Admin privilege.
e356f18… drh 2188 */
e356f18… drh 2189 void th1_page(void){
e356f18… drh 2190 const char *zQ = P("q");
e356f18… drh 2191 int go = P("go")!=0;
e356f18… drh 2192 login_check_credentials();
e356f18… drh 2193 if( !g.perm.Setup ){
653dd40… drh 2194 login_needed(0);
653dd40… drh 2195 return;
e356f18… drh 2196 }
112c713… drh 2197 style_set_current_feature("setup");
e356f18… drh 2198 style_header("Raw TH1 Commands");
e356f18… drh 2199 @ <p><b>Caution:</b> There are no restrictions on the TH1 that can be
e356f18… drh 2200 @ run by this page. If Tcl integration was enabled at compile-time and
e356f18… drh 2201 @ the "tcl" setting is enabled, Tcl commands may be run as well.</p>
e356f18… drh 2202 @
920ace1… drh 2203 form_begin(0, "%R/admin_th1");
f5482a0… wyoung 2204 @ TH1:<br>
f5482a0… wyoung 2205 @ <textarea name="q" rows="5" cols="80">%h(zQ)</textarea><br>
e356f18… drh 2206 @ <input type="submit" name="go" value="Run TH1">
e356f18… drh 2207 @ </form>
920ace1… drh 2208 if( go && cgi_csrf_safe(2) ){
e356f18… drh 2209 const char *zR;
e356f18… drh 2210 int rc;
e356f18… drh 2211 int n;
f5482a0… wyoung 2212 @ <hr>
e356f18… drh 2213 rc = Th_Eval(g.interp, 0, zQ, -1);
e356f18… drh 2214 zR = Th_GetResult(g.interp, &n);
e356f18… drh 2215 if( rc==TH_OK ){
e356f18… drh 2216 @ <pre class="th1result">%h(zR)</pre>
e356f18… drh 2217 }else{
e356f18… drh 2218 @ <pre class="th1error">%h(zR)</pre>
e356f18… drh 2219 }
e356f18… drh 2220 }
112c713… drh 2221 style_finish_page();
f3455a5… drh 2222 }
f3455a5… drh 2223
f3455a5… drh 2224 /*
f3455a5… drh 2225 ** WEBPAGE: admin_log
f3455a5… drh 2226 **
f3455a5… drh 2227 ** Shows the contents of the admin_log table, which is only created if
f3455a5… drh 2228 ** the admin-log setting is enabled. Requires Admin or Setup ('a' or
f3455a5… drh 2229 ** 's') permissions.
f3455a5… drh 2230 */
f3455a5… drh 2231 void page_admin_log(){
703b57c… drh 2232 Stmt stLog;
703b57c… drh 2233 int limit; /* How many entries to show */
703b57c… drh 2234 int ofst; /* Offset to the first entry */
f3455a5… drh 2235 int fLogEnabled;
f3455a5… drh 2236 int counter = 0;
f3455a5… drh 2237 login_check_credentials();
42c3364… wyoung 2238 if( !g.perm.Admin ){
653dd40… drh 2239 login_needed(0);
653dd40… drh 2240 return;
653dd40… drh 2241 }
112c713… drh 2242 style_set_current_feature("setup");
3967d04… drh 2243 style_header("Admin Log");
b28badb… drh 2244 style_submenu_element("Log-Menu", "setup-logmenu");
3967d04… drh 2245 create_admin_log_table();
703b57c… drh 2246 limit = atoi(PD("n","200"));
703b57c… drh 2247 ofst = atoi(PD("x","0"));
bdf12f4… drh 2248 fLogEnabled = db_get_boolean("admin-log", 1);
3967d04… drh 2249 @ <div>Admin logging is %s(fLogEnabled?"on":"off").
3967d04… drh 2250 @ (Change this on the <a href="setup_settings">settings</a> page.)</div>
3967d04… drh 2251
703b57c… drh 2252 if( ofst>0 ){
703b57c… drh 2253 int prevx = ofst - limit;
703b57c… drh 2254 if( prevx<0 ) prevx = 0;
703b57c… drh 2255 @ <p><a href="admin_log?n=%d(limit)&x=%d(prevx)">[Newer]</a></p>
703b57c… drh 2256 }
703b57c… drh 2257 db_prepare(&stLog,
703b57c… drh 2258 "SELECT datetime(time,'unixepoch'), who, page, what "
703b57c… drh 2259 "FROM admin_log "
673dc38… stephan 2260 "ORDER BY time DESC, rowid DESC");
6b645d6… drh 2261 style_table_sorter();
6b645d6… drh 2262 @ <table class="sortable adminLogTable" width="100%%" \
6b645d6… drh 2263 @ data-column-types='Tttx' data-init-sort='1'>
f3455a5… drh 2264 @ <thead>
f3455a5… drh 2265 @ <th>Time</th>
f3455a5… drh 2266 @ <th>User</th>
f3455a5… drh 2267 @ <th>Page</th>
f3455a5… drh 2268 @ <th width="60%%">Message</th>
f3455a5… drh 2269 @ </thead><tbody>
f3455a5… drh 2270 while( SQLITE_ROW == db_step(&stLog) ){
5330d10… jan.nijtmans 2271 const char *zTime = db_column_text(&stLog, 0);
5330d10… jan.nijtmans 2272 const char *zUser = db_column_text(&stLog, 1);
5330d10… jan.nijtmans 2273 const char *zPage = db_column_text(&stLog, 2);
5330d10… jan.nijtmans 2274 const char *zMessage = db_column_text(&stLog, 3);
703b57c… drh 2275 counter++;
703b57c… drh 2276 if( counter<ofst ) continue;
703b57c… drh 2277 if( counter>ofst+limit ) break;
703b57c… drh 2278 @ <tr class="row%d(counter%2)">
f3455a5… drh 2279 @ <td class="adminTime">%s(zTime)</td>
f3455a5… drh 2280 @ <td>%s(zUser)</td>
f3455a5… drh 2281 @ <td>%s(zPage)</td>
f3455a5… drh 2282 @ <td>%h(zMessage)</td>
f3455a5… drh 2283 @ </tr>
f3455a5… drh 2284 }
6022ad4… drh 2285 db_finalize(&stLog);
f3455a5… drh 2286 @ </tbody></table>
703b57c… drh 2287 if( counter>ofst+limit ){
703b57c… drh 2288 @ <p><a href="admin_log?n=%d(limit)&x=%d(limit+ofst)">[Older]</a></p>
ca833ff… drh 2289 }
112c713… drh 2290 style_finish_page();
112c713… drh 2291 }
112c713… drh 2292
0e5d27f… stephan 2293
0e5d27f… stephan 2294 /*
0e5d27f… stephan 2295 ** Renders a selection list of values for the search-tokenizer
0e5d27f… stephan 2296 ** setting, using the form field name "ftstok".
0e5d27f… stephan 2297 */
0e5d27f… stephan 2298 static void select_fts_tokenizer(void){
0e5d27f… stephan 2299 const char *const aTokenizer[] = {
0e5d27f… stephan 2300 "off", "None",
0e5d27f… stephan 2301 "porter", "Porter Stemmer",
e180dbb… stephan 2302 "unicode61", "Unicode without stemming",
e180dbb… stephan 2303 "trigram", "Trigram",
0e5d27f… stephan 2304 };
0e5d27f… stephan 2305 multiple_choice_attribute("FTS Tokenizer", "search-tokenizer",
e180dbb… stephan 2306 "ftstok", "off", 4, aTokenizer);
0e5d27f… stephan 2307 }
0e5d27f… stephan 2308
ca833ff… drh 2309 /*
ca833ff… drh 2310 ** WEBPAGE: srchsetup
ca833ff… drh 2311 **
7ab0328… drh 2312 ** Configure the search engine. Requires Admin privilege.
ca833ff… drh 2313 */
ca833ff… drh 2314 void page_srchsetup(){
ca0d66b… danield 2315 const char *zMainBranch;
ca833ff… drh 2316 login_check_credentials();
42c3364… wyoung 2317 if( !g.perm.Admin ){
653dd40… drh 2318 login_needed(0);
653dd40… drh 2319 return;
ca833ff… drh 2320 }
112c713… drh 2321 style_set_current_feature("setup");
ca833ff… drh 2322 style_header("Search Configuration");
a40e8a0… drh 2323 @ <form action="%R/srchsetup" method="post"><div>
ca833ff… drh 2324 login_insert_csrf_secret();
ca833ff… drh 2325 @ <div style="text-align:center;font-weight:bold;">
5260fbf… jan.nijtmans 2326 @ Server-specific settings that affect the
6714c94… drh 2327 @ <a href="%R/search">/search</a> webpage.
ca833ff… drh 2328 @ </div>
f5482a0… wyoung 2329 @ <hr>
ca833ff… drh 2330 textarea_attribute("Document Glob List", 3, 35, "doc-glob", "dg", "", 0);
5260fbf… jan.nijtmans 2331 @ <p>The "Document Glob List" is a comma- or newline-separated list
ca833ff… drh 2332 @ of GLOB expressions that identify all documents within the source
ca833ff… drh 2333 @ tree that are to be searched when "Document Search" is enabled.
ca833ff… drh 2334 @ Some examples:
ca833ff… drh 2335 @ <table border=0 cellpadding=2 align=center>
ca833ff… drh 2336 @ <tr><td>*.wiki,*.html,*.md,*.txt<td style="width: 4x;">
ca833ff… drh 2337 @ <td>Search all wiki, HTML, Markdown, and Text files</tr>
ca833ff… drh 2338 @ <tr><td>doc/*.md,*/README.txt,README.txt<td>
ca833ff… drh 2339 @ <td>Search all Markdown files in the doc/ subfolder and all README.txt
ca833ff… drh 2340 @ files.</tr>
ca833ff… drh 2341 @ <tr><td>*<td><td>Search all checked-in files</tr>
ca833ff… drh 2342 @ <tr><td><i>(blank)</i><td>
ca833ff… drh 2343 @ <td>Search nothing. (Disables document search).</tr>
ca833ff… drh 2344 @ </table>
f5482a0… wyoung 2345 @ <hr>
ca0d66b… danield 2346 zMainBranch = db_main_branch();
3a6dd83… drh 2347 entry_attribute("Document Branches", 20, "doc-branch", "db", zMainBranch, 0);
ca833ff… drh 2348 @ <p>When searching documents, use the versions of the files found at the
3a6dd83… drh 2349 @ type of the "Document Branches" branch. Recommended value: the name of
3a6dd83… drh 2350 @ the main branch (usually "trunk").
40d0b36… stephan 2351 @ Document search is disabled if blank. It may be a list of branch names
40d0b36… stephan 2352 @ separated by spaces and/or commas.
f5482a0… wyoung 2353 @ <hr>
ca833ff… drh 2354 onoff_attribute("Search Check-in Comments", "search-ci", "sc", 0, 0);
f5482a0… wyoung 2355 @ <br>
ca833ff… drh 2356 onoff_attribute("Search Documents", "search-doc", "sd", 0, 0);
f5482a0… wyoung 2357 @ <br>
ca833ff… drh 2358 onoff_attribute("Search Tickets", "search-tkt", "st", 0, 0);
f5482a0… wyoung 2359 @ <br>
a551d50… andygoth 2360 onoff_attribute("Search Wiki", "search-wiki", "sw", 0, 0);
f5482a0… wyoung 2361 @ <br>
a551d50… andygoth 2362 onoff_attribute("Search Tech Notes", "search-technote", "se", 0, 0);
f5482a0… wyoung 2363 @ <br>
99fcc43… drh 2364 onoff_attribute("Search Forum", "search-forum", "sf", 0, 0);
6d9f0f5… drh 2365 @ <br>
6d9f0f5… drh 2366 onoff_attribute("Search Built-in Help Text", "search-help", "sh", 0, 0);
f5482a0… wyoung 2367 @ <hr>
f5482a0… wyoung 2368 @ <p><input type="submit" name="submit" value="Apply Changes"></p>
f5482a0… wyoung 2369 @ <hr>
43af043… drh 2370 if( cgi_csrf_safe(2) ){
43af043… drh 2371 if( P("fts0") ){
43af043… drh 2372 search_drop_index();
43af043… drh 2373 }else if( P("fts1") ){
43af043… drh 2374 const char *zTokenizer = PD("ftstok","off");
43af043… drh 2375 search_set_tokenizer(zTokenizer);
43af043… drh 2376 search_drop_index();
43af043… drh 2377 search_create_index();
43af043… drh 2378 search_fill_index();
43af043… drh 2379 search_update_index(search_restrict(SRCH_ALL));
43af043… drh 2380 }
43af043… drh 2381 if( P("rbldchatidx") ){
43af043… drh 2382 chat_rebuild_index(1);
43af043… drh 2383 }
a00a140… drh 2384 }
a00a140… drh 2385 if( search_index_exists() ){
5c5e549… drh 2386 int pgsz = db_int64(0, "PRAGMA repository.page_size;");
5c5e549… drh 2387 i64 nTotal = db_int64(0, "PRAGMA repository.page_count;")*pgsz;
5c5e549… drh 2388 i64 nFts = db_int64(0, "SELECT count(*) FROM dbstat"
5c5e549… drh 2389 " WHERE schema='repository'"
5c5e549… drh 2390 " AND name LIKE 'fts%%'")*pgsz;
5c5e549… drh 2391 char zSize[30];
5c5e549… drh 2392 approxSizeName(sizeof(zSize),zSize,nFts);
c3c4ef1… stephan 2393 @ <p>Currently using an SQLite FTS%d(search_index_type(0)) search index.
c3c4ef1… stephan 2394 @ The index helps search run faster, especially on large repositories,
5c5e549… drh 2395 @ but takes up space. The index is currently using about %s(zSize)
5c5e549… drh 2396 @ or %.1f(100.0*(double)nFts/(double)nTotal)%% of the repository.</p>
0e5d27f… stephan 2397 select_fts_tokenizer();
a00a140… drh 2398 @ <p><input type="submit" name="fts0" value="Delete The Full-Text Index">
13d93e4… drh 2399 @ <input type="submit" name="fts1" value="Rebuild The Full-Text Index">
43af043… drh 2400 if( db_table_exists("repository","chat") ){
43af043… drh 2401 @ <input type="submit" name="rbldchatidx" \
43af043… drh 2402 @ value="Rebuild The Chat FTS Index">
43af043… drh 2403 }
53d1f05… drh 2404 style_submenu_element("FTS Index Debugging","%R/test-ftsdocs");
a00a140… drh 2405 }else{
c3c4ef1… stephan 2406 @ <p>The SQLite search index is disabled. All searching will be
a00a140… drh 2407 @ a full-text scan. This usually works fine, but can be slow for
a00a140… drh 2408 @ larger repositories.</p>
0e5d27f… stephan 2409 select_fts_tokenizer();
a00a140… drh 2410 @ <p><input type="submit" name="fts1" value="Create A Full-Text Index">
a00a140… drh 2411 }
ca833ff… drh 2412 @ </div></form>
112c713… drh 2413 style_finish_page();
8131f1c… drh 2414 }
8131f1c… drh 2415
8131f1c… drh 2416 /*
8131f1c… drh 2417 ** A URL Alias originally called zOldName is now zNewName/zValue.
8131f1c… drh 2418 ** Write SQL to make this change into pSql.
8131f1c… drh 2419 **
8131f1c… drh 2420 ** If zNewName or zValue is an empty string, then delete the entry.
8131f1c… drh 2421 **
8131f1c… drh 2422 ** If zOldName is an empty string, create a new entry.
8131f1c… drh 2423 */
8131f1c… drh 2424 static void setup_update_url_alias(
8131f1c… drh 2425 Blob *pSql,
8131f1c… drh 2426 const char *zOldName,
8131f1c… drh 2427 const char *zNewName,
8131f1c… drh 2428 const char *zValue
8131f1c… drh 2429 ){
920ace1… drh 2430 if( !cgi_csrf_safe(2) ) return;
8131f1c… drh 2431 if( zNewName[0]==0 || zValue[0]==0 ){
8131f1c… drh 2432 if( zOldName[0] ){
8131f1c… drh 2433 blob_append_sql(pSql,
8131f1c… drh 2434 "DELETE FROM config WHERE name='walias:%q';\n",
8131f1c… drh 2435 zOldName);
8131f1c… drh 2436 }
8131f1c… drh 2437 return;
8131f1c… drh 2438 }
8131f1c… drh 2439 if( zOldName[0]==0 ){
8131f1c… drh 2440 blob_append_sql(pSql,
8131f1c… drh 2441 "INSERT INTO config(name,value,mtime) VALUES('walias:%q',%Q,now());\n",
8131f1c… drh 2442 zNewName, zValue);
8131f1c… drh 2443 return;
8131f1c… drh 2444 }
8131f1c… drh 2445 if( strcmp(zOldName, zNewName)!=0 ){
8131f1c… drh 2446 blob_append_sql(pSql,
8131f1c… drh 2447 "UPDATE config SET name='walias:%q', value=%Q, mtime=now()"
8131f1c… drh 2448 " WHERE name='walias:%q';\n",
8131f1c… drh 2449 zNewName, zValue, zOldName);
8131f1c… drh 2450 }else{
8131f1c… drh 2451 blob_append_sql(pSql,
8131f1c… drh 2452 "UPDATE config SET value=%Q, mtime=now()"
8131f1c… drh 2453 " WHERE name='walias:%q' AND value<>%Q;\n",
8131f1c… drh 2454 zValue, zOldName, zValue);
8131f1c… drh 2455 }
8131f1c… drh 2456 }
8131f1c… drh 2457
8131f1c… drh 2458 /*
8131f1c… drh 2459 ** WEBPAGE: waliassetup
8131f1c… drh 2460 **
8131f1c… drh 2461 ** Configure the URL aliases
8131f1c… drh 2462 */
8131f1c… drh 2463 void page_waliassetup(){
8131f1c… drh 2464 Stmt q;
8131f1c… drh 2465 int cnt = 0;
8131f1c… drh 2466 Blob namelist;
8131f1c… drh 2467 login_check_credentials();
42c3364… wyoung 2468 if( !g.perm.Admin ){
8131f1c… drh 2469 login_needed(0);
8131f1c… drh 2470 return;
8131f1c… drh 2471 }
112c713… drh 2472 style_set_current_feature("setup");
a3e50c9… andygoth 2473 style_header("URL Alias Configuration");
920ace1… drh 2474 if( P("submit")!=0 && cgi_csrf_safe(2) ){
8131f1c… drh 2475 Blob token;
8131f1c… drh 2476 Blob sql;
8131f1c… drh 2477 const char *zNewName;
8131f1c… drh 2478 const char *zValue;
8131f1c… drh 2479 char zCnt[10];
8131f1c… drh 2480 blob_init(&namelist, PD("namelist",""), -1);
8131f1c… drh 2481 blob_init(&sql, 0, 0);
8131f1c… drh 2482 while( blob_token(&namelist, &token) ){
8131f1c… drh 2483 const char *zOldName = blob_str(&token);
8131f1c… drh 2484 sqlite3_snprintf(sizeof(zCnt), zCnt, "n%d", cnt);
8131f1c… drh 2485 zNewName = PD(zCnt, "");
8131f1c… drh 2486 sqlite3_snprintf(sizeof(zCnt), zCnt, "v%d", cnt);
8131f1c… drh 2487 zValue = PD(zCnt, "");
8131f1c… drh 2488 setup_update_url_alias(&sql, zOldName, zNewName, zValue);
8131f1c… drh 2489 cnt++;
8131f1c… drh 2490 blob_reset(&token);
8131f1c… drh 2491 }
8131f1c… drh 2492 sqlite3_snprintf(sizeof(zCnt), zCnt, "n%d", cnt);
8131f1c… drh 2493 zNewName = PD(zCnt,"");
8131f1c… drh 2494 sqlite3_snprintf(sizeof(zCnt), zCnt, "v%d", cnt);
8131f1c… drh 2495 zValue = PD(zCnt,"");
8131f1c… drh 2496 setup_update_url_alias(&sql, "", zNewName, zValue);
f273832… mistachkin 2497 db_unprotect(PROTECT_CONFIG);
8131f1c… drh 2498 db_multi_exec("%s", blob_sql_text(&sql));
f273832… mistachkin 2499 db_protect_pop();
8131f1c… drh 2500 blob_reset(&sql);
8131f1c… drh 2501 blob_reset(&namelist);
8131f1c… drh 2502 cnt = 0;
8131f1c… drh 2503 }
8131f1c… drh 2504 db_prepare(&q,
8131f1c… drh 2505 "SELECT substr(name,8), value FROM config WHERE name GLOB 'walias:/*'"
8131f1c… drh 2506 " UNION ALL SELECT '', ''"
8131f1c… drh 2507 );
a40e8a0… drh 2508 @ <form action="%R/waliassetup" method="post"><div>
8131f1c… drh 2509 login_insert_csrf_secret();
8131f1c… drh 2510 @ <table border=0 cellpadding=5>
8131f1c… drh 2511 @ <tr><th>Alias<th>URI That The Alias Maps Into
8131f1c… drh 2512 blob_init(&namelist, 0, 0);
8131f1c… drh 2513 while( db_step(&q)==SQLITE_ROW ){
8131f1c… drh 2514 const char *zName = db_column_text(&q, 0);
8131f1c… drh 2515 const char *zValue = db_column_text(&q, 1);
8131f1c… drh 2516 @ <tr><td>
8131f1c… drh 2517 @ <input type='text' size='20' value='%h(zName)' name='n%d(cnt)'>
8131f1c… drh 2518 @ </td><td>
8131f1c… drh 2519 @ <input type='text' size='80' value='%h(zValue)' name='v%d(cnt)'>
8131f1c… drh 2520 @ </td></tr>
8131f1c… drh 2521 cnt++;
8131f1c… drh 2522 if( blob_size(&namelist)>0 ) blob_append(&namelist, " ", 1);
8131f1c… drh 2523 blob_append(&namelist, zName, -1);
8131f1c… drh 2524 }
8131f1c… drh 2525 db_finalize(&q);
8131f1c… drh 2526 @ <tr><td>
8131f1c… drh 2527 @ <input type='hidden' name='namelist' value='%h(blob_str(&namelist))'>
8131f1c… drh 2528 @ <input type='submit' name='submit' value="Apply Changes">
8131f1c… drh 2529 @ </td><td></td></tr>
8131f1c… drh 2530 @ </table></form>
a3b689b… drh 2531 @ <hr>
7001228… drh 2532 @ <p>When the first term of an incoming URL exactly matches one of
7001228… drh 2533 @ the "Aliases" on the left-hand side (LHS) above, the URL is
7001228… drh 2534 @ converted into the corresponding form on the right-hand side (RHS).
a3b689b… drh 2535 @ <ul>
a3b689b… drh 2536 @ <li><p>
a3b689b… drh 2537 @ The LHS is compared against only the first term of the incoming URL.
a3b689b… drh 2538 @ All LHS entries in the alias table should therefore begin with a
a3b689b… drh 2539 @ single "/" followed by a single path element.
a3b689b… drh 2540 @ <li><p>
7001228… drh 2541 @ The RHS entries in the alias table should begin with a single "/"
7001228… drh 2542 @ followed by a path element, and optionally followed by "?" and a
7001228… drh 2543 @ list of query parameters.
a3b689b… drh 2544 @ <li><p>
a3b689b… drh 2545 @ Query parameters on the RHS are added to the set of query parameters
a3b689b… drh 2546 @ in the incoming URL.
a3b689b… drh 2547 @ <li><p>
7001228… drh 2548 @ If the same query parameter appears in both the incoming URL and
7001228… drh 2549 @ on the RHS of the alias, the RHS query parameter value overwrites
7001228… drh 2550 @ the value on the incoming URL.
a3b689b… drh 2551 @ <li><p>
7001228… drh 2552 @ If a query parameter on the RHS of the alias is of the form "X!"
7001228… drh 2553 @ (a name followed by "!") then the X query parameter is removed
7001228… drh 2554 @ from the incoming URL if
7001228… drh 2555 @ it exists.
a3b689b… drh 2556 @ <li><p>
a3b689b… drh 2557 @ Only a single alias operation occurs. It is not possible to nest aliases.
a3b689b… drh 2558 @ The RHS entries must be built-in webpage names.
a3b689b… drh 2559 @ <li><p>
7001228… drh 2560 @ The alias table is only checked if no built-in webpage matches
7001228… drh 2561 @ the incoming URL.
7001228… drh 2562 @ Hence, it is not possible to override a built-in webpage using aliases.
7001228… drh 2563 @ This is by design.
a3b689b… drh 2564 @ </ul>
a3b689b… drh 2565 @
aad384d… andygoth 2566 @ <p>To delete an entry from the alias table, change its name or value to an
a3b689b… drh 2567 @ empty string and press "Apply Changes".
a3b689b… drh 2568 @
7001228… drh 2569 @ <p>To add a new alias, fill in the name and value in the bottom row
7001228… drh 2570 @ of the table above and press "Apply Changes".
112c713… drh 2571 style_finish_page();
dbda8d6… drh 2572 }

Keyboard Shortcuts

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