Skip to content

Commit 6b16950

Browse files
Add user alias management for Easee charging sessions (#25)
* Initial plan * Implement Easee user alias feature with management UI Co-authored-by: thomasneuberger <23504477+thomasneuberger@users.noreply.github.com> * Fix security issues: prevent temp file race conditions and ensure HTML encoding Co-authored-by: thomasneuberger <23504477+thomasneuberger@users.noreply.github.com> * Add comprehensive documentation for Easee user alias feature Co-authored-by: thomasneuberger <23504477+thomasneuberger@users.noreply.github.com> * Improve UI styling for user alias management pages to match login page Co-authored-by: thomasneuberger <23504477+thomasneuberger@users.noreply.github.com> * Remove empty CSS rules from Edit view Co-authored-by: thomasneuberger <23504477+thomasneuberger@users.noreply.github.com> * Change token IDs to dynamic list with add/remove functionality Co-authored-by: thomasneuberger <23504477+thomasneuberger@users.noreply.github.com> * Add null check for TokenIds to prevent NullReferenceException Co-authored-by: thomasneuberger <23504477+thomasneuberger@users.noreply.github.com> --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: thomasneuberger <23504477+thomasneuberger@users.noreply.github.com>
1 parent 9598f7b commit 6b16950

14 files changed

Lines changed: 1094 additions & 18 deletions

File tree

EASEE_USER_ALIAS.md

Lines changed: 148 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,148 @@
1+
# Easee User Alias Feature
2+
3+
This document describes the Easee user alias feature that allows managing user-friendly names for charging session users.
4+
5+
## Overview
6+
7+
The feature automatically tracks all user IDs from Easee charging sessions and allows administrators to assign human-readable aliases and token ID mappings for each user.
8+
9+
## Features
10+
11+
### 1. Automatic User Tracking
12+
- All user IDs encountered in charging sessions are automatically tracked
13+
- Stored in `easee-users.json` file in the FileStorage path
14+
- Duplicates are automatically removed
15+
16+
### 2. User Alias Management
17+
- Assign a user-friendly alias (display name) to any user ID
18+
- Associate multiple token IDs with a user
19+
- Web-based interface for easy management
20+
21+
### 3. Smart User Name Resolution
22+
When displaying charging sessions in reports, the system resolves user names using this priority:
23+
1. **Direct alias match**: If the user ID has an alias, use it
24+
2. **Token ID match**: If the session's authToken matches any user's token IDs, use that user's alias
25+
3. **Fallback**: Use the user ID as-is if no alias is found
26+
27+
### 4. Updated Reports
28+
Both monthly and detailed reports now display user aliases instead of raw user IDs.
29+
30+
## Usage
31+
32+
### Accessing the Management Page
33+
34+
1. Navigate to the Easee login page: `/Easee/Login`
35+
2. Click "Benutzer-Aliase verwalten" button
36+
3. Or directly access: `/UserAlias`
37+
38+
### Managing User Aliases
39+
40+
On the management page, you can:
41+
42+
1. **View all users**: See all tracked user IDs and their current aliases
43+
2. **Edit an alias**:
44+
- Click "Bearbeiten" for any user
45+
- Enter a friendly name (e.g., "Max Mustermann")
46+
- Optionally add comma-separated token IDs
47+
- Click "Speichern" to save
48+
3. **Delete an alias**: Click "Löschen" to remove an alias (the user ID remains tracked)
49+
50+
### Token IDs
51+
52+
Token IDs are useful when:
53+
- A user has multiple authentication tokens
54+
- You want to associate different charging sessions (with different tokens) to the same user alias
55+
- Sessions are recorded with an authToken that differs from the user ID
56+
57+
Format: Enter as comma-separated values (e.g., `token1, token2, token3`)
58+
59+
## File Storage
60+
61+
The feature creates two JSON files in the `FileStorage.Path`:
62+
63+
1. **easee-users.json**: List of all encountered user IDs
64+
```json
65+
[
66+
"123",
67+
"456",
68+
"789"
69+
]
70+
```
71+
72+
2. **easee-user-aliases.json**: User alias configurations
73+
```json
74+
[
75+
{
76+
"UserId": "123",
77+
"Alias": "Max Mustermann",
78+
"TokenIds": ["token1", "token2"]
79+
}
80+
]
81+
```
82+
83+
## Technical Implementation
84+
85+
### Components
86+
87+
1. **UserAlias Model** (`TgHomeBot.Charging.Contract.Models.UserAlias`)
88+
- Represents a user alias configuration
89+
- Properties: UserId, Alias, TokenIds
90+
91+
2. **IUserAliasService** (`TgHomeBot.Charging.Contract.IUserAliasService`)
92+
- Service interface for managing aliases
93+
- Methods: GetAllAliases, SaveAlias, DeleteAlias, ResolveUserName, TrackUserId, etc.
94+
95+
3. **UserAliasService** (`TgHomeBot.Charging.Easee.UserAliasService`)
96+
- Implementation of IUserAliasService
97+
- Handles file persistence and alias resolution
98+
99+
4. **UserAliasController** (`TgHomeBot.Api.Controllers.UserAliasController`)
100+
- Web controller for the management UI
101+
- Actions: Index (list), Edit (create/update), Delete
102+
103+
5. **Views**
104+
- `Views/UserAlias/Index.cshtml`: List all users and aliases
105+
- `Views/UserAlias/Edit.cshtml`: Edit form for aliases
106+
107+
### Integration Points
108+
109+
1. **EaseeConnector**:
110+
- Tracks user IDs when fetching sessions
111+
- Resolves user names using the alias service
112+
- Sets the `UserName` property on `ChargingSession` objects
113+
114+
2. **ChargingSession Model**:
115+
- Extended with `UserName` property
116+
- Contains both `UserId` (original ID) and `UserName` (resolved display name)
117+
118+
3. **Report Commands**:
119+
- `MonthlyReportCommand`: Groups by and displays UserName
120+
- `DetailedReportCommand`: Groups by and displays UserName
121+
122+
## Security
123+
124+
- User input is properly HTML-encoded to prevent XSS attacks
125+
- File writes use atomic operations (temp file + move) to prevent corruption
126+
- Temp files use unique GUIDs to prevent race conditions
127+
- Thread-safe access to shared data structures using locks
128+
129+
## Example Workflow
130+
131+
1. User authenticates with Easee API
132+
2. System fetches charging sessions from API
133+
3. For each session:
134+
- User ID is tracked (if not already tracked)
135+
- User name is resolved using alias service
136+
- Session is created with both UserId and UserName
137+
4. Administrator navigates to `/UserAlias`
138+
5. Administrator sees all tracked user IDs
139+
6. Administrator edits user "123" and sets alias "Max Mustermann"
140+
7. Future reports show "Max Mustermann" instead of "123"
141+
142+
## Future Enhancements
143+
144+
Potential improvements:
145+
- Bulk import/export of aliases
146+
- User groups or categories
147+
- Integration with external user directories
148+
- Automatic alias suggestions based on session metadata
Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
using Microsoft.AspNetCore.Mvc;
2+
using TgHomeBot.Charging.Contract;
3+
using TgHomeBot.Charging.Contract.Models;
4+
5+
namespace TgHomeBot.Api.Controllers;
6+
7+
/// <summary>
8+
/// Controller for managing Easee user aliases
9+
/// </summary>
10+
public class UserAliasController : Controller
11+
{
12+
private readonly ILogger<UserAliasController> _logger;
13+
private readonly IUserAliasService _userAliasService;
14+
15+
public UserAliasController(
16+
ILogger<UserAliasController> logger,
17+
IUserAliasService userAliasService)
18+
{
19+
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
20+
_userAliasService = userAliasService ?? throw new ArgumentNullException(nameof(userAliasService));
21+
}
22+
23+
[HttpGet]
24+
public IActionResult Index()
25+
{
26+
_logger.LogInformation("User alias management page accessed");
27+
28+
var trackedUserIds = _userAliasService.GetTrackedUserIds();
29+
var aliases = _userAliasService.GetAllAliases();
30+
31+
var model = trackedUserIds.Select(userId =>
32+
{
33+
var alias = aliases.FirstOrDefault(a => a.UserId == userId);
34+
return alias ?? new UserAlias { UserId = userId };
35+
}).ToList();
36+
37+
return View(model);
38+
}
39+
40+
[HttpGet]
41+
public IActionResult Edit(string userId)
42+
{
43+
_logger.LogInformation("Editing user alias for user {UserId}", userId);
44+
45+
var alias = _userAliasService.GetAliasByUserId(userId)
46+
?? new UserAlias { UserId = userId };
47+
48+
return View(alias);
49+
}
50+
51+
[HttpPost]
52+
[ValidateAntiForgeryToken]
53+
public IActionResult Edit(UserAlias model)
54+
{
55+
_logger.LogInformation("Saving user alias for user {UserId}", model.UserId);
56+
57+
if (!ModelState.IsValid)
58+
{
59+
_logger.LogWarning("User alias validation failed for user {UserId}", model.UserId);
60+
return View(model);
61+
}
62+
63+
// Filter out empty token IDs
64+
if (model.TokenIds != null)
65+
{
66+
model.TokenIds = model.TokenIds
67+
.Where(t => !string.IsNullOrWhiteSpace(t))
68+
.Select(t => t.Trim())
69+
.Distinct()
70+
.ToList();
71+
}
72+
else
73+
{
74+
model.TokenIds = [];
75+
}
76+
77+
_userAliasService.SaveAlias(model);
78+
79+
TempData["Message"] = "Alias erfolgreich gespeichert!";
80+
return RedirectToAction(nameof(Index));
81+
}
82+
83+
[HttpPost]
84+
[ValidateAntiForgeryToken]
85+
public IActionResult Delete(string userId)
86+
{
87+
_logger.LogInformation("Deleting user alias for user {UserId}", userId);
88+
89+
_userAliasService.DeleteAlias(userId);
90+
91+
TempData["Message"] = "Alias erfolgreich gelöscht!";
92+
return RedirectToAction(nameof(Index));
93+
}
94+
}

TgHomeBot.Api/Views/Easee/Login.cshtml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,12 @@
148148
<button type="submit" class="btn">Anmelden</button>
149149
</form>
150150

151+
<div style="margin-top: 20px;">
152+
<a href="/UserAlias" style="display: inline-block; padding: 12px 24px; background-color: #007bff; color: white; text-decoration: none; border-radius: 4px; text-align: center; width: 100%; box-sizing: border-box;">
153+
Benutzer-Aliase verwalten
154+
</a>
155+
</div>
156+
151157
<p style="margin-top: 20px; color: #666; font-size: 14px;">
152158
<strong>Hinweis:</strong> Die Zugangsdaten werden nicht gespeichert, sondern nur zur Authentifizierung mit der Easee API verwendet.
153159
</p>

0 commit comments

Comments
 (0)