Fossil SCM
Correct redirection of /attachadd after attach to target=WikiPageName. Add some pieces to hypothetically support a NOSCRIPT fallback for file attachment using the legacy form, but it's completely tested.
Commit
31d882879aed1364ca151cec5ca9cbc36641189f0cb469b603b55ee09562eaa6
Parent
2f71c2bb50bec04…
2 files changed
+59
-32
+1
+59
-32
| --- src/attach.c | ||
| +++ src/attach.c | ||
| @@ -445,10 +445,41 @@ | ||
| 445 | 445 | blob_appendf(&manifest, "Z %b\n", &cksum); |
| 446 | 446 | attach_put(&manifest, rid, needModerator); |
| 447 | 447 | assert( blob_is_reset(&manifest) ); |
| 448 | 448 | db_end_transaction(0); |
| 449 | 449 | } |
| 450 | + | |
| 451 | +static void attach_render_legacy_form(const char *zForumPost, | |
| 452 | + const char *zTechNote, | |
| 453 | + const char *zTicket, | |
| 454 | + const char *zWikiPage, | |
| 455 | + const char *zComment, | |
| 456 | + const char *zFrom){ | |
| 457 | + form_begin("enctype='multipart/form-data'", "%R/attachadd"); | |
| 458 | + @ <div>\ | |
| 459 | + @ File to Attach: | |
| 460 | + @ <input type="file" name="f" size="60"><br> | |
| 461 | + @ Description:<br> | |
| 462 | + @ <textarea name="comment" cols="80" rows="5" wrap="virtual"\ | |
| 463 | + @ >%h(zComment)</textarea><br> | |
| 464 | + if( zForumPost ){ | |
| 465 | + @ <input type="hidden" name="forumpost" value="%h(zForumPost)">\ | |
| 466 | + }else if( zTicket ){ | |
| 467 | + @ <input type="hidden" name="tkt" value="%h(zTicket)">\ | |
| 468 | + }else if( zTechNote ){ | |
| 469 | + @ <input type="hidden" name="technote" value="%h(zTechNote)">\ | |
| 470 | + }else if( zWikiPage ){ | |
| 471 | + @ <input type="hidden" name="page" value="%h(zWikiPage)">\ | |
| 472 | + } | |
| 473 | + @ <input type="hidden" name="from" value="%h(zFrom)">\ | |
| 474 | + @ <input type="submit" name="ok" value="Add Attachment">\ | |
| 475 | + @ <input type="submit" name="cancel" value="Cancel">\ | |
| 476 | + @ </div> | |
| 477 | + captcha_generate(0); | |
| 478 | + login_insert_csrf_secret(); | |
| 479 | + @ </form> | |
| 480 | +} | |
| 450 | 481 | |
| 451 | 482 | /* |
| 452 | 483 | ** WEBPAGE: attachadd |
| 453 | 484 | ** Add a new attachment. |
| 454 | 485 | ** |
| @@ -586,33 +617,12 @@ | ||
| 586 | 617 | style_header("Add Attachment"); |
| 587 | 618 | if( !goodCaptcha ){ |
| 588 | 619 | @ <p class="generalError">Error: Incorrect security code.</p> |
| 589 | 620 | } |
| 590 | 621 | @ <h2>Add Attachment To %s(zTargetType)</h2> |
| 591 | - form_begin("enctype='multipart/form-data'", "%R/attachadd"); | |
| 592 | - @ <div> | |
| 593 | - @ File to Attach: | |
| 594 | - @ <input type="file" name="f" size="60"><br> | |
| 595 | - @ Description:<br> | |
| 596 | - @ <textarea name="comment" cols="80" rows="5" wrap="virtual"\ | |
| 597 | - @ >%h(zComment)</textarea><br> | |
| 598 | - if( zForumPost ){ | |
| 599 | - @ <input type="hidden" name="forumpost" value="%h(zTarget)"> | |
| 600 | - }else if( zTkt ){ | |
| 601 | - @ <input type="hidden" name="tkt" value="%h(zTkt)"> | |
| 602 | - }else if( zTechNote ){ | |
| 603 | - @ <input type="hidden" name="technote" value="%h(zTechNote)"> | |
| 604 | - }else{ | |
| 605 | - @ <input type="hidden" name="page" value="%h(zPage)"> | |
| 606 | - } | |
| 607 | - @ <input type="hidden" name="from" value="%h(zFrom)"> | |
| 608 | - @ <input type="submit" name="ok" value="Add Attachment"> | |
| 609 | - @ <input type="submit" name="cancel" value="Cancel"> | |
| 610 | - @ </div> | |
| 611 | - captcha_generate(0); | |
| 612 | - login_insert_csrf_secret(); | |
| 613 | - @ </form> | |
| 622 | + attach_render_legacy_form(zForumPost, zTechNote, zTechNote, zPage, | |
| 623 | + zComment, zFrom); | |
| 614 | 624 | builtin_fossil_js_bundle_or("attach", NULL); |
| 615 | 625 | style_finish_page(); |
| 616 | 626 | fossil_free(zTargetType); |
| 617 | 627 | fossil_free(zExtraFree); |
| 618 | 628 | } |
| @@ -657,10 +667,11 @@ | ||
| 657 | 667 | return; |
| 658 | 668 | } |
| 659 | 669 | db_begin_transaction(); |
| 660 | 670 | zTarget = P("target"); |
| 661 | 671 | iTgtType = attachment_target_type(zTarget); |
| 672 | + CX("{"); | |
| 662 | 673 | switch( iTgtType ){ |
| 663 | 674 | default: |
| 664 | 675 | case 0: |
| 665 | 676 | ajax_route_error(400, "Invalid attachment target."); |
| 666 | 677 | db_rollback_transaction(); |
| @@ -754,11 +765,11 @@ | ||
| 754 | 765 | bNeedsModeration, P(aKeyDesc)); |
| 755 | 766 | } |
| 756 | 767 | } |
| 757 | 768 | fossil_free(zExtraFree); |
| 758 | 769 | if( !bRollback ){ |
| 759 | - CX("{}"); | |
| 770 | + CX("}"); | |
| 760 | 771 | if( atoi(PD("dryrun","0"))>0 ){ |
| 761 | 772 | bRollback = 1; |
| 762 | 773 | } |
| 763 | 774 | } |
| 764 | 775 | db_end_transaction(bRollback); |
| @@ -778,14 +789,14 @@ | ||
| 778 | 789 | ** |
| 779 | 790 | ** Lists attachments for, and can add them to, a target artifact. |
| 780 | 791 | ** |
| 781 | 792 | ** target=TKT_HASH|WIKIPAGE_NAME|TECHNOTE_HASH|FORUMPOST_HASH |
| 782 | 793 | ** from=ORIGINATING_URL |
| 783 | -** to=URL_ON_COMPLETION | |
| 784 | 794 | ** |
| 785 | 795 | ** Works like /attachadd but uses a JS-based interactive attachment |
| 786 | -** selector. | |
| 796 | +** selector. If from=X is set, this page arrganges for a redirect | |
| 797 | +** back to X after attaching. | |
| 787 | 798 | ** |
| 788 | 799 | ** from=X and to=X tell it how to redirect when it's done. to=X |
| 789 | 800 | ** overrides from=X. If neither is set, it will redirect back to this |
| 790 | 801 | ** page to render the updated attachment list. |
| 791 | 802 | ** |
| @@ -795,21 +806,21 @@ | ||
| 795 | 806 | const char *zFrom = P("from"); |
| 796 | 807 | const char *zTarget = P("target"); |
| 797 | 808 | char *zTo = 0; |
| 798 | 809 | char *zTargetType = 0; |
| 799 | 810 | char *zExtraFree = 0; |
| 800 | - int iTgtType = 0; | |
| 811 | + int eTgtType = 0; | |
| 801 | 812 | int goodCaptcha = 1; |
| 813 | + char const * noJsArgs[] = {0,0,0,0}; /* Args for noscript form */ | |
| 802 | 814 | |
| 803 | - if( zFrom==0 ) zFrom = mprintf("%R/home"); | |
| 804 | 815 | if( P("cancel") ) cgi_redirect(zFrom); |
| 805 | 816 | if( 0==zTarget ){ |
| 806 | 817 | webpage_error("Requires target=X"); |
| 807 | 818 | } |
| 808 | 819 | login_check_credentials(); |
| 809 | - iTgtType = attachment_target_type(zTarget); | |
| 810 | - switch( iTgtType ){ | |
| 820 | + eTgtType = attachment_target_type(zTarget); | |
| 821 | + switch( eTgtType ){ | |
| 811 | 822 | default: |
| 812 | 823 | case 0: |
| 813 | 824 | webpage_error("Cannot resolve target=%h.", zTarget); |
| 814 | 825 | break; |
| 815 | 826 | case CFTYPE_FORUM:{ |
| @@ -824,10 +835,11 @@ | ||
| 824 | 835 | }else if( !g.perm.Admin && !forumpost_is_owner(fpid, 0) ){ |
| 825 | 836 | webpage_error("Only admins can attach files to other users' " |
| 826 | 837 | "forum posts."); |
| 827 | 838 | } |
| 828 | 839 | zTarget = zExtraFree = rid_to_uuid(fpid); |
| 840 | + noJsArgs[0] = zTarget; | |
| 829 | 841 | zTargetType = mprintf("Forum post <a href=\"%R/forumpost/%S\">%.16h</a>", |
| 830 | 842 | zTarget, zTarget); |
| 831 | 843 | zTo = mprintf("%R/forumpost/%S", zTarget); |
| 832 | 844 | break; |
| 833 | 845 | } |
| @@ -839,12 +851,14 @@ | ||
| 839 | 851 | if( !db_exists("SELECT 1 FROM tag WHERE tagname='event-%q'", zTarget) ){ |
| 840 | 852 | zTarget = db_text(0, "SELECT substr(tagname,7) FROM tag" |
| 841 | 853 | " WHERE tagname GLOB 'event-%q*'", zTarget); |
| 842 | 854 | if( zTarget==0) fossil_redirect_home(); |
| 843 | 855 | } |
| 856 | + zTo = zFrom ? 0 : mprintf("%R/technote?name=%T", zTarget); | |
| 844 | 857 | zTargetType = mprintf("Tech Note <a href=\"%R/technote/%s\">%S</a>", |
| 845 | 858 | zTarget, zTarget); |
| 859 | + noJsArgs[1] = zTarget; | |
| 846 | 860 | break; |
| 847 | 861 | } |
| 848 | 862 | case CFTYPE_TICKET:{ |
| 849 | 863 | if( g.perm.ApndTkt==0 || g.perm.Attach==0 ){ |
| 850 | 864 | login_needed(g.anon.ApndTkt && g.anon.Attach); |
| @@ -853,12 +867,14 @@ | ||
| 853 | 867 | if( !db_exists("SELECT 1 FROM tag WHERE tagname='tkt-%q'", zTarget) ){ |
| 854 | 868 | zTarget = db_text(0, "SELECT substr(tagname,5) FROM tag" |
| 855 | 869 | " WHERE tagname GLOB 'tkt-%q*'", zTarget); |
| 856 | 870 | if( zTarget==0 ) fossil_redirect_home(); |
| 857 | 871 | } |
| 872 | + zTo = zFrom ? 0 : mprintf("%R/tktview/%t", zTarget); | |
| 858 | 873 | zTargetType = mprintf("Ticket <a href=\"%R/tktview/%s\">%S</a>", |
| 859 | 874 | zTarget, zTarget); |
| 875 | + noJsArgs[2] = zTarget; | |
| 860 | 876 | break; |
| 861 | 877 | } |
| 862 | 878 | case CFTYPE_WIKI:{ |
| 863 | 879 | if( g.perm.ApndWiki==0 || g.perm.Attach==0 ){ |
| 864 | 880 | login_needed(g.anon.ApndWiki && g.anon.Attach); |
| @@ -865,12 +881,14 @@ | ||
| 865 | 881 | return; |
| 866 | 882 | } |
| 867 | 883 | if( !db_exists("SELECT 1 FROM tag WHERE tagname='wiki-%q'", zTarget) ){ |
| 868 | 884 | fossil_redirect_home(); |
| 869 | 885 | } |
| 886 | + zTo = zFrom ? 0 : mprintf("%R/wiki?name=%T", zTarget); | |
| 870 | 887 | zTargetType = mprintf("Wiki Page <a href=\"%R/wiki?name=%h\">%h</a>", |
| 871 | 888 | zTarget, zTarget); |
| 889 | + noJsArgs[3] = zTarget; | |
| 872 | 890 | break; |
| 873 | 891 | } |
| 874 | 892 | } |
| 875 | 893 | |
| 876 | 894 | db_begin_transaction(); |
| @@ -879,14 +897,23 @@ | ||
| 879 | 897 | style_header("Add Attachment"); |
| 880 | 898 | if( !goodCaptcha ){ |
| 881 | 899 | @ <p class="generalError">Error: Incorrect security code.</p> |
| 882 | 900 | } |
| 883 | 901 | @ <h2>Attachments for %s(zTargetType)</h2> |
| 902 | + if(1){ | |
| 903 | + /* noscript fallback is completely tested */ | |
| 904 | + @ <noscript> | |
| 905 | + attach_render_legacy_form(noJsArgs[0], noJsArgs[1], noJsArgs[2], | |
| 906 | + noJsArgs[3], 0, | |
| 907 | + zFrom ? zFrom : mprintf("%R/home")); | |
| 908 | + @ </noscript> | |
| 909 | + } | |
| 884 | 910 | attachment_list(zTarget, NULL, |
| 885 | 911 | ATTACHLIST_SIZE | ATTACHLIST_HIDE_UNAPPROVED); |
| 886 | - @ <div id='attachadd-form-wrapper'> | |
| 887 | - /* JS code imports these hidden fields into a form it generates. */ | |
| 912 | + @ <div id='attachadd-form-wrapper' class='hidden'> | |
| 913 | + /* fossil.attach.js populates this DIV with the attachment widget | |
| 914 | + ** and imports these hidden fields. */ | |
| 888 | 915 | @ <input type="hidden" name="target" value="%h(zTarget)"> |
| 889 | 916 | if( zFrom ){ |
| 890 | 917 | @ <input type="hidden" name="from" value="%h(zFrom)"> |
| 891 | 918 | } |
| 892 | 919 | if( zTo ){ |
| 893 | 920 |
| --- src/attach.c | |
| +++ src/attach.c | |
| @@ -445,10 +445,41 @@ | |
| 445 | blob_appendf(&manifest, "Z %b\n", &cksum); |
| 446 | attach_put(&manifest, rid, needModerator); |
| 447 | assert( blob_is_reset(&manifest) ); |
| 448 | db_end_transaction(0); |
| 449 | } |
| 450 | |
| 451 | /* |
| 452 | ** WEBPAGE: attachadd |
| 453 | ** Add a new attachment. |
| 454 | ** |
| @@ -586,33 +617,12 @@ | |
| 586 | style_header("Add Attachment"); |
| 587 | if( !goodCaptcha ){ |
| 588 | @ <p class="generalError">Error: Incorrect security code.</p> |
| 589 | } |
| 590 | @ <h2>Add Attachment To %s(zTargetType)</h2> |
| 591 | form_begin("enctype='multipart/form-data'", "%R/attachadd"); |
| 592 | @ <div> |
| 593 | @ File to Attach: |
| 594 | @ <input type="file" name="f" size="60"><br> |
| 595 | @ Description:<br> |
| 596 | @ <textarea name="comment" cols="80" rows="5" wrap="virtual"\ |
| 597 | @ >%h(zComment)</textarea><br> |
| 598 | if( zForumPost ){ |
| 599 | @ <input type="hidden" name="forumpost" value="%h(zTarget)"> |
| 600 | }else if( zTkt ){ |
| 601 | @ <input type="hidden" name="tkt" value="%h(zTkt)"> |
| 602 | }else if( zTechNote ){ |
| 603 | @ <input type="hidden" name="technote" value="%h(zTechNote)"> |
| 604 | }else{ |
| 605 | @ <input type="hidden" name="page" value="%h(zPage)"> |
| 606 | } |
| 607 | @ <input type="hidden" name="from" value="%h(zFrom)"> |
| 608 | @ <input type="submit" name="ok" value="Add Attachment"> |
| 609 | @ <input type="submit" name="cancel" value="Cancel"> |
| 610 | @ </div> |
| 611 | captcha_generate(0); |
| 612 | login_insert_csrf_secret(); |
| 613 | @ </form> |
| 614 | builtin_fossil_js_bundle_or("attach", NULL); |
| 615 | style_finish_page(); |
| 616 | fossil_free(zTargetType); |
| 617 | fossil_free(zExtraFree); |
| 618 | } |
| @@ -657,10 +667,11 @@ | |
| 657 | return; |
| 658 | } |
| 659 | db_begin_transaction(); |
| 660 | zTarget = P("target"); |
| 661 | iTgtType = attachment_target_type(zTarget); |
| 662 | switch( iTgtType ){ |
| 663 | default: |
| 664 | case 0: |
| 665 | ajax_route_error(400, "Invalid attachment target."); |
| 666 | db_rollback_transaction(); |
| @@ -754,11 +765,11 @@ | |
| 754 | bNeedsModeration, P(aKeyDesc)); |
| 755 | } |
| 756 | } |
| 757 | fossil_free(zExtraFree); |
| 758 | if( !bRollback ){ |
| 759 | CX("{}"); |
| 760 | if( atoi(PD("dryrun","0"))>0 ){ |
| 761 | bRollback = 1; |
| 762 | } |
| 763 | } |
| 764 | db_end_transaction(bRollback); |
| @@ -778,14 +789,14 @@ | |
| 778 | ** |
| 779 | ** Lists attachments for, and can add them to, a target artifact. |
| 780 | ** |
| 781 | ** target=TKT_HASH|WIKIPAGE_NAME|TECHNOTE_HASH|FORUMPOST_HASH |
| 782 | ** from=ORIGINATING_URL |
| 783 | ** to=URL_ON_COMPLETION |
| 784 | ** |
| 785 | ** Works like /attachadd but uses a JS-based interactive attachment |
| 786 | ** selector. |
| 787 | ** |
| 788 | ** from=X and to=X tell it how to redirect when it's done. to=X |
| 789 | ** overrides from=X. If neither is set, it will redirect back to this |
| 790 | ** page to render the updated attachment list. |
| 791 | ** |
| @@ -795,21 +806,21 @@ | |
| 795 | const char *zFrom = P("from"); |
| 796 | const char *zTarget = P("target"); |
| 797 | char *zTo = 0; |
| 798 | char *zTargetType = 0; |
| 799 | char *zExtraFree = 0; |
| 800 | int iTgtType = 0; |
| 801 | int goodCaptcha = 1; |
| 802 | |
| 803 | if( zFrom==0 ) zFrom = mprintf("%R/home"); |
| 804 | if( P("cancel") ) cgi_redirect(zFrom); |
| 805 | if( 0==zTarget ){ |
| 806 | webpage_error("Requires target=X"); |
| 807 | } |
| 808 | login_check_credentials(); |
| 809 | iTgtType = attachment_target_type(zTarget); |
| 810 | switch( iTgtType ){ |
| 811 | default: |
| 812 | case 0: |
| 813 | webpage_error("Cannot resolve target=%h.", zTarget); |
| 814 | break; |
| 815 | case CFTYPE_FORUM:{ |
| @@ -824,10 +835,11 @@ | |
| 824 | }else if( !g.perm.Admin && !forumpost_is_owner(fpid, 0) ){ |
| 825 | webpage_error("Only admins can attach files to other users' " |
| 826 | "forum posts."); |
| 827 | } |
| 828 | zTarget = zExtraFree = rid_to_uuid(fpid); |
| 829 | zTargetType = mprintf("Forum post <a href=\"%R/forumpost/%S\">%.16h</a>", |
| 830 | zTarget, zTarget); |
| 831 | zTo = mprintf("%R/forumpost/%S", zTarget); |
| 832 | break; |
| 833 | } |
| @@ -839,12 +851,14 @@ | |
| 839 | if( !db_exists("SELECT 1 FROM tag WHERE tagname='event-%q'", zTarget) ){ |
| 840 | zTarget = db_text(0, "SELECT substr(tagname,7) FROM tag" |
| 841 | " WHERE tagname GLOB 'event-%q*'", zTarget); |
| 842 | if( zTarget==0) fossil_redirect_home(); |
| 843 | } |
| 844 | zTargetType = mprintf("Tech Note <a href=\"%R/technote/%s\">%S</a>", |
| 845 | zTarget, zTarget); |
| 846 | break; |
| 847 | } |
| 848 | case CFTYPE_TICKET:{ |
| 849 | if( g.perm.ApndTkt==0 || g.perm.Attach==0 ){ |
| 850 | login_needed(g.anon.ApndTkt && g.anon.Attach); |
| @@ -853,12 +867,14 @@ | |
| 853 | if( !db_exists("SELECT 1 FROM tag WHERE tagname='tkt-%q'", zTarget) ){ |
| 854 | zTarget = db_text(0, "SELECT substr(tagname,5) FROM tag" |
| 855 | " WHERE tagname GLOB 'tkt-%q*'", zTarget); |
| 856 | if( zTarget==0 ) fossil_redirect_home(); |
| 857 | } |
| 858 | zTargetType = mprintf("Ticket <a href=\"%R/tktview/%s\">%S</a>", |
| 859 | zTarget, zTarget); |
| 860 | break; |
| 861 | } |
| 862 | case CFTYPE_WIKI:{ |
| 863 | if( g.perm.ApndWiki==0 || g.perm.Attach==0 ){ |
| 864 | login_needed(g.anon.ApndWiki && g.anon.Attach); |
| @@ -865,12 +881,14 @@ | |
| 865 | return; |
| 866 | } |
| 867 | if( !db_exists("SELECT 1 FROM tag WHERE tagname='wiki-%q'", zTarget) ){ |
| 868 | fossil_redirect_home(); |
| 869 | } |
| 870 | zTargetType = mprintf("Wiki Page <a href=\"%R/wiki?name=%h\">%h</a>", |
| 871 | zTarget, zTarget); |
| 872 | break; |
| 873 | } |
| 874 | } |
| 875 | |
| 876 | db_begin_transaction(); |
| @@ -879,14 +897,23 @@ | |
| 879 | style_header("Add Attachment"); |
| 880 | if( !goodCaptcha ){ |
| 881 | @ <p class="generalError">Error: Incorrect security code.</p> |
| 882 | } |
| 883 | @ <h2>Attachments for %s(zTargetType)</h2> |
| 884 | attachment_list(zTarget, NULL, |
| 885 | ATTACHLIST_SIZE | ATTACHLIST_HIDE_UNAPPROVED); |
| 886 | @ <div id='attachadd-form-wrapper'> |
| 887 | /* JS code imports these hidden fields into a form it generates. */ |
| 888 | @ <input type="hidden" name="target" value="%h(zTarget)"> |
| 889 | if( zFrom ){ |
| 890 | @ <input type="hidden" name="from" value="%h(zFrom)"> |
| 891 | } |
| 892 | if( zTo ){ |
| 893 |
| --- src/attach.c | |
| +++ src/attach.c | |
| @@ -445,10 +445,41 @@ | |
| 445 | blob_appendf(&manifest, "Z %b\n", &cksum); |
| 446 | attach_put(&manifest, rid, needModerator); |
| 447 | assert( blob_is_reset(&manifest) ); |
| 448 | db_end_transaction(0); |
| 449 | } |
| 450 | |
| 451 | static void attach_render_legacy_form(const char *zForumPost, |
| 452 | const char *zTechNote, |
| 453 | const char *zTicket, |
| 454 | const char *zWikiPage, |
| 455 | const char *zComment, |
| 456 | const char *zFrom){ |
| 457 | form_begin("enctype='multipart/form-data'", "%R/attachadd"); |
| 458 | @ <div>\ |
| 459 | @ File to Attach: |
| 460 | @ <input type="file" name="f" size="60"><br> |
| 461 | @ Description:<br> |
| 462 | @ <textarea name="comment" cols="80" rows="5" wrap="virtual"\ |
| 463 | @ >%h(zComment)</textarea><br> |
| 464 | if( zForumPost ){ |
| 465 | @ <input type="hidden" name="forumpost" value="%h(zForumPost)">\ |
| 466 | }else if( zTicket ){ |
| 467 | @ <input type="hidden" name="tkt" value="%h(zTicket)">\ |
| 468 | }else if( zTechNote ){ |
| 469 | @ <input type="hidden" name="technote" value="%h(zTechNote)">\ |
| 470 | }else if( zWikiPage ){ |
| 471 | @ <input type="hidden" name="page" value="%h(zWikiPage)">\ |
| 472 | } |
| 473 | @ <input type="hidden" name="from" value="%h(zFrom)">\ |
| 474 | @ <input type="submit" name="ok" value="Add Attachment">\ |
| 475 | @ <input type="submit" name="cancel" value="Cancel">\ |
| 476 | @ </div> |
| 477 | captcha_generate(0); |
| 478 | login_insert_csrf_secret(); |
| 479 | @ </form> |
| 480 | } |
| 481 | |
| 482 | /* |
| 483 | ** WEBPAGE: attachadd |
| 484 | ** Add a new attachment. |
| 485 | ** |
| @@ -586,33 +617,12 @@ | |
| 617 | style_header("Add Attachment"); |
| 618 | if( !goodCaptcha ){ |
| 619 | @ <p class="generalError">Error: Incorrect security code.</p> |
| 620 | } |
| 621 | @ <h2>Add Attachment To %s(zTargetType)</h2> |
| 622 | attach_render_legacy_form(zForumPost, zTechNote, zTechNote, zPage, |
| 623 | zComment, zFrom); |
| 624 | builtin_fossil_js_bundle_or("attach", NULL); |
| 625 | style_finish_page(); |
| 626 | fossil_free(zTargetType); |
| 627 | fossil_free(zExtraFree); |
| 628 | } |
| @@ -657,10 +667,11 @@ | |
| 667 | return; |
| 668 | } |
| 669 | db_begin_transaction(); |
| 670 | zTarget = P("target"); |
| 671 | iTgtType = attachment_target_type(zTarget); |
| 672 | CX("{"); |
| 673 | switch( iTgtType ){ |
| 674 | default: |
| 675 | case 0: |
| 676 | ajax_route_error(400, "Invalid attachment target."); |
| 677 | db_rollback_transaction(); |
| @@ -754,11 +765,11 @@ | |
| 765 | bNeedsModeration, P(aKeyDesc)); |
| 766 | } |
| 767 | } |
| 768 | fossil_free(zExtraFree); |
| 769 | if( !bRollback ){ |
| 770 | CX("}"); |
| 771 | if( atoi(PD("dryrun","0"))>0 ){ |
| 772 | bRollback = 1; |
| 773 | } |
| 774 | } |
| 775 | db_end_transaction(bRollback); |
| @@ -778,14 +789,14 @@ | |
| 789 | ** |
| 790 | ** Lists attachments for, and can add them to, a target artifact. |
| 791 | ** |
| 792 | ** target=TKT_HASH|WIKIPAGE_NAME|TECHNOTE_HASH|FORUMPOST_HASH |
| 793 | ** from=ORIGINATING_URL |
| 794 | ** |
| 795 | ** Works like /attachadd but uses a JS-based interactive attachment |
| 796 | ** selector. If from=X is set, this page arrganges for a redirect |
| 797 | ** back to X after attaching. |
| 798 | ** |
| 799 | ** from=X and to=X tell it how to redirect when it's done. to=X |
| 800 | ** overrides from=X. If neither is set, it will redirect back to this |
| 801 | ** page to render the updated attachment list. |
| 802 | ** |
| @@ -795,21 +806,21 @@ | |
| 806 | const char *zFrom = P("from"); |
| 807 | const char *zTarget = P("target"); |
| 808 | char *zTo = 0; |
| 809 | char *zTargetType = 0; |
| 810 | char *zExtraFree = 0; |
| 811 | int eTgtType = 0; |
| 812 | int goodCaptcha = 1; |
| 813 | char const * noJsArgs[] = {0,0,0,0}; /* Args for noscript form */ |
| 814 | |
| 815 | if( P("cancel") ) cgi_redirect(zFrom); |
| 816 | if( 0==zTarget ){ |
| 817 | webpage_error("Requires target=X"); |
| 818 | } |
| 819 | login_check_credentials(); |
| 820 | eTgtType = attachment_target_type(zTarget); |
| 821 | switch( eTgtType ){ |
| 822 | default: |
| 823 | case 0: |
| 824 | webpage_error("Cannot resolve target=%h.", zTarget); |
| 825 | break; |
| 826 | case CFTYPE_FORUM:{ |
| @@ -824,10 +835,11 @@ | |
| 835 | }else if( !g.perm.Admin && !forumpost_is_owner(fpid, 0) ){ |
| 836 | webpage_error("Only admins can attach files to other users' " |
| 837 | "forum posts."); |
| 838 | } |
| 839 | zTarget = zExtraFree = rid_to_uuid(fpid); |
| 840 | noJsArgs[0] = zTarget; |
| 841 | zTargetType = mprintf("Forum post <a href=\"%R/forumpost/%S\">%.16h</a>", |
| 842 | zTarget, zTarget); |
| 843 | zTo = mprintf("%R/forumpost/%S", zTarget); |
| 844 | break; |
| 845 | } |
| @@ -839,12 +851,14 @@ | |
| 851 | if( !db_exists("SELECT 1 FROM tag WHERE tagname='event-%q'", zTarget) ){ |
| 852 | zTarget = db_text(0, "SELECT substr(tagname,7) FROM tag" |
| 853 | " WHERE tagname GLOB 'event-%q*'", zTarget); |
| 854 | if( zTarget==0) fossil_redirect_home(); |
| 855 | } |
| 856 | zTo = zFrom ? 0 : mprintf("%R/technote?name=%T", zTarget); |
| 857 | zTargetType = mprintf("Tech Note <a href=\"%R/technote/%s\">%S</a>", |
| 858 | zTarget, zTarget); |
| 859 | noJsArgs[1] = zTarget; |
| 860 | break; |
| 861 | } |
| 862 | case CFTYPE_TICKET:{ |
| 863 | if( g.perm.ApndTkt==0 || g.perm.Attach==0 ){ |
| 864 | login_needed(g.anon.ApndTkt && g.anon.Attach); |
| @@ -853,12 +867,14 @@ | |
| 867 | if( !db_exists("SELECT 1 FROM tag WHERE tagname='tkt-%q'", zTarget) ){ |
| 868 | zTarget = db_text(0, "SELECT substr(tagname,5) FROM tag" |
| 869 | " WHERE tagname GLOB 'tkt-%q*'", zTarget); |
| 870 | if( zTarget==0 ) fossil_redirect_home(); |
| 871 | } |
| 872 | zTo = zFrom ? 0 : mprintf("%R/tktview/%t", zTarget); |
| 873 | zTargetType = mprintf("Ticket <a href=\"%R/tktview/%s\">%S</a>", |
| 874 | zTarget, zTarget); |
| 875 | noJsArgs[2] = zTarget; |
| 876 | break; |
| 877 | } |
| 878 | case CFTYPE_WIKI:{ |
| 879 | if( g.perm.ApndWiki==0 || g.perm.Attach==0 ){ |
| 880 | login_needed(g.anon.ApndWiki && g.anon.Attach); |
| @@ -865,12 +881,14 @@ | |
| 881 | return; |
| 882 | } |
| 883 | if( !db_exists("SELECT 1 FROM tag WHERE tagname='wiki-%q'", zTarget) ){ |
| 884 | fossil_redirect_home(); |
| 885 | } |
| 886 | zTo = zFrom ? 0 : mprintf("%R/wiki?name=%T", zTarget); |
| 887 | zTargetType = mprintf("Wiki Page <a href=\"%R/wiki?name=%h\">%h</a>", |
| 888 | zTarget, zTarget); |
| 889 | noJsArgs[3] = zTarget; |
| 890 | break; |
| 891 | } |
| 892 | } |
| 893 | |
| 894 | db_begin_transaction(); |
| @@ -879,14 +897,23 @@ | |
| 897 | style_header("Add Attachment"); |
| 898 | if( !goodCaptcha ){ |
| 899 | @ <p class="generalError">Error: Incorrect security code.</p> |
| 900 | } |
| 901 | @ <h2>Attachments for %s(zTargetType)</h2> |
| 902 | if(1){ |
| 903 | /* noscript fallback is completely tested */ |
| 904 | @ <noscript> |
| 905 | attach_render_legacy_form(noJsArgs[0], noJsArgs[1], noJsArgs[2], |
| 906 | noJsArgs[3], 0, |
| 907 | zFrom ? zFrom : mprintf("%R/home")); |
| 908 | @ </noscript> |
| 909 | } |
| 910 | attachment_list(zTarget, NULL, |
| 911 | ATTACHLIST_SIZE | ATTACHLIST_HIDE_UNAPPROVED); |
| 912 | @ <div id='attachadd-form-wrapper' class='hidden'> |
| 913 | /* fossil.attach.js populates this DIV with the attachment widget |
| 914 | ** and imports these hidden fields. */ |
| 915 | @ <input type="hidden" name="target" value="%h(zTarget)"> |
| 916 | if( zFrom ){ |
| 917 | @ <input type="hidden" name="from" value="%h(zFrom)"> |
| 918 | } |
| 919 | if( zTo ){ |
| 920 |
+1
| --- src/fossil.attach.js | ||
| +++ src/fossil.attach.js | ||
| @@ -488,10 +488,11 @@ | ||
| 488 | 488 | F.Attacher = Attacher; |
| 489 | 489 | |
| 490 | 490 | const eFormWrapper = document.querySelector('#attachadd-form-wrapper'); |
| 491 | 491 | if( eFormWrapper ){ |
| 492 | 492 | /* Inject a file-attachment form. */ |
| 493 | + eFormWrapper.classList.remove('hidden'); | |
| 493 | 494 | const urlArgs = new URLSearchParams(window.location.search); |
| 494 | 495 | let zTarget = urlArgs.get('target'); |
| 495 | 496 | let zTo = urlArgs.get('to') || urlArgs.get('from'); |
| 496 | 497 | const eBtnSubmit = D.button("Submit"); |
| 497 | 498 | eBtnSubmit.type = 'button'; |
| 498 | 499 |
| --- src/fossil.attach.js | |
| +++ src/fossil.attach.js | |
| @@ -488,10 +488,11 @@ | |
| 488 | F.Attacher = Attacher; |
| 489 | |
| 490 | const eFormWrapper = document.querySelector('#attachadd-form-wrapper'); |
| 491 | if( eFormWrapper ){ |
| 492 | /* Inject a file-attachment form. */ |
| 493 | const urlArgs = new URLSearchParams(window.location.search); |
| 494 | let zTarget = urlArgs.get('target'); |
| 495 | let zTo = urlArgs.get('to') || urlArgs.get('from'); |
| 496 | const eBtnSubmit = D.button("Submit"); |
| 497 | eBtnSubmit.type = 'button'; |
| 498 |
| --- src/fossil.attach.js | |
| +++ src/fossil.attach.js | |
| @@ -488,10 +488,11 @@ | |
| 488 | F.Attacher = Attacher; |
| 489 | |
| 490 | const eFormWrapper = document.querySelector('#attachadd-form-wrapper'); |
| 491 | if( eFormWrapper ){ |
| 492 | /* Inject a file-attachment form. */ |
| 493 | eFormWrapper.classList.remove('hidden'); |
| 494 | const urlArgs = new URLSearchParams(window.location.search); |
| 495 | let zTarget = urlArgs.get('target'); |
| 496 | let zTo = urlArgs.get('to') || urlArgs.get('from'); |
| 497 | const eBtnSubmit = D.button("Submit"); |
| 498 | eBtnSubmit.type = 'button'; |
| 499 |