Skip to content

Commit 59459ab

Browse files
committed
feat: address review feedback for detail views
- Make parent groups clickable links (same as members) - Change member count to heading "N Direct Members:" - Add groups list to home screen with "N Direct Groups:" heading - Add LastLogon display to user detail view - Update simple-ldap-go to v1.8.0 for User.LastLogon field - Add ParentGroups field to FullLDAPGroup for resolved group objects - Update Index template to use FullLDAPUser with resolved groups
1 parent 825db33 commit 59459ab

File tree

7 files changed

+64
-29
lines changed

7 files changed

+64
-29
lines changed

go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ require (
88
github.com/gofiber/storage/bbolt/v2 v2.1.2
99
github.com/gofiber/storage/memory/v2 v2.1.1
1010
github.com/joho/godotenv v1.5.1
11-
github.com/netresearch/simple-ldap-go v1.7.0
11+
github.com/netresearch/simple-ldap-go v1.8.0
1212
github.com/playwright-community/playwright-go v0.5200.1
1313
github.com/rs/zerolog v1.34.0
1414
github.com/stretchr/testify v1.11.1

go.sum

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -135,8 +135,8 @@ github.com/moby/term v0.5.2 h1:6qk3FJAFDs6i/q3W/pQ97SX192qKfZgGjCQqfCJkgzQ=
135135
github.com/moby/term v0.5.2/go.mod h1:d3djjFCrjnB+fl8NJux+EJzu0msscUP+f8it8hPkFLc=
136136
github.com/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A=
137137
github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc=
138-
github.com/netresearch/simple-ldap-go v1.7.0 h1:eFCqDP38B750VP9VROS0SiTSQBLdlE37tTFAq0hAJaA=
139-
github.com/netresearch/simple-ldap-go v1.7.0/go.mod h1:Qx2OKwlIfykMU9JNDwjVLMcWHzOQbeqRrNF6oGTDB0A=
138+
github.com/netresearch/simple-ldap-go v1.8.0 h1:eQG0y2/eHPYjOxAyh5//DDN9SCkUO0lf7GqL/oT631E=
139+
github.com/netresearch/simple-ldap-go v1.8.0/go.mod h1:Qx2OKwlIfykMU9JNDwjVLMcWHzOQbeqRrNF6oGTDB0A=
140140
github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U=
141141
github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM=
142142
github.com/opencontainers/image-spec v1.1.1 h1:y0fUlFfIZhPF1W537XOLg0/fcx6zcHCJwooC2xJA040=

internal/ldap_cache/manager.go

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,8 @@ type FullLDAPUser struct {
5959
// This provides a complete view of group data including all member users.
6060
type FullLDAPGroup struct {
6161
ldap.Group
62-
Members []ldap.User // All users that belong to this group
62+
Members []ldap.User // All users that belong to this group
63+
ParentGroups []ldap.Group // All groups this group belongs to (from MemberOf)
6364
}
6465

6566
// FullLDAPComputer represents a computer with populated group memberships.
@@ -436,12 +437,14 @@ func (m *Manager) PopulateGroupsForUser(user *ldap.User) *FullLDAPUser {
436437

437438
// PopulateUsersForGroup creates a FullLDAPGroup with populated member list.
438439
// Takes a group and resolves all member DNs to full user objects from the cache.
440+
// Also resolves parent groups from the MemberOf field.
439441
// When showDisabled is false, filters out disabled users from membership.
440-
// Returns a complete group object with expanded member information.
442+
// Returns a complete group object with expanded member and parent group information.
441443
func (m *Manager) PopulateUsersForGroup(group *ldap.Group, showDisabled bool) *FullLDAPGroup {
442444
full := &FullLDAPGroup{
443-
Group: *group,
444-
Members: make([]ldap.User, 0),
445+
Group: *group,
446+
Members: make([]ldap.User, 0),
447+
ParentGroups: make([]ldap.Group, 0),
445448
}
446449

447450
for _, userDN := range group.Members {
@@ -455,6 +458,14 @@ func (m *Manager) PopulateUsersForGroup(group *ldap.Group, showDisabled bool) *F
455458
}
456459
}
457460

461+
// Resolve parent groups from MemberOf
462+
for _, parentDN := range group.MemberOf {
463+
parentGroup, err := m.FindGroupByDN(parentDN)
464+
if err == nil {
465+
full.ParentGroups = append(full.ParentGroups, *parentGroup)
466+
}
467+
}
468+
458469
return full
459470
}
460471

internal/web/server.go

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -368,8 +368,11 @@ func (a *App) indexHandler(c *fiber.Ctx) error {
368368
return handle500(c, err)
369369
}
370370

371+
// Populate groups for the home screen
372+
fullUser := a.ldapCache.PopulateGroupsForUser(user)
373+
371374
// Use template caching
372-
return a.templateCache.RenderWithCache(c, templates.Index(user))
375+
return a.templateCache.RenderWithCache(c, templates.Index(fullUser))
373376
}
374377

375378
func (a *App) fourOhFourHandler(c *fiber.Ctx) error {

internal/web/templates/groups.templ

Lines changed: 16 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -32,29 +32,30 @@ templ Group(group *ldap_cache.FullLDAPGroup, unassignedUsers []ldap.User, flashe
3232
@loggedIn(string(groupUrl(group.Group)), group.CN(), flashes) {
3333
<h1 class="text-3xl">{ group.CN() }</h1>
3434
<p class="text-sm text-text-secondary">@Copyable(group.DN())</p>
35-
<div class="mt-4 grid gap-2 sm:grid-cols-2">
36-
if group.Description != "" {
37-
<div class="rounded-md border border-border bg-surface-elevated px-3 py-2">
38-
<span class="text-sm text-text-secondary">Description</span>
39-
<p class="font-medium">{ group.Description }</p>
40-
</div>
41-
}
42-
<div class="rounded-md border border-border bg-surface-elevated px-3 py-2">
43-
<span class="text-sm text-text-secondary">Member count</span>
44-
<p class="font-medium">{ fmt.Sprintf("%d", len(group.Members)) }</p>
35+
if group.Description != "" {
36+
<div class="mt-4 rounded-md border border-border bg-surface-elevated px-3 py-2">
37+
<span class="text-sm text-text-secondary">Description</span>
38+
<p class="font-medium">{ group.Description }</p>
4539
</div>
46-
</div>
40+
}
4741
if len(group.MemberOf) > 0 {
48-
<h2 class="mt-4 text-xl">Parent groups:</h2>
42+
<h2 class="mt-4 text-xl">{ fmt.Sprintf("%d Parent Groups:", len(group.MemberOf)) }</h2>
4943
<div class="list-container">
50-
for _, parentDN := range group.MemberOf {
44+
for _, parentGroup := range group.ParentGroups {
5145
<div class="list-row">
52-
<span class="px-3 py-2 text-sm text-text-secondary">{ parentDN }</span>
46+
<a
47+
href={ groupUrl(parentGroup) }
48+
class="list-link"
49+
title={ "View group details: " + parentGroup.CN() }
50+
>
51+
<span>{ parentGroup.CN() }</span>
52+
@rightArrowIcon()
53+
</a>
5354
</div>
5455
}
5556
</div>
5657
}
57-
<h2 class="mt-4 text-xl">Members:</h2>
58+
<h2 class="mt-4 text-xl">{ fmt.Sprintf("%d Direct Members:", len(group.Members)) }</h2>
5859
<div class="list-container">
5960
for _, user := range group.Members {
6061
<div class="list-row">

internal/web/templates/index.templ

Lines changed: 20 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
package templates
22

3-
import "github.com/netresearch/simple-ldap-go"
3+
import "github.com/netresearch/ldap-manager/internal/ldap_cache"
44
import "fmt"
55

6-
templ Index(user *ldap.User) {
6+
templ Index(user *ldap_cache.FullLDAPUser) {
77
@loggedIn("/", "Home", []Flash{}) {
88
<h1 class="mb-4 text-3xl">Hi { user.CN() }!</h1>
99
if user.Description != "" {
@@ -28,11 +28,25 @@ templ Index(user *ldap.User) {
2828
</a>
2929
</p>
3030
}
31-
<p>
32-
<span class="text-text-secondary">Groups: </span>
33-
<span>{ fmt.Sprintf("%d", len(user.Groups)) } memberships</span>
34-
</p>
3531
</div>
32+
<h2 class="mt-4 text-xl">{ fmt.Sprintf("%d Direct Groups:", len(user.Groups)) }</h2>
33+
<div class="list-container">
34+
for _, group := range user.Groups {
35+
<div class="list-row">
36+
<a
37+
href={ groupUrl(group) }
38+
class="list-link"
39+
title={ "View group details: " + group.CN() }
40+
>
41+
<span>{ group.CN() }</span>
42+
@rightArrowIcon()
43+
</a>
44+
</div>
45+
}
46+
</div>
47+
if len(user.Groups) == 0 {
48+
<p class="text-text-secondary">No group memberships</p>
49+
}
3650
}
3751
}
3852

internal/web/templates/users.templ

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,12 @@ templ User(user *ldap_cache.FullLDAPUser, unassignedGroups []ldap.Group, flashes
5454
<p class="font-medium">{ user.Description }</p>
5555
</div>
5656
}
57+
if user.LastLogon > 0 {
58+
<div class="rounded-md border border-border bg-surface-elevated px-3 py-2">
59+
<span class="text-sm text-text-secondary">Last Logon</span>
60+
<p class="font-medium">{ formatLastLogon(user.LastLogon) }</p>
61+
</div>
62+
}
5763
</div>
5864
<h2 class="mt-4 text-xl">Groups:</h2>
5965
<div class="list-container">

0 commit comments

Comments
 (0)