Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
| Comment: | Added the /srchsetup page for configuring the /search screen. |
|---|---|
| Timelines: | family | ancestors | descendants | both | trunk |
| Files: | files | file ages | folders |
| SHA1: |
ca833ff86f0a6a7e00477cf88fb88176 |
| User & Date: | drh 2015-02-02 00:17:39.481 |
Context
|
2015-02-02
| ||
| 01:32 | Add support for searching tickets. This is still a full-scan search. check-in: e2230a446b user: drh tags: trunk | |
| 00:17 | Added the /srchsetup page for configuring the /search screen. check-in: ca833ff86f user: drh tags: trunk | |
|
2015-02-01
| ||
| 21:21 | Minor refactoring and general cleanup of the "fossil setting" logic. check-in: 32f8da0ce7 user: drh tags: trunk | |
Changes
Changes to src/search.c.
| ︙ | ︙ | |||
422 423 424 425 426 427 428 |
static void search_stext_sqlfunc(
sqlite3_context *context,
int argc,
sqlite3_value **argv
){
Blob txt;
const char *zType = (const char*)sqlite3_value_text(argv[0]);
| | | | | 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 |
static void search_stext_sqlfunc(
sqlite3_context *context,
int argc,
sqlite3_value **argv
){
Blob txt;
const char *zType = (const char*)sqlite3_value_text(argv[0]);
int rid = sqlite3_value_int(argv[1]);
const char *zName = (const char*)sqlite3_value_text(argv[2]);
search_stext(zType[0], rid, zName, &txt);
sqlite3_result_text(context, blob_materialize(&txt), -1, fossil_free);
}
/*
** Encode a string for use as a query parameter in a URL
*/
static void search_urlencode_sqlfunc(
|
| ︙ | ︙ | |||
554 555 556 557 558 559 560 |
** Other pending enhancements:
** * Search tickets
** * Search wiki
*/
void search_page(void){
const char *zPattern = PD("s","");
Stmt q;
| > > > > > | > | > > > > > | | > > > | > > > | | | | | | | | | | | | < < | | > | | | | 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 |
** Other pending enhancements:
** * Search tickets
** * Search wiki
*/
void search_page(void){
const char *zPattern = PD("s","");
Stmt q;
int okCheckin;
int okDoc;
int okTicket;
int okWiki;
int allOff;
const char *zDisable;
login_check_credentials();
okCheckin = g.perm.Read && db_get_boolean("search-ci",0);
okDoc = g.perm.Read && db_get_boolean("search-doc",0);
okTicket = g.perm.RdTkt && db_get_boolean("search-tkt",0);
okWiki = g.perm.RdWiki && db_get_boolean("search-wiki",0);
allOff = (okCheckin + okDoc + okTicket + okWiki == 0);
zDisable = allOff ? " disabled" : "";
zPattern = allOff ? "" : PD("s","");
style_header("Search");
@ <form method="GET" action="search"><center>
@ <input type="text" name="s" size="40" value="%h(zPattern)"%s(zDisable)>
@ <input type="submit" value="Search"%s(zDisable)>
if( allOff ){
@ <p class="generalError">Search is disabled</p>
}
@ </center></form>
while( fossil_isspace(zPattern[0]) ) zPattern++;
if( zPattern[0] ){
search_sql_setup(g.db);
add_content_sql_commands(g.db);
search_init(zPattern, "<b>", "</b>", " ... ",
SRCHFLG_STATIC|SRCHFLG_HTML|SRCHFLG_SCORE);
db_multi_exec(
"CREATE VIRTUAL TABLE IF NOT EXISTS temp.foci USING files_of_checkin;"
"CREATE TEMP TABLE x(label TEXT,url TEXT,date TEXT,snip TEXT);"
);
if( okDoc ){
char *zDocGlob = db_get("doc-glob","");
char *zDocBr = db_get("doc-branch","trunk");
if( zDocGlob && zDocGlob[0] && zDocBr && zDocBr[0] ){
db_multi_exec(
"INSERT INTO x(label,url,date,snip)"
" SELECT printf('Document: %%s',foci.filename),"
" printf('%R/doc/%T/%%s',foci.filename),"
" (SELECT datetime(event.mtime) FROM event"
" WHERE objid=symbolic_name_to_rid('trunk')),"
" snippet(stext('d',blob.rid,foci.filename))"
" FROM foci CROSS JOIN blob"
" WHERE checkinID=symbolic_name_to_rid('trunk')"
" AND blob.uuid=foci.uuid"
" AND %z",
zDocBr, glob_expr("foci.filename", zDocGlob)
);
}
}
if( okWiki ){
db_multi_exec(
"WITH wiki(name,rid,mtime) AS ("
" SELECT substr(tagname,6), tagxref.rid, max(tagxref.mtime)"
" FROM tag, tagxref"
" WHERE tag.tagname GLOB 'wiki-*'"
" AND tagxref.tagid=tag.tagid"
" GROUP BY 1"
")"
"INSERT INTO x(label,url,date,snip)"
" SELECT printf('Wiki: %%s',name),"
" printf('%R/wiki?name=%%s',urlencode(name)),"
" datetime(mtime),"
" snippet(stext('w',rid,name))"
" FROM wiki;"
);
}
if( okCheckin ){
db_multi_exec(
"WITH ckin(uuid,rid,mtime) AS ("
" SELECT blob.uuid, event.objid, event.mtime"
" FROM event, blob"
" WHERE event.type='ci'"
" AND blob.rid=event.objid"
")"
"INSERT INTO x(label,url,date,snip)"
" SELECT printf('Check-in [%%.10s] on %%s',uuid,datetime(mtime)),"
" printf('%R/timeline?c=%%s&n=8&y=ci',uuid),"
" datetime(mtime),"
" snippet(stext('c',rid,NULL))"
" FROM ckin;"
);
}
db_prepare(&q, "SELECT url, substr(snip,9), label"
" FROM x WHERE snip IS NOT NULL"
" ORDER BY substr(snip,1,8) DESC, date DESC;");
@ <ol>
while( db_step(&q)==SQLITE_ROW ){
const char *zUrl = db_column_text(&q, 0);
const char *zSnippet = db_column_text(&q, 1);
const char *zLabel = db_column_text(&q, 2);
@ <li><p>%s(href("%s",zUrl))%h(zLabel)</a><br>%s(zSnippet)</li>
}
|
| ︙ | ︙ | |||
674 675 676 677 678 679 680 | } /* ** Return "search text" - a reduced version of a document appropriate for ** full text search and/or for constructing a search result snippet. ** ** cType: d Embedded documentation | < | | | | | | | < < | | < | < | 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 |
}
/*
** Return "search text" - a reduced version of a document appropriate for
** full text search and/or for constructing a search result snippet.
**
** cType: d Embedded documentation
** w Wiki page
** c Check-in comment
** t Ticket text
**
** rid The RID of an artifact that defines the object
** being searched.
**
** zName Name of the object being searched.
*/
void search_stext(
char cType, /* Type of document */
int rid, /* BLOB.RID or TAG.TAGID value for document */
const char *zName, /* Name of the document */
Blob *pOut /* OUT: Initialize to the search text */
){
blob_init(pOut, 0, 0);
switch( cType ){
case 'd': { /* Documents */
Blob doc;
content_get(rid, &doc);
blob_to_utf8_no_bom(&doc, 0);
get_stext_by_mimetype(&doc, mimetype_from_name(zName), pOut);
blob_reset(&doc);
break;
}
case 'w': { /* Wiki */
Manifest *pWiki = manifest_get(rid, CFTYPE_WIKI,0);
Blob wiki;
if( pWiki==0 ) break;
blob_init(&wiki, pWiki->zWiki, -1);
get_stext_by_mimetype(&wiki, wiki_filter_mimetypes(pWiki->zMimetype),
pOut);
blob_reset(&wiki);
manifest_destroy(pWiki);
break;
}
case 'c': { /* Ckeck-in Comments */
static Stmt q;
db_static_prepare(&q,
"SELECT coalesce(ecomment,comment)"
" ||' (user: '||coalesce(euser,user,'?')"
" ||', tags: '||"
" (SELECT group_concat(substr(tag.tagname,5),',')"
" FROM tag, tagxref"
|
| ︙ | ︙ | |||
739 740 741 742 743 744 745 |
db_reset(&q);
break;
}
}
}
/*
| | | | | < | | | | | | | | | | | 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 |
db_reset(&q);
break;
}
}
}
/*
** The arguments cType,rid,zName define an object that can be searched
** for. Return a URL (relative to the root of the Fossil project) that
** will jump to that document.
**
** Space to hold the returned string is obtained from mprintf() and should
** be freed by the caller using fossil_free() or the equivalent.
*/
char *search_url(
char cType, /* Type of document */
int rid, /* BLOB.RID or TAG.TAGID for the object */
const char *zName /* Name of the object */
){
char *zUrl = 0;
switch( cType ){
case 'd': { /* Documents */
zUrl = db_text(0,
"SELECT printf('/doc/%%s%%s', substr(blob.uuid,20), %Q)"
" FROM mlink, blob"
" WHERE mlink.fid=%d AND mlink.mid=blob.rid",
zName, rid);
break;
}
case 'w': { /* Wiki */
char *zId = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", rid);
zUrl = mprintf("/wiki?id=%z&name=%t", zId, zName);
break;
}
case 'c': { /* Ckeck-in Comment */
char *zId = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", rid);
zUrl = mprintf("/info/%z", zId);
break;
}
}
return zUrl;
}
/*
** COMMAND: test-search-stext
**
** Usage: fossil test-search-stext TYPE ARG1 ARG2
*/
void test_search_stext(void){
Blob out;
char *zUrl;
db_find_and_open_repository(0,0);
if( g.argc!=5 ) usage("TYPE RID NAME");
search_stext(g.argv[2][0], atoi(g.argv[3]), g.argv[4], &out);
zUrl = search_url(g.argv[2][0], atoi(g.argv[3]), g.argv[4]);
fossil_print("%s\n%z\n",blob_str(&out),zUrl);
blob_reset(&out);
}
|
Changes to src/setup.c.
| ︙ | ︙ | |||
68 69 70 71 72 73 74 |
** if it does not. */
if( !cgi_header_contains("<base href=") ){
@ <p class="generalError"><b>Configuration Error:</b> Please add
@ <tt><base href="$secureurl/$current_page"></tt> after
@ <tt><head></tt> in the <a href="setup_header">HTML header</a>!</p>
}
| | > > | 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 |
** if it does not. */
if( !cgi_header_contains("<base href=") ){
@ <p class="generalError"><b>Configuration Error:</b> Please add
@ <tt><base href="$secureurl/$current_page"></tt> after
@ <tt><head></tt> in the <a href="setup_header">HTML header</a>!</p>
}
@ <table border="0" cellspacing="3">
setup_menu_entry("Users", "setup_ulist",
"Grant privileges to individual users.");
setup_menu_entry("Access", "setup_access",
"Control access settings.");
setup_menu_entry("Configuration", "setup_config",
"Configure the WWW components of the repository");
setup_menu_entry("Settings", "setup_settings",
"Web interface to the \"fossil settings\" command");
setup_menu_entry("Timeline", "setup_timeline",
"Timeline display preferences");
setup_menu_entry("Login-Group", "setup_login_group",
"Manage single sign-on between this repository and others"
" on the same server");
setup_menu_entry("Tickets", "tktsetup",
"Configure the trouble-ticketing system for this repository");
setup_menu_entry("Search","srchsetup",
"Configure the built-in search engine");
setup_menu_entry("Transfers", "xfersetup",
"Configure the transfer system for this repository");
setup_menu_entry("Skins", "setup_skin",
"Select from a menu of prepackaged \"skins\" for the web interface");
setup_menu_entry("CSS", "setup_editcss",
"Edit the Cascading Style Sheet used by all pages of this repository");
setup_menu_entry("Header", "setup_header",
|
| ︙ | ︙ | |||
2153 2154 2155 2156 2157 2158 2159 |
}
@ </tbody></table>
if(limit>0 && counter<limit){
@ <div>%d(counter) entries shown.</div>
}
style_footer();
}
| > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 2155 2156 2157 2158 2159 2160 2161 2162 2163 2164 2165 2166 2167 2168 2169 2170 2171 2172 2173 2174 2175 2176 2177 2178 2179 2180 2181 2182 2183 2184 2185 2186 2187 2188 2189 2190 2191 2192 2193 2194 2195 2196 2197 2198 2199 2200 2201 2202 2203 2204 2205 2206 2207 2208 2209 2210 2211 2212 2213 |
}
@ </tbody></table>
if(limit>0 && counter<limit){
@ <div>%d(counter) entries shown.</div>
}
style_footer();
}
/*
** WEBPAGE: srchsetup
**
** Configure the search engine.
*/
void page_srchsetup(){
login_check_credentials();
if( !g.perm.Setup && !g.perm.Admin ){
login_needed();
}
style_header("Search Configuration");
@ <form action="%s(g.zTop)/srchsetup" method="post"><div>
login_insert_csrf_secret();
@ <div style="text-align:center;font-weight:bold;">
@ Server-specific settings that affect the
@ <a href="%R/help?cmd=/search">/search</a> webpage.
@ </div>
@ <hr />
textarea_attribute("Document Glob List", 3, 35, "doc-glob", "dg", "", 0);
@ <p>The "Document Glob List" is a comma- or newline-separated list
@ of GLOB expressions that identify all documents within the source
@ tree that are to be searched when "Document Search" is enabled.
@ Some examples:
@ <table border=0 cellpadding=2 align=center>
@ <tr><td>*.wiki,*.html,*.md,*.txt<td style="width: 4x;">
@ <td>Search all wiki, HTML, Markdown, and Text files</tr>
@ <tr><td>doc/*.md,*/README.txt,README.txt<td>
@ <td>Search all Markdown files in the doc/ subfolder and all README.txt
@ files.</tr>
@ <tr><td>*<td><td>Search all checked-in files</tr>
@ <tr><td><i>(blank)</i><td>
@ <td>Search nothing. (Disables document search).</tr>
@ </table>
@ <hr />
entry_attribute("Document Branch", 20, "doc-branch", "db", "trunk", 0);
@ <p>When searching documents, use the versions of the files found at the
@ type of the "Document Branch" branch. Recommended value: "trunk".
@ Document search is disabled if blank.
@ <hr/>
onoff_attribute("Search Check-in Comments", "search-ci", "sc", 0, 0);
@ <br>
onoff_attribute("Search Documents", "search-doc", "sd", 0, 0);
@ <br>
onoff_attribute("Search Tickets", "search-tkt", "st", 0, 0);
@ <br>
onoff_attribute("Search Wiki","search-wiki", "sw", 0, 0);
@ <hr/>
@ <p><input type="submit" name="submit" value="Apply Changes" /></p>
@ </div></form>
style_footer();
}
|