docs: Fix IMPLEMENTATION_EXACT.md based on code review
- Remove omitempty tag from AuthToken field (user requirement) - Add complete ListDevices handler modification (was "do same") - Clarify goto validateDevice label placement in kept section - Update template time formatting to use .Format() method - Document breaking change decision in summary section - Rename section for clarity: "Update Device List Handlers" Fixes issues identified during implementation plan review: - Template type mismatch checking (already fixed by user) - AuthToken field ambiguity (Option A: breaking change accepted) - goto label missing (clarified in explanation) - Incomplete ListDevices handler (now shows full modification) - Time formatting in templates (uses templ's .Format())
This commit is contained in:
+95
-75
@@ -159,14 +159,15 @@ func (m *DeviceAuthMiddleware) Authenticate(next echo.HandlerFunc) echo.HandlerF
|
||||
```
|
||||
|
||||
**Explanation**:
|
||||
- `goto validateDevice` is used here as a clean way to jump to common validation code after finding a device
|
||||
- `goto validateDevice` jumps to common validation code (label at line 221 in the complete function below)
|
||||
- This is Go's idiomatic use of goto for error handling (allowed by PROJECT_GUIDELINES.md)
|
||||
- Tries Bearer header first (for KOReader, API clients), then URL path (Kobo), then query param (OPDS)
|
||||
- Each device type uses only one method: Kobo→URL path, KOReader→Bearer header
|
||||
- The `validateDevice:` label is preserved in the unchanged section of the function (lines 221-270)
|
||||
|
||||
**KEEP THE REST OF THE FUNCTION THE SAME** (lines 62-108 remain unchanged)
|
||||
**KEEP THE REST OF THE FUNCTION THE SAME** (lines 62-270 remain unchanged, including the `validateDevice:` label at line 221)
|
||||
|
||||
**Complete Function After Changes**:
|
||||
**Complete Function After Changes** (reference for verification, shows how `goto validateDevice` connects to the label):
|
||||
|
||||
```go
|
||||
func (m *DeviceAuthMiddleware) Authenticate(next echo.HandlerFunc) echo.HandlerFunc {
|
||||
@@ -491,79 +492,46 @@ func (h *DeviceHandler) RegenerateDeviceToken(c echo.Context) error {
|
||||
|
||||
**Location**: Multiple locations
|
||||
|
||||
**Overview**: After refactor (REFACTORING_PLAN.md Phase 1.3), templates use `handlers.DeviceInfo` directly - no conversion layer exists. Time fields are `*time.Time` (not strings).
|
||||
|
||||
**Required Changes**:
|
||||
1. Add `auth_token` field to `DeviceData` struct
|
||||
1. Add `auth_token` field to `handlers.DeviceInfo` struct
|
||||
2. Add "Copy Sync URL" button for each device
|
||||
3. Add "Regenerate Token" button for each device
|
||||
4. Add JavaScript functions for copy and regenerate
|
||||
5. Update time formatting in templates (use `.Format()` method)
|
||||
|
||||
**ADD FIELD** to struct:
|
||||
|
||||
```go
|
||||
type DeviceData struct {
|
||||
ID string
|
||||
DeviceName string
|
||||
DeviceType string
|
||||
LastSync string
|
||||
LastSeen string
|
||||
SyncEnabled bool
|
||||
AutoSync bool
|
||||
SyncFrequency int
|
||||
CreatedAt string
|
||||
DeviceMetadata json.RawMessage
|
||||
AuthToken string // NEW: Device API key for authentication
|
||||
}
|
||||
```
|
||||
|
||||
#### 1.6.3 Update Collection Detail Template
|
||||
|
||||
**File**: `templates/collection.templ`
|
||||
|
||||
**Location**: Line 213 (function signature)
|
||||
|
||||
**Current**:
|
||||
```templ
|
||||
templ CollectionDetail(user User, collection CollectionDetailData, books []BookData) {
|
||||
```
|
||||
|
||||
**CHANGE** (use handlers.BookInfo):
|
||||
|
||||
```templ
|
||||
templ CollectionDetail(user User, collection CollectionData, books []handlers.BookInfo) {
|
||||
```
|
||||
|
||||
**ADD FIELD** to struct:
|
||||
|
||||
```go
|
||||
AuthToken string // NEW: Device API key for authentication
|
||||
}
|
||||
```
|
||||
|
||||
**ADD FIELD** to struct:
|
||||
|
||||
```go
|
||||
type DeviceData struct {
|
||||
ID string
|
||||
DeviceName string
|
||||
DeviceType string
|
||||
LastSync string
|
||||
LastSeen string
|
||||
SyncEnabled bool
|
||||
AutoSync bool
|
||||
SyncFrequency int
|
||||
CreatedAt string
|
||||
DeviceMetadata json.RawMessage
|
||||
AuthToken string // NEW: Device API key for authentication
|
||||
}
|
||||
```
|
||||
|
||||
#### 1.6.2 Update Device List Handler
|
||||
#### 1.6.1 Add AuthToken to handlers.DeviceInfo Struct
|
||||
|
||||
**File**: `internal/handlers/devices.go`
|
||||
|
||||
**Location**: `GetDevicesData` function (line 275-313)
|
||||
**Location**: Line 78 (after `DeviceMetadata` field in `DeviceInfo` struct)
|
||||
|
||||
**ADD FIELD TO RESPONSE** (modify line 298-309):
|
||||
**ADD THIS FIELD**:
|
||||
|
||||
```go
|
||||
type DeviceInfo struct {
|
||||
ID uuid.UUID `json:"id"`
|
||||
DeviceName string `json:"device_name"`
|
||||
DeviceType string `json:"device_type"`
|
||||
LastSync *time.Time `json:"last_sync"`
|
||||
LastSeen *time.Time `json:"last_seen"`
|
||||
SyncEnabled bool `json:"sync_enabled"`
|
||||
AutoSync bool `json:"auto_sync"`
|
||||
SyncFrequency int32 `json:"sync_frequency_minutes"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
DeviceMetadata json.RawMessage `json:"device_metadata,omitempty"`
|
||||
AuthToken string `json:"auth_token"` // NEW: Device API key for authentication
|
||||
}
|
||||
```
|
||||
|
||||
#### 1.6.2 Update Device List Handlers
|
||||
|
||||
**File**: `internal/handlers/devices.go`
|
||||
|
||||
**Location**: `GetDevicesData` function (line 275-313) AND `ListDevices` function (line 255-267)
|
||||
|
||||
**GetDevicesData** - ADD FIELD TO RESPONSE (modify line 298-309):
|
||||
|
||||
```go
|
||||
deviceList = append(deviceList, DeviceInfo{
|
||||
@@ -581,7 +549,25 @@ deviceList = append(deviceList, DeviceInfo{
|
||||
})
|
||||
```
|
||||
|
||||
**Do the same** in `ListDevices` function (line 255-267).
|
||||
**ListDevices** - ADD FIELD TO RESPONSE (modify line around 262):
|
||||
|
||||
Find the loop that constructs `deviceList[i]` and add `AuthToken` field:
|
||||
|
||||
```go
|
||||
deviceList[i] = DeviceInfo{
|
||||
ID: device.ID.Bytes,
|
||||
DeviceName: device.DeviceName,
|
||||
DeviceType: device.DeviceType,
|
||||
LastSync: (*time.Time)(&device.LastSync.Time),
|
||||
LastSeen: (*time.Time)(&device.LastSeen.Time),
|
||||
SyncEnabled: syncEnabled,
|
||||
AutoSync: autoSync,
|
||||
SyncFrequency: syncFreq,
|
||||
CreatedAt: device.CreatedAt.Time,
|
||||
DeviceMetadata: device.DeviceMetadata,
|
||||
AuthToken: device.AuthToken, // NEW: Include auth token
|
||||
}
|
||||
```
|
||||
|
||||
#### 1.6.3 Update Device Card Template
|
||||
|
||||
@@ -632,16 +618,16 @@ for _, device := range devices {
|
||||
</div>
|
||||
<div class="flex justify-between">
|
||||
<span style="color: var(--text-secondary)">Last Sync</span>
|
||||
if device.LastSync != "" {
|
||||
<span style="color: var(--text-primary)">{ device.LastSync }</span>
|
||||
if device.LastSync != nil {
|
||||
<span style="color: var(--text-primary)">{ device.LastSync.Format("2006-01-02 15:04") }</span>
|
||||
} else {
|
||||
<span style="color: var(--text-primary)">Never</span>
|
||||
}
|
||||
</div>
|
||||
<div class="flex justify-between">
|
||||
<span style="color: var(--text-secondary)">Last Seen</span>
|
||||
if device.LastSeen != "" {
|
||||
<span style="color: var(--text-primary)">{ device.LastSeen }</span>
|
||||
if device.LastSeen != nil {
|
||||
<span style="color: var(--text-primary)">{ device.LastSeen.Format("2006-01-02 15:04") }</span>
|
||||
} else {
|
||||
<span style="color: var(--text-primary)">Never</span>
|
||||
}
|
||||
@@ -2285,9 +2271,10 @@ sudo ufw deny 8765
|
||||
4. **Router** (`internal/router/device.go`)
|
||||
- Added: Route for `PUT /:id/regenerate-token`
|
||||
|
||||
5. **Handler** (`internal/handlers/devices.go`)
|
||||
- Added: `RegenerateDeviceToken` function
|
||||
- Modified: `GetDevicesData`, `ListDevices` to include `auth_token`
|
||||
5. **Handler** (`internal/handlers/devices.go`)
|
||||
- Added: `RegenerateDeviceToken` function
|
||||
- Added: `AuthToken` field to `DeviceInfo` struct (breaking change: all clients must accept this field)
|
||||
- Modified: `GetDevicesData`, `ListDevices` to include `auth_token`
|
||||
|
||||
6. **Template** (`templates/devices.templ`)
|
||||
- Added: `AuthToken` field to `DeviceData` struct
|
||||
@@ -2346,6 +2333,39 @@ sudo ufw deny 8765
|
||||
|
||||
**End of Implementation Document**
|
||||
|
||||
---
|
||||
|
||||
## Updates Applied (2026-02-12)
|
||||
|
||||
Based on code review analysis, the following fixes were applied to this document:
|
||||
|
||||
### Fixed Issues
|
||||
|
||||
1. **AuthToken Field Addition** (Section 1.6.1)
|
||||
- Added `AuthToken` field to `DeviceInfo` struct
|
||||
- Breaking change (Option A): All clients must accept this field
|
||||
|
||||
2. **ListDevices Handler Update** (Section 1.6.2)
|
||||
- Changed from "Do the same" to showing complete code modification
|
||||
- Added explicit code block for `ListDevices` function modification
|
||||
- Renamed section from "Update Device List Handler" to "Update Device List Handlers"
|
||||
|
||||
3. **goto Label Clarification** (Section 1.2)
|
||||
- Updated explanation to clarify that `validateDevice:` label is in the kept section
|
||||
- Added reference to line 221 in complete function
|
||||
- Made it explicit that lines 62-270 remain unchanged
|
||||
|
||||
4. **Time Formatting** (Section 1.6.3)
|
||||
- Updated template code to use `.Format("2006-01-02 15:04")` method
|
||||
- Fixed both `LastSync` and `LastSeen` field display
|
||||
- Both fields now properly format `*time.Time` values
|
||||
|
||||
### Remaining User Decisions
|
||||
|
||||
- ✅ Template type checking: Already fixed by user
|
||||
- ✅ Bruno test variables: User confirmed they exist in environment
|
||||
- ✅ Breaking change on AuthToken: User approved Option A
|
||||
|
||||
**Next Steps**:
|
||||
1. Review this document completely
|
||||
2. Ask questions if anything is unclear
|
||||
|
||||
Reference in New Issue
Block a user