Fossil SCM
Provide the ability to shun an entire RCVID in a single click.
Commit
9b30c01e8b5af03c4e25616315ff0e970b5e76fe
Parent
f163faf128d36c7…
2 files changed
+134
-46
+4
+134
-46
| --- src/shun.c | ||
| +++ src/shun.c | ||
| @@ -40,12 +40,17 @@ | ||
| 40 | 40 | */ |
| 41 | 41 | void shun_page(void){ |
| 42 | 42 | Stmt q; |
| 43 | 43 | int cnt = 0; |
| 44 | 44 | const char *zUuid = P("uuid"); |
| 45 | + const char *zShun = P("shun"); | |
| 46 | + const char *zAccept = P("accept"); | |
| 47 | + const char *zRcvid = P("rcvid"); | |
| 48 | + int nRcvid; | |
| 45 | 49 | int nUuid; |
| 46 | - char zCanonical[UUID_SIZE+1]; | |
| 50 | + int numRows = 3; | |
| 51 | + char *zCanonical = 0; | |
| 47 | 52 | |
| 48 | 53 | login_check_credentials(); |
| 49 | 54 | if( !g.perm.Admin ){ |
| 50 | 55 | login_needed(); |
| 51 | 56 | } |
| @@ -55,71 +60,117 @@ | ||
| 55 | 60 | db_begin_transaction(); |
| 56 | 61 | rebuild_db(0, 0, 0); |
| 57 | 62 | db_end_transaction(0); |
| 58 | 63 | } |
| 59 | 64 | if( zUuid ){ |
| 60 | - nUuid = strlen(zUuid); | |
| 61 | - if( nUuid!=40 || !validate16(zUuid, nUuid) ){ | |
| 62 | - zUuid = 0; | |
| 63 | - }else{ | |
| 64 | - memcpy(zCanonical, zUuid, UUID_SIZE+1); | |
| 65 | - canonical16(zCanonical, UUID_SIZE); | |
| 66 | - zUuid = zCanonical; | |
| 67 | - } | |
| 65 | + char *p; | |
| 66 | + int i = 0; | |
| 67 | + int j = 0; | |
| 68 | + zCanonical = fossil_malloc(strlen(zUuid)+2); | |
| 69 | + while( zUuid[i] ){ | |
| 70 | + if( fossil_isspace(zUuid[i]) ){ | |
| 71 | + if( j && zCanonical[j-1] ){ | |
| 72 | + zCanonical[j] = 0; | |
| 73 | + j++; | |
| 74 | + } | |
| 75 | + }else{ | |
| 76 | + zCanonical[j] = zUuid[i]; | |
| 77 | + j++; | |
| 78 | + } | |
| 79 | + i++; | |
| 80 | + } | |
| 81 | + zCanonical[j+1] = zCanonical[j] = 0; | |
| 82 | + p = zCanonical; | |
| 83 | + while( *p ){ | |
| 84 | + nUuid = strlen(p); | |
| 85 | + if( nUuid!=UUID_SIZE || !validate16(p, nUuid) ){ | |
| 86 | + @ <p class="generalError">Error: Bad artifact IDs.</p> | |
| 87 | + fossil_free(zCanonical); | |
| 88 | + zCanonical = 0; | |
| 89 | + break; | |
| 90 | + }else{ | |
| 91 | + canonical16(p, UUID_SIZE); | |
| 92 | + p += UUID_SIZE+1; | |
| 93 | + } | |
| 94 | + } | |
| 95 | + zUuid = zCanonical; | |
| 68 | 96 | } |
| 69 | 97 | style_header("Shunned Artifacts"); |
| 70 | 98 | if( zUuid && P("sub") ){ |
| 99 | + const char *p = zUuid; | |
| 100 | + int allExist = 1; | |
| 71 | 101 | login_verify_csrf_secret(); |
| 72 | - db_multi_exec("DELETE FROM shun WHERE uuid='%s'", zUuid); | |
| 73 | - if( db_exists("SELECT 1 FROM blob WHERE uuid='%s'", zUuid) ){ | |
| 74 | - @ <p class="noMoreShun">Artifact | |
| 75 | - @ <a href="%s(g.zTop)/artifact/%s(zUuid)">%s(zUuid)</a> is no | |
| 76 | - @ longer being shunned.</p> | |
| 102 | + while( *p ){ | |
| 103 | + db_multi_exec("DELETE FROM shun WHERE uuid='%s'", p); | |
| 104 | + if( !db_exists("SELECT 1 FROM blob WHERE uuid='%s'", p) ){ | |
| 105 | + allExist = 0; | |
| 106 | + } | |
| 107 | + p += UUID_SIZE+1; | |
| 108 | + } | |
| 109 | + if( allExist ){ | |
| 110 | + @ <p class="noMoreShun">Artifact(s)<br /> | |
| 111 | + for( p = zUuid ; *p ; p += UUID_SIZE+1 ){ | |
| 112 | + @ <a href="%s(g.zTop)/artifact/%s(p)">%s(p)</a><br /> | |
| 113 | + } | |
| 114 | + @ are no longer being shunned.</p> | |
| 77 | 115 | }else{ |
| 78 | - @ <p class="noMoreShun">Artifact %s(zUuid) will no longer | |
| 79 | - @ be shunned. But it does not exist in the repository. It | |
| 80 | - @ may be necessary to rebuild the repository using the | |
| 116 | + @ <p class="noMoreShun">Artifact(s)<br /> | |
| 117 | + for( p = zUuid ; *p ; p += UUID_SIZE+1 ){ | |
| 118 | + @ %s(p)<br /> | |
| 119 | + } | |
| 120 | + @ will no longer be shunned. But they may not exist in the repository. | |
| 121 | + @ It may be necessary to rebuild the repository using the | |
| 81 | 122 | @ <b>fossil rebuild</b> command-line before the artifact content |
| 82 | 123 | @ can pulled in from other repositories.</p> |
| 83 | 124 | } |
| 84 | 125 | } |
| 85 | 126 | if( zUuid && P("add") ){ |
| 127 | + const char *p = zUuid; | |
| 86 | 128 | int rid, tagid; |
| 87 | 129 | login_verify_csrf_secret(); |
| 88 | - db_multi_exec( | |
| 89 | - "INSERT OR IGNORE INTO shun(uuid,mtime)" | |
| 90 | - " VALUES('%s', now())", zUuid); | |
| 91 | - @ <p class="shunned">Artifact | |
| 92 | - @ <a href="%s(g.zTop)/artifact/%s(zUuid)">%s(zUuid)</a> has been | |
| 93 | - @ shunned. It will no longer be pushed. | |
| 94 | - @ It will be removed from the repository the next time the repository | |
| 95 | - @ is rebuilt using the <b>fossil rebuild</b> command-line</p> | |
| 96 | - db_multi_exec("DELETE FROM attachment WHERE src=%Q", zUuid); | |
| 97 | - rid = db_int(0, "SELECT rid FROM blob WHERE uuid=%Q", zUuid); | |
| 98 | - if( rid ){ | |
| 99 | - db_multi_exec("DELETE FROM event WHERE objid=%d", rid); | |
| 100 | - } | |
| 101 | - tagid = db_int(0, "SELECT tagid FROM tag WHERE tagname='tkt-%q'", zUuid); | |
| 102 | - if( tagid ){ | |
| 103 | - db_multi_exec("DELETE FROM ticket WHERE tkt_uuid=%Q", zUuid); | |
| 104 | - db_multi_exec("DELETE FROM tag WHERE tagid=%d", tagid); | |
| 105 | - db_multi_exec("DELETE FROM tagxref WHERE tagid=%d", tagid); | |
| 106 | - } | |
| 130 | + while( *p ){ | |
| 131 | + db_multi_exec( | |
| 132 | + "INSERT OR IGNORE INTO shun(uuid,mtime)" | |
| 133 | + " VALUES('%s', now())", p); | |
| 134 | + db_multi_exec("DELETE FROM attachment WHERE src=%Q", p); | |
| 135 | + rid = db_int(0, "SELECT rid FROM blob WHERE uuid=%Q", p); | |
| 136 | + if( rid ){ | |
| 137 | + db_multi_exec("DELETE FROM event WHERE objid=%d", rid); | |
| 138 | + } | |
| 139 | + tagid = db_int(0, "SELECT tagid FROM tag WHERE tagname='tkt-%q'", p); | |
| 140 | + if( tagid ){ | |
| 141 | + db_multi_exec("DELETE FROM ticket WHERE tkt_uuid=%Q", p); | |
| 142 | + db_multi_exec("DELETE FROM tag WHERE tagid=%d", tagid); | |
| 143 | + db_multi_exec("DELETE FROM tagxref WHERE tagid=%d", tagid); | |
| 144 | + } | |
| 145 | + p += UUID_SIZE+1; | |
| 146 | + } | |
| 147 | + @ <p class="shunned">Artifact(s)<br /> | |
| 148 | + for( p = zUuid ; *p ; p += UUID_SIZE+1 ){ | |
| 149 | + @ <a href="%s(g.zTop)/artifact/%s(p)">%s(p)</a><br /> | |
| 150 | + } | |
| 151 | + @ have been shunned. They will no longer be pushed. | |
| 152 | + @ They will be removed from the repository the next time the repository | |
| 153 | + @ is rebuilt using the <b>fossil rebuild</b> command-line</p> | |
| 154 | + } | |
| 155 | + if( zRcvid ){ | |
| 156 | + nRcvid = atoi(zRcvid); | |
| 157 | + numRows = db_int(0, "SELECT min(count(), 10) FROM blob WHERE rcvid=%d", nRcvid); | |
| 107 | 158 | } |
| 108 | 159 | @ <p>A shunned artifact will not be pushed nor accepted in a pull and the |
| 109 | 160 | @ artifact content will be purged from the repository the next time the |
| 110 | 161 | @ repository is rebuilt. A list of shunned artifacts can be seen at the |
| 111 | 162 | @ bottom of this page.</p> |
| 112 | 163 | @ |
| 113 | 164 | @ <a name="addshun"></a> |
| 114 | - @ <p>To shun an artifact, enter its artifact ID (the 40-character SHA1 | |
| 115 | - @ hash of the artifact) in the | |
| 116 | - @ following box and press the "Shun" button. This will cause the artifact | |
| 117 | - @ to be removed from the repository and will prevent the artifact from being | |
| 165 | + @ <p>To shun artifacts, enter their artifact IDs (the 40-character SHA1 | |
| 166 | + @ hash of the artifacts) in the | |
| 167 | + @ following box and press the "Shun" button. This will cause the artifacts | |
| 168 | + @ to be removed from the repository and will prevent the artifacts from being | |
| 118 | 169 | @ readded to the repository by subsequent sync operation.</p> |
| 119 | 170 | @ |
| 120 | - @ <p>Note that you must enter the full 40-character artifact ID, not | |
| 171 | + @ <p>Note that you must enter the full 40-character artifact IDs, not | |
| 121 | 172 | @ an abbreviation or a symbolic tag.</p> |
| 122 | 173 | @ |
| 123 | 174 | @ <p>Warning: Shunning should only be used to remove inappropriate content |
| 124 | 175 | @ from the repository. Inappropriate content includes such things as |
| 125 | 176 | @ spam added to Wiki, files that violate copyright or patent agreements, |
| @@ -128,26 +179,50 @@ | ||
| 128 | 179 | @ sight - set the "hidden" tag on such artifacts instead.</p> |
| 129 | 180 | @ |
| 130 | 181 | @ <blockquote> |
| 131 | 182 | @ <form method="post" action="%s(g.zTop)/%s(g.zPath)"><div> |
| 132 | 183 | login_insert_csrf_secret(); |
| 133 | - @ <input type="text" name="uuid" value="%h(PD("shun",""))" size="50" /> | |
| 184 | + @ <textarea class="fullsize-text" cols="50" rows="%d(numRows)" name="uuid"> | |
| 185 | + if( zShun ){ | |
| 186 | + if( strlen(zShun) ){ | |
| 187 | + @ %h(zShun) | |
| 188 | + }else if( zRcvid ){ | |
| 189 | + db_prepare(&q, "SELECT uuid FROM blob WHERE rcvid=%d", nRcvid); | |
| 190 | + while( db_step(&q)==SQLITE_ROW ){ | |
| 191 | + @ %s(db_column_text(&q, 0)) | |
| 192 | + } | |
| 193 | + db_finalize(&q); | |
| 194 | + } | |
| 195 | + } | |
| 196 | + @ </textarea> | |
| 134 | 197 | @ <input type="submit" name="add" value="Shun" /> |
| 135 | 198 | @ </div></form> |
| 136 | 199 | @ </blockquote> |
| 137 | 200 | @ |
| 138 | 201 | @ <a name="delshun"></a> |
| 139 | - @ <p>Enter the UUID of a previous shunned artifact to cause it to be | |
| 140 | - @ accepted again in the repository. The artifact content is not | |
| 202 | + @ <p>Enter the UUIDs of previously shunned artifacts to cause them to be | |
| 203 | + @ accepted again in the repository. The artifacts content is not | |
| 141 | 204 | @ restored because the content is unknown. The only change is that |
| 142 | - @ the formerly shunned artifact will be accepted on subsequent sync | |
| 205 | + @ the formerly shunned artifacts will be accepted on subsequent sync | |
| 143 | 206 | @ operations.</p> |
| 144 | 207 | @ |
| 145 | 208 | @ <blockquote> |
| 146 | 209 | @ <form method="post" action="%s(g.zTop)/%s(g.zPath)"><div> |
| 147 | 210 | login_insert_csrf_secret(); |
| 148 | - @ <input type="text" name="uuid" value="%h(PD("accept", ""))" size="50" /> | |
| 211 | + @ <textarea class="fullsize-text" cols="50" rows="%d(numRows)" name="uuid"> | |
| 212 | + if( zAccept ){ | |
| 213 | + if( strlen(zAccept) ){ | |
| 214 | + @ %h(zAccept) | |
| 215 | + }else if( zRcvid ){ | |
| 216 | + db_prepare(&q, "SELECT uuid FROM blob WHERE rcvid=%d", nRcvid); | |
| 217 | + while( db_step(&q)==SQLITE_ROW ){ | |
| 218 | + @ %s(db_column_text(&q, 0)) | |
| 219 | + } | |
| 220 | + db_finalize(&q); | |
| 221 | + } | |
| 222 | + } | |
| 223 | + @ </textarea> | |
| 149 | 224 | @ <input type="submit" name="sub" value="Accept" /> |
| 150 | 225 | @ </div></form> |
| 151 | 226 | @ </blockquote> |
| 152 | 227 | @ |
| 153 | 228 | @ <p>Press the Rebuild button below to rebuild the repository. The |
| @@ -181,10 +256,11 @@ | ||
| 181 | 256 | @ <i>no artifacts are shunned on this server</i> |
| 182 | 257 | } |
| 183 | 258 | db_finalize(&q); |
| 184 | 259 | @ </p></blockquote> |
| 185 | 260 | style_footer(); |
| 261 | + fossil_free(zCanonical); | |
| 186 | 262 | } |
| 187 | 263 | |
| 188 | 264 | /* |
| 189 | 265 | ** Remove from the BLOB table all artifacts that are in the SHUN table. |
| 190 | 266 | */ |
| @@ -287,10 +363,22 @@ | ||
| 287 | 363 | login_check_credentials(); |
| 288 | 364 | if( !g.perm.Admin ){ |
| 289 | 365 | login_needed(); |
| 290 | 366 | } |
| 291 | 367 | style_header("Content Source %d", rcvid); |
| 368 | + if( db_exists( | |
| 369 | + "SELECT 1 FROM blob WHERE rcvid=%d AND" | |
| 370 | + " NOT EXISTS (SELECT 1 FROM shun WHERE shun.uuid=blob.uuid)", rcvid) | |
| 371 | + ){ | |
| 372 | + style_submenu_element("Shun All", "Shun All", "shun?shun&rcvid=%d#addshun", rcvid); | |
| 373 | + } | |
| 374 | + if( db_exists( | |
| 375 | + "SELECT 1 FROM blob WHERE rcvid=%d AND" | |
| 376 | + " EXISTS (SELECT 1 FROM shun WHERE shun.uuid=blob.uuid)", rcvid) | |
| 377 | + ){ | |
| 378 | + style_submenu_element("Unshun All", "Unshun All", "shun?accept&rcvid=%d#delshun", rcvid); | |
| 379 | + } | |
| 292 | 380 | db_prepare(&q, |
| 293 | 381 | "SELECT login, datetime(rcvfrom.mtime), rcvfrom.ipaddr" |
| 294 | 382 | " FROM rcvfrom LEFT JOIN user USING(uid)" |
| 295 | 383 | " WHERE rcvid=%d", |
| 296 | 384 | rcvid |
| 297 | 385 |
| --- src/shun.c | |
| +++ src/shun.c | |
| @@ -40,12 +40,17 @@ | |
| 40 | */ |
| 41 | void shun_page(void){ |
| 42 | Stmt q; |
| 43 | int cnt = 0; |
| 44 | const char *zUuid = P("uuid"); |
| 45 | int nUuid; |
| 46 | char zCanonical[UUID_SIZE+1]; |
| 47 | |
| 48 | login_check_credentials(); |
| 49 | if( !g.perm.Admin ){ |
| 50 | login_needed(); |
| 51 | } |
| @@ -55,71 +60,117 @@ | |
| 55 | db_begin_transaction(); |
| 56 | rebuild_db(0, 0, 0); |
| 57 | db_end_transaction(0); |
| 58 | } |
| 59 | if( zUuid ){ |
| 60 | nUuid = strlen(zUuid); |
| 61 | if( nUuid!=40 || !validate16(zUuid, nUuid) ){ |
| 62 | zUuid = 0; |
| 63 | }else{ |
| 64 | memcpy(zCanonical, zUuid, UUID_SIZE+1); |
| 65 | canonical16(zCanonical, UUID_SIZE); |
| 66 | zUuid = zCanonical; |
| 67 | } |
| 68 | } |
| 69 | style_header("Shunned Artifacts"); |
| 70 | if( zUuid && P("sub") ){ |
| 71 | login_verify_csrf_secret(); |
| 72 | db_multi_exec("DELETE FROM shun WHERE uuid='%s'", zUuid); |
| 73 | if( db_exists("SELECT 1 FROM blob WHERE uuid='%s'", zUuid) ){ |
| 74 | @ <p class="noMoreShun">Artifact |
| 75 | @ <a href="%s(g.zTop)/artifact/%s(zUuid)">%s(zUuid)</a> is no |
| 76 | @ longer being shunned.</p> |
| 77 | }else{ |
| 78 | @ <p class="noMoreShun">Artifact %s(zUuid) will no longer |
| 79 | @ be shunned. But it does not exist in the repository. It |
| 80 | @ may be necessary to rebuild the repository using the |
| 81 | @ <b>fossil rebuild</b> command-line before the artifact content |
| 82 | @ can pulled in from other repositories.</p> |
| 83 | } |
| 84 | } |
| 85 | if( zUuid && P("add") ){ |
| 86 | int rid, tagid; |
| 87 | login_verify_csrf_secret(); |
| 88 | db_multi_exec( |
| 89 | "INSERT OR IGNORE INTO shun(uuid,mtime)" |
| 90 | " VALUES('%s', now())", zUuid); |
| 91 | @ <p class="shunned">Artifact |
| 92 | @ <a href="%s(g.zTop)/artifact/%s(zUuid)">%s(zUuid)</a> has been |
| 93 | @ shunned. It will no longer be pushed. |
| 94 | @ It will be removed from the repository the next time the repository |
| 95 | @ is rebuilt using the <b>fossil rebuild</b> command-line</p> |
| 96 | db_multi_exec("DELETE FROM attachment WHERE src=%Q", zUuid); |
| 97 | rid = db_int(0, "SELECT rid FROM blob WHERE uuid=%Q", zUuid); |
| 98 | if( rid ){ |
| 99 | db_multi_exec("DELETE FROM event WHERE objid=%d", rid); |
| 100 | } |
| 101 | tagid = db_int(0, "SELECT tagid FROM tag WHERE tagname='tkt-%q'", zUuid); |
| 102 | if( tagid ){ |
| 103 | db_multi_exec("DELETE FROM ticket WHERE tkt_uuid=%Q", zUuid); |
| 104 | db_multi_exec("DELETE FROM tag WHERE tagid=%d", tagid); |
| 105 | db_multi_exec("DELETE FROM tagxref WHERE tagid=%d", tagid); |
| 106 | } |
| 107 | } |
| 108 | @ <p>A shunned artifact will not be pushed nor accepted in a pull and the |
| 109 | @ artifact content will be purged from the repository the next time the |
| 110 | @ repository is rebuilt. A list of shunned artifacts can be seen at the |
| 111 | @ bottom of this page.</p> |
| 112 | @ |
| 113 | @ <a name="addshun"></a> |
| 114 | @ <p>To shun an artifact, enter its artifact ID (the 40-character SHA1 |
| 115 | @ hash of the artifact) in the |
| 116 | @ following box and press the "Shun" button. This will cause the artifact |
| 117 | @ to be removed from the repository and will prevent the artifact from being |
| 118 | @ readded to the repository by subsequent sync operation.</p> |
| 119 | @ |
| 120 | @ <p>Note that you must enter the full 40-character artifact ID, not |
| 121 | @ an abbreviation or a symbolic tag.</p> |
| 122 | @ |
| 123 | @ <p>Warning: Shunning should only be used to remove inappropriate content |
| 124 | @ from the repository. Inappropriate content includes such things as |
| 125 | @ spam added to Wiki, files that violate copyright or patent agreements, |
| @@ -128,26 +179,50 @@ | |
| 128 | @ sight - set the "hidden" tag on such artifacts instead.</p> |
| 129 | @ |
| 130 | @ <blockquote> |
| 131 | @ <form method="post" action="%s(g.zTop)/%s(g.zPath)"><div> |
| 132 | login_insert_csrf_secret(); |
| 133 | @ <input type="text" name="uuid" value="%h(PD("shun",""))" size="50" /> |
| 134 | @ <input type="submit" name="add" value="Shun" /> |
| 135 | @ </div></form> |
| 136 | @ </blockquote> |
| 137 | @ |
| 138 | @ <a name="delshun"></a> |
| 139 | @ <p>Enter the UUID of a previous shunned artifact to cause it to be |
| 140 | @ accepted again in the repository. The artifact content is not |
| 141 | @ restored because the content is unknown. The only change is that |
| 142 | @ the formerly shunned artifact will be accepted on subsequent sync |
| 143 | @ operations.</p> |
| 144 | @ |
| 145 | @ <blockquote> |
| 146 | @ <form method="post" action="%s(g.zTop)/%s(g.zPath)"><div> |
| 147 | login_insert_csrf_secret(); |
| 148 | @ <input type="text" name="uuid" value="%h(PD("accept", ""))" size="50" /> |
| 149 | @ <input type="submit" name="sub" value="Accept" /> |
| 150 | @ </div></form> |
| 151 | @ </blockquote> |
| 152 | @ |
| 153 | @ <p>Press the Rebuild button below to rebuild the repository. The |
| @@ -181,10 +256,11 @@ | |
| 181 | @ <i>no artifacts are shunned on this server</i> |
| 182 | } |
| 183 | db_finalize(&q); |
| 184 | @ </p></blockquote> |
| 185 | style_footer(); |
| 186 | } |
| 187 | |
| 188 | /* |
| 189 | ** Remove from the BLOB table all artifacts that are in the SHUN table. |
| 190 | */ |
| @@ -287,10 +363,22 @@ | |
| 287 | login_check_credentials(); |
| 288 | if( !g.perm.Admin ){ |
| 289 | login_needed(); |
| 290 | } |
| 291 | style_header("Content Source %d", rcvid); |
| 292 | db_prepare(&q, |
| 293 | "SELECT login, datetime(rcvfrom.mtime), rcvfrom.ipaddr" |
| 294 | " FROM rcvfrom LEFT JOIN user USING(uid)" |
| 295 | " WHERE rcvid=%d", |
| 296 | rcvid |
| 297 |
| --- src/shun.c | |
| +++ src/shun.c | |
| @@ -40,12 +40,17 @@ | |
| 40 | */ |
| 41 | void shun_page(void){ |
| 42 | Stmt q; |
| 43 | int cnt = 0; |
| 44 | const char *zUuid = P("uuid"); |
| 45 | const char *zShun = P("shun"); |
| 46 | const char *zAccept = P("accept"); |
| 47 | const char *zRcvid = P("rcvid"); |
| 48 | int nRcvid; |
| 49 | int nUuid; |
| 50 | int numRows = 3; |
| 51 | char *zCanonical = 0; |
| 52 | |
| 53 | login_check_credentials(); |
| 54 | if( !g.perm.Admin ){ |
| 55 | login_needed(); |
| 56 | } |
| @@ -55,71 +60,117 @@ | |
| 60 | db_begin_transaction(); |
| 61 | rebuild_db(0, 0, 0); |
| 62 | db_end_transaction(0); |
| 63 | } |
| 64 | if( zUuid ){ |
| 65 | char *p; |
| 66 | int i = 0; |
| 67 | int j = 0; |
| 68 | zCanonical = fossil_malloc(strlen(zUuid)+2); |
| 69 | while( zUuid[i] ){ |
| 70 | if( fossil_isspace(zUuid[i]) ){ |
| 71 | if( j && zCanonical[j-1] ){ |
| 72 | zCanonical[j] = 0; |
| 73 | j++; |
| 74 | } |
| 75 | }else{ |
| 76 | zCanonical[j] = zUuid[i]; |
| 77 | j++; |
| 78 | } |
| 79 | i++; |
| 80 | } |
| 81 | zCanonical[j+1] = zCanonical[j] = 0; |
| 82 | p = zCanonical; |
| 83 | while( *p ){ |
| 84 | nUuid = strlen(p); |
| 85 | if( nUuid!=UUID_SIZE || !validate16(p, nUuid) ){ |
| 86 | @ <p class="generalError">Error: Bad artifact IDs.</p> |
| 87 | fossil_free(zCanonical); |
| 88 | zCanonical = 0; |
| 89 | break; |
| 90 | }else{ |
| 91 | canonical16(p, UUID_SIZE); |
| 92 | p += UUID_SIZE+1; |
| 93 | } |
| 94 | } |
| 95 | zUuid = zCanonical; |
| 96 | } |
| 97 | style_header("Shunned Artifacts"); |
| 98 | if( zUuid && P("sub") ){ |
| 99 | const char *p = zUuid; |
| 100 | int allExist = 1; |
| 101 | login_verify_csrf_secret(); |
| 102 | while( *p ){ |
| 103 | db_multi_exec("DELETE FROM shun WHERE uuid='%s'", p); |
| 104 | if( !db_exists("SELECT 1 FROM blob WHERE uuid='%s'", p) ){ |
| 105 | allExist = 0; |
| 106 | } |
| 107 | p += UUID_SIZE+1; |
| 108 | } |
| 109 | if( allExist ){ |
| 110 | @ <p class="noMoreShun">Artifact(s)<br /> |
| 111 | for( p = zUuid ; *p ; p += UUID_SIZE+1 ){ |
| 112 | @ <a href="%s(g.zTop)/artifact/%s(p)">%s(p)</a><br /> |
| 113 | } |
| 114 | @ are no longer being shunned.</p> |
| 115 | }else{ |
| 116 | @ <p class="noMoreShun">Artifact(s)<br /> |
| 117 | for( p = zUuid ; *p ; p += UUID_SIZE+1 ){ |
| 118 | @ %s(p)<br /> |
| 119 | } |
| 120 | @ will no longer be shunned. But they may not exist in the repository. |
| 121 | @ It may be necessary to rebuild the repository using the |
| 122 | @ <b>fossil rebuild</b> command-line before the artifact content |
| 123 | @ can pulled in from other repositories.</p> |
| 124 | } |
| 125 | } |
| 126 | if( zUuid && P("add") ){ |
| 127 | const char *p = zUuid; |
| 128 | int rid, tagid; |
| 129 | login_verify_csrf_secret(); |
| 130 | while( *p ){ |
| 131 | db_multi_exec( |
| 132 | "INSERT OR IGNORE INTO shun(uuid,mtime)" |
| 133 | " VALUES('%s', now())", p); |
| 134 | db_multi_exec("DELETE FROM attachment WHERE src=%Q", p); |
| 135 | rid = db_int(0, "SELECT rid FROM blob WHERE uuid=%Q", p); |
| 136 | if( rid ){ |
| 137 | db_multi_exec("DELETE FROM event WHERE objid=%d", rid); |
| 138 | } |
| 139 | tagid = db_int(0, "SELECT tagid FROM tag WHERE tagname='tkt-%q'", p); |
| 140 | if( tagid ){ |
| 141 | db_multi_exec("DELETE FROM ticket WHERE tkt_uuid=%Q", p); |
| 142 | db_multi_exec("DELETE FROM tag WHERE tagid=%d", tagid); |
| 143 | db_multi_exec("DELETE FROM tagxref WHERE tagid=%d", tagid); |
| 144 | } |
| 145 | p += UUID_SIZE+1; |
| 146 | } |
| 147 | @ <p class="shunned">Artifact(s)<br /> |
| 148 | for( p = zUuid ; *p ; p += UUID_SIZE+1 ){ |
| 149 | @ <a href="%s(g.zTop)/artifact/%s(p)">%s(p)</a><br /> |
| 150 | } |
| 151 | @ have been shunned. They will no longer be pushed. |
| 152 | @ They will be removed from the repository the next time the repository |
| 153 | @ is rebuilt using the <b>fossil rebuild</b> command-line</p> |
| 154 | } |
| 155 | if( zRcvid ){ |
| 156 | nRcvid = atoi(zRcvid); |
| 157 | numRows = db_int(0, "SELECT min(count(), 10) FROM blob WHERE rcvid=%d", nRcvid); |
| 158 | } |
| 159 | @ <p>A shunned artifact will not be pushed nor accepted in a pull and the |
| 160 | @ artifact content will be purged from the repository the next time the |
| 161 | @ repository is rebuilt. A list of shunned artifacts can be seen at the |
| 162 | @ bottom of this page.</p> |
| 163 | @ |
| 164 | @ <a name="addshun"></a> |
| 165 | @ <p>To shun artifacts, enter their artifact IDs (the 40-character SHA1 |
| 166 | @ hash of the artifacts) in the |
| 167 | @ following box and press the "Shun" button. This will cause the artifacts |
| 168 | @ to be removed from the repository and will prevent the artifacts from being |
| 169 | @ readded to the repository by subsequent sync operation.</p> |
| 170 | @ |
| 171 | @ <p>Note that you must enter the full 40-character artifact IDs, not |
| 172 | @ an abbreviation or a symbolic tag.</p> |
| 173 | @ |
| 174 | @ <p>Warning: Shunning should only be used to remove inappropriate content |
| 175 | @ from the repository. Inappropriate content includes such things as |
| 176 | @ spam added to Wiki, files that violate copyright or patent agreements, |
| @@ -128,26 +179,50 @@ | |
| 179 | @ sight - set the "hidden" tag on such artifacts instead.</p> |
| 180 | @ |
| 181 | @ <blockquote> |
| 182 | @ <form method="post" action="%s(g.zTop)/%s(g.zPath)"><div> |
| 183 | login_insert_csrf_secret(); |
| 184 | @ <textarea class="fullsize-text" cols="50" rows="%d(numRows)" name="uuid"> |
| 185 | if( zShun ){ |
| 186 | if( strlen(zShun) ){ |
| 187 | @ %h(zShun) |
| 188 | }else if( zRcvid ){ |
| 189 | db_prepare(&q, "SELECT uuid FROM blob WHERE rcvid=%d", nRcvid); |
| 190 | while( db_step(&q)==SQLITE_ROW ){ |
| 191 | @ %s(db_column_text(&q, 0)) |
| 192 | } |
| 193 | db_finalize(&q); |
| 194 | } |
| 195 | } |
| 196 | @ </textarea> |
| 197 | @ <input type="submit" name="add" value="Shun" /> |
| 198 | @ </div></form> |
| 199 | @ </blockquote> |
| 200 | @ |
| 201 | @ <a name="delshun"></a> |
| 202 | @ <p>Enter the UUIDs of previously shunned artifacts to cause them to be |
| 203 | @ accepted again in the repository. The artifacts content is not |
| 204 | @ restored because the content is unknown. The only change is that |
| 205 | @ the formerly shunned artifacts will be accepted on subsequent sync |
| 206 | @ operations.</p> |
| 207 | @ |
| 208 | @ <blockquote> |
| 209 | @ <form method="post" action="%s(g.zTop)/%s(g.zPath)"><div> |
| 210 | login_insert_csrf_secret(); |
| 211 | @ <textarea class="fullsize-text" cols="50" rows="%d(numRows)" name="uuid"> |
| 212 | if( zAccept ){ |
| 213 | if( strlen(zAccept) ){ |
| 214 | @ %h(zAccept) |
| 215 | }else if( zRcvid ){ |
| 216 | db_prepare(&q, "SELECT uuid FROM blob WHERE rcvid=%d", nRcvid); |
| 217 | while( db_step(&q)==SQLITE_ROW ){ |
| 218 | @ %s(db_column_text(&q, 0)) |
| 219 | } |
| 220 | db_finalize(&q); |
| 221 | } |
| 222 | } |
| 223 | @ </textarea> |
| 224 | @ <input type="submit" name="sub" value="Accept" /> |
| 225 | @ </div></form> |
| 226 | @ </blockquote> |
| 227 | @ |
| 228 | @ <p>Press the Rebuild button below to rebuild the repository. The |
| @@ -181,10 +256,11 @@ | |
| 256 | @ <i>no artifacts are shunned on this server</i> |
| 257 | } |
| 258 | db_finalize(&q); |
| 259 | @ </p></blockquote> |
| 260 | style_footer(); |
| 261 | fossil_free(zCanonical); |
| 262 | } |
| 263 | |
| 264 | /* |
| 265 | ** Remove from the BLOB table all artifacts that are in the SHUN table. |
| 266 | */ |
| @@ -287,10 +363,22 @@ | |
| 363 | login_check_credentials(); |
| 364 | if( !g.perm.Admin ){ |
| 365 | login_needed(); |
| 366 | } |
| 367 | style_header("Content Source %d", rcvid); |
| 368 | if( db_exists( |
| 369 | "SELECT 1 FROM blob WHERE rcvid=%d AND" |
| 370 | " NOT EXISTS (SELECT 1 FROM shun WHERE shun.uuid=blob.uuid)", rcvid) |
| 371 | ){ |
| 372 | style_submenu_element("Shun All", "Shun All", "shun?shun&rcvid=%d#addshun", rcvid); |
| 373 | } |
| 374 | if( db_exists( |
| 375 | "SELECT 1 FROM blob WHERE rcvid=%d AND" |
| 376 | " EXISTS (SELECT 1 FROM shun WHERE shun.uuid=blob.uuid)", rcvid) |
| 377 | ){ |
| 378 | style_submenu_element("Unshun All", "Unshun All", "shun?accept&rcvid=%d#delshun", rcvid); |
| 379 | } |
| 380 | db_prepare(&q, |
| 381 | "SELECT login, datetime(rcvfrom.mtime), rcvfrom.ipaddr" |
| 382 | " FROM rcvfrom LEFT JOIN user USING(uid)" |
| 383 | " WHERE rcvid=%d", |
| 384 | rcvid |
| 385 |
+4
| --- src/skins.c | ||
| +++ src/skins.c | ||
| @@ -874,10 +874,14 @@ | ||
| 874 | 874 | @ cursor: pointer; |
| 875 | 875 | @ } |
| 876 | 876 | @ |
| 877 | 877 | @ textarea { |
| 878 | 878 | @ font-size: 1em; |
| 879 | +@ } | |
| 880 | +@ | |
| 881 | +@ .fullsize-text { | |
| 882 | +@ font-size: 1.25em; | |
| 879 | 883 | @ }'); |
| 880 | 884 | @ REPLACE INTO config(name,mtime,value) VALUES('header',now(),'<html> |
| 881 | 885 | @ <head> |
| 882 | 886 | @ <base href="$baseurl/$current_page" /> |
| 883 | 887 | @ <title>$<project_name>: $<title></title> |
| 884 | 888 |
| --- src/skins.c | |
| +++ src/skins.c | |
| @@ -874,10 +874,14 @@ | |
| 874 | @ cursor: pointer; |
| 875 | @ } |
| 876 | @ |
| 877 | @ textarea { |
| 878 | @ font-size: 1em; |
| 879 | @ }'); |
| 880 | @ REPLACE INTO config(name,mtime,value) VALUES('header',now(),'<html> |
| 881 | @ <head> |
| 882 | @ <base href="$baseurl/$current_page" /> |
| 883 | @ <title>$<project_name>: $<title></title> |
| 884 |
| --- src/skins.c | |
| +++ src/skins.c | |
| @@ -874,10 +874,14 @@ | |
| 874 | @ cursor: pointer; |
| 875 | @ } |
| 876 | @ |
| 877 | @ textarea { |
| 878 | @ font-size: 1em; |
| 879 | @ } |
| 880 | @ |
| 881 | @ .fullsize-text { |
| 882 | @ font-size: 1.25em; |
| 883 | @ }'); |
| 884 | @ REPLACE INTO config(name,mtime,value) VALUES('header',now(),'<html> |
| 885 | @ <head> |
| 886 | @ <base href="$baseurl/$current_page" /> |
| 887 | @ <title>$<project_name>: $<title></title> |
| 888 |