Skip to content

Commit 8425073

Browse files
committed
Fix up membership date rendering
1 parent 8aee30c commit 8425073

File tree

8 files changed

+664
-28
lines changed

8 files changed

+664
-28
lines changed

multipass/internal/handlers/public.go

Lines changed: 29 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import (
55
"log"
66
"multipass/internal/config"
77
"multipass/internal/models"
8+
"multipass/internal/services"
89
"multipass/internal/utils"
910
"net/http"
1011
"net/url"
@@ -33,14 +34,19 @@ func PublicCardHandler(c *gin.Context) {
3334
// Load config
3435
cfg := config.Load()
3536

36-
// Build membership info (simplified version)
37-
// In a real implementation, this would be fetched from a database or service
38-
membershipInfo := &models.MembershipInfo{
39-
MembershipType: "Digital Member",
40-
Status: models.StatusActive,
41-
UserLevel: user.AccessLevel,
42-
JoinDate: getDefaultJoinDate(),
43-
ExpiryDate: getDefaultExpiryDate(),
37+
// Get membership info from the membership service
38+
membershipService := services.NewMembershipService()
39+
membershipInfo, err := membershipService.GetMembershipInfo(user)
40+
if err != nil {
41+
log.Printf("[ERROR] Failed to retrieve membership info: %v", err)
42+
// Fall back to default membership info if service fails
43+
membershipInfo = &models.MembershipInfo{
44+
MembershipType: "Digital Member",
45+
Status: models.StatusActive,
46+
UserLevel: user.AccessLevel,
47+
JoinDate: getDefaultJoinDate(),
48+
ExpiryDate: getDefaultExpiryDate(),
49+
}
4450
}
4551

4652
// Get debug info if available
@@ -74,6 +80,18 @@ func PublicCardHandler(c *gin.Context) {
7480
// Convert to template.HTML to prevent escaping
7581
qrCodeHTML := template.HTML("<img src=\"" + qrCodeBase64 + "\" alt=\"QR Code\" class=\"qr-code\">")
7682

83+
// Format dates for display
84+
joinDateStr := "Unknown"
85+
expiryDateStr := "Unknown"
86+
87+
if membershipInfo.JoinDate != nil {
88+
joinDateStr = membershipInfo.JoinDate.Format("Jan 2, 2006")
89+
}
90+
91+
if membershipInfo.ExpiryDate != nil {
92+
expiryDateStr = membershipInfo.ExpiryDate.Format("Jan 2, 2006")
93+
}
94+
7795
// Prepare template data
7896
templateData := gin.H{
7997
"title": "Digital ID Card - " + cfg.MakerspaceName,
@@ -84,6 +102,9 @@ func PublicCardHandler(c *gin.Context) {
84102
"qr_code_html": qrCodeHTML, // Add QR code HTML
85103
"qr_data": fullURL, // Keep the URL as data attribute for backward compatibility
86104
"public_view": true, // Flag to indicate this is a public view
105+
"current_time": time.Now().Format("Jan 2, 2006 15:04:05"), // Current time for reference
106+
"join_date": joinDateStr, // Member since date
107+
"expiry_date": expiryDateStr, // Membership expiry date
87108
}
88109

89110
// Add debug info if available

multipass/internal/middleware/debug.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,8 +41,8 @@ func DebugAuthMiddleware() gin.HandlerFunc {
4141
if debugMode || cfg.IsDevelopment() {
4242
// Collect all headers for debugging
4343
debugInfo := map[string]string{
44-
"X-Authentik-Email": c.GetHeader("X-Authentik-Email"),
45-
"X-Authentik-Name": c.GetHeader("X-Authentik-Name"),
44+
"X-Authentik-Email": c.GetHeader("X-Authentik-Email"),
45+
"X-Authentik-Name": c.GetHeader("X-Authentik-Name"),
4646
"X-Authentik-Groups": c.GetHeader("X-Authentik-Groups"),
4747
}
4848

multipass/internal/models/user.go

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -33,14 +33,18 @@ func (ul UserLevel) String() string {
3333
}
3434

3535
type UserProfile struct {
36-
Email string `json:"email"`
37-
FullName string `json:"full_name"`
38-
Groups []string `json:"groups"`
39-
Avatar *string `json:"avatar,omitempty"`
40-
Phone *string `json:"phone,omitempty"`
41-
MemberID string `json:"member_id"`
42-
AccessLevel UserLevel `json:"access_level"`
43-
AuthentikID string `json:"authentik_id,omitempty"`
36+
Email string `json:"email"`
37+
FullName string `json:"full_name"`
38+
Groups []string `json:"groups"`
39+
Avatar *string `json:"avatar,omitempty"`
40+
Phone *string `json:"phone,omitempty"`
41+
MemberID string `json:"member_id"`
42+
AccessLevel UserLevel `json:"access_level"`
43+
AuthentikID string `json:"authentik_id,omitempty"`
44+
MemberSince string `json:"member_since,omitempty"`
45+
MembershipType string `json:"membership_type,omitempty"`
46+
ExpiryDate string `json:"expiry_date,omitempty"`
47+
MembershipStatus string `json:"membership_status,omitempty"`
4448
}
4549

4650
type UserFromHeaders struct {

multipass/internal/services/authentik.go

Lines changed: 45 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -24,14 +24,15 @@ type AuthentikClient struct {
2424

2525
// AuthentikUserResponse represents the response from Authentik's user API
2626
type AuthentikUserResponse struct {
27-
ID int `json:"pk"`
28-
Username string `json:"username"`
29-
Name string `json:"name"`
30-
Email string `json:"email"`
31-
IsActive bool `json:"is_active"`
32-
LastLogin string `json:"last_login"`
33-
Groups []string `json:"groups"`
34-
Avatar string `json:"avatar"`
27+
ID int `json:"pk"`
28+
Username string `json:"username"`
29+
Name string `json:"name"`
30+
Email string `json:"email"`
31+
IsActive bool `json:"is_active"`
32+
LastLogin string `json:"last_login"`
33+
Groups []string `json:"groups"`
34+
Avatar string `json:"avatar"`
35+
Attributes map[string]interface{} `json:"attributes"`
3536
}
3637

3738
// NewAuthentikClient creates a new Authentik API client
@@ -230,6 +231,12 @@ func (ac *AuthentikClient) GetUserByEmail(email string) (*models.UserProfile, er
230231
return createUserProfileFromAuthentikUser(ac, authUser)
231232
}
232233

234+
// Check if we have any results
235+
if len(paginatedResponse.Results) == 0 {
236+
log.Printf("[ERROR] No user found with email: %s in paginated response", email)
237+
return nil, errors.New("user not found")
238+
}
239+
233240
// Get first user from paginated response
234241
authUser := paginatedResponse.Results[0]
235242
log.Printf("[DEBUG] Found user by email in paginated response: %s (ID: %d)", authUser.Name, authUser.ID)
@@ -264,6 +271,36 @@ func createUserProfileFromAuthentikUser(ac *AuthentikClient, authUser AuthentikU
264271
userProfile.Avatar = &authUser.Avatar
265272
}
266273

274+
// Extract user attributes/metadata
275+
if authUser.Attributes != nil {
276+
// Log available attributes for debugging
277+
log.Printf("[DEBUG] User attributes for %s: %v", authUser.Email, authUser.Attributes)
278+
279+
// Extract member_since if available
280+
if memberSince, ok := authUser.Attributes["member_since"].(string); ok {
281+
log.Printf("[DEBUG] Found member_since attribute: %s", memberSince)
282+
userProfile.MemberSince = memberSince
283+
}
284+
285+
// Extract membership_type if available
286+
if membershipType, ok := authUser.Attributes["membership_type"].(string); ok {
287+
log.Printf("[DEBUG] Found membership_type attribute: %s", membershipType)
288+
userProfile.MembershipType = membershipType
289+
}
290+
291+
// Extract expiry_date if available
292+
if expiryDate, ok := authUser.Attributes["expiry_date"].(string); ok {
293+
log.Printf("[DEBUG] Found expiry_date attribute: %s", expiryDate)
294+
userProfile.ExpiryDate = expiryDate
295+
}
296+
297+
// Extract membership_status if available
298+
if status, ok := authUser.Attributes["membership_status"].(string); ok {
299+
log.Printf("[DEBUG] Found membership_status attribute: %s", status)
300+
userProfile.MembershipStatus = status
301+
}
302+
}
303+
267304
return userProfile, nil
268305
}
269306

0 commit comments

Comments
 (0)