Remove too many debug messages

This commit is contained in:
2024-12-19 22:00:42 +01:00
parent 0aa67f5cc2
commit b065938211
26 changed files with 75 additions and 586 deletions

View File

@@ -23,7 +23,6 @@ func initSecretsService(cfg *Config) (secrets.Service, error) {
if err != nil { if err != nil {
return nil, fmt.Errorf("failed to initialize secrets service: %w", err) return nil, fmt.Errorf("failed to initialize secrets service: %w", err)
} }
logging.Debug("secrets service initialized")
return secretsService, nil return secretsService, nil
} }
@@ -36,12 +35,10 @@ func initDatabase(cfg *Config, secretsService secrets.Service) (db.Database, err
return nil, fmt.Errorf("failed to initialize database: %w", err) return nil, fmt.Errorf("failed to initialize database: %w", err)
} }
logging.Debug("running database migrations")
if err := database.Migrate(); err != nil { if err := database.Migrate(); err != nil {
return nil, fmt.Errorf("failed to apply database migrations: %w", err) return nil, fmt.Errorf("failed to apply database migrations: %w", err)
} }
logging.Debug("database initialization complete")
return database, nil return database, nil
} }
@@ -61,14 +58,8 @@ func initAuth(cfg *Config, database db.Database) (auth.JWTManager, auth.SessionM
if err != nil { if err != nil {
return nil, nil, nil, fmt.Errorf("failed to ensure JWT secret: %w", err) return nil, nil, nil, fmt.Errorf("failed to ensure JWT secret: %w", err)
} }
logging.Debug("JWT signing key generated")
} }
logging.Debug("initializing JWT service",
"accessTokenExpiry", accessTokeExpiry.String(),
"refreshTokenExpiry", refreshTokenExpiry.String())
// Initialize JWT service
jwtManager, err := auth.NewJWTService(auth.JWTConfig{ jwtManager, err := auth.NewJWTService(auth.JWTConfig{
SigningKey: signingKey, SigningKey: signingKey,
AccessTokenExpiry: accessTokeExpiry, AccessTokenExpiry: accessTokeExpiry,
@@ -78,24 +69,14 @@ func initAuth(cfg *Config, database db.Database) (auth.JWTManager, auth.SessionM
return nil, nil, nil, fmt.Errorf("failed to initialize JWT service: %w", err) return nil, nil, nil, fmt.Errorf("failed to initialize JWT service: %w", err)
} }
// Initialize session service
logging.Debug("initializing session service")
sessionManager := auth.NewSessionService(database, jwtManager) sessionManager := auth.NewSessionService(database, jwtManager)
// Initialize cookie service
logging.Debug("initializing cookie service",
"isDevelopment", cfg.IsDevelopment,
"domain", cfg.Domain)
cookieService := auth.NewCookieService(cfg.IsDevelopment, cfg.Domain) cookieService := auth.NewCookieService(cfg.IsDevelopment, cfg.Domain)
logging.Debug("authentication services initialized")
return jwtManager, sessionManager, cookieService, nil return jwtManager, sessionManager, cookieService, nil
} }
// setupAdminUser creates the admin user if it doesn't exist // setupAdminUser creates the admin user if it doesn't exist
func setupAdminUser(database db.Database, storageManager storage.Manager, cfg *Config) error { func setupAdminUser(database db.Database, storageManager storage.Manager, cfg *Config) error {
logging.Debug("checking for existing admin user", "email", cfg.AdminEmail)
// Check if admin user exists // Check if admin user exists
adminUser, err := database.GetUserByEmail(cfg.AdminEmail) adminUser, err := database.GetUserByEmail(cfg.AdminEmail)
if err != nil && err != sql.ErrNoRows { if err != nil && err != sql.ErrNoRows {
@@ -107,8 +88,6 @@ func setupAdminUser(database db.Database, storageManager storage.Manager, cfg *C
return nil return nil
} }
logging.Debug("creating new admin user")
// Hash the password // Hash the password
hashedPassword, err := bcrypt.GenerateFromPassword([]byte(cfg.AdminPassword), bcrypt.DefaultCost) hashedPassword, err := bcrypt.GenerateFromPassword([]byte(cfg.AdminPassword), bcrypt.DefaultCost)
if err != nil { if err != nil {
@@ -128,15 +107,6 @@ func setupAdminUser(database db.Database, storageManager storage.Manager, cfg *C
return fmt.Errorf("failed to create admin user: %w", err) return fmt.Errorf("failed to create admin user: %w", err)
} }
logging.Debug("admin user created",
"userId", createdUser.ID,
"workspaceId", createdUser.LastWorkspaceID)
// Initialize workspace directory
logging.Debug("initializing admin workspace directory",
"userId", createdUser.ID,
"workspaceId", createdUser.LastWorkspaceID)
err = storageManager.InitializeUserWorkspace(createdUser.ID, createdUser.LastWorkspaceID) err = storageManager.InitializeUserWorkspace(createdUser.ID, createdUser.LastWorkspaceID)
if err != nil { if err != nil {
return fmt.Errorf("failed to initialize admin workspace: %w", err) return fmt.Errorf("failed to initialize admin workspace: %w", err)

View File

@@ -31,7 +31,6 @@ func setupRouter(o Options) *chi.Mux {
r.Use(middleware.Timeout(30 * time.Second)) r.Use(middleware.Timeout(30 * time.Second))
// Security headers // Security headers
logging.Debug("setting up security headers")
r.Use(secure.New(secure.Options{ r.Use(secure.New(secure.Options{
SSLRedirect: false, SSLRedirect: false,
SSLProxyHeaders: map[string]string{"X-Forwarded-Proto": "https"}, SSLProxyHeaders: map[string]string{"X-Forwarded-Proto": "https"},
@@ -39,7 +38,6 @@ func setupRouter(o Options) *chi.Mux {
}).Handler) }).Handler)
// CORS if origins are configured // CORS if origins are configured
logging.Debug("setting up CORS")
if len(o.Config.CORSOrigins) > 0 { if len(o.Config.CORSOrigins) > 0 {
r.Use(cors.Handler(cors.Options{ r.Use(cors.Handler(cors.Options{
AllowedOrigins: o.Config.CORSOrigins, AllowedOrigins: o.Config.CORSOrigins,
@@ -52,7 +50,6 @@ func setupRouter(o Options) *chi.Mux {
} }
// Initialize auth middleware and handler // Initialize auth middleware and handler
logging.Debug("setting up authentication middleware")
authMiddleware := auth.NewMiddleware(o.JWTManager, o.SessionManager, o.CookieService) authMiddleware := auth.NewMiddleware(o.JWTManager, o.SessionManager, o.CookieService)
handler := &handlers.Handler{ handler := &handlers.Handler{
DB: o.Database, DB: o.Database,
@@ -60,14 +57,12 @@ func setupRouter(o Options) *chi.Mux {
} }
if o.Config.IsDevelopment { if o.Config.IsDevelopment {
logging.Debug("setting up Swagger docs")
r.Get("/swagger/*", httpSwagger.Handler( r.Get("/swagger/*", httpSwagger.Handler(
httpSwagger.URL("/swagger/doc.json"), // The URL pointing to API definition httpSwagger.URL("/swagger/doc.json"), // The URL pointing to API definition
)) ))
} }
// API routes // API routes
logging.Debug("setting up API routes")
r.Route("/api/v1", func(r chi.Router) { r.Route("/api/v1", func(r chi.Router) {
// Rate limiting for API routes // Rate limiting for API routes
if o.Config.RateLimitRequests > 0 { if o.Config.RateLimitRequests > 0 {
@@ -154,7 +149,6 @@ func setupRouter(o Options) *chi.Mux {
}) })
// Handle all other routes with static file server // Handle all other routes with static file server
logging.Debug("setting up static file server")
r.Get("/*", handlers.NewStaticHandler(o.Config.StaticPath).ServeHTTP) r.Get("/*", handlers.NewStaticHandler(o.Config.StaticPath).ServeHTTP)
return r return r

View File

@@ -61,11 +61,9 @@ func NewJWTService(config JWTConfig) (JWTManager, error) {
// Set default expiry times if not provided // Set default expiry times if not provided
if config.AccessTokenExpiry == 0 { if config.AccessTokenExpiry == 0 {
config.AccessTokenExpiry = 15 * time.Minute config.AccessTokenExpiry = 15 * time.Minute
log.Debug("using default access token expiry", "expiry", config.AccessTokenExpiry)
} }
if config.RefreshTokenExpiry == 0 { if config.RefreshTokenExpiry == 0 {
config.RefreshTokenExpiry = 7 * 24 * time.Hour config.RefreshTokenExpiry = 7 * 24 * time.Hour
log.Debug("using default refresh token expiry", "expiry", config.RefreshTokenExpiry)
} }
log.Info("initialized JWT service", log.Info("initialized JWT service",
@@ -87,7 +85,6 @@ func (s *jwtService) GenerateRefreshToken(userID int, role, sessionID string) (s
// generateToken is an internal helper function that creates a new JWT token // generateToken is an internal helper function that creates a new JWT token
func (s *jwtService) generateToken(userID int, role string, sessionID string, tokenType TokenType, expiry time.Duration) (string, error) { func (s *jwtService) generateToken(userID int, role string, sessionID string, tokenType TokenType, expiry time.Duration) (string, error) {
log := getJWTLogger()
now := time.Now() now := time.Now()
// Add a random nonce to ensure uniqueness // Add a random nonce to ensure uniqueness
@@ -114,12 +111,6 @@ func (s *jwtService) generateToken(userID int, role string, sessionID string, to
return "", err return "", err
} }
log.Debug("generated JWT token",
"userId", userID,
"role", role,
"tokenType", tokenType,
"expiresAt", claims.ExpiresAt)
return signedToken, nil return signedToken, nil
} }

View File

@@ -20,9 +20,6 @@ type Middleware struct {
// NewMiddleware creates a new authentication middleware // NewMiddleware creates a new authentication middleware
func NewMiddleware(jwtManager JWTManager, sessionManager SessionManager, cookieManager CookieManager) *Middleware { func NewMiddleware(jwtManager JWTManager, sessionManager SessionManager, cookieManager CookieManager) *Middleware {
log := getMiddlewareLogger()
log.Info("initialized auth middleware")
return &Middleware{ return &Middleware{
jwtManager: jwtManager, jwtManager: jwtManager,
sessionManager: sessionManager, sessionManager: sessionManager,
@@ -33,11 +30,15 @@ func NewMiddleware(jwtManager JWTManager, sessionManager SessionManager, cookieM
// Authenticate middleware validates JWT tokens and sets user information in context // Authenticate middleware validates JWT tokens and sets user information in context
func (m *Middleware) Authenticate(next http.Handler) http.Handler { func (m *Middleware) Authenticate(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
log := getMiddlewareLogger() log := getMiddlewareLogger().With(
"handler", "Authenticate",
"clientIP", r.RemoteAddr,
)
// Extract token from cookie // Extract token from cookie
cookie, err := r.Cookie("access_token") cookie, err := r.Cookie("access_token")
if err != nil { if err != nil {
log.Warn("attempt to access protected route without token")
http.Error(w, "Unauthorized", http.StatusUnauthorized) http.Error(w, "Unauthorized", http.StatusUnauthorized)
return return
} }
@@ -45,12 +46,14 @@ func (m *Middleware) Authenticate(next http.Handler) http.Handler {
// Validate token // Validate token
claims, err := m.jwtManager.ValidateToken(cookie.Value) claims, err := m.jwtManager.ValidateToken(cookie.Value)
if err != nil { if err != nil {
log.Warn("attempt to access protected route with invalid token", "error", err.Error())
http.Error(w, "Invalid token", http.StatusUnauthorized) http.Error(w, "Invalid token", http.StatusUnauthorized)
return return
} }
// Check token type // Check token type
if claims.Type != AccessToken { if claims.Type != AccessToken {
log.Warn("attempt to access protected route with invalid token type", "type", claims.Type)
http.Error(w, "Invalid token type", http.StatusUnauthorized) http.Error(w, "Invalid token type", http.StatusUnauthorized)
return return
} }
@@ -58,6 +61,7 @@ func (m *Middleware) Authenticate(next http.Handler) http.Handler {
// Check if session is still valid in database // Check if session is still valid in database
session, err := m.sessionManager.ValidateSession(claims.ID) session, err := m.sessionManager.ValidateSession(claims.ID)
if err != nil || session == nil { if err != nil || session == nil {
log.Warn("attempt to access protected route with invalid session", "error", err.Error())
m.cookieManager.InvalidateCookie("access_token") m.cookieManager.InvalidateCookie("access_token")
m.cookieManager.InvalidateCookie("refresh_token") m.cookieManager.InvalidateCookie("refresh_token")
m.cookieManager.InvalidateCookie("csrf_token") m.cookieManager.InvalidateCookie("csrf_token")
@@ -69,17 +73,20 @@ func (m *Middleware) Authenticate(next http.Handler) http.Handler {
if r.Method != http.MethodGet && r.Method != http.MethodHead && r.Method != http.MethodOptions { if r.Method != http.MethodGet && r.Method != http.MethodHead && r.Method != http.MethodOptions {
csrfCookie, err := r.Cookie("csrf_token") csrfCookie, err := r.Cookie("csrf_token")
if err != nil { if err != nil {
log.Warn("attempt to access protected route without CSRF token", "error", err.Error())
http.Error(w, "CSRF cookie not found", http.StatusForbidden) http.Error(w, "CSRF cookie not found", http.StatusForbidden)
return return
} }
csrfHeader := r.Header.Get("X-CSRF-Token") csrfHeader := r.Header.Get("X-CSRF-Token")
if csrfHeader == "" { if csrfHeader == "" {
log.Warn("attempt to access protected route without CSRF header")
http.Error(w, "CSRF token header not found", http.StatusForbidden) http.Error(w, "CSRF token header not found", http.StatusForbidden)
return return
} }
if subtle.ConstantTimeCompare([]byte(csrfCookie.Value), []byte(csrfHeader)) != 1 { if subtle.ConstantTimeCompare([]byte(csrfCookie.Value), []byte(csrfHeader)) != 1 {
log.Warn("attempt to access protected route with invalid CSRF token")
http.Error(w, "CSRF token mismatch", http.StatusForbidden) http.Error(w, "CSRF token mismatch", http.StatusForbidden)
return return
} }
@@ -91,12 +98,6 @@ func (m *Middleware) Authenticate(next http.Handler) http.Handler {
UserRole: claims.Role, UserRole: claims.Role,
} }
log.Debug("authentication completed",
"userId", claims.UserID,
"role", claims.Role,
"method", r.Method,
"path", r.URL.Path)
// Add context to request and continue // Add context to request and continue
next.ServeHTTP(w, context.WithHandlerContext(r, hctx)) next.ServeHTTP(w, context.WithHandlerContext(r, hctx))
}) })
@@ -106,7 +107,11 @@ func (m *Middleware) Authenticate(next http.Handler) http.Handler {
func (m *Middleware) RequireRole(role string) func(http.Handler) http.Handler { func (m *Middleware) RequireRole(role string) func(http.Handler) http.Handler {
return func(next http.Handler) http.Handler { return func(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
log := getMiddlewareLogger() log := getMiddlewareLogger().With(
"handler", "RequireRole",
"requiredRole", role,
"clientIP", r.RemoteAddr,
)
ctx, ok := context.GetRequestContext(w, r) ctx, ok := context.GetRequestContext(w, r)
if !ok { if !ok {
@@ -114,15 +119,11 @@ func (m *Middleware) RequireRole(role string) func(http.Handler) http.Handler {
} }
if ctx.UserRole != role && ctx.UserRole != "admin" { if ctx.UserRole != role && ctx.UserRole != "admin" {
log.Warn("attempt to access protected route without required role")
http.Error(w, "Insufficient permissions", http.StatusForbidden) http.Error(w, "Insufficient permissions", http.StatusForbidden)
return return
} }
log.Debug("role requirement satisfied",
"requiredRole", role,
"userRole", ctx.UserRole,
"path", r.URL.Path)
next.ServeHTTP(w, r) next.ServeHTTP(w, r)
}) })
} }
@@ -131,14 +132,19 @@ func (m *Middleware) RequireRole(role string) func(http.Handler) http.Handler {
// RequireWorkspaceAccess returns a middleware that ensures the user has access to the workspace // RequireWorkspaceAccess returns a middleware that ensures the user has access to the workspace
func (m *Middleware) RequireWorkspaceAccess(next http.Handler) http.Handler { func (m *Middleware) RequireWorkspaceAccess(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
log := getMiddlewareLogger()
ctx, ok := context.GetRequestContext(w, r) ctx, ok := context.GetRequestContext(w, r)
if !ok { if !ok {
return return
} }
// If no workspace in context, allow the request (might be a non-workspace endpoint) log := getMiddlewareLogger().With(
"handler", "RequireWorkspaceAccess",
"clientIP", r.RemoteAddr,
"userId", ctx.UserID,
"workspaceId", ctx.Workspace.ID,
)
// If no workspace in context, allow the request
if ctx.Workspace == nil { if ctx.Workspace == nil {
next.ServeHTTP(w, r) next.ServeHTTP(w, r)
return return
@@ -146,15 +152,11 @@ func (m *Middleware) RequireWorkspaceAccess(next http.Handler) http.Handler {
// Check if user has access (either owner or admin) // Check if user has access (either owner or admin)
if ctx.Workspace.UserID != ctx.UserID && ctx.UserRole != "admin" { if ctx.Workspace.UserID != ctx.UserID && ctx.UserRole != "admin" {
log.Warn("attempt to access workspace without permission")
http.Error(w, "Not Found", http.StatusNotFound) http.Error(w, "Not Found", http.StatusNotFound)
return return
} }
log.Debug("workspace access granted",
"userId", ctx.UserID,
"workspaceId", ctx.Workspace.ID,
"path", r.URL.Path)
next.ServeHTTP(w, r) next.ServeHTTP(w, r)
}) })
} }

View File

@@ -32,9 +32,6 @@ type sessionManager struct {
// NewSessionService creates a new session service with the given database and JWT manager // NewSessionService creates a new session service with the given database and JWT manager
// revive:disable:unexported-return // revive:disable:unexported-return
func NewSessionService(db db.SessionStore, jwtManager JWTManager) *sessionManager { func NewSessionService(db db.SessionStore, jwtManager JWTManager) *sessionManager {
log := getSessionLogger()
log.Info("initialized session manager")
return &sessionManager{ return &sessionManager{
db: db, db: db,
jwtManager: jwtManager, jwtManager: jwtManager,
@@ -90,9 +87,7 @@ func (s *sessionManager) CreateSession(userID int, role string) (*models.Session
// RefreshSession creates a new access token using a refreshToken // RefreshSession creates a new access token using a refreshToken
func (s *sessionManager) RefreshSession(refreshToken string) (string, error) { func (s *sessionManager) RefreshSession(refreshToken string) (string, error) {
log := getSessionLogger() // Get session from database
// Get session from database first
session, err := s.db.GetSessionByRefreshToken(refreshToken) session, err := s.db.GetSessionByRefreshToken(refreshToken)
if err != nil { if err != nil {
return "", fmt.Errorf("invalid session: %w", err) return "", fmt.Errorf("invalid session: %w", err)
@@ -104,7 +99,6 @@ func (s *sessionManager) RefreshSession(refreshToken string) (string, error) {
return "", fmt.Errorf("invalid refresh token: %w", err) return "", fmt.Errorf("invalid refresh token: %w", err)
} }
// Double check that the claims match the session
if claims.UserID != session.UserID { if claims.UserID != session.UserID {
return "", fmt.Errorf("token does not match session") return "", fmt.Errorf("token does not match session")
} }
@@ -115,11 +109,6 @@ func (s *sessionManager) RefreshSession(refreshToken string) (string, error) {
return "", err return "", err
} }
log.Debug("refreshed session",
"userId", claims.UserID,
"role", claims.Role,
"sessionId", session.ID)
return newToken, nil return newToken, nil
} }

View File

@@ -26,11 +26,6 @@ func WithUserContextMiddleware(next http.Handler) http.Handler {
UserRole: claims.Role, UserRole: claims.Role,
} }
log.Debug("user context extracted from claims",
"userID", claims.UserID,
"role", claims.Role,
"path", r.URL.Path)
r = WithHandlerContext(r, hctx) r = WithHandlerContext(r, hctx)
next.ServeHTTP(w, r) next.ServeHTTP(w, r)
}) })
@@ -58,12 +53,6 @@ func WithWorkspaceContextMiddleware(db db.WorkspaceReader) func(http.Handler) ht
return return
} }
log.Debug("workspace context added",
"userID", ctx.UserID,
"workspaceID", workspace.ID,
"workspaceName", workspace.Name,
"path", r.URL.Path)
ctx.Workspace = workspace ctx.Workspace = workspace
r = WithHandlerContext(r, ctx) r = WithHandlerContext(r, ctx)
next.ServeHTTP(w, r) next.ServeHTTP(w, r)

View File

@@ -89,6 +89,10 @@ func TestWithUserContextMiddleware(t *testing.T) {
} }
} }
type contextKey string
const workspaceNameKey contextKey = "workspaceName"
func TestWithWorkspaceContextMiddleware(t *testing.T) { func TestWithWorkspaceContextMiddleware(t *testing.T) {
tests := []struct { tests := []struct {
name string name string
@@ -158,7 +162,7 @@ func TestWithWorkspaceContextMiddleware(t *testing.T) {
} }
// Add workspace name to request context via chi URL params // Add workspace name to request context via chi URL params
req = req.WithContext(stdctx.WithValue(req.Context(), "workspaceName", tt.workspaceName)) req = req.WithContext(stdctx.WithValue(req.Context(), workspaceNameKey, tt.workspaceName))
nextCalled := false nextCalled := false
next := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { next := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {

View File

@@ -113,7 +113,6 @@ type database struct {
// Init initializes the database connection // Init initializes the database connection
func Init(dbPath string, secretsService secrets.Service) (Database, error) { func Init(dbPath string, secretsService secrets.Service) (Database, error) {
log := getLogger() log := getLogger()
log.Info("initializing database", "path", dbPath)
db, err := sql.Open("sqlite3", dbPath) db, err := sql.Open("sqlite3", dbPath)
if err != nil { if err != nil {
@@ -136,7 +135,6 @@ func Init(dbPath string, secretsService secrets.Service) (Database, error) {
secretsService: secretsService, secretsService: secretsService,
} }
log.Info("database initialized successfully")
return database, nil return database, nil
} }
@@ -148,17 +146,12 @@ func (db *database) Close() error {
if err := db.DB.Close(); err != nil { if err := db.DB.Close(); err != nil {
return fmt.Errorf("failed to close database: %w", err) return fmt.Errorf("failed to close database: %w", err)
} }
log.Info("database connection closed successfully")
return nil return nil
} }
// Helper methods for token encryption/decryption // Helper methods for token encryption/decryption
func (db *database) encryptToken(token string) (string, error) { func (db *database) encryptToken(token string) (string, error) {
log := getLogger()
if token == "" { if token == "" {
log.Debug("skipping encryption for empty token")
return "", nil return "", nil
} }
@@ -167,15 +160,11 @@ func (db *database) encryptToken(token string) (string, error) {
return "", fmt.Errorf("failed to encrypt token: %w", err) return "", fmt.Errorf("failed to encrypt token: %w", err)
} }
log.Debug("token encrypted successfully")
return encrypted, nil return encrypted, nil
} }
func (db *database) decryptToken(token string) (string, error) { func (db *database) decryptToken(token string) (string, error) {
log := getLogger()
if token == "" { if token == "" {
log.Debug("skipping decryption for empty token")
return "", nil return "", nil
} }
@@ -184,6 +173,5 @@ func (db *database) decryptToken(token string) (string, error) {
return "", fmt.Errorf("failed to decrypt token: %w", err) return "", fmt.Errorf("failed to decrypt token: %w", err)
} }
log.Debug("token decrypted successfully")
return decrypted, nil return decrypted, nil
} }

View File

@@ -82,7 +82,6 @@ func (db *database) Migrate() error {
log.Info("starting database migration") log.Info("starting database migration")
// Create migrations table if it doesn't exist // Create migrations table if it doesn't exist
log.Debug("ensuring migrations table exists")
_, err := db.Exec(`CREATE TABLE IF NOT EXISTS migrations ( _, err := db.Exec(`CREATE TABLE IF NOT EXISTS migrations (
version INTEGER PRIMARY KEY version INTEGER PRIMARY KEY
)`) )`)
@@ -91,58 +90,49 @@ func (db *database) Migrate() error {
} }
// Get current version // Get current version
log.Debug("checking current migration version")
var currentVersion int var currentVersion int
err = db.QueryRow("SELECT COALESCE(MAX(version), 0) FROM migrations").Scan(&currentVersion) err = db.QueryRow("SELECT COALESCE(MAX(version), 0) FROM migrations").Scan(&currentVersion)
if err != nil { if err != nil {
return fmt.Errorf("failed to get current migration version: %w", err) return fmt.Errorf("failed to get current migration version: %w", err)
} }
log.Info("current database version", "version", currentVersion)
// Apply new migrations // Apply new migrations
for _, migration := range migrations { for _, migration := range migrations {
if migration.Version > currentVersion { if migration.Version > currentVersion {
log := log.With("migration_version", migration.Version) log := log.With("migration_version", migration.Version)
log.Info("applying migration")
tx, err := db.Begin() tx, err := db.Begin()
if err != nil { if err != nil {
return fmt.Errorf("failed to begin transaction for migration %d: %w", migration.Version, err) return fmt.Errorf("failed to begin transaction for migration %d: %w", migration.Version, err)
} }
// Execute migration SQL // Execute migration SQL
log.Debug("executing migration SQL")
_, err = tx.Exec(migration.SQL) _, err = tx.Exec(migration.SQL)
if err != nil { if err != nil {
if rbErr := tx.Rollback(); rbErr != nil { if rbErr := tx.Rollback(); rbErr != nil {
return fmt.Errorf("migration %d failed: %v, rollback failed: %v", return fmt.Errorf("migration %d failed: %v, rollback failed: %v",
migration.Version, err, rbErr) migration.Version, err, rbErr)
} }
log.Debug("successfully rolled back failed migration")
return fmt.Errorf("migration %d failed: %w", migration.Version, err) return fmt.Errorf("migration %d failed: %w", migration.Version, err)
} }
// Update migrations table // Update migrations table
log.Debug("updating migrations version")
_, err = tx.Exec("INSERT INTO migrations (version) VALUES (?)", migration.Version) _, err = tx.Exec("INSERT INTO migrations (version) VALUES (?)", migration.Version)
if err != nil { if err != nil {
if rbErr := tx.Rollback(); rbErr != nil { if rbErr := tx.Rollback(); rbErr != nil {
return fmt.Errorf("failed to update migration version: %v, rollback failed: %v", return fmt.Errorf("failed to update migration version: %v, rollback failed: %v",
err, rbErr) err, rbErr)
} }
log.Debug("successfully rolled back failed version update")
return fmt.Errorf("failed to update migration version: %w", err) return fmt.Errorf("failed to update migration version: %w", err)
} }
// Commit transaction // Commit transaction
log.Debug("committing migration")
err = tx.Commit() err = tx.Commit()
if err != nil { if err != nil {
return fmt.Errorf("failed to commit migration %d: %w", migration.Version, err) return fmt.Errorf("failed to commit migration %d: %w", migration.Version, err)
} }
currentVersion = migration.Version currentVersion = migration.Version
log.Info("migration applied successfully", "new_version", currentVersion) log.Debug("migration applied", "new_version", currentVersion)
} }
} }

View File

@@ -10,12 +10,6 @@ import (
// CreateSession inserts a new session record into the database // CreateSession inserts a new session record into the database
func (db *database) CreateSession(session *models.Session) error { func (db *database) CreateSession(session *models.Session) error {
log := getLogger().WithGroup("sessions")
log.Debug("creating new session",
"session_id", session.ID,
"user_id", session.UserID,
"expires_at", session.ExpiresAt)
_, err := db.Exec(` _, err := db.Exec(`
INSERT INTO sessions (id, user_id, refresh_token, expires_at, created_at) INSERT INTO sessions (id, user_id, refresh_token, expires_at, created_at)
VALUES (?, ?, ?, ?, ?)`, VALUES (?, ?, ?, ?, ?)`,
@@ -25,17 +19,11 @@ func (db *database) CreateSession(session *models.Session) error {
return fmt.Errorf("failed to store session: %w", err) return fmt.Errorf("failed to store session: %w", err)
} }
log.Info("session created successfully",
"session_id", session.ID,
"user_id", session.UserID)
return nil return nil
} }
// GetSessionByRefreshToken retrieves a session by its refresh token // GetSessionByRefreshToken retrieves a session by its refresh token
func (db *database) GetSessionByRefreshToken(refreshToken string) (*models.Session, error) { func (db *database) GetSessionByRefreshToken(refreshToken string) (*models.Session, error) {
log := getLogger().WithGroup("sessions")
log.Debug("fetching session by refresh token")
session := &models.Session{} session := &models.Session{}
err := db.QueryRow(` err := db.QueryRow(`
SELECT id, user_id, refresh_token, expires_at, created_at SELECT id, user_id, refresh_token, expires_at, created_at
@@ -45,24 +33,17 @@ func (db *database) GetSessionByRefreshToken(refreshToken string) (*models.Sessi
).Scan(&session.ID, &session.UserID, &session.RefreshToken, &session.ExpiresAt, &session.CreatedAt) ).Scan(&session.ID, &session.UserID, &session.RefreshToken, &session.ExpiresAt, &session.CreatedAt)
if err == sql.ErrNoRows { if err == sql.ErrNoRows {
log.Debug("session not found or expired")
return nil, fmt.Errorf("session not found or expired") return nil, fmt.Errorf("session not found or expired")
} }
if err != nil { if err != nil {
return nil, fmt.Errorf("failed to fetch session: %w", err) return nil, fmt.Errorf("failed to fetch session: %w", err)
} }
log.Debug("session retrieved successfully",
"session_id", session.ID,
"user_id", session.UserID)
return session, nil return session, nil
} }
// GetSessionByID retrieves a session by its ID // GetSessionByID retrieves a session by its ID
func (db *database) GetSessionByID(sessionID string) (*models.Session, error) { func (db *database) GetSessionByID(sessionID string) (*models.Session, error) {
log := getLogger().WithGroup("sessions")
log.Debug("fetching session by ID", "session_id", sessionID)
session := &models.Session{} session := &models.Session{}
err := db.QueryRow(` err := db.QueryRow(`
SELECT id, user_id, refresh_token, expires_at, created_at SELECT id, user_id, refresh_token, expires_at, created_at
@@ -72,24 +53,17 @@ func (db *database) GetSessionByID(sessionID string) (*models.Session, error) {
).Scan(&session.ID, &session.UserID, &session.RefreshToken, &session.ExpiresAt, &session.CreatedAt) ).Scan(&session.ID, &session.UserID, &session.RefreshToken, &session.ExpiresAt, &session.CreatedAt)
if err == sql.ErrNoRows { if err == sql.ErrNoRows {
log.Debug("session not found", "session_id", sessionID)
return nil, fmt.Errorf("session not found") return nil, fmt.Errorf("session not found")
} }
if err != nil { if err != nil {
return nil, fmt.Errorf("failed to fetch session: %w", err) return nil, fmt.Errorf("failed to fetch session: %w", err)
} }
log.Debug("session retrieved successfully",
"session_id", session.ID,
"user_id", session.UserID)
return session, nil return session, nil
} }
// DeleteSession removes a session from the database // DeleteSession removes a session from the database
func (db *database) DeleteSession(sessionID string) error { func (db *database) DeleteSession(sessionID string) error {
log := getLogger().WithGroup("sessions")
log.Debug("deleting session", "session_id", sessionID)
result, err := db.Exec("DELETE FROM sessions WHERE id = ?", sessionID) result, err := db.Exec("DELETE FROM sessions WHERE id = ?", sessionID)
if err != nil { if err != nil {
return fmt.Errorf("failed to delete session: %w", err) return fmt.Errorf("failed to delete session: %w", err)
@@ -101,19 +75,15 @@ func (db *database) DeleteSession(sessionID string) error {
} }
if rowsAffected == 0 { if rowsAffected == 0 {
log.Debug("no session found to delete", "session_id", sessionID)
return fmt.Errorf("session not found") return fmt.Errorf("session not found")
} }
log.Info("session deleted successfully", "session_id", sessionID)
return nil return nil
} }
// CleanExpiredSessions removes all expired sessions from the database // CleanExpiredSessions removes all expired sessions from the database
func (db *database) CleanExpiredSessions() error { func (db *database) CleanExpiredSessions() error {
log := getLogger().WithGroup("sessions") log := getLogger().WithGroup("sessions")
log.Info("cleaning expired sessions")
result, err := db.Exec("DELETE FROM sessions WHERE expires_at <= ?", time.Now()) result, err := db.Exec("DELETE FROM sessions WHERE expires_at <= ?", time.Now())
if err != nil { if err != nil {
return fmt.Errorf("failed to clean expired sessions: %w", err) return fmt.Errorf("failed to clean expired sessions: %w", err)
@@ -124,6 +94,6 @@ func (db *database) CleanExpiredSessions() error {
return fmt.Errorf("failed to get rows affected: %w", err) return fmt.Errorf("failed to get rows affected: %w", err)
} }
log.Info("expired sessions cleaned successfully", "sessions_removed", rowsAffected) log.Info("cleaned expired sessions", "sessions_removed", rowsAffected)
return nil return nil
} }

View File

@@ -22,17 +22,13 @@ type UserStats struct {
// If no secret exists, it generates and stores a new one // If no secret exists, it generates and stores a new one
func (db *database) EnsureJWTSecret() (string, error) { func (db *database) EnsureJWTSecret() (string, error) {
log := getLogger().WithGroup("system") log := getLogger().WithGroup("system")
log.Debug("ensuring JWT secret exists")
// First, try to get existing secret // First, try to get existing secret
secret, err := db.GetSystemSetting(JWTSecretKey) secret, err := db.GetSystemSetting(JWTSecretKey)
if err == nil { if err == nil {
log.Debug("existing JWT secret found")
return secret, nil return secret, nil
} }
log.Info("no existing JWT secret found, generating new secret")
// Generate new secret if none exists // Generate new secret if none exists
newSecret, err := generateRandomSecret(32) // 256 bits newSecret, err := generateRandomSecret(32) // 256 bits
if err != nil { if err != nil {
@@ -45,30 +41,24 @@ func (db *database) EnsureJWTSecret() (string, error) {
return "", fmt.Errorf("failed to store JWT secret: %w", err) return "", fmt.Errorf("failed to store JWT secret: %w", err)
} }
log.Info("new JWT secret generated and stored successfully") log.Info("new JWT secret generated and stored")
return newSecret, nil return newSecret, nil
} }
// GetSystemSetting retrieves a system setting by key // GetSystemSetting retrieves a system setting by key
func (db *database) GetSystemSetting(key string) (string, error) { func (db *database) GetSystemSetting(key string) (string, error) {
log := getLogger().WithGroup("system")
log.Debug("retrieving system setting", "key", key)
var value string var value string
err := db.QueryRow("SELECT value FROM system_settings WHERE key = ?", key).Scan(&value) err := db.QueryRow("SELECT value FROM system_settings WHERE key = ?", key).Scan(&value)
if err != nil { if err != nil {
return "", err return "", err
} }
log.Debug("system setting retrieved successfully", "key", key)
return value, nil return value, nil
} }
// SetSystemSetting stores or updates a system setting // SetSystemSetting stores or updates a system setting
func (db *database) SetSystemSetting(key, value string) error { func (db *database) SetSystemSetting(key, value string) error {
log := getLogger().WithGroup("system")
log.Debug("storing system setting", "key", key)
_, err := db.Exec(` _, err := db.Exec(`
INSERT INTO system_settings (key, value) INSERT INTO system_settings (key, value)
VALUES (?, ?) VALUES (?, ?)
@@ -79,7 +69,6 @@ func (db *database) SetSystemSetting(key, value string) error {
return fmt.Errorf("failed to store system setting: %w", err) return fmt.Errorf("failed to store system setting: %w", err)
} }
log.Info("system setting stored successfully", "key", key)
return nil return nil
} }
@@ -95,15 +84,11 @@ func generateRandomSecret(bytes int) (string, error) {
} }
secret := base64.StdEncoding.EncodeToString(b) secret := base64.StdEncoding.EncodeToString(b)
log.Debug("random secret generated successfully", "bytes", bytes)
return secret, nil return secret, nil
} }
// GetSystemStats returns system-wide statistics // GetSystemStats returns system-wide statistics
func (db *database) GetSystemStats() (*UserStats, error) { func (db *database) GetSystemStats() (*UserStats, error) {
log := getLogger().WithGroup("system")
log.Debug("collecting system statistics")
stats := &UserStats{} stats := &UserStats{}
// Get total users // Get total users
@@ -111,14 +96,12 @@ func (db *database) GetSystemStats() (*UserStats, error) {
if err != nil { if err != nil {
return nil, fmt.Errorf("failed to get total users count: %w", err) return nil, fmt.Errorf("failed to get total users count: %w", err)
} }
log.Debug("got total users count", "count", stats.TotalUsers)
// Get total workspaces // Get total workspaces
err = db.QueryRow("SELECT COUNT(*) FROM workspaces").Scan(&stats.TotalWorkspaces) err = db.QueryRow("SELECT COUNT(*) FROM workspaces").Scan(&stats.TotalWorkspaces)
if err != nil { if err != nil {
return nil, fmt.Errorf("failed to get total workspaces count: %w", err) return nil, fmt.Errorf("failed to get total workspaces count: %w", err)
} }
log.Debug("got total workspaces count", "count", stats.TotalWorkspaces)
// Get active users (users with activity in last 30 days) // Get active users (users with activity in last 30 days)
err = db.QueryRow(` err = db.QueryRow(`
@@ -129,6 +112,5 @@ func (db *database) GetSystemStats() (*UserStats, error) {
if err != nil { if err != nil {
return nil, fmt.Errorf("failed to get active users count: %w", err) return nil, fmt.Errorf("failed to get active users count: %w", err)
} }
log.Debug("got active users count", "count", stats.ActiveUsers)
return stats, nil return stats, nil
} }

View File

@@ -9,9 +9,7 @@ import (
// CreateUser inserts a new user record into the database // CreateUser inserts a new user record into the database
func (db *database) CreateUser(user *models.User) (*models.User, error) { func (db *database) CreateUser(user *models.User) (*models.User, error) {
log := getLogger().WithGroup("users") log := getLogger().WithGroup("users")
log.Debug("creating new user", log.Debug("creating user", "email", user.Email)
"email", user.Email,
"role", user.Role)
tx, err := db.Begin() tx, err := db.Begin()
if err != nil { if err != nil {
@@ -40,7 +38,6 @@ func (db *database) CreateUser(user *models.User) (*models.User, error) {
} }
// Create default workspace with default settings // Create default workspace with default settings
log.Debug("creating default workspace for user", "user_id", user.ID)
defaultWorkspace := &models.Workspace{ defaultWorkspace := &models.Workspace{
UserID: user.ID, UserID: user.ID,
Name: "Main", Name: "Main",
@@ -54,9 +51,6 @@ func (db *database) CreateUser(user *models.User) (*models.User, error) {
} }
// Update user's last workspace ID // Update user's last workspace ID
log.Debug("updating user's last workspace",
"user_id", user.ID,
"workspace_id", defaultWorkspace.ID)
_, err = tx.Exec("UPDATE users SET last_workspace_id = ? WHERE id = ?", defaultWorkspace.ID, user.ID) _, err = tx.Exec("UPDATE users SET last_workspace_id = ? WHERE id = ?", defaultWorkspace.ID, user.ID)
if err != nil { if err != nil {
return nil, fmt.Errorf("failed to update last workspace ID: %w", err) return nil, fmt.Errorf("failed to update last workspace ID: %w", err)
@@ -67,21 +61,15 @@ func (db *database) CreateUser(user *models.User) (*models.User, error) {
return nil, fmt.Errorf("failed to commit transaction: %w", err) return nil, fmt.Errorf("failed to commit transaction: %w", err)
} }
log.Debug("created user", "user_id", user.ID)
user.LastWorkspaceID = defaultWorkspace.ID user.LastWorkspaceID = defaultWorkspace.ID
log.Info("user created",
"user_id", user.ID,
"email", user.Email,
"workspace_id", defaultWorkspace.ID)
return user, nil return user, nil
} }
// Helper function to create a workspace in a transaction // Helper function to create a workspace in a transaction
func (db *database) createWorkspaceTx(tx *sql.Tx, workspace *models.Workspace) error { func (db *database) createWorkspaceTx(tx *sql.Tx, workspace *models.Workspace) error {
log := getLogger().WithGroup("users") log := getLogger().WithGroup("users")
log.Debug("creating workspace in transaction",
"user_id", workspace.UserID,
"name", workspace.Name)
result, err := tx.Exec(` result, err := tx.Exec(`
INSERT INTO workspaces ( INSERT INTO workspaces (
user_id, name, user_id, name,
@@ -106,16 +94,13 @@ func (db *database) createWorkspaceTx(tx *sql.Tx, workspace *models.Workspace) e
} }
workspace.ID = int(id) workspace.ID = int(id)
log.Debug("workspace created successfully", log.Debug("created user workspace",
"workspace_id", workspace.ID, "workspace_id", workspace.ID,
"user_id", workspace.UserID) "user_id", workspace.UserID)
return nil return nil
} }
func (db *database) GetUserByID(id int) (*models.User, error) { func (db *database) GetUserByID(id int) (*models.User, error) {
log := getLogger().WithGroup("users")
log.Debug("fetching user by ID", "user_id", id)
user := &models.User{} user := &models.User{}
err := db.QueryRow(` err := db.QueryRow(`
SELECT SELECT
@@ -127,21 +112,15 @@ func (db *database) GetUserByID(id int) (*models.User, error) {
&user.Role, &user.CreatedAt, &user.LastWorkspaceID) &user.Role, &user.CreatedAt, &user.LastWorkspaceID)
if err == sql.ErrNoRows { if err == sql.ErrNoRows {
log.Debug("user not found", "user_id", id)
return nil, fmt.Errorf("user not found") return nil, fmt.Errorf("user not found")
} }
if err != nil { if err != nil {
return nil, fmt.Errorf("failed to fetch user: %w", err) return nil, fmt.Errorf("failed to fetch user: %w", err)
} }
log.Debug("user retrieved successfully", "user_id", id)
return user, nil return user, nil
} }
func (db *database) GetUserByEmail(email string) (*models.User, error) { func (db *database) GetUserByEmail(email string) (*models.User, error) {
log := getLogger().WithGroup("users")
log.Debug("fetching user by email", "email", email)
user := &models.User{} user := &models.User{}
err := db.QueryRow(` err := db.QueryRow(`
SELECT SELECT
@@ -153,19 +132,16 @@ func (db *database) GetUserByEmail(email string) (*models.User, error) {
&user.Role, &user.CreatedAt, &user.LastWorkspaceID) &user.Role, &user.CreatedAt, &user.LastWorkspaceID)
if err == sql.ErrNoRows { if err == sql.ErrNoRows {
log.Debug("user not found", "email", email)
return nil, fmt.Errorf("user not found") return nil, fmt.Errorf("user not found")
} }
if err != nil { if err != nil {
return nil, fmt.Errorf("failed to fetch user: %w", err) return nil, fmt.Errorf("failed to fetch user: %w", err)
} }
log.Debug("user retrieved successfully", "user_id", user.ID)
return user, nil return user, nil
} }
func (db *database) UpdateUser(user *models.User) error { func (db *database) UpdateUser(user *models.User) error {
log := getLogger().WithGroup("users")
result, err := db.Exec(` result, err := db.Exec(`
UPDATE users UPDATE users
SET email = ?, display_name = ?, password_hash = ?, role = ?, last_workspace_id = ? SET email = ?, display_name = ?, password_hash = ?, role = ?, last_workspace_id = ?
@@ -183,18 +159,13 @@ func (db *database) UpdateUser(user *models.User) error {
} }
if rowsAffected == 0 { if rowsAffected == 0 {
log.Warn("no user found to update", "user_id", user.ID)
return fmt.Errorf("user not found") return fmt.Errorf("user not found")
} }
log.Info("user updated", "user_id", user.ID)
return nil return nil
} }
func (db *database) GetAllUsers() ([]*models.User, error) { func (db *database) GetAllUsers() ([]*models.User, error) {
log := getLogger().WithGroup("users")
log.Debug("fetching all users")
rows, err := db.Query(` rows, err := db.Query(`
SELECT SELECT
id, email, display_name, role, created_at, id, email, display_name, role, created_at,
@@ -219,16 +190,10 @@ func (db *database) GetAllUsers() ([]*models.User, error) {
users = append(users, user) users = append(users, user)
} }
log.Debug("users retrieved successfully", "count", len(users))
return users, nil return users, nil
} }
func (db *database) UpdateLastWorkspace(userID int, workspaceName string) error { func (db *database) UpdateLastWorkspace(userID int, workspaceName string) error {
log := getLogger().WithGroup("users")
log.Debug("updating last workspace",
"user_id", userID,
"workspace_name", workspaceName)
tx, err := db.Begin() tx, err := db.Begin()
if err != nil { if err != nil {
return fmt.Errorf("failed to begin transaction: %w", err) return fmt.Errorf("failed to begin transaction: %w", err)
@@ -253,9 +218,6 @@ func (db *database) UpdateLastWorkspace(userID int, workspaceName string) error
return fmt.Errorf("failed to commit transaction: %w", err) return fmt.Errorf("failed to commit transaction: %w", err)
} }
log.Info("last workspace updated",
"user_id", userID,
"workspace_id", workspaceID)
return nil return nil
} }
@@ -271,48 +233,27 @@ func (db *database) DeleteUser(id int) error {
// Delete all user's workspaces first // Delete all user's workspaces first
log.Debug("deleting user workspaces", "user_id", id) log.Debug("deleting user workspaces", "user_id", id)
result, err := tx.Exec("DELETE FROM workspaces WHERE user_id = ?", id) _, err = tx.Exec("DELETE FROM workspaces WHERE user_id = ?", id)
if err != nil { if err != nil {
return fmt.Errorf("failed to delete workspaces: %w", err) return fmt.Errorf("failed to delete workspaces: %w", err)
} }
workspacesDeleted, err := result.RowsAffected()
if err != nil {
return fmt.Errorf("failed to get deleted workspaces count: %w", err)
}
// Delete the user // Delete the user
log.Debug("deleting user record", "user_id", id) _, err = tx.Exec("DELETE FROM users WHERE id = ?", id)
result, err = tx.Exec("DELETE FROM users WHERE id = ?", id)
if err != nil { if err != nil {
return fmt.Errorf("failed to delete user: %w", err) return fmt.Errorf("failed to delete user: %w", err)
} }
userDeleted, err := result.RowsAffected()
if err != nil {
return fmt.Errorf("failed to get deleted user count: %w", err)
}
if userDeleted == 0 {
log.Warn("no user found to delete", "user_id", id)
return fmt.Errorf("user not found")
}
err = tx.Commit() err = tx.Commit()
if err != nil { if err != nil {
return fmt.Errorf("failed to commit transaction: %w", err) return fmt.Errorf("failed to commit transaction: %w", err)
} }
log.Info("user deleted", log.Debug("deleted user", "user_id", id)
"user_id", id,
"workspaces_deleted", workspacesDeleted)
return nil return nil
} }
func (db *database) GetLastWorkspaceName(userID int) (string, error) { func (db *database) GetLastWorkspaceName(userID int) (string, error) {
log := getLogger().WithGroup("users")
log.Debug("fetching last workspace name", "user_id", userID)
var workspaceName string var workspaceName string
err := db.QueryRow(` err := db.QueryRow(`
SELECT SELECT
@@ -323,30 +264,22 @@ func (db *database) GetLastWorkspaceName(userID int) (string, error) {
Scan(&workspaceName) Scan(&workspaceName)
if err == sql.ErrNoRows { if err == sql.ErrNoRows {
log.Debug("no last workspace found", "user_id", userID)
return "", fmt.Errorf("no last workspace found") return "", fmt.Errorf("no last workspace found")
} }
if err != nil { if err != nil {
return "", fmt.Errorf("failed to fetch last workspace name: %w", err) return "", fmt.Errorf("failed to fetch last workspace name: %w", err)
} }
log.Debug("last workspace name retrieved",
"user_id", userID,
"workspace_name", workspaceName)
return workspaceName, nil return workspaceName, nil
} }
// CountAdminUsers returns the number of admin users in the system // CountAdminUsers returns the number of admin users in the system
func (db *database) CountAdminUsers() (int, error) { func (db *database) CountAdminUsers() (int, error) {
log := getLogger().WithGroup("users")
log.Debug("counting admin users")
var count int var count int
err := db.QueryRow("SELECT COUNT(*) FROM users WHERE role = 'admin'").Scan(&count) err := db.QueryRow("SELECT COUNT(*) FROM users WHERE role = 'admin'").Scan(&count)
if err != nil { if err != nil {
return 0, fmt.Errorf("failed to count admin users: %w", err) return 0, fmt.Errorf("failed to count admin users: %w", err)
} }
log.Debug("admin users counted successfully", "count", count)
return count, nil return count, nil
} }

View File

@@ -16,7 +16,6 @@ func (db *database) CreateWorkspace(workspace *models.Workspace) error {
// Set default settings if not provided // Set default settings if not provided
if workspace.Theme == "" { if workspace.Theme == "" {
log.Debug("setting default workspace settings")
workspace.SetDefaultSettings() workspace.SetDefaultSettings()
} }
@@ -47,17 +46,11 @@ func (db *database) CreateWorkspace(workspace *models.Workspace) error {
} }
workspace.ID = int(id) workspace.ID = int(id)
log.Info("workspace created",
"workspace_id", workspace.ID,
"user_id", workspace.UserID)
return nil return nil
} }
// GetWorkspaceByID retrieves a workspace by its ID // GetWorkspaceByID retrieves a workspace by its ID
func (db *database) GetWorkspaceByID(id int) (*models.Workspace, error) { func (db *database) GetWorkspaceByID(id int) (*models.Workspace, error) {
log := getLogger().WithGroup("workspaces")
log.Debug("fetching workspace by ID", "workspace_id", id)
workspace := &models.Workspace{} workspace := &models.Workspace{}
var encryptedToken string var encryptedToken string
@@ -80,7 +73,6 @@ func (db *database) GetWorkspaceByID(id int) (*models.Workspace, error) {
) )
if err == sql.ErrNoRows { if err == sql.ErrNoRows {
log.Debug("workspace not found", "workspace_id", id)
return nil, fmt.Errorf("workspace not found") return nil, fmt.Errorf("workspace not found")
} }
if err != nil { if err != nil {
@@ -93,19 +85,11 @@ func (db *database) GetWorkspaceByID(id int) (*models.Workspace, error) {
return nil, fmt.Errorf("failed to decrypt token: %w", err) return nil, fmt.Errorf("failed to decrypt token: %w", err)
} }
log.Debug("workspace retrieved",
"workspace_id", id,
"user_id", workspace.UserID)
return workspace, nil return workspace, nil
} }
// GetWorkspaceByName retrieves a workspace by its name and user ID // GetWorkspaceByName retrieves a workspace by its name and user ID
func (db *database) GetWorkspaceByName(userID int, workspaceName string) (*models.Workspace, error) { func (db *database) GetWorkspaceByName(userID int, workspaceName string) (*models.Workspace, error) {
log := getLogger().WithGroup("workspaces")
log.Debug("fetching workspace by name",
"user_id", userID,
"workspace_name", workspaceName)
workspace := &models.Workspace{} workspace := &models.Workspace{}
var encryptedToken string var encryptedToken string
@@ -128,9 +112,6 @@ func (db *database) GetWorkspaceByName(userID int, workspaceName string) (*model
) )
if err == sql.ErrNoRows { if err == sql.ErrNoRows {
log.Debug("workspace not found",
"user_id", userID,
"workspace_name", workspaceName)
return nil, fmt.Errorf("workspace not found") return nil, fmt.Errorf("workspace not found")
} }
if err != nil { if err != nil {
@@ -143,27 +124,18 @@ func (db *database) GetWorkspaceByName(userID int, workspaceName string) (*model
return nil, fmt.Errorf("failed to decrypt token: %w", err) return nil, fmt.Errorf("failed to decrypt token: %w", err)
} }
log.Debug("workspace retrieved successfully",
"workspace_id", workspace.ID,
"user_id", userID)
return workspace, nil return workspace, nil
} }
// UpdateWorkspace updates a workspace record in the database // UpdateWorkspace updates a workspace record in the database
func (db *database) UpdateWorkspace(workspace *models.Workspace) error { func (db *database) UpdateWorkspace(workspace *models.Workspace) error {
log := getLogger().WithGroup("workspaces")
log.Debug("updating workspace",
"workspace_id", workspace.ID,
"user_id", workspace.UserID,
"git_enabled", workspace.GitEnabled)
// Encrypt token before storing // Encrypt token before storing
encryptedToken, err := db.encryptToken(workspace.GitToken) encryptedToken, err := db.encryptToken(workspace.GitToken)
if err != nil { if err != nil {
return fmt.Errorf("failed to encrypt token: %w", err) return fmt.Errorf("failed to encrypt token: %w", err)
} }
result, err := db.Exec(` _, err = db.Exec(`
UPDATE workspaces UPDATE workspaces
SET SET
name = ?, name = ?,
@@ -198,29 +170,11 @@ func (db *database) UpdateWorkspace(workspace *models.Workspace) error {
return fmt.Errorf("failed to update workspace: %w", err) return fmt.Errorf("failed to update workspace: %w", err)
} }
rowsAffected, err := result.RowsAffected()
if err != nil {
return fmt.Errorf("failed to get rows affected: %w", err)
}
if rowsAffected == 0 {
log.Warn("no workspace found to update",
"workspace_id", workspace.ID,
"user_id", workspace.UserID)
return fmt.Errorf("workspace not found")
}
log.Debug("workspace updated",
"workspace_id", workspace.ID,
"user_id", workspace.UserID)
return nil return nil
} }
// GetWorkspacesByUserID retrieves all workspaces for a user // GetWorkspacesByUserID retrieves all workspaces for a user
func (db *database) GetWorkspacesByUserID(userID int) ([]*models.Workspace, error) { func (db *database) GetWorkspacesByUserID(userID int) ([]*models.Workspace, error) {
log := getLogger().WithGroup("workspaces")
log.Debug("fetching workspaces for user", "user_id", userID)
rows, err := db.Query(` rows, err := db.Query(`
SELECT SELECT
id, user_id, name, created_at, id, user_id, name, created_at,
@@ -265,20 +219,12 @@ func (db *database) GetWorkspacesByUserID(userID int) ([]*models.Workspace, erro
return nil, fmt.Errorf("error iterating workspace rows: %w", err) return nil, fmt.Errorf("error iterating workspace rows: %w", err)
} }
log.Debug("workspaces retrieved successfully",
"user_id", userID,
"count", len(workspaces))
return workspaces, nil return workspaces, nil
} }
// UpdateWorkspaceSettings updates only the settings portion of a workspace // UpdateWorkspaceSettings updates only the settings portion of a workspace
func (db *database) UpdateWorkspaceSettings(workspace *models.Workspace) error { func (db *database) UpdateWorkspaceSettings(workspace *models.Workspace) error {
log := getLogger().WithGroup("workspaces") _, err := db.Exec(`
log.Debug("updating workspace settings",
"workspace_id", workspace.ID,
"git_enabled", workspace.GitEnabled)
result, err := db.Exec(`
UPDATE workspaces UPDATE workspaces
SET SET
theme = ?, theme = ?,
@@ -310,142 +256,74 @@ func (db *database) UpdateWorkspaceSettings(workspace *models.Workspace) error {
return fmt.Errorf("failed to update workspace settings: %w", err) return fmt.Errorf("failed to update workspace settings: %w", err)
} }
rowsAffected, err := result.RowsAffected()
if err != nil {
return fmt.Errorf("failed to get rows affected: %w", err)
}
if rowsAffected == 0 {
log.Warn("no workspace found to update settings",
"workspace_id", workspace.ID)
return fmt.Errorf("workspace not found")
}
log.Info("workspace settings updated",
"workspace_id", workspace.ID)
return nil return nil
} }
// DeleteWorkspace removes a workspace record from the database // DeleteWorkspace removes a workspace record from the database
func (db *database) DeleteWorkspace(id int) error { func (db *database) DeleteWorkspace(id int) error {
log := getLogger().WithGroup("workspaces") log := getLogger().WithGroup("workspaces")
log.Debug("deleting workspace", "workspace_id", id)
result, err := db.Exec("DELETE FROM workspaces WHERE id = ?", id) _, err := db.Exec("DELETE FROM workspaces WHERE id = ?", id)
if err != nil { if err != nil {
return fmt.Errorf("failed to delete workspace: %w", err) return fmt.Errorf("failed to delete workspace: %w", err)
} }
rowsAffected, err := result.RowsAffected() log.Debug("workspace deleted", "workspace_id", id)
if err != nil {
return fmt.Errorf("failed to get rows affected: %w", err)
}
if rowsAffected == 0 {
log.Warn("no workspace found to delete", "workspace_id", id)
return fmt.Errorf("workspace not found")
}
log.Info("workspace deleted", "workspace_id", id)
return nil return nil
} }
// DeleteWorkspaceTx removes a workspace record from the database within a transaction // DeleteWorkspaceTx removes a workspace record from the database within a transaction
func (db *database) DeleteWorkspaceTx(tx *sql.Tx, id int) error { func (db *database) DeleteWorkspaceTx(tx *sql.Tx, id int) error {
log := getLogger().WithGroup("workspaces") log := getLogger().WithGroup("workspaces")
log.Debug("deleting workspace in transaction", "workspace_id", id)
result, err := tx.Exec("DELETE FROM workspaces WHERE id = ?", id) result, err := tx.Exec("DELETE FROM workspaces WHERE id = ?", id)
if err != nil { if err != nil {
return fmt.Errorf("failed to delete workspace in transaction: %w", err) return fmt.Errorf("failed to delete workspace in transaction: %w", err)
} }
rowsAffected, err := result.RowsAffected() _, err = result.RowsAffected()
if err != nil { if err != nil {
return fmt.Errorf("failed to get rows affected in transaction: %w", err) return fmt.Errorf("failed to get rows affected in transaction: %w", err)
} }
if rowsAffected == 0 { log.Debug("workspace deleted",
log.Warn("no workspace found to delete in transaction",
"workspace_id", id)
return fmt.Errorf("workspace not found")
}
log.Debug("workspace deleted successfully in transaction",
"workspace_id", id) "workspace_id", id)
return nil return nil
} }
// UpdateLastWorkspaceTx sets the last workspace for a user in a transaction // UpdateLastWorkspaceTx sets the last workspace for a user in a transaction
func (db *database) UpdateLastWorkspaceTx(tx *sql.Tx, userID, workspaceID int) error { func (db *database) UpdateLastWorkspaceTx(tx *sql.Tx, userID, workspaceID int) error {
log := getLogger().WithGroup("workspaces")
log.Debug("updating last workspace in transaction",
"user_id", userID,
"workspace_id", workspaceID)
result, err := tx.Exec("UPDATE users SET last_workspace_id = ? WHERE id = ?", result, err := tx.Exec("UPDATE users SET last_workspace_id = ? WHERE id = ?",
workspaceID, userID) workspaceID, userID)
if err != nil { if err != nil {
return fmt.Errorf("failed to update last workspace in transaction: %w", err) return fmt.Errorf("failed to update last workspace in transaction: %w", err)
} }
rowsAffected, err := result.RowsAffected() _, err = result.RowsAffected()
if err != nil { if err != nil {
return fmt.Errorf("failed to get rows affected in transaction: %w", err) return fmt.Errorf("failed to get rows affected in transaction: %w", err)
} }
if rowsAffected == 0 {
log.Warn("no user found to update last workspace",
"user_id", userID)
return fmt.Errorf("user not found")
}
log.Debug("last workspace updated successfully in transaction",
"user_id", userID,
"workspace_id", workspaceID)
return nil return nil
} }
// UpdateLastOpenedFile updates the last opened file path for a workspace // UpdateLastOpenedFile updates the last opened file path for a workspace
func (db *database) UpdateLastOpenedFile(workspaceID int, filePath string) error { func (db *database) UpdateLastOpenedFile(workspaceID int, filePath string) error {
log := getLogger().WithGroup("workspaces") _, err := db.Exec("UPDATE workspaces SET last_opened_file_path = ? WHERE id = ?",
log.Debug("updating last opened file",
"workspace_id", workspaceID,
"file_path", filePath)
result, err := db.Exec("UPDATE workspaces SET last_opened_file_path = ? WHERE id = ?",
filePath, workspaceID) filePath, workspaceID)
if err != nil { if err != nil {
return fmt.Errorf("failed to update last opened file: %w", err) return fmt.Errorf("failed to update last opened file: %w", err)
} }
rowsAffected, err := result.RowsAffected()
if err != nil {
return fmt.Errorf("failed to get rows affected: %w", err)
}
if rowsAffected == 0 {
log.Warn("no workspace found to update last opened file",
"workspace_id", workspaceID)
return fmt.Errorf("workspace not found")
}
log.Debug("last opened file updated successfully",
"workspace_id", workspaceID)
return nil return nil
} }
// GetLastOpenedFile retrieves the last opened file path for a workspace // GetLastOpenedFile retrieves the last opened file path for a workspace
func (db *database) GetLastOpenedFile(workspaceID int) (string, error) { func (db *database) GetLastOpenedFile(workspaceID int) (string, error) {
log := getLogger().WithGroup("workspaces")
log.Debug("fetching last opened file", "workspace_id", workspaceID)
var filePath sql.NullString var filePath sql.NullString
err := db.QueryRow("SELECT last_opened_file_path FROM workspaces WHERE id = ?", err := db.QueryRow("SELECT last_opened_file_path FROM workspaces WHERE id = ?",
workspaceID).Scan(&filePath) workspaceID).Scan(&filePath)
if err == sql.ErrNoRows { if err == sql.ErrNoRows {
log.Debug("workspace not found", "workspace_id", workspaceID)
return "", fmt.Errorf("workspace not found") return "", fmt.Errorf("workspace not found")
} }
if err != nil { if err != nil {
@@ -453,21 +331,14 @@ func (db *database) GetLastOpenedFile(workspaceID int) (string, error) {
} }
if !filePath.Valid { if !filePath.Valid {
log.Debug("no last opened file found", "workspace_id", workspaceID)
return "", nil return "", nil
} }
log.Debug("last opened file retrieved successfully",
"workspace_id", workspaceID,
"file_path", filePath.String)
return filePath.String, nil return filePath.String, nil
} }
// GetAllWorkspaces retrieves all workspaces in the database // GetAllWorkspaces retrieves all workspaces in the database
func (db *database) GetAllWorkspaces() ([]*models.Workspace, error) { func (db *database) GetAllWorkspaces() ([]*models.Workspace, error) {
log := getLogger().WithGroup("workspaces")
log.Debug("fetching all workspaces")
rows, err := db.Query(` rows, err := db.Query(`
SELECT SELECT
id, user_id, name, created_at, id, user_id, name, created_at,
@@ -510,6 +381,5 @@ func (db *database) GetAllWorkspaces() ([]*models.Workspace, error) {
return nil, fmt.Errorf("error iterating workspace rows: %w", err) return nil, fmt.Errorf("error iterating workspace rows: %w", err)
} }
log.Debug("all workspaces retrieved successfully", "count", len(workspaces))
return workspaces, nil return workspaces, nil
} }

View File

@@ -59,12 +59,6 @@ func getLogger() logging.Logger {
// New creates a new git Client instance // New creates a new git Client instance
func New(url, username, token, workDir, commitName, commitEmail string) Client { func New(url, username, token, workDir, commitName, commitEmail string) Client {
getLogger().Debug("creating new git client",
"url", url,
"username", username,
"workDir", workDir,
"commitName", commitName,
"commitEmail", commitEmail)
return &client{ return &client{
Config: Config{ Config: Config{
URL: url, URL: url,
@@ -99,23 +93,19 @@ func (c *client) Clone() error {
return fmt.Errorf("failed to clone repository: %w", err) return fmt.Errorf("failed to clone repository: %w", err)
} }
log.Info("repository cloned",
"url", c.URL,
"workDir", c.WorkDir)
return nil return nil
} }
// Pull pulls the latest changes from the remote repository // Pull pulls the latest changes from the remote repository
func (c *client) Pull() error { func (c *client) Pull() error {
log := getLogger() log := getLogger().With(
"workDir", c.WorkDir,
)
if c.repo == nil { if c.repo == nil {
return fmt.Errorf("repository not initialized") return fmt.Errorf("repository not initialized")
} }
log.Debug("pulling repository changes",
"workDir", c.WorkDir)
w, err := c.repo.Worktree() w, err := c.repo.Worktree()
if err != nil { if err != nil {
return fmt.Errorf("failed to get worktree: %w", err) return fmt.Errorf("failed to get worktree: %w", err)
@@ -135,27 +125,24 @@ func (c *client) Pull() error {
} }
if err == git.NoErrAlreadyUpToDate { if err == git.NoErrAlreadyUpToDate {
log.Debug("repository already up to date", log.Debug("repository already up to date")
"workDir", c.WorkDir)
} else { } else {
log.Info("pulled repository changes", log.Debug("pulled latest changes")
"workDir", c.WorkDir)
} }
return nil return nil
} }
// Commit commits the changes in the repository with the given message // Commit commits the changes in the repository with the given message
func (c *client) Commit(message string) (CommitHash, error) { func (c *client) Commit(message string) (CommitHash, error) {
log := getLogger() log := getLogger().With(
"workDir", c.WorkDir,
)
if c.repo == nil { if c.repo == nil {
return CommitHash(plumbing.ZeroHash), fmt.Errorf("repository not initialized") return CommitHash(plumbing.ZeroHash), fmt.Errorf("repository not initialized")
} }
log.Debug("preparing to commit changes",
"workDir", c.WorkDir,
"message", message)
w, err := c.repo.Worktree() w, err := c.repo.Worktree()
if err != nil { if err != nil {
return CommitHash(plumbing.ZeroHash), fmt.Errorf("failed to get worktree: %w", err) return CommitHash(plumbing.ZeroHash), fmt.Errorf("failed to get worktree: %w", err)
@@ -177,24 +164,20 @@ func (c *client) Commit(message string) (CommitHash, error) {
return CommitHash(plumbing.ZeroHash), fmt.Errorf("failed to commit changes: %w", err) return CommitHash(plumbing.ZeroHash), fmt.Errorf("failed to commit changes: %w", err)
} }
log.Info("changes committed", log.Debug("changes committed")
"hash", hash.String(),
"workDir", c.WorkDir,
"message", message)
return CommitHash(hash), nil return CommitHash(hash), nil
} }
// Push pushes the changes to the remote repository // Push pushes the changes to the remote repository
func (c *client) Push() error { func (c *client) Push() error {
log := getLogger() log := getLogger().With(
"workDir", c.WorkDir,
)
if c.repo == nil { if c.repo == nil {
return fmt.Errorf("repository not initialized") return fmt.Errorf("repository not initialized")
} }
log.Debug("pushing repository changes",
"workDir", c.WorkDir)
auth := &http.BasicAuth{ auth := &http.BasicAuth{
Username: c.Username, Username: c.Username,
Password: c.Token, Password: c.Token,
@@ -212,7 +195,7 @@ func (c *client) Push() error {
log.Debug("remote already up to date", log.Debug("remote already up to date",
"workDir", c.WorkDir) "workDir", c.WorkDir)
} else { } else {
log.Info("pushed repository changes", log.Debug("pushed repository changes",
"workDir", c.WorkDir) "workDir", c.WorkDir)
} }
return nil return nil
@@ -220,14 +203,14 @@ func (c *client) Push() error {
// EnsureRepo ensures the local repository is cloned and up-to-date // EnsureRepo ensures the local repository is cloned and up-to-date
func (c *client) EnsureRepo() error { func (c *client) EnsureRepo() error {
log := getLogger() log := getLogger().With(
"workDir", c.WorkDir,
)
log.Debug("ensuring repository exists and is up to date", log.Debug("ensuring repository exists and is up to date")
"workDir", c.WorkDir)
if _, err := os.Stat(filepath.Join(c.WorkDir, ".git")); os.IsNotExist(err) { if _, err := os.Stat(filepath.Join(c.WorkDir, ".git")); os.IsNotExist(err) {
log.Info("repository not found, initiating clone", log.Info("repository not found, initiating clone")
"workDir", c.WorkDir)
return c.Clone() return c.Clone()
} }
@@ -237,7 +220,5 @@ func (c *client) EnsureRepo() error {
return fmt.Errorf("failed to open existing repository: %w", err) return fmt.Errorf("failed to open existing repository: %w", err)
} }
log.Debug("repository opened, pulling latest changes",
"workDir", c.WorkDir)
return c.Pull() return c.Pull()
} }

View File

@@ -344,7 +344,7 @@ func (h *Handler) AdminUpdateUser() http.HandlerFunc {
return return
} }
log.Info("user updated", log.Debug("user updated",
"targetUserID", userID, "targetUserID", userID,
"updates", updates, "updates", updates,
) )

View File

@@ -124,7 +124,7 @@ func (h *Handler) Login(authManager auth.SessionManager, cookieService auth.Cook
ExpiresAt: session.ExpiresAt, ExpiresAt: session.ExpiresAt,
} }
log.Info("user logged in successfully", log.Debug("user logged in",
"userID", user.ID, "userID", user.ID,
"email", user.Email, "email", user.Email,
"role", user.Role, "role", user.Role,

View File

@@ -73,9 +73,6 @@ func (h *Handler) ListFiles() http.HandlerFunc {
return return
} }
log.Debug("files listed successfully",
"fileCount", len(files),
)
respondJSON(w, files) respondJSON(w, files)
} }
} }
@@ -129,10 +126,6 @@ func (h *Handler) LookupFileByName() http.HandlerFunc {
return return
} }
log.Debug("file lookup successful",
"filename", filename,
"matchCount", len(filePaths),
)
respondJSON(w, &LookupResponse{Paths: filePaths}) respondJSON(w, &LookupResponse{Paths: filePaths})
} }
} }
@@ -203,11 +196,6 @@ func (h *Handler) GetFileContent() http.HandlerFunc {
respondError(w, "Failed to write response", http.StatusInternalServerError) respondError(w, "Failed to write response", http.StatusInternalServerError)
return return
} }
log.Debug("file content retrieved",
"filePath", filePath,
"contentSize", len(content),
)
} }
} }
@@ -276,11 +264,6 @@ func (h *Handler) SaveFile() http.HandlerFunc {
UpdatedAt: time.Now().UTC(), UpdatedAt: time.Now().UTC(),
} }
log.Debug("file saved",
"filePath", filePath,
"size", response.Size,
"updatedAt", response.UpdatedAt,
)
respondJSON(w, response) respondJSON(w, response)
} }
} }
@@ -339,9 +322,6 @@ func (h *Handler) DeleteFile() http.HandlerFunc {
return return
} }
log.Debug("file deleted",
"filePath", filePath,
)
w.WriteHeader(http.StatusNoContent) w.WriteHeader(http.StatusNoContent)
} }
} }
@@ -389,9 +369,6 @@ func (h *Handler) GetLastOpenedFile() http.HandlerFunc {
return return
} }
log.Debug("last opened file retrieved successfully",
"filePath", filePath,
)
respondJSON(w, &LastOpenedFileResponse{LastOpenedFilePath: filePath}) respondJSON(w, &LastOpenedFileResponse{LastOpenedFilePath: filePath})
} }
} }
@@ -473,9 +450,6 @@ func (h *Handler) UpdateLastOpenedFile() http.HandlerFunc {
return return
} }
log.Debug("last opened file updated successfully",
"filePath", requestBody.FilePath,
)
w.WriteHeader(http.StatusNoContent) w.WriteHeader(http.StatusNoContent)
} }
} }

View File

@@ -78,11 +78,6 @@ func (h *Handler) StageCommitAndPush() http.HandlerFunc {
return return
} }
log.Debug("git operations completed successfully",
"commitHash", hash.String(),
"commitMessage", requestBody.Message,
)
respondJSON(w, CommitResponse{CommitHash: hash.String()}) respondJSON(w, CommitResponse{CommitHash: hash.String()})
} }
} }
@@ -120,7 +115,6 @@ func (h *Handler) PullChanges() http.HandlerFunc {
return return
} }
log.Debug("successfully pulled changes from remote")
respondJSON(w, PullResponse{Message: "Successfully pulled changes from remote"}) respondJSON(w, PullResponse{Message: "Successfully pulled changes from remote"})
} }
} }

View File

@@ -51,9 +51,6 @@ func (h *StaticHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
// Set cache headers for assets // Set cache headers for assets
if strings.HasPrefix(requestedPath, "/assets/") { if strings.HasPrefix(requestedPath, "/assets/") {
w.Header().Set("Cache-Control", "public, max-age=31536000") // 1 year w.Header().Set("Cache-Control", "public, max-age=31536000") // 1 year
log.Debug("cache headers set for asset",
"path", requestedPath,
)
} }
// Check if file exists (not counting .gz files) // Check if file exists (not counting .gz files)
@@ -97,22 +94,11 @@ func (h *StaticHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
contentType = "text/html" contentType = "text/html"
} }
w.Header().Set("Content-Type", contentType) w.Header().Set("Content-Type", contentType)
log.Debug("serving gzipped file",
"path", requestedPath,
"gzPath", gzPath,
"contentType", contentType,
)
http.ServeFile(w, r, gzPath) http.ServeFile(w, r, gzPath)
return return
} }
} }
// Serve original file // Serve original file
log.Debug("serving original file",
"path", requestedPath,
"size", stat.Size(),
"modTime", stat.ModTime(),
)
http.ServeFile(w, r, cleanPath) http.ServeFile(w, r, cleanPath)
} }

