Update bot messages
This commit is contained in:
@@ -17,6 +17,7 @@ public class UserController : BaseController
|
|||||||
{
|
{
|
||||||
private IConfiguration _config;
|
private IConfiguration _config;
|
||||||
private readonly IJwtUtils _jwtUtils;
|
private readonly IJwtUtils _jwtUtils;
|
||||||
|
private readonly IWebhookService _webhookService;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes a new instance of the <see cref="UserController"/> class.
|
/// Initializes a new instance of the <see cref="UserController"/> class.
|
||||||
@@ -24,11 +25,13 @@ public class UserController : BaseController
|
|||||||
/// <param name="config">Configuration settings.</param>
|
/// <param name="config">Configuration settings.</param>
|
||||||
/// <param name="userService">Service for user-related operations.</param>
|
/// <param name="userService">Service for user-related operations.</param>
|
||||||
/// <param name="jwtUtils">Utility for JWT token operations.</param>
|
/// <param name="jwtUtils">Utility for JWT token operations.</param>
|
||||||
public UserController(IConfiguration config, IUserService userService, IJwtUtils jwtUtils)
|
/// <param name="webhookService">Service for webhook operations.</param>
|
||||||
|
public UserController(IConfiguration config, IUserService userService, IJwtUtils jwtUtils, IWebhookService webhookService)
|
||||||
: base(userService)
|
: base(userService)
|
||||||
{
|
{
|
||||||
_config = config;
|
_config = config;
|
||||||
_jwtUtils = jwtUtils;
|
_jwtUtils = jwtUtils;
|
||||||
|
_webhookService = webhookService;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -98,7 +101,74 @@ public class UserController : BaseController
|
|||||||
{
|
{
|
||||||
var user = await GetUser();
|
var user = await GetUser();
|
||||||
var updatedUser = await _userService.UpdateTelegramChannel(user, telegramChannel);
|
var updatedUser = await _userService.UpdateTelegramChannel(user, telegramChannel);
|
||||||
|
|
||||||
|
// Send welcome message to the newly configured telegram channel
|
||||||
|
if (!string.IsNullOrEmpty(telegramChannel))
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var welcomeMessage = $"🎉 **Trading Bot - Welcome!**\n\n" +
|
||||||
|
$"┌─────────────────────────────┐\n" +
|
||||||
|
$"│ CHANNEL CONFIGURED ✅ │\n" +
|
||||||
|
$"└─────────────────────────────┘\n\n" +
|
||||||
|
$"🎯 **Agent:** {user.Name}\n" +
|
||||||
|
$"📡 **Channel ID:** {telegramChannel}\n" +
|
||||||
|
$"⏰ **Setup Time:** {DateTime.UtcNow:MMM dd, yyyy • HH:mm:ss} UTC\n\n" +
|
||||||
|
$"🔔 **Notification Types:**\n" +
|
||||||
|
$"• 📈 Position Opens & Closes\n" +
|
||||||
|
$"• 🤖 Bot configuration changes\n\n" +
|
||||||
|
$"━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n" +
|
||||||
|
$"🚀 **Welcome aboard!** Your trading notifications are now live.";
|
||||||
|
|
||||||
|
await _webhookService.SendMessage(welcomeMessage, telegramChannel);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
// Log the error but don't fail the update operation
|
||||||
|
Console.WriteLine($"Failed to send welcome message to telegram channel {telegramChannel}: {ex.Message}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return Ok(updatedUser);
|
return Ok(updatedUser);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Tests the Telegram channel configuration by sending a test message.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>A message indicating the test result.</returns>
|
||||||
|
[HttpPost("telegram-channel/test")]
|
||||||
|
public async Task<ActionResult<string>> TestTelegramChannel()
|
||||||
|
{
|
||||||
|
var user = await GetUser();
|
||||||
|
|
||||||
|
if (string.IsNullOrEmpty(user.TelegramChannel))
|
||||||
|
{
|
||||||
|
return BadRequest("No Telegram channel configured for this user. Please set a Telegram channel first.");
|
||||||
|
}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var testMessage = $"🚀 **Trading Bot - Channel Test**\n\n" +
|
||||||
|
$"┌─────────────────────────────┐\n" +
|
||||||
|
$"│ CONNECTION SUCCESSFUL ✅ │\n" +
|
||||||
|
$"└─────────────────────────────┘\n\n" +
|
||||||
|
$"🎯 **Agent:** {user.Name}\n" +
|
||||||
|
$"📡 **Channel ID:** {user.TelegramChannel}\n" +
|
||||||
|
$"⏰ **Test Time:** {DateTime.UtcNow:MMM dd, yyyy • HH:mm:ss} UTC\n\n" +
|
||||||
|
$"🔔 **You will receive notifications for:**\n" +
|
||||||
|
$"• 📈 Position Opens & Closes\n" +
|
||||||
|
$"• 🤖 Bot configuration changes\n\n" +
|
||||||
|
$"━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n" +
|
||||||
|
$"🎉 **Ready to trade!** Your notifications are now active.";
|
||||||
|
|
||||||
|
await _webhookService.SendMessage(testMessage, user.TelegramChannel);
|
||||||
|
|
||||||
|
return Ok($"Test message sent successfully to Telegram channel {user.TelegramChannel}. Please check your Telegram to verify delivery.");
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
return StatusCode(500, $"Failed to send test message: {ex.Message}");
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -188,6 +188,18 @@ namespace Managing.Application.ManageBot
|
|||||||
{
|
{
|
||||||
await Task.Run(() =>
|
await Task.Run(() =>
|
||||||
bot.Stop()); // Assuming Stop is an asynchronous process wrapped in Task.Run for synchronous methods
|
bot.Stop()); // Assuming Stop is an asynchronous process wrapped in Task.Run for synchronous methods
|
||||||
|
|
||||||
|
var stopMessage = $"🛑 **Bot Stopped**\n\n" +
|
||||||
|
$"┌─────────────────────────────┐\n" +
|
||||||
|
$"│ BOT STOPPED 🔴 │\n" +
|
||||||
|
$"└─────────────────────────────┘\n\n" +
|
||||||
|
$"🎯 **Agent:** {bot.User.AgentName}\n" +
|
||||||
|
$"🤖 **Bot Name:** {bot.Name}\n" +
|
||||||
|
$"⏰ **Stopped At:** {DateTime.UtcNow:MMM dd, yyyy • HH:mm:ss} UTC\n\n" +
|
||||||
|
$"━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n" +
|
||||||
|
$"✅ **Bot has been safely stopped and is no longer active.**";
|
||||||
|
|
||||||
|
await _messengerService.SendTradeMessage(stopMessage, false, bot.User);
|
||||||
return bot.GetStatus();
|
return bot.GetStatus();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -205,6 +217,18 @@ namespace Managing.Application.ManageBot
|
|||||||
{
|
{
|
||||||
await Task.Run(() =>
|
await Task.Run(() =>
|
||||||
bot.Stop()); // Assuming Stop is an asynchronous process wrapped in Task.Run for synchronous methods
|
bot.Stop()); // Assuming Stop is an asynchronous process wrapped in Task.Run for synchronous methods
|
||||||
|
|
||||||
|
var deleteMessage = $"🗑️ **Bot Deleted**\n\n" +
|
||||||
|
$"┌─────────────────────────────┐\n" +
|
||||||
|
$"│ BOT DELETED ❌ │\n" +
|
||||||
|
$"└─────────────────────────────┘\n\n" +
|
||||||
|
$"🎯 **Agent:** {bot.User.AgentName}\n" +
|
||||||
|
$"🤖 **Bot Name:** {bot.Name}\n" +
|
||||||
|
$"⏰ **Deleted At:** {DateTime.UtcNow:MMM dd, yyyy • HH:mm:ss} UTC\n\n" +
|
||||||
|
$"━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n" +
|
||||||
|
$"⚠️ **Bot has been permanently deleted and all data removed.**";
|
||||||
|
|
||||||
|
await _messengerService.SendTradeMessage(deleteMessage, false, bot.User);
|
||||||
}
|
}
|
||||||
|
|
||||||
await _botRepository.DeleteBotBackup(identifier);
|
await _botRepository.DeleteBotBackup(identifier);
|
||||||
@@ -220,18 +244,30 @@ namespace Managing.Application.ManageBot
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Task<string> RestartBot(string identifier)
|
public async Task<string> RestartBot(string identifier)
|
||||||
{
|
{
|
||||||
if (_botTasks.TryGetValue(identifier, out var botWrapper))
|
if (_botTasks.TryGetValue(identifier, out var botWrapper))
|
||||||
{
|
{
|
||||||
if (botWrapper.BotInstance is IBot bot)
|
if (botWrapper.BotInstance is IBot bot)
|
||||||
{
|
{
|
||||||
bot.Restart();
|
bot.Restart();
|
||||||
return Task.FromResult(bot.GetStatus());
|
|
||||||
|
var restartMessage = $"🔄 **Bot Restarted**\n\n" +
|
||||||
|
$"┌─────────────────────────────┐\n" +
|
||||||
|
$"│ BOT RESTARTED 🟢 │\n" +
|
||||||
|
$"└─────────────────────────────┘\n\n" +
|
||||||
|
$"🎯 **Agent:** {bot.User.AgentName}\n" +
|
||||||
|
$"🤖 **Bot Name:** {bot.Name}\n" +
|
||||||
|
$"⏰ **Restarted At:** {DateTime.UtcNow:MMM dd, yyyy • HH:mm:ss} UTC\n\n" +
|
||||||
|
$"━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n" +
|
||||||
|
$"🚀 **Bot has been successfully restarted and is now active.**";
|
||||||
|
|
||||||
|
await _messengerService.SendTradeMessage(restartMessage, false, bot.User);
|
||||||
|
return bot.GetStatus();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return Task.FromResult(BotStatus.Down.ToString());
|
return BotStatus.Down.ToString();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void ToggleIsForWatchingOnly(string identifier)
|
public void ToggleIsForWatchingOnly(string identifier)
|
||||||
|
|||||||
@@ -68,6 +68,11 @@ public class MessengerService : IMessengerService
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async Task SendMessage(string message, string telegramChannel)
|
||||||
|
{
|
||||||
|
await _webhookService.SendMessage(message, telegramChannel);
|
||||||
|
}
|
||||||
|
|
||||||
private string BuildPositionMessage(Position position)
|
private string BuildPositionMessage(Position position)
|
||||||
{
|
{
|
||||||
var direction = position.OriginDirection.ToString();
|
var direction = position.OriginDirection.ToString();
|
||||||
|
|||||||
@@ -77,7 +77,7 @@ public class WebhookService : IWebhookService
|
|||||||
message = message,
|
message = message,
|
||||||
timestamp = DateTime.UtcNow,
|
timestamp = DateTime.UtcNow,
|
||||||
type = "general_message",
|
type = "general_message",
|
||||||
telegramChannel = telegramChannel
|
telegramChannel = FormatTelegramChannel(telegramChannel)
|
||||||
};
|
};
|
||||||
|
|
||||||
// Send the webhook notification
|
// Send the webhook notification
|
||||||
@@ -97,4 +97,23 @@ public class WebhookService : IWebhookService
|
|||||||
_logger.LogError(ex, "Error sending webhook message");
|
_logger.LogError(ex, "Error sending webhook message");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private string FormatTelegramChannel(string? telegramChannel)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrEmpty(telegramChannel))
|
||||||
|
{
|
||||||
|
return string.Empty;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (telegramChannel.StartsWith("100"))
|
||||||
|
{
|
||||||
|
return telegramChannel.Substring(3);
|
||||||
|
}
|
||||||
|
else if (telegramChannel.StartsWith("-100"))
|
||||||
|
{
|
||||||
|
return telegramChannel.Substring(4);
|
||||||
|
}
|
||||||
|
|
||||||
|
return telegramChannel;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -2598,6 +2598,41 @@ export class UserClient extends AuthorizedApiBase {
|
|||||||
}
|
}
|
||||||
return Promise.resolve<User>(null as any);
|
return Promise.resolve<User>(null as any);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
user_TestTelegramChannel(): Promise<string> {
|
||||||
|
let url_ = this.baseUrl + "/User/telegram-channel/test";
|
||||||
|
url_ = url_.replace(/[?&]$/, "");
|
||||||
|
|
||||||
|
let options_: RequestInit = {
|
||||||
|
method: "POST",
|
||||||
|
headers: {
|
||||||
|
"Accept": "application/json"
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return this.transformOptions(options_).then(transformedOptions_ => {
|
||||||
|
return this.http.fetch(url_, transformedOptions_);
|
||||||
|
}).then((_response: Response) => {
|
||||||
|
return this.processUser_TestTelegramChannel(_response);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
protected processUser_TestTelegramChannel(response: Response): Promise<string> {
|
||||||
|
const status = response.status;
|
||||||
|
let _headers: any = {}; if (response.headers && response.headers.forEach) { response.headers.forEach((v: any, k: any) => _headers[k] = v); };
|
||||||
|
if (status === 200) {
|
||||||
|
return response.text().then((_responseText) => {
|
||||||
|
let result200: any = null;
|
||||||
|
result200 = _responseText === "" ? null : JSON.parse(_responseText, this.jsonParseReviver) as string;
|
||||||
|
return result200;
|
||||||
|
});
|
||||||
|
} else if (status !== 200 && status !== 204) {
|
||||||
|
return response.text().then((_responseText) => {
|
||||||
|
return throwException("An unexpected server error occurred.", status, _responseText, _headers);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return Promise.resolve<string>(null as any);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class WorkflowClient extends AuthorizedApiBase {
|
export class WorkflowClient extends AuthorizedApiBase {
|
||||||
|
|||||||
@@ -88,6 +88,24 @@ function UserInfoSettings() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const testTelegramChannel = async () => {
|
||||||
|
if (!user?.telegramChannel) {
|
||||||
|
const toast = new Toast('No telegram channel configured')
|
||||||
|
toast.update('error', 'Please configure a telegram channel first')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const toast = new Toast('Testing telegram channel...')
|
||||||
|
try {
|
||||||
|
const response = await api.user_TestTelegramChannel()
|
||||||
|
toast.update('success', 'Test message sent! Check your Telegram.')
|
||||||
|
} catch (error: any) {
|
||||||
|
console.error('Error testing telegram channel:', error)
|
||||||
|
const errorMessage = error.response?.data || error.message || 'Failed to send test message'
|
||||||
|
toast.update('error', errorMessage)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="container mx-auto p-4">
|
<div className="container mx-auto p-4">
|
||||||
<div className="bg-base-200 rounded-lg p-6 shadow-lg">
|
<div className="bg-base-200 rounded-lg p-6 shadow-lg">
|
||||||
@@ -136,12 +154,22 @@ function UserInfoSettings() {
|
|||||||
<div>
|
<div>
|
||||||
<label className="font-semibold">Telegram Channel:</label>
|
<label className="font-semibold">Telegram Channel:</label>
|
||||||
<p>{user?.telegramChannel || 'Not set'}</p>
|
<p>{user?.telegramChannel || 'Not set'}</p>
|
||||||
|
<div className="flex gap-2 mt-2">
|
||||||
<button
|
<button
|
||||||
className="btn btn-primary mt-2"
|
className="btn btn-primary"
|
||||||
onClick={() => setShowTelegramModal(true)}
|
onClick={() => setShowTelegramModal(true)}
|
||||||
>
|
>
|
||||||
Update Telegram Channel
|
Update Telegram Channel
|
||||||
</button>
|
</button>
|
||||||
|
{user?.telegramChannel && (
|
||||||
|
<button
|
||||||
|
className="btn btn-secondary"
|
||||||
|
onClick={testTelegramChannel}
|
||||||
|
>
|
||||||
|
Test Channel
|
||||||
|
</button>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Reference in New Issue
Block a user