Files
rr3-server/RR3CommunityServer/Pages/DeviceSettings.cshtml
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

202 lines
9.4 KiB
Plaintext
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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.
@page
@model RR3CommunityServer.Pages.DeviceSettingsModel
@{
ViewData["Title"] = "Device Server Settings";
}
<div class="container-fluid mt-4">
<div class="row mb-4">
<div class="col-12">
<div class="d-flex justify-content-between align-items-center">
<div>
<h1>📱 Device Server Settings</h1>
<p class="text-muted">Configure server URLs for individual devices (syncs with APK)</p>
</div>
<a href="/admin" class="btn btn-outline-secondary">← Back to Dashboard</a>
</div>
</div>
</div>
@if (TempData["Message"] != null)
{
<div class="alert alert-success alert-dismissible fade show" role="alert">
<strong>✅ Success!</strong> @TempData["Message"]
<button type="button" class="btn-close" data-bs-dismiss="alert"></button>
</div>
}
<!-- Add New Device Settings -->
<div class="row mb-4">
<div class="col-lg-8">
<div class="card">
<div class="card-header bg-success text-white">
<h5 class="mb-0"> Add New Device Configuration</h5>
</div>
<div class="card-body">
<form method="post" asp-page-handler="AddOrUpdate">
<div class="row">
<div class="col-md-4 mb-3">
<label for="deviceId" class="form-label">Device ID</label>
<input type="text" class="form-control" id="deviceId" name="deviceId"
placeholder="e.g., device_abc123" required>
<small class="text-muted">Enter the device ID from the APK</small>
</div>
<div class="col-md-3 mb-3">
<label for="mode" class="form-label">Mode</label>
<select class="form-select" id="mode" name="mode" required>
<option value="offline">📱 Offline</option>
<option value="online" selected>🌐 Online</option>
</select>
</div>
<div class="col-md-5 mb-3">
<label for="serverUrl" class="form-label">Server URL</label>
<input type="text" class="form-control" id="serverUrl" name="serverUrl"
placeholder="https://example.com:8443" value="@Model.CurrentServerUrl">
<small class="text-muted">Include port if not 80/443</small>
</div>
</div>
<button type="submit" class="btn btn-success">
<i class="bi bi-plus-circle"></i> Add / Update Settings
</button>
</form>
</div>
</div>
</div>
<div class="col-lg-4">
<div class="card bg-light">
<div class="card-body">
<h6 class="mb-3"> How It Works</h6>
<ol class="small mb-0">
<li>Add device configuration here</li>
<li>User opens RR3 APK</li>
<li>User taps "🔄 Sync from Web Panel"</li>
<li>APK fetches settings from this server</li>
<li>Game restarts with new settings</li>
</ol>
</div>
</div>
</div>
</div>
<!-- Existing Device Settings -->
<div class="row">
<div class="col-12">
<div class="card">
<div class="card-header bg-primary text-white">
<h5 class="mb-0">🗂️ Configured Devices (@Model.DeviceSettings.Count)</h5>
</div>
<div class="card-body">
@if (Model.DeviceSettings.Count == 0)
{
<div class="alert alert-info">
<i class="bi bi-info-circle"></i> No device settings configured yet. Add one above to get started.
</div>
}
else
{
<div class="table-responsive">
<table class="table table-hover">
<thead>
<tr>
<th>Device ID</th>
<th>Mode</th>
<th>Server URL</th>
<th>Last Updated</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
@foreach (var setting in Model.DeviceSettings)
{
<tr>
<td><code>@setting.DeviceId</code></td>
<td>
@if (setting.Mode == "online")
{
<span class="badge bg-success">🌐 Online</span>
}
else
{
<span class="badge bg-secondary">📱 Offline</span>
}
</td>
<td>
@if (!string.IsNullOrEmpty(setting.ServerUrl))
{
<code>@setting.ServerUrl</code>
}
else
{
<span class="text-muted">—</span>
}
</td>
<td>
<small class="text-muted">
@setting.LastUpdated.ToLocalTime().ToString("MMM dd, yyyy HH:mm")
</small>
</td>
<td>
<form method="post" asp-page-handler="Delete" class="d-inline">
<input type="hidden" name="deviceId" value="@setting.DeviceId" />
<button type="submit" class="btn btn-sm btn-outline-danger"
onclick="return confirm('Delete settings for @setting.DeviceId?')">
<i class="bi bi-trash"></i> Delete
</button>
</form>
</td>
</tr>
}
</tbody>
</table>
</div>
}
</div>
</div>
</div>
</div>
<!-- API Documentation -->
<div class="row mt-4">
<div class="col-12">
<div class="card">
<div class="card-header bg-dark text-white">
<h5 class="mb-0">📚 API Endpoints</h5>
</div>
<div class="card-body">
<h6>GET /api/settings/getUserSettings?deviceId={deviceId}</h6>
<p class="text-muted">Returns server configuration for a device (called by APK sync button)</p>
<pre class="bg-light p-3"><code>{
"mode": "online",
"serverUrl": "https://rr3.example.com:8443",
"message": "Settings retrieved successfully"
}</code></pre>
<h6 class="mt-4">POST /api/settings/updateUserSettings</h6>
<p class="text-muted">Update settings from web panel (this page uses it)</p>
<pre class="bg-light p-3"><code>{
"deviceId": "device_abc123",
"mode": "online",
"serverUrl": "https://rr3.example.com:8443"
}</code></pre>
<h6 class="mt-4">GET /api/settings/getAllUserSettings</h6>
<p class="text-muted">Get all device settings (admin only)</p>
</div>
</div>
</div>
</div>
</div>
@section Scripts {
<script>
// Auto-populate server URL field with current server
document.addEventListener('DOMContentLoaded', function() {
const serverUrlInput = document.getElementById('serverUrl');
if (!serverUrlInput.value) {
serverUrlInput.value = '@Model.CurrentServerUrl';
}
});
</script>
}