public IQueryable <V2FeedPackage> Search(string searchTerm, string targetFramework, bool includePrerelease) { var curatedFeedName = GetCuratedFeedName(); var curatedFeedKey = _curatedFeedService.GetKey(curatedFeedName); if (curatedFeedKey == null) { throw new DataServiceException(404, "Not Found"); } var curatedPackages = _curatedFeedService.GetPackages(curatedFeedName); return(SearchAdaptor.SearchCore(SearchService, HttpContext.Request, curatedPackages, searchTerm, targetFramework, includePrerelease, curatedFeedKey: curatedFeedKey) .ToV2FeedPackageQuery(Configuration.GetSiteRoot(UseHttps()), Configuration.Features.FriendlyLicenses)); }
private async Task TestOrderBy(string queryString, SortOrder?expected) { RawUrl += "&" + queryString; var result = await SearchAdaptor.SearchCore( SearchService.Object, Request.Object, Packages, SearchTerm, TargetFramework, IncludePrerelease, SemVerLevel); VerifySortOrder(expected); }
public void GeneratesNextLinkForComplexUrlWithSemVerLevel2() { // Arrange var requestUri = new Uri("https://localhost:8081/api/v2/Search()?searchTerm='foo'&$orderby=Id&$skip=100&$top=1000&semVerLevel=2.0.0"); var resultCount = 2000; // our result set contains 2000 elements // Act var nextLink = SearchAdaptor.GetNextLink(requestUri, resultCount, new { searchTerm = "foo" }, GetODataQueryOptionsForTest(requestUri), GetODataQuerySettingsForTest(), SemVerLevelKey.SemVer2); // Assert Assert.Equal(new Uri("https://localhost:8081/api/v2/Search()?searchTerm='foo'&$orderby=Id&$skip=200&$top=1000&semVerLevel=2.0.0"), nextLink); }
public virtual async Task <ActionResult> ListPackages(string curatedFeedName, string q, int page = 1, bool prerel = true) { if (page < 1) { page = 1; } q = (q ?? string.Empty).Trim(); var searchFilter = SearchAdaptor.GetSearchFilter( q, page, includePrerelease: prerel, sortOrder: null, context: SearchFilter.UISearchContext, semVerLevel: SemVerLevelKey.SemVerLevel2); searchFilter.CuratedFeed = CuratedFeedService.GetFeedByName(curatedFeedName, includePackages: false); if (searchFilter.CuratedFeed == null) { return(HttpNotFound()); } SearchResults results = await SearchService.Search(searchFilter); int totalHits = results.Hits; if (page == 1 && !results.Data.Any()) { // In the event the index wasn't updated, we may get an incorrect count. totalHits = 0; } var viewModel = new PackageListViewModel( results.Data, results.IndexTimestampUtc, q, totalHits, page - 1, Constants.DefaultPackageListPageSize, Url, curatedFeedName, includePrerelease: prerel); ViewBag.SearchTerm = q; return(View("ListPackages", viewModel)); }
private async Task <SearchResults> SearchAsync(ISearchService searchService, string searchTerm) { await Task.Yield(); var searchFilter = SearchAdaptor.GetSearchFilter( searchTerm, page: 1, includePrerelease: true, sortOrder: null, context: SearchFilter.UISearchContext, semVerLevel: SemVerLevelKey.SemVerLevel2); searchFilter.Take = 10; return(await searchService.Search(searchFilter)); }
public virtual ActionResult ListPackages(string curatedFeedName, string q, string sortOrder = null, int page = 1, bool prerelease = false) { if (page < 1) { page = 1; } q = (q ?? "").Trim(); if (String.IsNullOrEmpty(sortOrder)) { // Determine the default sort order. If no query string is specified, then the sortOrder is DownloadCount // If we are searching for something, sort by relevance. sortOrder = q.IsEmpty() ? Constants.PopularitySortOrder : Constants.RelevanceSortOrder; } var searchFilter = SearchAdaptor.GetSearchFilter(q, sortOrder, page, prerelease); searchFilter.CuratedFeedKey = CuratedFeedService.GetKey(curatedFeedName); if (searchFilter.CuratedFeedKey == 0) { return(HttpNotFound()); } int totalHits; IQueryable <Package> packageVersions = SearchService.Search(searchFilter, out totalHits); if (page == 1 && !packageVersions.Any()) { // In the event the index wasn't updated, we may get an incorrect count. totalHits = 0; } var viewModel = new PackageListViewModel( packageVersions, q, sortOrder, totalHits, page - 1, Constants.DefaultPackageListPageSize, Url, prerelease); ViewBag.SearchTerm = q; return(View("~/Views/Packages/ListPackages.cshtml", viewModel)); }
public IQueryable <V2FeedPackage> Search(string searchTerm, string targetFramework, bool includePrerelease) { var packages = PackageRepository.GetAll() .Include(p => p.PackageRegistration) .Include(p => p.PackageRegistration.Owners) .Where(p => p.Listed); return(SearchAdaptor.SearchCore( SearchService, HttpContext.Request, packages, searchTerm, targetFramework, includePrerelease, curatedFeed: null) // TODO: Async this when I can figure out OData async stuff... .Result .ToV2FeedPackageQuery(GetSiteRoot(), Configuration.Features.FriendlyLicenses)); }
public void ReturnsDefaultSearchFilterOnNull() { var searchFilter = SearchAdaptor.GetSearchFilter( q: null, page: -1, includePrerelease: true, packageType: null, sortOrder: null, context: null, semVerLevel: null); Assert.Null(searchFilter.SearchTerm); Assert.Equal(0, searchFilter.Skip); Assert.Equal(GalleryConstants.DefaultPackageListPageSize, searchFilter.Take); Assert.True(searchFilter.IncludePrerelease); Assert.Null(searchFilter.Context); Assert.Null(searchFilter.SemVerLevel); Assert.Equal(string.Empty, searchFilter.PackageType); Assert.Equal(SortOrder.Relevance, searchFilter.SortOrder); }
public IQueryable <V1FeedPackage> Search(string searchTerm, string targetFramework) { var packages = PackageRepository.GetAll() .Include(p => p.PackageRegistration) .Include(p => p.PackageRegistration.Owners) .Where(p => p.Listed && !p.IsPrerelease); // For v1 feed, only allow stable package versions. packages = SearchAdaptor.SearchCore( SearchService, HttpContext.Request, packages, searchTerm, targetFramework, includePrerelease: false, curatedFeed: null) // TODO: Async once I figure Odata Async stuff out .Result; return(packages.ToV1FeedPackageQuery(Configuration.GetSiteRoot(UseHttps()))); }
public void MapsAllSortOrders(SortOrder sortOrder) { var searchFilter = SearchAdaptor.GetSearchFilter( q: string.Empty, page: 1, includePrerelease: true, packageType: "Dependency", sortOrder: SortNames[sortOrder], context: string.Empty, semVerLevel: "SomeSemVer"); Assert.Equal(string.Empty, searchFilter.SearchTerm); Assert.Equal(0, searchFilter.Skip); Assert.Equal(GalleryConstants.DefaultPackageListPageSize, searchFilter.Take); Assert.Equal(true, searchFilter.IncludePrerelease); Assert.Equal(string.Empty, searchFilter.Context); Assert.Equal("SomeSemVer", searchFilter.SemVerLevel); Assert.Equal("Dependency", searchFilter.PackageType); Assert.Equal(sortOrder, searchFilter.SortOrder); }
public void GeneratesNextLinkForSimpleUrl1() { // Arrange var requestUri = new Uri("https://localhost:8081/api/v2/Packages"); var resultCount = 200; // our result set contains 200 elements // Act var nextLink = SearchAdaptor.GetNextLink(requestUri, resultCount, null, GetODataQueryOptionsForTest(requestUri), GetODataQuerySettingsForTest()); // Assert Assert.Equal(new Uri("https://localhost:8081/api/v2/Packages?$skip=100"), nextLink); // Act 2 nextLink = SearchAdaptor.GetNextLink(nextLink, resultCount, null, GetODataQueryOptionsForTest(nextLink), GetODataQuerySettingsForTest()); // Assert 2 Assert.Null(nextLink); }
public IQueryable <V2FeedPackage> Search(string searchTerm, string targetFramework, bool includePrerelease) { // Handle OData-style |-separated list of frameworks. string[] targetFrameworkList = (targetFramework ?? "").Split(new[] { '\'', '|' }, StringSplitOptions.RemoveEmptyEntries); // For now, we'll just filter on the first one. if (targetFrameworkList.Length > 0) { // Until we support multiple frameworks, we need to prefer aspnet50 over aspnetcore50. if (targetFrameworkList.Contains("aspnet50")) { targetFramework = "aspnet50"; } else { targetFramework = targetFrameworkList[0]; } } var packages = PackageRepository.GetAll() .Include(p => p.PackageRegistration) .Include(p => p.PackageRegistration.Owners) .Where(p => p.Listed); var query = SearchAdaptor.SearchCore( SearchService, HttpContext.Request, packages, searchTerm, targetFramework, includePrerelease, curatedFeed: null) // TODO: Async this when I can figure out OData async stuff... .Result .ToV2FeedPackageQuery(GetSiteRoot(), Configuration.Features.FriendlyLicenses); var result = query.ToList(); return(query); }
public IQueryable <V2FeedPackage> FindPackagesById(string id) { var packages = PackageRepository.GetAll() .Include(p => p.PackageRegistration) .Where(p => p.PackageRegistration.Id.Equals(id, StringComparison.OrdinalIgnoreCase)); if (Configuration.Features.PackageRestoreViaSearch) { try { packages = SearchAdaptor.FindByIdCore(SearchService, HttpContext.Request, packages, id, curatedFeed: null).Result; } catch (Exception ex) { // Swallowing Exception intentionally. If *anything* goes wrong in search, just fall back to the database. // We don't want to break package restores. We do want to know if this happens, so here goes: QuietLog.LogHandledException(ex); } } var query = packages.ToV2FeedPackageQuery(GetSiteRoot(), Configuration.Features.FriendlyLicenses); return(query); }
public IQueryable <V2FeedPackage> Search(string searchTerm, string targetFramework, bool includePrerelease) { var curatedFeedName = GetCuratedFeedName(); var curatedFeed = _curatedFeedService.GetFeedByName(curatedFeedName, includePackages: false); if (curatedFeed == null) { throw new DataServiceException(404, "Not Found"); } var curatedPackages = _curatedFeedService.GetPackages(curatedFeedName); return(SearchAdaptor.SearchCore( SearchService, HttpContext.Request, curatedPackages, searchTerm, targetFramework, includePrerelease, curatedFeed) // TODO: Async this when I can figure out OData async stuff... .Result .ToV2FeedPackageQuery(Configuration.GetSiteRoot(UseHttps()), Configuration.Features.FriendlyLicenses)); }
public virtual async Task <ActionResult> ListPackages(string q, int page = 1) { if (page < 1) { page = 1; } q = (q ?? string.Empty).Trim(); // We are not going to SQL here anyway, but our request logs do show some attempts to SQL injection. // The below code just fails out those requests early. if (q.ToLowerInvariant().Contains("char(") || q.ToLowerInvariant().Contains("union select") || q.ToLowerInvariant().Contains("/*") || q.ToLowerInvariant().Contains("--")) { return(new HttpStatusCodeResult(HttpStatusCode.BadRequest)); } SearchResults results; // fetch most common query from cache to relieve load on the search service if (string.IsNullOrEmpty(q) && page == 1) { var cachedResults = HttpContext.Cache.Get("DefaultSearchResults"); if (cachedResults == null) { var searchFilter = SearchAdaptor.GetSearchFilter(q, page, null, SearchFilter.UISearchContext); results = await _searchService.Search(searchFilter); // note: this is a per instance cache HttpContext.Cache.Add( "DefaultSearchResults", results, null, DateTime.UtcNow.AddMinutes(10), Cache.NoSlidingExpiration, CacheItemPriority.Default, null); } else { // default for /packages view results = (SearchResults)cachedResults; } } else { var searchFilter = SearchAdaptor.GetSearchFilter(q, page, null, SearchFilter.UISearchContext); results = await _searchService.Search(searchFilter); } int totalHits = results.Hits; if (page == 1 && !results.Data.Any()) { // In the event the index wasn't updated, we may get an incorrect count. totalHits = 0; } var viewModel = new PackageListViewModel( results.Data, results.IndexTimestampUtc, q, totalHits, page - 1, Constants.DefaultPackageListPageSize, Url); ViewBag.SearchTerm = q; return(View(viewModel)); }
public virtual async Task <ActionResult> DisplayPackage(string id, string version) { string normalized = NuGetVersionNormalizer.Normalize(version); if (!string.Equals(version, normalized)) { // Permanent redirect to the normalized one (to avoid multiple URLs for the same content) return(RedirectToActionPermanent("DisplayPackage", new { id = id, version = normalized })); } var package = _packageService.FindPackageByIdAndVersion(id, version); if (package == null) { return(HttpNotFound()); } var packageHistory = package.PackageRegistration.Packages.ToList() .OrderByDescending(p => new NuGetVersion(p.Version)); var model = new DisplayPackageViewModel(package, packageHistory); if (package.IsOwner(User)) { // Tell logged-in package owners not to cache the package page, // so they won't be confused about the state of pending edits. Response.Cache.SetCacheability(HttpCacheability.NoCache); Response.Cache.SetNoStore(); Response.Cache.SetMaxAge(TimeSpan.Zero); Response.Cache.SetRevalidation(HttpCacheRevalidation.AllCaches); var pendingMetadata = _editPackageService.GetPendingMetadata(package); if (pendingMetadata != null) { model.SetPendingMetadata(pendingMetadata); } } var externalSearchService = _searchService as ExternalSearchService; if (_searchService.ContainsAllVersions && externalSearchService != null) { var isIndexedCacheKey = $"IsIndexed_{package.PackageRegistration.Id}_{package.Version}"; var isIndexed = HttpContext.Cache.Get(isIndexedCacheKey) as bool?; if (!isIndexed.HasValue) { var searchFilter = SearchAdaptor.GetSearchFilter( "id:\"" + package.PackageRegistration.Id + "\" AND version:\"" + package.Version + "\"", 1, null, SearchFilter.ODataSearchContext); var results = await externalSearchService.RawSearch(searchFilter); isIndexed = results.Hits > 0; var expiration = Cache.NoAbsoluteExpiration; if (!isIndexed.Value) { expiration = DateTime.UtcNow.Add(TimeSpan.FromSeconds(30)); } HttpContext.Cache.Add(isIndexedCacheKey, isIndexed, null, expiration, Cache.NoSlidingExpiration, CacheItemPriority.Default, null); } model.IsIndexed = isIndexed; } ViewBag.FacebookAppID = _config.FacebookAppId; return(View(model)); }
public virtual async Task <ActionResult> ListPackages(string q, int page = 1) { if (page < 1) { page = 1; } q = (q ?? string.Empty).Trim(); SearchResults results; // fetch most common query from cache to relieve load on the search service if (string.IsNullOrEmpty(q) && page == 1) { var cachedResults = HttpContext.Cache.Get("DefaultSearchResults"); if (cachedResults == null) { var searchFilter = SearchAdaptor.GetSearchFilter(q, page, null, SearchFilter.UISearchContext); results = await _searchService.Search(searchFilter); // note: this is a per instance cache HttpContext.Cache.Add( "DefaultSearchResults", results, null, DateTime.UtcNow.AddMinutes(10), Cache.NoSlidingExpiration, CacheItemPriority.Default, null); } else { // default for /packages view results = (SearchResults)cachedResults; } } else { var searchFilter = SearchAdaptor.GetSearchFilter(q, page, null, SearchFilter.UISearchContext); results = await _searchService.Search(searchFilter); } int totalHits = results.Hits; if (page == 1 && !results.Data.Any()) { // In the event the index wasn't updated, we may get an incorrect count. totalHits = 0; } var viewModel = new PackageListViewModel( results.Data, results.IndexTimestampUtc, q, totalHits, page - 1, Constants.DefaultPackageListPageSize, Url); ViewBag.SearchTerm = q; return(View(viewModel)); }