private static IEnumerable <string> _additionalPathsToInclude; // typically a problem image file public void RegisterWithApiHandler(BloomApiHandler apiHandler) { // This one is an exception: it's not used BY the problem report dialog, but to launch one // from Javascript. However, it also must not require the lock, because if it holds it, // no calls that need it can run (such as one put forth by the Cancel button). apiHandler.RegisterEndpointLegacy("problemReport/showDialog", HandleShowDialog, true, false); // Similarly, but this launches from a button shown in Book.ErrorDom apiHandler.RegisterEndpointHandler("problemReport/unreadableBook", HandleUnreadableBook, true, false); // For the paranoid - We could also have showProblemReport block these handlers while _reportInfo is being populated. // I think it's unnecessary since the problem report dialog's URL isn't even set until after the _reportInfo is populated, // and we assume that nothing sends problemReport API requests except the problemReportDialog that this class loads. // ProblemDialog.tsx uses this endpoint to get the string to show at the top of the main dialog apiHandler.RegisterEndpointHandlerUsedByOthers("problemReport/reportHeadingHtml", (ApiRequest request) => { request.ReplyWithText(_reportInfo.HeadingHtml ?? ""); }, false); // ProblemDialog.tsx uses this endpoint to get the screenshot image. apiHandler.RegisterEndpointHandlerUsedByOthers("problemReport/screenshot", (ApiRequest request) => { // Wait until the screenshot is finished. // If not available within the time limit, just continue anyway (so we don't deadlock or anything) and hope for the best. bool isLockTaken = _takingScreenshotLock.Wait(millisecondsTimeout: 5000); if (_reportInfo?.ScreenshotTempFile == null) { request.Failed(); } else { request.ReplyWithImage(_reportInfo.ScreenshotTempFile.Path); } if (isLockTaken) { _takingScreenshotLock.Release(); } }, true); // ProblemDialog.tsx uses this endpoint to get the name of the book. apiHandler.RegisterEndpointHandlerUsedByOthers("problemReport/bookName", (ApiRequest request) => { request.ReplyWithText(_reportInfo.BookName ?? "??"); }, true); // ProblemDialog.tsx uses this endpoint to get the registered user's email address. apiHandler.RegisterEndpointHandlerUsedByOthers("problemReport/emailAddress", (ApiRequest request) => { request.ReplyWithText(_reportInfo.UserEmail); }, true); // PrivacyScreen.tsx uses this endpoint to show the user what info will be included in the report. apiHandler.RegisterEndpointHandlerUsedByOthers("problemReport/diagnosticInfo", (ApiRequest request) => { var userWantsToIncludeBook = request.RequiredParam("includeBook") == "true"; var userInput = request.RequiredParam("userInput"); var userEmail = request.RequiredParam("email"); request.ReplyWithText(GetDiagnosticInfo(userWantsToIncludeBook, userInput, userEmail)); }, true); // ProblemDialog.tsx uses this endpoint in its AttemptSubmit method; // it expects a response that it will use to show the issue link to the user. apiHandler.RegisterEndpointHandlerUsedByOthers("problemReport/submit", (ApiRequest request) => { var report = DynamicJson.Parse(request.RequiredPostJson()); string issueLink = SubmitToYouTrack(report.kind, report.userInput, report.email, report.includeBook, report.includeScreenshot, null); object linkToNewIssue = new { issueLink }; request.ReplyWithJson(linkToNewIssue); }, true); }