Files
rr3-server/RR3CommunityServer/Controllers/ServerSettingsController.cs
Daniel Elliott 8ba7c605f1 Add device settings management and web panel sync API
Features:
- New DeviceSettings admin page at /devicesettings
- Manage device server configurations (URL, mode, deviceId)
- 3 new API endpoints for APK sync functionality
- UserSettings database model with SQLite storage

Implementation:
- ServerSettingsController.cs with getUserSettings, updateUserSettings, getAllUserSettings
- DeviceSettings.cshtml Razor page with add/edit/delete UI
- DeviceSettings.cshtml.cs page model with CRUD operations
- UserSettings model added to ApiModels.cs
- UserSettings DbSet added to RR3DbContext
- EF Core migration: 20260219180936_AddUserSettings
- Link added to Admin dashboard

API Endpoints:
- GET /api/settings/getUserSettings?deviceId={id} - APK sync endpoint
- POST /api/settings/updateUserSettings - Web panel update
- GET /api/settings/getAllUserSettings - Admin list view

Database Schema:
- UserSettings table (Id, DeviceId, ServerUrl, Mode, LastUpdated)
- SQLite storage with EF Core migrations

Integration:
- Works with APK SettingsActivity sync button
- Real-time configuration updates
- Emoji logging for all operations
- Device-specific server URL management

Usage:
1. Admin configures device settings at /devicesettings
2. User opens RR3 APK and taps Sync from Web Panel
3. APK downloads settings via API
4. Settings saved to SharedPreferences
5. Game restart applies configuration

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-02-19 10:15:02 -08:00

175 lines
5.7 KiB
C#
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using RR3CommunityServer.Data;
using RR3CommunityServer.Models;
namespace RR3CommunityServer.Controllers;
[ApiController]
[Route("api/settings")]
public class ServerSettingsController : ControllerBase
{
private readonly RR3DbContext _context;
private readonly ILogger<ServerSettingsController> _logger;
public ServerSettingsController(RR3DbContext context, ILogger<ServerSettingsController> logger)
{
_context = context;
_logger = logger;
}
/// <summary>
/// Get user settings (called by APK sync button)
/// GET /api/settings/getUserSettings?deviceId=xxx
/// </summary>
[HttpGet("getUserSettings")]
public async Task<ActionResult<UserSettingsResponse>> GetUserSettings([FromQuery] string? deviceId)
{
try
{
if (string.IsNullOrEmpty(deviceId))
{
_logger.LogWarning("GetUserSettings: No deviceId provided");
return BadRequest(new { error = "deviceId is required" });
}
_logger.LogInformation($"🔄 GetUserSettings: deviceId={deviceId}");
var settings = await _context.UserSettings
.Where(s => s.DeviceId == deviceId)
.FirstOrDefaultAsync();
if (settings == null)
{
_logger.LogInformation($"⚠️ No settings found for deviceId={deviceId}, returning defaults");
return Ok(new UserSettingsResponse
{
mode = "offline",
serverUrl = "",
message = "No settings found, using defaults"
});
}
_logger.LogInformation($"✅ Found settings: mode={settings.Mode}, url={settings.ServerUrl}");
return Ok(new UserSettingsResponse
{
mode = settings.Mode,
serverUrl = settings.ServerUrl,
message = "Settings retrieved successfully"
});
}
catch (Exception ex)
{
_logger.LogError(ex, "❌ Error in GetUserSettings");
return StatusCode(500, new { error = "Internal server error" });
}
}
/// <summary>
/// Update user settings (called by web panel)
/// POST /api/settings/updateUserSettings
/// Body: { "deviceId": "xxx", "mode": "online", "serverUrl": "https://example.com:8443" }
/// </summary>
[HttpPost("updateUserSettings")]
public async Task<ActionResult<UpdateSettingsResponse>> UpdateUserSettings([FromBody] UpdateUserSettingsRequest request)
{
try
{
if (string.IsNullOrEmpty(request.deviceId))
{
return BadRequest(new { error = "deviceId is required" });
}
if (string.IsNullOrEmpty(request.mode))
{
return BadRequest(new { error = "mode is required" });
}
_logger.LogInformation($"🔄 UpdateUserSettings: deviceId={request.deviceId}, mode={request.mode}, url={request.serverUrl}");
var settings = await _context.UserSettings
.Where(s => s.DeviceId == request.deviceId)
.FirstOrDefaultAsync();
if (settings == null)
{
// Create new settings
settings = new UserSettings
{
DeviceId = request.deviceId,
Mode = request.mode,
ServerUrl = request.serverUrl ?? "",
LastUpdated = DateTime.UtcNow
};
_context.UserSettings.Add(settings);
_logger.LogInformation($" Created new settings for deviceId={request.deviceId}");
}
else
{
// Update existing settings
settings.Mode = request.mode;
settings.ServerUrl = request.serverUrl ?? "";
settings.LastUpdated = DateTime.UtcNow;
_logger.LogInformation($"✏️ Updated existing settings for deviceId={request.deviceId}");
}
await _context.SaveChangesAsync();
return Ok(new UpdateSettingsResponse
{
success = true,
message = "Settings updated successfully"
});
}
catch (Exception ex)
{
_logger.LogError(ex, "❌ Error in UpdateUserSettings");
return StatusCode(500, new { error = "Internal server error" });
}
}
/// <summary>
/// Get all user settings (for admin panel)
/// GET /api/settings/getAllUserSettings
/// </summary>
[HttpGet("getAllUserSettings")]
public async Task<ActionResult<List<UserSettings>>> GetAllUserSettings()
{
try
{
var allSettings = await _context.UserSettings
.OrderByDescending(s => s.LastUpdated)
.ToListAsync();
_logger.LogInformation($"📋 Retrieved {allSettings.Count} user settings");
return Ok(allSettings);
}
catch (Exception ex)
{
_logger.LogError(ex, "❌ Error in GetAllUserSettings");
return StatusCode(500, new { error = "Internal server error" });
}
}
}
// Response models
public class UserSettingsResponse
{
public string mode { get; set; } = "offline";
public string serverUrl { get; set; } = "";
public string? message { get; set; }
}
public class UpdateUserSettingsRequest
{
public string deviceId { get; set; } = string.Empty;
public string mode { get; set; } = "offline";
public string? serverUrl { get; set; }
}
public class UpdateSettingsResponse
{
public bool success { get; set; }
public string? message { get; set; }
}