Fossil SCM
Got basic /fileedit page skeleton in place. It can load/display a file, with some limits, but cannot yet do anything with it.
Commit
b5e3bc9e41127bbd1db145bad2bbb1a037f9ca159fe1cbbd1f2620341ae3d409
Parent
126d34fb321c798…
2 files changed
+133
+9
+133
| --- src/checkin.c | ||
| +++ src/checkin.c | ||
| @@ -3489,5 +3489,138 @@ | ||
| 3489 | 3489 | "with regards to this commit. It needs to be " |
| 3490 | 3490 | "'update'd or 'close'd and re-'open'ed."); |
| 3491 | 3491 | } |
| 3492 | 3492 | CheckinMiniInfo_cleanup(&cinf); |
| 3493 | 3493 | } |
| 3494 | + | |
| 3495 | + | |
| 3496 | +/* | |
| 3497 | +** Returns true if the given filename qualified for online editing | |
| 3498 | +** by the current user. | |
| 3499 | +** | |
| 3500 | +** Currently only looks at the user's permissions, pending decisions | |
| 3501 | +** on whether we want to filter them based on a glob list or mimetype | |
| 3502 | +** list. | |
| 3503 | +*/ | |
| 3504 | +int file_is_online_editable(const char *zFilename){ | |
| 3505 | + if(g.perm.Write){ | |
| 3506 | + return 1; | |
| 3507 | + } | |
| 3508 | + return 0; | |
| 3509 | +} | |
| 3510 | + | |
| 3511 | +/* | |
| 3512 | +** WEBPAGE: fileedit | |
| 3513 | +** | |
| 3514 | +** EXPERIMENTAL and subject to change and removal at any time. The goal | |
| 3515 | +** is to allow online edits of files. | |
| 3516 | +** | |
| 3517 | +** Query parameters: | |
| 3518 | +** | |
| 3519 | +** file=FILE Repo-relative path to the file. | |
| 3520 | +** r=VERSION Checkin version | |
| 3521 | +** | |
| 3522 | +** Parameters intended to be passed in only via the editor's own form: | |
| 3523 | +** | |
| 3524 | +** diff If true, show diff from prev version. | |
| 3525 | +** preview If true, preview (how depends on mimetype). | |
| 3526 | +** content File content. | |
| 3527 | +** | |
| 3528 | +** | |
| 3529 | +*/ | |
| 3530 | +void fileedit_page(){ | |
| 3531 | + const char * zFilename = PD("file",P("name")); /* filename */ | |
| 3532 | + const char * zRev = P("r"); /* checkin version */ | |
| 3533 | + const char * zContent = P("content"); /* file content */ | |
| 3534 | + const char * zComment = P("comment"); /* checkin comment */ | |
| 3535 | + char * zRevResolved = 0; /* Resolved zRev */ | |
| 3536 | + int vid, frid; /* checkin/file rids */ | |
| 3537 | + char * zFileUuid = 0; | |
| 3538 | + Blob content = empty_blob; | |
| 3539 | + | |
| 3540 | + login_check_credentials(); | |
| 3541 | + if( !g.perm.Write ){ | |
| 3542 | + login_needed(g.anon.Write); | |
| 3543 | + return; | |
| 3544 | + } | |
| 3545 | + /* | |
| 3546 | + ** TODOs include, but are not limited to: | |
| 3547 | + ** | |
| 3548 | + ** - On initial hit, fetch file content and stuff it in a textarea. | |
| 3549 | + ** | |
| 3550 | + ** - Preview button + view | |
| 3551 | + ** | |
| 3552 | + ** - Diff button + view | |
| 3553 | + ** | |
| 3554 | + ** - Checkbox options: allow fork, dry-run, convert EOL, | |
| 3555 | + ** allow merge conflict, allow older (just in case server time | |
| 3556 | + ** is messed up or someone checked something in w/ a future | |
| 3557 | + ** timestamp) | |
| 3558 | + ** | |
| 3559 | + */ | |
| 3560 | + if(!zRev || !*zRev || !zFilename || !*zFilename){ | |
| 3561 | + webpage_error("Missing required URL parameters."); | |
| 3562 | + } | |
| 3563 | + vid = symbolic_name_to_rid(zRev, "ci"); | |
| 3564 | + if(0==vid){ | |
| 3565 | + webpage_error("Could not resolve checkin version."); | |
| 3566 | + } | |
| 3567 | + zRevResolved = rid_to_uuid(vid); | |
| 3568 | + zFileUuid = db_text(0,"SELECT uuid FROM files_of_checkin WHERE " | |
| 3569 | + "filename=%Q %s AND checkinID=%d", | |
| 3570 | + zFilename, filename_collation(), vid); | |
| 3571 | + if(!zFileUuid){ | |
| 3572 | + webpage_error("Checkin [%S] does not contain file: %T", | |
| 3573 | + zRevResolved, zFilename); | |
| 3574 | + } | |
| 3575 | + | |
| 3576 | + frid = fast_uuid_to_rid(zFileUuid); | |
| 3577 | + assert(frid); | |
| 3578 | + if(zContent==0){ | |
| 3579 | + content_get(frid, &content); | |
| 3580 | + zContent = blob_size(&content) ? blob_str(&content) : NULL; | |
| 3581 | + }else{ | |
| 3582 | + blob_init(&content,zContent,-1); | |
| 3583 | + } | |
| 3584 | + if(looks_like_binary(&content)){ | |
| 3585 | + webpage_error("File appears to be binary. Cannot edit: %T", | |
| 3586 | + zFilename); | |
| 3587 | + } | |
| 3588 | + | |
| 3589 | + style_header("File Editor"); | |
| 3590 | +#define fp fossil_print | |
| 3591 | + /* ^^^ Appologies, Richard, but the @ form plays havoc with emacs */ | |
| 3592 | + | |
| 3593 | + fp("<h1>Editing: %T</h1>",zFilename); | |
| 3594 | + fp("<p>This page is <em>far from complete</em>.</p>"); | |
| 3595 | + | |
| 3596 | + fp("<form action=\"%R/fileedit\" method=\"POST\" class=\"fileedit-form\">"); | |
| 3597 | + fp("<input type=\"hidden\" name=\"r\" value=\"%s\">", zRevResolved); | |
| 3598 | + fp("<input type=\"hidden\" name=\"file\" value=\"%T\">", | |
| 3599 | + zFilename); | |
| 3600 | + fp("<h3>Comment</h3>"); | |
| 3601 | + fp("<textarea name=\"comment\" rows=\"3\" cols=\"80\">"); | |
| 3602 | + if(zComment && *zComment){ | |
| 3603 | + fp("%T"/*%T?*/, zComment); | |
| 3604 | + } | |
| 3605 | + fp("</textarea>"); | |
| 3606 | + fp("<h3>Content</h3>"); | |
| 3607 | + fp("<textarea name=\"content\" rows=\"20\" cols=\"80\">"); | |
| 3608 | + if(zContent && *zContent){ | |
| 3609 | + fp("%s", zContent); | |
| 3610 | + } | |
| 3611 | + fp("</textarea>"); | |
| 3612 | + | |
| 3613 | + fp("<div class=\"fileedit-options\">"); | |
| 3614 | + /* Put checkboxes here... */ | |
| 3615 | + fp("Many buttons and checkboxes to put here"); | |
| 3616 | + fp("</div>"); | |
| 3617 | + | |
| 3618 | + fp("</form>"); | |
| 3619 | + | |
| 3620 | + blob_reset(&content); | |
| 3621 | + fossil_free(zRevResolved); | |
| 3622 | + fossil_free(zFileUuid); | |
| 3623 | + | |
| 3624 | + style_footer(); | |
| 3625 | +#undef fp | |
| 3626 | +} | |
| 3494 | 3627 |
| --- src/checkin.c | |
| +++ src/checkin.c | |
| @@ -3489,5 +3489,138 @@ | |
| 3489 | "with regards to this commit. It needs to be " |
| 3490 | "'update'd or 'close'd and re-'open'ed."); |
| 3491 | } |
| 3492 | CheckinMiniInfo_cleanup(&cinf); |
| 3493 | } |
| 3494 |
| --- src/checkin.c | |
| +++ src/checkin.c | |
| @@ -3489,5 +3489,138 @@ | |
| 3489 | "with regards to this commit. It needs to be " |
| 3490 | "'update'd or 'close'd and re-'open'ed."); |
| 3491 | } |
| 3492 | CheckinMiniInfo_cleanup(&cinf); |
| 3493 | } |
| 3494 | |
| 3495 | |
| 3496 | /* |
| 3497 | ** Returns true if the given filename qualified for online editing |
| 3498 | ** by the current user. |
| 3499 | ** |
| 3500 | ** Currently only looks at the user's permissions, pending decisions |
| 3501 | ** on whether we want to filter them based on a glob list or mimetype |
| 3502 | ** list. |
| 3503 | */ |
| 3504 | int file_is_online_editable(const char *zFilename){ |
| 3505 | if(g.perm.Write){ |
| 3506 | return 1; |
| 3507 | } |
| 3508 | return 0; |
| 3509 | } |
| 3510 | |
| 3511 | /* |
| 3512 | ** WEBPAGE: fileedit |
| 3513 | ** |
| 3514 | ** EXPERIMENTAL and subject to change and removal at any time. The goal |
| 3515 | ** is to allow online edits of files. |
| 3516 | ** |
| 3517 | ** Query parameters: |
| 3518 | ** |
| 3519 | ** file=FILE Repo-relative path to the file. |
| 3520 | ** r=VERSION Checkin version |
| 3521 | ** |
| 3522 | ** Parameters intended to be passed in only via the editor's own form: |
| 3523 | ** |
| 3524 | ** diff If true, show diff from prev version. |
| 3525 | ** preview If true, preview (how depends on mimetype). |
| 3526 | ** content File content. |
| 3527 | ** |
| 3528 | ** |
| 3529 | */ |
| 3530 | void fileedit_page(){ |
| 3531 | const char * zFilename = PD("file",P("name")); /* filename */ |
| 3532 | const char * zRev = P("r"); /* checkin version */ |
| 3533 | const char * zContent = P("content"); /* file content */ |
| 3534 | const char * zComment = P("comment"); /* checkin comment */ |
| 3535 | char * zRevResolved = 0; /* Resolved zRev */ |
| 3536 | int vid, frid; /* checkin/file rids */ |
| 3537 | char * zFileUuid = 0; |
| 3538 | Blob content = empty_blob; |
| 3539 | |
| 3540 | login_check_credentials(); |
| 3541 | if( !g.perm.Write ){ |
| 3542 | login_needed(g.anon.Write); |
| 3543 | return; |
| 3544 | } |
| 3545 | /* |
| 3546 | ** TODOs include, but are not limited to: |
| 3547 | ** |
| 3548 | ** - On initial hit, fetch file content and stuff it in a textarea. |
| 3549 | ** |
| 3550 | ** - Preview button + view |
| 3551 | ** |
| 3552 | ** - Diff button + view |
| 3553 | ** |
| 3554 | ** - Checkbox options: allow fork, dry-run, convert EOL, |
| 3555 | ** allow merge conflict, allow older (just in case server time |
| 3556 | ** is messed up or someone checked something in w/ a future |
| 3557 | ** timestamp) |
| 3558 | ** |
| 3559 | */ |
| 3560 | if(!zRev || !*zRev || !zFilename || !*zFilename){ |
| 3561 | webpage_error("Missing required URL parameters."); |
| 3562 | } |
| 3563 | vid = symbolic_name_to_rid(zRev, "ci"); |
| 3564 | if(0==vid){ |
| 3565 | webpage_error("Could not resolve checkin version."); |
| 3566 | } |
| 3567 | zRevResolved = rid_to_uuid(vid); |
| 3568 | zFileUuid = db_text(0,"SELECT uuid FROM files_of_checkin WHERE " |
| 3569 | "filename=%Q %s AND checkinID=%d", |
| 3570 | zFilename, filename_collation(), vid); |
| 3571 | if(!zFileUuid){ |
| 3572 | webpage_error("Checkin [%S] does not contain file: %T", |
| 3573 | zRevResolved, zFilename); |
| 3574 | } |
| 3575 | |
| 3576 | frid = fast_uuid_to_rid(zFileUuid); |
| 3577 | assert(frid); |
| 3578 | if(zContent==0){ |
| 3579 | content_get(frid, &content); |
| 3580 | zContent = blob_size(&content) ? blob_str(&content) : NULL; |
| 3581 | }else{ |
| 3582 | blob_init(&content,zContent,-1); |
| 3583 | } |
| 3584 | if(looks_like_binary(&content)){ |
| 3585 | webpage_error("File appears to be binary. Cannot edit: %T", |
| 3586 | zFilename); |
| 3587 | } |
| 3588 | |
| 3589 | style_header("File Editor"); |
| 3590 | #define fp fossil_print |
| 3591 | /* ^^^ Appologies, Richard, but the @ form plays havoc with emacs */ |
| 3592 | |
| 3593 | fp("<h1>Editing: %T</h1>",zFilename); |
| 3594 | fp("<p>This page is <em>far from complete</em>.</p>"); |
| 3595 | |
| 3596 | fp("<form action=\"%R/fileedit\" method=\"POST\" class=\"fileedit-form\">"); |
| 3597 | fp("<input type=\"hidden\" name=\"r\" value=\"%s\">", zRevResolved); |
| 3598 | fp("<input type=\"hidden\" name=\"file\" value=\"%T\">", |
| 3599 | zFilename); |
| 3600 | fp("<h3>Comment</h3>"); |
| 3601 | fp("<textarea name=\"comment\" rows=\"3\" cols=\"80\">"); |
| 3602 | if(zComment && *zComment){ |
| 3603 | fp("%T"/*%T?*/, zComment); |
| 3604 | } |
| 3605 | fp("</textarea>"); |
| 3606 | fp("<h3>Content</h3>"); |
| 3607 | fp("<textarea name=\"content\" rows=\"20\" cols=\"80\">"); |
| 3608 | if(zContent && *zContent){ |
| 3609 | fp("%s", zContent); |
| 3610 | } |
| 3611 | fp("</textarea>"); |
| 3612 | |
| 3613 | fp("<div class=\"fileedit-options\">"); |
| 3614 | /* Put checkboxes here... */ |
| 3615 | fp("Many buttons and checkboxes to put here"); |
| 3616 | fp("</div>"); |
| 3617 | |
| 3618 | fp("</form>"); |
| 3619 | |
| 3620 | blob_reset(&content); |
| 3621 | fossil_free(zRevResolved); |
| 3622 | fossil_free(zFileUuid); |
| 3623 | |
| 3624 | style_footer(); |
| 3625 | #undef fp |
| 3626 | } |
| 3627 |
+9
| --- src/default_css.txt | ||
| +++ src/default_css.txt | ||
| @@ -860,5 +860,14 @@ | ||
| 860 | 860 | // } |
| 861 | 861 | // #setup_skinedit_css_defaults > tbody > tr > td:nth-of-type(2) > div { |
| 862 | 862 | // max-width: 30em; |
| 863 | 863 | // overflow: auto; |
| 864 | 864 | // } |
| 865 | +// .fileedit-XXX => /fileedit page | |
| 866 | +.fileedit-form textarea { | |
| 867 | + width: 100%; | |
| 868 | +} | |
| 869 | +.fileedit-form .fileedit-options { | |
| 870 | + padding: 0.5em; | |
| 871 | + margin: 1em 0 0 0; | |
| 872 | + border: 2px inset #a0a0a0; | |
| 873 | +} | |
| 865 | 874 |
| --- src/default_css.txt | |
| +++ src/default_css.txt | |
| @@ -860,5 +860,14 @@ | |
| 860 | // } |
| 861 | // #setup_skinedit_css_defaults > tbody > tr > td:nth-of-type(2) > div { |
| 862 | // max-width: 30em; |
| 863 | // overflow: auto; |
| 864 | // } |
| 865 |
| --- src/default_css.txt | |
| +++ src/default_css.txt | |
| @@ -860,5 +860,14 @@ | |
| 860 | // } |
| 861 | // #setup_skinedit_css_defaults > tbody > tr > td:nth-of-type(2) > div { |
| 862 | // max-width: 30em; |
| 863 | // overflow: auto; |
| 864 | // } |
| 865 | // .fileedit-XXX => /fileedit page |
| 866 | .fileedit-form textarea { |
| 867 | width: 100%; |
| 868 | } |
| 869 | .fileedit-form .fileedit-options { |
| 870 | padding: 0.5em; |
| 871 | margin: 1em 0 0 0; |
| 872 | border: 2px inset #a0a0a0; |
| 873 | } |
| 874 |