diff --git a/auth_test.go b/auth_test.go new file mode 100644 index 0000000..1987c02 --- /dev/null +++ b/auth_test.go @@ -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 +} diff --git a/controllers.go b/controllers.go index e7254a5..ee2c453 100644 --- a/controllers.go +++ b/controllers.go @@ -255,8 +255,7 @@ func AdminAuthMiddleware() gin.HandlerFunc { // CreateInitialAdmin allows creation of the first admin user if none exist func (ctrl *Controller) CreateInitialAdmin(c *gin.Context) { // Only allow if no users exist - var count int - err := ctrl.repo.CountUsers(&count) + count, err := ctrl.repo.CountUsers(c.Request.Context()) if err != nil || count > 0 { c.JSON(http.StatusForbidden, gin.H{"error": "Admin user already exists or error"}) return @@ -272,7 +271,7 @@ func (ctrl *Controller) CreateInitialAdmin(c *gin.Context) { c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to hash password"}) return } - err = ctrl.repo.CreateUser(username, hash) + err = ctrl.repo.CreateUser(c.Request.Context(), username, hash) if err != nil { c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to create user"}) return diff --git a/go.mod b/go.mod index 1ea3fa1..a992042 100644 --- a/go.mod +++ b/go.mod @@ -10,6 +10,7 @@ require ( github.com/jackc/pgx/v5 v5.7.5 github.com/pressly/goose/v3 v3.26.0 github.com/sirupsen/logrus v1.9.3 + github.com/stretchr/testify v1.11.1 golang.org/x/crypto v0.42.0 gopkg.in/yaml.v3 v3.0.1 ) @@ -37,6 +38,7 @@ require ( github.com/bytedance/sonic v1.14.0 // indirect github.com/bytedance/sonic/loader v0.3.0 // 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/gin-contrib/sse v1.1.0 // 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/mschoch/smat v0.2.0 // 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/quic-go v0.54.0 // indirect github.com/sethvargo/go-retry v0.3.0 // indirect diff --git a/handlechat_integration_test.go b/handlechat_integration_test.go index 74c246a..870a7e6 100644 --- a/handlechat_integration_test.go +++ b/handlechat_integration_test.go @@ -74,6 +74,20 @@ func (r *mapChatRepo) ListLLMRawEvents(ctx context.Context, correlationID string } 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 // (avoids relying on real Bleve index) diff --git a/repository.go b/repository.go index ae45b29..aa3f79e 100644 --- a/repository.go +++ b/repository.go @@ -35,6 +35,8 @@ type ChatRepositoryAPI interface { ListKnowledgeModels(ctx context.Context, limit, offset int) ([]knowledgeModelMeta, error) GetKnowledgeModelText(ctx context.Context, id int64) (string, 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 @@ -246,13 +248,18 @@ func (r *PGChatRepository) GetUserByUsername(ctx context.Context, username strin } // CountUsers returns the number of users in the users table -func (r *PGChatRepository) CountUsers(count *int) error { - return r.pool.QueryRow(context.Background(), "SELECT COUNT(*) FROM users").Scan(count) +func (r *PGChatRepository) CountUsers(ctx context.Context) (int, error) { + 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 -func (r *PGChatRepository) CreateUser(username, passwordHash string) error { - _, err := r.pool.Exec(context.Background(), "INSERT INTO users (username, password_hash) VALUES ($1, $2)", username, passwordHash) +func (r *PGChatRepository) CreateUser(ctx context.Context, username, passwordHash string) error { + _, err := r.pool.Exec(ctx, "INSERT INTO users (username, password_hash) VALUES ($1, $2)", username, passwordHash) return err } diff --git a/visits.bleve/index_meta.json b/visits.bleve/index_meta.json deleted file mode 100644 index 5dc3405..0000000 --- a/visits.bleve/index_meta.json +++ /dev/null @@ -1 +0,0 @@ -{"storage":"boltdb","index_type":"scorch"} \ No newline at end of file diff --git a/visits.bleve/store/root.bolt b/visits.bleve/store/root.bolt deleted file mode 100644 index 914c19f..0000000 Binary files a/visits.bleve/store/root.bolt and /dev/null differ