private static string GetPopularRoutes(Area area, ResultParameters parameters) { string result = ""; List <Route> popularRoutes = new List <Route>(); if (area.PopularRouteIDs.Count == 0) //MountainProject doesn't list any popular routes. Figure out some ourselves { popularRoutes = area.GetPopularRoutes(3); } else { area.PopularRouteIDs.ForEach(id => popularRoutes.Add(MountainProjectDataSearch.GetItemWithMatchingID(id, MountainProjectDataSearch.DestAreas) as Route)); } foreach (Route popularRoute in popularRoutes) { result += $"\n- {Markdown.Link(popularRoute.Name, popularRoute.URL)} {GetRouteAdditionalInfo(popularRoute, parameters)}"; } if (string.IsNullOrEmpty(result)) { return(""); } return("Popular routes:" + Markdown.NewLine + result + Markdown.NewLine); }
public void TestSearch() { InitMPData(); for (int i = 0; i < testCriteria_search.GetLength(0); i++) { string query = testCriteria_search[i, 0]; string expectedUrl = testCriteria_search[i, 1]; _ = ResultParameters.ParseParameters(ref query); //This is here just to filter out any query items (not to be used) SearchParameters searchParameters = SearchParameters.ParseParameters(ref query); SearchResult searchResult = MountainProjectDataSearch.Search(query, searchParameters); if (string.IsNullOrEmpty(expectedUrl)) { Assert.IsNull(searchResult.FilteredResult, "Failed for " + testCriteria_search[i, 0]); } else { Assert.AreEqual(Utilities.GetSimpleURL(Utilities.MPBASEURL + expectedUrl), searchResult.FilteredResult.URL, "Failed for " + testCriteria_search[i, 0]); } Assert.IsTrue(searchResult.TimeSpanTaken().TotalSeconds < 5, $"{query} took too long ({searchResult.TimeTakenMS} ms)"); } }
public static string GetLocationString(MPObject child, Area referenceLocation = null) { MPObject innerParent = MountainProjectDataSearch.GetInnerParent(child); MPObject outerParent = MountainProjectDataSearch.GetOuterParent(child); if (referenceLocation != null) //Override the "innerParent" in situations where we want the location string to include the "insisted" location { //Only override if the location is not already present if (innerParent?.URL != referenceLocation.URL && outerParent?.URL != referenceLocation.URL) { innerParent = referenceLocation; } } if (innerParent == null) { return(""); } string locationString = $"Located in {Markdown.Link(innerParent.Name, innerParent.URL)}"; if (outerParent != null && outerParent.URL != innerParent.URL) { locationString += $", {Markdown.Link(outerParent.Name, outerParent.URL)}"; } locationString += Markdown.NewLine; return(locationString); }
static void Main(string[] args) { Console.OutputEncoding = System.Text.Encoding.UTF8; AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException; if (args.FirstOrDefault(p => p.Contains("xmlpath=")) != null) { xmlPath = args.FirstOrDefault(p => p.Contains("xmlpath=")).Split('=')[1]; } if (args.FirstOrDefault(p => p.Contains("credentials=")) != null) { credentialsPath = args.FirstOrDefault(p => p.Contains("credentials=")).Split('=')[1]; } if (args.FirstOrDefault(p => p.Contains("repliedto=")) != null) { repliedToPath = args.FirstOrDefault(p => p.Contains("repliedto=")).Split('=')[1]; } if (args.FirstOrDefault(p => p.Contains("blacklisted=")) != null) { blacklistedPath = args.FirstOrDefault(p => p.Contains("blacklisted=")).Split('=')[1]; } CheckRequiredFiles(); MountainProjectDataSearch.InitMountainProjectData(xmlPath); redditHelper.Auth(credentialsPath).Wait(); DoBotLoop().Wait(); }
public static void InitStreams() { while (true) { try { MountainProjectDataSearch.InitMountainProjectData(xmlPath); break; } catch { ConsoleHelper.Write("MountainProjectAreas.xml is in use. Waiting 5s before trying again..."); Thread.Sleep(TimeSpan.FromSeconds(5)); } } BotFunctions.RedditHelper = new RedditHelper(); BotFunctions.RedditHelper.Auth(credentialsPath).Wait(); requestForApprovalURL = GetCredentialValue(credentialsPath, "requestForApprovalURL"); WebServerURL = GetCredentialValue(credentialsPath, "webServerURL"); spreadsheetHistoryURL = GetCredentialValue(credentialsPath, "spreadsheetURL"); //Start approval server ApprovalServer = new Server(9999) { HandleRequest = ApprovalServerRequestHandler.HandleRequest }; ApprovalServer.Start(); }
public static string GetReplyForMPLinks(Comment comment) { List <MPObject> foundMPObjects = new List <MPObject>(); foreach (string url in ExtractMPLinks(WebUtility.HtmlDecode(comment.Body))) { MPObject mpObjectWithID = MountainProjectDataSearch.GetItemWithMatchingID(Utilities.GetID(url)); if (mpObjectWithID != null) { foundMPObjects.Add(mpObjectWithID); } } string response = ""; if (foundMPObjects.Count == 0) { return(null); } foundMPObjects.ForEach(p => response += GetFormattedString(p, includeUrl: false) + Markdown.HRule); response += GetBotLinks(comment); return(response); }
private static string GetPopularRoutes(Area area, ResultParameters parameters) { string result = "Popular routes:\n"; List <Route> popularRoutes = new List <Route>(); if (area.PopularRouteUrls.Count == 0) //MountainProject doesn't list any popular routes. Figure out some ourselves { popularRoutes = area.GetPopularRoutes(3); } else { List <MPObject> itemsToSearch = new List <MPObject>(); itemsToSearch.AddRange(area.SubAreas); itemsToSearch.AddRange(area.Routes); area.PopularRouteUrls.ForEach(p => popularRoutes.Add(MountainProjectDataSearch.GetItemWithMatchingUrl(p, itemsToSearch) as Route)); } foreach (Route popularRoute in popularRoutes) { result += $"\n- {Markdown.Link(popularRoute.Name, popularRoute.URL)} {GetRouteAdditionalInfo(popularRoute, parameters)}"; } if (string.IsNullOrEmpty(result)) { return(""); } result += Markdown.NewLine; return(result); }
private void InitMPData() { //The MountainProject data will actually persist between unit tests if multiple unit tests are run at once. Doing it this way //ensures that the delay time to init the MountainProject data is only part of the first test if (MountainProjectDataSearch.DestAreas.Count == 0) { MountainProjectDataSearch.InitMountainProjectData(@"..\..\MountainProjectDBBuilder\bin\MountainProjectAreas.xml"); } }
public void TestCommentBodyParse() { MountainProjectDataSearch.InitMountainProjectData(@"..\..\MountainProjectDBBuilder\bin\MountainProjectAreas.xml"); for (int i = 0; i < testCriteria_keyword.GetLength(0); i++) { string commentBody = testCriteria_keyword[i, 0]; string expectedUrl = testCriteria_keyword[i, 1]; string resultReply = BotReply.GetReplyForCommentBody(commentBody); Assert.IsTrue(resultReply.Contains(expectedUrl)); } }
public void TestSearch() { MountainProjectDataSearch.InitMountainProjectData(@"..\..\MountainProjectDBBuilder\bin\MountainProjectAreas.xml"); for (int i = 0; i < testCriteria_search.GetLength(0); i++) { string query = testCriteria_search[i, 0]; string expectedUrl = testCriteria_search[i, 1]; MPObject result = MountainProjectDataSearch.SearchMountainProject(query); Assert.AreEqual(Utilities.MPBASEURL + expectedUrl, result.URL); } }
private static void ParseInputString() { MountainProjectDataSearch.InitMountainProjectData(serializationPath); if (MountainProjectDataSearch.DestAreas.Count() == 0) { Console.WriteLine("The xml either doesn't exist or is empty"); Environment.Exit(0); } Console.WriteLine("File read."); bool keepSearching = true; while (keepSearching) { Console.WriteLine("\n\nPlease input the string you would like to parse: "); string input = Console.ReadLine(); Stopwatch stopwatch = Stopwatch.StartNew(); MPObject result = MountainProjectDataSearch.SearchMountainProject(input); stopwatch.Stop(); if (result == null) { Console.WriteLine("Nothing found matching \"" + input + "\""); } else { string resultStr = ""; if (result is Area) { resultStr = (result as Area).ToString(); } else if (result is Route) { resultStr = (result as Route).ToString(); } Console.WriteLine("The following was found: " + resultStr + " (Found in " + stopwatch.ElapsedMilliseconds + " ms)"); Console.WriteLine($"Parent: {MountainProjectDataSearch.GetParent(result, -1).Name}"); Console.WriteLine("\nOpen result? (y/n) "); if (Console.ReadKey().Key == ConsoleKey.Y) { Process.Start(result.URL); } } Console.WriteLine("\nSearch something else? (y/n) "); keepSearching = Console.ReadKey().Key == ConsoleKey.Y; } }
public static string GetLocationString(MPObject child) { MPObject innerParent, outerParent; innerParent = null; if (child is Route) { innerParent = MountainProjectDataSearch.GetParent(child, -2); //Get the "second to last" parent https://github.com/derekantrican/MountainProject/issues/12 } else if (child is Area) { innerParent = MountainProjectDataSearch.GetParent(child, -1); //Get immediate parent } if (innerParent == null || //If "child" is a dest area, the parent will be "All Locations" which won't be in our directory innerParent.URL == Utilities.INTERNATIONALURL) //If "child" is an area like "Europe" { return(""); } outerParent = MountainProjectDataSearch.GetParent(child, 1); //Get state that route/area is in if (outerParent.URL == Utilities.INTERNATIONALURL) //If this is international, get the country instead of the state (eg "China") { if (child.ParentUrls.Count > 3) { if (child.ParentUrls.Contains(Utilities.AUSTRALIAURL)) //Australia is both a continent and a country so it is an exception { outerParent = MountainProjectDataSearch.GetParent(child, 2); } else { outerParent = MountainProjectDataSearch.GetParent(child, 3); } } else { return(""); //Return a blank string if we are in an area like "China" (so we don't return a string like "China is located in Asia") } } string locationString = $"Located in {innerParent.Name}"; if (outerParent != null && outerParent.URL != innerParent.URL) { locationString += $", {outerParent.Name}"; } locationString += "\n\n"; return(locationString); }
public static string GetReplyForCommentBody(string commentBody) { string queryText = commentBody.Split(new string[] { BOTKEYWORD }, StringSplitOptions.None)[1].Trim(); MPObject searchResult = MountainProjectDataSearch.SearchMountainProject(queryText); string replyText = GetFormattedString(searchResult); if (string.IsNullOrEmpty(replyText)) { replyText = $"I could not find anything for \"{queryText}\". Please use the Feedback button below if you think this is a bug"; } return(replyText); }
public static string HandleRequest(ServerRequest request) { if (request.RequestMethod == HttpMethod.Get && !request.IsFaviconRequest && !request.IsDefaultPageRequest) { Dictionary <string, string> parameters = request.GetParameters(); if (parameters.ContainsKey("status")) //UpTimeRobot will ping this { return("UP"); } else if (parameters.ContainsKey("posthistory")) { string query = parameters.ContainsKey("query") ? parameters["query"] : ""; int page = parameters.ContainsKey("page") ? Convert.ToInt32(parameters["page"]) : 1; return(ShowPostHistory(query, page)); } else if (parameters.ContainsKey("postid") && (parameters.ContainsKey("approve") || parameters.ContainsKey("approveall") || parameters.ContainsKey("approveother"))) { if (BotFunctions.PostsPendingApproval.ContainsKey(parameters["postid"])) { ApprovalRequest approvalRequest = BotFunctions.PostsPendingApproval[parameters["postid"]]; return(GetApproval(parameters, approvalRequest)); } else if (parameters.ContainsKey("force")) { //Because the ApprovalRequest & SearchResult have been disposed by now, we need to recreate them. Maybe we can do this in a better way in the future Post post = BotFunctions.RedditHelper.GetPost(parameters["postid"]).Result; SearchResult searchResult = MountainProjectDataSearch.ParseRouteFromString(post.Title); return(GetApproval(parameters, new ApprovalRequest { Force = true, RedditPost = post, SearchResult = searchResult })); } else { return(WrapHtml($"<h1>Post '{parameters["postid"]}' expired</h1>" + $"<br>" + $"<br>" + $"<input type=\"button\" onclick=\"force()\" value=\"Force\">" + $"<script>" + $" function force(){{" + $" window.location.replace(\"{BotUtilities.ApprovalServerUrl}?{string.Join("&", parameters.Select(p => $"{p.Key}={p.Value}").Concat(new[] { "force" }))}\");" + $"}}" + $"</script>")); } } } return(WrapHtml($"<h1>Path '{request.Path}' not understood</h1>")); }
public void TestLocationString() { MountainProjectDataSearch.InitMountainProjectData(@"..\..\MountainProjectDBBuilder\bin\MountainProjectAreas.xml"); for (int i = 0; i < testCriteria_location.GetLength(0); i++) { string query = testCriteria_location[i, 0]; string expectedLocation = testCriteria_location[i, 1]; string resultLocation = BotReply.GetLocationString(MountainProjectDataSearch.SearchMountainProject(query)); resultLocation = resultLocation.Replace("\n\n", ""); //Remove markdown newline resultLocation = resultLocation.Replace("Located in ", ""); //Simplify results for unit test Assert.AreEqual(expectedLocation, resultLocation); } }
public void TestGradeEquality() { InitMPData(); for (int i = 0; i < testCriteria_gradeEquality.GetLength(0); i++) { string inputUrl = testCriteria_gradeEquality[i, 0].ToString(); GradeSystem gradeSystem = (GradeSystem)testCriteria_gradeEquality[i, 1]; string inputGrade = testCriteria_gradeEquality[i, 2].ToString(); Grade expectedGrade = Grade.ParseString(inputGrade)[0]; Route route = MountainProjectDataSearch.GetItemWithMatchingID(Utilities.GetID(Utilities.MPBASEURL + inputUrl)) as Route; Assert.IsTrue(route.Grades.Any(g => expectedGrade.Equals(g, true, true))); } }
public static string GetReplyForRequest(string commentBody) { //Get everything AFTER the keyword, but on the same line string queryText = Regex.Match(commentBody, BOTKEYWORDREGEX).Groups[1].Value.Trim(); if (string.IsNullOrWhiteSpace(queryText)) { return("I didn't understand what you were looking for. Please use the Feedback button below if you think this is a bug"); } ResultParameters resultParameters = ResultParameters.ParseParameters(ref queryText); SearchParameters searchParameters = SearchParameters.ParseParameters(ref queryText); SearchResult searchResult = MountainProjectDataSearch.Search(queryText, searchParameters); return(GetResponse(queryText, searchParameters?.SpecificLocation, searchResult, resultParameters)); }
public void TestLocationString() { InitMPData(); for (int i = 0; i < testCriteria_location.GetLength(0); i++) { string query = testCriteria_location[i, 0]; string expectedLocation = testCriteria_location[i, 1]; SearchResult searchResult = MountainProjectDataSearch.Search(query); string resultLocation = BotReply.GetLocationString(searchResult.FilteredResult); resultLocation = resultLocation.Replace(Markdown.NewLine, ""); //Remove markdown newline resultLocation = resultLocation.Replace("Located in ", ""); //Simplify results for unit test resultLocation = Regex.Replace(resultLocation, @"\[|\]\(.*?\)", ""); //Remove markdown link formatting Assert.AreEqual(expectedLocation, resultLocation, "Failed for " + testCriteria_location[i, 0]); Assert.IsTrue(searchResult.TimeSpanTaken().TotalSeconds < 5, $"{query} took too long ({searchResult.TimeTakenMS} ms)"); } }
static void Main(string[] args) { if (args.FirstOrDefault(p => p.Contains("xmlpath=")) != null) { xmlPath = args.FirstOrDefault(p => p.Contains("xmlpath=")).Split('=')[1]; } if (args.FirstOrDefault(p => p.Contains("credentials=")) != null) { credentialsPath = args.FirstOrDefault(p => p.Contains("credentials=")).Split('=')[1]; } if (args.FirstOrDefault(p => p.Contains("repliedto=")) != null) { repliedToPath = args.FirstOrDefault(p => p.Contains("repliedto=")).Split('=')[1]; } CheckRequiredFiles(); MountainProjectDataSearch.InitMountainProjectData(xmlPath); AuthReddit().Wait(); DoBotLoop().Wait(); }
public static string GetPopularRoutes(Area area) { string result = "Popular routes:\n"; if (area.PopularRouteUrls.Count == 0) { return(""); } foreach (string url in area.PopularRouteUrls) { List <MPObject> itemsToSearch = new List <MPObject>(); itemsToSearch.AddRange(area.SubAreas); itemsToSearch.AddRange(area.Routes); Route popularRoute = MountainProjectDataSearch.GetItemWithMatchingUrl(url, itemsToSearch) as Route; result += $"\n- {popularRoute.Name}"; } result += "\n\n"; return(result); }
public static async Task CheckPostsForAutoReply(List <Subreddit> subreddits) { List <Post> recentPosts = new List <Post>(); foreach (Subreddit subreddit in subreddits) { List <Post> subredditPosts = await RedditHelper.GetPosts(subreddit, 10); subredditPosts = BotUtilities.RemoveAlreadySeenPosts(subredditPosts); subredditPosts = BotUtilities.RemoveBlacklisted(subredditPosts, new[] { BlacklistLevel.NoPostReplies, BlacklistLevel.OnlyKeywordReplies, BlacklistLevel.Total }); //Remove posts from users who don't want the bot to automatically reply to them foreach (Post post in subredditPosts.ToList()) { if (post.IsSelfPost) { subredditPosts.Remove(post); ConsoleHelper.Write($"\tSkipping {post.Id} (self-post)", ConsoleColor.Red); BotUtilities.LogPostBeenSeen(post, "self-post"); } double ageInMin = (DateTime.UtcNow - post.CreatedUTC).TotalMinutes; if (ageInMin > 30) { subredditPosts.Remove(post); ConsoleHelper.Write($"\tSkipping {post.Id} (too old: {Math.Round(ageInMin, 2)} min)", ConsoleColor.Red); BotUtilities.LogPostBeenSeen(post, $"too old ({Math.Round(ageInMin, 2)} min)"); } } recentPosts.AddRange(subredditPosts); } foreach (Post post in recentPosts) { try { string postTitle = WebUtility.HtmlDecode(post.Title); Console.WriteLine($"\tTrying to get an automatic reply for post (/r/{post.SubredditName}): {postTitle}"); SearchResult searchResult = MountainProjectDataSearch.ParseRouteFromString(postTitle); if (!searchResult.IsEmpty()) { ApprovalRequest approvalRequest = new ApprovalRequest { RedditPost = post, SearchResult = searchResult }; PostsPendingApproval.TryAdd(post.Id, approvalRequest); BotUtilities.LogPostBeenSeen(post, searchResult.Confidence == 1 ? "auto-replying" : "pending approval"); if (!DryRun) { if (searchResult.Confidence == 1) { string reply = BotReply.GetFormattedString(searchResult); reply += Markdown.HRule; reply += BotReply.GetBotLinks(post); Comment botReplyComment = await RedditHelper.CommentOnPost(post, reply); monitoredComments.Add(new CommentMonitor() { Parent = post, BotResponseComment = botReplyComment }); ConsoleHelper.Write($"\n\tAuto-replied to post {post.Id}", ConsoleColor.Green); } else { //Until we are more confident with automatic results, we're going to request for approval for confidence values greater than 1 (less than 100%) ConsoleHelper.Write($"\tRequesting approval for post {post.Id}", ConsoleColor.Yellow); BotUtilities.RequestApproval(approvalRequest); } BotUtilities.LogOrUpdateSpreadsheet(approvalRequest); } } else { Console.WriteLine("\tNothing found"); BotUtilities.LogPostBeenSeen(post, "nothing found"); } } catch (RateLimitException) { Console.WriteLine("\tRate limit hit. Postponing reply until next iteration"); } catch (Exception e) { Console.WriteLine($"\tException occurred with post {RedditHelper.GetFullLink(post.Permalink)}"); Console.WriteLine($"\t{e.Message}\n{e.StackTrace}"); } } }
private static string GetApproval(Dictionary <string, string> parameters, ApprovalRequest approvalRequest) { string result = ""; if (parameters.ContainsKey("approveother")) { if (parameters.ContainsKey("option")) { foreach (string approvedId in parameters["option"].Split(',')) { MPObject matchingOption = approvalRequest.SearchResult.AllResults.Find(p => p.ID == approvedId) ?? MountainProjectDataSearch.GetItemWithMatchingID(approvedId); if (matchingOption == null) { result += $"Option '{approvedId}' not found<br>"; } else { approvalRequest.ApprovedResults.Add(matchingOption); } } } else { return(ShowApproveOtherPicker(parameters, approvalRequest)); } } else if (parameters.ContainsKey("approve")) { approvalRequest.ApprovedResults = new List <MPObject> { approvalRequest.SearchResult.FilteredResult }; approvalRequest.RelatedLocation = approvalRequest.SearchResult.RelatedLocation; } else if (parameters.ContainsKey("approveall")) { approvalRequest.ApprovedResults = approvalRequest.SearchResult.AllResults; approvalRequest.RelatedLocation = approvalRequest.SearchResult.RelatedLocation; } if (approvalRequest.IsApproved) { BotFunctions.PostsPendingApproval[parameters["postid"]] = approvalRequest; result = $"Approved:<br>{string.Join("<br>", approvalRequest.ApprovedResults.Select(r => $"• {r.Name} ({r.ID})"))}"; //Print out approved results as a bulleted list } return(WrapHtml($"<h1>{result}</h1>")); }
public void TestPostTitleParse(/*bool outputExtraInfo, bool isGoogleSheetsTest*/) { bool outputExtraInfo = false; bool isGoogleSheetsTest = false; Stopwatch totalStopwatch = Stopwatch.StartNew(); int totalPasses = 0; int totalFailures = 0; int yessesWithConfidence1 = 0; List <string> failingPostsWithConfidence1 = new List <string>(); StringWriter writer = new StringWriter(); Console.SetOut(writer); MountainProjectDataSearch.OutputExtraInfo = outputExtraInfo; InitMPData(); string[] testCriteria; if (isGoogleSheetsTest) { string requestUrl = BotUtilities.GetCredentialValue(@"..\..\MountainProjectBot\Credentials.txt", "spreadsheetURL") + "PostHistory"; testCriteria = Utilities.GetHtml(requestUrl).Split('\n'); } else { testCriteria = File.ReadAllLines(@"..\PostTitleTest.txt"); } for (int i = 0; i < testCriteria.Length; i++) { Stopwatch routeStopwatch = Stopwatch.StartNew(); string[] lineParts = testCriteria[i].Split('\t'); string inputPostTitle, expectedMPLink, comment; if (isGoogleSheetsTest) { inputPostTitle = lineParts[2]; expectedMPLink = lineParts[9].ToUpper() == "YES" ? Utilities.GetSimpleURL(lineParts[7]) : !string.IsNullOrEmpty(lineParts[10]) ? $"{Utilities.MPROUTEURL}/{lineParts[10]}" : null; comment = lineParts.Length > 11 && !string.IsNullOrEmpty(lineParts[11]) ? $"//{lineParts[11]}" : null; } else { inputPostTitle = lineParts[0]; expectedMPLink = lineParts[1] == "null" ? null : Utilities.GetSimpleURL(lineParts[1]); comment = lineParts.Length > 2 && !string.IsNullOrEmpty(lineParts[2]) ? $"//{lineParts[2]}" : null; } //Override input title (uncomment only for debugging) //inputPostTitle = "Happy Star Wars Day! Had to practice my mental game for this one: \"Jedi Mind Tricks\" (v4). One of the Best."; writer.WriteLine($"POST TITLE: {inputPostTitle}"); SearchResult result = MountainProjectDataSearch.ParseRouteFromString(WebUtility.HtmlDecode(inputPostTitle)); Route route = result.FilteredResult as Route; if (expectedMPLink == null) { if (route == null) { writer.WriteLine($"PASS (Correctly guessed no match)"); totalPasses++; } else { writer.WriteLine($"FAILED (confidence {result.Confidence}). EXPECTED: , ACTUAL: {route?.URL} {comment}"); totalFailures++; if (result.Confidence == 1) { failingPostsWithConfidence1.Add($"{inputPostTitle} {comment}"); } } } else { if (route == null || route.URL != expectedMPLink) { writer.WriteLine($"FAILED (confidence {result.Confidence}). EXPECTED: {expectedMPLink} , ACTUAL: {route?.URL} {comment}"); totalFailures++; if (result.Confidence == 1) { failingPostsWithConfidence1.Add($"{inputPostTitle} {comment}"); } } else { writer.WriteLine($"PASS (confidence: {result.Confidence})"); totalPasses++; if (isGoogleSheetsTest && result.Confidence == 1) { yessesWithConfidence1++; } } } if (outputExtraInfo) { writer.WriteLine($"Time taken: {routeStopwatch.Elapsed}"); } } if (outputExtraInfo) { Debug.WriteLine($"Test completed in {totalStopwatch.Elapsed}\n"); } if (!isGoogleSheetsTest) { Debug.WriteLine($"Passes: {totalPasses}, Failures: {totalFailures}, Pass percentage: {Math.Round((double)totalPasses / (totalPasses + totalFailures) * 100, 2)}%\n"); } else { Debug.WriteLine($"Yesses that now have confidence 1: {yessesWithConfidence1} (out of {testCriteria.Count(p => p.Split('\t')[9].ToUpper() == "YES")} total yesses)\n"); Debug.WriteLine($"Passes: {totalPasses}, Failures: {totalFailures}\n"); } if (failingPostsWithConfidence1.Any()) { Debug.WriteLine($"Failing posts with confidence 1 ({failingPostsWithConfidence1.Count()}):\n\n{string.Join("\n", failingPostsWithConfidence1)}\n"); } Debug.WriteLine(writer.ToString()); writer.Dispose(); Assert.IsTrue(failingPostsWithConfidence1.Count == 0, "Some failed matches have a confidence of 1"); if (!isGoogleSheetsTest) //Todo: may want to rework how the spreadsheet is setup so that this line is also relevant for GoogleSheetsTest { Assert.IsTrue((double)totalPasses / (totalPasses + totalFailures) > 0.95); } }
private static void AddNewItems() { Parsers.TotalTimer = totalTimer; List <Area> destAreas = Parsers.GetDestAreas(); DateTime lastBuild = File.GetLastWriteTime(serializationPath); string rssUrl = $"https://www.mountainproject.com/rss/new?selectedIds={string.Join(",", destAreas.Select(p => p.ID))}&routes=on&areas=on"; SyndicationFeed feed = null; using (XmlReader reader = XmlReader.Create(rssUrl)) { feed = SyndicationFeed.Load(reader); } IEnumerable <string> newlyAddedItemUrls = feed.Items.Where(p => p.PublishDate > lastBuild).OrderBy(p => p.PublishDate).Select(p => p.Links[0].Uri.ToString()); MountainProjectDataSearch.InitMountainProjectData(serializationPath); foreach (string newItemUrl in newlyAddedItemUrls) { string newId = Utilities.GetID(newItemUrl); if (MountainProjectDataSearch.GetItemWithMatchingID(newId) != null) //Item has already been added (probably via a recursive area add) { continue; } MPObject newItem; if (newItemUrl.Contains(Utilities.MPAREAURL)) { newItem = new Area { ID = newId }; Parsers.ParseAreaAsync(newItem as Area).Wait(); } else { newItem = new Route { ID = newId }; Parsers.ParseRouteAsync(newItem as Route).Wait(); } Area currentParent = null; bool itemAddedViaRecursiveParse = false; foreach (string parentId in newItem.ParentIDs) //Make sure all parents are populated { MPObject matchingItem = MountainProjectDataSearch.GetItemWithMatchingID(parentId); if (matchingItem == null) { Area newArea = new Area { ID = parentId }; Parsers.ParseAreaAsync(newArea).Wait(); currentParent.SubAreas.Add(newArea); itemAddedViaRecursiveParse = true; break; } else { currentParent = matchingItem as Area; } } if (!itemAddedViaRecursiveParse) { if (newItem is Area) { (MountainProjectDataSearch.GetItemWithMatchingID(newItem.ParentIDs.Last()) as Area).SubAreas.Add(newItem as Area); } else { (MountainProjectDataSearch.GetItemWithMatchingID(newItem.ParentIDs.Last()) as Area).Routes.Add(newItem as Route); } } } destAreas = MountainProjectDataSearch.DestAreas; totalTimer.Stop(); Console.WriteLine($"------PROGRAM FINISHED------ ({totalTimer.Elapsed})"); Console.WriteLine(); Console.WriteLine($"Total # of areas: {Parsers.TotalAreas}, total # of routes: {Parsers.TotalRoutes}"); SerializeResults(destAreas); SendReport($"MountainProjectDBBuilder database updated SUCCESSFULLY in {totalTimer.Elapsed}", $"{newlyAddedItemUrls.Count()} new items:\n\n{string.Join("\n", newlyAddedItemUrls)}"); }
private static void ParseInputString() { MountainProjectDataSearch.InitMountainProjectData(serializationPath); if (MountainProjectDataSearch.DestAreas.Count() == 0) { Console.WriteLine("The xml either doesn't exist or is empty"); Environment.Exit(0); } Console.WriteLine("File read."); bool keepSearching = true; while (keepSearching) { Console.WriteLine("\n\nPlease input the string you would like to parse: "); string input = Console.ReadLine(); SearchParameters searchParameters = SearchParameters.ParseParameters(ref input); ResultParameters resultParameters = ResultParameters.ParseParameters(ref input); bool allResults = input.Contains("-all"); if (allResults) { input = input.Replace("-all", "").Trim(); } Stopwatch stopwatch = Stopwatch.StartNew(); SearchResult searchResult = MountainProjectDataSearch.Search(input, searchParameters); stopwatch.Stop(); if (searchResult.IsEmpty()) { Console.WriteLine("Nothing found matching \"" + input + "\""); } else if (allResults) { List <MPObject> matchedObjectsByPopularity = searchResult.AllResults.OrderByDescending(p => p.Popularity).ToList(); Console.WriteLine($"Found {matchedObjectsByPopularity.Count} items match that search query (found in {stopwatch.ElapsedMilliseconds} ms):"); foreach (MPObject result in matchedObjectsByPopularity) { string url = result.URL.Replace(Utilities.MPBASEURL, ""); if (result is Route) { Console.WriteLine($" Route: {result.Name} (Pop: {result.Popularity}) | Location: {GetLocationString(result)} | {url}"); } else if (result is Area) { Console.WriteLine($" Area: {result.Name} (Pop: {result.Popularity}) | Location: {GetLocationString(result)} | {url}"); } } } else { string resultStr = ""; MPObject result = searchResult.FilteredResult; if (result is Area) { resultStr = (result as Area).ToString(); } else if (result is Route) { resultStr = (result as Route).ToString(resultParameters); } Console.WriteLine($"The following was found (found in {stopwatch.ElapsedMilliseconds} ms):"); Console.WriteLine(" " + resultStr); Console.WriteLine($" Location: {GetLocationString(result, searchResult.RelatedLocation)}"); Console.WriteLine("\nOpen result? (y/n) "); if (Console.ReadLine().ToLower() == "y") { Process.Start(result.URL); } } Console.WriteLine("\nSearch something else? (y/n) "); keepSearching = Console.ReadLine().ToLower() == "y"; } }
public static string GetLocationString(MPObject child, Area referenceLocation = null) { MPObject innerParent, outerParent; innerParent = null; outerParent = MountainProjectDataSearch.GetParent(child, 1); //Get state that route/area is in if (child is Route) { innerParent = MountainProjectDataSearch.GetParent(child, -2); //Get the "second to last" parent https://github.com/derekantrican/MountainProject/issues/12 if (innerParent.URL == outerParent.URL) { innerParent = MountainProjectDataSearch.GetParent(child, -1); } } else if (child is Area) { innerParent = MountainProjectDataSearch.GetParent(child, -1); //Get immediate parent } if (innerParent == null || //If "child" is a dest area, the parent will be "All Locations" which won't be in our directory innerParent.URL == Utilities.INTERNATIONALURL) //If "child" is an area like "Europe" { return(""); } if (outerParent.URL == Utilities.INTERNATIONALURL) //If this is international, get the country instead of the state (eg "China") { if (child.ParentUrls.Count > 3) { if (child.ParentUrls.Contains(Utilities.AUSTRALIAURL)) //Australia is both a continent and a country so it is an exception { outerParent = MountainProjectDataSearch.GetParent(child, 2); } else { outerParent = MountainProjectDataSearch.GetParent(child, 3); } } else { return(""); //Return a blank string if we are in an area like "China" (so we don't return a string like "China is located in Asia") } } if (referenceLocation != null) //Override the "innerParent" in situations where we want the location string to include the "insisted" location { //Only override if the location is not already present if (innerParent.URL != referenceLocation.URL && outerParent.URL != referenceLocation.URL) { innerParent = referenceLocation; } } string locationString = $"Located in {Markdown.Link(innerParent.Name, innerParent.URL)}"; if (outerParent != null && outerParent.URL != innerParent.URL) { locationString += $", {Markdown.Link(outerParent.Name, outerParent.URL)}"; } locationString += Markdown.NewLine; return(locationString); }