public static void LogOrUpdateSpreadsheet(ApprovalRequest approvalRequest) { if (string.IsNullOrEmpty(spreadsheetHistoryURL)) { return; } string locationString = Regex.Replace(BotReply.GetLocationString(approvalRequest.SearchResult.FilteredResult, approvalRequest.SearchResult.RelatedLocation), @"\[|\]\(.*?\)", "").Replace("Located in ", "").Replace("\n", ""); List <string> parameters = new List <string> { $"reason={(string.IsNullOrEmpty(approvalRequest.SearchResult.UnconfidentReason) ? "" : Uri.EscapeDataString(approvalRequest.SearchResult.UnconfidentReason))}", $"postTitle={Uri.EscapeDataString(WebUtility.HtmlDecode(approvalRequest.RedditPost.Title))}", $"postURL={Uri.EscapeDataString(approvalRequest.RedditPost.Shortlink)}", $"mpResultTitle={Uri.EscapeDataString(approvalRequest.SearchResult.FilteredResult.Name)}", $"mpResultLocation={Uri.EscapeDataString(locationString)}", $"mpResultURL={Uri.EscapeDataString(approvalRequest.SearchResult.FilteredResult.URL)}", $"mpResultID={Uri.EscapeDataString(approvalRequest.SearchResult.FilteredResult.ID)}", }; if (approvalRequest.SearchResult.FilteredResult is Route route) { parameters.Add($"mpResultGrade={Uri.EscapeDataString(route.GetRouteGrade(Grade.GradeSystem.YDS).ToString(false))}"); } if (approvalRequest.SearchResult.Confidence == 1 || approvalRequest.IsApproved) { parameters.Add("alreadyApproved=true"); } DoPOST(spreadsheetHistoryURL, parameters); }
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>")); }
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 static void RequestApproval(ApprovalRequest approvalRequest) { if (string.IsNullOrEmpty(requestForApprovalURL) || string.IsNullOrEmpty(WebServerURL)) { return; } Post post = approvalRequest.RedditPost; SearchResult searchResult = approvalRequest.SearchResult; string messageText = "--------------------------------\n" + $"**Possible AutoReply found:**\n" + $"{searchResult.UnconfidentReason}\n\n" + $"**PostTitle:** {post.Title}\n" + $"**PostURL:** <{post.Shortlink}>\n\n"; if (searchResult.AllResults.Count > 1) { messageText += $"**All results found:**\n"; foreach (MPObject result in searchResult.AllResults /*Todo: Make sure this is ordered by the likely response*/) { messageText += $"\t- [{result.Name} ({(result as Route).GetRouteGrade(Grade.GradeSystem.YDS).ToString(false)})](<{result.URL}>)\n"; } messageText += "\n" + $"**Filtered Result:** [{searchResult.FilteredResult.Name} ({(searchResult.FilteredResult as Route).GetRouteGrade(Grade.GradeSystem.YDS).ToString(false)})](<{searchResult.FilteredResult.URL}>)\n" + $"{Regex.Replace(BotReply.GetLocationString(searchResult.FilteredResult, searchResult.RelatedLocation), @"\[|\]\(.*?\)", "").Replace("Located in ", "").Replace("\n", "")}\n\n" + $"[[APPROVE FILTERED]](<{ApprovalServerUrl}?approve&postid={post.Id}>) " + $"[[APPROVE ALL]](<{ApprovalServerUrl}?approveall&postid={post.Id}>) " + $"[[APPROVE OTHER]](<{ApprovalServerUrl}?approveother&postid={post.Id}>)"; } else { messageText += $"**MPResult:** {searchResult.FilteredResult.Name} ({(searchResult.FilteredResult as Route).GetRouteGrade(Grade.GradeSystem.YDS).ToString(false)})\n" + $"{Regex.Replace(BotReply.GetLocationString(searchResult.FilteredResult, searchResult.RelatedLocation), @"\[|\]\(.*?\)", "").Replace("Located in ", "").Replace("\n", "")}\n" + $"<{searchResult.FilteredResult.URL}>\n\n" + $"[[APPROVE]](<{ApprovalServerUrl}?approve&postid={post.Id}>) " + $"[[APPROVE OTHER]](<{ApprovalServerUrl}?approveother&postid={post.Id}>)"; } messageText += "\n--------------------------------"; SendDiscordMessage(messageText); }
private static string ShowApproveOtherPicker(Dictionary <string, string> parameters, ApprovalRequest approvalRequest) { string htmlPicker = "<form>"; foreach (MPObject option in approvalRequest.SearchResult.AllResults) { htmlPicker += $"<input type=\"radio\" name=\"options\" value=\"{option.ID}\"{(approvalRequest.SearchResult.AllResults.IndexOf(option) == 0 ? " checked=\"true\"" : "")}>" + $"<a href=\"{option.URL}\">{option.Name} ({(option as Route).GetRouteGrade(Grade.GradeSystem.YDS).ToString(false)})</a>" + $" ({Regex.Replace(BotReply.GetLocationString(option, approvalRequest.SearchResult.RelatedLocation), @"\[|\]\(.*?\)", "").Replace("\n", "")})<br>"; } htmlPicker += "<input type=\"radio\" name=\"options\" id=\"other_option\">Other: <input type=\"text\" id=\"other_option_value\" size=\"100\"> (separate multiple urls with semicolons)" + "<br><input type=\"button\" onclick=\"choose()\" value=\"Choose\"></form><script>" + "function choose(){" + " var options = document.forms[0];" + " for (var i = 0; i < options.length; i++){" + " if (options[i].checked){" + " var chosen = options[i].id != \"other_option\" ? options[i].value : document.getElementById(\"other_option_value\").value.match(/(?<=\\/)\\d+(?=\\/)/g);" + $" window.location.replace(\"{BotUtilities.ApprovalServerUrl}?approveother&postid={parameters["postid"]}{(parameters.ContainsKey("force") ? "&force" : "")}&option=\" + chosen);" + " break;" + " }" + " }" + "}" + "</script>"; return(WrapHtml(htmlPicker)); }
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}"); } } }