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] branch timeline
- sym-experimental inherited from [c3d7df650b]
Changes
[hide diffs]Changes to src/attach.c
@@ -64,11 +64,11 @@
}
blob_appendf(&sql, " ORDER BY mtime DESC");
db_prepare(&q, "%s", blob_str(&sql));
while( db_step(&q)==SQLITE_ROW ){
const char *zDate = db_column_text(&q, 0);
- /* const char *zSrc = db_column_text(&q, 1); */
+ const char *zSrc = db_column_text(&q, 1);
const char *zTarget = db_column_text(&q, 2);
const char *zFilename = db_column_text(&q, 3);
const char *zComment = db_column_text(&q, 4);
const char *zUser = db_column_text(&q, 5);
int i;
@@ -85,24 +85,36 @@
zUrlTail = mprintf("page=%t&file=%t", zTarget, zFilename);
}
@
@ <p><a href="/attachview?%s(zUrlTail)">%h(zFilename)</a>
@ [<a href="/attachdownload/%t(zFilename)?%s(zUrlTail)">download</a>]<br>
- @ %w(zComment)<br>
+ if( zComment ) while( isspace(zComment[0]) ) zComment++;
+ if( zComment && zComment[0] ){
+ @ %w(zComment)<br>
+ }
if( zPage==0 && zTkt==0 ){
+ if( zSrc==0 || zSrc[0]==0 ){
+ zSrc = "Deleted from";
+ }else {
+ zSrc = "Added to";
+ }
if( strlen(zTarget)==UUID_SIZE && validate16(zTarget, UUID_SIZE) ){
char zShort[20];
memcpy(zShort, zTarget, 10);
zShort[10] = 0;
- @ Added to ticket <a href="%s(g.zTop)/tktview?name=%s(zTarget)">
+ @ %s(zSrc) ticket <a href="%s(g.zTop)/tktview?name=%s(zTarget)">
@ %s(zShort)</a>
}else{
- @ Added to wiki page <a href="%s(g.zTop)/wiki?name=%t(zTarget)">
+ @ %s(zSrc) wiki page <a href="%s(g.zTop)/wiki?name=%t(zTarget)">
@ %h(zTarget)</a>
}
}else{
- @ Add
+ if( zSrc==0 || zSrc[0]==0 ){
+ @ Deleted
+ }else {
+ @ Added
+ }
}
@ by %h(zUser) on
hyperlink_to_date(zDate, ".");
free(zUrlTail);
}
@@ -155,11 +167,11 @@
" WHERE target=%Q AND filename=%Q"
" ORDER BY mtime DESC LIMIT 1",
zTarget, zFile
);
}
- if( zUUID==0 ){
+ if( zUUID==0 || zUUID[0]==0 ){
style_header("No Such Attachment");
@ No such attachment....
style_footer();
return;
}else if( zUUID[0]=='x' ){
@@ -176,10 +188,11 @@
cgi_replace_parameter("m", mimetype_from_name(zFile));
rawartifact_page();
}
}
+
/*
** WEBPAGE: attachadd
**
** tkt=TICKETUUID
** page=WIKIPAGE
@@ -188,11 +201,11 @@
** Add a new attachment.
*/
void attachadd_page(void){
const char *zPage = P("page");
const char *zTkt = P("tkt");
- const char *zFrom = PD("from", "/home");
+ const char *zFrom = P("from");
const char *aContent = P("f");
const char *zName = PD("f:filename","unknown");
const char *zTarget;
const char *zTargetType;
int szContent = atoi(PD("f:bytes","0"));
@@ -215,10 +228,14 @@
fossil_redirect_home();
}
zTarget = zTkt;
zTargetType = mprintf("Ticket <a href=\"%s/tktview?name=%.10s\">%.10s</a>",
g.zTop, zTkt, zTkt);
+ }
+ if( zFrom==0 ) zFrom = mprintf("%s/home", g.zTop);
+ if( P("cancel") ){
+ cgi_redirect(zFrom);
}
if( P("ok") && szContent>0 ){
Blob content;
Blob manifest;
Blob cksum;
@@ -270,9 +287,87 @@
}else{
@ <input type="hidden" name="page" value="%h(zPage)">
}
@ <input type="hidden" name="from" value="%h(zFrom)">
@ <input type="submit" name="ok" value="Add Attachment">
- @ <input type="submit" name="can" value="Cancel">
+ @ <input type="submit" name="cancel" value="Cancel">
+ @ </form>
+ style_footer();
+}
+
+
+/*
+** WEBPAGE: attachdelete
+**
+** tkt=TICKETUUID
+** page=WIKIPAGE
+** file=FILENAME
+**
+** "Delete" an attachment. Because objects in Fossil are immutable
+** the attachment isn't really deleted. Instead, we change the content
+** of the attachment to NULL, which the system understands as being
+** deleted. Historical values of the attachment are preserved.
+*/
+void attachdel_page(void){
+ const char *zPage = P("page");
+ const char *zTkt = P("tkt");
+ const char *zFile = P("file");
+ const char *zFrom = P("from");
+ const char *zTarget;
+
+ if( zPage && zTkt ) fossil_redirect_home();
+ if( zPage==0 && zTkt==0 ) fossil_redirect_home();
+ if( zFile==0 ) fossil_redirect_home();
+ login_check_credentials();
+ if( zPage ){
+ if( g.okWrWiki==0 || g.okAttach==0 ) login_needed();
+ zTarget = zPage;
+ }else{
+ if( g.okWrTkt==0 || g.okAttach==0 ) login_needed();
+ zTarget = zTkt;
+ }
+ if( zFrom==0 ) zFrom = mprintf("%s/home", g.zTop);
+ if( P("cancel") ){
+ cgi_redirect(zFrom);
+ }
+ if( P("confirm") ){
+ int i, n, rid;
+ char *zDate;
+ Blob manifest;
+ Blob cksum;
+
+ db_begin_transaction();
+ blob_zero(&manifest);
+ for(i=n=0; zFile[i]; i++){
+ if( zFile[i]=='/' || zFile[i]=='\\' ) n = i;
+ }
+ zFile += n;
+ if( zFile[0]==0 ) zFile = "unknown";
+ blob_appendf(&manifest, "A %F %F\n", zFile, zTarget);
+ zDate = db_text(0, "SELECT datetime('now')");
+ zDate[10] = 'T';
+ blob_appendf(&manifest, "D %s\n", zDate);
+ blob_appendf(&manifest, "U %F\n", g.zLogin ? g.zLogin : "nobody");
+ md5sum_blob(&manifest, &cksum);
+ blob_appendf(&manifest, "Z %b\n", &cksum);
+ rid = content_put(&manifest, 0, 0);
+ manifest_crosslink(rid, &manifest);
+ db_end_transaction(0);
+ cgi_redirect(zFrom);
+ }
+ style_header("Delete Attachment");
+ @ <form action="%s(g.zBaseURL)/attachdelete" method="POST">
+ @ <p>Confirm that you want to delete the attachment named
+ @ "%h(zFile)" on %s(zTkt?"ticket":"wiki page") %h(zTarget):<br>
+ if( zTkt ){
+ @ <input type="hidden" name="tkt" value="%h(zTkt)">
+ }else{
+ @ <input type="hidden" name="page" value="%h(zPage)">
+ }
+ @ <input type="hidden" name="file" value="%h(zFile)">
+ @ <input type="hidden" name="from" value="%h(zFrom)">
+ @ <input type="submit" name="confirm" value="Delete">
+ @ <input type="submit" name="cancel" value="Cancel">
@ </form>
style_footer();
+
}
Changes to src/manifest.c
@@ -1136,28 +1136,45 @@
m.zAttachTarget, m.zAttachName
);
if( strlen(m.zAttachTarget)!=UUID_SIZE
|| !validate16(m.zAttachTarget, UUID_SIZE)
){
- char *zTag = mprintf("wiki-%s", m.zAttachTarget);
char *zComment;
+#if 0
+ char *zTag = mprintf("wiki-%s", m.zAttachTarget);
tag_findid(zTag, 1);
free(zTag);
- if( m.zAttachSrc ){
+#endif
+ if( m.zAttachSrc && m.zAttachSrc[0] ){
zComment = mprintf("Add attachment \"%h\" to wiki page [%h]",
m.zAttachName, m.zAttachTarget);
}else{
zComment = mprintf("Delete attachment \"%h\" from wiki page [%h]",
m.zAttachName, m.zAttachTarget);
}
db_multi_exec(
"REPLACE INTO event(type,mtime,objid,user,comment)"
"VALUES('w',%.17g,%d,%Q,%Q)",
+ m.rDate, rid, m.zUser, zComment
+ );
+ free(zComment);
+ }else{
+ char *zComment;
+ if( m.zAttachSrc && m.zAttachSrc[0] ){
+ zComment = mprintf("Add attachment \"%h\" to ticket [%.10s]",
+ m.zAttachName, m.zAttachTarget);
+ }else{
+ zComment = mprintf("Delete attachment \"%h\" from ticket [%.10s]",
+ m.zAttachName, m.zAttachTarget);
+ }
+ db_multi_exec(
+ "REPLACE INTO event(type,mtime,objid,user,comment)"
+ "VALUES('t',%.17g,%d,%Q,%Q)",
m.rDate, rid, m.zUser, zComment
);
free(zComment);
}
}
db_end_transaction(0);
manifest_clear(&m);
return 1;
}
Changes to src/tkt.c
@@ -242,10 +242,11 @@
manifest_clear(&manifest);
createFlag = 0;
}
db_finalize(&q);
+#if 0
db_prepare(&q,
"SELECT attachid, mtime, src IS NULL, filename, user"
" FROM attachment"
" WHERE target=%Q",
zTktUuid
@@ -271,10 +272,11 @@
tagid, mtime, attachid, zUser, zCom, zCom
);
free(zCom);
}
db_finalize(&q);
+#endif
}
/*
** Create the subscript interpreter and load the "common" code.
*/
@@ -349,11 +351,12 @@
style_submenu_element("New Ticket", "Create a new ticket",
"%s/tktnew", g.zTop);
}
if( g.okApndTkt && g.okAttach ){
style_submenu_element("Attach", "Add An Attachment",
- "%s/attachadd?tkt=%T", g.zTop, zUuid);
+ "%s/attachadd?tkt=%T&from=%s/tktview%%3fname=%t",
+ g.zTop, zUuid, g.zTop, zUuid);
}
style_header("View Ticket");
if( g.thTrace ) Th_Trace("BEGIN_TKTVIEW<br />\n", -1);
ticket_init();
initializeVariablesFromDb();
@@ -369,11 +372,11 @@
int cnt = 0;
Stmt q;
db_prepare(&q,
"SELECT datetime(mtime,'localtime'), filename, user"
" FROM attachment"
- " WHERE isLatest AND src NOT NULL AND target=%Q"
+ " WHERE isLatest AND src!='' AND target=%Q"
" ORDER BY mtime DESC",
zFullName);
while( db_step(&q)==SQLITE_ROW ){
const char *zDate = db_column_text(&q, 0);
const char *zFile = db_column_text(&q, 1);
@@ -383,11 +386,14 @@
@ <ul>
}
cnt++;
@ <li><a href="%s(g.zTop)/attachview?tkt=%s(zFullName)&file=%t(zFile)">
@ %h(zFile)</a> add by %h(zUser) on
- hyperlink_to_date(zDate, ".</li>");
+ hyperlink_to_date(zDate, ".");
+ if( g.okWrTkt && g.okAttach ){
+ @ [<a href="%s(g.zTop)/attachdelete?tkt=%s(zFullName)&file=%t(zFile)&from=%s(g.zTop)/tktview%%3fname=%s(zFullName)">delete</a>]
+ }
}
if( cnt ){
@ </ul>
}
db_finalize(&q);
@@ -765,12 +771,11 @@
" WHERE objid IN (SELECT rid FROM tagxref WHERE tagid=%d)"
" AND blob.rid=event.objid"
" UNION "
"SELECT datetime(mtime,'localtime'), attachid, uuid, src, filename, user"
" FROM attachment, blob"
- " WHERE isLatest AND target=(SELECT substr(tagname,5) FROM tag"
- " WHERE tagid=%d)"
+ " WHERE target=(SELECT substr(tagname,5) FROM tag WHERE tagid=%d)"
" AND blob.rid=attachid"
" ORDER BY 1 DESC",
tagid, tagid
);
while( db_step(&q)==SQLITE_ROW ){
@@ -784,11 +789,11 @@
memcpy(zShort, zChngUuid, 10);
zShort[10] = 0;
if( zFile!=0 ){
const char *zSrc = db_column_text(&q, 3);
const char *zUser = db_column_text(&q, 5);
- if( zSrc==0 ){
+ if( zSrc==0 || zSrc[0]==0 ){
@
@ <p>Delete attachment "%h(zFile)"
}else{
@
@ <p>Add attachment "%h(zFile)"
Changes to src/wiki.c
@@ -191,11 +191,12 @@
style_submenu_element("Edit", "Edit Wiki Page", "%s/wikiedit?name=%T",
g.zTop, zPageName);
}
if( rid && g.okWrWiki && g.okAttach ){
style_submenu_element("Attach", "Add An Attachment",
- "%s/attachadd?page=%T", g.zTop, zPageName);
+ "%s/attachadd?page=%T&from=%s/wiki%%3fname=%T",
+ g.zTop, zPageName, g.zTop, zPageName);
}
if( rid && g.okApndWiki ){
style_submenu_element("Append", "Add A Comment", "%s/wikiappend?name=%T",
g.zTop, zPageName);
}
@@ -210,11 +211,11 @@
blob_reset(&wiki);
db_prepare(&q,
"SELECT datetime(mtime,'localtime'), filename, user"
" FROM attachment"
- " WHERE isLatest AND src NOT NULL AND target=%Q"
+ " WHERE isLatest AND src!='' AND target=%Q"
" ORDER BY mtime DESC",
zPageName);
while( db_step(&q)==SQLITE_ROW ){
const char *zDate = db_column_text(&q, 0);
const char *zFile = db_column_text(&q, 1);
@@ -224,11 +225,14 @@
@ <ul>
}
cnt++;
@ <li><a href="%s(g.zTop)/attachview?page=%s(zPageName)&file=%t(zFile)">
@ %h(zFile)</a> add by %h(zUser) on
- hyperlink_to_date(zDate, ".</li>");
+ hyperlink_to_date(zDate, ".");
+ if( g.okWrWiki && g.okAttach ){
+ @ [<a href="%s(g.zTop)/attachdelete?page=%s(zPageName)&file=%t(zFile)&from=%s(g.zTop)/wiki%%3fname=%s(zPageName)">delete</a>]
+ }
}
if( cnt ){
@ </ul>
}
db_finalize(&q);
@@ -547,11 +551,13 @@
/*
** Function called to output extra text at the end of each line in
** a wiki history listing.
*/
static void wiki_history_extra(int rid){
- @ <a href="%s(g.zTop)/wdiff?name=%t(zWikiPageName)&a=%d(rid)">[diff]</a>
+ if( db_exists("SELECT 1 FROM tagxref WHERE rid=%d", rid) ){
+ @ <a href="%s(g.zTop)/wdiff?name=%t(zWikiPageName)&a=%d(rid)">[diff]</a>
+ }
}
/*
** WEBPAGE: whistory
** URL: /whistory?name=PAGENAME