| | @@ -713,84 +713,66 @@ |
| 713 | 713 | style_footer(); |
| 714 | 714 | } |
| 715 | 715 | |
| 716 | 716 | /* |
| 717 | 717 | ** WEBPAGE: winfo |
| 718 | | -** URL: /winfo?name=RID |
| 718 | +** URL: /winfo?name=UUID |
| 719 | 719 | ** |
| 720 | 720 | ** Return information about a wiki page. |
| 721 | 721 | */ |
| 722 | 722 | void winfo_page(void){ |
| 723 | | - Stmt q; |
| 724 | 723 | int rid; |
| 724 | + Manifest *pWiki; |
| 725 | + char *zUuid; |
| 726 | + char *zDate; |
| 727 | + Blob wiki; |
| 725 | 728 | |
| 726 | 729 | login_check_credentials(); |
| 727 | 730 | if( !g.perm.RdWiki ){ login_needed(); return; } |
| 728 | 731 | rid = name_to_rid_www("name"); |
| 729 | | - if( rid==0 ){ |
| 732 | + if( rid==0 || (pWiki = manifest_get(rid, CFTYPE_WIKI))==0 ){ |
| 730 | 733 | style_header("Wiki Page Information Error"); |
| 731 | | - @ No such object: %h(g.argv[2]) |
| 734 | + @ No such object: %h(P("name")) |
| 732 | 735 | style_footer(); |
| 733 | 736 | return; |
| 734 | 737 | } |
| 735 | | - db_prepare(&q, |
| 736 | | - "SELECT substr(tagname, 6, 1000), uuid," |
| 737 | | - " datetime(event.mtime, 'localtime'), user" |
| 738 | | - " FROM tagxref, tag, blob, event" |
| 739 | | - " WHERE tagxref.rid=%d" |
| 740 | | - " AND tag.tagid=tagxref.tagid" |
| 741 | | - " AND tag.tagname LIKE 'wiki-%%'" |
| 742 | | - " AND blob.rid=%d" |
| 743 | | - " AND event.objid=%d", |
| 744 | | - rid, rid, rid |
| 745 | | - ); |
| 746 | | - if( db_step(&q)==SQLITE_ROW ){ |
| 747 | | - const char *zName = db_column_text(&q, 0); |
| 748 | | - const char *zUuid = db_column_text(&q, 1); |
| 749 | | - char *zTitle = mprintf("Wiki Page %s", zName); |
| 750 | | - const char *zDate = db_column_text(&q,2); |
| 751 | | - const char *zUser = db_column_text(&q,3); |
| 752 | | - style_header(zTitle); |
| 753 | | - free(zTitle); |
| 754 | | - login_anonymous_available(); |
| 755 | | - @ <div class="section">Overview</div> |
| 756 | | - @ <p><table class="label-value"> |
| 757 | | - @ <tr><th>Version:</th><td>%s(zUuid)</td></tr> |
| 758 | | - @ <tr><th>Date:</th><td> |
| 759 | | - hyperlink_to_date(zDate, "</td></tr>"); |
| 760 | | - if( g.perm.Setup ){ |
| 761 | | - @ <tr><th>Record ID:</th><td>%d(rid)</td></tr> |
| 762 | | - } |
| 763 | | - @ <tr><th>Original User:</th><td> |
| 764 | | - hyperlink_to_user(zUser, zDate, "</td></tr>"); |
| 765 | | - if( g.perm.Hyperlink ){ |
| 766 | | - @ <tr><th>Commands:</th> |
| 767 | | - @ <td> |
| 768 | | - @ %z(href("%R/whistory?name=%t",zName))history</a> |
| 769 | | - @ | %z(href("%R/artifact/%S",zUuid))raw-text</a> |
| 770 | | - @ </td> |
| 771 | | - @ </tr> |
| 772 | | - } |
| 773 | | - @ </table></p> |
| 774 | | - }else{ |
| 775 | | - style_header("Wiki Information"); |
| 776 | | - rid = 0; |
| 777 | | - } |
| 778 | | - db_finalize(&q); |
| 779 | | - showTags(rid, "wiki-*"); |
| 780 | | - if( rid ){ |
| 781 | | - Manifest *pWiki; |
| 782 | | - pWiki = manifest_get(rid, CFTYPE_WIKI); |
| 783 | | - if( pWiki ){ |
| 784 | | - Blob wiki; |
| 785 | | - blob_init(&wiki, pWiki->zWiki, -1); |
| 786 | | - @ <div class="section">Content</div> |
| 787 | | - wiki_convert(&wiki, 0, 0); |
| 788 | | - blob_reset(&wiki); |
| 789 | | - } |
| 790 | | - manifest_destroy(pWiki); |
| 791 | | - } |
| 738 | + style_header("Edit To %h", pWiki->zWikiTitle); |
| 739 | + zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", rid); |
| 740 | + zDate = db_text(0, "SELECT datetime(%.17g)", pWiki->rDate); |
| 741 | + style_submenu_element("Raw", "Raw", "artifact/%S", zUuid); |
| 742 | + style_submenu_element("History", "History", "whistory?name=%t", |
| 743 | + pWiki->zWikiTitle); |
| 744 | + style_submenu_element("Page", "Page", "wiki?name=%t", |
| 745 | + pWiki->zWikiTitle); |
| 746 | + login_anonymous_available(); |
| 747 | + @ <div class="section">Overview</div> |
| 748 | + @ <p><table class="label-value"> |
| 749 | + @ <tr><th>Artifact ID:</th><td>%s(zUuid) |
| 750 | + if( g.perm.Setup ){ |
| 751 | + @ (%d(rid)) |
| 752 | + } |
| 753 | + @ </td></tr> |
| 754 | + @ <tr><th>Page Name:</th><td>%h(pWiki->zWikiTitle)</td></tr> |
| 755 | + @ <tr><th>Date:</th><td> |
| 756 | + hyperlink_to_date(zDate, "</td></tr>"); |
| 757 | + @ <tr><th>Original User:</th><td> |
| 758 | + hyperlink_to_user(pWiki->zUser, zDate, "</td></tr>"); |
| 759 | + if( pWiki->nParent>0 ){ |
| 760 | + int i; |
| 761 | + @ <tr><th>Parent%s(pWiki->nParent==1?"":"s"):</th><td> |
| 762 | + for(i=0; i<pWiki->nParent; i++){ |
| 763 | + char *zParent = pWiki->azParent[i]; |
| 764 | + @ %z(href("info/%S",zParent))%s(zParent)</a> |
| 765 | + } |
| 766 | + @ </td></tr> |
| 767 | + } |
| 768 | + @ </table> |
| 769 | + blob_init(&wiki, pWiki->zWiki, -1); |
| 770 | + @ <div class="section">Content</div> |
| 771 | + wiki_convert(&wiki, 0, 0); |
| 772 | + blob_reset(&wiki); |
| 773 | + manifest_destroy(pWiki); |
| 792 | 774 | style_footer(); |
| 793 | 775 | } |
| 794 | 776 | |
| 795 | 777 | /* |
| 796 | 778 | ** Show a webpage error message |
| | @@ -993,10 +975,25 @@ |
| 993 | 975 | manifest_destroy(pTo); |
| 994 | 976 | |
| 995 | 977 | style_footer(); |
| 996 | 978 | } |
| 997 | 979 | |
| 980 | +#if INTERFACE |
| 981 | +/* |
| 982 | +** Possible return values from object_description() |
| 983 | +*/ |
| 984 | +#define OBJTYPE_CHECKIN 0x0001 |
| 985 | +#define OBJTYPE_CONTENT 0x0002 |
| 986 | +#define OBJTYPE_WIKI 0x0004 |
| 987 | +#define OBJTYPE_TICKET 0x0008 |
| 988 | +#define OBJTYPE_ATTACHMENT 0x0010 |
| 989 | +#define OBJTYPE_EVENT 0x0020 |
| 990 | +#define OBJTYPE_TAG 0x0040 |
| 991 | +#define OBJTYPE_SYMLINK 0x0080 |
| 992 | +#define OBJTYPE_EXE 0x0100 |
| 993 | +#endif |
| 994 | + |
| 998 | 995 | /* |
| 999 | 996 | ** Write a description of an object to the www reply. |
| 1000 | 997 | ** |
| 1001 | 998 | ** If the object is a file then mention: |
| 1002 | 999 | ** |
| | @@ -1008,18 +1005,19 @@ |
| 1008 | 1005 | ** |
| 1009 | 1006 | ** * It's artifact ID |
| 1010 | 1007 | ** * date of check-in |
| 1011 | 1008 | ** * Comment & user |
| 1012 | 1009 | */ |
| 1013 | | -void object_description( |
| 1010 | +int object_description( |
| 1014 | 1011 | int rid, /* The artifact ID */ |
| 1015 | 1012 | int linkToView, /* Add viewer link if true */ |
| 1016 | 1013 | Blob *pDownloadName /* Fill with an appropriate download name */ |
| 1017 | 1014 | ){ |
| 1018 | 1015 | Stmt q; |
| 1019 | 1016 | int cnt = 0; |
| 1020 | 1017 | int nWiki = 0; |
| 1018 | + int objType = 0; |
| 1021 | 1019 | char *zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", rid); |
| 1022 | 1020 | |
| 1023 | 1021 | char *prevName = 0; |
| 1024 | 1022 | |
| 1025 | 1023 | db_prepare(&q, |
| | @@ -1051,15 +1049,18 @@ |
| 1051 | 1049 | if( prevName ) { |
| 1052 | 1050 | @ </ul> |
| 1053 | 1051 | } |
| 1054 | 1052 | if( mPerm==PERM_LNK ){ |
| 1055 | 1053 | @ <li>Symbolic link |
| 1054 | + objType |= OBJTYPE_SYMLINK; |
| 1056 | 1055 | }else if( mPerm==PERM_EXE ){ |
| 1057 | 1056 | @ <li>Executable file |
| 1057 | + objType |= OBJTYPE_EXE; |
| 1058 | 1058 | }else{ |
| 1059 | 1059 | @ <li>File |
| 1060 | 1060 | } |
| 1061 | + objType |= OBJTYPE_CONTENT; |
| 1061 | 1062 | @ %z(href("%R/finfo?name=%T",zName))%h(zName)</a> |
| 1062 | 1063 | @ <ul> |
| 1063 | 1064 | prevName = fossil_strdup(zName); |
| 1064 | 1065 | } |
| 1065 | 1066 | @ <li> |
| | @@ -1100,17 +1101,18 @@ |
| 1100 | 1101 | if( cnt>0 ){ |
| 1101 | 1102 | @ Also wiki page |
| 1102 | 1103 | }else{ |
| 1103 | 1104 | @ Wiki page |
| 1104 | 1105 | } |
| 1106 | + objType |= OBJTYPE_WIKI; |
| 1105 | 1107 | @ [%z(href("%R/wiki?name=%t",zPagename))%h(zPagename)</a>] by |
| 1106 | 1108 | hyperlink_to_user(zUser,zDate," on"); |
| 1107 | 1109 | hyperlink_to_date(zDate,"."); |
| 1108 | 1110 | nWiki++; |
| 1109 | 1111 | cnt++; |
| 1110 | 1112 | if( pDownloadName && blob_size(pDownloadName)==0 ){ |
| 1111 | | - blob_appendf(pDownloadName, "%s.wiki", zPagename); |
| 1113 | + blob_appendf(pDownloadName, "%s.txt", zPagename); |
| 1112 | 1114 | } |
| 1113 | 1115 | } |
| 1114 | 1116 | db_finalize(&q); |
| 1115 | 1117 | if( nWiki==0 ){ |
| 1116 | 1118 | db_prepare(&q, |
| | @@ -1129,16 +1131,20 @@ |
| 1129 | 1131 | if( cnt>0 ){ |
| 1130 | 1132 | @ Also |
| 1131 | 1133 | } |
| 1132 | 1134 | if( zType[0]=='w' ){ |
| 1133 | 1135 | @ Wiki edit |
| 1136 | + objType |= OBJTYPE_WIKI; |
| 1134 | 1137 | }else if( zType[0]=='t' ){ |
| 1135 | 1138 | @ Ticket change |
| 1139 | + objType |= OBJTYPE_TICKET; |
| 1136 | 1140 | }else if( zType[0]=='c' ){ |
| 1137 | 1141 | @ Manifest of check-in |
| 1142 | + objType |= OBJTYPE_CHECKIN; |
| 1138 | 1143 | }else if( zType[0]=='e' ){ |
| 1139 | 1144 | @ Instance of event |
| 1145 | + objType |= OBJTYPE_EVENT; |
| 1140 | 1146 | hyperlink_to_event_tagid(db_column_int(&q, 5)); |
| 1141 | 1147 | }else{ |
| 1142 | 1148 | @ Control file referencing |
| 1143 | 1149 | } |
| 1144 | 1150 | if( zType[0]!='e' ){ |
| | @@ -1170,10 +1176,11 @@ |
| 1170 | 1176 | if( cnt>0 ){ |
| 1171 | 1177 | @ Also attachment "%h(zFilename)" to |
| 1172 | 1178 | }else{ |
| 1173 | 1179 | @ Attachment "%h(zFilename)" to |
| 1174 | 1180 | } |
| 1181 | + objType |= OBJTYPE_ATTACHMENT; |
| 1175 | 1182 | if( strlen(zTarget)==UUID_SIZE && validate16(zTarget,UUID_SIZE) ){ |
| 1176 | 1183 | if( g.perm.Hyperlink && g.perm.RdTkt ){ |
| 1177 | 1184 | @ ticket [%z(href("%R/tktview?name=%S",zTarget))%S(zTarget)</a>] |
| 1178 | 1185 | }else{ |
| 1179 | 1186 | @ ticket [%S(zTarget)] |
| | @@ -1200,10 +1207,11 @@ |
| 1200 | 1207 | blob_appendf(pDownloadName, "%.10s.txt", zUuid); |
| 1201 | 1208 | } |
| 1202 | 1209 | }else if( linkToView && g.perm.Hyperlink ){ |
| 1203 | 1210 | @ %z(href("%R/artifact/%S",zUuid))[view]</a> |
| 1204 | 1211 | } |
| 1212 | + return objType; |
| 1205 | 1213 | } |
| 1206 | 1214 | |
| 1207 | 1215 | |
| 1208 | 1216 | /* |
| 1209 | 1217 | ** WEBPAGE: fdiff |
| | @@ -1519,11 +1527,15 @@ |
| 1519 | 1527 | Blob content; |
| 1520 | 1528 | const char *zMime; |
| 1521 | 1529 | Blob downloadName; |
| 1522 | 1530 | int renderAsWiki = 0; |
| 1523 | 1531 | int renderAsHtml = 0; |
| 1532 | + int objType; |
| 1533 | + int asText; |
| 1524 | 1534 | const char *zUuid; |
| 1535 | + Manifest *pManifest; |
| 1536 | + |
| 1525 | 1537 | if( P("ci") && P("filename") ){ |
| 1526 | 1538 | rid = artifact_from_ci_and_filename(); |
| 1527 | 1539 | } |
| 1528 | 1540 | if( rid==0 ){ |
| 1529 | 1541 | rid = name_to_rid_www("name"); |
| | @@ -1544,35 +1556,39 @@ |
| 1544 | 1556 | } |
| 1545 | 1557 | style_header("Artifact Content"); |
| 1546 | 1558 | zUuid = db_text("?", "SELECT uuid FROM blob WHERE rid=%d", rid); |
| 1547 | 1559 | @ <h2>Artifact %s(zUuid)</h2> |
| 1548 | 1560 | blob_zero(&downloadName); |
| 1549 | | - object_description(rid, 0, &downloadName); |
| 1561 | + objType = object_description(rid, 0, &downloadName); |
| 1550 | 1562 | style_submenu_element("Download", "Download", |
| 1551 | 1563 | "%s/raw/%T?name=%s", g.zTop, blob_str(&downloadName), zUuid); |
| 1564 | + asText = P("txt")!=0; |
| 1552 | 1565 | zMime = mimetype_from_name(blob_str(&downloadName)); |
| 1553 | 1566 | if( zMime ){ |
| 1554 | 1567 | if( fossil_strcmp(zMime, "text/html")==0 ){ |
| 1555 | | - if( P("txt") ){ |
| 1568 | + if( asText ){ |
| 1556 | 1569 | style_submenu_element("Html", "Html", |
| 1557 | 1570 | "%s/artifact/%s", g.zTop, zUuid); |
| 1558 | 1571 | }else{ |
| 1559 | 1572 | renderAsHtml = 1; |
| 1560 | 1573 | style_submenu_element("Text", "Text", |
| 1561 | 1574 | "%s/artifact/%s?txt=1", g.zTop, zUuid); |
| 1562 | 1575 | } |
| 1563 | 1576 | }else if( fossil_strcmp(zMime, "application/x-fossil-wiki")==0 ){ |
| 1564 | | - if( P("txt") ){ |
| 1577 | + if( asText ){ |
| 1565 | 1578 | style_submenu_element("Wiki", "Wiki", |
| 1566 | 1579 | "%s/artifact/%s", g.zTop, zUuid); |
| 1567 | 1580 | }else{ |
| 1568 | 1581 | renderAsWiki = 1; |
| 1569 | 1582 | style_submenu_element("Text", "Text", |
| 1570 | 1583 | "%s/artifact/%s?txt=1", g.zTop, zUuid); |
| 1571 | 1584 | } |
| 1572 | 1585 | } |
| 1573 | 1586 | } |
| 1587 | + if( (objType & (OBJTYPE_WIKI|OBJTYPE_TICKET))!=0 ){ |
| 1588 | + style_submenu_element("Parsed", "Parsed", "%R/info/%s", zUuid); |
| 1589 | + } |
| 1574 | 1590 | @ <hr /> |
| 1575 | 1591 | content_get(rid, &content); |
| 1576 | 1592 | if( renderAsWiki ){ |
| 1577 | 1593 | wiki_convert(&content, 0, 0); |
| 1578 | 1594 | }else if( renderAsHtml ){ |
| | @@ -1643,13 +1659,14 @@ |
| 1643 | 1659 | zTktName[10] = 0; |
| 1644 | 1660 | if( g.perm.Hyperlink ){ |
| 1645 | 1661 | @ <h2>Changes to ticket |
| 1646 | 1662 | @ %z(href("%R/tktview/%s",pTktChng->zTicketUuid))%s(zTktName)</a></h2> |
| 1647 | 1663 | @ |
| 1648 | | - @ <p>By %h(pTktChng->zUser) on %s(zDate). See also: |
| 1649 | | - @ %z(href("%R/artifact/%T",zUuid))artifact content</a>, and |
| 1650 | | - @ %z(href("%R/tkthistory/%s",pTktChng->zTicketUuid))ticket history</a></p> |
| 1664 | + @ <p>By %h(pTktChng->zUser) on %s(zDate). |
| 1665 | + style_submenu_element("Raw", "Raw", "%R/artifact/%T", zUuid); |
| 1666 | + style_submenu_element("History", "History", |
| 1667 | + "%R/tkthistory/%s", pTktChng->zTicketUuid); |
| 1651 | 1668 | }else{ |
| 1652 | 1669 | @ <h2>Changes to ticket %s(zTktName)</h2> |
| 1653 | 1670 | @ |
| 1654 | 1671 | @ <p>By %h(pTktChng->zUser) on %s(zDate). |
| 1655 | 1672 | @ </p> |
| 1656 | 1673 | |