login handler
This commit is contained in:
parent
9f28daa4fa
commit
d297afb04a
|
|
@ -0,0 +1,53 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"errors"
|
||||||
|
)
|
||||||
|
|
||||||
|
var ErrUserExists = errors.New("user already exists")
|
||||||
|
var ErrUserNotFound = errors.New("user not found")
|
||||||
|
|
||||||
|
// mockRepo implements ChatRepositoryAPI for auth tests
|
||||||
|
// Only implements methods needed for auth
|
||||||
|
|
||||||
|
type mockRepo struct {
|
||||||
|
users map[string]string // username: passwordHash
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *mockRepo) CountUsers(ctx context.Context) (int, error) {
|
||||||
|
return len(m.users), nil
|
||||||
|
}
|
||||||
|
func (m *mockRepo) CreateUser(ctx context.Context, username, passwordHash string) error {
|
||||||
|
if _, exists := m.users[username]; exists {
|
||||||
|
return ErrUserExists
|
||||||
|
}
|
||||||
|
m.users[username] = passwordHash
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
func (m *mockRepo) GetUserByUsername(ctx context.Context, username string) (*User, error) {
|
||||||
|
hash, ok := m.users[username]
|
||||||
|
if !ok {
|
||||||
|
return nil, ErrUserNotFound
|
||||||
|
}
|
||||||
|
return &User{Username: username, PasswordHash: hash}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add stubs for all ChatRepositoryAPI methods not used in tests
|
||||||
|
func (m *mockRepo) SaveChatInteraction(ctx context.Context, rec ChatInteraction) error { return nil }
|
||||||
|
func (m *mockRepo) ListChatInteractions(ctx context.Context, limit, offset int) ([]ChatInteraction, error) {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
func (m *mockRepo) SaveLLMRawEvent(ctx context.Context, correlationID, phase, raw string) error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
func (m *mockRepo) ListLLMRawEvents(ctx context.Context, correlationID string, limit, offset int) ([]RawLLMEvent, error) {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
func (m *mockRepo) SaveKnowledgeModel(ctx context.Context, text string) error { return nil }
|
||||||
|
func (m *mockRepo) ListKnowledgeModels(ctx context.Context, limit, offset int) ([]knowledgeModelMeta, error) {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
func (m *mockRepo) GetKnowledgeModelText(ctx context.Context, id int64) (string, error) {
|
||||||
|
return "", nil
|
||||||
|
}
|
||||||
|
|
@ -255,8 +255,7 @@ func AdminAuthMiddleware() gin.HandlerFunc {
|
||||||
// CreateInitialAdmin allows creation of the first admin user if none exist
|
// CreateInitialAdmin allows creation of the first admin user if none exist
|
||||||
func (ctrl *Controller) CreateInitialAdmin(c *gin.Context) {
|
func (ctrl *Controller) CreateInitialAdmin(c *gin.Context) {
|
||||||
// Only allow if no users exist
|
// Only allow if no users exist
|
||||||
var count int
|
count, err := ctrl.repo.CountUsers(c.Request.Context())
|
||||||
err := ctrl.repo.CountUsers(&count)
|
|
||||||
if err != nil || count > 0 {
|
if err != nil || count > 0 {
|
||||||
c.JSON(http.StatusForbidden, gin.H{"error": "Admin user already exists or error"})
|
c.JSON(http.StatusForbidden, gin.H{"error": "Admin user already exists or error"})
|
||||||
return
|
return
|
||||||
|
|
@ -272,7 +271,7 @@ func (ctrl *Controller) CreateInitialAdmin(c *gin.Context) {
|
||||||
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to hash password"})
|
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to hash password"})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
err = ctrl.repo.CreateUser(username, hash)
|
err = ctrl.repo.CreateUser(c.Request.Context(), username, hash)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to create user"})
|
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to create user"})
|
||||||
return
|
return
|
||||||
|
|
|
||||||
3
go.mod
3
go.mod
|
|
@ -10,6 +10,7 @@ require (
|
||||||
github.com/jackc/pgx/v5 v5.7.5
|
github.com/jackc/pgx/v5 v5.7.5
|
||||||
github.com/pressly/goose/v3 v3.26.0
|
github.com/pressly/goose/v3 v3.26.0
|
||||||
github.com/sirupsen/logrus v1.9.3
|
github.com/sirupsen/logrus v1.9.3
|
||||||
|
github.com/stretchr/testify v1.11.1
|
||||||
golang.org/x/crypto v0.42.0
|
golang.org/x/crypto v0.42.0
|
||||||
gopkg.in/yaml.v3 v3.0.1
|
gopkg.in/yaml.v3 v3.0.1
|
||||||
)
|
)
|
||||||
|
|
@ -37,6 +38,7 @@ require (
|
||||||
github.com/bytedance/sonic v1.14.0 // indirect
|
github.com/bytedance/sonic v1.14.0 // indirect
|
||||||
github.com/bytedance/sonic/loader v0.3.0 // indirect
|
github.com/bytedance/sonic/loader v0.3.0 // indirect
|
||||||
github.com/cloudwego/base64x v0.1.6 // indirect
|
github.com/cloudwego/base64x v0.1.6 // indirect
|
||||||
|
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||||
github.com/gabriel-vasile/mimetype v1.4.8 // indirect
|
github.com/gabriel-vasile/mimetype v1.4.8 // indirect
|
||||||
github.com/gin-contrib/sse v1.1.0 // indirect
|
github.com/gin-contrib/sse v1.1.0 // indirect
|
||||||
github.com/go-playground/locales v0.14.1 // indirect
|
github.com/go-playground/locales v0.14.1 // indirect
|
||||||
|
|
@ -59,6 +61,7 @@ require (
|
||||||
github.com/modern-go/reflect2 v1.0.2 // indirect
|
github.com/modern-go/reflect2 v1.0.2 // indirect
|
||||||
github.com/mschoch/smat v0.2.0 // indirect
|
github.com/mschoch/smat v0.2.0 // indirect
|
||||||
github.com/pelletier/go-toml/v2 v2.2.4 // indirect
|
github.com/pelletier/go-toml/v2 v2.2.4 // indirect
|
||||||
|
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||||
github.com/quic-go/qpack v0.5.1 // indirect
|
github.com/quic-go/qpack v0.5.1 // indirect
|
||||||
github.com/quic-go/quic-go v0.54.0 // indirect
|
github.com/quic-go/quic-go v0.54.0 // indirect
|
||||||
github.com/sethvargo/go-retry v0.3.0 // indirect
|
github.com/sethvargo/go-retry v0.3.0 // indirect
|
||||||
|
|
|
||||||
|
|
@ -74,6 +74,20 @@ func (r *mapChatRepo) ListLLMRawEvents(ctx context.Context, correlationID string
|
||||||
}
|
}
|
||||||
return out, nil
|
return out, nil
|
||||||
}
|
}
|
||||||
|
func (r *mapChatRepo) CountUsers(ctx context.Context) (int, error) { return 0, nil }
|
||||||
|
func (r *mapChatRepo) CreateUser(ctx context.Context, username, passwordHash string) error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
func (r *mapChatRepo) GetUserByUsername(ctx context.Context, username string) (*User, error) {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
func (r *mapChatRepo) SaveKnowledgeModel(ctx context.Context, text string) error { return nil }
|
||||||
|
func (r *mapChatRepo) ListKnowledgeModels(ctx context.Context, limit, offset int) ([]knowledgeModelMeta, error) {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
func (r *mapChatRepo) GetKnowledgeModelText(ctx context.Context, id int64) (string, error) {
|
||||||
|
return "", nil
|
||||||
|
}
|
||||||
|
|
||||||
// testVisitDB2 replicates a minimal VisitDB for integration
|
// testVisitDB2 replicates a minimal VisitDB for integration
|
||||||
// (avoids relying on real Bleve index)
|
// (avoids relying on real Bleve index)
|
||||||
|
|
|
||||||
|
|
@ -35,6 +35,8 @@ type ChatRepositoryAPI interface {
|
||||||
ListKnowledgeModels(ctx context.Context, limit, offset int) ([]knowledgeModelMeta, error)
|
ListKnowledgeModels(ctx context.Context, limit, offset int) ([]knowledgeModelMeta, error)
|
||||||
GetKnowledgeModelText(ctx context.Context, id int64) (string, error)
|
GetKnowledgeModelText(ctx context.Context, id int64) (string, error)
|
||||||
GetUserByUsername(ctx context.Context, username string) (*User, error)
|
GetUserByUsername(ctx context.Context, username string) (*User, error)
|
||||||
|
CountUsers(ctx context.Context) (int, error)
|
||||||
|
CreateUser(ctx context.Context, username, passwordHash string) error
|
||||||
}
|
}
|
||||||
|
|
||||||
// RawLLMEvent represents a stored raw LLM exchange phase
|
// RawLLMEvent represents a stored raw LLM exchange phase
|
||||||
|
|
@ -246,13 +248,18 @@ func (r *PGChatRepository) GetUserByUsername(ctx context.Context, username strin
|
||||||
}
|
}
|
||||||
|
|
||||||
// CountUsers returns the number of users in the users table
|
// CountUsers returns the number of users in the users table
|
||||||
func (r *PGChatRepository) CountUsers(count *int) error {
|
func (r *PGChatRepository) CountUsers(ctx context.Context) (int, error) {
|
||||||
return r.pool.QueryRow(context.Background(), "SELECT COUNT(*) FROM users").Scan(count)
|
var count int
|
||||||
|
err := r.pool.QueryRow(ctx, "SELECT COUNT(*) FROM users").Scan(&count)
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
return count, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// CreateUser inserts a new user with username and password hash
|
// CreateUser inserts a new user with username and password hash
|
||||||
func (r *PGChatRepository) CreateUser(username, passwordHash string) error {
|
func (r *PGChatRepository) CreateUser(ctx context.Context, username, passwordHash string) error {
|
||||||
_, err := r.pool.Exec(context.Background(), "INSERT INTO users (username, password_hash) VALUES ($1, $2)", username, passwordHash)
|
_, err := r.pool.Exec(ctx, "INSERT INTO users (username, password_hash) VALUES ($1, $2)", username, passwordHash)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
{"storage":"boltdb","index_type":"scorch"}
|
|
||||||
Binary file not shown.
Loading…
Reference in New Issue