add device token
This commit is contained in:
249
src/GreenHome.Infrastructure/DeviceTokenService.cs
Normal file
249
src/GreenHome.Infrastructure/DeviceTokenService.cs
Normal 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 = "خطا در تایید توکن"
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
1218
src/GreenHome.Infrastructure/Migrations/20251217154130_AddDeviceTokenAndPhoneFields.Designer.cs
generated
Normal file
1218
src/GreenHome.Infrastructure/Migrations/20251217154130_AddDeviceTokenAndPhoneFields.Designer.cs
generated
Normal file
File diff suppressed because it is too large
Load Diff
@@ -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");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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")
|
||||
|
||||
Reference in New Issue
Block a user