add voice service call service and more
This commit is contained in:
319
src/GreenHome.Infrastructure/AlertService.cs
Normal file
319
src/GreenHome.Infrastructure/AlertService.cs
Normal file
@@ -0,0 +1,319 @@
|
||||
using GreenHome.Application;
|
||||
using GreenHome.Sms.Ippanel;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using System.Text.Json;
|
||||
using static GreenHome.Sms.Ippanel.IppanelSmsService;
|
||||
|
||||
namespace GreenHome.Infrastructure;
|
||||
|
||||
public sealed class AlertService : IAlertService
|
||||
{
|
||||
private readonly GreenHomeDbContext dbContext;
|
||||
private readonly IDeviceSettingsService deviceSettingsService;
|
||||
private readonly ISmsService smsService;
|
||||
private readonly ILogger<AlertService> logger;
|
||||
private const int AlertCooldownMinutes = 10;
|
||||
|
||||
private sealed record AlertInfo(
|
||||
string Type,
|
||||
string Message,
|
||||
string ParameterName,
|
||||
decimal Value,
|
||||
string Status
|
||||
);
|
||||
|
||||
public AlertService(
|
||||
GreenHomeDbContext dbContext,
|
||||
IDeviceSettingsService deviceSettingsService,
|
||||
ISmsService smsService,
|
||||
ILogger<AlertService> logger)
|
||||
{
|
||||
this.dbContext = dbContext;
|
||||
this.deviceSettingsService = deviceSettingsService;
|
||||
this.smsService = smsService;
|
||||
this.logger = logger;
|
||||
}
|
||||
|
||||
public async Task CheckAndSendAlertsAsync(int deviceId, TelemetryDto telemetry, CancellationToken cancellationToken)
|
||||
{
|
||||
var settings = await deviceSettingsService.GetByDeviceIdAsync(deviceId, cancellationToken);
|
||||
if (settings == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var device = await dbContext.Devices
|
||||
.Include(d => d.User)
|
||||
.FirstOrDefaultAsync(d => d.Id == deviceId, cancellationToken);
|
||||
|
||||
if (device == null || device.User == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var alerts = CollectAlerts(telemetry, settings, device.DeviceName);
|
||||
|
||||
foreach (var alert in alerts)
|
||||
{
|
||||
await SendAlertIfNeededAsync(deviceId, device.User.Id, device.DeviceName, alert, cancellationToken);
|
||||
}
|
||||
}
|
||||
|
||||
private List<AlertInfo> CollectAlerts(TelemetryDto telemetry, DeviceSettingsDto settings, string deviceName)
|
||||
{
|
||||
var alerts = new List<AlertInfo>();
|
||||
|
||||
CheckTemperatureAlert(telemetry, settings, deviceName, alerts);
|
||||
CheckHumidityAlert(telemetry, settings, deviceName, alerts);
|
||||
CheckSoilAlert(telemetry, deviceName, alerts);
|
||||
CheckGasAlert(telemetry, settings, deviceName, alerts);
|
||||
CheckLuxAlert(telemetry, settings, deviceName, alerts);
|
||||
|
||||
return alerts;
|
||||
}
|
||||
|
||||
private void CheckTemperatureAlert(TelemetryDto telemetry, DeviceSettingsDto settings, string deviceName, List<AlertInfo> alerts)
|
||||
{
|
||||
if (telemetry.TemperatureC > settings.MaxTemperature)
|
||||
{
|
||||
alerts.Add(new AlertInfo(
|
||||
Type: "Temperature",
|
||||
Message: $"هشدار: دمای گلخانه {deviceName} به {telemetry.TemperatureC} درجه رسیده که از حداکثر مجاز ({settings.MaxTemperature}) بیشتر است.",
|
||||
ParameterName: "دما",
|
||||
Value: telemetry.TemperatureC,
|
||||
Status: "بالاتر"
|
||||
));
|
||||
}
|
||||
else if (telemetry.TemperatureC < settings.MinTemperature)
|
||||
{
|
||||
alerts.Add(new AlertInfo(
|
||||
Type: "Temperature",
|
||||
Message: $"هشدار: دمای گلخانه {deviceName} به {telemetry.TemperatureC} درجه رسیده که از حداقل مجاز ({settings.MinTemperature}) کمتر است.",
|
||||
ParameterName: "دما",
|
||||
Value: telemetry.TemperatureC,
|
||||
Status: "پایینتر"
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
private void CheckHumidityAlert(TelemetryDto telemetry, DeviceSettingsDto settings, string deviceName, List<AlertInfo> alerts)
|
||||
{
|
||||
if (telemetry.HumidityPercent > settings.MaxHumidityPercent)
|
||||
{
|
||||
alerts.Add(new AlertInfo(
|
||||
Type: "Humidity",
|
||||
Message: $"هشدار: رطوبت گلخانه {deviceName} به {telemetry.HumidityPercent}% رسیده که از حداکثر مجاز ({settings.MaxHumidityPercent}%) بیشتر است.",
|
||||
ParameterName: "رطوبت",
|
||||
Value: telemetry.HumidityPercent,
|
||||
Status: "بالاتر"
|
||||
));
|
||||
}
|
||||
else if (telemetry.HumidityPercent < settings.MinHumidityPercent)
|
||||
{
|
||||
alerts.Add(new AlertInfo(
|
||||
Type: "Humidity",
|
||||
Message: $"هشدار: رطوبت گلخانه {deviceName} به {telemetry.HumidityPercent}% رسیده که از حداقل مجاز ({settings.MinHumidityPercent}%) کمتر است.",
|
||||
ParameterName: "رطوبت",
|
||||
Value: telemetry.HumidityPercent,
|
||||
Status: "پایینتر"
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
private void CheckSoilAlert(TelemetryDto telemetry, string deviceName, List<AlertInfo> alerts)
|
||||
{
|
||||
if (telemetry.SoilPercent > 100)
|
||||
{
|
||||
alerts.Add(new AlertInfo(
|
||||
Type: "Soil",
|
||||
Message: $"هشدار: رطوبت خاک گلخانه {deviceName} مقدار نامعتبر ({telemetry.SoilPercent}%) دارد.",
|
||||
ParameterName: "رطوبت خاک",
|
||||
Value: telemetry.SoilPercent,
|
||||
Status: "بالاتر"
|
||||
));
|
||||
}
|
||||
else if (telemetry.SoilPercent < 0)
|
||||
{
|
||||
alerts.Add(new AlertInfo(
|
||||
Type: "Soil",
|
||||
Message: $"هشدار: رطوبت خاک گلخانه {deviceName} مقدار نامعتبر ({telemetry.SoilPercent}%) دارد.",
|
||||
ParameterName: "رطوبت خاک",
|
||||
Value: telemetry.SoilPercent,
|
||||
Status: "پایینتر"
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
private void CheckGasAlert(TelemetryDto telemetry, DeviceSettingsDto settings, string deviceName, List<AlertInfo> alerts)
|
||||
{
|
||||
if (telemetry.GasPPM > settings.MaxGasPPM)
|
||||
{
|
||||
alerts.Add(new AlertInfo(
|
||||
Type: "Gas",
|
||||
Message: $"هشدار: گاز گلخانه {deviceName} به {telemetry.GasPPM} PPM رسیده که از حداکثر مجاز ({settings.MaxGasPPM}) بیشتر است.",
|
||||
ParameterName: "گاز Co",
|
||||
Value: telemetry.GasPPM,
|
||||
Status: "بالاتر"
|
||||
));
|
||||
}
|
||||
else if (telemetry.GasPPM < settings.MinGasPPM)
|
||||
{
|
||||
alerts.Add(new AlertInfo(
|
||||
Type: "Gas",
|
||||
Message: $"هشدار: گاز گلخانه {deviceName} به {telemetry.GasPPM} PPM رسیده که از حداقل مجاز ({settings.MinGasPPM}) کمتر است.",
|
||||
ParameterName: "گاز Co",
|
||||
Value: telemetry.GasPPM,
|
||||
Status: "پایینتر"
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
private void CheckLuxAlert(TelemetryDto telemetry, DeviceSettingsDto settings, string deviceName, List<AlertInfo> alerts)
|
||||
{
|
||||
if (telemetry.Lux > settings.MaxLux)
|
||||
{
|
||||
alerts.Add(new AlertInfo(
|
||||
Type: "Lux",
|
||||
Message: $"هشدار: نور گلخانه {deviceName} به {telemetry.Lux} لوکس رسیده که از حداکثر مجاز ({settings.MaxLux}) بیشتر است.",
|
||||
ParameterName: "نور",
|
||||
Value: telemetry.Lux,
|
||||
Status: "بالاتر"
|
||||
));
|
||||
}
|
||||
else if (telemetry.Lux < settings.MinLux)
|
||||
{
|
||||
alerts.Add(new AlertInfo(
|
||||
Type: "Lux",
|
||||
Message: $"هشدار: نور گلخانه {deviceName} به {telemetry.Lux} لوکس رسیده که از حداقل مجاز ({settings.MinLux}) کمتر است.",
|
||||
ParameterName: "نور",
|
||||
Value: telemetry.Lux,
|
||||
Status: "پایینتر"
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
private async Task SendAlertIfNeededAsync(
|
||||
int deviceId,
|
||||
int userId,
|
||||
string deviceName,
|
||||
AlertInfo alert,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
// Check if alert was sent in the last 10 minutes
|
||||
var cooldownTime = DateTime.UtcNow.AddMinutes(-AlertCooldownMinutes);
|
||||
var recentAlert = await dbContext.AlertNotifications
|
||||
.Where(a => a.DeviceId == deviceId &&
|
||||
a.UserId == userId &&
|
||||
a.AlertType == alert.Type &&
|
||||
a.SentAt >= cooldownTime)
|
||||
.FirstOrDefaultAsync(cancellationToken);
|
||||
|
||||
if (recentAlert != null)
|
||||
{
|
||||
logger.LogInformation("Alert skipped due to cooldown: DeviceId={DeviceId}, AlertType={AlertType}", deviceId, alert.Type);
|
||||
return;
|
||||
}
|
||||
|
||||
// Get user to send SMS
|
||||
var user = await dbContext.Users
|
||||
.FirstOrDefaultAsync(u => u.Id == userId, cancellationToken);
|
||||
|
||||
if (user == null || string.IsNullOrWhiteSpace(user.Mobile))
|
||||
{
|
||||
logger.LogWarning("User not found or mobile is empty: UserId={UserId}", userId);
|
||||
return;
|
||||
}
|
||||
|
||||
// Send SMS and collect response/errors
|
||||
string? messageOutboxIdsJson = null;
|
||||
string? errorMessage = null;
|
||||
bool isSent = false;
|
||||
|
||||
try
|
||||
{
|
||||
var smsResponse = await smsService.SendPatternSmsAsync(new PatternSmsRequest
|
||||
{
|
||||
Recipients = [user.Mobile],
|
||||
PatternCode = "64di3w9kb0fxvif",
|
||||
Variables = new Dictionary<string, string> {
|
||||
{ "name", deviceName },
|
||||
{ "parameter", alert.ParameterName },
|
||||
{ "value", alert.Value.ToString("F1") },
|
||||
{ "status", alert.Status },
|
||||
}
|
||||
}, cancellationToken);
|
||||
|
||||
if (smsResponse != null)
|
||||
{
|
||||
// Check if SMS was sent successfully
|
||||
if (smsResponse.Meta.Status && smsResponse.Data != null && smsResponse.Data.MessageOutboxIds != null && smsResponse.Data.MessageOutboxIds.Count > 0)
|
||||
{
|
||||
// Success - save message outbox IDs
|
||||
messageOutboxIdsJson = JsonSerializer.Serialize(smsResponse.Data.MessageOutboxIds);
|
||||
isSent = true;
|
||||
logger.LogInformation("Alert SMS sent: DeviceId={DeviceId}, UserId={UserId}, AlertType={AlertType}, OutboxIds={OutboxIds}",
|
||||
deviceId, userId, alert.Type, messageOutboxIdsJson);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Failed - save error from meta
|
||||
var errors = new List<string>();
|
||||
if (!string.IsNullOrWhiteSpace(smsResponse.Meta.Message))
|
||||
{
|
||||
errors.Add(smsResponse.Meta.Message);
|
||||
}
|
||||
if (smsResponse.Meta.Errors != null && smsResponse.Meta.Errors.Count > 0)
|
||||
{
|
||||
foreach (var error in smsResponse.Meta.Errors)
|
||||
{
|
||||
errors.Add($"{error.Key}: {string.Join(", ", error.Value)}");
|
||||
}
|
||||
}
|
||||
if (errors.Count == 0)
|
||||
{
|
||||
errors.Add("SMS sending failed with unknown error");
|
||||
}
|
||||
errorMessage = string.Join(" | ", errors);
|
||||
isSent = false;
|
||||
logger.LogWarning("Alert SMS failed: DeviceId={DeviceId}, UserId={UserId}, AlertType={AlertType}, Error={Error}",
|
||||
deviceId, userId, alert.Type, errorMessage);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
errorMessage = "SMS service returned null response";
|
||||
isSent = false;
|
||||
logger.LogWarning("Alert SMS returned null: DeviceId={DeviceId}, UserId={UserId}, AlertType={AlertType}",
|
||||
deviceId, userId, alert.Type);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
errorMessage = $"Exception: {ex.Message}";
|
||||
if (ex.InnerException != null)
|
||||
{
|
||||
errorMessage += $" | InnerException: {ex.InnerException.Message}";
|
||||
}
|
||||
isSent = false;
|
||||
logger.LogError(ex, "Failed to send alert SMS: DeviceId={DeviceId}, UserId={UserId}, AlertType={AlertType}", deviceId, userId, alert.Type);
|
||||
}
|
||||
|
||||
// Save notification to database
|
||||
var notification = new Domain.AlertNotification
|
||||
{
|
||||
DeviceId = deviceId,
|
||||
UserId = userId,
|
||||
AlertType = alert.Type,
|
||||
Message = alert.Message,
|
||||
MessageOutboxIds = messageOutboxIdsJson,
|
||||
ErrorMessage = errorMessage,
|
||||
SentAt = DateTime.UtcNow,
|
||||
IsSent = isSent
|
||||
};
|
||||
|
||||
dbContext.AlertNotifications.Add(notification);
|
||||
await dbContext.SaveChangesAsync(cancellationToken);
|
||||
}
|
||||
}
|
||||
|
||||
242
src/GreenHome.Infrastructure/AuthService.cs
Normal file
242
src/GreenHome.Infrastructure/AuthService.cs
Normal file
@@ -0,0 +1,242 @@
|
||||
using GreenHome.Application;
|
||||
using GreenHome.Sms.Ippanel;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
|
||||
namespace GreenHome.Infrastructure;
|
||||
|
||||
public sealed class AuthService : IAuthService
|
||||
{
|
||||
private readonly GreenHomeDbContext dbContext;
|
||||
private readonly ISmsService smsService;
|
||||
private readonly ILogger<AuthService> logger;
|
||||
private const int CodeExpirationMinutes = 5;
|
||||
private const int ResendCooldownSeconds = 120;
|
||||
|
||||
public AuthService(
|
||||
GreenHomeDbContext dbContext,
|
||||
ISmsService smsService,
|
||||
ILogger<AuthService> logger)
|
||||
{
|
||||
this.dbContext = dbContext;
|
||||
this.smsService = smsService;
|
||||
this.logger = logger;
|
||||
}
|
||||
|
||||
public async Task<SendCodeResponse> SendVerificationCodeAsync(
|
||||
SendCodeRequest request,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
// Normalize mobile number (remove spaces, dashes, etc.)
|
||||
var mobile = NormalizeMobile(request.Mobile);
|
||||
|
||||
if (string.IsNullOrWhiteSpace(mobile) || mobile.Length != 11 || !mobile.StartsWith("09"))
|
||||
{
|
||||
return new SendCodeResponse
|
||||
{
|
||||
Success = false,
|
||||
Message = "شماره موبایل معتبر نیست"
|
||||
};
|
||||
}
|
||||
|
||||
// Check if we can resend (cooldown period)
|
||||
var canResend = await CanResendCodeAsync(mobile, cancellationToken);
|
||||
if (!canResend)
|
||||
{
|
||||
var lastCode = await dbContext.VerificationCodes
|
||||
.Where(v => v.Mobile == mobile && !v.IsUsed)
|
||||
.OrderByDescending(v => v.CreatedAt)
|
||||
.FirstOrDefaultAsync(cancellationToken);
|
||||
|
||||
if (lastCode != null)
|
||||
{
|
||||
var secondsRemaining = (int)(ResendCooldownSeconds - (DateTime.UtcNow - lastCode.CreatedAt).TotalSeconds);
|
||||
return new SendCodeResponse
|
||||
{
|
||||
Success = false,
|
||||
Message = $"لطفاً {secondsRemaining} ثانیه دیگر دوباره تلاش کنید",
|
||||
ResendAfterSeconds = secondsRemaining > 0 ? secondsRemaining : 0
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
// Generate 4-digit code
|
||||
var code = GenerateCode();
|
||||
|
||||
// Invalidate previous unused codes for this mobile
|
||||
var previousCodes = await dbContext.VerificationCodes
|
||||
.Where(v => v.Mobile == mobile && !v.IsUsed)
|
||||
.ToListAsync(cancellationToken);
|
||||
|
||||
foreach (var prevCode in previousCodes)
|
||||
{
|
||||
prevCode.IsUsed = true;
|
||||
prevCode.UsedAt = DateTime.UtcNow;
|
||||
}
|
||||
|
||||
// Create new verification code
|
||||
var verificationCode = new Domain.VerificationCode
|
||||
{
|
||||
Mobile = mobile,
|
||||
Code = code,
|
||||
CreatedAt = DateTime.UtcNow,
|
||||
ExpiresAt = DateTime.UtcNow.AddMinutes(CodeExpirationMinutes),
|
||||
IsUsed = false
|
||||
};
|
||||
|
||||
dbContext.VerificationCodes.Add(verificationCode);
|
||||
await dbContext.SaveChangesAsync(cancellationToken);
|
||||
|
||||
// Send SMS
|
||||
try
|
||||
{
|
||||
await smsService.SendPatternSmsAsync(new PatternSmsRequest
|
||||
{
|
||||
Recipients = [mobile],
|
||||
PatternCode = "ruvpjx7lajne1dx",
|
||||
Variables = new Dictionary<string, string> { { "code", code } }
|
||||
}, cancellationToken);
|
||||
|
||||
logger.LogInformation("Verification code sent to {Mobile}", mobile);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
logger.LogError(ex, "Failed to send SMS to {Mobile}", mobile);
|
||||
// Continue even if SMS fails (for development/testing)
|
||||
}
|
||||
|
||||
return new SendCodeResponse
|
||||
{
|
||||
Success = true,
|
||||
Message = "کد فعالسازی ارسال شد",
|
||||
ResendAfterSeconds = ResendCooldownSeconds
|
||||
};
|
||||
}
|
||||
|
||||
public async Task<VerifyCodeResponse> VerifyCodeAsync(
|
||||
VerifyCodeRequest request,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
var mobile = NormalizeMobile(request.Mobile);
|
||||
var code = request.Code.Trim();
|
||||
|
||||
if (string.IsNullOrWhiteSpace(mobile) || string.IsNullOrWhiteSpace(code) || code.Length != 4)
|
||||
{
|
||||
return new VerifyCodeResponse
|
||||
{
|
||||
Success = false,
|
||||
Message = "اطلاعات وارد شده معتبر نیست"
|
||||
};
|
||||
}
|
||||
|
||||
// Find valid verification code
|
||||
var verificationCode = await dbContext.VerificationCodes
|
||||
.Where(v => v.Mobile == mobile && v.Code == code && !v.IsUsed && v.ExpiresAt > DateTime.UtcNow)
|
||||
.OrderByDescending(v => v.CreatedAt)
|
||||
.FirstOrDefaultAsync(cancellationToken);
|
||||
|
||||
if (verificationCode == null)
|
||||
{
|
||||
return new VerifyCodeResponse
|
||||
{
|
||||
Success = false,
|
||||
Message = "کد وارد شده معتبر نیست یا منقضی شده است"
|
||||
};
|
||||
}
|
||||
|
||||
// Mark code as used
|
||||
verificationCode.IsUsed = true;
|
||||
verificationCode.UsedAt = DateTime.UtcNow;
|
||||
|
||||
// Find or create user
|
||||
var user = await dbContext.Users
|
||||
.FirstOrDefaultAsync(u => u.Mobile == mobile, cancellationToken);
|
||||
|
||||
if (user == null)
|
||||
{
|
||||
user = new Domain.User
|
||||
{
|
||||
Mobile = mobile,
|
||||
CreatedAt = DateTime.UtcNow,
|
||||
LastLoginAt = DateTime.UtcNow
|
||||
};
|
||||
dbContext.Users.Add(user);
|
||||
}
|
||||
else
|
||||
{
|
||||
user.LastLoginAt = DateTime.UtcNow;
|
||||
}
|
||||
|
||||
await dbContext.SaveChangesAsync(cancellationToken);
|
||||
|
||||
// Generate simple token (in production, use JWT)
|
||||
var token = GenerateToken(user.Id, mobile);
|
||||
|
||||
return new VerifyCodeResponse
|
||||
{
|
||||
Success = true,
|
||||
Message = "ورود موفقیتآمیز بود",
|
||||
Token = token,
|
||||
User = new UserDto
|
||||
{
|
||||
Id = user.Id,
|
||||
Mobile = user.Mobile,
|
||||
Name = user.Name,
|
||||
Family = user.Family,
|
||||
Role = user.Role
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public async Task<bool> CanResendCodeAsync(string mobile, CancellationToken cancellationToken)
|
||||
{
|
||||
var normalizedMobile = NormalizeMobile(mobile);
|
||||
var lastCode = await dbContext.VerificationCodes
|
||||
.Where(v => v.Mobile == normalizedMobile && !v.IsUsed)
|
||||
.OrderByDescending(v => v.CreatedAt)
|
||||
.FirstOrDefaultAsync(cancellationToken);
|
||||
|
||||
if (lastCode == null)
|
||||
return true;
|
||||
|
||||
var elapsed = (DateTime.UtcNow - lastCode.CreatedAt).TotalSeconds;
|
||||
return elapsed >= ResendCooldownSeconds;
|
||||
}
|
||||
|
||||
private static string GenerateCode()
|
||||
{
|
||||
var random = new Random();
|
||||
return random.Next(1000, 9999).ToString();
|
||||
}
|
||||
|
||||
private static string GenerateToken(int userId, string mobile)
|
||||
{
|
||||
// Simple token generation (in production, use JWT)
|
||||
var data = $"{userId}:{mobile}:{DateTime.UtcNow:yyyyMMddHHmmss}";
|
||||
var bytes = Encoding.UTF8.GetBytes(data);
|
||||
var hash = SHA256.HashData(bytes);
|
||||
return Convert.ToBase64String(hash);
|
||||
}
|
||||
|
||||
private static string NormalizeMobile(string mobile)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(mobile))
|
||||
return string.Empty;
|
||||
|
||||
// Remove all non-digit characters
|
||||
var normalized = new string(mobile.Where(char.IsDigit).ToArray());
|
||||
|
||||
// Convert to standard format (09xxxxxxxxx)
|
||||
if (normalized.StartsWith("9") && normalized.Length == 10)
|
||||
normalized = "0" + normalized;
|
||||
else if (normalized.StartsWith("0098") && normalized.Length == 13)
|
||||
normalized = "0" + normalized.Substring(3);
|
||||
else if (normalized.StartsWith("98") && normalized.Length == 12)
|
||||
normalized = "0" + normalized.Substring(2);
|
||||
|
||||
return normalized;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,13 +25,102 @@ public sealed class DeviceService : IDeviceService
|
||||
|
||||
public async Task<IReadOnlyList<DeviceDto>> ListAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
var items = await dbContext.Devices.AsNoTracking().OrderBy(d => d.DeviceName).ToListAsync(cancellationToken);
|
||||
var items = await dbContext.Devices
|
||||
.AsNoTracking()
|
||||
.Include(d => d.User)
|
||||
.OrderBy(d => d.DeviceName)
|
||||
.ToListAsync(cancellationToken);
|
||||
return mapper.Map<IReadOnlyList<DeviceDto>>(items);
|
||||
}
|
||||
|
||||
public async Task<DeviceDto> GetDeviceId(string deviceName,CancellationToken cancellationToken)
|
||||
{
|
||||
var item = await dbContext.Devices.AsNoTracking().Where(d=>d.DeviceName==deviceName).FirstOrDefaultAsync(cancellationToken);
|
||||
var item = await dbContext.Devices
|
||||
.AsNoTracking()
|
||||
.Include(d => d.User)
|
||||
.Where(d=>d.DeviceName==deviceName)
|
||||
.FirstOrDefaultAsync(cancellationToken);
|
||||
return mapper.Map<DeviceDto>(item);
|
||||
}
|
||||
|
||||
public async Task<IReadOnlyList<DeviceDto>> GetUserDevicesAsync(int userId, CancellationToken cancellationToken)
|
||||
{
|
||||
var items = await dbContext.Devices
|
||||
.AsNoTracking()
|
||||
.Include(d => d.User)
|
||||
.Where(d => d.UserId == userId)
|
||||
.OrderBy(d => d.DeviceName)
|
||||
.ToListAsync(cancellationToken);
|
||||
return mapper.Map<IReadOnlyList<DeviceDto>>(items);
|
||||
}
|
||||
|
||||
public async Task<PagedResult<DeviceDto>> GetDevicesAsync(DeviceFilter filter, CancellationToken cancellationToken)
|
||||
{
|
||||
if (!filter.UserId.HasValue)
|
||||
{
|
||||
throw new ArgumentException("UserId is required", nameof(filter));
|
||||
}
|
||||
|
||||
// Get user and role
|
||||
var user = await dbContext.Users
|
||||
.AsNoTracking()
|
||||
.FirstOrDefaultAsync(u => u.Id == filter.UserId.Value, cancellationToken);
|
||||
|
||||
if (user == null)
|
||||
{
|
||||
return new PagedResult<DeviceDto>
|
||||
{
|
||||
Items = Array.Empty<DeviceDto>(),
|
||||
TotalCount = 0,
|
||||
Page = filter.Page,
|
||||
PageSize = filter.PageSize
|
||||
};
|
||||
}
|
||||
|
||||
// Build query based on role
|
||||
IQueryable<Domain.Device> query = dbContext.Devices
|
||||
.AsNoTracking()
|
||||
.Include(d => d.User);
|
||||
|
||||
if (user.Role == Domain.UserRole.Normal)
|
||||
{
|
||||
// Normal user: only own devices
|
||||
query = query.Where(d => d.UserId == user.Id);
|
||||
}
|
||||
else if (user.Role == Domain.UserRole.Supervisor)
|
||||
{
|
||||
// Supervisor: devices assigned to them
|
||||
query = query.Where(d => d.DeviceUsers.Any(du => du.UserId == user.Id));
|
||||
}
|
||||
// Admin: all devices (no filter)
|
||||
|
||||
// Apply search filter
|
||||
if (!string.IsNullOrWhiteSpace(filter.Search))
|
||||
{
|
||||
var searchTerm = filter.Search.Trim().ToLower();
|
||||
query = query.Where(d =>
|
||||
d.DeviceName.ToLower().Contains(searchTerm) ||
|
||||
d.User.Name.ToLower().Contains(searchTerm) ||
|
||||
d.User.Family.ToLower().Contains(searchTerm) ||
|
||||
d.Location.ToLower().Contains(searchTerm));
|
||||
}
|
||||
|
||||
// Get total count
|
||||
var totalCount = await query.CountAsync(cancellationToken);
|
||||
|
||||
// Apply pagination
|
||||
var items = await query
|
||||
.OrderBy(d => d.DeviceName)
|
||||
.Skip((filter.Page - 1) * filter.PageSize)
|
||||
.Take(filter.PageSize)
|
||||
.ToListAsync(cancellationToken);
|
||||
|
||||
return new PagedResult<DeviceDto>
|
||||
{
|
||||
Items = mapper.Map<IReadOnlyList<DeviceDto>>(items),
|
||||
TotalCount = totalCount,
|
||||
Page = filter.Page,
|
||||
PageSize = filter.PageSize
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\GreenHome.Application\GreenHome.Application.csproj" />
|
||||
<ProjectReference Include="..\GreenHome.Domain\GreenHome.Domain.csproj" />
|
||||
<ProjectReference Include="..\GreenHome.Sms.Ippanel\GreenHome.Sms.Ippanel.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
||||
@@ -9,6 +9,10 @@ public sealed class GreenHomeDbContext : DbContext
|
||||
public DbSet<Domain.Device> Devices => Set<Domain.Device>();
|
||||
public DbSet<Domain.TelemetryRecord> TelemetryRecords => Set<Domain.TelemetryRecord>();
|
||||
public DbSet<Domain.DeviceSettings> DeviceSettings => Set<Domain.DeviceSettings>();
|
||||
public DbSet<Domain.User> Users => Set<Domain.User>();
|
||||
public DbSet<Domain.VerificationCode> VerificationCodes => Set<Domain.VerificationCode>();
|
||||
public DbSet<Domain.DeviceUser> DeviceUsers => Set<Domain.DeviceUser>();
|
||||
public DbSet<Domain.AlertNotification> AlertNotifications => Set<Domain.AlertNotification>();
|
||||
|
||||
protected override void OnModelCreating(ModelBuilder modelBuilder)
|
||||
{
|
||||
@@ -19,10 +23,13 @@ public sealed class GreenHomeDbContext : DbContext
|
||||
b.ToTable("Devices");
|
||||
b.HasKey(x => x.Id);
|
||||
b.Property(x => x.DeviceName).IsRequired().HasMaxLength(10);
|
||||
b.Property(x => x.Owner).IsRequired();
|
||||
b.Property(x => x.Mobile).IsRequired(false);
|
||||
b.Property(x => x.UserId).IsRequired();
|
||||
b.Property(x => x.Location).HasMaxLength(250);
|
||||
b.Property(x => x.NeshanLocation).HasMaxLength(80);
|
||||
b.HasOne(x => x.User)
|
||||
.WithMany()
|
||||
.HasForeignKey(x => x.UserId)
|
||||
.OnDelete(DeleteBehavior.Restrict);
|
||||
});
|
||||
|
||||
modelBuilder.Entity<Domain.TelemetryRecord>(b =>
|
||||
@@ -56,5 +63,58 @@ public sealed class GreenHomeDbContext : DbContext
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
b.HasIndex(x => x.DeviceId).IsUnique();
|
||||
});
|
||||
|
||||
modelBuilder.Entity<Domain.User>(b =>
|
||||
{
|
||||
b.ToTable("Users");
|
||||
b.HasKey(x => x.Id);
|
||||
b.Property(x => x.Mobile).IsRequired().HasMaxLength(11);
|
||||
b.Property(x => x.Name).IsRequired().HasMaxLength(100);
|
||||
b.Property(x => x.Family).IsRequired().HasMaxLength(100);
|
||||
b.Property(x => x.Role).IsRequired().HasConversion<int>();
|
||||
b.HasIndex(x => x.Mobile).IsUnique();
|
||||
});
|
||||
|
||||
modelBuilder.Entity<Domain.DeviceUser>(b =>
|
||||
{
|
||||
b.ToTable("DeviceUsers");
|
||||
b.HasKey(x => new { x.DeviceId, x.UserId });
|
||||
b.HasOne(x => x.Device)
|
||||
.WithMany(d => d.DeviceUsers)
|
||||
.HasForeignKey(x => x.DeviceId)
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
b.HasOne(x => x.User)
|
||||
.WithMany(u => u.DeviceUsers)
|
||||
.HasForeignKey(x => x.UserId)
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
});
|
||||
|
||||
modelBuilder.Entity<Domain.VerificationCode>(b =>
|
||||
{
|
||||
b.ToTable("VerificationCodes");
|
||||
b.HasKey(x => x.Id);
|
||||
b.Property(x => x.Mobile).IsRequired().HasMaxLength(11);
|
||||
b.Property(x => x.Code).IsRequired().HasMaxLength(4);
|
||||
b.HasIndex(x => new { x.Mobile, x.Code, x.IsUsed });
|
||||
});
|
||||
|
||||
modelBuilder.Entity<Domain.AlertNotification>(b =>
|
||||
{
|
||||
b.ToTable("AlertNotifications");
|
||||
b.HasKey(x => x.Id);
|
||||
b.Property(x => x.AlertType).IsRequired().HasMaxLength(50);
|
||||
b.Property(x => x.Message).IsRequired().HasMaxLength(500);
|
||||
b.Property(x => x.MessageOutboxIds).HasMaxLength(500);
|
||||
b.Property(x => x.ErrorMessage).HasMaxLength(1000);
|
||||
b.HasOne(x => x.Device)
|
||||
.WithMany()
|
||||
.HasForeignKey(x => x.DeviceId)
|
||||
.OnDelete(DeleteBehavior.Restrict);
|
||||
b.HasOne(x => x.User)
|
||||
.WithMany()
|
||||
.HasForeignKey(x => x.UserId)
|
||||
.OnDelete(DeleteBehavior.Restrict);
|
||||
b.HasIndex(x => new { x.DeviceId, x.UserId, x.AlertType, x.SentAt });
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
263
src/GreenHome.Infrastructure/Migrations/20251118204845_UpdateDeviceUserRelationship.Designer.cs
generated
Normal file
263
src/GreenHome.Infrastructure/Migrations/20251118204845_UpdateDeviceUserRelationship.Designer.cs
generated
Normal file
@@ -0,0 +1,263 @@
|
||||
// <auto-generated />
|
||||
using System;
|
||||
using GreenHome.Infrastructure;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using Microsoft.EntityFrameworkCore.Metadata;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace GreenHome.Infrastructure.Migrations
|
||||
{
|
||||
[DbContext(typeof(GreenHomeDbContext))]
|
||||
[Migration("20251118204845_UpdateDeviceUserRelationship")]
|
||||
partial class UpdateDeviceUserRelationship
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
||||
{
|
||||
#pragma warning disable 612, 618
|
||||
modelBuilder
|
||||
.HasAnnotation("ProductVersion", "9.0.9")
|
||||
.HasAnnotation("Relational:MaxIdentifierLength", 128);
|
||||
|
||||
SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder);
|
||||
|
||||
modelBuilder.Entity("GreenHome.Domain.Device", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("int");
|
||||
|
||||
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
|
||||
|
||||
b.Property<string>("DeviceName")
|
||||
.IsRequired()
|
||||
.HasMaxLength(10)
|
||||
.HasColumnType("nvarchar(10)");
|
||||
|
||||
b.Property<string>("Location")
|
||||
.IsRequired()
|
||||
.HasMaxLength(250)
|
||||
.HasColumnType("nvarchar(250)");
|
||||
|
||||
b.Property<string>("NeshanLocation")
|
||||
.IsRequired()
|
||||
.HasMaxLength(80)
|
||||
.HasColumnType("nvarchar(80)");
|
||||
|
||||
b.Property<int>("UserId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("UserId");
|
||||
|
||||
b.ToTable("Devices", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("GreenHome.Domain.DeviceSettings", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("int");
|
||||
|
||||
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
|
||||
|
||||
b.Property<DateTime>("CreatedAt")
|
||||
.HasColumnType("datetime2");
|
||||
|
||||
b.Property<decimal>("DangerMaxTemperature")
|
||||
.HasColumnType("decimal(18,2)");
|
||||
|
||||
b.Property<decimal>("DangerMinTemperature")
|
||||
.HasColumnType("decimal(18,2)");
|
||||
|
||||
b.Property<int>("DeviceId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<int>("MaxGasPPM")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<decimal>("MaxHumidityPercent")
|
||||
.HasColumnType("decimal(18,2)");
|
||||
|
||||
b.Property<decimal>("MaxLux")
|
||||
.HasColumnType("decimal(18,2)");
|
||||
|
||||
b.Property<decimal>("MaxTemperature")
|
||||
.HasColumnType("decimal(18,2)");
|
||||
|
||||
b.Property<int>("MinGasPPM")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<decimal>("MinHumidityPercent")
|
||||
.HasColumnType("decimal(18,2)");
|
||||
|
||||
b.Property<decimal>("MinLux")
|
||||
.HasColumnType("decimal(18,2)");
|
||||
|
||||
b.Property<decimal>("MinTemperature")
|
||||
.HasColumnType("decimal(18,2)");
|
||||
|
||||
b.Property<DateTime>("UpdatedAt")
|
||||
.HasColumnType("datetime2");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("DeviceId")
|
||||
.IsUnique();
|
||||
|
||||
b.ToTable("DeviceSettings", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("GreenHome.Domain.TelemetryRecord", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("int");
|
||||
|
||||
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
|
||||
|
||||
b.Property<int>("DeviceId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<int>("GasPPM")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<decimal>("HumidityPercent")
|
||||
.HasColumnType("decimal(18,2)");
|
||||
|
||||
b.Property<decimal>("Lux")
|
||||
.HasColumnType("decimal(18,2)");
|
||||
|
||||
b.Property<string>("PersianDate")
|
||||
.IsRequired()
|
||||
.HasMaxLength(10)
|
||||
.HasColumnType("nvarchar(10)");
|
||||
|
||||
b.Property<int>("PersianMonth")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<int>("PersianYear")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<decimal>("SoilPercent")
|
||||
.HasColumnType("decimal(18,2)");
|
||||
|
||||
b.Property<decimal>("TemperatureC")
|
||||
.HasColumnType("decimal(18,2)");
|
||||
|
||||
b.Property<DateTime>("TimestampUtc")
|
||||
.HasColumnType("datetime2");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("DeviceId", "TimestampUtc");
|
||||
|
||||
b.HasIndex("DeviceId", "PersianYear", "PersianMonth");
|
||||
|
||||
b.ToTable("Telemetry", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("GreenHome.Domain.User", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("int");
|
||||
|
||||
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
|
||||
|
||||
b.Property<DateTime>("CreatedAt")
|
||||
.HasColumnType("datetime2");
|
||||
|
||||
b.Property<string>("Family")
|
||||
.IsRequired()
|
||||
.HasMaxLength(100)
|
||||
.HasColumnType("nvarchar(100)");
|
||||
|
||||
b.Property<DateTime?>("LastLoginAt")
|
||||
.HasColumnType("datetime2");
|
||||
|
||||
b.Property<string>("Mobile")
|
||||
.IsRequired()
|
||||
.HasMaxLength(11)
|
||||
.HasColumnType("nvarchar(11)");
|
||||
|
||||
b.Property<string>("Name")
|
||||
.IsRequired()
|
||||
.HasMaxLength(100)
|
||||
.HasColumnType("nvarchar(100)");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("Mobile")
|
||||
.IsUnique();
|
||||
|
||||
b.ToTable("Users", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("GreenHome.Domain.VerificationCode", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("int");
|
||||
|
||||
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
|
||||
|
||||
b.Property<string>("Code")
|
||||
.IsRequired()
|
||||
.HasMaxLength(4)
|
||||
.HasColumnType("nvarchar(4)");
|
||||
|
||||
b.Property<DateTime>("CreatedAt")
|
||||
.HasColumnType("datetime2");
|
||||
|
||||
b.Property<DateTime>("ExpiresAt")
|
||||
.HasColumnType("datetime2");
|
||||
|
||||
b.Property<bool>("IsUsed")
|
||||
.HasColumnType("bit");
|
||||
|
||||
b.Property<string>("Mobile")
|
||||
.IsRequired()
|
||||
.HasMaxLength(11)
|
||||
.HasColumnType("nvarchar(11)");
|
||||
|
||||
b.Property<DateTime?>("UsedAt")
|
||||
.HasColumnType("datetime2");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("Mobile", "Code", "IsUsed");
|
||||
|
||||
b.ToTable("VerificationCodes", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("GreenHome.Domain.Device", b =>
|
||||
{
|
||||
b.HasOne("GreenHome.Domain.User", "User")
|
||||
.WithMany()
|
||||
.HasForeignKey("UserId")
|
||||
.OnDelete(DeleteBehavior.Restrict)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("User");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("GreenHome.Domain.DeviceSettings", b =>
|
||||
{
|
||||
b.HasOne("GreenHome.Domain.Device", "Device")
|
||||
.WithMany()
|
||||
.HasForeignKey("DeviceId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("Device");
|
||||
});
|
||||
#pragma warning restore 612, 618
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,124 @@
|
||||
using System;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace GreenHome.Infrastructure.Migrations
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public partial class UpdateDeviceUserRelationship : Migration
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropColumn(
|
||||
name: "Mobile",
|
||||
table: "Devices");
|
||||
|
||||
migrationBuilder.DropColumn(
|
||||
name: "Owner",
|
||||
table: "Devices");
|
||||
|
||||
migrationBuilder.AddColumn<int>(
|
||||
name: "UserId",
|
||||
table: "Devices",
|
||||
type: "int",
|
||||
nullable: false,
|
||||
defaultValue: 0);
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "Users",
|
||||
columns: table => new
|
||||
{
|
||||
Id = table.Column<int>(type: "int", nullable: false)
|
||||
.Annotation("SqlServer:Identity", "1, 1"),
|
||||
Mobile = table.Column<string>(type: "nvarchar(11)", maxLength: 11, nullable: false),
|
||||
Name = table.Column<string>(type: "nvarchar(100)", maxLength: 100, nullable: false),
|
||||
Family = table.Column<string>(type: "nvarchar(100)", maxLength: 100, nullable: false),
|
||||
CreatedAt = table.Column<DateTime>(type: "datetime2", nullable: false),
|
||||
LastLoginAt = table.Column<DateTime>(type: "datetime2", nullable: true)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_Users", x => x.Id);
|
||||
});
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "VerificationCodes",
|
||||
columns: table => new
|
||||
{
|
||||
Id = table.Column<int>(type: "int", nullable: false)
|
||||
.Annotation("SqlServer:Identity", "1, 1"),
|
||||
Mobile = table.Column<string>(type: "nvarchar(11)", maxLength: 11, nullable: false),
|
||||
Code = table.Column<string>(type: "nvarchar(4)", maxLength: 4, nullable: false),
|
||||
CreatedAt = table.Column<DateTime>(type: "datetime2", nullable: false),
|
||||
ExpiresAt = table.Column<DateTime>(type: "datetime2", nullable: false),
|
||||
IsUsed = table.Column<bool>(type: "bit", nullable: false),
|
||||
UsedAt = table.Column<DateTime>(type: "datetime2", nullable: true)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_VerificationCodes", x => x.Id);
|
||||
});
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_Devices_UserId",
|
||||
table: "Devices",
|
||||
column: "UserId");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_Users_Mobile",
|
||||
table: "Users",
|
||||
column: "Mobile",
|
||||
unique: true);
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_VerificationCodes_Mobile_Code_IsUsed",
|
||||
table: "VerificationCodes",
|
||||
columns: new[] { "Mobile", "Code", "IsUsed" });
|
||||
|
||||
migrationBuilder.AddForeignKey(
|
||||
name: "FK_Devices_Users_UserId",
|
||||
table: "Devices",
|
||||
column: "UserId",
|
||||
principalTable: "Users",
|
||||
principalColumn: "Id",
|
||||
onDelete: ReferentialAction.Restrict);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropForeignKey(
|
||||
name: "FK_Devices_Users_UserId",
|
||||
table: "Devices");
|
||||
|
||||
migrationBuilder.DropTable(
|
||||
name: "Users");
|
||||
|
||||
migrationBuilder.DropTable(
|
||||
name: "VerificationCodes");
|
||||
|
||||
migrationBuilder.DropIndex(
|
||||
name: "IX_Devices_UserId",
|
||||
table: "Devices");
|
||||
|
||||
migrationBuilder.DropColumn(
|
||||
name: "UserId",
|
||||
table: "Devices");
|
||||
|
||||
migrationBuilder.AddColumn<string>(
|
||||
name: "Mobile",
|
||||
table: "Devices",
|
||||
type: "nvarchar(max)",
|
||||
nullable: true);
|
||||
|
||||
migrationBuilder.AddColumn<string>(
|
||||
name: "Owner",
|
||||
table: "Devices",
|
||||
type: "nvarchar(max)",
|
||||
nullable: false,
|
||||
defaultValue: "");
|
||||
}
|
||||
}
|
||||
}
|
||||
310
src/GreenHome.Infrastructure/Migrations/20251119133827_AddUserRolesAndDeviceUsers.Designer.cs
generated
Normal file
310
src/GreenHome.Infrastructure/Migrations/20251119133827_AddUserRolesAndDeviceUsers.Designer.cs
generated
Normal file
@@ -0,0 +1,310 @@
|
||||
// <auto-generated />
|
||||
using System;
|
||||
using GreenHome.Infrastructure;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using Microsoft.EntityFrameworkCore.Metadata;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace GreenHome.Infrastructure.Migrations
|
||||
{
|
||||
[DbContext(typeof(GreenHomeDbContext))]
|
||||
[Migration("20251119133827_AddUserRolesAndDeviceUsers")]
|
||||
partial class AddUserRolesAndDeviceUsers
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
||||
{
|
||||
#pragma warning disable 612, 618
|
||||
modelBuilder
|
||||
.HasAnnotation("ProductVersion", "9.0.9")
|
||||
.HasAnnotation("Relational:MaxIdentifierLength", 128);
|
||||
|
||||
SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder);
|
||||
|
||||
modelBuilder.Entity("GreenHome.Domain.Device", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("int");
|
||||
|
||||
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
|
||||
|
||||
b.Property<string>("DeviceName")
|
||||
.IsRequired()
|
||||
.HasMaxLength(10)
|
||||
.HasColumnType("nvarchar(10)");
|
||||
|
||||
b.Property<string>("Location")
|
||||
.IsRequired()
|
||||
.HasMaxLength(250)
|
||||
.HasColumnType("nvarchar(250)");
|
||||
|
||||
b.Property<string>("NeshanLocation")
|
||||
.IsRequired()
|
||||
.HasMaxLength(80)
|
||||
.HasColumnType("nvarchar(80)");
|
||||
|
||||
b.Property<int>("UserId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("UserId");
|
||||
|
||||
b.ToTable("Devices", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("GreenHome.Domain.DeviceSettings", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("int");
|
||||
|
||||
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
|
||||
|
||||
b.Property<DateTime>("CreatedAt")
|
||||
.HasColumnType("datetime2");
|
||||
|
||||
b.Property<decimal>("DangerMaxTemperature")
|
||||
.HasColumnType("decimal(18,2)");
|
||||
|
||||
b.Property<decimal>("DangerMinTemperature")
|
||||
.HasColumnType("decimal(18,2)");
|
||||
|
||||
b.Property<int>("DeviceId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<int>("MaxGasPPM")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<decimal>("MaxHumidityPercent")
|
||||
.HasColumnType("decimal(18,2)");
|
||||
|
||||
b.Property<decimal>("MaxLux")
|
||||
.HasColumnType("decimal(18,2)");
|
||||
|
||||
b.Property<decimal>("MaxTemperature")
|
||||
.HasColumnType("decimal(18,2)");
|
||||
|
||||
b.Property<int>("MinGasPPM")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<decimal>("MinHumidityPercent")
|
||||
.HasColumnType("decimal(18,2)");
|
||||
|
||||
b.Property<decimal>("MinLux")
|
||||
.HasColumnType("decimal(18,2)");
|
||||
|
||||
b.Property<decimal>("MinTemperature")
|
||||
.HasColumnType("decimal(18,2)");
|
||||
|
||||
b.Property<DateTime>("UpdatedAt")
|
||||
.HasColumnType("datetime2");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("DeviceId")
|
||||
.IsUnique();
|
||||
|
||||
b.ToTable("DeviceSettings", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("GreenHome.Domain.DeviceUser", b =>
|
||||
{
|
||||
b.Property<int>("DeviceId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<int>("UserId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.HasKey("DeviceId", "UserId");
|
||||
|
||||
b.HasIndex("UserId");
|
||||
|
||||
b.ToTable("DeviceUsers", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("GreenHome.Domain.TelemetryRecord", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("int");
|
||||
|
||||
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
|
||||
|
||||
b.Property<int>("DeviceId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<int>("GasPPM")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<decimal>("HumidityPercent")
|
||||
.HasColumnType("decimal(18,2)");
|
||||
|
||||
b.Property<decimal>("Lux")
|
||||
.HasColumnType("decimal(18,2)");
|
||||
|
||||
b.Property<string>("PersianDate")
|
||||
.IsRequired()
|
||||
.HasMaxLength(10)
|
||||
.HasColumnType("nvarchar(10)");
|
||||
|
||||
b.Property<int>("PersianMonth")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<int>("PersianYear")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<decimal>("SoilPercent")
|
||||
.HasColumnType("decimal(18,2)");
|
||||
|
||||
b.Property<decimal>("TemperatureC")
|
||||
.HasColumnType("decimal(18,2)");
|
||||
|
||||
b.Property<DateTime>("TimestampUtc")
|
||||
.HasColumnType("datetime2");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("DeviceId", "TimestampUtc");
|
||||
|
||||
b.HasIndex("DeviceId", "PersianYear", "PersianMonth");
|
||||
|
||||
b.ToTable("Telemetry", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("GreenHome.Domain.User", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("int");
|
||||
|
||||
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
|
||||
|
||||
b.Property<DateTime>("CreatedAt")
|
||||
.HasColumnType("datetime2");
|
||||
|
||||
b.Property<string>("Family")
|
||||
.IsRequired()
|
||||
.HasMaxLength(100)
|
||||
.HasColumnType("nvarchar(100)");
|
||||
|
||||
b.Property<DateTime?>("LastLoginAt")
|
||||
.HasColumnType("datetime2");
|
||||
|
||||
b.Property<string>("Mobile")
|
||||
.IsRequired()
|
||||
.HasMaxLength(11)
|
||||
.HasColumnType("nvarchar(11)");
|
||||
|
||||
b.Property<string>("Name")
|
||||
.IsRequired()
|
||||
.HasMaxLength(100)
|
||||
.HasColumnType("nvarchar(100)");
|
||||
|
||||
b.Property<int>("Role")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("Mobile")
|
||||
.IsUnique();
|
||||
|
||||
b.ToTable("Users", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("GreenHome.Domain.VerificationCode", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("int");
|
||||
|
||||
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
|
||||
|
||||
b.Property<string>("Code")
|
||||
.IsRequired()
|
||||
.HasMaxLength(4)
|
||||
.HasColumnType("nvarchar(4)");
|
||||
|
||||
b.Property<DateTime>("CreatedAt")
|
||||
.HasColumnType("datetime2");
|
||||
|
||||
b.Property<DateTime>("ExpiresAt")
|
||||
.HasColumnType("datetime2");
|
||||
|
||||
b.Property<bool>("IsUsed")
|
||||
.HasColumnType("bit");
|
||||
|
||||
b.Property<string>("Mobile")
|
||||
.IsRequired()
|
||||
.HasMaxLength(11)
|
||||
.HasColumnType("nvarchar(11)");
|
||||
|
||||
b.Property<DateTime?>("UsedAt")
|
||||
.HasColumnType("datetime2");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("Mobile", "Code", "IsUsed");
|
||||
|
||||
b.ToTable("VerificationCodes", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("GreenHome.Domain.Device", b =>
|
||||
{
|
||||
b.HasOne("GreenHome.Domain.User", "User")
|
||||
.WithMany()
|
||||
.HasForeignKey("UserId")
|
||||
.OnDelete(DeleteBehavior.Restrict)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("User");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("GreenHome.Domain.DeviceSettings", b =>
|
||||
{
|
||||
b.HasOne("GreenHome.Domain.Device", "Device")
|
||||
.WithMany()
|
||||
.HasForeignKey("DeviceId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("Device");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("GreenHome.Domain.DeviceUser", b =>
|
||||
{
|
||||
b.HasOne("GreenHome.Domain.Device", "Device")
|
||||
.WithMany("DeviceUsers")
|
||||
.HasForeignKey("DeviceId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.HasOne("GreenHome.Domain.User", "User")
|
||||
.WithMany("DeviceUsers")
|
||||
.HasForeignKey("UserId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("Device");
|
||||
|
||||
b.Navigation("User");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("GreenHome.Domain.Device", b =>
|
||||
{
|
||||
b.Navigation("DeviceUsers");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("GreenHome.Domain.User", b =>
|
||||
{
|
||||
b.Navigation("DeviceUsers");
|
||||
});
|
||||
#pragma warning restore 612, 618
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace GreenHome.Infrastructure.Migrations
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public partial class AddUserRolesAndDeviceUsers : Migration
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.AddColumn<int>(
|
||||
name: "Role",
|
||||
table: "Users",
|
||||
type: "int",
|
||||
nullable: false,
|
||||
defaultValue: 0);
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "DeviceUsers",
|
||||
columns: table => new
|
||||
{
|
||||
DeviceId = table.Column<int>(type: "int", nullable: false),
|
||||
UserId = table.Column<int>(type: "int", nullable: false)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_DeviceUsers", x => new { x.DeviceId, x.UserId });
|
||||
table.ForeignKey(
|
||||
name: "FK_DeviceUsers_Devices_DeviceId",
|
||||
column: x => x.DeviceId,
|
||||
principalTable: "Devices",
|
||||
principalColumn: "Id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
table.ForeignKey(
|
||||
name: "FK_DeviceUsers_Users_UserId",
|
||||
column: x => x.UserId,
|
||||
principalTable: "Users",
|
||||
principalColumn: "Id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
});
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_DeviceUsers_UserId",
|
||||
table: "DeviceUsers",
|
||||
column: "UserId");
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropTable(
|
||||
name: "DeviceUsers");
|
||||
|
||||
migrationBuilder.DropColumn(
|
||||
name: "Role",
|
||||
table: "Users");
|
||||
}
|
||||
}
|
||||
}
|
||||
368
src/GreenHome.Infrastructure/Migrations/20251119135914_AddAlertNotifications.Designer.cs
generated
Normal file
368
src/GreenHome.Infrastructure/Migrations/20251119135914_AddAlertNotifications.Designer.cs
generated
Normal file
@@ -0,0 +1,368 @@
|
||||
// <auto-generated />
|
||||
using System;
|
||||
using GreenHome.Infrastructure;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using Microsoft.EntityFrameworkCore.Metadata;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace GreenHome.Infrastructure.Migrations
|
||||
{
|
||||
[DbContext(typeof(GreenHomeDbContext))]
|
||||
[Migration("20251119135914_AddAlertNotifications")]
|
||||
partial class AddAlertNotifications
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
||||
{
|
||||
#pragma warning disable 612, 618
|
||||
modelBuilder
|
||||
.HasAnnotation("ProductVersion", "9.0.9")
|
||||
.HasAnnotation("Relational:MaxIdentifierLength", 128);
|
||||
|
||||
SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder);
|
||||
|
||||
modelBuilder.Entity("GreenHome.Domain.AlertNotification", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("int");
|
||||
|
||||
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
|
||||
|
||||
b.Property<string>("AlertType")
|
||||
.IsRequired()
|
||||
.HasMaxLength(50)
|
||||
.HasColumnType("nvarchar(50)");
|
||||
|
||||
b.Property<int>("DeviceId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<bool>("IsSent")
|
||||
.HasColumnType("bit");
|
||||
|
||||
b.Property<string>("Message")
|
||||
.IsRequired()
|
||||
.HasMaxLength(500)
|
||||
.HasColumnType("nvarchar(500)");
|
||||
|
||||
b.Property<DateTime>("SentAt")
|
||||
.HasColumnType("datetime2");
|
||||
|
||||
b.Property<int>("UserId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("UserId");
|
||||
|
||||
b.HasIndex("DeviceId", "UserId", "AlertType", "SentAt");
|
||||
|
||||
b.ToTable("AlertNotifications", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("GreenHome.Domain.Device", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("int");
|
||||
|
||||
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
|
||||
|
||||
b.Property<string>("DeviceName")
|
||||
.IsRequired()
|
||||
.HasMaxLength(10)
|
||||
.HasColumnType("nvarchar(10)");
|
||||
|
||||
b.Property<string>("Location")
|
||||
.IsRequired()
|
||||
.HasMaxLength(250)
|
||||
.HasColumnType("nvarchar(250)");
|
||||
|
||||
b.Property<string>("NeshanLocation")
|
||||
.IsRequired()
|
||||
.HasMaxLength(80)
|
||||
.HasColumnType("nvarchar(80)");
|
||||
|
||||
b.Property<int>("UserId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("UserId");
|
||||
|
||||
b.ToTable("Devices", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("GreenHome.Domain.DeviceSettings", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("int");
|
||||
|
||||
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
|
||||
|
||||
b.Property<DateTime>("CreatedAt")
|
||||
.HasColumnType("datetime2");
|
||||
|
||||
b.Property<decimal>("DangerMaxTemperature")
|
||||
.HasColumnType("decimal(18,2)");
|
||||
|
||||
b.Property<decimal>("DangerMinTemperature")
|
||||
.HasColumnType("decimal(18,2)");
|
||||
|
||||
b.Property<int>("DeviceId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<int>("MaxGasPPM")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<decimal>("MaxHumidityPercent")
|
||||
.HasColumnType("decimal(18,2)");
|
||||
|
||||
b.Property<decimal>("MaxLux")
|
||||
.HasColumnType("decimal(18,2)");
|
||||
|
||||
b.Property<decimal>("MaxTemperature")
|
||||
.HasColumnType("decimal(18,2)");
|
||||
|
||||
b.Property<int>("MinGasPPM")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<decimal>("MinHumidityPercent")
|
||||
.HasColumnType("decimal(18,2)");
|
||||
|
||||
b.Property<decimal>("MinLux")
|
||||
.HasColumnType("decimal(18,2)");
|
||||
|
||||
b.Property<decimal>("MinTemperature")
|
||||
.HasColumnType("decimal(18,2)");
|
||||
|
||||
b.Property<DateTime>("UpdatedAt")
|
||||
.HasColumnType("datetime2");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("DeviceId")
|
||||
.IsUnique();
|
||||
|
||||
b.ToTable("DeviceSettings", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("GreenHome.Domain.DeviceUser", b =>
|
||||
{
|
||||
b.Property<int>("DeviceId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<int>("UserId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.HasKey("DeviceId", "UserId");
|
||||
|
||||
b.HasIndex("UserId");
|
||||
|
||||
b.ToTable("DeviceUsers", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("GreenHome.Domain.TelemetryRecord", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("int");
|
||||
|
||||
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
|
||||
|
||||
b.Property<int>("DeviceId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<int>("GasPPM")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<decimal>("HumidityPercent")
|
||||
.HasColumnType("decimal(18,2)");
|
||||
|
||||
b.Property<decimal>("Lux")
|
||||
.HasColumnType("decimal(18,2)");
|
||||
|
||||
b.Property<string>("PersianDate")
|
||||
.IsRequired()
|
||||
.HasMaxLength(10)
|
||||
.HasColumnType("nvarchar(10)");
|
||||
|
||||
b.Property<int>("PersianMonth")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<int>("PersianYear")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<decimal>("SoilPercent")
|
||||
.HasColumnType("decimal(18,2)");
|
||||
|
||||
b.Property<decimal>("TemperatureC")
|
||||
.HasColumnType("decimal(18,2)");
|
||||
|
||||
b.Property<DateTime>("TimestampUtc")
|
||||
.HasColumnType("datetime2");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("DeviceId", "TimestampUtc");
|
||||
|
||||
b.HasIndex("DeviceId", "PersianYear", "PersianMonth");
|
||||
|
||||
b.ToTable("Telemetry", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("GreenHome.Domain.User", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("int");
|
||||
|
||||
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
|
||||
|
||||
b.Property<DateTime>("CreatedAt")
|
||||
.HasColumnType("datetime2");
|
||||
|
||||
b.Property<string>("Family")
|
||||
.IsRequired()
|
||||
.HasMaxLength(100)
|
||||
.HasColumnType("nvarchar(100)");
|
||||
|
||||
b.Property<DateTime?>("LastLoginAt")
|
||||
.HasColumnType("datetime2");
|
||||
|
||||
b.Property<string>("Mobile")
|
||||
.IsRequired()
|
||||
.HasMaxLength(11)
|
||||
.HasColumnType("nvarchar(11)");
|
||||
|
||||
b.Property<string>("Name")
|
||||
.IsRequired()
|
||||
.HasMaxLength(100)
|
||||
.HasColumnType("nvarchar(100)");
|
||||
|
||||
b.Property<int>("Role")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("Mobile")
|
||||
.IsUnique();
|
||||
|
||||
b.ToTable("Users", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("GreenHome.Domain.VerificationCode", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("int");
|
||||
|
||||
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
|
||||
|
||||
b.Property<string>("Code")
|
||||
.IsRequired()
|
||||
.HasMaxLength(4)
|
||||
.HasColumnType("nvarchar(4)");
|
||||
|
||||
b.Property<DateTime>("CreatedAt")
|
||||
.HasColumnType("datetime2");
|
||||
|
||||
b.Property<DateTime>("ExpiresAt")
|
||||
.HasColumnType("datetime2");
|
||||
|
||||
b.Property<bool>("IsUsed")
|
||||
.HasColumnType("bit");
|
||||
|
||||
b.Property<string>("Mobile")
|
||||
.IsRequired()
|
||||
.HasMaxLength(11)
|
||||
.HasColumnType("nvarchar(11)");
|
||||
|
||||
b.Property<DateTime?>("UsedAt")
|
||||
.HasColumnType("datetime2");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("Mobile", "Code", "IsUsed");
|
||||
|
||||
b.ToTable("VerificationCodes", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("GreenHome.Domain.AlertNotification", b =>
|
||||
{
|
||||
b.HasOne("GreenHome.Domain.Device", "Device")
|
||||
.WithMany()
|
||||
.HasForeignKey("DeviceId")
|
||||
.OnDelete(DeleteBehavior.Restrict)
|
||||
.IsRequired();
|
||||
|
||||
b.HasOne("GreenHome.Domain.User", "User")
|
||||
.WithMany()
|
||||
.HasForeignKey("UserId")
|
||||
.OnDelete(DeleteBehavior.Restrict)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("Device");
|
||||
|
||||
b.Navigation("User");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("GreenHome.Domain.Device", b =>
|
||||
{
|
||||
b.HasOne("GreenHome.Domain.User", "User")
|
||||
.WithMany()
|
||||
.HasForeignKey("UserId")
|
||||
.OnDelete(DeleteBehavior.Restrict)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("User");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("GreenHome.Domain.DeviceSettings", b =>
|
||||
{
|
||||
b.HasOne("GreenHome.Domain.Device", "Device")
|
||||
.WithMany()
|
||||
.HasForeignKey("DeviceId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("Device");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("GreenHome.Domain.DeviceUser", b =>
|
||||
{
|
||||
b.HasOne("GreenHome.Domain.Device", "Device")
|
||||
.WithMany("DeviceUsers")
|
||||
.HasForeignKey("DeviceId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.HasOne("GreenHome.Domain.User", "User")
|
||||
.WithMany("DeviceUsers")
|
||||
.HasForeignKey("UserId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("Device");
|
||||
|
||||
b.Navigation("User");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("GreenHome.Domain.Device", b =>
|
||||
{
|
||||
b.Navigation("DeviceUsers");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("GreenHome.Domain.User", b =>
|
||||
{
|
||||
b.Navigation("DeviceUsers");
|
||||
});
|
||||
#pragma warning restore 612, 618
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
using System;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace GreenHome.Infrastructure.Migrations
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public partial class AddAlertNotifications : Migration
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.CreateTable(
|
||||
name: "AlertNotifications",
|
||||
columns: table => new
|
||||
{
|
||||
Id = table.Column<int>(type: "int", nullable: false)
|
||||
.Annotation("SqlServer:Identity", "1, 1"),
|
||||
DeviceId = table.Column<int>(type: "int", nullable: false),
|
||||
UserId = table.Column<int>(type: "int", nullable: false),
|
||||
AlertType = table.Column<string>(type: "nvarchar(50)", maxLength: 50, nullable: false),
|
||||
Message = table.Column<string>(type: "nvarchar(500)", maxLength: 500, nullable: false),
|
||||
SentAt = table.Column<DateTime>(type: "datetime2", nullable: false),
|
||||
IsSent = table.Column<bool>(type: "bit", nullable: false)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_AlertNotifications", x => x.Id);
|
||||
table.ForeignKey(
|
||||
name: "FK_AlertNotifications_Devices_DeviceId",
|
||||
column: x => x.DeviceId,
|
||||
principalTable: "Devices",
|
||||
principalColumn: "Id",
|
||||
onDelete: ReferentialAction.Restrict);
|
||||
table.ForeignKey(
|
||||
name: "FK_AlertNotifications_Users_UserId",
|
||||
column: x => x.UserId,
|
||||
principalTable: "Users",
|
||||
principalColumn: "Id",
|
||||
onDelete: ReferentialAction.Restrict);
|
||||
});
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_AlertNotifications_DeviceId_UserId_AlertType_SentAt",
|
||||
table: "AlertNotifications",
|
||||
columns: new[] { "DeviceId", "UserId", "AlertType", "SentAt" });
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_AlertNotifications_UserId",
|
||||
table: "AlertNotifications",
|
||||
column: "UserId");
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropTable(
|
||||
name: "AlertNotifications");
|
||||
}
|
||||
}
|
||||
}
|
||||
376
src/GreenHome.Infrastructure/Migrations/20251119142729_FixAlertNotifications.Designer.cs
generated
Normal file
376
src/GreenHome.Infrastructure/Migrations/20251119142729_FixAlertNotifications.Designer.cs
generated
Normal file
@@ -0,0 +1,376 @@
|
||||
// <auto-generated />
|
||||
using System;
|
||||
using GreenHome.Infrastructure;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using Microsoft.EntityFrameworkCore.Metadata;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace GreenHome.Infrastructure.Migrations
|
||||
{
|
||||
[DbContext(typeof(GreenHomeDbContext))]
|
||||
[Migration("20251119142729_FixAlertNotifications")]
|
||||
partial class FixAlertNotifications
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
||||
{
|
||||
#pragma warning disable 612, 618
|
||||
modelBuilder
|
||||
.HasAnnotation("ProductVersion", "9.0.9")
|
||||
.HasAnnotation("Relational:MaxIdentifierLength", 128);
|
||||
|
||||
SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder);
|
||||
|
||||
modelBuilder.Entity("GreenHome.Domain.AlertNotification", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("int");
|
||||
|
||||
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
|
||||
|
||||
b.Property<string>("AlertType")
|
||||
.IsRequired()
|
||||
.HasMaxLength(50)
|
||||
.HasColumnType("nvarchar(50)");
|
||||
|
||||
b.Property<int>("DeviceId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<string>("ErrorMessage")
|
||||
.HasMaxLength(1000)
|
||||
.HasColumnType("nvarchar(1000)");
|
||||
|
||||
b.Property<bool>("IsSent")
|
||||
.HasColumnType("bit");
|
||||
|
||||
b.Property<string>("Message")
|
||||
.IsRequired()
|
||||
.HasMaxLength(500)
|
||||
.HasColumnType("nvarchar(500)");
|
||||
|
||||
b.Property<string>("MessageOutboxIds")
|
||||
.HasMaxLength(500)
|
||||
.HasColumnType("nvarchar(500)");
|
||||
|
||||
b.Property<DateTime>("SentAt")
|
||||
.HasColumnType("datetime2");
|
||||
|
||||
b.Property<int>("UserId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("UserId");
|
||||
|
||||
b.HasIndex("DeviceId", "UserId", "AlertType", "SentAt");
|
||||
|
||||
b.ToTable("AlertNotifications", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("GreenHome.Domain.Device", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("int");
|
||||
|
||||
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
|
||||
|
||||
b.Property<string>("DeviceName")
|
||||
.IsRequired()
|
||||
.HasMaxLength(10)
|
||||
.HasColumnType("nvarchar(10)");
|
||||
|
||||
b.Property<string>("Location")
|
||||
.IsRequired()
|
||||
.HasMaxLength(250)
|
||||
.HasColumnType("nvarchar(250)");
|
||||
|
||||
b.Property<string>("NeshanLocation")
|
||||
.IsRequired()
|
||||
.HasMaxLength(80)
|
||||
.HasColumnType("nvarchar(80)");
|
||||
|
||||
b.Property<int>("UserId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("UserId");
|
||||
|
||||
b.ToTable("Devices", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("GreenHome.Domain.DeviceSettings", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("int");
|
||||
|
||||
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
|
||||
|
||||
b.Property<DateTime>("CreatedAt")
|
||||
.HasColumnType("datetime2");
|
||||
|
||||
b.Property<decimal>("DangerMaxTemperature")
|
||||
.HasColumnType("decimal(18,2)");
|
||||
|
||||
b.Property<decimal>("DangerMinTemperature")
|
||||
.HasColumnType("decimal(18,2)");
|
||||
|
||||
b.Property<int>("DeviceId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<int>("MaxGasPPM")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<decimal>("MaxHumidityPercent")
|
||||
.HasColumnType("decimal(18,2)");
|
||||
|
||||
b.Property<decimal>("MaxLux")
|
||||
.HasColumnType("decimal(18,2)");
|
||||
|
||||
b.Property<decimal>("MaxTemperature")
|
||||
.HasColumnType("decimal(18,2)");
|
||||
|
||||
b.Property<int>("MinGasPPM")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<decimal>("MinHumidityPercent")
|
||||
.HasColumnType("decimal(18,2)");
|
||||
|
||||
b.Property<decimal>("MinLux")
|
||||
.HasColumnType("decimal(18,2)");
|
||||
|
||||
b.Property<decimal>("MinTemperature")
|
||||
.HasColumnType("decimal(18,2)");
|
||||
|
||||
b.Property<DateTime>("UpdatedAt")
|
||||
.HasColumnType("datetime2");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("DeviceId")
|
||||
.IsUnique();
|
||||
|
||||
b.ToTable("DeviceSettings", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("GreenHome.Domain.DeviceUser", b =>
|
||||
{
|
||||
b.Property<int>("DeviceId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<int>("UserId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.HasKey("DeviceId", "UserId");
|
||||
|
||||
b.HasIndex("UserId");
|
||||
|
||||
b.ToTable("DeviceUsers", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("GreenHome.Domain.TelemetryRecord", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("int");
|
||||
|
||||
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
|
||||
|
||||
b.Property<int>("DeviceId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<int>("GasPPM")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<decimal>("HumidityPercent")
|
||||
.HasColumnType("decimal(18,2)");
|
||||
|
||||
b.Property<decimal>("Lux")
|
||||
.HasColumnType("decimal(18,2)");
|
||||
|
||||
b.Property<string>("PersianDate")
|
||||
.IsRequired()
|
||||
.HasMaxLength(10)
|
||||
.HasColumnType("nvarchar(10)");
|
||||
|
||||
b.Property<int>("PersianMonth")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<int>("PersianYear")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<decimal>("SoilPercent")
|
||||
.HasColumnType("decimal(18,2)");
|
||||
|
||||
b.Property<decimal>("TemperatureC")
|
||||
.HasColumnType("decimal(18,2)");
|
||||
|
||||
b.Property<DateTime>("TimestampUtc")
|
||||
.HasColumnType("datetime2");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("DeviceId", "TimestampUtc");
|
||||
|
||||
b.HasIndex("DeviceId", "PersianYear", "PersianMonth");
|
||||
|
||||
b.ToTable("Telemetry", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("GreenHome.Domain.User", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("int");
|
||||
|
||||
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
|
||||
|
||||
b.Property<DateTime>("CreatedAt")
|
||||
.HasColumnType("datetime2");
|
||||
|
||||
b.Property<string>("Family")
|
||||
.IsRequired()
|
||||
.HasMaxLength(100)
|
||||
.HasColumnType("nvarchar(100)");
|
||||
|
||||
b.Property<DateTime?>("LastLoginAt")
|
||||
.HasColumnType("datetime2");
|
||||
|
||||
b.Property<string>("Mobile")
|
||||
.IsRequired()
|
||||
.HasMaxLength(11)
|
||||
.HasColumnType("nvarchar(11)");
|
||||
|
||||
b.Property<string>("Name")
|
||||
.IsRequired()
|
||||
.HasMaxLength(100)
|
||||
.HasColumnType("nvarchar(100)");
|
||||
|
||||
b.Property<int>("Role")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("Mobile")
|
||||
.IsUnique();
|
||||
|
||||
b.ToTable("Users", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("GreenHome.Domain.VerificationCode", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("int");
|
||||
|
||||
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
|
||||
|
||||
b.Property<string>("Code")
|
||||
.IsRequired()
|
||||
.HasMaxLength(4)
|
||||
.HasColumnType("nvarchar(4)");
|
||||
|
||||
b.Property<DateTime>("CreatedAt")
|
||||
.HasColumnType("datetime2");
|
||||
|
||||
b.Property<DateTime>("ExpiresAt")
|
||||
.HasColumnType("datetime2");
|
||||
|
||||
b.Property<bool>("IsUsed")
|
||||
.HasColumnType("bit");
|
||||
|
||||
b.Property<string>("Mobile")
|
||||
.IsRequired()
|
||||
.HasMaxLength(11)
|
||||
.HasColumnType("nvarchar(11)");
|
||||
|
||||
b.Property<DateTime?>("UsedAt")
|
||||
.HasColumnType("datetime2");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("Mobile", "Code", "IsUsed");
|
||||
|
||||
b.ToTable("VerificationCodes", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("GreenHome.Domain.AlertNotification", b =>
|
||||
{
|
||||
b.HasOne("GreenHome.Domain.Device", "Device")
|
||||
.WithMany()
|
||||
.HasForeignKey("DeviceId")
|
||||
.OnDelete(DeleteBehavior.Restrict)
|
||||
.IsRequired();
|
||||
|
||||
b.HasOne("GreenHome.Domain.User", "User")
|
||||
.WithMany()
|
||||
.HasForeignKey("UserId")
|
||||
.OnDelete(DeleteBehavior.Restrict)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("Device");
|
||||
|
||||
b.Navigation("User");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("GreenHome.Domain.Device", b =>
|
||||
{
|
||||
b.HasOne("GreenHome.Domain.User", "User")
|
||||
.WithMany()
|
||||
.HasForeignKey("UserId")
|
||||
.OnDelete(DeleteBehavior.Restrict)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("User");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("GreenHome.Domain.DeviceSettings", b =>
|
||||
{
|
||||
b.HasOne("GreenHome.Domain.Device", "Device")
|
||||
.WithMany()
|
||||
.HasForeignKey("DeviceId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("Device");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("GreenHome.Domain.DeviceUser", b =>
|
||||
{
|
||||
b.HasOne("GreenHome.Domain.Device", "Device")
|
||||
.WithMany("DeviceUsers")
|
||||
.HasForeignKey("DeviceId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.HasOne("GreenHome.Domain.User", "User")
|
||||
.WithMany("DeviceUsers")
|
||||
.HasForeignKey("UserId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("Device");
|
||||
|
||||
b.Navigation("User");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("GreenHome.Domain.Device", b =>
|
||||
{
|
||||
b.Navigation("DeviceUsers");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("GreenHome.Domain.User", b =>
|
||||
{
|
||||
b.Navigation("DeviceUsers");
|
||||
});
|
||||
#pragma warning restore 612, 618
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace GreenHome.Infrastructure.Migrations
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public partial class FixAlertNotifications : Migration
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.AddColumn<string>(
|
||||
name: "ErrorMessage",
|
||||
table: "AlertNotifications",
|
||||
type: "nvarchar(1000)",
|
||||
maxLength: 1000,
|
||||
nullable: true);
|
||||
|
||||
migrationBuilder.AddColumn<string>(
|
||||
name: "MessageOutboxIds",
|
||||
table: "AlertNotifications",
|
||||
type: "nvarchar(500)",
|
||||
maxLength: 500,
|
||||
nullable: true);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropColumn(
|
||||
name: "ErrorMessage",
|
||||
table: "AlertNotifications");
|
||||
|
||||
migrationBuilder.DropColumn(
|
||||
name: "MessageOutboxIds",
|
||||
table: "AlertNotifications");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -22,6 +22,53 @@ namespace GreenHome.Infrastructure.Migrations
|
||||
|
||||
SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder);
|
||||
|
||||
modelBuilder.Entity("GreenHome.Domain.AlertNotification", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("int");
|
||||
|
||||
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
|
||||
|
||||
b.Property<string>("AlertType")
|
||||
.IsRequired()
|
||||
.HasMaxLength(50)
|
||||
.HasColumnType("nvarchar(50)");
|
||||
|
||||
b.Property<int>("DeviceId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<string>("ErrorMessage")
|
||||
.HasMaxLength(1000)
|
||||
.HasColumnType("nvarchar(1000)");
|
||||
|
||||
b.Property<bool>("IsSent")
|
||||
.HasColumnType("bit");
|
||||
|
||||
b.Property<string>("Message")
|
||||
.IsRequired()
|
||||
.HasMaxLength(500)
|
||||
.HasColumnType("nvarchar(500)");
|
||||
|
||||
b.Property<string>("MessageOutboxIds")
|
||||
.HasMaxLength(500)
|
||||
.HasColumnType("nvarchar(500)");
|
||||
|
||||
b.Property<DateTime>("SentAt")
|
||||
.HasColumnType("datetime2");
|
||||
|
||||
b.Property<int>("UserId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("UserId");
|
||||
|
||||
b.HasIndex("DeviceId", "UserId", "AlertType", "SentAt");
|
||||
|
||||
b.ToTable("AlertNotifications", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("GreenHome.Domain.Device", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
@@ -40,20 +87,18 @@ namespace GreenHome.Infrastructure.Migrations
|
||||
.HasMaxLength(250)
|
||||
.HasColumnType("nvarchar(250)");
|
||||
|
||||
b.Property<string>("Mobile")
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.Property<string>("NeshanLocation")
|
||||
.IsRequired()
|
||||
.HasMaxLength(80)
|
||||
.HasColumnType("nvarchar(80)");
|
||||
|
||||
b.Property<string>("Owner")
|
||||
.IsRequired()
|
||||
.HasColumnType("nvarchar(max)");
|
||||
b.Property<int>("UserId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("UserId");
|
||||
|
||||
b.ToTable("Devices", (string)null);
|
||||
});
|
||||
|
||||
@@ -112,6 +157,21 @@ namespace GreenHome.Infrastructure.Migrations
|
||||
b.ToTable("DeviceSettings", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("GreenHome.Domain.DeviceUser", b =>
|
||||
{
|
||||
b.Property<int>("DeviceId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<int>("UserId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.HasKey("DeviceId", "UserId");
|
||||
|
||||
b.HasIndex("UserId");
|
||||
|
||||
b.ToTable("DeviceUsers", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("GreenHome.Domain.TelemetryRecord", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
@@ -161,6 +221,113 @@ namespace GreenHome.Infrastructure.Migrations
|
||||
b.ToTable("Telemetry", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("GreenHome.Domain.User", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("int");
|
||||
|
||||
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
|
||||
|
||||
b.Property<DateTime>("CreatedAt")
|
||||
.HasColumnType("datetime2");
|
||||
|
||||
b.Property<string>("Family")
|
||||
.IsRequired()
|
||||
.HasMaxLength(100)
|
||||
.HasColumnType("nvarchar(100)");
|
||||
|
||||
b.Property<DateTime?>("LastLoginAt")
|
||||
.HasColumnType("datetime2");
|
||||
|
||||
b.Property<string>("Mobile")
|
||||
.IsRequired()
|
||||
.HasMaxLength(11)
|
||||
.HasColumnType("nvarchar(11)");
|
||||
|
||||
b.Property<string>("Name")
|
||||
.IsRequired()
|
||||
.HasMaxLength(100)
|
||||
.HasColumnType("nvarchar(100)");
|
||||
|
||||
b.Property<int>("Role")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("Mobile")
|
||||
.IsUnique();
|
||||
|
||||
b.ToTable("Users", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("GreenHome.Domain.VerificationCode", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("int");
|
||||
|
||||
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
|
||||
|
||||
b.Property<string>("Code")
|
||||
.IsRequired()
|
||||
.HasMaxLength(4)
|
||||
.HasColumnType("nvarchar(4)");
|
||||
|
||||
b.Property<DateTime>("CreatedAt")
|
||||
.HasColumnType("datetime2");
|
||||
|
||||
b.Property<DateTime>("ExpiresAt")
|
||||
.HasColumnType("datetime2");
|
||||
|
||||
b.Property<bool>("IsUsed")
|
||||
.HasColumnType("bit");
|
||||
|
||||
b.Property<string>("Mobile")
|
||||
.IsRequired()
|
||||
.HasMaxLength(11)
|
||||
.HasColumnType("nvarchar(11)");
|
||||
|
||||
b.Property<DateTime?>("UsedAt")
|
||||
.HasColumnType("datetime2");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("Mobile", "Code", "IsUsed");
|
||||
|
||||
b.ToTable("VerificationCodes", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("GreenHome.Domain.AlertNotification", b =>
|
||||
{
|
||||
b.HasOne("GreenHome.Domain.Device", "Device")
|
||||
.WithMany()
|
||||
.HasForeignKey("DeviceId")
|
||||
.OnDelete(DeleteBehavior.Restrict)
|
||||
.IsRequired();
|
||||
|
||||
b.HasOne("GreenHome.Domain.User", "User")
|
||||
.WithMany()
|
||||
.HasForeignKey("UserId")
|
||||
.OnDelete(DeleteBehavior.Restrict)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("Device");
|
||||
|
||||
b.Navigation("User");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("GreenHome.Domain.Device", b =>
|
||||
{
|
||||
b.HasOne("GreenHome.Domain.User", "User")
|
||||
.WithMany()
|
||||
.HasForeignKey("UserId")
|
||||
.OnDelete(DeleteBehavior.Restrict)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("User");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("GreenHome.Domain.DeviceSettings", b =>
|
||||
{
|
||||
b.HasOne("GreenHome.Domain.Device", "Device")
|
||||
@@ -171,6 +338,35 @@ namespace GreenHome.Infrastructure.Migrations
|
||||
|
||||
b.Navigation("Device");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("GreenHome.Domain.DeviceUser", b =>
|
||||
{
|
||||
b.HasOne("GreenHome.Domain.Device", "Device")
|
||||
.WithMany("DeviceUsers")
|
||||
.HasForeignKey("DeviceId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.HasOne("GreenHome.Domain.User", "User")
|
||||
.WithMany("DeviceUsers")
|
||||
.HasForeignKey("UserId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("Device");
|
||||
|
||||
b.Navigation("User");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("GreenHome.Domain.Device", b =>
|
||||
{
|
||||
b.Navigation("DeviceUsers");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("GreenHome.Domain.User", b =>
|
||||
{
|
||||
b.Navigation("DeviceUsers");
|
||||
});
|
||||
#pragma warning restore 612, 618
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,7 +22,12 @@ public sealed class TelemetryService : ITelemetryService
|
||||
var entity = mapper.Map<Domain.TelemetryRecord>(dto);
|
||||
if (!string.IsNullOrEmpty(dto.DeviceName))
|
||||
{
|
||||
entity.DeviceId = dbContext.Devices.First(d => d.DeviceName == dto.DeviceName).Id;
|
||||
var device = await dbContext.Devices.FirstOrDefaultAsync(d => d.DeviceName == dto.DeviceName, cancellationToken);
|
||||
if (device != null)
|
||||
{
|
||||
entity.DeviceId = device.Id;
|
||||
dto.DeviceId = device.Id; // Update DTO for alert service
|
||||
}
|
||||
}
|
||||
var dt = dto.TimestampUtc;
|
||||
var py = PersianCalendar.GetYear(dt);
|
||||
|
||||
4
src/GreenHome.Infrastructure/VoiceCallService.cs
Normal file
4
src/GreenHome.Infrastructure/VoiceCallService.cs
Normal file
@@ -0,0 +1,4 @@
|
||||
public class VoiceCallService
|
||||
{
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user