View File

@@ -118,7 +118,7 @@ func (h *Handler) UpdateProfile() http.HandlerFunc {
// Handle email update if requested // Handle email update if requested
if req.Email != "" && req.Email != user.Email { if req.Email != "" && req.Email != user.Email {
if req.CurrentPassword == "" { if req.CurrentPassword == "" {
log.Debug("email change attempted without current password") log.Warn("attempted email change without current password")
respondError(w, "Current password is required to change email", http.StatusBadRequest) respondError(w, "Current password is required to change email", http.StatusBadRequest)
return return
} }
@@ -159,9 +159,6 @@ func (h *Handler) UpdateProfile() http.HandlerFunc {
return return
} }
log.Debug("profile updated successfully",
"updates", updates,
)
respondJSON(w, user) respondJSON(w, user)
} }
} }

View File

@@ -55,9 +55,6 @@ func (h *Handler) ListWorkspaces() http.HandlerFunc {
return return
} }
log.Debug("workspaces retrieved successfully",
"count", len(workspaces),
)
respondJSON(w, workspaces) respondJSON(w, workspaces)
} }
} }
@@ -127,11 +124,6 @@ func (h *Handler) CreateWorkspace() http.HandlerFunc {
} }
if workspace.GitEnabled { if workspace.GitEnabled {
log.Debug("setting up git repository",
"workspaceID", workspace.ID,
"gitURL", workspace.GitURL,
)
if err := h.Storage.SetupGitRepo( if err := h.Storage.SetupGitRepo(
ctx.UserID, ctx.UserID,
workspace.ID, workspace.ID,
@@ -260,10 +252,6 @@ func (h *Handler) UpdateWorkspace() http.HandlerFunc {
// Handle Git repository setup/teardown if Git settings changed // Handle Git repository setup/teardown if Git settings changed
if changes["gitSettings"] { if changes["gitSettings"] {
if workspace.GitEnabled { if workspace.GitEnabled {
log.Debug("updating git repository configuration",
"gitURL", workspace.GitURL,
)
if err := h.Storage.SetupGitRepo( if err := h.Storage.SetupGitRepo(
ctx.UserID, ctx.UserID,
ctx.Workspace.ID, ctx.Workspace.ID,
@@ -280,7 +268,6 @@ func (h *Handler) UpdateWorkspace() http.HandlerFunc {
return return
} }
} else { } else {
log.Debug("disabling git repository")
h.Storage.DisableGitRepo(ctx.UserID, ctx.Workspace.ID) h.Storage.DisableGitRepo(ctx.UserID, ctx.Workspace.ID)
} }
} }
@@ -293,9 +280,6 @@ func (h *Handler) UpdateWorkspace() http.HandlerFunc {
return return
} }
log.Debug("workspace updated",
"changes", changes,
)
respondJSON(w, workspace) respondJSON(w, workspace)
} }
} }
@@ -445,9 +429,6 @@ func (h *Handler) GetLastWorkspaceName() http.HandlerFunc {
return return
} }
log.Debug("last workspace name retrieved",
"workspaceName", workspaceName,
)
respondJSON(w, &LastWorkspaceNameResponse{LastWorkspaceName: workspaceName}) respondJSON(w, &LastWorkspaceNameResponse{LastWorkspaceName: workspaceName})
} }
} }
@@ -497,9 +478,6 @@ func (h *Handler) UpdateLastWorkspaceName() http.HandlerFunc {
return return
} }
log.Debug("last workspace name updated",
"workspaceName", requestBody.WorkspaceName,
)
w.WriteHeader(http.StatusNoContent) w.WriteHeader(http.StatusNoContent)
} }
} }

