Check-in [dd2d3177b1]
Not logged in

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
SHA1 Hash:dd2d3177b1b8333ee909d14edfd5f3287b689498
Date: 2010-03-17 23:15:04
User: drh
Comment:Basic functionality of attachments is now in place.
Tags And Properties
Changes

Changes to src/attach.c

28 #include <assert.h> 28 #include <assert.h> 29 29 30 /* 30 /* 31 ** WEBPAGE: attachlist 31 ** WEBPAGE: attachlist 32 ** 32 ** 33 ** tkt=TICKETUUID 33 ** tkt=TICKETUUID 34 ** page=WIKIPAGE 34 ** page=WIKIPAGE > 35 ** all 35 ** 36 ** 36 ** List attachments. 37 ** List attachments. 37 */ 38 */ 38 void attachlist_page(void){ 39 void attachlist_page(void){ 39 const char *zPage = P("page"); 40 const char *zPage = P("page"); 40 const char *zTkt = P("tkt"); 41 const char *zTkt = P("tkt"); 41 Blob sql; 42 Blob sql; ................................................................................................................................................................................ 77 zFilename = &zFilename[i+1]; 78 zFilename = &zFilename[i+1]; 78 i = -1; 79 i = -1; 79 } 80 } 80 } 81 } 81 if( strlen(zTarget)==UUID_SIZE && validate16(zTarget,UUID_SIZE) ){ 82 if( strlen(zTarget)==UUID_SIZE && validate16(zTarget,UUID_SIZE) ){ 82 zUrlTail = mprintf("tkt=%s&file=%t", zTarget, zFilename); 83 zUrlTail = mprintf("tkt=%s&file=%t", zTarget, zFilename); 83 }else{ 84 }else{ 84 zUrlTail = mprintf("page=%s&file=%t", zTarget, zFilename); | 85 zUrlTail = mprintf("page=%t&file=%t", zTarget, zFilename); 85 } 86 } > 87 @ 86 @ <p><a href="/attachview?%s(zUrlTail)">%h(zFilename)</a> 88 @ <p><a href="/attachview?%s(zUrlTail)">%h(zFilename)</a> 87 @ [<a href="/attachdownload?%s(zUrlTail)">download</a>]<br> | 89 @ [<a href="/attachdownload/%t(zFilename)?%s(zUrlTail)">download</a>]<br> 88 @ %w(zComment)<br> 90 @ %w(zComment)<br> > 91 if( zPage==0 && zTkt==0 ){ > 92 if( strlen(zTarget)==UUID_SIZE && validate16(zTarget, UUID_SIZE) ){ > 93 char zShort[20]; > 94 memcpy(zShort, zTarget, 10); > 95 zShort[10] = 0; > 96 @ Added to ticket <a href="%s(g.zTop)/tktview?name=%s(zTarget)"> > 97 @ %s(zShort)</a> > 98 }else{ > 99 @ Added to wiki page <a href="%s(g.zTop)/wiki?name=%t(zTarget)"> > 100 @ %h(zTarget)</a> > 101 } > 102 }else{ > 103 @ Add > 104 } 89 @ Added by %h(zUser) on %s(zDate)</p> | 105 @ by %h(zUser) on 90 @ < > 106 hyperlink_to_date(zDate, "."); 91 free(zUrlTail); 107 free(zUrlTail); 92 } 108 } 93 db_finalize(&q); 109 db_finalize(&q); 94 style_footer(); 110 style_footer(); 95 return; 111 return; 96 } 112 } > 113 > 114 /* > 115 ** WEBPAGE: attachdownload > 116 ** WEBPAGE: attachimage > 117 ** WEBPAGE: attachview > 118 ** > 119 ** tkt=TICKETUUID > 120 ** page=WIKIPAGE > 121 ** file=FILENAME > 122 ** attachid=ID > 123 ** > 124 ** List attachments. > 125 */ > 126 void attachview_page(void){ > 127 const char *zPage = P("page"); > 128 const char *zTkt = P("tkt"); > 129 const char *zFile = P("file"); > 130 const char *zTarget; > 131 int attachid = atoi(PD("attachid","0")); > 132 char *zUUID; > 133 > 134 if( zPage && zTkt ) zTkt = 0; > 135 if( zFile==0 ) fossil_redirect_home(); > 136 login_check_credentials(); > 137 if( zPage ){ > 138 if( g.okRdWiki==0 ) login_needed(); > 139 zTarget = zPage; > 140 }else if( zTkt ){ > 141 if( g.okRdTkt==0 ) login_needed(); > 142 zTarget = zTkt; > 143 }else{ > 144 fossil_redirect_home(); > 145 } > 146 if( attachid>0 ){ > 147 zUUID = db_text(0, > 148 "SELECT coalesce(src,'x') FROM attachment" > 149 " WHERE target=%Q AND attachid=%d", > 150 zTarget, attachid > 151 ); > 152 }else{ > 153 zUUID = db_text(0, > 154 "SELECT coalesce(src,'x') FROM attachment" > 155 " WHERE target=%Q AND filename=%Q" > 156 " ORDER BY mtime DESC LIMIT 1", > 157 zTarget, zFile > 158 ); > 159 } > 160 if( zUUID==0 ){ > 161 style_header("No Such Attachment"); > 162 @ No such attachment.... > 163 style_footer(); > 164 return; > 165 }else if( zUUID[0]=='x' ){ > 166 style_header("Missing"); > 167 @ Attachment has been deleted > 168 style_footer(); > 169 return; > 170 } > 171 g.okRead = 1; > 172 cgi_replace_parameter("name",zUUID); > 173 if( strcmp(g.zPath,"attachview")==0 ){ > 174 artifact_page(); > 175 }else{ > 176 cgi_replace_parameter("m", mimetype_from_name(zFile)); > 177 rawartifact_page(); > 178 } > 179 } 97 180 98 /* 181 /* 99 ** WEBPAGE: attachadd 182 ** WEBPAGE: attachadd 100 ** 183 ** 101 ** tkt=TICKETUUID 184 ** tkt=TICKETUUID 102 ** page=WIKIPAGE 185 ** page=WIKIPAGE 103 ** from=URL 186 ** from=URL ................................................................................................................................................................................ 171 blob_appendf(&manifest, "Z %b\n", &cksum); 254 blob_appendf(&manifest, "Z %b\n", &cksum); 172 rid = content_put(&manifest, 0, 0); 255 rid = content_put(&manifest, 0, 0); 173 manifest_crosslink(rid, &manifest); 256 manifest_crosslink(rid, &manifest); 174 db_end_transaction(0); 257 db_end_transaction(0); 175 cgi_redirect(zFrom); 258 cgi_redirect(zFrom); 176 } 259 } 177 style_header("Add Attachment"); 260 style_header("Add Attachment"); 178 @ <h1>Add Attachment To %s(zTargetType)</h1> | 261 @ <h2>Add Attachment To %s(zTargetType)</h2> 179 @ <form action="%s(g.zBaseURL)/attachadd" method="POST" 262 @ <form action="%s(g.zBaseURL)/attachadd" method="POST" 180 @ enctype="multipart/form-data"> 263 @ enctype="multipart/form-data"> 181 @ File to Attach: 264 @ File to Attach: 182 @ <input type="file" name="f" size="60"><br> 265 @ <input type="file" name="f" size="60"><br> 183 @ Description:<br> 266 @ Description:<br> 184 @ <textarea name="comment" cols=80 rows=5 wrap="virtual"></textarea><br> 267 @ <textarea name="comment" cols=80 rows=5 wrap="virtual"></textarea><br> 185 if( zTkt ){ 268 if( zTkt ){

