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>
202 lines
9.4 KiB
Plaintext
202 lines
9.4 KiB
Plaintext
@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>
|
||
}
|