Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
| SHA1 Hash: | 01c0180b3f084975f5fbb9f251681df02f694fb5 |
|---|---|
| Date: | 2010-03-18 02:11:47 |
| User: | drh |
| Comment: | Add the ability to delete attachments and fix issues with timelines. |
Tags And Properties
- bgcolor=#c0ffc0 inherited from [c3d7df650b]
- branch=experimental inherited from [c3d7df650b]
- sym-experimental inherited from [c3d7df650b]
Changes
Changes to src/attach.c
62 if( g.okRdTkt==0 && g.okRdWiki==0 ) login_needed(); 62 if( g.okRdTkt==0 && g.okRdWiki==0 ) login_needed(); 63 style_header("All Attachments"); 63 style_header("All Attachments"); 64 } 64 } 65 blob_appendf(&sql, " ORDER BY mtime DESC"); 65 blob_appendf(&sql, " ORDER BY mtime DESC"); 66 db_prepare(&q, "%s", blob_str(&sql)); 66 db_prepare(&q, "%s", blob_str(&sql)); 67 while( db_step(&q)==SQLITE_ROW ){ 67 while( db_step(&q)==SQLITE_ROW ){ 68 const char *zDate = db_column_text(&q, 0); 68 const char *zDate = db_column_text(&q, 0); 69 /* const char *zSrc = db_column_text(&q, 1); */ | 69 const char *zSrc = db_column_text(&q, 1); 70 const char *zTarget = db_column_text(&q, 2); 70 const char *zTarget = db_column_text(&q, 2); 71 const char *zFilename = db_column_text(&q, 3); 71 const char *zFilename = db_column_text(&q, 3); 72 const char *zComment = db_column_text(&q, 4); 72 const char *zComment = db_column_text(&q, 4); 73 const char *zUser = db_column_text(&q, 5); 73 const char *zUser = db_column_text(&q, 5); 74 int i; 74 int i; 75 char *zUrlTail; 75 char *zUrlTail; 76 for(i=0; zFilename[i]; i++){ 76 for(i=0; zFilename[i]; i++){ ................................................................................................................................................................................ 83 zUrlTail = mprintf("tkt=%s&file=%t", zTarget, zFilename); 83 zUrlTail = mprintf("tkt=%s&file=%t", zTarget, zFilename); 84 }else{ 84 }else{ 85 zUrlTail = mprintf("page=%t&file=%t", zTarget, zFilename); 85 zUrlTail = mprintf("page=%t&file=%t", zTarget, zFilename); 86 } 86 } 87 @ 87 @ 88 @ <p><a href="/attachview?%s(zUrlTail)">%h(zFilename)</a> 88 @ <p><a href="/attachview?%s(zUrlTail)">%h(zFilename)</a> 89 @ [<a href="/attachdownload/%t(zFilename)?%s(zUrlTail)">download</a>]<br> 89 @ [<a href="/attachdownload/%t(zFilename)?%s(zUrlTail)">download</a>]<br> > 90 if( zComment ) while( isspace(zComment[0]) ) zComment++; > 91 if( zComment && zComment[0] ){ 90 @ %w(zComment)<br> | 92 @ %w(zComment)<br> > 93 } 91 if( zPage==0 && zTkt==0 ){ 94 if( zPage==0 && zTkt==0 ){ > 95 if( zSrc==0 || zSrc[0]==0 ){ > 96 zSrc = "Deleted from"; > 97 }else { > 98 zSrc = "Added to"; > 99 } 92 if( strlen(zTarget)==UUID_SIZE && validate16(zTarget, UUID_SIZE) ){ 100 if( strlen(zTarget)==UUID_SIZE && validate16(zTarget, UUID_SIZE) ){ 93 char zShort[20]; 101 char zShort[20]; 94 memcpy(zShort, zTarget, 10); 102 memcpy(zShort, zTarget, 10); 95 zShort[10] = 0; 103 zShort[10] = 0; 96 @ Added to ticket <a href="%s(g.zTop)/tktview?name=%s(zTarget)"> | 104 @ %s(zSrc) ticket <a href="%s(g.zTop)/tktview?name=%s(zTarget)"> 97 @ %s(zShort)</a> 105 @ %s(zShort)</a> 98 }else{ 106 }else{ 99 @ Added to wiki page <a href="%s(g.zTop)/wiki?name=%t(zTarget)"> | 107 @ %s(zSrc) wiki page <a href="%s(g.zTop)/wiki?name=%t(zTarget)"> 100 @ %h(zTarget)</a> 108 @ %h(zTarget)</a> 101 } 109 } 102 }else{ 110 }else{ > 111 if( zSrc==0 || zSrc[0]==0 ){ > 112 @ Deleted > 113 }else { 103 @ Add | 114 @ Added > 115 } 104 } 116 } 105 @ by %h(zUser) on 117 @ by %h(zUser) on 106 hyperlink_to_date(zDate, "."); 118 hyperlink_to_date(zDate, "."); 107 free(zUrlTail); 119 free(zUrlTail); 108 } 120 } 109 db_finalize(&q); 121 db_finalize(&q); 110 style_footer(); 122 style_footer(); ................................................................................................................................................................................ 153 zUUID = db_text(0, 165 zUUID = db_text(0, 154 "SELECT coalesce(src,'x') FROM attachment" 166 "SELECT coalesce(src,'x') FROM attachment" 155 " WHERE target=%Q AND filename=%Q" 167 " WHERE target=%Q AND filename=%Q" 156 " ORDER BY mtime DESC LIMIT 1", 168 " ORDER BY mtime DESC LIMIT 1", 157 zTarget, zFile 169 zTarget, zFile 158 ); 170 ); 159 } 171 } 160 if( zUUID==0 ){ | 172 if( zUUID==0 || zUUID[0]==0 ){ 161 style_header("No Such Attachment"); 173 style_header("No Such Attachment"); 162 @ No such attachment.... 174 @ No such attachment.... 163 style_footer(); 175 style_footer(); 164 return; 176 return; 165 }else if( zUUID[0]=='x' ){ 177 }else if( zUUID[0]=='x' ){ 166 style_header("Missing"); 178 style_header("Missing"); 167 @ Attachment has been deleted 179 @ Attachment has been deleted ................................................................................................................................................................................ 173 if( strcmp(g.zPath,"attachview")==0 ){ 185 if( strcmp(g.zPath,"attachview")==0 ){ 174 artifact_page(); 186 artifact_page(); 175 }else{ 187 }else{ 176 cgi_replace_parameter("m", mimetype_from_name(zFile)); 188 cgi_replace_parameter("m", mimetype_from_name(zFile)); 177 rawartifact_page(); 189 rawartifact_page(); 178 } 190 } 179 } 191 } > 192 180 193 181 /* 194 /* 182 ** WEBPAGE: attachadd 195 ** WEBPAGE: attachadd 183 ** 196 ** 184 ** tkt=TICKETUUID 197 ** tkt=TICKETUUID 185 ** page=WIKIPAGE 198 ** page=WIKIPAGE 186 ** from=URL 199 ** from=URL 187 ** 200 ** 188 ** Add a new attachment. 201 ** Add a new attachment. 189 */ 202 */ 190 void attachadd_page(void){ 203 void attachadd_page(void){ 191 const char *zPage = P("page"); 204 const char *zPage = P("page"); 192 const char *zTkt = P("tkt"); 205 const char *zTkt = P("tkt"); 193 const char *zFrom = PD("from", "/home"); | 206 const char *zFrom = P("from"); 194 const char *aContent = P("f"); 207 const char *aContent = P("f"); 195 const char *zName = PD("f:filename","unknown"); 208 const char *zName = PD("f:filename","unknown"); 196 const char *zTarget; 209 const char *zTarget; 197 const char *zTargetType; 210 const char *zTargetType; 198 int szContent = atoi(PD("f:bytes","0")); 211 int szContent = atoi(PD("f:bytes","0")); 199 212 200 if( P("cancel") ) cgi_redirect(zFrom); 213 if( P("cancel") ) cgi_redirect(zFrom); ................................................................................................................................................................................ 213 if( g.okApndTkt==0 || g.okAttach==0 ) login_needed(); 226 if( g.okApndTkt==0 || g.okAttach==0 ) login_needed(); 214 if( !db_exists("SELECT 1 FROM tag WHERE tagname='tkt-%q'", zTkt) ){ 227 if( !db_exists("SELECT 1 FROM tag WHERE tagname='tkt-%q'", zTkt) ){ 215 fossil_redirect_home(); 228 fossil_redirect_home(); 216 } 229 } 217 zTarget = zTkt; 230 zTarget = zTkt; 218 zTargetType = mprintf("Ticket <a href=\"%s/tktview?name=%.10s\">%.10s</a>", 231 zTargetType = mprintf("Ticket <a href=\"%s/tktview?name=%.10s\">%.10s</a>", 219 g.zTop, zTkt, zTkt); 232 g.zTop, zTkt, zTkt); > 233 } > 234 if( zFrom==0 ) zFrom = mprintf("%s/home", g.zTop); > 235 if( P("cancel") ){ > 236 cgi_redirect(zFrom); 220 } 237 } 221 if( P("ok") && szContent>0 ){ 238 if( P("ok") && szContent>0 ){ 222 Blob content; 239 Blob content; 223 Blob manifest; 240 Blob manifest; 224 Blob cksum; 241 Blob cksum; 225 char *zUUID; 242 char *zUUID; 226 const char *zComment; 243 const char *zComment; ................................................................................................................................................................................ 268 if( zTkt ){ 285 if( zTkt ){ 269 @ <input type="hidden" name="tkt" value="%h(zTkt)"> 286 @ <input type="hidden" name="tkt" value="%h(zTkt)"> 270 }else{ 287 }else{ 271 @ <input type="hidden" name="page" value="%h(zPage)"> 288 @ <input type="hidden" name="page" value="%h(zPage)"> 272 } 289 } 273 @ <input type="hidden" name="from" value="%h(zFrom)"> 290 @ <input type="hidden" name="from" value="%h(zFrom)"> 274 @ <input type="submit" name="ok" value="Add Attachment"> 291 @ <input type="submit" name="ok" value="Add Attachment"> 275 @ <input type="submit" name="can" value="Cancel"> | 292 @ <input type="submit" name="cancel" value="Cancel"> > 293 @ </form> > 294 style_footer(); > 295 } > 296 > 297 > 298 /* > 299 ** WEBPAGE: attachdelete > 300 ** > 301 ** tkt=TICKETUUID > 302 ** page=WIKIPAGE > 303 ** file=FILENAME > 304 ** > 305 ** "Delete" an attachment. Because objects in Fossil are immutable > 306 ** the attachment isn't really deleted. Instead, we change the content > 307 ** of the attachment to NULL, which the system understands as being > 308 ** deleted. Historical values of the attachment are preserved. > 309 */ > 310 void attachdel_page(void){ > 311 const char *zPage = P("page"); > 312 const char *zTkt = P("tkt"); > 313 const char *zFile = P("file"); > 314 const char *zFrom = P("from"); > 315 const char *zTarget; > 316 > 317 if( zPage && zTkt ) fossil_redirect_home(); > 318 if( zPage==0 && zTkt==0 ) fossil_redirect_home(); > 319 if( zFile==0 ) fossil_redirect_home(); > 320 login_check_credentials(); > 321 if( zPage ){ > 322 if( g.okWrWiki==0 || g.okAttach==0 ) login_needed(); > 323 zTarget = zPage; > 324 }else{ > 325 if( g.okWrTkt==0 || g.okAttach==0 ) login_needed(); > 326 zTarget = zTkt; > 327 } > 328 if( zFrom==0 ) zFrom = mprintf("%s/home", g.zTop); > 329 if( P("cancel") ){ > 330 cgi_redirect(zFrom); > 331 } > 332 if( P("confirm") ){ > 333 int i, n, rid; > 334 char *zDate; > 335 Blob manifest; > 336 Blob cksum; > 337 > 338 db_begin_transaction(); > 339 blob_zero(&manifest); > 340 for(i=n=0; zFile[i]; i++){ > 341 if( zFile[i]=='/' || zFile[i]=='\\' ) n = i; > 342 } > 343 zFile += n; > 344 if( zFile[0]==0 ) zFile = "unknown"; > 345 blob_appendf(&manifest, "A %F %F\n", zFile, zTarget); > 346 zDate = db_text(0, "SELECT datetime('now')"); > 347 zDate[10] = 'T'; > 348 blob_appendf(&manifest, "D %s\n", zDate); > 349 blob_appendf(&manifest, "U %F\n", g.zLogin ? g.zLogin : "nobody"); > 350 md5sum_blob(&manifest, &cksum); > 351 blob_appendf(&manifest, "Z %b\n", &cksum); > 352 rid = content_put(&manifest, 0, 0); > 353 manifest_crosslink(rid, &manifest); > 354 db_end_transaction(0); > 355 cgi_redirect(zFrom); > 356 } > 357 style_header("Delete Attachment"); > 358 @ <form action="%s(g.zBaseURL)/attachdelete" method="POST"> > 359 @ <p>Confirm that you want to delete the attachment named > 360 @ "%h(zFile)" on %s(zTkt?"ticket":"wiki page") %h(zTarget):<br> > 361 if( zTkt ){ > 362 @ <input type="hidden" name="tkt" value="%h(zTkt)"> > 363 }else{ > 364 @ <input type="hidden" name="page" value="%h(zPage)"> > 365 } > 366 @ <input type="hidden" name="file" value="%h(zFile)"> > 367 @ <input type="hidden" name="from" value="%h(zFrom)"> > 368 @ <input type="submit" name="confirm" value="Delete"> > 369 @ <input type="submit" name="cancel" value="Cancel"> 276 @ </form> 370 @ </form> 277 style_footer(); 371 style_footer(); > 372 278 } 373 }
Changes to src/manifest.c
1134 " WHERE target=%Q AND filename=%Q", 1134 " WHERE target=%Q AND filename=%Q", 1135 m.zAttachTarget, m.zAttachName, 1135 m.zAttachTarget, m.zAttachName, 1136 m.zAttachTarget, m.zAttachName 1136 m.zAttachTarget, m.zAttachName 1137 ); 1137 ); 1138 if( strlen(m.zAttachTarget)!=UUID_SIZE 1138 if( strlen(m.zAttachTarget)!=UUID_SIZE 1139 || !validate16(m.zAttachTarget, UUID_SIZE) 1139 || !validate16(m.zAttachTarget, UUID_SIZE) 1140 ){ 1140 ){ 1141 char *zTag = mprintf("wiki-%s", m.zAttachTarget); < 1142 char *zComment; 1141 char *zComment; > 1142 #if 0 > 1143 char *zTag = mprintf("wiki-%s", m.zAttachTarget); 1143 tag_findid(zTag, 1); 1144 tag_findid(zTag, 1); 1144 free(zTag); 1145 free(zTag); > 1146 #endif 1145 if( m.zAttachSrc ){ | 1147 if( m.zAttachSrc && m.zAttachSrc[0] ){ 1146 zComment = mprintf("Add attachment \"%h\" to wiki page [%h]", 1148 zComment = mprintf("Add attachment \"%h\" to wiki page [%h]", 1147 m.zAttachName, m.zAttachTarget); 1149 m.zAttachName, m.zAttachTarget); 1148 }else{ 1150 }else{ 1149 zComment = mprintf("Delete attachment \"%h\" from wiki page [%h]", 1151 zComment = mprintf("Delete attachment \"%h\" from wiki page [%h]", 1150 m.zAttachName, m.zAttachTarget); 1152 m.zAttachName, m.zAttachTarget); 1151 } 1153 } 1152 db_multi_exec( 1154 db_multi_exec( 1153 "REPLACE INTO event(type,mtime,objid,user,comment)" 1155 "REPLACE INTO event(type,mtime,objid,user,comment)" 1154 "VALUES('w',%.17g,%d,%Q,%Q)", 1156 "VALUES('w',%.17g,%d,%Q,%Q)", 1155 m.rDate, rid, m.zUser, zComment 1157 m.rDate, rid, m.zUser, zComment 1156 ); 1158 ); > 1159 free(zComment); > 1160 }else{ > 1161 char *zComment; > 1162 if( m.zAttachSrc && m.zAttachSrc[0] ){ > 1163 zComment = mprintf("Add attachment \"%h\" to ticket [%.10s]", > 1164 m.zAttachName, m.zAttachTarget); > 1165 }else{ > 1166 zComment = mprintf("Delete attachment \"%h\" from ticket [%.10s]", > 1167 m.zAttachName, m.zAttachTarget); > 1168 } > 1169 db_multi_exec( > 1170 "REPLACE INTO event(type,mtime,objid,user,comment)" > 1171 "VALUES('t',%.17g,%d,%Q,%Q)", > 1172 m.rDate, rid, m.zUser, zComment > 1173 ); 1157 free(zComment); 1174 free(zComment); 1158 } 1175 } 1159 } 1176 } 1160 db_end_transaction(0); 1177 db_end_transaction(0); 1161 manifest_clear(&m); 1178 manifest_clear(&m); 1162 return 1; 1179 return 1; 1163 } 1180 }
Changes to src/tkt.c
240 ticket_insert(&manifest, createFlag, rid); 240 ticket_insert(&manifest, createFlag, rid); 241 manifest_ticket_event(rid, &manifest, createFlag, tagid); 241 manifest_ticket_event(rid, &manifest, createFlag, tagid); 242 manifest_clear(&manifest); 242 manifest_clear(&manifest); 243 createFlag = 0; 243 createFlag = 0; 244 } 244 } 245 db_finalize(&q); 245 db_finalize(&q); 246 246 > 247 #if 0 247 db_prepare(&q, 248 db_prepare(&q, 248 "SELECT attachid, mtime, src IS NULL, filename, user" 249 "SELECT attachid, mtime, src IS NULL, filename, user" 249 " FROM attachment" 250 " FROM attachment" 250 " WHERE target=%Q", 251 " WHERE target=%Q", 251 zTktUuid 252 zTktUuid 252 ); 253 ); 253 while( db_step(&q)==SQLITE_ROW ){ 254 while( db_step(&q)==SQLITE_ROW ){ ................................................................................................................................................................................ 269 "REPLACE INTO event(type,tagid,mtime,objid,user,comment,brief)" 270 "REPLACE INTO event(type,tagid,mtime,objid,user,comment,brief)" 270 "VALUES('t',%d,%.17g,%d,%Q,%Q,%Q)", 271 "VALUES('t',%d,%.17g,%d,%Q,%Q,%Q)", 271 tagid, mtime, attachid, zUser, zCom, zCom 272 tagid, mtime, attachid, zUser, zCom, zCom 272 ); 273 ); 273 free(zCom); 274 free(zCom); 274 } 275 } 275 db_finalize(&q); 276 db_finalize(&q); > 277 #endif 276 } 278 } 277 279 278 /* 280 /* 279 ** Create the subscript interpreter and load the "common" code. 281 ** Create the subscript interpreter and load the "common" code. 280 */ 282 */ 281 void ticket_init(void){ 283 void ticket_init(void){ 282 const char *zConfig; 284 const char *zConfig; ................................................................................................................................................................................ 347 } 349 } 348 if( g.okNewTkt ){ 350 if( g.okNewTkt ){ 349 style_submenu_element("New Ticket", "Create a new ticket", 351 style_submenu_element("New Ticket", "Create a new ticket", 350 "%s/tktnew", g.zTop); 352 "%s/tktnew", g.zTop); 351 } 353 } 352 if( g.okApndTkt && g.okAttach ){ 354 if( g.okApndTkt && g.okAttach ){ 353 style_submenu_element("Attach", "Add An Attachment", 355 style_submenu_element("Attach", "Add An Attachment", > 356 "%s/attachadd?tkt=%T&from=%s/tktview%%3fname=%t", 354 "%s/attachadd?tkt=%T", g.zTop, zUuid); | 357 g.zTop, zUuid, g.zTop, zUuid); 355 } 358 } 356 style_header("View Ticket"); 359 style_header("View Ticket"); 357 if( g.thTrace ) Th_Trace("BEGIN_TKTVIEW<br />\n", -1); 360 if( g.thTrace ) Th_Trace("BEGIN_TKTVIEW<br />\n", -1); 358 ticket_init(); 361 ticket_init(); 359 initializeVariablesFromDb(); 362 initializeVariablesFromDb(); 360 zScript = ticket_viewpage_code(); 363 zScript = ticket_viewpage_code(); 361 if( g.thTrace ) Th_Trace("BEGIN_TKTVIEW_SCRIPT<br />\n", -1); 364 if( g.thTrace ) Th_Trace("BEGIN_TKTVIEW_SCRIPT<br />\n", -1); ................................................................................................................................................................................ 367 " WHERE tkt_uuid GLOB '%q*'", zUuid); 370 " WHERE tkt_uuid GLOB '%q*'", zUuid); 368 if( zFullName ){ 371 if( zFullName ){ 369 int cnt = 0; 372 int cnt = 0; 370 Stmt q; 373 Stmt q; 371 db_prepare(&q, 374 db_prepare(&q, 372 "SELECT datetime(mtime,'localtime'), filename, user" 375 "SELECT datetime(mtime,'localtime'), filename, user" 373 " FROM attachment" 376 " FROM attachment" 374 " WHERE isLatest AND src NOT NULL AND target=%Q" | 377 " WHERE isLatest AND src!='' AND target=%Q" 375 " ORDER BY mtime DESC", 378 " ORDER BY mtime DESC", 376 zFullName); 379 zFullName); 377 while( db_step(&q)==SQLITE_ROW ){ 380 while( db_step(&q)==SQLITE_ROW ){ 378 const char *zDate = db_column_text(&q, 0); 381 const char *zDate = db_column_text(&q, 0); 379 const char *zFile = db_column_text(&q, 1); 382 const char *zFile = db_column_text(&q, 1); 380 const char *zUser = db_column_text(&q, 2); 383 const char *zUser = db_column_text(&q, 2); 381 if( cnt==0 ){ 384 if( cnt==0 ){ 382 @ <hr><h2>Attachments:</h2> 385 @ <hr><h2>Attachments:</h2> 383 @ <ul> 386 @ <ul> 384 } 387 } 385 cnt++; 388 cnt++; 386 @ <li><a href="%s(g.zTop)/attachview?tkt=%s(zFullName)&file=%t(zFile)"> 389 @ <li><a href="%s(g.zTop)/attachview?tkt=%s(zFullName)&file=%t(zFile)"> 387 @ %h(zFile)</a> add by %h(zUser) on 390 @ %h(zFile)</a> add by %h(zUser) on 388 hyperlink_to_date(zDate, ".</li>"); | 391 hyperlink_to_date(zDate, "."); > 392 if( g.okWrTkt && g.okAttach ){ > 393 @ [<a href="%s(g.zTop)/attachdelete?tkt=%s(zFullName)&file=%t(zFile)&fro > 394 } 389 } 395 } 390 if( cnt ){ 396 if( cnt ){ 391 @ </ul> 397 @ </ul> 392 } 398 } 393 db_finalize(&q); 399 db_finalize(&q); 394 } 400 } 395 401 ................................................................................................................................................................................ 763 "SELECT datetime(mtime,'localtime'), objid, uuid, NULL, NULL, NULL" 769 "SELECT datetime(mtime,'localtime'), objid, uuid, NULL, NULL, NULL" 764 " FROM event, blob" 770 " FROM event, blob" 765 " WHERE objid IN (SELECT rid FROM tagxref WHERE tagid=%d)" 771 " WHERE objid IN (SELECT rid FROM tagxref WHERE tagid=%d)" 766 " AND blob.rid=event.objid" 772 " AND blob.rid=event.objid" 767 " UNION " 773 " UNION " 768 "SELECT datetime(mtime,'localtime'), attachid, uuid, src, filename, user" 774 "SELECT datetime(mtime,'localtime'), attachid, uuid, src, filename, user" 769 " FROM attachment, blob" 775 " FROM attachment, blob" 770 " WHERE isLatest AND target=(SELECT substr(tagname,5) FROM tag" | 776 " WHERE target=(SELECT substr(tagname,5) FROM tag WHERE tagid=%d)" 771 " WHERE tagid=%d)" < 772 " AND blob.rid=attachid" 777 " AND blob.rid=attachid" 773 " ORDER BY 1 DESC", 778 " ORDER BY 1 DESC", 774 tagid, tagid 779 tagid, tagid 775 ); 780 ); 776 while( db_step(&q)==SQLITE_ROW ){ 781 while( db_step(&q)==SQLITE_ROW ){ 777 Blob content; 782 Blob content; 778 Manifest m; 783 Manifest m; ................................................................................................................................................................................ 782 const char *zChngUuid = db_column_text(&q, 2); 787 const char *zChngUuid = db_column_text(&q, 2); 783 const char *zFile = db_column_text(&q, 4); 788 const char *zFile = db_column_text(&q, 4); 784 memcpy(zShort, zChngUuid, 10); 789 memcpy(zShort, zChngUuid, 10); 785 zShort[10] = 0; 790 zShort[10] = 0; 786 if( zFile!=0 ){ 791 if( zFile!=0 ){ 787 const char *zSrc = db_column_text(&q, 3); 792 const char *zSrc = db_column_text(&q, 3); 788 const char *zUser = db_column_text(&q, 5); 793 const char *zUser = db_column_text(&q, 5); 789 if( zSrc==0 ){ | 794 if( zSrc==0 || zSrc[0]==0 ){ 790 @ 795 @ 791 @ <p>Delete attachment "%h(zFile)" 796 @ <p>Delete attachment "%h(zFile)" 792 }else{ 797 }else{ 793 @ 798 @ 794 @ <p>Add attachment "%h(zFile)" 799 @ <p>Add attachment "%h(zFile)" 795 } 800 } 796 @ [<a href="%s(g.zTop)/artifact/%T(zChngUuid)">%s(zShort)</a>] 801 @ [<a href="%s(g.zTop)/artifact/%T(zChngUuid)">%s(zShort)</a>]
Changes to src/wiki.c
189 if( !g.isHome ){ 189 if( !g.isHome ){ 190 if( (rid && g.okWrWiki) || (!rid && g.okNewWiki) ){ 190 if( (rid && g.okWrWiki) || (!rid && g.okNewWiki) ){ 191 style_submenu_element("Edit", "Edit Wiki Page", "%s/wikiedit?name=%T", 191 style_submenu_element("Edit", "Edit Wiki Page", "%s/wikiedit?name=%T", 192 g.zTop, zPageName); 192 g.zTop, zPageName); 193 } 193 } 194 if( rid && g.okWrWiki && g.okAttach ){ 194 if( rid && g.okWrWiki && g.okAttach ){ 195 style_submenu_element("Attach", "Add An Attachment", 195 style_submenu_element("Attach", "Add An Attachment", > 196 "%s/attachadd?page=%T&from=%s/wiki%%3fname=%T", 196 "%s/attachadd?page=%T", g.zTop, zPageName); | 197 g.zTop, zPageName, g.zTop, zPageName); 197 } 198 } 198 if( rid && g.okApndWiki ){ 199 if( rid && g.okApndWiki ){ 199 style_submenu_element("Append", "Add A Comment", "%s/wikiappend?name=%T", 200 style_submenu_element("Append", "Add A Comment", "%s/wikiappend?name=%T", 200 g.zTop, zPageName); 201 g.zTop, zPageName); 201 } 202 } 202 if( g.okHistory ){ 203 if( g.okHistory ){ 203 style_submenu_element("History", "History", "%s/whistory?name=%T", 204 style_submenu_element("History", "History", "%s/whistory?name=%T", ................................................................................................................................................................................ 208 blob_init(&wiki, zBody, -1); 209 blob_init(&wiki, zBody, -1); 209 wiki_convert(&wiki, 0, 0); 210 wiki_convert(&wiki, 0, 0); 210 blob_reset(&wiki); 211 blob_reset(&wiki); 211 212 212 db_prepare(&q, 213 db_prepare(&q, 213 "SELECT datetime(mtime,'localtime'), filename, user" 214 "SELECT datetime(mtime,'localtime'), filename, user" 214 " FROM attachment" 215 " FROM attachment" 215 " WHERE isLatest AND src NOT NULL AND target=%Q" | 216 " WHERE isLatest AND src!='' AND target=%Q" 216 " ORDER BY mtime DESC", 217 " ORDER BY mtime DESC", 217 zPageName); 218 zPageName); 218 while( db_step(&q)==SQLITE_ROW ){ 219 while( db_step(&q)==SQLITE_ROW ){ 219 const char *zDate = db_column_text(&q, 0); 220 const char *zDate = db_column_text(&q, 0); 220 const char *zFile = db_column_text(&q, 1); 221 const char *zFile = db_column_text(&q, 1); 221 const char *zUser = db_column_text(&q, 2); 222 const char *zUser = db_column_text(&q, 2); 222 if( cnt==0 ){ 223 if( cnt==0 ){ 223 @ <hr><h2>Attachments:</h2> 224 @ <hr><h2>Attachments:</h2> 224 @ <ul> 225 @ <ul> 225 } 226 } 226 cnt++; 227 cnt++; 227 @ <li><a href="%s(g.zTop)/attachview?page=%s(zPageName)&file=%t(zFile)"> 228 @ <li><a href="%s(g.zTop)/attachview?page=%s(zPageName)&file=%t(zFile)"> 228 @ %h(zFile)</a> add by %h(zUser) on 229 @ %h(zFile)</a> add by %h(zUser) on 229 hyperlink_to_date(zDate, ".</li>"); | 230 hyperlink_to_date(zDate, "."); > 231 if( g.okWrWiki && g.okAttach ){ > 232 @ [<a href="%s(g.zTop)/attachdelete?page=%s(zPageName)&file=%t(zFile)&from > 233 } 230 } 234 } 231 if( cnt ){ 235 if( cnt ){ 232 @ </ul> 236 @ </ul> 233 } 237 } 234 db_finalize(&q); 238 db_finalize(&q); 235 239 236 if( !isSandbox ){ 240 if( !isSandbox ){ ................................................................................................................................................................................ 545 static const char *zWikiPageName; 549 static const char *zWikiPageName; 546 550 547 /* 551 /* 548 ** Function called to output extra text at the end of each line in 552 ** Function called to output extra text at the end of each line in 549 ** a wiki history listing. 553 ** a wiki history listing. 550 */ 554 */ 551 static void wiki_history_extra(int rid){ 555 static void wiki_history_extra(int rid){ > 556 if( db_exists("SELECT 1 FROM tagxref WHERE rid=%d", rid) ){ 552 @ <a href="%s(g.zTop)/wdiff?name=%t(zWikiPageName)&a=%d(rid)">[diff]</a> | 557 @ <a href="%s(g.zTop)/wdiff?name=%t(zWikiPageName)&a=%d(rid)">[diff]</a> > 558 } 553 } 559 } 554 560 555 /* 561 /* 556 ** WEBPAGE: whistory 562 ** WEBPAGE: whistory 557 ** URL: /whistory?name=PAGENAME 563 ** URL: /whistory?name=PAGENAME 558 ** 564 ** 559 ** Show the complete change history for a single wiki page. 565 ** Show the complete change history for a single wiki page.