public async Task <ActionResult> Search(string q = null, string date = null, string ministry = null, string sector = null, string city = null, string content = null, string language = null, DateTime?fromDate = null, DateTime?toDate = null, string page = null) { var filters = new Dictionary <string, string>(); if (!string.IsNullOrEmpty(date)) { filters.Add("Date", date); } if (ministry != null) { var ministries = await Repository.GetMinistriesAsync(); var ministryName = ministries.FirstOrDefault(m => m.Key == ministry)?.Name; filters.Add("Ministry", ministryName ?? ministry); } if (sector != null) { var sectors = await Repository.GetSectorsAsync(); var sectorName = sectors.FirstOrDefault(s => s.Key == sector)?.Name; filters.Add("Sector", sectorName ?? sector); } if (!string.IsNullOrEmpty(city)) { filters.Add("City", city); } if (content != null) { filters.Add("Content", content); } if (!string.IsNullOrEmpty(language)) { filters.Add("Language", language); } var queryModel = new SearchViewModel.SearchQuery(q, fromDate, toDate, filters); if (Properties.Settings.Default.NewsMediaHostUri != null) { ViewBag.ProxyUrl = Properties.Settings.Default.NewsMediaHostUri.ToString() + "embed/"; } else { ViewBag.ProxyUrl = new Uri("https://media.news.gov.bc.ca/embed/").ToString(); } return(View("SearchView", await Search(queryModel, page))); }
protected async Task <SearchViewModel> Search(SearchViewModel.SearchQuery query, string page = null) { var model = new SearchViewModel(); int ResultsPerPage = 10; model.ResultsPerPage = ResultsPerPage; await LoadAsync(model); #if !DEBUG try { #endif model.Title = "Search"; bool isTranslationsSearch = string.Equals(query.Text, "translation", StringComparison.OrdinalIgnoreCase) || string.Equals(query.Text, "translations", StringComparison.OrdinalIgnoreCase); string requestPath = Properties.Settings.Default.AzureSearchUri.ToString(); if (!string.IsNullOrEmpty(query.Text)) { if (!isTranslationsSearch) { requestPath += string.Format("&{0}={1}", "search", UrlEncoder.Default.Encode(query.Text)); } requestPath += string.Format("&{0}={1}", "searchMode", "all"); } //if (!string.IsNullOrEmpty(query.DateRange)) //requestPath += string.Format("+{0}:{1}", "daterange", query.DateRange); requestPath += string.Format("&{0}={1}", "$top", Convert.ToString(ResultsPerPage)); requestPath += string.Format("&{0}={1}", "$select", "key,releaseType,documentsHeadline,documentsSubheadline,summary,publishDateTime,hasMediaAssets,assetUrl,translations,hasTranslations, socialMediaHeadline"); requestPath += string.Format("&{0}={1}", "$orderby", "publishDateTime desc"); var facets = new Dictionary <string, string> { { "languages", "Language" }, { "collection", "Date" }, { "ministries", "Ministry" }, { "sectors", "Sector" }, { "location", "City" }, { "releaseType", "Content" } }; bool useCustomRange = query.UseCustomRange(); foreach (var facet in facets) { if (facet.Value == "Date" && useCustomRange) { continue; } if (query.Filters?.ContainsKey(facet.Value) != true) { requestPath += string.Format("&{0}={1}", "facet", facet.Key); } } var filters = new List <string>(); if (isTranslationsSearch) { filters.Add("hasTranslations eq true"); filters.Add("translations ne null"); filters.Add("translations ne ''"); } if (useCustomRange) { filters.Add("publishDateTime le " + query.ToDate.ToUniversalTime().AddDays(1).ToString("s") + "Z"); // include the selected day too filters.Add("publishDateTime ge " + query.FromDate.ToUniversalTime().ToString("s") + "Z"); } if (query.Filters != null) { foreach (var filter in query.Filters) { string facetKey = facets.SingleOrDefault(f => f.Value == filter.Key).Key; filters.Add(string.Format(facetKey.EndsWith('s') ? "{0}/any(t: t eq '{1}')" : "{0} eq '{1}'", facetKey, filter.Value.Replace("'", "''"))); } } if (filters.Count != 0) { requestPath += string.Format("&{0}={1}", "$filter", string.Join(" and ", filters)); } //This should match page meta data date format, which is now "yyyy-mm" //if (query.YearMonth != null) // requestPath += String.Format("&{0}={1}", "partialfields", "DC%252Edate%252Eissued:" + query.YearMonth); requestPath += string.Format("&{0}={1}", "$count", "true"); int skip = (int.Parse(page ?? "1") - 1) * ResultsPerPage; if (skip > 0) { requestPath += string.Format("&{0}={1}", "$skip", skip); } dynamic searchServiceResult = null; using (Profiler.StepStatic("Calling search.gov.bc.ca")) { System.Net.WebRequest request = System.Net.WebRequest.Create(requestPath); request.Headers.Add("api-key", Properties.Settings.Default.AzureSearchKey); using (System.Net.WebResponse response = await request.GetResponseAsync()) { using (System.IO.StreamReader reader = new System.IO.StreamReader(response.GetResponseStream())) { string res = reader.ReadToEnd(); searchServiceResult = JsonConvert.DeserializeObject <dynamic>(res); } } } model.Count = searchServiceResult["@odata.count"]; model.FirstResult = Math.Min(Math.Max(skip + 1, 1), (model.Count / ResultsPerPage) * ResultsPerPage + 1); model.LastResult = Math.Min(model.FirstResult + ResultsPerPage - 1, model.Count); model.Query = query; var searchFacets = searchServiceResult["@search.facets"]; if (searchFacets != null) { foreach (var facet in facets) // iterate in the order we asked for { var facetHits = new List <SearchViewModel.FacetHit>(); string filteredFacet; var searchFacet = searchFacets[facet.Key]; if (searchFacet != null) { foreach (var facetHit in searchFacet) { string facetHitValue = facetHit["value"]; if (string.IsNullOrEmpty(facetHitValue)) { continue; } facetHits.Add(new SearchViewModel.FacetHit { Value = facetHitValue, Count = facetHit["count"] }); } } else if (query.Filters != null && query.Filters.TryGetValue(facet.Value, out filteredFacet)) { facetHits.Add(new SearchViewModel.FacetHit { Value = filteredFacet, Count = model.Count }); } bool isDateCollection = facet.Key == "collection"; model.FacetResults.Add(facet.Value, isDateCollection ? facetHits.OrderByDescending(f => f.Value) : facetHits.OrderByDescending(f => f.Count)); } } if (searchServiceResult.value != null) { foreach (var result in searchServiceResult.value) { string key = result["key"]; string postKind = result["releaseType"]; postKind = postKind.EndsWith("y") ? postKind.Substring(0, postKind.Length - 1) + "ies" : postKind + "s"; IEnumerable <object> titles = result["documentsHeadline"]; IEnumerable <object> headlines = result["documentsSubheadline"]; string translations = result["translations"]; bool hasTranslations = result["hasTranslations"]; string assetUrl = result["assetUrl"]; var date = (DateTimeOffset)DateTimeOffset.Parse(Convert.ToString(result["publishDateTime"])); model.Results.Add(new SearchViewModel.Result() { Title = System.Net.WebUtility.HtmlDecode(titles.FirstOrDefault().ToString()), Headline = System.Net.WebUtility.HtmlDecode(headlines?.FirstOrDefault().ToString()), Uri = NewsroomExtensions.GetPostUri(postKind.ToLower(), key), Description = result["summary"], HasMediaAssets = result["hasMediaAssets"], HasTranslations = translations != null && hasTranslations, PublishDate = DateTime.Parse(date.FormatDateLong()), ThumbnailUri = NewsroomExtensions.GetThumbnailUri(assetUrl), AssetUrl = result["assetUrl"], SocialMediaHeadline = result["socialMediaHeadline"] }); } } model.LastPage = Math.Min(Convert.ToInt32(Math.Ceiling(model.Count / (decimal)ResultsPerPage)), 100); #if !DEBUG } catch { model.Success = false; //TODO: Report exception message } #endif return(model); }
protected async Task <SearchViewModel> Search(SearchViewModel.SearchQuery query, int first) { var model = new SearchViewModel(); int ResultsPerPage = 10; model.ResultsPerPage = ResultsPerPage; await LoadAsync(model); #if !DEBUG try { #endif model.Title = "Search"; //Google Search Protocol Reference - Request Format //http://www.google.com/support/enterprise/static/gsa/docs/admin/72/gsa_doc_set/xml_reference/request_format.html string requestPath = Properties.Settings.Default.GoogleSearchApplianceUri.ToString(); string searchText = ""; if (!string.IsNullOrEmpty(query.Text)) { searchText = query.Text; } else if (!string.IsNullOrEmpty(query.DateRange)) { searchText = "bc"; //Assume all stories have "bc" word in them. This is because daterange search by google appliance does not support daterange search without text query } requestPath += String.Format("&{0}={1}", "q", UrlEncoder.Default.Encode(searchText)); if (!string.IsNullOrEmpty(query.DateRange)) { requestPath += String.Format("+{0}:{1}", "daterange", query.DateRange); } requestPath += String.Format("&{0}={1}", "output", "xml_no_dtd"); requestPath += String.Format("&{0}={1}", "num", Convert.ToString(ResultsPerPage)); requestPath += String.Format("&{0}={1}", "requiredfields", "MBCTERMS%252EcontentType:News"); if (!string.IsNullOrEmpty(query.Sector)) { requestPath += String.Format(".{0}:{1}", "NEWSTERMS%252EsectorKeys", query.Sector); } if (!string.IsNullOrEmpty(query.Ministry)) { requestPath += String.Format(".{0}:{1}", "NEWSTERMS%252EministryKeys", query.Ministry); } if (!string.IsNullOrEmpty(query.NewsType)) { requestPath += String.Format(".{0}:{1}", "NEWSTERMS%252EcontentPath", query.NewsType); } //This should match page meta data date format, which is now "yyyy-mm" //if (query.YearMonth != null) // requestPath += String.Format("&{0}={1}", "partialfields", "DC%252Edate%252Eissued:" + query.YearMonth); requestPath += String.Format("&{0}={1}", "filter", "p"); requestPath += String.Format("&{0}={1}", "rc", 1); //requestPath += String.Format("&{0}={1}", "sitesearch", "news.gov.bc.ca"); requestPath += String.Format("&{0}={1}", "sort", "date:D:R:d1"); if (first > 1) { requestPath += String.Format("&{0}={1}", "start", first - 1); } System.Xml.Linq.XDocument xml; using (Profiler.StepStatic("Calling search.gov.bc.ca")) { System.Net.WebRequest request = System.Net.WebRequest.Create(requestPath); request.Proxy = null; using (System.Net.WebResponse response = await request.GetResponseAsync()) { using (System.IO.StreamReader reader = new System.IO.StreamReader(response.GetResponseStream())) xml = System.Xml.Linq.XDocument.Load(reader, System.Xml.Linq.LoadOptions.None); } } model.Count = xml.Element("GSP").Element("RES") == null ? 0 : Convert.ToInt32(xml.Element("GSP").Element("RES").Element("M").Value); model.FirstResult = Math.Min(Math.Max(first, 1), (model.Count / ResultsPerPage) * ResultsPerPage + 1); model.LastResult = Math.Min(model.FirstResult + ResultsPerPage - 1, model.Count); model.Query = query; if (!string.IsNullOrEmpty(query.Ministry)) { model.Ministry = (await Repository.GetMinistryAsync(query.Ministry)).Index as Ministry; } if (!string.IsNullOrEmpty(query.Sector)) { model.Sector = (await Repository.GetSectorAsync(query.Sector)).Index as Sector; } if (!string.IsNullOrEmpty(query.DateRange)) { var dates = query.DateRange.Replace("..", "+").Split('+'); if (dates.Count() == 2) { model.DateRangeText = string.Format("{0:MMMM d, yyyy} to {1:MMMM d, yyyy}", DateTime.Parse(dates[0]), DateTime.Parse(dates[1])); } } else { model.DateRangeText = string.Format("{0} to {1}", "March 12, 2011", "Present"); } var results = xml.Element("GSP").Element("RES"); if (results != null) { var result = results.Element("R"); while (result != null) { if (result.Name == "R") { string url = result.Element("U").Value; string title = result.Element("T") == null ? "[no title]" : result.Element("T").Value.Replace(" | BC Newsroom", "").Replace(" | BC Gov News", "").Replace(" | BC <b>...</b>", ""); string description = result.Element("S").Value.Replace("�", "").Replace("<br>", "<br />").Replace("<br />", " "); string size = result.Element("HAS").Element("C") == null ? "" : result.Element("HAS").Element("C").Attribute("SZ").Value; string localUrl = url.Replace("http://", "").Replace("https://", ""); Post post = null; //TODO: Use result["CRAWLDATE"] to set Date try { if (url.StartsWith("https://news.gov.bc.ca/")) { string[] urlFragments = url.Split("/"); string postKind = urlFragments[urlFragments.Length - 2]; if (postKind == "stories" || postKind == "releases" || postKind == "factsheets" || postKind == "updates") { post = await Repository.GetPostAsync(urlFragments[urlFragments.Length - 1]); } } } // handle cases where the search has a result not in our database. catch (Exception) { } var searchResult = new Models.SearchViewModel.Result(); searchResult.Title = System.Net.WebUtility.HtmlDecode(title.Replace("<b>", "").Replace("</b>", "")); searchResult.Uri = new Uri(url.Replace("https://news.gov.bc.ca/", Properties.Settings.Default.NewsHostUri.ToString())); searchResult.UriLabel = localUrl; searchResult.Description = ""; searchResult.HasMediaAssets = false; if (post != null) { searchResult.Title = post.Headline(); if (!string.IsNullOrEmpty(post.Summary)) { searchResult.Description = post.Summary; } searchResult.HasMediaAssets = post.HasMediaAssets == true; searchResult.PublishDate = post.PublishDate.HasValue ? post.PublishDate.Value : DateTimeOffset.MinValue; searchResult.ThumbnailUri = post.GetThumbnailUri(); } else { if (searchResult.Title.EndsWith(" | BC Gov News")) { searchResult.Title = searchResult.Title.Substring(0, searchResult.Title.Length - " | BC Gov News".Length); } if (searchResult.Title.EndsWith(" | BC ...")) { searchResult.Title = searchResult.Title.Substring(0, searchResult.Title.Length - " | BC ...".Length); } } model.Results.Add(searchResult); } result = result.ElementsAfterSelf().FirstOrDefault(); } } model.LastPage = Math.Min(Convert.ToInt32(Math.Ceiling((decimal)model.Count / (decimal)ResultsPerPage)), 100); #if !DEBUG } catch { model.Success = false; //TODO: Report exception message } #endif return(model); }