Added an optional login link/status to the search public top nav bar.

Thus allowing a more convenient way (wihout the need to go to the admin
section) to login when searching on your remote or password protected
peer and benefit from extended search features such as Heuristics,
Bookmarking or JavasScript resorting.

Can be disabled using the ConfigSearchPage_p.html.
pull/135/head
luccioman 8 years ago
parent 1de86cf1bf
commit af198b990b

@ -1057,6 +1057,9 @@ publicSearchpage = true
# to /Status.html to get the main memu bar back
publicTopmenu = true
# set to true to include a login link/status in the search page public top navigation bar
search.publicTopNavBar.login = true
# Wiki access rights
# the built-in wiki system allows by default only that the administrator is allowed to make changes
# this can be changed. There are three options:

@ -40,11 +40,25 @@
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a class="navbar-brand" id="navbar-brand-cfg" href="#[promoteSearchPageGreeting.homepage]#" style="position:absolute;top:-6px;display:inline;white-space:nowrap;">
<img id="greeting-icon" class="yacylogo" src="#[promoteSearchPageGreeting.smallImage]#" alt="#[promoteSearchPageGreeting.imageAlt]#" style="height:auto; width:auto; max-width:200px; max-height:32px;vertical-align:middle;float:left;">&nbsp;<span id="greeting" style="position:absolute; top:50%;float:left;"></span>
<a class="navbar-brand" id="navbar-brand-cfg" href="#[promoteSearchPageGreeting.homepage]#" style="margin-top:-6px;white-space:nowrap;">
<img id="greeting-icon" class="yacylogo" src="#[promoteSearchPageGreeting.smallImage]#" alt="#[promoteSearchPageGreeting.imageAlt]#" style="height:auto; width:auto; max-width:200px; max-height:32px;vertical-align:middle;float:left;">&nbsp;
<span id="greeting"></span>
</a>
</div>
<div class="navbar-collapse collapse">
<input type="checkbox" name="search.publicTopNavBar.login" title="Enable login link/status" value="true" #(search.publicTopNavBar.login)#::checked="checked" #(/search.publicTopNavBar.login)# />
<ul class="nav navbar-nav">
<li id="header_login">
<a title="Log in to use extended search features" href="#" onclick="document.getElementById('header_login').className='hidden';document.getElementById('header_login_logged').className='navbar-text';return false;">
<span>Log in</span>
<span class="glyphicon glyphicon-log-in"></span>
</a>
</li>
<li id="header_login_logged" title="You are authenticated as userName" class="navbar-text hidden">
<span class="glyphicon glyphicon-user text-info"></span>
<span>userName</span>
</li>
</ul>
<ul class="nav navbar-nav navbar-right">
<li id="header_search-cfg" class="dropdown">
<a href="#" data-toggle="dropdown" class="dropdown-toggle">Search Interfaces<b class="caret"></b></a>

