Example #1
0
        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);
        }