View File

@@ -65,8 +65,6 @@ func decodeAndValidateKey(key string) ([]byte, error) {
// NewService creates a new Encryptor instance with the provided base64-encoded key // NewService creates a new Encryptor instance with the provided base64-encoded key
func NewService(key string) (Service, error) { func NewService(key string) (Service, error) {
log := getLogger() log := getLogger()
log.Debug("creating new encryption service")
keyBytes, err := decodeAndValidateKey(key) keyBytes, err := decodeAndValidateKey(key)
if err != nil { if err != nil {
return nil, err return nil, err

View File

@@ -30,21 +30,12 @@ type FileNode struct {
// ListFilesRecursively returns a list of all files in the workspace directory and its subdirectories. // ListFilesRecursively returns a list of all files in the workspace directory and its subdirectories.
// Workspace is identified by the given userID and workspaceID. // Workspace is identified by the given userID and workspaceID.
func (s *Service) ListFilesRecursively(userID, workspaceID int) ([]FileNode, error) { func (s *Service) ListFilesRecursively(userID, workspaceID int) ([]FileNode, error) {
log := getLogger()
log.Debug("listing files recursively",
"userID", userID,
"workspaceID", workspaceID)
workspacePath := s.GetWorkspacePath(userID, workspaceID) workspacePath := s.GetWorkspacePath(userID, workspaceID)
nodes, err := s.walkDirectory(workspacePath, "") nodes, err := s.walkDirectory(workspacePath, "")
if err != nil { if err != nil {
return nil, err return nil, err
} }
log.Debug("file listing complete",
"userID", userID,
"workspaceID", workspaceID,
"nodeCount", len(nodes))
return nodes, nil return nodes, nil
} }
@@ -116,12 +107,6 @@ func (s *Service) walkDirectory(dir, prefix string) ([]FileNode, error) {
// Files are searched recursively in the workspace directory and its subdirectories. // Files are searched recursively in the workspace directory and its subdirectories.
// Workspace is identified by the given userID and workspaceID. // Workspace is identified by the given userID and workspaceID.
func (s *Service) FindFileByName(userID, workspaceID int, filename string) ([]string, error) { func (s *Service) FindFileByName(userID, workspaceID int, filename string) ([]string, error) {
log := getLogger()
log.Debug("searching for file by name",
"userID", userID,
"workspaceID", workspaceID,
"filename", filename)
var foundPaths []string var foundPaths []string
workspacePath := s.GetWorkspacePath(userID, workspaceID) workspacePath := s.GetWorkspacePath(userID, workspaceID)
@@ -149,23 +134,12 @@ func (s *Service) FindFileByName(userID, workspaceID int, filename string) ([]st
return nil, fmt.Errorf("file not found") return nil, fmt.Errorf("file not found")
} }
log.Debug("file search complete",
"userID", userID,
"workspaceID", workspaceID,
"filename", filename,
"matchCount", len(foundPaths))
return foundPaths, nil return foundPaths, nil
} }
// GetFileContent returns the content of the file at the given filePath. // GetFileContent returns the content of the file at the given filePath.
// Path must be a relative path within the workspace directory given by userID and workspaceID. // Path must be a relative path within the workspace directory given by userID and workspaceID.
func (s *Service) GetFileContent(userID, workspaceID int, filePath string) ([]byte, error) { func (s *Service) GetFileContent(userID, workspaceID int, filePath string) ([]byte, error) {
log := getLogger()
log.Debug("reading file content",
"userID", userID,
"workspaceID", workspaceID,
"path", filePath)
fullPath, err := s.ValidatePath(userID, workspaceID, filePath) fullPath, err := s.ValidatePath(userID, workspaceID, filePath)
if err != nil { if err != nil {
return nil, err return nil, err
@@ -177,11 +151,6 @@ func (s *Service) GetFileContent(userID, workspaceID int, filePath string) ([]by
// Path must be a relative path within the workspace directory given by userID and workspaceID. // Path must be a relative path within the workspace directory given by userID and workspaceID.
func (s *Service) SaveFile(userID, workspaceID int, filePath string, content []byte) error { func (s *Service) SaveFile(userID, workspaceID int, filePath string, content []byte) error {
log := getLogger() log := getLogger()
log.Debug("saving file",
"userID", userID,
"workspaceID", workspaceID,
"path", filePath,
"contentSize", len(content))
fullPath, err := s.ValidatePath(userID, workspaceID, filePath) fullPath, err := s.ValidatePath(userID, workspaceID, filePath)
if err != nil { if err != nil {
@@ -209,11 +178,6 @@ func (s *Service) SaveFile(userID, workspaceID int, filePath string, content []b
// Path must be a relative path within the workspace directory given by userID and workspaceID. // Path must be a relative path within the workspace directory given by userID and workspaceID.
func (s *Service) DeleteFile(userID, workspaceID int, filePath string) error { func (s *Service) DeleteFile(userID, workspaceID int, filePath string) error {
log := getLogger() log := getLogger()
log.Debug("deleting file",
"userID", userID,
"workspaceID", workspaceID,
"path", filePath)
fullPath, err := s.ValidatePath(userID, workspaceID, filePath) fullPath, err := s.ValidatePath(userID, workspaceID, filePath)
if err != nil { if err != nil {
return err return err
@@ -239,11 +203,6 @@ type FileCountStats struct {
// GetFileStats returns the total number of files and related statistics in a workspace // GetFileStats returns the total number of files and related statistics in a workspace
// Workspace is identified by the given userID and workspaceID // Workspace is identified by the given userID and workspaceID
func (s *Service) GetFileStats(userID, workspaceID int) (*FileCountStats, error) { func (s *Service) GetFileStats(userID, workspaceID int) (*FileCountStats, error) {
log := getLogger()
log.Debug("gathering file statistics",
"userID", userID,
"workspaceID", workspaceID)
workspacePath := s.GetWorkspacePath(userID, workspaceID) workspacePath := s.GetWorkspacePath(userID, workspaceID)
// Check if workspace exists // Check if workspace exists
@@ -256,27 +215,16 @@ func (s *Service) GetFileStats(userID, workspaceID int) (*FileCountStats, error)
return nil, err return nil, err
} }
log.Debug("file statistics collected",
"userID", userID,
"workspaceID", workspaceID,
"totalFiles", stats.TotalFiles,
"totalSize", stats.TotalSize)
return stats, nil return stats, nil
} }
// GetTotalFileStats returns the total file statistics for the storage. // GetTotalFileStats returns the total file statistics for the storage.
func (s *Service) GetTotalFileStats() (*FileCountStats, error) { func (s *Service) GetTotalFileStats() (*FileCountStats, error) {
log := getLogger()
log.Debug("gathering total storage statistics")
stats, err := s.countFilesInPath(s.RootDir) stats, err := s.countFilesInPath(s.RootDir)
if err != nil { if err != nil {
return nil, err return nil, err
} }
log.Debug("total storage statistics collected",
"totalFiles", stats.TotalFiles,
"totalSize", stats.TotalSize)
return stats, nil return stats, nil
} }

View File

@@ -16,17 +16,9 @@ type RepositoryManager interface {
// SetupGitRepo sets up a Git repository for the given userID and workspaceID. // SetupGitRepo sets up a Git repository for the given userID and workspaceID.
// The repository is cloned from the given gitURL using the given gitUser and gitToken. // The repository is cloned from the given gitURL using the given gitUser and gitToken.
func (s *Service) SetupGitRepo(userID, workspaceID int, gitURL, gitUser, gitToken, commitName, commitEmail string) error { func (s *Service) SetupGitRepo(userID, workspaceID int, gitURL, gitUser, gitToken, commitName, commitEmail string) error {
log := getLogger()
log.Info("setting up git repository",
"userID", userID,
"workspaceID", workspaceID,
)
workspacePath := s.GetWorkspacePath(userID, workspaceID) workspacePath := s.GetWorkspacePath(userID, workspaceID)
if _, ok := s.GitRepos[userID]; !ok { if _, ok := s.GitRepos[userID]; !ok {
log.Debug("initializing git repo map for user",
"userID", userID)
s.GitRepos[userID] = make(map[int]git.Client) s.GitRepos[userID] = make(map[int]git.Client)
} }
@@ -37,16 +29,14 @@ func (s *Service) SetupGitRepo(userID, workspaceID int, gitURL, gitUser, gitToke
// DisableGitRepo disables the Git repository for the given userID and workspaceID. // DisableGitRepo disables the Git repository for the given userID and workspaceID.
func (s *Service) DisableGitRepo(userID, workspaceID int) { func (s *Service) DisableGitRepo(userID, workspaceID int) {
log := getLogger() log := getLogger().WithGroup("git")
log.Info("disabling git repository", log.Debug("disabling git repository",
"userID", userID, "userID", userID,
"workspaceID", workspaceID) "workspaceID", workspaceID)
if userRepos, ok := s.GitRepos[userID]; ok { if userRepos, ok := s.GitRepos[userID]; ok {
delete(userRepos, workspaceID) delete(userRepos, workspaceID)
if len(userRepos) == 0 { if len(userRepos) == 0 {
log.Debug("removing empty user git repos map",
"userID", userID)
delete(s.GitRepos, userID) delete(s.GitRepos, userID)
} }
} }
@@ -55,12 +45,6 @@ func (s *Service) DisableGitRepo(userID, workspaceID int) {
// StageCommitAndPush stages, commit with the message, and pushes the changes to the Git repository. // StageCommitAndPush stages, commit with the message, and pushes the changes to the Git repository.
// The git repository belongs to the given userID and is associated with the given workspaceID. // The git repository belongs to the given userID and is associated with the given workspaceID.
func (s *Service) StageCommitAndPush(userID, workspaceID int, message string) (git.CommitHash, error) { func (s *Service) StageCommitAndPush(userID, workspaceID int, message string) (git.CommitHash, error) {
log := getLogger()
log.Debug("preparing to stage, commit and push changes",
"userID", userID,
"workspaceID", workspaceID,
"message", message)
repo, ok := s.getGitRepo(userID, workspaceID) repo, ok := s.getGitRepo(userID, workspaceID)
if !ok { if !ok {
return git.CommitHash{}, fmt.Errorf("git settings not configured for this workspace") return git.CommitHash{}, fmt.Errorf("git settings not configured for this workspace")
@@ -75,21 +59,12 @@ func (s *Service) StageCommitAndPush(userID, workspaceID int, message string) (g
return hash, err return hash, err
} }
log.Debug("changes committed and pushed",
"userID", userID,
"workspaceID", workspaceID,
"commitHash", hash.String())
return hash, nil return hash, nil
} }
// Pull pulls the changes from the remote Git repository. // Pull pulls the changes from the remote Git repository.
// The git repository belongs to the given userID and is associated with the given workspaceID. // The git repository belongs to the given userID and is associated with the given workspaceID.
func (s *Service) Pull(userID, workspaceID int) error { func (s *Service) Pull(userID, workspaceID int) error {
log := getLogger()
log.Debug("preparing to pull changes",
"userID", userID,
"workspaceID", workspaceID)
repo, ok := s.getGitRepo(userID, workspaceID) repo, ok := s.getGitRepo(userID, workspaceID)
if !ok { if !ok {
return fmt.Errorf("git settings not configured for this workspace") return fmt.Errorf("git settings not configured for this workspace")
@@ -100,9 +75,6 @@ func (s *Service) Pull(userID, workspaceID int) error {
return err return err
} }
log.Debug("changes pulled from remote",
"userID", userID,
"workspaceID", workspaceID)
return nil return nil
} }

View File

@@ -43,18 +43,13 @@ func NewServiceWithOptions(rootDir string, options Options) *Service {
"rootDir", rootDir) "rootDir", rootDir)
if options.Fs == nil { if options.Fs == nil {
log.Debug("filesystem not provided, using default osFS")
options.Fs = &osFS{} options.Fs = &osFS{}
} }
if options.NewGitClient == nil { if options.NewGitClient == nil {
log.Debug("git client factory not provided, using default git.New")
options.NewGitClient = git.New options.NewGitClient = git.New
} }
log.Info("storage service created",
"rootDir", rootDir)
return &Service{ return &Service{
fs: options.Fs, fs: options.Fs,
newGitClient: options.NewGitClient, newGitClient: options.NewGitClient,

View File

@@ -17,12 +17,6 @@ type WorkspaceManager interface {
// ValidatePath validates the if the given path is valid within the workspace directory. // ValidatePath validates the if the given path is valid within the workspace directory.
// Workspace directory is defined as the directory for the given userID and workspaceID. // Workspace directory is defined as the directory for the given userID and workspaceID.
func (s *Service) ValidatePath(userID, workspaceID int, path string) (string, error) { func (s *Service) ValidatePath(userID, workspaceID int, path string) (string, error) {
log := getLogger()
log.Debug("validating path",
"userID", userID,
"workspaceID", workspaceID,
"path", path)
workspacePath := s.GetWorkspacePath(userID, workspaceID) workspacePath := s.GetWorkspacePath(userID, workspaceID)
// First check if the path is absolute // First check if the path is absolute