From 9d586974e25a9584cf49b59fb9851b3cd9c1318c Mon Sep 17 00:00:00 2001 From: cryptooda Date: Tue, 28 Oct 2025 17:37:07 +0700 Subject: [PATCH] Add indicators request endpoint --- .../Controllers/TradingController.cs | 116 +++++++++++++++++- .../Models/Requests/IndicatorRequestDto.cs | 35 ++++++ src/Managing.Api/appsettings.json | 3 +- 3 files changed, 151 insertions(+), 3 deletions(-) create mode 100644 src/Managing.Api/Models/Requests/IndicatorRequestDto.cs diff --git a/src/Managing.Api/Controllers/TradingController.cs b/src/Managing.Api/Controllers/TradingController.cs index 55e33eae..3e3a9209 100644 --- a/src/Managing.Api/Controllers/TradingController.cs +++ b/src/Managing.Api/Controllers/TradingController.cs @@ -1,4 +1,5 @@ -using Managing.Application.Abstractions; +using Managing.Api.Models.Requests; +using Managing.Application.Abstractions; using Managing.Application.Abstractions.Services; using Managing.Application.Shared; using Managing.Application.Trading.Commands; @@ -29,6 +30,8 @@ public class TradingController : BaseController private readonly ILogger _logger; private readonly IAdminConfigurationService _adminService; private readonly IAccountService _accountService; + private readonly IHttpClientFactory _httpClientFactory; + private readonly IConfiguration _configuration; /// /// Initializes a new instance of the class. @@ -40,6 +43,8 @@ public class TradingController : BaseController /// Mediator for handling commands and requests. /// Service for checking admin privileges. /// Service for account operations. + /// HTTP client factory for making web requests. + /// Application configuration. public TradingController( ILogger logger, ICommandHandler openTradeCommandHandler, @@ -47,7 +52,9 @@ public class TradingController : BaseController ITradingService tradingService, IMediator mediator, IMoneyManagementService moneyManagementService, IUserService userService, IAdminConfigurationService adminService, - IAccountService accountService) : base(userService) + IAccountService accountService, + IHttpClientFactory httpClientFactory, + IConfiguration configuration) : base(userService) { _logger = logger; _openTradeCommandHandler = openTradeCommandHandler; @@ -57,6 +64,8 @@ public class TradingController : BaseController _moneyManagementService = moneyManagementService; _adminService = adminService; _accountService = accountService; + _httpClientFactory = httpClientFactory; + _configuration = configuration; } @@ -235,4 +244,107 @@ public class TradingController : BaseController return false; } } + + /// + /// Submits a request for a new indicator to be developed via N8n webhook. + /// + /// The indicator request details including name, strategy, documentation, and requester information. + /// A success response indicating the request was submitted. + [HttpPost("RequestIndicator")] + public async Task> RequestIndicator([FromBody] IndicatorRequestDto request) + { + if (request == null) + { + return BadRequest("Request cannot be null."); + } + + if (string.IsNullOrWhiteSpace(request.IndicatorName)) + { + return BadRequest("Indicator name is required."); + } + + if (string.IsNullOrWhiteSpace(request.StrategyDescription)) + { + return BadRequest("Strategy is required."); + } + + if (string.IsNullOrWhiteSpace(request.DocumentationUrl)) + { + return BadRequest("Documentation URL is required."); + } + + if (string.IsNullOrWhiteSpace(request.RequesterName)) + { + return BadRequest("Requester name is required."); + } + + try + { + var webhookUrl = _configuration["N8n:IndicatorRequestWebhookUrl"]; + + if (string.IsNullOrEmpty(webhookUrl)) + { + _logger.LogError("N8n indicator request webhook URL is not configured"); + return StatusCode(500, new { Success = false, Error = "Webhook URL is not configured." }); + } + + var httpClient = _httpClientFactory.CreateClient(); + + // Create multipart form data content + using var content = new MultipartFormDataContent(); + content.Add(new StringContent(request.IndicatorName), "field-0"); + content.Add(new StringContent(request.StrategyDescription), "field-1"); + content.Add(new StringContent(request.DocumentationUrl), "field-2"); + content.Add(new StringContent(request.ImageUrl ?? string.Empty), "field-3"); + content.Add(new StringContent(request.RequesterName), "field-4"); + + _logger.LogInformation( + "Submitting indicator request: {IndicatorName} - {Strategy} by {Requester}", + request.IndicatorName, + request.StrategyDescription, + request.RequesterName); + + var response = await httpClient.PostAsync(webhookUrl, content); + + if (response.IsSuccessStatusCode) + { + _logger.LogInformation( + "Successfully submitted indicator request: {IndicatorName} by {Requester}", + request.IndicatorName, + request.RequesterName); + + return Ok(new + { + Success = true, + Message = "Indicator request submitted successfully.", + IndicatorName = request.IndicatorName, + Strategy = request.StrategyDescription, + Requester = request.RequesterName + }); + } + else + { + var responseContent = await response.Content.ReadAsStringAsync(); + _logger.LogError( + "Failed to submit indicator request. Status: {StatusCode}, Response: {Response}", + response.StatusCode, + responseContent); + + return StatusCode(500, new + { + Success = false, + Error = $"Failed to submit indicator request. Status: {response.StatusCode}" + }); + } + } + catch (Exception ex) + { + _logger.LogError(ex, "Error submitting indicator request: {IndicatorName}", request.IndicatorName); + return StatusCode(500, new + { + Success = false, + Error = "An error occurred while submitting the indicator request." + }); + } + } } \ No newline at end of file diff --git a/src/Managing.Api/Models/Requests/IndicatorRequestDto.cs b/src/Managing.Api/Models/Requests/IndicatorRequestDto.cs new file mode 100644 index 00000000..39641206 --- /dev/null +++ b/src/Managing.Api/Models/Requests/IndicatorRequestDto.cs @@ -0,0 +1,35 @@ +#nullable enable + +namespace Managing.Api.Models.Requests; + +/// +/// Request model for submitting indicator requests to N8n webhook +/// +public class IndicatorRequestDto +{ + /// + /// Name of the indicator (e.g., "MACD", "RSI", "Bollinger Bands") + /// + public string IndicatorName { get; set; } = string.Empty; + + /// + /// Strategy or description of how the indicator is used (e.g., "MACD Cross", "RSI Divergence") + /// + public string StrategyDescription { get; set; } = string.Empty; + + /// + /// Primary documentation URL for the indicator + /// + public string DocumentationUrl { get; set; } = string.Empty; + + /// + /// Image URL for the indicator (optional) - can be a chart, diagram, or visual representation + /// + public string? ImageUrl { get; set; } + + /// + /// Name of the person requesting the indicator + /// + public string RequesterName { get; set; } = string.Empty; +} + diff --git a/src/Managing.Api/appsettings.json b/src/Managing.Api/appsettings.json index 90c938ee..816c0d50 100644 --- a/src/Managing.Api/appsettings.json +++ b/src/Managing.Api/appsettings.json @@ -32,7 +32,8 @@ "RefundEndpoint": "/api/credits/refund" }, "N8n": { - "WebhookUrl": "https://n8n.kai.managing.live/webhook/fa9308b6-983b-42ec-b085-71599d655951" + "WebhookUrl": "https://n8n.kai.managing.live/webhook/fa9308b6-983b-42ec-b085-71599d655951", + "IndicatorRequestWebhookUrl": "https://n8n.kai.managing.live/form-test/c7dd294c-004e-4c0f-b4ce-42cc19734e0e" }, "Sentry": { "Dsn": "https://fe12add48c56419bbdfa86227c188e7a@glitch.kai.managing.live/1",