@ -62,6 +62,10 @@ public class ConfigSearchPage_p {
sb.tables.recordAPICall(post, "ConfigPortal_p.html", WorkTables.TABLE_API_TYPE_CONFIGURATION, "new portal design. greeting: " + newGreeting);
sb.setConfig("publicTopmenu", post.getBoolean("publicTopmenu"));
sb.setConfig(SwitchboardConstants.SEARCH_PUBLIC_TOP_NAV_BAR_LOGIN,
post.getBoolean(SwitchboardConstants.SEARCH_PUBLIC_TOP_NAV_BAR_LOGIN));
sb.setConfig("search.options", post.getBoolean("search.options"));
sb.setConfig("search.text", post.getBoolean("search.text"));
@ -162,6 +166,9 @@ public class ConfigSearchPage_p {
}
}
sb.setConfig("publicTopmenu", config.getProperty("publicTopmenu","true"));
sb.setConfig(SwitchboardConstants.SEARCH_PUBLIC_TOP_NAV_BAR_LOGIN,
config.getProperty(SwitchboardConstants.SEARCH_PUBLIC_TOP_NAV_BAR_LOGIN,
Boolean.toString(SwitchboardConstants.SEARCH_PUBLIC_TOP_NAV_BAR_LOGIN_DEFAULT)));
sb.setConfig("search.navigation", config.getProperty("search.navigation","hosts,authors,namespace,topics"));
sb.setConfig("search.options", config.getProperty("search.options","true"));
sb.setConfig("search.text", config.getProperty("search.text","true"));
@ -204,6 +211,11 @@ public class ConfigSearchPage_p {
prop.putHTML(SwitchboardConstants.GREETING_IMAGE_ALT, sb.getConfig(SwitchboardConstants.GREETING_IMAGE_ALT, ""));
prop.putHTML(SwitchboardConstants.INDEX_FORWARD, sb.getConfig(SwitchboardConstants.INDEX_FORWARD, ""));
prop.put("publicTopmenu", sb.getConfigBool("publicTopmenu", false) ? 1 : 0);
prop.put(SwitchboardConstants.SEARCH_PUBLIC_TOP_NAV_BAR_LOGIN,
sb.getConfigBool(SwitchboardConstants.SEARCH_PUBLIC_TOP_NAV_BAR_LOGIN,
SwitchboardConstants.SEARCH_PUBLIC_TOP_NAV_BAR_LOGIN_DEFAULT) ? 1 : 0);
prop.put("search.options", sb.getConfigBool("search.options", false) ? 1 : 0);
prop.put("search.text", sb.getConfigBool("search.text", false) ? 1 : 0);

@ -8,11 +8,28 @@
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a class="navbar-brand hidden-xs" id="navbar-brand" href="#[promoteSearchPageGreeting.homepage]#" style="position:absolute;top:-6px;display:inline;white-space:nowrap;">
<img id="greeting-icon" class="yacylogo" src="#[promoteSearchPageGreeting.smallImage]#" alt="#[promoteSearchPageGreeting.imageAlt]#" style="height:auto; width:auto; max-width:200px; max-height:32px;vertical-align:middle;float:left;">&nbsp;<span id="greeting" style="position:absolute; top:50%;float:left;"></span>
<a class="navbar-brand hidden-xs" id="navbar-brand" href="#[promoteSearchPageGreeting.homepage]#" style="margin-top:-6px;white-space:nowrap;">
<img id="greeting-icon" class="yacylogo" src="#[promoteSearchPageGreeting.smallImage]#" alt="#[promoteSearchPageGreeting.imageAlt]#"
style="height:auto; width:auto; max-width:200px; max-height:32px;vertical-align:middle;float:left;">&nbsp;
<span id="greeting"></span>
</a>
</div>
<div class="navbar-collapse collapse">
<ul class="nav navbar-nav">
#(showLogin)#::
<li id="header_login" title="You are authenticated as #[userName]#" class="navbar-text">
<span class="glyphicon glyphicon-user text-info"></span>
<span>#[userName]#</span>
</li>
::
<li id="header_login">
<a title="Log in to use extended search features" href="#[loginURL]#">
<span>Log in</span>
<span class="glyphicon glyphicon-log-in"></span>
</a>
</li>
#(/showLogin)#
</ul>
<ul class="nav navbar-nav navbar-right">
<li id="header_search" class="dropdown">
<a href="#" data-toggle="dropdown" class="dropdown-toggle" role="button" aria-haspopup="true" aria-expanded="false" title="Search Interfaces">

@ -101,14 +101,23 @@ public class yacysearch {
final Switchboard sb = (Switchboard) env;
sb.localSearchLastAccess = System.currentTimeMillis();
final boolean authorized = sb.verifyAuthentication(header);
final boolean searchAllowed = sb.getConfigBool(SwitchboardConstants.PUBLIC_SEARCHPAGE, true) || authorized;
String authenticatedUserName = null;
final boolean adminAuthenticated = sb.verifyAuthentication(header);
final boolean searchAllowed = sb.getConfigBool(SwitchboardConstants.PUBLIC_SEARCHPAGE, true) || adminAuthenticated;
boolean authenticated = sb.adminAuthenticated(header) >= 2;
if ( !authenticated ) {
boolean extendedSearchRights = adminAuthenticated;
if(adminAuthenticated) {
authenticatedUserName = sb.getConfig(SwitchboardConstants.ADMIN_ACCOUNT_USER_NAME, "admin");
}
if (!extendedSearchRights) {
final UserDB.Entry user = sb.userDB != null ? sb.userDB.getUser(header) : null;
authenticated = (user != null && user.hasRight(UserDB.AccessRight.EXTENDED_SEARCH_RIGHT));
if(user != null) {
extendedSearchRights = user.hasRight(UserDB.AccessRight.EXTENDED_SEARCH_RIGHT);
authenticatedUserName = user.getUserName();
}
}
final boolean localhostAccess = header.accessFromLocalhost();
final String promoteSearchPageGreeting =
(env.getConfigBool(SwitchboardConstants.GREETING_NETWORK_NAME, false)) ? env.getConfig(
@ -118,7 +127,7 @@ public class yacysearch {
// in case that the crawler is running and the search user is the peer admin, we expect that the user wants to check recently crawled document
// to ensure that recent crawl results are inside the search results, we do a soft commit here. This is also important for live demos!
if (authenticated && sb.getThread(SwitchboardConstants.CRAWLJOB_LOCAL_CRAWL).getJobCount() > 0) {
if (extendedSearchRights && sb.getThread(SwitchboardConstants.CRAWLJOB_LOCAL_CRAWL).getJobCount() > 0) {
sb.index.fulltext().commit(true);
}
final boolean focus = (post == null) ? true : post.get("focus", "1").equals("1");
@ -198,7 +207,7 @@ public class yacysearch {
return prop;
}
if (post.containsKey("auth") && !authenticated) {
if (post.containsKey("auth") && !extendedSearchRights) {
/*
* Access to authentication protected features is explicitely requested here
* but no authentication is provided : ask now for authentication.
@ -209,7 +218,7 @@ public class yacysearch {
prop.authenticationRequired();
return prop;
}
// check for JSONP
if ( post.containsKey("callback") ) {
final String jsonp = post.get("callback") + "([";
@ -266,7 +275,7 @@ public class yacysearch {
if ( !global ) {
// we count only searches on the local peer here, because global searches
// are counted on the target peer to preserve privacy of the searcher
if ( authenticated ) {
if ( extendedSearchRights ) {
// local or authenticated search requests are counted separately
// because they are not part of a public available peer statistic
sb.searchQueriesRobinsonFromLocal++;
@ -299,7 +308,7 @@ public class yacysearch {
ConcurrentLog.warn("LOCAL_SEARCH", "ACCESS CONTROL: BLACKLISTED CLIENT FROM "
+ client
+ " gets no permission to search");
} else if ( !authenticated && !localhostAccess && !intranetMode ) {
} else if ( !extendedSearchRights && !localhostAccess && !intranetMode ) {
// in case that we do a global search or we want to fetch snippets, we check for DoS cases
synchronized ( trackerHandles ) {
final int accInThreeSeconds =
@ -659,7 +668,7 @@ public class yacysearch {
DigestURL.hosthashess(sb.getConfig("search.excludehosth", "")),
MultiProtocolURL.TLD_any_zone_filter,
client,
authenticated,
extendedSearchRights,
indexSegment,
ranking,
header.get(HeaderFramework.USER_AGENT, ""),
@ -724,7 +733,7 @@ public class yacysearch {
theSearch.resortCachedResults();
}
if ( startRecord == 0 && authenticated && !stealthmode ) {
if ( startRecord == 0 && extendedSearchRights && !stealthmode ) {
if ( modifier.sitehost != null && sb.getConfigBool(SwitchboardConstants.HEURISTIC_SITE, false) ) {
sb.heuristicSite(theSearch, modifier.sitehost);
}
@ -776,7 +785,7 @@ public class yacysearch {
RequestHeader.FileType.HTML,
0,
theQuery,
suggestion, true, authenticated).toString());
suggestion, true, extendedSearchRights).toString());
prop.put("didYouMean_suggestions_" + meanCount + "_sep", "|");
meanCount++;
} catch (final ConcurrentModificationException e) {
@ -844,7 +853,7 @@ public class yacysearch {
prop.put("num-results_globalresults_remoteIndexCount", Formatter.number(theSearch.remote_rwi_available.get() + theSearch.remote_solr_available.get(), true));
prop.put("num-results_globalresults_remotePeerCount", Formatter.number(theSearch.remote_rwi_peerCount.get() + theSearch.remote_solr_peerCount.get(), true));
final boolean jsResort = global && authenticated // for now enable JavaScript resorting only for authenticated users as it requires too much resources per search request
final boolean jsResort = global && extendedSearchRights // for now enable JavaScript resorting only for authenticated users as it requires too much resources per search request
&& (contentdom == ContentDomain.ALL || contentdom == ContentDomain.TEXT) // For now JavaScript resorting can only be applied for text search
&& sb.getConfigBool(SwitchboardConstants.SEARCH_JS_RESORT, SwitchboardConstants.SEARCH_JS_RESORT_DEFAULT);
prop.put("jsResort", jsResort);
@ -854,7 +863,7 @@ public class yacysearch {
* eventually including fetched results with higher ranks from the Solr and RWI stacks */
prop.put("resortEnabled", !jsResort && global && !stealthmode && theSearch.resortCacheAllowed.availablePermits() > 0 ? 1 : 0);
prop.put("resortEnabled_url",
QueryParams.navurlBase(RequestHeader.FileType.HTML, theQuery, null, true, authenticated)
QueryParams.navurlBase(RequestHeader.FileType.HTML, theQuery, null, true, extendedSearchRights)
.append("&startRecord=").append(startRecord).append("&resortCachedResults=true")
.toString());
@ -893,8 +902,26 @@ public class yacysearch {
prop.put("depth", "0");
prop.put("localQuery", theSearch.query.isLocal() ? "1" : "0");
prop.put("jsResort_localQuery", theSearch.query.isLocal() ? "1" : "0");
final boolean showLogin = sb.getConfigBool(SwitchboardConstants.SEARCH_PUBLIC_TOP_NAV_BAR_LOGIN,
SwitchboardConstants.SEARCH_PUBLIC_TOP_NAV_BAR_LOGIN_DEFAULT);
if(showLogin) {
if(authenticatedUserName != null) {
/* Show the name of the authenticated user */
prop.put("showLogin", 1);
prop.put("showLogin_userName", authenticatedUserName);
} else {
/* Show a login link */
prop.put("showLogin", 2);
prop.put("showLogin_loginURL",
QueryParams.navurlBase(RequestHeader.FileType.HTML, theQuery, null, true, true).toString());
}
} else {
prop.put("showLogin", 0);
}
}
prop.put("focus", focus ? 1 : 0); // focus search field
prop.put("searchagain", global ? "1" : "0");
String former = originalquerystring.replaceAll(Segment.catchallString, "*");

@ -3823,6 +3823,10 @@ public final class Switchboard extends serverSwitch {
return 1;
}
/**
* @param header servlet request headers
* @return true when the headers contains valid admin authentication information
*/
public boolean verifyAuthentication(final RequestHeader header) {
// handle access rights
switch ( adminAuthenticated(header) ) {

@ -552,6 +552,12 @@ public final class SwitchboardConstants {
/** Default setting value controlling whether search results resorting by browser JavaScript is enabled */
public static final boolean SEARCH_JS_RESORT_DEFAULT = false;
/** Key of the setting controlling whether the search public top navigation bar includes a login link/status */
public static final String SEARCH_PUBLIC_TOP_NAV_BAR_LOGIN = "search.publicTopNavBar.login";
/** Default setting value controlling whether the search public top navigation bar includes a login link/status */
public static final boolean SEARCH_PUBLIC_TOP_NAV_BAR_LOGIN_DEFAULT = true;
/** Key of the setting controlling the max lines displayed in standard search navigators/facets */
public static final String SEARCH_NAVIGATION_MAXCOUNT = "search.navigation.maxcount";

Loading…
Cancel
Save