add device token

This commit is contained in:
2025-12-19 11:07:31 +03:30
parent 74e8480a68
commit 10178de7c1
10 changed files with 2078 additions and 0 deletions

View File

@@ -0,0 +1,249 @@
using GreenHome.Application;
using GreenHome.Sms.Ippanel;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
namespace GreenHome.Infrastructure;
/// <summary>
/// سرویس مدیریت توکن و تنظیمات دستگاه
/// </summary>
public sealed class DeviceTokenService : IDeviceTokenService
{
private readonly GreenHomeDbContext dbContext;
private readonly ISmsService smsService;
private readonly ILogger<DeviceTokenService> logger;
public DeviceTokenService(
GreenHomeDbContext dbContext,
ISmsService smsService,
ILogger<DeviceTokenService> logger)
{
this.dbContext = dbContext;
this.smsService = smsService;
this.logger = logger;
}
/// <summary>
/// دریافت فاصله زمانی آپلود بر اساس شماره تلفن یا شناسه دستگاه
/// </summary>
public async Task<GetUploadIntervalResponse> GetUploadIntervalAsync(
GetUploadIntervalRequest request,
CancellationToken cancellationToken)
{
try
{
Domain.DeviceSettings? settings = null;
// جستجو بر اساس DeviceId یا DevicePhoneNumber
if (request.DeviceId.HasValue)
{
settings = await dbContext.DeviceSettings
.AsNoTracking()
.FirstOrDefaultAsync(ds => ds.DeviceId == request.DeviceId.Value, cancellationToken);
}
else if (!string.IsNullOrWhiteSpace(request.DevicePhoneNumber))
{
settings = await dbContext.DeviceSettings
.AsNoTracking()
.FirstOrDefaultAsync(ds => ds.DevicePhoneNumber == request.DevicePhoneNumber, cancellationToken);
}
if (settings == null)
{
return new GetUploadIntervalResponse
{
Success = false,
Message = "دستگاه یافت نشد"
};
}
return new GetUploadIntervalResponse
{
Success = true,
UploadIntervalMin = settings.UploadIntervalMin
};
}
catch (Exception ex)
{
logger.LogError(ex, "Error getting upload interval for device");
return new GetUploadIntervalResponse
{
Success = false,
Message = "خطا در دریافت اطلاعات"
};
}
}
/// <summary>
/// درخواست توکن دستگاه (تولید و ارسال کد)
/// </summary>
public async Task<RequestDeviceTokenResponse> RequestDeviceTokenAsync(
RequestDeviceTokenRequest request,
CancellationToken cancellationToken)
{
try
{
// پیدا کردن تنظیمات دستگاه بر اساس شماره تلفن
var settings = await dbContext.DeviceSettings
.FirstOrDefaultAsync(ds => ds.DevicePhoneNumber == request.DevicePhoneNumber, cancellationToken);
if (settings == null)
{
return new RequestDeviceTokenResponse
{
Success = false,
Message = "دستگاه با این شماره تلفن یافت نشد"
};
}
// تولید کد توکن 5 رقمی
var random = new Random();
var tokenCode = random.Next(10000, 99999).ToString();
// تولید کد تایید بر اساس فرمول: (TokenCode * 7 + 12345) % 100000
var verificationCode = ((int.Parse(tokenCode) * 7 + 12345) % 100000).ToString("D5");
// ذخیره کدها
settings.TokenCode = tokenCode;
settings.VerificationCode = verificationCode;
settings.TokenExpiresAt = DateTime.UtcNow.AddMinutes(10); // اعتبار 10 دقیقه
settings.UpdatedAt = DateTime.UtcNow;
await dbContext.SaveChangesAsync(cancellationToken);
// ارسال کد توکن از طریق پیامک
try
{
await smsService.SendWebserviceSmsAsync(new WebserviceSmsRequest
{
Recipient = request.DevicePhoneNumber,
Message = $"کد تایید دستگاه شما: {tokenCode}\nاعتبار: 10 دقیقه"
}, cancellationToken);
}
catch (Exception smsEx)
{
logger.LogError(smsEx, "Error sending token SMS to {PhoneNumber}", request.DevicePhoneNumber);
return new RequestDeviceTokenResponse
{
Success = false,
Message = "خطا در ارسال پیامک"
};
}
logger.LogInformation("Token requested for device phone {PhoneNumber}", request.DevicePhoneNumber);
return new RequestDeviceTokenResponse
{
Success = true,
Message = "کد تایید با موفقیت ارسال شد",
TokenCode = tokenCode
};
}
catch (Exception ex)
{
logger.LogError(ex, "Error requesting device token");
return new RequestDeviceTokenResponse
{
Success = false,
Message = "خطا در درخواست توکن"
};
}
}
/// <summary>
/// تایید توکن دستگاه (ارسال تنظیمات)
/// </summary>
public async Task<VerifyDeviceTokenResponse> VerifyDeviceTokenAsync(
VerifyDeviceTokenRequest request,
CancellationToken cancellationToken)
{
try
{
// پیدا کردن تنظیمات دستگاه
var settings = await dbContext.DeviceSettings
.Include(ds => ds.Device)
.FirstOrDefaultAsync(ds => ds.DevicePhoneNumber == request.DevicePhoneNumber, cancellationToken);
if (settings == null)
{
return new VerifyDeviceTokenResponse
{
Success = false,
Message = "دستگاه با این شماره تلفن یافت نشد"
};
}
// بررسی انقضای توکن
if (settings.TokenExpiresAt == null || settings.TokenExpiresAt < DateTime.UtcNow)
{
return new VerifyDeviceTokenResponse
{
Success = false,
Message = "کد تایید منقضی شده است"
};
}
// بررسی کد تایید
if (settings.VerificationCode != request.VerificationCode)
{
return new VerifyDeviceTokenResponse
{
Success = false,
Message = "کد تایید نادرست است"
};
}
// رمزگذاری ساده تنظیمات: DeviceName|UploadIntervalMin به Base64
var deviceName = settings.Device.DeviceName;
var uploadInterval = settings.UploadIntervalMin;
var plainText = $"{deviceName}|{uploadInterval}";
var encodedSettings = Convert.ToBase64String(System.Text.Encoding.UTF8.GetBytes(plainText));
// ارسال تنظیمات کدشده از طریق پیامک
try
{
await smsService.SendWebserviceSmsAsync(new WebserviceSmsRequest
{
Recipient = request.DevicePhoneNumber,
Message = $"تنظیمات دستگاه:\n{encodedSettings}"
}, cancellationToken);
}
catch (Exception smsEx)
{
logger.LogError(smsEx, "Error sending settings SMS to {PhoneNumber}", request.DevicePhoneNumber);
return new VerifyDeviceTokenResponse
{
Success = false,
Message = "خطا در ارسال پیامک"
};
}
// پاک کردن کدها بعد از استفاده موفق
settings.TokenCode = null;
settings.VerificationCode = null;
settings.TokenExpiresAt = null;
settings.UpdatedAt = DateTime.UtcNow;
await dbContext.SaveChangesAsync(cancellationToken);
logger.LogInformation("Device token verified for {PhoneNumber}", request.DevicePhoneNumber);
return new VerifyDeviceTokenResponse
{
Success = true,
Message = "تنظیمات با موفقیت ارسال شد",
EncodedSettings = encodedSettings
};
}
catch (Exception ex)
{
logger.LogError(ex, "Error verifying device token");
return new VerifyDeviceTokenResponse
{
Success = false,
Message = "خطا در تایید توکن"
};
}
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,81 @@
using System;
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace GreenHome.Infrastructure.Migrations
{
/// <inheritdoc />
public partial class AddDeviceTokenAndPhoneFields : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AddColumn<string>(
name: "DevicePhoneNumber",
table: "DeviceSettings",
type: "nvarchar(max)",
nullable: false,
defaultValue: "");
migrationBuilder.AddColumn<int>(
name: "SimCardType",
table: "DeviceSettings",
type: "int",
nullable: true);
migrationBuilder.AddColumn<string>(
name: "TokenCode",
table: "DeviceSettings",
type: "nvarchar(max)",
nullable: true);
migrationBuilder.AddColumn<DateTime>(
name: "TokenExpiresAt",
table: "DeviceSettings",
type: "datetime2",
nullable: true);
migrationBuilder.AddColumn<int>(
name: "UploadIntervalMin",
table: "DeviceSettings",
type: "int",
nullable: false,
defaultValue: 0);
migrationBuilder.AddColumn<string>(
name: "VerificationCode",
table: "DeviceSettings",
type: "nvarchar(max)",
nullable: true);
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropColumn(
name: "DevicePhoneNumber",
table: "DeviceSettings");
migrationBuilder.DropColumn(
name: "SimCardType",
table: "DeviceSettings");
migrationBuilder.DropColumn(
name: "TokenCode",
table: "DeviceSettings");
migrationBuilder.DropColumn(
name: "TokenExpiresAt",
table: "DeviceSettings");
migrationBuilder.DropColumn(
name: "UploadIntervalMin",
table: "DeviceSettings");
migrationBuilder.DropColumn(
name: "VerificationCode",
table: "DeviceSettings");
}
}
}

View File

@@ -590,6 +590,10 @@ namespace GreenHome.Infrastructure.Migrations
b.Property<int>("DeviceId")
.HasColumnType("int");
b.Property<string>("DevicePhoneNumber")
.IsRequired()
.HasColumnType("nvarchar(max)");
b.Property<decimal?>("Latitude")
.HasColumnType("decimal(9,6)");
@@ -616,9 +620,24 @@ namespace GreenHome.Infrastructure.Migrations
.HasMaxLength(100)
.HasColumnType("nvarchar(100)");
b.Property<int?>("SimCardType")
.HasColumnType("int");
b.Property<string>("TokenCode")
.HasColumnType("nvarchar(max)");
b.Property<DateTime?>("TokenExpiresAt")
.HasColumnType("datetime2");
b.Property<DateTime>("UpdatedAt")
.HasColumnType("datetime2");
b.Property<int>("UploadIntervalMin")
.HasColumnType("int");
b.Property<string>("VerificationCode")
.HasColumnType("nvarchar(max)");
b.HasKey("Id");
b.HasIndex("DeviceId")