Fossil SCM

Added basic /admin_log page, added settings change logging through onoff_attribute().

stephan 2014-11-28 17:38 UTC admin-logging
Commit 8f1fc455819bddb82817503b6aae72e093b84962
3 files changed +8 -4 +63 -2 +10
+8 -4
--- src/db.c
+++ src/db.c
@@ -2692,27 +2692,31 @@
26922692
if( once ) return;
26932693
once = 1;
26942694
db_multi_exec(
26952695
"CREATE TABLE IF NOT EXISTS \"%w\".admin_log(\n"
26962696
" id INTEGER PRIMARY KEY,\n"
2697
- " time FLOAT, -- Seconds since 1970\n"
2697
+ " time INTEGER, -- Seconds since 1970\n"
26982698
" page TEXT, -- path of page\n"
26992699
" who TEXT, -- User who made the change\n "
27002700
" what TEXT -- What changed\n"
27012701
")", db_name("repository")
27022702
);
27032703
}
27042704
27052705
/*
27062706
** Write a message into the admin_event table, if admin logging is
2707
-** enabled
2707
+** enabled via the admin-log configuration option.
27082708
*/
27092709
void admin_log(const char *zFormat, ...){
27102710
Blob what = empty_blob;
27112711
va_list ap;
2712
- int rc;
2713
- if( !db_get_boolean("admin-log", 0) ) return;
2712
+ if( !db_get_boolean("admin-log", 0) ){
2713
+ /* Potential leak here (on %z params) but
2714
+ the alternative is to let blob_vappendf()
2715
+ do it below. */
2716
+ return;
2717
+ }
27142718
create_admin_log_table();
27152719
va_start(ap,zFormat);
27162720
blob_vappendf( &what, zFormat, ap );
27172721
va_end(ap);
27182722
db_multi_exec("INSERT INTO admin_log(time,page,who,what)"
27192723
--- src/db.c
+++ src/db.c
@@ -2692,27 +2692,31 @@
2692 if( once ) return;
2693 once = 1;
2694 db_multi_exec(
2695 "CREATE TABLE IF NOT EXISTS \"%w\".admin_log(\n"
2696 " id INTEGER PRIMARY KEY,\n"
2697 " time FLOAT, -- Seconds since 1970\n"
2698 " page TEXT, -- path of page\n"
2699 " who TEXT, -- User who made the change\n "
2700 " what TEXT -- What changed\n"
2701 ")", db_name("repository")
2702 );
2703 }
2704
2705 /*
2706 ** Write a message into the admin_event table, if admin logging is
2707 ** enabled
2708 */
2709 void admin_log(const char *zFormat, ...){
2710 Blob what = empty_blob;
2711 va_list ap;
2712 int rc;
2713 if( !db_get_boolean("admin-log", 0) ) return;
 
 
 
 
2714 create_admin_log_table();
2715 va_start(ap,zFormat);
2716 blob_vappendf( &what, zFormat, ap );
2717 va_end(ap);
2718 db_multi_exec("INSERT INTO admin_log(time,page,who,what)"
2719
--- src/db.c
+++ src/db.c
@@ -2692,27 +2692,31 @@
2692 if( once ) return;
2693 once = 1;
2694 db_multi_exec(
2695 "CREATE TABLE IF NOT EXISTS \"%w\".admin_log(\n"
2696 " id INTEGER PRIMARY KEY,\n"
2697 " time INTEGER, -- Seconds since 1970\n"
2698 " page TEXT, -- path of page\n"
2699 " who TEXT, -- User who made the change\n "
2700 " what TEXT -- What changed\n"
2701 ")", db_name("repository")
2702 );
2703 }
2704
2705 /*
2706 ** Write a message into the admin_event table, if admin logging is
2707 ** enabled via the admin-log configuration option.
2708 */
2709 void admin_log(const char *zFormat, ...){
2710 Blob what = empty_blob;
2711 va_list ap;
2712 if( !db_get_boolean("admin-log", 0) ){
2713 /* Potential leak here (on %z params) but
2714 the alternative is to let blob_vappendf()
2715 do it below. */
2716 return;
2717 }
2718 create_admin_log_table();
2719 va_start(ap,zFormat);
2720 blob_vappendf( &what, zFormat, ap );
2721 va_end(ap);
2722 db_multi_exec("INSERT INTO admin_log(time,page,who,what)"
2723
+63 -2
--- src/setup.c
+++ src/setup.c
@@ -109,10 +109,12 @@
109109
"Show artifacts that are shunned by this repository");
110110
setup_menu_entry("Log", "rcvfromlist",
111111
"A record of received artifacts and their sources");
112112
setup_menu_entry("User-Log", "access_log",
113113
"A record of login attempts");
114
+ setup_menu_entry("Admin-Log", "admin_log",
115
+ "View the admin_log entries");
114116
setup_menu_entry("Stats", "stat",
115117
"Display repository statistics");
116118
setup_menu_entry("SQL", "admin_sql",
117119
"Enter raw SQL commands");
118120
setup_menu_entry("TH1", "admin_th1",
@@ -382,11 +384,12 @@
382384
db_multi_exec(
383385
"REPLACE INTO user(uid,login,info,pw,cap,mtime) "
384386
"VALUES(nullif(%d,0),%Q,%Q,%Q,%Q,now())",
385387
uid, zLogin, P("info"), zPw, zCap
386388
);
387
- admin_log( "Updated user %Q with capapbilities [%q].", zLogin, zCap );
389
+ admin_log( "Updated user [%q] with capabilities [%q].",
390
+ zLogin, zCap );
388391
if( atoi(PD("all","0"))>0 ){
389392
Blob sql;
390393
char *zErr = 0;
391394
blob_zero(&sql);
392395
if( zOldLogin==0 ){
@@ -408,11 +411,13 @@
408411
zLogin, P("pw"), zLogin, P("info"), zCap,
409412
zOldLogin
410413
);
411414
login_group_sql(blob_str(&sql), "<li> ", " </li>\n", &zErr);
412415
blob_reset(&sql);
413
- admin_log( "Updated user '%q' with capapbilities.", zLogin, zCap );
416
+ admin_log( "Updated user [%q] in all login groups "
417
+ "with capabilities [%q].",
418
+ zLogin, zCap );
414419
if( zErr ){
415420
style_header("User Change Error");
416421
admin_log( "Error updating user '%q': %s'.", zLogin, zErr );
417422
@ <span class="loginError">%s(zErr)</span>
418423
@
@@ -865,10 +870,12 @@
865870
if( zQ ){
866871
int iQ = fossil_strcmp(zQ,"on")==0 || atoi(zQ);
867872
if( iQ!=iVal ){
868873
login_verify_csrf_secret();
869874
db_set(zVar, iQ ? "1" : "0", 0);
875
+ admin_log("Set option [%q] to [%q].",
876
+ zVar, iQ ? "on" : "off");
870877
iVal = iQ;
871878
}
872879
}
873880
@ <input type="checkbox" name="%s(zQParm)"
874881
if( iVal ){
@@ -2026,5 +2033,59 @@
20262033
@ <pre class="th1error">%h(zR)</pre>
20272034
}
20282035
}
20292036
style_footer();
20302037
}
2038
+
2039
+/*
2040
+** WEBPAGE: admin_log
2041
+**
2042
+*/
2043
+void page_admin_log(){
2044
+ Stmt stLog = empty_Stmt;
2045
+ Blob qLog = empty_blob;
2046
+ int limit;
2047
+ int fLogEnabled;
2048
+ int counter = 0;
2049
+ login_check_credentials();
2050
+ if( !g.perm.Setup && !g.perm.Admin ){
2051
+ login_needed();
2052
+ }
2053
+ style_header("Admin Log");
2054
+ create_admin_log_table();
2055
+ limit = atoi(PD("n","20"));
2056
+ fLogEnabled = db_get_boolean("admin-log", 0);
2057
+ @ Admin logging is %s(fLogEnabled?"on":"off").
2058
+
2059
+ blob_append_sql(&qLog,
2060
+ "SELECT datetime(time,'unixepoch'), who, page, what "
2061
+ "FROM admin_log "
2062
+ "ORDER BY time DESC ");
2063
+ if(limit>0){
2064
+ @ %d(limit) Most recent entries:
2065
+ blob_append_sql(&qLog, "LIMIT %d", limit);
2066
+ }
2067
+
2068
+ db_prepare(&stLog, "%s", blob_sql_text(&qLog));
2069
+ blob_reset(&qLog);
2070
+ @ <table id="adminLogTable" class="adminLogTable" width="100%%">
2071
+ @ <thead>
2072
+ @ <th>Time</th>
2073
+ @ <th>User</th>
2074
+ @ <th>Page</th>
2075
+ @ <th width="60%%">Message</th>
2076
+ @ </thead><tbody>
2077
+ while( SQLITE_ROW == db_step(&stLog) ){
2078
+ char const * zTime = db_column_text(&stLog, 0);
2079
+ char const * zUser = db_column_text(&stLog, 1);
2080
+ char const * zPage = db_column_text(&stLog, 2);
2081
+ char const * zMessage = db_column_text(&stLog, 3);
2082
+ @ <tr class="row%d(counter++%2)">
2083
+ @ <td class="adminTime">%s(zTime)</td>
2084
+ @ <td>%s(zUser)</td>
2085
+ @ <td>%s(zPage)</td>
2086
+ @ <td>%s(zMessage)</td>
2087
+ @ </tr>
2088
+ }
2089
+ @ </tbody></table>
2090
+ style_footer();
2091
+}
20312092
--- src/setup.c
+++ src/setup.c
@@ -109,10 +109,12 @@
109 "Show artifacts that are shunned by this repository");
110 setup_menu_entry("Log", "rcvfromlist",
111 "A record of received artifacts and their sources");
112 setup_menu_entry("User-Log", "access_log",
113 "A record of login attempts");
 
 
114 setup_menu_entry("Stats", "stat",
115 "Display repository statistics");
116 setup_menu_entry("SQL", "admin_sql",
117 "Enter raw SQL commands");
118 setup_menu_entry("TH1", "admin_th1",
@@ -382,11 +384,12 @@
382 db_multi_exec(
383 "REPLACE INTO user(uid,login,info,pw,cap,mtime) "
384 "VALUES(nullif(%d,0),%Q,%Q,%Q,%Q,now())",
385 uid, zLogin, P("info"), zPw, zCap
386 );
387 admin_log( "Updated user %Q with capapbilities [%q].", zLogin, zCap );
 
388 if( atoi(PD("all","0"))>0 ){
389 Blob sql;
390 char *zErr = 0;
391 blob_zero(&sql);
392 if( zOldLogin==0 ){
@@ -408,11 +411,13 @@
408 zLogin, P("pw"), zLogin, P("info"), zCap,
409 zOldLogin
410 );
411 login_group_sql(blob_str(&sql), "<li> ", " </li>\n", &zErr);
412 blob_reset(&sql);
413 admin_log( "Updated user '%q' with capapbilities.", zLogin, zCap );
 
 
414 if( zErr ){
415 style_header("User Change Error");
416 admin_log( "Error updating user '%q': %s'.", zLogin, zErr );
417 @ <span class="loginError">%s(zErr)</span>
418 @
@@ -865,10 +870,12 @@
865 if( zQ ){
866 int iQ = fossil_strcmp(zQ,"on")==0 || atoi(zQ);
867 if( iQ!=iVal ){
868 login_verify_csrf_secret();
869 db_set(zVar, iQ ? "1" : "0", 0);
 
 
870 iVal = iQ;
871 }
872 }
873 @ <input type="checkbox" name="%s(zQParm)"
874 if( iVal ){
@@ -2026,5 +2033,59 @@
2026 @ <pre class="th1error">%h(zR)</pre>
2027 }
2028 }
2029 style_footer();
2030 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2031
--- src/setup.c
+++ src/setup.c
@@ -109,10 +109,12 @@
109 "Show artifacts that are shunned by this repository");
110 setup_menu_entry("Log", "rcvfromlist",
111 "A record of received artifacts and their sources");
112 setup_menu_entry("User-Log", "access_log",
113 "A record of login attempts");
114 setup_menu_entry("Admin-Log", "admin_log",
115 "View the admin_log entries");
116 setup_menu_entry("Stats", "stat",
117 "Display repository statistics");
118 setup_menu_entry("SQL", "admin_sql",
119 "Enter raw SQL commands");
120 setup_menu_entry("TH1", "admin_th1",
@@ -382,11 +384,12 @@
384 db_multi_exec(
385 "REPLACE INTO user(uid,login,info,pw,cap,mtime) "
386 "VALUES(nullif(%d,0),%Q,%Q,%Q,%Q,now())",
387 uid, zLogin, P("info"), zPw, zCap
388 );
389 admin_log( "Updated user [%q] with capabilities [%q].",
390 zLogin, zCap );
391 if( atoi(PD("all","0"))>0 ){
392 Blob sql;
393 char *zErr = 0;
394 blob_zero(&sql);
395 if( zOldLogin==0 ){
@@ -408,11 +411,13 @@
411 zLogin, P("pw"), zLogin, P("info"), zCap,
412 zOldLogin
413 );
414 login_group_sql(blob_str(&sql), "<li> ", " </li>\n", &zErr);
415 blob_reset(&sql);
416 admin_log( "Updated user [%q] in all login groups "
417 "with capabilities [%q].",
418 zLogin, zCap );
419 if( zErr ){
420 style_header("User Change Error");
421 admin_log( "Error updating user '%q': %s'.", zLogin, zErr );
422 @ <span class="loginError">%s(zErr)</span>
423 @
@@ -865,10 +870,12 @@
870 if( zQ ){
871 int iQ = fossil_strcmp(zQ,"on")==0 || atoi(zQ);
872 if( iQ!=iVal ){
873 login_verify_csrf_secret();
874 db_set(zVar, iQ ? "1" : "0", 0);
875 admin_log("Set option [%q] to [%q].",
876 zVar, iQ ? "on" : "off");
877 iVal = iQ;
878 }
879 }
880 @ <input type="checkbox" name="%s(zQParm)"
881 if( iVal ){
@@ -2026,5 +2033,59 @@
2033 @ <pre class="th1error">%h(zR)</pre>
2034 }
2035 }
2036 style_footer();
2037 }
2038
2039 /*
2040 ** WEBPAGE: admin_log
2041 **
2042 */
2043 void page_admin_log(){
2044 Stmt stLog = empty_Stmt;
2045 Blob qLog = empty_blob;
2046 int limit;
2047 int fLogEnabled;
2048 int counter = 0;
2049 login_check_credentials();
2050 if( !g.perm.Setup && !g.perm.Admin ){
2051 login_needed();
2052 }
2053 style_header("Admin Log");
2054 create_admin_log_table();
2055 limit = atoi(PD("n","20"));
2056 fLogEnabled = db_get_boolean("admin-log", 0);
2057 @ Admin logging is %s(fLogEnabled?"on":"off").
2058
2059 blob_append_sql(&qLog,
2060 "SELECT datetime(time,'unixepoch'), who, page, what "
2061 "FROM admin_log "
2062 "ORDER BY time DESC ");
2063 if(limit>0){
2064 @ %d(limit) Most recent entries:
2065 blob_append_sql(&qLog, "LIMIT %d", limit);
2066 }
2067
2068 db_prepare(&stLog, "%s", blob_sql_text(&qLog));
2069 blob_reset(&qLog);
2070 @ <table id="adminLogTable" class="adminLogTable" width="100%%">
2071 @ <thead>
2072 @ <th>Time</th>
2073 @ <th>User</th>
2074 @ <th>Page</th>
2075 @ <th width="60%%">Message</th>
2076 @ </thead><tbody>
2077 while( SQLITE_ROW == db_step(&stLog) ){
2078 char const * zTime = db_column_text(&stLog, 0);
2079 char const * zUser = db_column_text(&stLog, 1);
2080 char const * zPage = db_column_text(&stLog, 2);
2081 char const * zMessage = db_column_text(&stLog, 3);
2082 @ <tr class="row%d(counter++%2)">
2083 @ <td class="adminTime">%s(zTime)</td>
2084 @ <td>%s(zUser)</td>
2085 @ <td>%s(zPage)</td>
2086 @ <td>%s(zMessage)</td>
2087 @ </tr>
2088 }
2089 @ </tbody></table>
2090 style_footer();
2091 }
2092
+10
--- src/style.c
+++ src/style.c
@@ -1208,10 +1208,20 @@
12081208
@ font-weight: bold;
12091209
},
12101210
{ "#canvas", "timeline graph node colors",
12111211
@ color: black;
12121212
@ background-color: white;
1213
+ },
1214
+ { "table.adminLogTable",
1215
+ "Class for the /admin_log table",
1216
+ @ text-align: left
1217
+ },
1218
+ { ".adminLogTable .adminTime",
1219
+ "Class for the /admin_log table",
1220
+ @ text-align: left
1221
+ @ vertical-align: top;
1222
+ @ white-space: nowrap;
12131223
},
12141224
{ 0,
12151225
0,
12161226
0
12171227
}
12181228
--- src/style.c
+++ src/style.c
@@ -1208,10 +1208,20 @@
1208 @ font-weight: bold;
1209 },
1210 { "#canvas", "timeline graph node colors",
1211 @ color: black;
1212 @ background-color: white;
 
 
 
 
 
 
 
 
 
 
1213 },
1214 { 0,
1215 0,
1216 0
1217 }
1218
--- src/style.c
+++ src/style.c
@@ -1208,10 +1208,20 @@
1208 @ font-weight: bold;
1209 },
1210 { "#canvas", "timeline graph node colors",
1211 @ color: black;
1212 @ background-color: white;
1213 },
1214 { "table.adminLogTable",
1215 "Class for the /admin_log table",
1216 @ text-align: left
1217 },
1218 { ".adminLogTable .adminTime",
1219 "Class for the /admin_log table",
1220 @ text-align: left
1221 @ vertical-align: top;
1222 @ white-space: nowrap;
1223 },
1224 { 0,
1225 0,
1226 0
1227 }
1228

Keyboard Shortcuts

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