Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion middleware/auth.go
Original file line number Diff line number Diff line change
Expand Up @@ -108,4 +108,3 @@ func Auth(acceptableRoles ...Role) func(c *gin.Context) {
Build())
}
}

2 changes: 1 addition & 1 deletion middleware/event_action.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ func GetClientFromContext(c *gin.Context) (clientId int64, err error) {
}

/*
Get event and put to context.
Get event and put to context.
This middleware should be added to any route that performs event action.
*/
func EventActionPreProcess(c *gin.Context) {
Expand Down
6 changes: 3 additions & 3 deletions middleware/huma_auth.go
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ func authenticateToken(authHeader string) (*AuthContext, error) {
if err != nil || !tokenParsed.Valid {
return nil, err
}

return &AuthContext{
ID: claims.Who,
Member: claims.Member,
Expand Down Expand Up @@ -153,7 +153,7 @@ func authenticateToken(authHeader string) (*AuthContext, error) {
Role: userRoles,
UserInfo: userinfo,
}

return &AuthContext{
User: user,
ID: member.MemberId,
Expand Down Expand Up @@ -196,4 +196,4 @@ func AuthenticateUserWithContext(ctx context.Context, authHeader string, accepta

// Fallback to original implementation for backward compatibility
return AuthenticateUser(authHeader, acceptableRoles...)
}
}
22 changes: 11 additions & 11 deletions middleware/huma_auth_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -183,7 +183,7 @@ func TestHumaAuthMiddleware(t *testing.T) {
ShouldFail: false,
},
{
CaseID: "1.2",
CaseID: "1.2",
Description: "Valid legacy JWT token with admin role",
Authorization: util.GenToken("admin", "2333333333"),
ExpectedAuth: true,
Expand Down Expand Up @@ -253,21 +253,21 @@ func TestHumaAuthMiddleware(t *testing.T) {
if capturedCtx != nil {
authCtx = middleware.GetAuthContextFromHuma(capturedCtx)
}

if tc.ExpectedAuth {
if authCtx == nil {
t.Errorf("Expected auth context to be set for case %s", tc.CaseID)
return
}

if authCtx.Role != tc.ExpectedRole {
t.Errorf("Expected role %s, got %s", tc.ExpectedRole, authCtx.Role)
}

if authCtx.ID == "" {
t.Error("Expected user ID to be set")
}

if !authCtx.IsLegacyJWT {
t.Error("Expected legacy JWT flag to be true")
}
Expand Down Expand Up @@ -302,7 +302,7 @@ func TestRequireAuthMiddleware(t *testing.T) {
ExpectedContinue: true,
},
{
CaseID: "2.2",
CaseID: "2.2",
Description: "Member access with member or admin role required",
AuthContext: &middleware.AuthContext{
ID: "member123",
Expand All @@ -326,7 +326,7 @@ func TestRequireAuthMiddleware(t *testing.T) {
Description: "Client access with admin role required",
AuthContext: &middleware.AuthContext{
ID: "client123",
Role: "client",
Role: "client",
IsLegacyJWT: true,
},
RequiredRoles: []middleware.Role{"admin"},
Expand All @@ -351,7 +351,7 @@ func TestRequireAuthMiddleware(t *testing.T) {
t.Run(tc.CaseID+"_"+tc.Description, func(t *testing.T) {
// Create mock context
mockCtx := NewMockHumaContext()

// Set auth context if provided
if tc.AuthContext != nil {
mockCtx.ctx = context.WithValue(mockCtx.ctx, middleware.GetAuthContextKey(), tc.AuthContext)
Expand Down Expand Up @@ -408,7 +408,7 @@ func TestGetAuthContextFromHuma(t *testing.T) {
for _, tc := range testCases {
t.Run(tc.CaseID+"_"+tc.Description, func(t *testing.T) {
mockCtx := NewMockHumaContext()

if tc.SetContext && tc.AuthContext != nil {
mockCtx.ctx = context.WithValue(mockCtx.ctx, middleware.GetAuthContextKey(), tc.AuthContext)
}
Expand Down Expand Up @@ -484,7 +484,7 @@ func TestAuthenticateUserWithContext(t *testing.T) {
for _, tc := range testCases {
t.Run(tc.CaseID+"_"+tc.Description, func(t *testing.T) {
ctx := context.Background()

if tc.ContextAuth != nil {
ctx = context.WithValue(ctx, middleware.GetAuthContextKey(), tc.ContextAuth)
}
Expand All @@ -510,4 +510,4 @@ func TestAuthenticateUserWithContext(t *testing.T) {
}
})
}
}
}
10 changes: 5 additions & 5 deletions middleware/huma_helpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ func AuthenticateUser(authHeader string, acceptableRoles ...Role) (*AuthContext,
if err != nil || !tokenParsed.Valid {
return nil, huma.Error401Unauthorized("not authorized, token not valid")
}

for _, roleObj := range acceptableRoles {
if string(roleObj) == claims.Role {
return &AuthContext{
Expand Down Expand Up @@ -90,7 +90,7 @@ func AuthenticateUser(authHeader string, acceptableRoles ...Role) (*AuthContext,
Role: userRoles,
UserInfo: userinfo,
}

return &AuthContext{
User: user,
ID: member.MemberId,
Expand Down Expand Up @@ -137,11 +137,11 @@ func CreateIdentityFromAuth(auth *AuthContext) model.Identity {
Id: auth.ID,
Role: auth.Role,
}

if member, ok := auth.Member.(model.Member); ok {
identity.Member = member
}

return identity
}

Expand All @@ -167,4 +167,4 @@ func GetClientIdFromAuthContext(ctx context.Context) (int64, error) {
func MustGetEventContext(ctx context.Context) struct{ Event model.Event } {
// This function is not used in the new approach
panic("MustGetEventContext should not be called in new Huma operations")
}
}
12 changes: 6 additions & 6 deletions middleware/huma_logger.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,25 +12,25 @@ import (
func HumaLogger() func(ctx huma.Context, next func(huma.Context)) {
return func(ctx huma.Context, next func(huma.Context)) {
startTime := time.Now()

// Process request
next(ctx)

endTime := time.Now()
latencyTime := endTime.Sub(startTime).Microseconds()

// Extract user ID from auth context if available
var userID string
if auth := GetAuthContext(ctx.Context()); auth != nil {
userID = auth.ID
}

// Get response status from context
status := ctx.Status()
if status == 0 {
status = 200 // Default to 200 if not set
}

util.Logger.WithFields(logrus.Fields{
"status_code": status,
"latency": latencyTime,
Expand All @@ -43,4 +43,4 @@ func HumaLogger() func(ctx huma.Context, next func(huma.Context)) {
"userId": userID,
}).Info("HTTP Request")
}
}
}
2 changes: 1 addition & 1 deletion middleware/logger.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ func Logger(c *gin.Context) {

endTime := time.Now()

latencyTime := endTime.Sub(startTime).Microseconds()
latencyTime := endTime.Sub(startTime).Microseconds()

util.Logger.WithFields(logrus.Fields{
"status_code": c.Writer.Status(),
Expand Down
17 changes: 17 additions & 0 deletions migrations/000007_optional_client_id.down.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
-- Rollback: Make client_id mandatory again in event table
-- This rollback will fail if there are any events with NULL client_id

-- Remove the indexes we added
DROP INDEX IF EXISTS public.event_anonymous_idx;
DROP INDEX IF EXISTS public.event_client_id_not_null_idx;

-- Drop the modified foreign key constraint
ALTER TABLE public.event DROP CONSTRAINT event_client_id_fkey;

-- Make client_id NOT NULL again (this will fail if there are NULL values)
ALTER TABLE public.event ALTER COLUMN client_id SET NOT NULL;

-- Recreate the original foreign key constraint
ALTER TABLE public.event ADD CONSTRAINT event_client_id_fkey
FOREIGN KEY (client_id) REFERENCES public.client(client_id)
ON UPDATE RESTRICT ON DELETE RESTRICT;
19 changes: 19 additions & 0 deletions migrations/000007_optional_client_id.up.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
-- Make client_id nullable in event table to allow anonymous event creation
-- Related to: https://github.com/nbtca/Saturday/issues/192

-- Drop existing foreign key constraint
ALTER TABLE public.event DROP CONSTRAINT event_client_id_fkey;

-- Make client_id nullable
ALTER TABLE public.event ALTER COLUMN client_id DROP NOT NULL;

-- Recreate foreign key constraint allowing NULL values
ALTER TABLE public.event ADD CONSTRAINT event_client_id_fkey
FOREIGN KEY (client_id) REFERENCES public.client(client_id)
ON UPDATE RESTRICT ON DELETE SET NULL;

-- Add index for efficient querying of anonymous events (where client_id IS NULL)
CREATE INDEX event_anonymous_idx ON public.event (client_id) WHERE client_id IS NULL;

-- Add index for better performance on non-null client_id queries
CREATE INDEX event_client_id_not_null_idx ON public.event (client_id) WHERE client_id IS NOT NULL;
2 changes: 1 addition & 1 deletion model/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ package model
type Client struct {
ClientId int64 `json:"clientId" db:"client_id"`
OpenId string `json:"openid"`
LogtoId string `json:"logtoId" db:"logto_id"`
LogtoId string `json:"logtoId" db:"logto_id"`
GmtCreate string `json:"gmtCreate" db:"gmt_create"`
GmtModified string `json:"gmtModified" db:"gmt_modified"`
}
4 changes: 2 additions & 2 deletions model/dto/event.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,12 @@ type EventID struct {

type CommitRequest struct {
Content string `json:"content"`
Size string `json:"size"`
Size string `json:"size"`
}

type AlterCommitRequest struct {
Content string `json:"content"`
Size string `json:"size"`
Size string `json:"size"`
}

type UpdateRequest struct {
Expand Down
12 changes: 10 additions & 2 deletions model/event.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import (

type Event struct {
EventId int64 `json:"eventId" db:"event_id"`
ClientId int64 `json:"clientId" db:"client_id"`
ClientId sql.NullInt64 `json:"clientId,omitempty" db:"client_id"`
GithubIssueId sql.NullInt64 `json:"githubIssueId" db:"github_issue_id"`
GithubIssueNumber sql.NullInt64 `json:"githubIssueNumber" db:"github_issue_number"`
Model string `json:"model"`
Expand Down Expand Up @@ -69,7 +69,7 @@ type EventAction struct {

type PublicEvent struct {
EventId int64 `json:"eventId" db:"event_id"`
ClientId int64 `json:"clientId" db:"client_id"`
ClientId sql.NullInt64 `json:"clientId,omitempty" db:"client_id"`
Model string `json:"model"`
Problem string `json:"problem" db:"event_description"`
MemberId string `json:"-" db:"member_id"`
Expand Down Expand Up @@ -140,3 +140,11 @@ type EventExportedGroupedByMember struct {
MemberPhone string
Hour float64
}

type CreateAnonymousEventRequest struct {
Model string `json:"model" validate:"omitempty,max=40"`
Phone string `json:"phone" validate:"required,len=11,numeric"`
QQ string `json:"qq" validate:"omitempty,min=5,max=20,numeric"`
ContactPreference string `json:"contactPreference" validate:"required,oneof=phone qq"`
Problem string `json:"problem" validate:"required,max=1000"`
}
2 changes: 1 addition & 1 deletion model/setting.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@ package model

type Setting struct {
Setting string `json:"setting"`
}
}
1 change: 0 additions & 1 deletion repo/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,6 @@ func GetClientByLogtoId(logtoId string) (model.Client, error) {
return client, nil
}


func CreateClient(client *model.Client) error {
client.GmtCreate = util.GetDate()
client.GmtModified = util.GetDate()
Expand Down
10 changes: 5 additions & 5 deletions repo/event.go
Original file line number Diff line number Diff line change
Expand Up @@ -307,12 +307,12 @@ func SetEventStatus(eventId int64, status string, conn *sqlx.Tx) (sql.Result, er
return conn.Exec(db.Rebind(sql), eventId, status, status)
}

func GetEventClientId(eventId int64) (int64, error) {
var clientId int64
sql, args, _ := sq.Select("client_id").From("event").Where(squirrel.Eq{"event_id": eventId}).ToSql()
err := db.Get(&clientId, sql, args...)
func GetEventClientId(eventId int64) (sql.NullInt64, error) {
var clientId sql.NullInt64
sqlStr, args, _ := sq.Select("client_id").From("event").Where(squirrel.Eq{"event_id": eventId}).ToSql()
err := db.Get(&clientId, sqlStr, args...)
if err != nil {
return 0, err
return sql.NullInt64{}, err
}
return clientId, nil
}
4 changes: 2 additions & 2 deletions router/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ func (ClientRouter) CreateTokenViaLogto(ctx context.Context, input *CreateTokenV
if err != nil {
return nil, err
}

logtoId := auth.User.UserInfo.Sub
if logtoId == "" {
return nil, huma.Error422UnprocessableEntity("user not found")
Expand All @@ -62,7 +62,7 @@ func (ClientRouter) CreateTokenViaLogto(ctx context.Context, input *CreateTokenV
if err != nil {
return nil, huma.Error422UnprocessableEntity(err.Error())
}

response := dto.ClientTokenResponse{
Token: token,
Client: client,
Expand Down
Loading