From c3a15ccf1fe69df6c58800e954c5fd71457e1bae Mon Sep 17 00:00:00 2001 From: Matt Roberts Date: Fri, 28 Jun 2024 09:13:19 +0100 Subject: [PATCH 1/3] Show email on the member listing --- app/models/entity/user.go | 8 ++++---- public/components/common/UserName.scss | 7 +++++++ public/components/common/UserName.tsx | 3 +++ public/models/identity.ts | 1 + public/pages/Administration/pages/ManageMembers.page.tsx | 9 +++++++-- 5 files changed, 22 insertions(+), 6 deletions(-) diff --git a/app/models/entity/user.go b/app/models/entity/user.go index bcf37e02b..5e6df4923 100644 --- a/app/models/entity/user.go +++ b/app/models/entity/user.go @@ -2,12 +2,12 @@ package entity import "github.com/getfider/fider/app/models/enum" -//User represents an user inside our application +// User represents an user inside our application type User struct { ID int `json:"id"` Name string `json:"name"` Tenant *Tenant `json:"-"` - Email string `json:"-"` + Email string `json:"email"` Role enum.Role `json:"role"` Providers []*UserProvider `json:"-"` AvatarBlobKey string `json:"-"` @@ -16,7 +16,7 @@ type User struct { Status enum.UserStatus `json:"status"` } -//HasProvider returns true if current user has registered with given provider +// HasProvider returns true if current user has registered with given provider func (u *User) HasProvider(provider string) bool { for _, p := range u.Providers { if p.Name == provider { @@ -36,7 +36,7 @@ func (u *User) IsAdministrator() bool { return u.Role == enum.RoleAdministrator } -//UserProvider represents the relationship between an User and an Authentication provide +// UserProvider represents the relationship between an User and an Authentication provide type UserProvider struct { Name string UID string diff --git a/public/components/common/UserName.scss b/public/components/common/UserName.scss index aaa8a796b..e4c70594f 100644 --- a/public/components/common/UserName.scss +++ b/public/components/common/UserName.scss @@ -6,6 +6,13 @@ display: inline-flex; align-items: center; + &--email { + margin-left: 10px; + color: get("colors.gray.600"); + font-size: get("font.size.xs"); + font-weight: 400; + } + &--staff { color: get("colors.primary.base"); border-color: get("colors.primary.base"); diff --git a/public/components/common/UserName.tsx b/public/components/common/UserName.tsx index 8559d3bd0..b7a7eb7a7 100644 --- a/public/components/common/UserName.tsx +++ b/public/components/common/UserName.tsx @@ -9,6 +9,7 @@ interface UserNameProps { id: number name: string role?: UserRole + email?: string } } @@ -22,6 +23,8 @@ export const UserName = (props: UserNameProps) => { return (
{props.user.name || "Anonymous"} + <>{props.user.email && ({props.user.email})} + {isStaff && (
diff --git a/public/models/identity.ts b/public/models/identity.ts index 8b561fbd9..47755d91e 100644 --- a/public/models/identity.ts +++ b/public/models/identity.ts @@ -22,6 +22,7 @@ export enum TenantStatus { export interface User { id: number name: string + email?: string role: UserRole status: UserStatus avatarURL: string diff --git a/public/pages/Administration/pages/ManageMembers.page.tsx b/public/pages/Administration/pages/ManageMembers.page.tsx index 37a44592c..7ae349f00 100644 --- a/public/pages/Administration/pages/ManageMembers.page.tsx +++ b/public/pages/Administration/pages/ManageMembers.page.tsx @@ -69,6 +69,7 @@ export default class ManageMembersPage extends AdminBasePage { + return user.name.toLowerCase().indexOf(query.toLowerCase()) >= 0 || (user.email && user.email.toLowerCase().indexOf(query.toLowerCase()) >= 0) || false; + } + private handleSearchFilterChanged = (query: string) => { - const users = this.props.users.filter((x) => x.name.toLowerCase().indexOf(query.toLowerCase()) >= 0).sort(this.sortByStaff) + const users = this.props.users.filter((x) => this.memberFilter(query, x)).sort(this.sortByStaff) this.setState({ query, users, visibleUsers: users.slice(0, 10) }) } @@ -145,7 +150,7 @@ export default class ManageMembersPage extends AdminBasePage From 35ef53e052cac3b0b37f19e9a935726f07c8f325 Mon Sep 17 00:00:00 2001 From: Matt Roberts Date: Fri, 28 Jun 2024 14:15:25 +0100 Subject: [PATCH 2/3] Only include email when listing the members. --- app/handlers/admin.go | 11 ++++++- app/models/entity/user.go | 24 +++++++++++++-- app/models/entity/user_test.go | 55 ++++++++++++++++++++++++++++++++++ 3 files changed, 87 insertions(+), 3 deletions(-) create mode 100644 app/models/entity/user_test.go diff --git a/app/handlers/admin.go b/app/handlers/admin.go index 9bdae3174..38959925b 100644 --- a/app/handlers/admin.go +++ b/app/handlers/admin.go @@ -5,6 +5,7 @@ import ( "github.com/getfider/fider/app/actions" "github.com/getfider/fider/app/models/cmd" + "github.com/getfider/fider/app/models/entity" "github.com/getfider/fider/app/models/query" "github.com/getfider/fider/app/pkg/bus" "github.com/getfider/fider/app/pkg/web" @@ -126,11 +127,19 @@ func ManageMembers() web.HandlerFunc { return c.Failure(err) } + // Create an array of UserWithEmail structs from the allUsers.Result + allUsersWithEmail := make([]entity.UserWithEmail, len(allUsers.Result)) + for i, user := range allUsers.Result { + allUsersWithEmail[i] = entity.UserWithEmail{ + User: user, + } + } + return c.Page(http.StatusOK, web.Props{ Page: "Administration/pages/ManageMembers.page", Title: "Manage Members ยท Site Settings", Data: web.Map{ - "users": allUsers.Result, + "users": allUsersWithEmail, }, }) } diff --git a/app/models/entity/user.go b/app/models/entity/user.go index 5e6df4923..8e270e293 100644 --- a/app/models/entity/user.go +++ b/app/models/entity/user.go @@ -1,13 +1,17 @@ package entity -import "github.com/getfider/fider/app/models/enum" +import ( + "encoding/json" + + "github.com/getfider/fider/app/models/enum" +) // User represents an user inside our application type User struct { ID int `json:"id"` Name string `json:"name"` Tenant *Tenant `json:"-"` - Email string `json:"email"` + Email string `json:"-"` Role enum.Role `json:"role"` Providers []*UserProvider `json:"-"` AvatarBlobKey string `json:"-"` @@ -41,3 +45,19 @@ type UserProvider struct { Name string UID string } + +// UserWithEmail is a wrapper around User that includes the email field when marshaling to JSON +type UserWithEmail struct { + *User +} + +func (umc UserWithEmail) MarshalJSON() ([]byte, error) { + type Alias User // Prevent recursion + return json.Marshal(&struct { + *Alias + Email string `json:"email"` + }{ + Alias: (*Alias)(umc.User), + Email: umc.User.Email, + }) +} diff --git a/app/models/entity/user_test.go b/app/models/entity/user_test.go new file mode 100644 index 000000000..af391886b --- /dev/null +++ b/app/models/entity/user_test.go @@ -0,0 +1,55 @@ +package entity_test + +import ( + "encoding/json" + "testing" + + "github.com/getfider/fider/app/models/entity" + . "github.com/getfider/fider/app/pkg/assert" +) + +func TestUserWithEmail_MarshalJSON(t *testing.T) { + + RegisterT(t) + user := entity.UserWithEmail{ + User: &entity.User{ + ID: 1, + Name: "John Doe", + Email: "johndoe@example.com", + Role: 1, + Status: 1, + }, + } + + expectedJSON := `{"id":1,"name":"John Doe","role":"visitor","status":"active","email":"johndoe@example.com"}` + + jsonData, err := json.Marshal(user) + if err != nil { + t.Errorf("Failed to marshal user to JSON: %v", err) + } + + Expect(string(jsonData)).Equals(expectedJSON) + +} + +func TestUser_MarshalJSON(t *testing.T) { + + RegisterT(t) + user := entity.User{ + ID: 1, + Name: "John Doe", + Email: "johndoe@example.com", + Role: 1, + Status: 1, + } + + expectedJSON := `{"id":1,"name":"John Doe","role":"visitor","status":"active"}` + + jsonData, err := json.Marshal(user) + if err != nil { + t.Errorf("Failed to marshal user to JSON: %v", err) + } + + Expect(string(jsonData)).Equals(expectedJSON) + +} From 916cf9d97b89a2c624736581be27203756d2c7f3 Mon Sep 17 00:00:00 2001 From: Matt Roberts Date: Fri, 28 Jun 2024 14:32:23 +0100 Subject: [PATCH 3/3] lint fix. --- public/pages/Administration/pages/ManageMembers.page.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/public/pages/Administration/pages/ManageMembers.page.tsx b/public/pages/Administration/pages/ManageMembers.page.tsx index 7ae349f00..c058e4617 100644 --- a/public/pages/Administration/pages/ManageMembers.page.tsx +++ b/public/pages/Administration/pages/ManageMembers.page.tsx @@ -88,7 +88,7 @@ export default class ManageMembersPage extends AdminBasePage { - return user.name.toLowerCase().indexOf(query.toLowerCase()) >= 0 || (user.email && user.email.toLowerCase().indexOf(query.toLowerCase()) >= 0) || false; + return user.name.toLowerCase().indexOf(query.toLowerCase()) >= 0 || (user.email && user.email.toLowerCase().indexOf(query.toLowerCase()) >= 0) || false } private handleSearchFilterChanged = (query: string) => {