Fossil SCM
Revamp the user list setup page. Show the last change time and expiration date for each login. Make the user list sortable using javascript.
Commit
01b1319931e282166dbd3e8b6defd91efee90b7e
Parent
5853fcf132800f9…
1 file changed
+89
-63
+89
-63
| --- src/setup.c | ||
| +++ src/setup.c | ||
| @@ -153,71 +153,98 @@ | ||
| 153 | 153 | login_needed(0); |
| 154 | 154 | return; |
| 155 | 155 | } |
| 156 | 156 | |
| 157 | 157 | style_submenu_element("Add", "Add User", "setup_uedit"); |
| 158 | - style_header("User List"); | |
| 159 | - @ <table class="usetupLayoutTable"> | |
| 160 | - @ <tr><td class="usetupColumnLayout"> | |
| 161 | - @ <span class="note">Users:</span> | |
| 162 | - @ <table class="usetupUserList"> | |
| 163 | - prevLevel = 0; | |
| 164 | - db_prepare(&s, | |
| 165 | - "SELECT uid, login, cap, info, 1 FROM user" | |
| 166 | - " WHERE login IN ('anonymous','nobody','developer','reader') " | |
| 167 | - " UNION ALL " | |
| 168 | - "SELECT uid, login, cap, info, 2 FROM user" | |
| 169 | - " WHERE login NOT IN ('anonymous','nobody','developer','reader') " | |
| 170 | - "ORDER BY 5, 2 COLLATE nocase" | |
| 171 | - ); | |
| 172 | - while( db_step(&s)==SQLITE_ROW ){ | |
| 173 | - int iLevel = db_column_int(&s, 4); | |
| 174 | - const char *zCap = db_column_text(&s, 2); | |
| 175 | - const char *zLogin = db_column_text(&s, 1); | |
| 176 | - if( iLevel>prevLevel ){ | |
| 177 | - if( prevLevel>0 ){ | |
| 178 | - @ <tr><td colspan="3"><hr></td></tr> | |
| 179 | - } | |
| 180 | - if( iLevel==1 ){ | |
| 181 | - @ <tr> | |
| 182 | - @ <th class="usetupListUser" | |
| 183 | - @ style="text-align: right;padding-right: 20px;">Category</th> | |
| 184 | - @ <th class="usetupListCap" | |
| 185 | - @ style="text-align: center;padding-right: 15px;">Capabilities</th> | |
| 186 | - @ <th class="usetupListCon" | |
| 187 | - @ style="text-align: left;">Notes</th> | |
| 188 | - @ </tr> | |
| 189 | - }else{ | |
| 190 | - @ <tr> | |
| 191 | - @ <th class="usetupListUser" | |
| 192 | - @ style="text-align: right;padding-right: 20px;">User ID</th> | |
| 193 | - @ <th class="usetupListCap" | |
| 194 | - @ style="text-align: center;padding-right: 15px;">Capabilities</th> | |
| 195 | - @ <th class="usetupListCon" | |
| 196 | - @ style="text-align: left;">Contact Info</th> | |
| 197 | - @ </tr> | |
| 198 | - } | |
| 199 | - prevLevel = iLevel; | |
| 200 | - } | |
| 201 | - @ <tr> | |
| 202 | - @ <td class="usetupListUser" | |
| 203 | - @ style="text-align: right;padding-right: 20px;white-space:nowrap;"> | |
| 204 | - if( g.perm.Admin && (zCap[0]!='s' || g.perm.Setup) ){ | |
| 205 | - @ <a href="setup_uedit?id=%d(db_column_int(&s,0))"> | |
| 206 | - } | |
| 207 | - @ %h(zLogin) | |
| 208 | - if( g.perm.Admin ){ | |
| 209 | - @ </a> | |
| 210 | - } | |
| 211 | - @ </td> | |
| 212 | - @ <td class="usetupListCap" style="text-align: center;padding-right: 15px;">%s(zCap)</td> | |
| 213 | - @ <td class="usetupListCon" style="text-align: left;">%h(db_column_text(&s,3))</td> | |
| 214 | - @ </tr> | |
| 215 | - } | |
| 216 | - @ </table> | |
| 217 | - @ </td><td class="usetupColumnLayout"> | |
| 218 | - @ <span class="note">Notes:</span> | |
| 158 | + style_submenu_element("Help", "Help", "setup_ulist_notes"); | |
| 159 | + style_header("User List"); | |
| 160 | + @ <table border=1 cellpadding=2 cellspacing=0 class='userTable'> | |
| 161 | + @ <thead><tr><th>UID <th>Category <th>Capabilities <th>Info <th>Last Change</tr></thead> | |
| 162 | + @ <tbody> | |
| 163 | + db_prepare(&s, | |
| 164 | + "SELECT uid, login, cap, date(mtime,'unixepoch')" | |
| 165 | + " FROM user" | |
| 166 | + " WHERE login IN ('anonymous','nobody','developer','reader')" | |
| 167 | + " ORDER BY login" | |
| 168 | + ); | |
| 169 | + while( db_step(&s)==SQLITE_ROW ){ | |
| 170 | + int uid = db_column_int(&s, 0); | |
| 171 | + const char *zLogin = db_column_text(&s, 1); | |
| 172 | + const char *zCap = db_column_text(&s, 2); | |
| 173 | + const char *zDate = db_column_text(&s, 4); | |
| 174 | + @ <tr> | |
| 175 | + @ <td><a href='setup_uedit?id=%d(uid)'>%d(uid)</a> | |
| 176 | + @ <td><a href='setup_uedit?id=%d(uid)'>%h(zLogin)</a> | |
| 177 | + @ <td>%h(zCap) | |
| 178 | + | |
| 179 | + if( fossil_strcmp(zLogin,"anonymous")==0 ){ | |
| 180 | + @ <td>All logged-in users | |
| 181 | + }else if( fossil_strcmp(zLogin,"developer")==0 ){ | |
| 182 | + @ <td>Users with '<b>v</b>' capability | |
| 183 | + }else if( fossil_strcmp(zLogin,"nobody")==0 ){ | |
| 184 | + @ <td>All users without login | |
| 185 | + }else if( fossil_strcmp(zLogin,"reader")==0 ){ | |
| 186 | + @ <td>Users with '<b>u</b>' capability | |
| 187 | + }else{ | |
| 188 | + @ <td> | |
| 189 | + } | |
| 190 | + if( zDate && zDate[0] ){ | |
| 191 | + @ <td>%h(zDate) | |
| 192 | + }else{ | |
| 193 | + @ <td> | |
| 194 | + } | |
| 195 | + @ </tr> | |
| 196 | + } | |
| 197 | + db_finalize(&s); | |
| 198 | + @ </tbody></table> | |
| 199 | + @ <div class='section'>Users</div> | |
| 200 | + @ <table border=1 cellpadding=2 cellspacing=0 class='userTable' id='userlist'> | |
| 201 | + @ <thead><tr> | |
| 202 | + @ <th>ID<th>Login<th>Caps<th>Info<th>Chng<th>Expire</tr></thead> | |
| 203 | + @ <tbody> | |
| 204 | + db_prepare(&s, | |
| 205 | + "SELECT uid, login, cap, info, date(mtime,'unixepoch'), lower(login) AS sortkey, " | |
| 206 | + " CASE WHEN info LIKE '%%expires 20%%'" | |
| 207 | + " THEN substr(info,instr(lower(info),'expires')+8,10)" | |
| 208 | + " END AS exp" | |
| 209 | + " FROM user" | |
| 210 | + " WHERE login NOT IN ('anonymous','nobody','developer','reader')" | |
| 211 | + " ORDER BY sortkey" | |
| 212 | + ); | |
| 213 | + while( db_step(&s)==SQLITE_ROW ){ | |
| 214 | + int uid = db_column_int(&s, 0); | |
| 215 | + const char *zLogin = db_column_text(&s, 1); | |
| 216 | + const char *zCap = db_column_text(&s, 2); | |
| 217 | + const char *zInfo = db_column_text(&s, 3); | |
| 218 | + const char *zDate = db_column_text(&s, 4); | |
| 219 | + const char *zSortKey = db_column_text(&s,5); | |
| 220 | + const char *zExp = db_column_text(&s,6); | |
| 221 | + @ <tr> | |
| 222 | + @ <td><a href='setup_uedit?id=%d(uid)'>%d(uid)</a> | |
| 223 | + @ <td data-sortkey='%h(zSortKey)'><a href='setup_uedit?id=%d(uid)'>%h(zLogin)</a> | |
| 224 | + @ <td>%h(zCap) | |
| 225 | + @ <td>%h(zInfo) | |
| 226 | + @ <td>%h(zDate?zDate:"") | |
| 227 | + @ <td>%h(zExp?zExp:"") | |
| 228 | + @ </tr> | |
| 229 | + } | |
| 230 | + @ </tbody></table> | |
| 231 | + db_finalize(&s); | |
| 232 | + output_table_sorting_javascript("userlist","nktxTT",2); | |
| 233 | + style_footer(); | |
| 234 | +} | |
| 235 | + | |
| 236 | +/* | |
| 237 | +** WEBPAGE: setup_ulist_notes | |
| 238 | +** | |
| 239 | +** A documentation page showing notes about user configuration. This information | |
| 240 | +** used to be a side-bar on the user list page, but has been factored out for | |
| 241 | +** improved presentation. | |
| 242 | +*/ | |
| 243 | +void setup_ulist_notes(void){ | |
| 244 | + style_header("User Configuration Notes"); | |
| 245 | + @ <h1>User Configuration Notes:</h1> | |
| 219 | 246 | @ <ol> |
| 220 | 247 | @ <li><p>The permission flags are as follows:</p> |
| 221 | 248 | @ <table> |
| 222 | 249 | @ <tr><th valign="top">a</th> |
| 223 | 250 | @ <td><i>Admin:</i> Create and delete users</td></tr> |
| @@ -295,14 +322,13 @@ | ||
| 295 | 322 | @ <span class="usertype">anonymous</span>, and |
| 296 | 323 | @ <span class="usertype">nobody</span>. |
| 297 | 324 | @ </p></li> |
| 298 | 325 | @ |
| 299 | 326 | @ </ol> |
| 300 | - @ </td></tr></table> | |
| 301 | 327 | style_footer(); |
| 302 | - db_finalize(&s); | |
| 303 | 328 | } |
| 329 | + | |
| 304 | 330 | |
| 305 | 331 | /* |
| 306 | 332 | ** Return true if zPw is a valid password string. A valid |
| 307 | 333 | ** password string is: |
| 308 | 334 | ** |
| 309 | 335 |
| --- src/setup.c | |
| +++ src/setup.c | |
| @@ -153,71 +153,98 @@ | |
| 153 | login_needed(0); |
| 154 | return; |
| 155 | } |
| 156 | |
| 157 | style_submenu_element("Add", "Add User", "setup_uedit"); |
| 158 | style_header("User List"); |
| 159 | @ <table class="usetupLayoutTable"> |
| 160 | @ <tr><td class="usetupColumnLayout"> |
| 161 | @ <span class="note">Users:</span> |
| 162 | @ <table class="usetupUserList"> |
| 163 | prevLevel = 0; |
| 164 | db_prepare(&s, |
| 165 | "SELECT uid, login, cap, info, 1 FROM user" |
| 166 | " WHERE login IN ('anonymous','nobody','developer','reader') " |
| 167 | " UNION ALL " |
| 168 | "SELECT uid, login, cap, info, 2 FROM user" |
| 169 | " WHERE login NOT IN ('anonymous','nobody','developer','reader') " |
| 170 | "ORDER BY 5, 2 COLLATE nocase" |
| 171 | ); |
| 172 | while( db_step(&s)==SQLITE_ROW ){ |
| 173 | int iLevel = db_column_int(&s, 4); |
| 174 | const char *zCap = db_column_text(&s, 2); |
| 175 | const char *zLogin = db_column_text(&s, 1); |
| 176 | if( iLevel>prevLevel ){ |
| 177 | if( prevLevel>0 ){ |
| 178 | @ <tr><td colspan="3"><hr></td></tr> |
| 179 | } |
| 180 | if( iLevel==1 ){ |
| 181 | @ <tr> |
| 182 | @ <th class="usetupListUser" |
| 183 | @ style="text-align: right;padding-right: 20px;">Category</th> |
| 184 | @ <th class="usetupListCap" |
| 185 | @ style="text-align: center;padding-right: 15px;">Capabilities</th> |
| 186 | @ <th class="usetupListCon" |
| 187 | @ style="text-align: left;">Notes</th> |
| 188 | @ </tr> |
| 189 | }else{ |
| 190 | @ <tr> |
| 191 | @ <th class="usetupListUser" |
| 192 | @ style="text-align: right;padding-right: 20px;">User ID</th> |
| 193 | @ <th class="usetupListCap" |
| 194 | @ style="text-align: center;padding-right: 15px;">Capabilities</th> |
| 195 | @ <th class="usetupListCon" |
| 196 | @ style="text-align: left;">Contact Info</th> |
| 197 | @ </tr> |
| 198 | } |
| 199 | prevLevel = iLevel; |
| 200 | } |
| 201 | @ <tr> |
| 202 | @ <td class="usetupListUser" |
| 203 | @ style="text-align: right;padding-right: 20px;white-space:nowrap;"> |
| 204 | if( g.perm.Admin && (zCap[0]!='s' || g.perm.Setup) ){ |
| 205 | @ <a href="setup_uedit?id=%d(db_column_int(&s,0))"> |
| 206 | } |
| 207 | @ %h(zLogin) |
| 208 | if( g.perm.Admin ){ |
| 209 | @ </a> |
| 210 | } |
| 211 | @ </td> |
| 212 | @ <td class="usetupListCap" style="text-align: center;padding-right: 15px;">%s(zCap)</td> |
| 213 | @ <td class="usetupListCon" style="text-align: left;">%h(db_column_text(&s,3))</td> |
| 214 | @ </tr> |
| 215 | } |
| 216 | @ </table> |
| 217 | @ </td><td class="usetupColumnLayout"> |
| 218 | @ <span class="note">Notes:</span> |
| 219 | @ <ol> |
| 220 | @ <li><p>The permission flags are as follows:</p> |
| 221 | @ <table> |
| 222 | @ <tr><th valign="top">a</th> |
| 223 | @ <td><i>Admin:</i> Create and delete users</td></tr> |
| @@ -295,14 +322,13 @@ | |
| 295 | @ <span class="usertype">anonymous</span>, and |
| 296 | @ <span class="usertype">nobody</span>. |
| 297 | @ </p></li> |
| 298 | @ |
| 299 | @ </ol> |
| 300 | @ </td></tr></table> |
| 301 | style_footer(); |
| 302 | db_finalize(&s); |
| 303 | } |
| 304 | |
| 305 | /* |
| 306 | ** Return true if zPw is a valid password string. A valid |
| 307 | ** password string is: |
| 308 | ** |
| 309 |
| --- src/setup.c | |
| +++ src/setup.c | |
| @@ -153,71 +153,98 @@ | |
| 153 | login_needed(0); |
| 154 | return; |
| 155 | } |
| 156 | |
| 157 | style_submenu_element("Add", "Add User", "setup_uedit"); |
| 158 | style_submenu_element("Help", "Help", "setup_ulist_notes"); |
| 159 | style_header("User List"); |
| 160 | @ <table border=1 cellpadding=2 cellspacing=0 class='userTable'> |
| 161 | @ <thead><tr><th>UID <th>Category <th>Capabilities <th>Info <th>Last Change</tr></thead> |
| 162 | @ <tbody> |
| 163 | db_prepare(&s, |
| 164 | "SELECT uid, login, cap, date(mtime,'unixepoch')" |
| 165 | " FROM user" |
| 166 | " WHERE login IN ('anonymous','nobody','developer','reader')" |
| 167 | " ORDER BY login" |
| 168 | ); |
| 169 | while( db_step(&s)==SQLITE_ROW ){ |
| 170 | int uid = db_column_int(&s, 0); |
| 171 | const char *zLogin = db_column_text(&s, 1); |
| 172 | const char *zCap = db_column_text(&s, 2); |
| 173 | const char *zDate = db_column_text(&s, 4); |
| 174 | @ <tr> |
| 175 | @ <td><a href='setup_uedit?id=%d(uid)'>%d(uid)</a> |
| 176 | @ <td><a href='setup_uedit?id=%d(uid)'>%h(zLogin)</a> |
| 177 | @ <td>%h(zCap) |
| 178 | |
| 179 | if( fossil_strcmp(zLogin,"anonymous")==0 ){ |
| 180 | @ <td>All logged-in users |
| 181 | }else if( fossil_strcmp(zLogin,"developer")==0 ){ |
| 182 | @ <td>Users with '<b>v</b>' capability |
| 183 | }else if( fossil_strcmp(zLogin,"nobody")==0 ){ |
| 184 | @ <td>All users without login |
| 185 | }else if( fossil_strcmp(zLogin,"reader")==0 ){ |
| 186 | @ <td>Users with '<b>u</b>' capability |
| 187 | }else{ |
| 188 | @ <td> |
| 189 | } |
| 190 | if( zDate && zDate[0] ){ |
| 191 | @ <td>%h(zDate) |
| 192 | }else{ |
| 193 | @ <td> |
| 194 | } |
| 195 | @ </tr> |
| 196 | } |
| 197 | db_finalize(&s); |
| 198 | @ </tbody></table> |
| 199 | @ <div class='section'>Users</div> |
| 200 | @ <table border=1 cellpadding=2 cellspacing=0 class='userTable' id='userlist'> |
| 201 | @ <thead><tr> |
| 202 | @ <th>ID<th>Login<th>Caps<th>Info<th>Chng<th>Expire</tr></thead> |
| 203 | @ <tbody> |
| 204 | db_prepare(&s, |
| 205 | "SELECT uid, login, cap, info, date(mtime,'unixepoch'), lower(login) AS sortkey, " |
| 206 | " CASE WHEN info LIKE '%%expires 20%%'" |
| 207 | " THEN substr(info,instr(lower(info),'expires')+8,10)" |
| 208 | " END AS exp" |
| 209 | " FROM user" |
| 210 | " WHERE login NOT IN ('anonymous','nobody','developer','reader')" |
| 211 | " ORDER BY sortkey" |
| 212 | ); |
| 213 | while( db_step(&s)==SQLITE_ROW ){ |
| 214 | int uid = db_column_int(&s, 0); |
| 215 | const char *zLogin = db_column_text(&s, 1); |
| 216 | const char *zCap = db_column_text(&s, 2); |
| 217 | const char *zInfo = db_column_text(&s, 3); |
| 218 | const char *zDate = db_column_text(&s, 4); |
| 219 | const char *zSortKey = db_column_text(&s,5); |
| 220 | const char *zExp = db_column_text(&s,6); |
| 221 | @ <tr> |
| 222 | @ <td><a href='setup_uedit?id=%d(uid)'>%d(uid)</a> |
| 223 | @ <td data-sortkey='%h(zSortKey)'><a href='setup_uedit?id=%d(uid)'>%h(zLogin)</a> |
| 224 | @ <td>%h(zCap) |
| 225 | @ <td>%h(zInfo) |
| 226 | @ <td>%h(zDate?zDate:"") |
| 227 | @ <td>%h(zExp?zExp:"") |
| 228 | @ </tr> |
| 229 | } |
| 230 | @ </tbody></table> |
| 231 | db_finalize(&s); |
| 232 | output_table_sorting_javascript("userlist","nktxTT",2); |
| 233 | style_footer(); |
| 234 | } |
| 235 | |
| 236 | /* |
| 237 | ** WEBPAGE: setup_ulist_notes |
| 238 | ** |
| 239 | ** A documentation page showing notes about user configuration. This information |
| 240 | ** used to be a side-bar on the user list page, but has been factored out for |
| 241 | ** improved presentation. |
| 242 | */ |
| 243 | void setup_ulist_notes(void){ |
| 244 | style_header("User Configuration Notes"); |
| 245 | @ <h1>User Configuration Notes:</h1> |
| 246 | @ <ol> |
| 247 | @ <li><p>The permission flags are as follows:</p> |
| 248 | @ <table> |
| 249 | @ <tr><th valign="top">a</th> |
| 250 | @ <td><i>Admin:</i> Create and delete users</td></tr> |
| @@ -295,14 +322,13 @@ | |
| 322 | @ <span class="usertype">anonymous</span>, and |
| 323 | @ <span class="usertype">nobody</span>. |
| 324 | @ </p></li> |
| 325 | @ |
| 326 | @ </ol> |
| 327 | style_footer(); |
| 328 | } |
| 329 | |
| 330 | |
| 331 | /* |
| 332 | ** Return true if zPw is a valid password string. A valid |
| 333 | ** password string is: |
| 334 | ** |
| 335 |