PageRenderTime 57ms CodeModel.GetById 25ms RepoModel.GetById 1ms app.codeStats 0ms

/Release/SSC-KP-20130517/Intranet.root/Intranet.Website/Plugins/GSA/GSA.ascx.cs

#
C# | 1604 lines | 1387 code | 98 blank | 119 comment | 122 complexity | 90bf1439e1715cb88619ae4838224b99 MD5 | raw file
Possible License(s): LGPL-2.0, GPL-2.0, LGPL-2.1

Large files files are truncated, but you can click here to view the full file

  1. using System;
  2. using System.Collections;
  3. using System.Configuration;
  4. using System.Data;
  5. using System.Linq;
  6. using System.Web;
  7. using System.Web.Security;
  8. using System.Web.UI;
  9. using System.Web.UI.HtmlControls;
  10. using System.Web.UI.WebControls;
  11. using System.Web.UI.WebControls.WebParts;
  12. using System.Xml;
  13. using Intranet.Utils;
  14. using Intranet.WebSite.Domain;
  15. using Intranet.WebSite.ConfigurationSections;
  16. using Intranet.ComponentLibrary;
  17. using Intranet.ComponentLibrary.ComponentLibraryComponents;
  18. using Intranet.WebSite.Plugins.Search;
  19. using Intranet.XmlObjects;
  20. using Intranet.XmlObjects.LanguagePacks;
  21. using System.Collections.Generic;
  22. using System.Text;
  23. using System.Text.RegularExpressions;
  24. using Intranet.Domain.ConfigurationSections;
  25. using System.Net;
  26. using System.Diagnostics;
  27. namespace Intranet.WebSite.Plugins.GSA
  28. {
  29. public partial class GSA : BaseWebSitePlugin
  30. {
  31. private const string GOOGLE_RESULTS_XSLT_NL = @"~/App_Data/DataFormatting/GoogleResultsNL.xslt";
  32. private const string GOOGLE_RESULTS_XSLT_EN = @"~/App_Data/DataFormatting/GoogleResultsENStandard.xslt";
  33. private const string PLUGINNAME = "SearchResults";
  34. private const string PLUGINCONFIGNAME = "SearchResultsConfig";
  35. protected GSALanguagePack currentLanguagePack;
  36. private List<Facet> facets = new List<Facet>();
  37. private List<Facet> facetsGeneral = new List<Facet>();
  38. private List<Facet> facetsIntranet = new List<Facet>();
  39. private List<Facet> facetsKennisplein = new List<Facet>();
  40. #region Init & Load
  41. protected override void OnInit(EventArgs e)
  42. {
  43. this.Name = PLUGINNAME;
  44. if (string.IsNullOrEmpty(this.ConfigurationName))
  45. {
  46. this.ConfigurationName = PLUGINCONFIGNAME;
  47. }
  48. base.OnInit(e);
  49. this.LoadLanguagePack();
  50. }
  51. private void LoadLanguagePack()
  52. {
  53. string languageFile = string.Empty;
  54. foreach (languagepack lp in this.CurrentConfiguration.languagepacks)
  55. {
  56. if (lp.cultureInfo == System.Globalization.CultureInfo.CurrentCulture.Name)
  57. {
  58. languageFile = lp.location;
  59. break;
  60. }
  61. }
  62. this.currentLanguagePack = new GSALanguagePack();
  63. this.currentLanguagePack = ObjectXMLSerializer<GSALanguagePack>.Load(Server.MapPath(languageFile));
  64. }
  65. protected void Page_Load(object sender, EventArgs e)
  66. {
  67. var searchParameters = GetSearchParameters(this.Request);
  68. InitializeAdvancedSearchControls(searchParameters);
  69. if (ContainsGSAQuery(searchParameters))
  70. {
  71. // Set search textbox to be the same as first advanced textbox.
  72. SearchTerm.Value = SearchTermAll.Value;
  73. string resultString = BuildResultString(searchParameters);
  74. SearchedFor.Text = HttpUtility.HtmlEncode(resultString);
  75. this.Page.Title = resultString;
  76. }
  77. else
  78. {
  79. if (searchParameters.ContainsKey("AdvancedSearch") && searchParameters["AdvancedSearch"] == "on")
  80. {
  81. this.Page.Title = currentLanguagePack.TitleAdvanced;
  82. }
  83. else
  84. {
  85. this.Page.Title = currentLanguagePack.TitleNormal;
  86. }
  87. }
  88. if (searchParameters.ContainsKey("AdvancedSearch") && searchParameters["AdvancedSearch"] == "on")
  89. {
  90. //this.SearchPageTitleLiteral.Text = "<h1>Geadvanceerde Zoeken</h1>";
  91. //this.AdvancedSearchLinkLiteral.Text = "<a href=\"javascript:void(0)\" class=\"AdvancedSearchLink\">Geadvanceerd zoeken Aan</a>&nbsp;<a href=\"javascript:void(0)\" class=\"AdvancedSearchLink\">Wissen</a>";
  92. this.SearchPageTitleLiteral.Text = String.Format("<h1>{0}</h1>", currentLanguagePack.TitleAdvanced);
  93. this.AdvancedSearchLinkLiteral.Text = String.Format("<a id=\"AdvancedSearchToggle\" href=\"javascript:void(0)\" class=\"AdvancedSearchLink\">{0}</a>&nbsp;<a id=\"AdvancedSearchClear\" href=\"javascript:void(0)\" class=\"AdvancedSearchLink\">{1}</a>", currentLanguagePack.AdvancedButtonOpen, currentLanguagePack.AdvancedButtonErase);
  94. }
  95. else
  96. {
  97. //this.SearchPageTitleLiteral.Text = "<h1>Zoeken</h1>";
  98. //this.AdvancedSearchLinkLiteral.Text = "<a href=\"javascript:void(0)\" class=\"AdvancedSearchLink\">Geadvanceerd zoeken</a>";
  99. this.SearchPageTitleLiteral.Text = String.Format("<h1>{0}</h1>", currentLanguagePack.TitleNormal);
  100. this.AdvancedSearchLinkLiteral.Text = String.Format("<a id=\"AdvancedSearchToggle\" href=\"javascript:void(0)\" class=\"AdvancedSearchLink\">{0}</a>", currentLanguagePack.AdvancedButtonClosed);
  101. }
  102. // Get results
  103. if (ContainsGSAQuery(searchParameters))
  104. {
  105. // Make sure we have xml output, and add any missing parameters.
  106. searchParameters["output"] = "xml_no_dtd";
  107. if (!searchParameters.ContainsKey("client")) searchParameters["client"] = this.currentLanguagePack.Client_FrontEnd;
  108. if (!searchParameters.ContainsKey("site")) searchParameters["site"] = this.currentLanguagePack.DefaultCollection;
  109. if (!searchParameters.ContainsKey("ie")) searchParameters["ie"] = "utf8";
  110. if (!searchParameters.ContainsKey("oe")) searchParameters["oe"] = "utf8";
  111. if (!searchParameters.ContainsKey("filter")) searchParameters["filter"] = "p"; // Else GSA sees all results from Kennisplein as the same
  112. if (searchParameters.ContainsKey("as_q")) searchParameters["dnavs"] = searchParameters["as_q"];
  113. // Turn advanced panel off
  114. if (searchParameters.ContainsKey("ShowAdvancedPanel")) searchParameters.Remove("ShowAdvancedPanel");
  115. var keys = new List<string>(searchParameters.Keys);
  116. foreach (var key in keys)
  117. {
  118. searchParameters[key] = DecodeUnicodeChars(searchParameters[key], true);
  119. }
  120. // Strip periods (.) from partialfields. Fixes searching for initials in author field, e.g. 'A.B. Fielding' becomes 'AB Fielding'.
  121. if (searchParameters.ContainsKey("partialfields"))
  122. {
  123. searchParameters["partialfields"] = searchParameters["partialfields"].Replace("%2E", String.Empty);
  124. }
  125. if (!searchParameters.ContainsKey("as_q"))
  126. {
  127. searchParameters.Add("as_q", "site:nl");
  128. }
  129. if (searchParameters.ContainsKey("as_q") && searchParameters["as_q"] == string.Empty)
  130. {
  131. searchParameters["as_q"] = "site:nl";
  132. }
  133. if (!searchParameters.ContainsKey("rc"))
  134. {
  135. //Always get actual result count instead of estimated
  136. searchParameters.Add("rc", "1");
  137. }
  138. this.GetResults(this.currentLanguagePack.GSAUrl + "?" + DictionaryToQuerystring(searchParameters));
  139. }
  140. //Set GSA Alerts Script
  141. int positionSearch = this.currentLanguagePack.GSAUrl.IndexOf("search");
  142. string serverAdres = this.currentLanguagePack.GSAUrl.Remove(positionSearch, 6);
  143. AlertJSLiteral.Text = "<script >function getHomeUrl() {return location.href = \"" + serverAdres + "ealerts?shu=\" + escape(document.location.href);}</script>";
  144. this.MyAlertsTitleLiteral.Text = this.currentLanguagePack.GSAAlertsText;
  145. this.GSAHelpLiteral.Text = "<img src=\"/App_Themes/1Logo/images/infoicon_small.jpg\" class=\"GSAInfo\" title='<div class=\"GSAAlertsInfo\">" +
  146. this.currentLanguagePack.GSAAlertsInfo +
  147. "</div>' />";
  148. }
  149. private static bool ContainsGSAQuery(Dictionary<string, string> searchParameters)
  150. {
  151. return searchParameters != null
  152. && !(searchParameters.Count == 2 && searchParameters.ContainsKey("AdvancedSearch") && searchParameters.ContainsKey("ShowAdvancedPanel"))
  153. && !(searchParameters.Count == 1 && searchParameters.ContainsKey("AdvancedSearch"))
  154. && !(searchParameters.Count == 0);
  155. }
  156. private static Dictionary<string, string> GetSearchParameters(HttpRequest currentRequest)
  157. {
  158. //var searchParameters = new Dictionary<string, string>();
  159. var searchParameters = QuerystringToDictionary(currentRequest);
  160. if (searchParameters == null) searchParameters = new Dictionary<string, string>();
  161. // Three possibilities: either 'SearchTerm' or Google-like params ('q', etc) in querystring, or a form post.
  162. if (!String.IsNullOrEmpty(currentRequest.QueryString["SearchTerm"]))
  163. {
  164. //searchParameters["q"] = HttpUtility.UrlEncode(currentRequest.QueryString["SearchTerm"]);
  165. searchParameters["q"] = currentRequest.QueryString["SearchTerm"];
  166. searchParameters.Remove("SearchTerm");
  167. }
  168. //else if (!string.IsNullOrEmpty(currentRequest.QueryString.ToString()))
  169. //{
  170. //var querystring = currentRequest.QueryString.ToString();
  171. // For some reason '+' is used instead of '%20'. Manually decoding them here as they don't get decoded like the rest.
  172. //querystring = querystring.Replace('+', ' ');
  173. //searchParameters = QuerystringToDictionary(querystring);
  174. // searchParameters = QuerystringToDictionary(currentRequest);
  175. //}
  176. else if (!string.IsNullOrEmpty(currentRequest.Form["SearchTerm"]))
  177. {
  178. //searchParameters["q"] = HttpUtility.UrlEncode(currentRequest.Form["SearchTerm"].ToString());
  179. searchParameters["q"] = currentRequest.Form["SearchTerm"].ToString();
  180. }
  181. var keys = new List<string>(searchParameters.Keys);
  182. foreach (var key in keys)
  183. {
  184. searchParameters[key] = DecodeUnicodeChars(searchParameters[key], true);
  185. }
  186. return searchParameters;
  187. }
  188. //private string BuildSearchTerm(Dictionary<string, string> searchParameters)
  189. //{
  190. // var terms = new List<string>();
  191. // // 'All words'
  192. // if (searchParameters.ContainsKey("q") && !String.IsNullOrEmpty(searchParameters["q"])) terms.Add(searchParameters["q"]);
  193. // // 'Any words'
  194. // if (searchParameters.ContainsKey("as_oq") && !String.IsNullOrEmpty(searchParameters["as_oq"]))
  195. // {
  196. // terms.Add(String.Join(" OR ", searchParameters["as_oq"].Split(' ')));
  197. // }
  198. // // 'Exact phrase'
  199. // if (searchParameters.ContainsKey("as_epq") && !String.IsNullOrEmpty(searchParameters["as_epq"]))
  200. // {
  201. // terms.Add("\"" + searchParameters["as_epq"] + "\"");
  202. // }
  203. // // 'Without words'
  204. // if (searchParameters.ContainsKey("as_eq") && !String.IsNullOrEmpty(searchParameters["as_eq"]))
  205. // {
  206. // var without = searchParameters["as_eq"].Split(' ');
  207. // terms.Add(String.Join(" ", without.Select(term => "-" + term).ToArray()));
  208. // }
  209. // //for (var i = 0; i < terms.Count; i++)
  210. // //{
  211. // // terms[i] = HttpUtility.UrlDecode(terms[i]);
  212. // //}
  213. // return String.Join(" ", terms.ToArray());
  214. //}
  215. private void InitializeAdvancedSearchControls(Dictionary<string, string> searchParameters)
  216. {
  217. // Initialize 'Source' dropdown list
  218. if (FilterBySource.Items.Count == 0)
  219. {
  220. //FilterBySource.Items.Add(new ListItem("Alle resultaten", "default_collection"));
  221. //var defaultSource = new ListItem("Alle resultaten", String.Empty);
  222. var defaultSource = new ListItem(currentLanguagePack.FilterBySourceDefaultValue, String.Empty);
  223. FilterBySource.Items.Add(defaultSource);
  224. defaultSource.Selected = true;
  225. // Collections string format example: 'IenM:staging-1ntra|Kennisplein:Kennisplein'
  226. //var collections = new Dictionary<string, string>();
  227. if (!String.IsNullOrEmpty(this.currentLanguagePack.Collections))
  228. {
  229. var pairs = this.currentLanguagePack.Collections.Split('|');
  230. foreach (var pair in pairs)
  231. {
  232. var col = pair.Split(':');
  233. FilterBySource.Items.Add(new ListItem(col[0], col[1]));
  234. }
  235. }
  236. if (FilterBySource.Items.Count <= 2)
  237. {
  238. //Only have 1 collection no need to show the filter by collection
  239. FilterBySourcePanel.Visible = false;
  240. }
  241. }
  242. //if (FilterByLanguage.Items.Count == 0)
  243. //{
  244. // foreach (var kvp in languageCodesToPrettyName)
  245. // {
  246. // FilterByLanguage.Items.Add(new ListItem(kvp.Value, kvp.Key));
  247. // }
  248. //}
  249. if (FilterByFiletype.Items.Count == 0)
  250. {
  251. foreach (var kvp in filetypes)
  252. {
  253. FilterByFiletype.Items.Add(new ListItem(kvp.Key, kvp.Value));
  254. }
  255. }
  256. FillAdvancedSearchInputs(searchParameters);
  257. }
  258. private void FillAdvancedSearchInputs(Dictionary<string, string> searchParameters)
  259. {
  260. // 'All words'
  261. if (searchParameters.ContainsKey("q") && !String.IsNullOrEmpty(searchParameters["q"]))
  262. {
  263. SearchTermAll.Value = searchParameters["q"];
  264. }
  265. // 'Any words'
  266. if (searchParameters.ContainsKey("as_oq") && !String.IsNullOrEmpty(searchParameters["as_oq"]))
  267. {
  268. var orTerms = searchParameters["as_oq"].Split(' ');
  269. for (int i = 0; i < orTerms.Length; i++)
  270. {
  271. if (i == 0) SearchTermAny1.Value = orTerms[i];
  272. if (i == 1) SearchTermAny2.Value = orTerms[i];
  273. if (i == 2) SearchTermAny3.Value = orTerms[i];
  274. }
  275. }
  276. // 'Exact phrase'
  277. if (searchParameters.ContainsKey("as_epq") && !String.IsNullOrEmpty(searchParameters["as_epq"]))
  278. {
  279. SearchTermPhrase.Value = searchParameters["as_epq"];
  280. }
  281. // 'Without words'
  282. if (searchParameters.ContainsKey("as_eq") && !String.IsNullOrEmpty(searchParameters["as_eq"]))
  283. {
  284. SearchTermWithout.Value = searchParameters["as_eq"];
  285. }
  286. // Source
  287. if (searchParameters.ContainsKey("site") && !String.IsNullOrEmpty(searchParameters["site"]))
  288. {
  289. foreach (ListItem sourceItem in FilterBySource.Items)
  290. {
  291. if (String.Equals(searchParameters["site"], sourceItem.Value, StringComparison.OrdinalIgnoreCase))
  292. {
  293. sourceItem.Selected = true;
  294. break;
  295. }
  296. }
  297. }
  298. if (searchParameters.ContainsKey("partialfields") && !String.IsNullOrEmpty(searchParameters["partialfields"]))
  299. {
  300. var partialFields = searchParameters["partialfields"];
  301. // Author
  302. List<string> authorParts = new List<string>();
  303. var authorRegex = new Regex(@"author:([^\.\|\)]+)", RegexOptions.IgnoreCase);
  304. foreach (Match m in authorRegex.Matches(searchParameters["partialfields"]))
  305. {
  306. if (m != null && m.Groups != null && m.Groups.Count >= 2) authorParts.Add(m.Groups[1].Value);
  307. }
  308. var author = String.Join(" ", authorParts.ToArray());
  309. author = author.Replace("%2E", ".");
  310. if (!String.IsNullOrEmpty(author)) FilterByAuthor.Value = author;
  311. // Language
  312. //var languagePattern = new Regex(@"dc%3Alanguage:([a-z]+)", RegexOptions.IgnoreCase);
  313. //var selectedLanguages = new List<string>();
  314. //foreach (Match m in languagePattern.Matches(partialFields))
  315. //{
  316. // if (m != null && m.Groups != null && m.Groups.Count >= 2) selectedLanguages.Add(m.Groups[1].Value);
  317. //}
  318. //foreach (ListItem languageItem in FilterByLanguage.Items)
  319. //{
  320. // languageItem.Selected = selectedLanguages.Contains(languageItem.Value);
  321. //}
  322. }
  323. if (searchParameters.ContainsKey("as_q") && !String.IsNullOrEmpty(searchParameters["as_q"]))
  324. {
  325. var as_qParameters = SplitAs_qParametersString(searchParameters["as_q"]);
  326. // Filetype
  327. foreach (ListItem filetypeItem in FilterByFiletype.Items)
  328. {
  329. if (!String.IsNullOrEmpty(filetypeItem.Value))
  330. {
  331. //filetypeItem.Selected = as_qParameters.Any(p => p.Contains("filetype:" + filetypeItem.Value.Split(',')[0], StringComparison.OrdinalIgnoreCase));
  332. filetypeItem.Selected = as_qParameters.Any(p => p.Contains("ext:" + filetypeItem.Value.Split(';')[0], StringComparison.OrdinalIgnoreCase));
  333. }
  334. }
  335. // Dates
  336. //var dateParam = as_qParameters.Find(p => p.Contains("daterange:", StringComparison.OrdinalIgnoreCase));
  337. var dateParam = as_qParameters.Find(p => p.Contains("inmeta:dc%3Adate:", StringComparison.OrdinalIgnoreCase));
  338. if (!String.IsNullOrEmpty(dateParam))
  339. {
  340. //var datesRegex = new Regex(@"daterange:(\d{4}-\d{1,2}-\d{1,2})?\.\.(\d{4}-\d{1,2}-\d{1,2})?", RegexOptions.IgnoreCase);
  341. var datesRegex = new Regex(@"inmeta:dc%3Adate:(\d{4}-\d{1,2}-\d{1,2})?\.\.(\d{4}-\d{1,2}-\d{1,2})?", RegexOptions.IgnoreCase);
  342. var match = datesRegex.Match(dateParam);
  343. if (match != null && match.Groups != null && match.Groups.Count >= 2)
  344. {
  345. SearchDateFrom.Value = ReverseDateString(match.Groups[1].Value);
  346. SearchDateTo.Value = ReverseDateString(match.Groups[2].Value);
  347. }
  348. }
  349. }
  350. }
  351. private string BuildResultString(Dictionary<string, string> searchParameters)
  352. {
  353. var descriptions = new List<string>();
  354. // 'All words'
  355. if (searchParameters.ContainsKey("q") && !String.IsNullOrEmpty(searchParameters["q"]))
  356. descriptions.Add(String.Format(currentLanguagePack.ResultDescriptionAllWords, searchParameters["q"]));
  357. // 'Any words'
  358. if (searchParameters.ContainsKey("as_oq") && !String.IsNullOrEmpty(searchParameters["as_oq"]))
  359. {
  360. string textValue = string.Empty;
  361. string[] splitValues = searchParameters["as_oq"].Split();
  362. for (int i = 0; i < splitValues.Length; i++)
  363. {
  364. textValue += "'" + splitValues[i] + "'";
  365. if (i < splitValues.Length - 1)
  366. {
  367. textValue += " " + currentLanguagePack.AdvancedControlOR + " ";
  368. }
  369. }
  370. descriptions.Add(String.Format(currentLanguagePack.ResultDescriptionAnyWords, textValue));
  371. }
  372. // 'Exact phrase'
  373. if (searchParameters.ContainsKey("as_epq") && !String.IsNullOrEmpty(searchParameters["as_epq"]))
  374. descriptions.Add(String.Format(currentLanguagePack.ResultDescriptionExactPhrase, searchParameters["as_epq"]));
  375. // 'Without words'
  376. if (searchParameters.ContainsKey("as_eq") && !String.IsNullOrEmpty(searchParameters["as_eq"]))
  377. descriptions.Add(String.Format(currentLanguagePack.ResultDescriptionWithoutWords, searchParameters["as_eq"]));
  378. // Source
  379. if (searchParameters.ContainsKey("site") && !String.IsNullOrEmpty(searchParameters["site"]))
  380. {
  381. var siteListItem = FilterBySource.Items.FindByValue(searchParameters["site"]);
  382. if (siteListItem != null && siteListItem != FilterBySource.Items[0])
  383. descriptions.Add(String.Format(currentLanguagePack.ResultDescriptionSourceFilter, siteListItem.Text));
  384. }
  385. if (searchParameters.ContainsKey("partialfields") && !String.IsNullOrEmpty(searchParameters["partialfields"]))
  386. {
  387. // Author
  388. List<string> authorParts = new List<string>();
  389. var authorRegex = new Regex(@"author:([^\.\|\)]+)", RegexOptions.IgnoreCase);
  390. foreach (Match m in authorRegex.Matches(searchParameters["partialfields"]))
  391. {
  392. if (m != null && m.Groups != null && m.Groups.Count >= 2) authorParts.Add(m.Groups[1].Value);
  393. }
  394. var author = String.Join(" ", authorParts.ToArray());
  395. author = author.Replace("%2E", ".");
  396. if (!String.IsNullOrEmpty(author)) descriptions.Add(String.Format(currentLanguagePack.ResultDescriptionByAuthor, author));
  397. // Language
  398. //var selectedLanguages = new List<string>();
  399. //var languageRegex = new Regex(@"dc%3Alanguage:([a-z]+)", RegexOptions.IgnoreCase);
  400. //foreach (Match matchLang in languageRegex.Matches(searchParameters["partialfields"]))
  401. //{
  402. // if (matchLang != null && matchLang.Groups != null && matchLang.Groups.Count >= 2)
  403. // {
  404. // var language = matchLang.Groups[1].Value;
  405. // if (!String.IsNullOrEmpty(language)) selectedLanguages.Add(LanguageCodesToPrettyText(language));
  406. // }
  407. //}
  408. //if (selectedLanguages.Count > 0)
  409. //{
  410. // var langText = String.Join(" of ", selectedLanguages.ToArray());
  411. // descriptions.Add(String.Format(currentLanguagePack.ResultDescriptionLanguage, langText));
  412. //}
  413. }
  414. // Filetype / extensions
  415. if (searchParameters.ContainsKey("as_q") && !String.IsNullOrEmpty(searchParameters["as_q"]))
  416. {
  417. var selectedFiletypes = new List<string>();
  418. var extensionRegex = new Regex(@"ext:([a-z]+)", RegexOptions.IgnoreCase);
  419. foreach (Match matchExt in extensionRegex.Matches(searchParameters["as_q"]))
  420. {
  421. if (matchExt != null && matchExt.Groups != null && matchExt.Groups.Count >= 2)
  422. {
  423. var ext = matchExt.Groups[1].Value;
  424. if (!String.IsNullOrEmpty(ext))
  425. {
  426. var filetype = filetypes.FirstOrDefault(kvp => kvp.Value.Contains(ext));
  427. if (filetype.Key != null) selectedFiletypes.Add(filetype.Key);
  428. }
  429. }
  430. }
  431. if (selectedFiletypes.Count > 0)
  432. {
  433. selectedFiletypes = selectedFiletypes.Distinct().ToList();
  434. var filetypeText = String.Join(" of ", selectedFiletypes.ToArray());
  435. descriptions.Add(String.Format(currentLanguagePack.ResultDescriptionFiletype, filetypeText));
  436. }
  437. }
  438. // Build the description with comma's and a conjunction ('and') between the last two.
  439. if (descriptions.Count > 0)
  440. {
  441. string result = currentLanguagePack.ResultDescriptionStart + " ";
  442. if (descriptions.Count > 1)
  443. {
  444. result += String.Join(", ", descriptions.GetRange(0, descriptions.Count - 1).ToArray());
  445. result += currentLanguagePack.ResultDescriptionConjunction + descriptions.Last();
  446. }
  447. else
  448. {
  449. result += descriptions[0];
  450. }
  451. result += ".";
  452. return result;
  453. }
  454. else
  455. {
  456. return String.Empty;
  457. }
  458. }
  459. public static List<string> SplitAs_qParametersString(string as_q)
  460. {
  461. if (!String.IsNullOrEmpty(as_q))
  462. {
  463. // The OR and AND are used with the 'filetype' parameter, so gotta keep them intact. Transform them here temporarily to avoid the '+' split below.
  464. as_q = as_q.Replace("+OR+", "_OR_").Replace("+AND+", "_AND_");
  465. var as_qParametersTemp = as_q.Split('+');
  466. var as_qParameters = new List<string>();
  467. foreach (var tempParam in as_qParametersTemp)
  468. {
  469. if (!String.IsNullOrEmpty(tempParam))
  470. {
  471. // Only separate terms that contain ':', else assume it was a second part of the previous term.
  472. // For example, when searching for 'inmeta:RootCategory=R6.6', the '.' in 'R6.6' will get replaced by a space because GSA can't handle periods.
  473. // It will become 'inmeta:RootCategory=R6+6'. Because we split on '+', that would give odd results. That's why we use ':' to check.
  474. if (tempParam.Contains(":"))
  475. {
  476. as_qParameters.Add(tempParam);
  477. }
  478. else
  479. {
  480. if (as_qParameters.Count > 0)
  481. as_qParameters[as_qParameters.Count - 1] += '+' + tempParam;
  482. else
  483. as_qParameters.Add(tempParam);
  484. }
  485. }
  486. }
  487. for (var i = 0; i < as_qParameters.Count; i++)
  488. {
  489. // Return OR and AND to original state
  490. as_qParameters[i] = as_qParameters[i].Replace("_OR_", "+OR+").Replace("_AND_", "+AND+");
  491. // MF: The GSA returns '=' encoded but '~' not. At the same time, it DOES require them both encoded when passing them to GSA. Fuck the GSA. And fuck their whole '+'/' '/'%20' thing too :P.
  492. as_qParameters[i] = as_qParameters[i].Replace("~", "%7E").Replace("+", "%20");
  493. }
  494. return as_qParameters.ToList();
  495. }
  496. return new List<string>();
  497. }
  498. #endregion
  499. #region Search Results & Facets
  500. private void GetResults(string QueryString)
  501. {
  502. XmlDocument xmlGoogleResults = new XmlDocument();
  503. var request = (HttpWebRequest)WebRequest.Create(QueryString);
  504. request.Headers.Add("Accept-Language", "nl");
  505. request.UseDefaultCredentials = true;
  506. string responseFromServer;
  507. using (var response = request.GetResponse())
  508. {
  509. using (var stream = new System.IO.StreamReader(response.GetResponseStream(), Encoding.UTF8))
  510. {
  511. responseFromServer = stream.ReadToEnd();
  512. }
  513. }
  514. xmlGoogleResults.LoadXml(responseFromServer);
  515. RenderFacets(xmlGoogleResults);
  516. //Set results xslt
  517. string xsltFileLocation = string.Empty;
  518. xsltFileLocation = HttpContext.Current.Server.MapPath(GOOGLE_RESULTS_XSLT_NL);
  519. //var searchresults = XMLTransformer.TransformXMLToXHTML(xmlGoogleResults, xsltFileLocation);
  520. var searchresults = XMLTransformer.TransformXMLToXHTML_RespectDisableOutputEscaping(xmlGoogleResults, xsltFileLocation);
  521. //this.SearchResults.Text = HttpUtility.HtmlDecode(searchresults);
  522. this.SearchResults.Text = searchresults;
  523. //Fix Google links to Categories
  524. this.SearchResults.Text = this.SearchResults.Text.Replace("%5C", "\\");
  525. }
  526. private void RenderFacets(XmlDocument xmlSearchResults)
  527. {
  528. this.FacetsHeaderLiteral.Text = String.Format("<div class=\"resultheader\">{0}</div>", currentLanguagePack.FacetsTitle);
  529. // Collections string format example: 'IenM:staging-1ntra|Kennisplein:Kennisplein'
  530. var collections = new Dictionary<string, string>();
  531. if (!String.IsNullOrEmpty(this.currentLanguagePack.Collections))
  532. {
  533. var pairs = this.currentLanguagePack.Collections.Split('|');
  534. foreach (var pair in pairs)
  535. {
  536. var col = pair.Split(':');
  537. collections.Add(col[0], col[1]);
  538. }
  539. }
  540. // 'as_q' parameter, split on '+'
  541. List<string> as_qParameters = new List<string>();
  542. if (xmlSearchResults.SelectSingleNode("/GSP/PARAM[@name='as_q']") != null)
  543. {
  544. as_qParameters = SplitAs_qParametersString(xmlSearchResults.SelectSingleNode("/GSP/PARAM[@name='as_q']").Attributes["original_value"].Value);
  545. }
  546. // Rest of the search url without the 'as_q' parameter
  547. var urlWithoutAs_q = CreateSearchUrl(xmlSearchResults, "as_q");
  548. var searchQuerystring = new SearchQuerystring();
  549. XmlNodeList searchParams = xmlSearchResults.SelectNodes("/GSP/PARAM");
  550. if (searchParams != null)
  551. {
  552. foreach (XmlNode param in searchParams)
  553. {
  554. string name = param.Attributes["name"].Value;
  555. if (name != "start" && name != "swrnum" && !name.Contains("metabased_") && name != "dnavs")
  556. {
  557. string value = param.Attributes["original_value"].Value;
  558. if (name == "as_q")
  559. searchQuerystring.SetParamAs_q(SplitAs_qParametersString(value));
  560. else
  561. searchQuerystring.SetParam(name, value);
  562. }
  563. }
  564. }
  565. // MF: Changed sitecollection facet to use new SearchQuerystring class, for better control over adding and removing params.
  566. // If it works it might be better to convert the other facets too, so they also use the SearchQuerystring class.
  567. //facets.Add(CreateSiteCollectionFacet(xmlSearchResults, collections));
  568. //If theres only one collection there's no point in being able to filter on the same collection
  569. if (collections.Count > 1)
  570. {
  571. facets.Add(CreateSiteCollectionFacet(searchQuerystring, collections));
  572. }
  573. facets.AddRange(CreateMetadataFacets(xmlSearchResults, as_qParameters, urlWithoutAs_q));
  574. facets.Add(CreateDateFacet(as_qParameters, urlWithoutAs_q));
  575. facets.Add(CreateFiletypeFacet(as_qParameters, urlWithoutAs_q));
  576. foreach (var facet in facets)
  577. {
  578. switch (facet.Name)
  579. {
  580. case "PageType":
  581. case "RootCategory":
  582. facetsIntranet.Add(facet);
  583. break;
  584. case "kp:kennistype":
  585. facetsKennisplein.Add(facet);
  586. break;
  587. default:
  588. facetsGeneral.Add(facet);
  589. break;
  590. }
  591. }
  592. var haveSearchResults = (xmlSearchResults.SelectNodes("/GSP/RES").Count > 0);
  593. if (haveSearchResults || facetsGeneral.Any(f => f.Values.Any(v => v.Selected)))
  594. Filters.Text = String.Format("<div class=\"facetBlock\"><h4>{0}</h4>{1}</div>", currentLanguagePack.FacetsGeneralTitle, RenderFacetsHtml(facetsGeneral, haveSearchResults));
  595. else
  596. Filters.Visible = false;
  597. var siteCollectionFacet = facets.Find(f => f.Name == "SiteCollection");
  598. //Now Using lang pack values for Pretty names
  599. //var intranetIenMSelected = (siteCollectionFacet != null && siteCollectionFacet.Values.Any(v => v.PrettyLabel == "Intranet IenM" && v.Selected));
  600. //var kennispleinSelected = (siteCollectionFacet != null && siteCollectionFacet.Values.Any(v => v.PrettyLabel == "Kennisplein" && v.Selected));
  601. var intranetIenMSelected = (siteCollectionFacet != null && siteCollectionFacet.Values.Any(v => v.PrettyLabel == currentLanguagePack.FacetsIntranetTitle && v.Selected));
  602. var kennispleinSelected = (siteCollectionFacet != null && siteCollectionFacet.Values.Any(v => v.PrettyLabel == currentLanguagePack.FacetsKennispleinTitle && v.Selected));
  603. if (facetsIntranet.Count > 0 && intranetIenMSelected && (haveSearchResults || facetsIntranet.Any(f => f.Values.Any(v => v.Selected))))
  604. FiltersIntranet.Text = String.Format("<div class=\"facetBlock\"><h4>{0}</h4>{1}</div>", currentLanguagePack.FacetsIntranetTitle, RenderFacetsHtml(facetsIntranet, haveSearchResults));
  605. else
  606. IenMWrapper.Visible = false;
  607. if (facetsKennisplein.Count > 0 && kennispleinSelected && (haveSearchResults || facetsKennisplein.Any(f => f.Values.Any(v => v.Selected))))
  608. FiltersKennisplein.Text = String.Format("<div class=\"facetBlock\"><h4>{0}</h4>{1}</div>", currentLanguagePack.FacetsKennispleinTitle, RenderFacetsHtml(facetsKennisplein, haveSearchResults));
  609. else
  610. KennispleinWrapper.Visible = false;
  611. if (Filters.Visible == false && FiltersIntranet.Visible == false && FiltersKennisplein.Visible == false)
  612. FacetColumn.Style.Add("visibility", "hidden");
  613. }
  614. private static string CreateSearchUrl(XmlDocument xdoc, params string[] skipParameters)
  615. {
  616. XmlNodeList searchParams = xdoc.SelectNodes("/GSP/PARAM");
  617. StringBuilder link = new StringBuilder();
  618. if (searchParams != null)
  619. {
  620. foreach (XmlNode param in searchParams)
  621. {
  622. string name = param.Attributes["name"].Value;
  623. if (name != "start" && name != "swrnum" && !name.Contains("metabased_") && name != "dnavs" && !skipParameters.Contains(name))
  624. {
  625. string value = param.Attributes["original_value"].Value;
  626. link.Append(string.Format("{0}={1}", name, value));
  627. link.Append("&amp;");
  628. }
  629. }
  630. }
  631. return link.ToString();
  632. }
  633. //private Facet CreateSiteCollectionFacet(XmlDocument xmlSearchResults, Dictionary<string, string> collections)
  634. private Facet CreateSiteCollectionFacet(SearchQuerystring searchQuerystring, Dictionary<string, string> collections)
  635. {
  636. // 'site' parameter
  637. //string siteParameter = null;
  638. //if (xmlSearchResults.SelectSingleNode("/GSP/PARAM[@name='site']") != null)
  639. // siteParameter = xmlSearchResults.SelectSingleNode("/GSP/PARAM[@name='site']").Attributes["value"].Value;
  640. // Rest of the search url without the 'as_q' parameter
  641. //var urlWithoutSiteCollection = CreateSearchUrl(xmlSearchResults, "site");
  642. //var urlWithoutSiteCollection = CreateSearchUrl(xmlSearchResults, "site");
  643. // Create facet
  644. var siteFacet = new Facet("SiteCollection", currentLanguagePack.FacetSourceHeader, null);
  645. siteFacet.Values = new List<FacetValue>();
  646. foreach (var collection in collections)
  647. {
  648. siteFacet.Values.Add(new FacetValue(collection.Key, collection.Value));
  649. }
  650. // Any selected values?
  651. var site = searchQuerystring.GetParamValue("site");
  652. bool facetSelected = false;
  653. foreach (var value in siteFacet.Values)
  654. {
  655. value.Selected = String.Equals(site, value.Value, StringComparison.OrdinalIgnoreCase);
  656. if (value.Selected)
  657. {
  658. facetSelected = true;
  659. break;
  660. }
  661. }
  662. // Set urls for toggling facet values on / off
  663. var localQuerystring = searchQuerystring.Copy();
  664. if (facetSelected)
  665. {
  666. siteFacet.Values.RemoveAll(v => !v.Selected);
  667. localQuerystring.RemoveParam("site");
  668. // Hardcoded linked facets for now... also matched on their PrettyLabel which is not elegant either.
  669. // TODO: add to LanguagePack or Setting or something
  670. // Now using lang pack values for pretty labels
  671. //if (siteFacet.Values[0].PrettyLabel == "Intranet IenM")
  672. if (siteFacet.Values[0].PrettyLabel == currentLanguagePack.FacetsIntranetTitle)
  673. {
  674. localQuerystring.RemoveAs_qParam("inmeta:PageType");
  675. localQuerystring.RemoveAs_qParam("inmeta:RootCategory");
  676. }
  677. //else if (siteFacet.Values[0].PrettyLabel == "Kennisplein")
  678. else if (siteFacet.Values[0].PrettyLabel == currentLanguagePack.FacetsKennispleinTitle)
  679. {
  680. localQuerystring.RemoveAs_qParam("inmeta:kp%253Akennistype");
  681. }
  682. foreach (var value in siteFacet.Values)
  683. {
  684. value.Url = "?" + localQuerystring.ToString();
  685. }
  686. }
  687. else
  688. {
  689. foreach (var value in siteFacet.Values)
  690. {
  691. localQuerystring.SetParam("site", value.Value);
  692. value.Url = String.Format("?" + localQuerystring.ToString());
  693. }
  694. }
  695. return siteFacet;
  696. }
  697. private List<Facet> CreateMetadataFacets(XmlDocument xmlSearchResults, List<string> as_qParameters, string urlWithoutAs_q)
  698. {
  699. var facets = new List<Facet>();
  700. var metadataFacetNodes = xmlSearchResults.SelectNodes("/GSP/RES/PARM/PMT");
  701. foreach (XmlNode metadataFacetNode in metadataFacetNodes)
  702. {
  703. // Create facet (example: 'TargetGroup')
  704. var facet = new Facet()
  705. {
  706. Name = metadataFacetNode.Attributes["NM"].Value,
  707. PrettyLabel = metadataFacetNode.Attributes["DN"].Value,
  708. QueryPrefix = "inmeta",
  709. Values = new List<FacetValue>()
  710. };
  711. if (facet.Name == "dc:language")
  712. {
  713. facet = CreateLanguageFacet(xmlSearchResults, metadataFacetNode, facet);
  714. }
  715. else
  716. {
  717. // Add possible values (examples: 'SSO', 'IVW', 'VenW', ..)
  718. foreach (XmlNode facetValueNode in metadataFacetNode.SelectNodes("PV"))
  719. {
  720. var facetValue = new FacetValue()
  721. {
  722. Value = facetValueNode.Attributes["V"].Value,
  723. PrettyLabel = facetValueNode.Attributes["V"].Value,
  724. Count = Int32.Parse(facetValueNode.Attributes["C"].Value)
  725. };
  726. //if (facet.Name == "dc:language") facetValue.PrettyLabel = LanguageCodesToPrettyText(facetValue.PrettyLabel);
  727. string as_qItem = String.Empty;
  728. // If queryprefix contains column it needs to be double-escaped. Whyyyyyy...
  729. if (facet.Name.Contains(":"))
  730. {
  731. as_qItem = facet.QueryPrefix + ":" + CustomUrlEncode(CustomUrlEncode(facet.Name) + "=" + CustomUrlEncode(facetValue.Value));
  732. }
  733. else
  734. {
  735. // Periods (.) also require some custom businesslogic.
  736. if (facetValue.Value.Contains('.'))
  737. {
  738. as_qItem = facet.QueryPrefix + ":" + CustomUrlEncode(facet.Name + "~" + CustomUrlEncode(facetValue.Value).Replace(".", " "));
  739. }
  740. else
  741. {
  742. as_qItem = facet.QueryPrefix + ":" + CustomUrlEncode(facet.Name + "=" + CustomUrlEncode(facetValue.Value));
  743. }
  744. }
  745. as_qItem = DecodeUnicodeChars(as_qItem, false);
  746. // Currently selected?
  747. facetValue.Selected = as_qParameters.Contains(as_qItem, StringComparer.OrdinalIgnoreCase);
  748. // Search url for toggling this filter on/off
  749. var localAs_qParameters = as_qParameters.ToList();
  750. if (facetValue.Selected)
  751. localAs_qParameters.RemoveAll(p => String.Equals(p, as_qItem, StringComparison.OrdinalIgnoreCase));
  752. else
  753. localAs_qParameters.Add(as_qItem);
  754. facetValue.Url = String.Format("?{0}as_q={1}", urlWithoutAs_q, DecodeUnicodeChars(String.Join(" ", localAs_qParameters.ToArray()), true));
  755. facet.Values.Add(facetValue);
  756. }
  757. }
  758. facets.Add(facet);
  759. }
  760. return facets;
  761. }
  762. private Facet CreateLanguageFacet(XmlDocument xmlSearchResults, XmlNode metadataFacetNode, Facet facet)
  763. {
  764. // Add the possible languagefacet values & their counts. Split values like 'en fr' into 'en' and 'fr'.
  765. foreach (XmlNode facetValueNode in metadataFacetNode.SelectNodes("PV"))
  766. {
  767. // Examples: 'en', 'fr', 'nl en'
  768. var value = facetValueNode.Attributes["V"].Value;
  769. if (value != null) value = value.Trim().ToLower();
  770. var languageCodes = value.Split(' ');
  771. foreach (var languageCode in languageCodes)
  772. {
  773. var count = Int32.Parse(facetValueNode.Attributes["C"].Value);
  774. var existingValue = facet.Values.Find(fv => fv.Value == languageCode);
  775. if (existingValue != null) // If already exists, just add the count.
  776. {
  777. existingValue.Count += count;
  778. }
  779. else // Else add a new language.
  780. {
  781. facet.Values.Add(new FacetValue()
  782. {
  783. Value = languageCode,
  784. PrettyLabel = LanguageCodesToPrettyText(languageCode),
  785. Count = count
  786. });
  787. }
  788. }
  789. }
  790. // Get current partialfields param and create a url without it.
  791. string partialfields = String.Empty;
  792. if (xmlSearchResults.SelectSingleNode("/GSP/PARAM[@name='partialfields']") != null)
  793. partialfields = xmlSearchResults.SelectSingleNode("/GSP/PARAM[@name='partialfields']").Attributes["original_value"].Value;
  794. var urlWithoutPartialFields = CreateSearchUrl(xmlSearchResults, "partialfields");
  795. // Extract the list of currently selected languages based on the partialfields param.
  796. var languageContainerPattern = new Regex(@"\((dc%253Alanguage.+?)\)\.?", RegexOptions.IgnoreCase);
  797. var languageContainerContents = String.Empty;
  798. var languagePattern = new Regex(@"dc%253Alanguage:([a-z]+)", RegexOptions.IgnoreCase);
  799. var selectedLanguages = new List<string>();
  800. var containerMatch = languageContainerPattern.Match(partialfields);
  801. if (containerMatch.Success)
  802. {
  803. languageContainerContents = containerMatch.Groups[1].Value;
  804. foreach (Match languageMatch in languagePattern.Matches(containerMatch.Value))
  805. {
  806. if (languageMatch != null && languageMatch.Groups.Count >= 2)
  807. {
  808. var language = languageMatch.Groups[1].Value;
  809. if (!String.IsNullOrEmpty(language))
  810. selectedLanguages.Add(language.Trim().ToLower());
  811. }
  812. }
  813. }
  814. selectedLanguages = selectedLanguages.Distinct().ToList();
  815. // Set Selected property for each language (facet value)
  816. foreach (var value in facet.Values)
  817. {
  818. value.Selected = selectedLanguages.Contains(value.Value);
  819. }
  820. // If any languages are selected, remove all non-selected languages.
  821. // This is to prevent odd looking (though still technically correct) filters when the search results contain pages that have multiple languages.
  822. if (selectedLanguages.Count > 0)
  823. {
  824. facet.Values.RemoveAll(fv => !fv.Selected);
  825. }
  826. // Go through each languagefacet value again and set the Url property (for toggling this facet value on/off).
  827. foreach (var value in facet.Values)
  828. {
  829. string newPartialFields;
  830. if (value.Selected)
  831. {
  832. var newSelectedLanguages = selectedLanguages.Where(lang => lang != value.Value);
  833. if (newSelectedLanguages.Count() > 0)
  834. {
  835. // Deselect this language, other languages still selected (example: 'en, fr' -> 'en')
  836. var newLangFilters = String.Join("|", newSelectedLanguages.Select(lang => "dc%253Alanguage:" + lang).ToArray());
  837. newPartialFields = partialfields.Replace(languageContainerContents, newLangFilters);
  838. }
  839. else
  840. {
  841. // Deselect this language, no other languages selected (example: 'en' -> '')
  842. newPartialFields = partialfields.Replace(containerMatch.Value, String.Empty);
  843. }
  844. }
  845. else
  846. {
  847. var newSelectedLanguages = selectedLanguages.ToList();
  848. newSelectedLanguages.Add(value.Value);
  849. if (newSelectedLanguages.Count() > 1)
  850. {
  851. // Select this language, other languages also selected (example: 'fr' -> 'fr, en')
  852. var newLangFilters = String.Join("|", newSelectedLanguages.Select(lang => "dc%253Alanguage:" + lang).ToArray());
  853. newPartialFields = partialfields.Replace(languageContainerContents, newLangFilters);
  854. }
  855. else
  856. {
  857. // Select this language, no other languages selected (example: '' -> 'en')
  858. newPartialFields = "(dc%253Alanguage:" + value.Value + ")";
  859. if (!String.IsNullOrEmpty(partialfields)) newPartialFields = partialfields + "." + newPartialFields;
  860. }
  861. }
  862. if (!String.IsNullOrEmpty(newPartialFields))
  863. value.Url = String.Format("?{0}partialfields={1}", urlWithoutPartialFields, DecodeUnicodeChars(newPartialFields, true));
  864. else
  865. value.Url = "?" + urlWithoutPartialFields;
  866. }
  867. return facet;

Large files files are truncated, but you can click here to view the full file