Changes to src/info.c

730 if( pDownloadName && blob_size(pDownloadName)==0 ){ 730 if( pDownloadName && blob_size(pDownloadName)==0 ){ 731 blob_append(pDownloadName, zUuid, -1); 731 blob_append(pDownloadName, zUuid, -1); 732 } 732 } 733 cnt++; 733 cnt++; 734 } 734 } 735 db_finalize(&q); 735 db_finalize(&q); 736 } 736 } > 737 db_prepare(&q, > 738 "SELECT target, filename, datetime(mtime), user, src" > 739 " FROM attachment" > 740 " WHERE src=(SELECT uuid FROM blob WHERE rid=%d)" > 741 " ORDER BY mtime DESC", > 742 rid > 743 ); > 744 while( db_step(&q)==SQLITE_ROW ){ > 745 const char *zTarget = db_column_text(&q, 0); > 746 const char *zFilename = db_column_text(&q, 1); > 747 const char *zDate = db_column_text(&q, 2); > 748 const char *zUser = db_column_text(&q, 3); > 749 const char *zSrc = db_column_text(&q, 4); > 750 if( cnt>0 ){ > 751 @ Also attachment "%h(zFilename)" to > 752 }else{ > 753 @ Attachment "%h(zFilename)" to > 754 } > 755 if( strlen(zTarget)==UUID_SIZE && validate16(zTarget,UUID_SIZE) ){ > 756 char zShort[20]; > 757 memcpy(zShort, zTarget, 10); > 758 if( g.okHistory && g.okRdTkt ){ > 759 @ ticket [<a href="%s(g.zTop)/tktview?name=%s(zShort)">%s(zShort)</a>] > 760 }else{ > 761 @ ticket [%s(zShort)] > 762 } > 763 }else{ > 764 if( g.okHistory && g.okRdWiki ){ > 765 @ wiki page [<a href="%s(g.zTop)/wiki?name=%t(zTarget)">%h(zTarget)</a>] > 766 }else{ > 767 @ wiki page [%h(zTarget)] > 768 } > 769 } > 770 @ added by > 771 hyperlink_to_user(zUser,zDate," on"); > 772 hyperlink_to_date(zDate,"."); > 773 cnt++; > 774 if( pDownloadName && blob_size(pDownloadName)==0 ){ > 775 blob_append(pDownloadName, zSrc, -1); > 776 } > 777 } > 778 db_finalize(&q); 737 if( cnt==0 ){ 779 if( cnt==0 ){ 738 char *zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", rid); 780 char *zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", rid); 739 @ Control artifact. 781 @ Control artifact. 740 if( pDownloadName && blob_size(pDownloadName)==0 ){ 782 if( pDownloadName && blob_size(pDownloadName)==0 ){ 741 blob_append(pDownloadName, zUuid, -1); 783 blob_append(pDownloadName, zUuid, -1); 742 } 784 } 743 }else if( linkToView && g.okHistory ){ 785 }else if( linkToView && g.okHistory ){

Changes to src/tkt.c

294 ** WEBPAGE: tktview 294 ** WEBPAGE: tktview 295 ** URL: tktview?name=UUID 295 ** URL: tktview?name=UUID 296 ** 296 ** 297 ** View a ticket. 297 ** View a ticket. 298 */ 298 */ 299 void tktview_page(void){ 299 void tktview_page(void){ 300 const char *zScript; 300 const char *zScript; > 301 char *zFullName; > 302 const char *zUuid = PD("name",""); > 303 301 login_check_credentials(); 304 login_check_credentials(); 302 if( !g.okRdTkt ){ login_needed(); return; } 305 if( !g.okRdTkt ){ login_needed(); return; } 303 if( g.okWrTkt || g.okApndTkt ){ 306 if( g.okWrTkt || g.okApndTkt ){ 304 style_submenu_element("Edit", "Edit The Ticket", "%s/tktedit?name=%T", 307 style_submenu_element("Edit", "Edit The Ticket", "%s/tktedit?name=%T", 305 g.zTop, PD("name","")); 308 g.zTop, PD("name","")); 306 } 309 } 307 if( g.okHistory ){ 310 if( g.okHistory ){ 308 const char *zUuid = PD("name",""); < 309 style_submenu_element("History", "History Of This Ticket", 311 style_submenu_element("History", "History Of This Ticket", 310 "%s/tkthistory/%T", g.zTop, zUuid); 312 "%s/tkthistory/%T", g.zTop, zUuid); 311 style_submenu_element("Timeline", "Timeline Of This Ticket", 313 style_submenu_element("Timeline", "Timeline Of This Ticket", 312 "%s/tkttimeline/%T", g.zTop, zUuid); 314 "%s/tkttimeline/%T", g.zTop, zUuid); 313 style_submenu_element("Check-ins", "Check-ins Of This Ticket", 315 style_submenu_element("Check-ins", "Check-ins Of This Ticket", 314 "%s/tkttimeline/%T?y=ci", g.zTop, zUuid); 316 "%s/tkttimeline/%T?y=ci", g.zTop, zUuid); 315 } 317 } 316 if( g.okNewTkt ){ 318 if( g.okNewTkt ){ 317 style_submenu_element("New Ticket", "Create a new ticket", 319 style_submenu_element("New Ticket", "Create a new ticket", 318 "%s/tktnew", g.zTop); 320 "%s/tktnew", g.zTop); 319 } 321 } > 322 if( g.okApndTkt && g.okAttach ){ > 323 style_submenu_element("Attach", "Add An Attachment", > 324 "%s/attachadd?tkt=%T", g.zTop, zUuid); > 325 } 320 style_header("View Ticket"); 326 style_header("View Ticket"); 321 if( g.thTrace ) Th_Trace("BEGIN_TKTVIEW<br />\n", -1); 327 if( g.thTrace ) Th_Trace("BEGIN_TKTVIEW<br />\n", -1); 322 ticket_init(); 328 ticket_init(); 323 initializeVariablesFromDb(); 329 initializeVariablesFromDb(); 324 zScript = ticket_viewpage_code(); 330 zScript = ticket_viewpage_code(); 325 if( g.thTrace ) Th_Trace("BEGIN_TKTVIEW_SCRIPT<br />\n", -1); 331 if( g.thTrace ) Th_Trace("BEGIN_TKTVIEW_SCRIPT<br />\n", -1); 326 Th_Render(zScript); 332 Th_Render(zScript); 327 if( g.thTrace ) Th_Trace("END_TKTVIEW<br />\n", -1); 333 if( g.thTrace ) Th_Trace("END_TKTVIEW<br />\n", -1); > 334 > 335 zFullName = db_text(0, > 336 "SELECT tkt_uuid FROM ticket" > 337 " WHERE tkt_uuid GLOB '%q*'", zUuid); > 338 if( zFullName ){ > 339 int cnt = 0; > 340 Stmt q; > 341 db_prepare(&q, > 342 "SELECT datetime(mtime,'localtime'), filename, user" > 343 " FROM attachment" > 344 " WHERE isLatest AND src NOT NULL AND target=%Q" > 345 " ORDER BY mtime DESC", > 346 zFullName); > 347 while( db_step(&q)==SQLITE_ROW ){ > 348 const char *zDate = db_column_text(&q, 0); > 349 const char *zFile = db_column_text(&q, 1); > 350 const char *zUser = db_column_text(&q, 2); > 351 if( cnt==0 ){ > 352 @ <hr><h2>Attachments:</h2> > 353 @ <ul> > 354 } > 355 cnt++; > 356 @ <li><a href="%s(g.zTop)/attachview?tkt=%s(zFullName)&file=%t(zFile)"> > 357 @ %h(zFile)</a> add by %h(zUser) on > 358 hyperlink_to_date(zDate, ".</li>"); > 359 } > 360 if( cnt ){ > 361 @ </ul> > 362 } > 363 db_finalize(&q); > 364 } > 365 328 style_footer(); 366 style_footer(); 329 } 367 } 330 368 331 /* 369 /* 332 ** TH command: append_field FIELD STRING 370 ** TH command: append_field FIELD STRING 333 ** 371 ** 334 ** FIELD is the name of a database column to which we might want 372 ** FIELD is the name of a database column to which we might want

Changes to src/wiki.c

125 char *zTag; 125 char *zTag; 126 int rid = 0; 126 int rid = 0; 127 int isSandbox; 127 int isSandbox; 128 Blob wiki; 128 Blob wiki; 129 Manifest m; 129 Manifest m; 130 const char *zPageName; 130 const char *zPageName; 131 char *zBody = mprintf("%s","<i>Empty Page</i>"); 131 char *zBody = mprintf("%s","<i>Empty Page</i>"); > 132 Stmt q; > 133 int cnt = 0; 132 134 133 login_check_credentials(); 135 login_check_credentials(); 134 if( !g.okRdWiki ){ login_needed(); return; } 136 if( !g.okRdWiki ){ login_needed(); return; } 135 zPageName = P("name"); 137 zPageName = P("name"); 136 if( zPageName==0 ){ 138 if( zPageName==0 ){ 137 style_header("Wiki"); 139 style_header("Wiki"); 138 @ <ul> 140 @ <ul> ................................................................................................................................................................................ 150 @ to experiment.</li> 152 @ to experiment.</li> 151 if( g.okNewWiki ){ 153 if( g.okNewWiki ){ 152 @ <li> Create a <a href="%s(g.zBaseURL)/wikinew">new wiki page</a>.</li> 154 @ <li> Create a <a href="%s(g.zBaseURL)/wikinew">new wiki page</a>.</li> 153 } 155 } 154 @ <li> <a href="%s(g.zBaseURL)/wcontent">List of All Wiki Pages</a> 156 @ <li> <a href="%s(g.zBaseURL)/wcontent">List of All Wiki Pages</a> 155 @ available on this server.</li> 157 @ available on this server.</li> 156 @ <li> <form method="GET" action="%s(g.zBaseURL)/wfind"> 158 @ <li> <form method="GET" action="%s(g.zBaseURL)/wfind"> 157 @ Search wiki titles: <input type="text" name="title"/> &nbsp; <inpu | 159 @ Search wiki titles: <input type="text" name="title"/> > 160 @ &nbsp; <input type="submit" /> 158 @ </li> 161 @ </li> 159 @ </ul> 162 @ </ul> 160 style_footer(); 163 style_footer(); 161 return; 164 return; 162 } 165 } 163 if( check_name(zPageName) ) return; 166 if( check_name(zPageName) ) return; 164 isSandbox = is_sandbox(zPageName); 167 isSandbox = is_sandbox(zPageName); ................................................................................................................................................................................ 184 } 187 } 185 } 188 } 186 if( !g.isHome ){ 189 if( !g.isHome ){ 187 if( (rid && g.okWrWiki) || (!rid && g.okNewWiki) ){ 190 if( (rid && g.okWrWiki) || (!rid && g.okNewWiki) ){ 188 style_submenu_element("Edit", "Edit Wiki Page", "%s/wikiedit?name=%T", 191 style_submenu_element("Edit", "Edit Wiki Page", "%s/wikiedit?name=%T", 189 g.zTop, zPageName); 192 g.zTop, zPageName); 190 } 193 } > 194 if( rid && g.okWrWiki && g.okAttach ){ > 195 style_submenu_element("Attach", "Add An Attachment", > 196 "%s/attachadd?page=%T", g.zTop, zPageName); > 197 } 191 if( rid && g.okApndWiki ){ 198 if( rid && g.okApndWiki ){ 192 style_submenu_element("Append", "Add A Comment", "%s/wikiappend?name=%T", 199 style_submenu_element("Append", "Add A Comment", "%s/wikiappend?name=%T", 193 g.zTop, zPageName); 200 g.zTop, zPageName); 194 } 201 } 195 if( g.okHistory ){ 202 if( g.okHistory ){ 196 style_submenu_element("History", "History", "%s/whistory?name=%T", 203 style_submenu_element("History", "History", "%s/whistory?name=%T", 197 g.zTop, zPageName); 204 g.zTop, zPageName); 198 } 205 } 199 } 206 } 200 style_header(zPageName); 207 style_header(zPageName); 201 blob_init(&wiki, zBody, -1); 208 blob_init(&wiki, zBody, -1); 202 wiki_convert(&wiki, 0, 0); 209 wiki_convert(&wiki, 0, 0); 203 blob_reset(&wiki); 210 blob_reset(&wiki); > 211 > 212 db_prepare(&q, > 213 "SELECT datetime(mtime,'localtime'), filename, user" > 214 " FROM attachment" > 215 " WHERE isLatest AND src NOT NULL AND target=%Q" > 216 " ORDER BY mtime DESC", > 217 zPageName); > 218 while( db_step(&q)==SQLITE_ROW ){ > 219 const char *zDate = db_column_text(&q, 0); > 220 const char *zFile = db_column_text(&q, 1); > 221 const char *zUser = db_column_text(&q, 2); > 222 if( cnt==0 ){ > 223 @ <hr><h2>Attachments:</h2> > 224 @ <ul> > 225 } > 226 cnt++; > 227 @ <li><a href="%s(g.zTop)/attachview?page=%s(zPageName)&file=%t(zFile)"> > 228 @ %h(zFile)</a> add by %h(zUser) on > 229 hyperlink_to_date(zDate, ".</li>"); > 230 } > 231 if( cnt ){ > 232 @ </ul> > 233 } > 234 db_finalize(&q); > 235 204 if( !isSandbox ){ 236 if( !isSandbox ){ 205 manifest_clear(&m); 237 manifest_clear(&m); 206 } 238 } 207 style_footer(); 239 style_footer(); 208 } 240 } 209 241 210 /* 242 /*