From 7b1da94e8a492fa78bb20377e215d7704844bc84 Mon Sep 17 00:00:00 2001 From: LordMathis Date: Sat, 9 Nov 2024 23:11:23 +0100 Subject: [PATCH] Implement file system stats --- backend/internal/db/admin.go | 8 +-- backend/internal/filesystem/files.go | 66 +++++++++++++++++++++ backend/internal/filesystem/filesystem.go | 5 ++ backend/internal/handlers/admin_handlers.go | 27 +++++++-- 4 files changed, 98 insertions(+), 8 deletions(-) diff --git a/backend/internal/db/admin.go b/backend/internal/db/admin.go index da217f2..15c8a84 100644 --- a/backend/internal/db/admin.go +++ b/backend/internal/db/admin.go @@ -3,8 +3,8 @@ package db import "novamd/internal/models" -// SystemStats represents system-wide statistics -type SystemStats struct { +// UserStats represents system-wide statistics +type UserStats struct { TotalUsers int `json:"totalUsers"` TotalWorkspaces int `json:"totalWorkspaces"` ActiveUsers int `json:"activeUsers"` // Users with activity in last 30 days @@ -39,8 +39,8 @@ func (db *DB) GetAllUsers() ([]*models.User, error) { } // GetSystemStats returns system-wide statistics -func (db *DB) GetSystemStats() (*SystemStats, error) { - stats := &SystemStats{} +func (db *DB) GetSystemStats() (*UserStats, error) { + stats := &UserStats{} // Get total users err := db.QueryRow("SELECT COUNT(*) FROM users").Scan(&stats.TotalUsers) diff --git a/backend/internal/filesystem/files.go b/backend/internal/filesystem/files.go index 152e284..3857708 100644 --- a/backend/internal/filesystem/files.go +++ b/backend/internal/filesystem/files.go @@ -4,6 +4,7 @@ package filesystem import ( "errors" + "fmt" "os" "path/filepath" "sort" @@ -151,3 +152,68 @@ func (fs *FileSystem) DeleteFile(userID, workspaceID int, filePath string) error } return os.Remove(fullPath) } + +// FileCountStats holds statistics about files in a workspace +type FileCountStats struct { + TotalFiles int `json:"totalFiles"` + TotalSize int64 `json:"totalSize"` +} + +// GetFileStats returns the total number of files and related statistics in a workspace +// Parameters: +// - userID: the ID of the user who owns the workspace +// - workspaceID: the ID of the workspace to count files in +// Returns: +// - result: statistics about the files in the workspace +// - error: any error that occurred during counting +func (fs *FileSystem) GetFileStats(userID, workspaceID int) (*FileCountStats, error) { + workspacePath := fs.GetWorkspacePath(userID, workspaceID) + + // Check if workspace exists + if _, err := os.Stat(workspacePath); os.IsNotExist(err) { + return nil, errors.New("workspace directory does not exist") + } + + return fs.countFilesInPath(workspacePath) + +} + +func (fs *FileSystem) countFilesInPath(directoryPath string) (*FileCountStats, error) { + result := &FileCountStats{} + + err := filepath.WalkDir(directoryPath, func(path string, d os.DirEntry, err error) error { + if err != nil { + return err + } + + // Skip the .git directory + if d.IsDir() && d.Name() == ".git" { + return filepath.SkipDir + } + + // Only count regular files + if !d.IsDir() { + // Get relative path from workspace root + relPath, err := filepath.Rel(directoryPath, path) + if err != nil { + return fmt.Errorf("failed to get relative path: %w", err) + } + + // Get file info for size + info, err := d.Info() + if err != nil { + return fmt.Errorf("failed to get file info for %s: %w", relPath, err) + } + + result.TotalFiles++ + result.TotalSize += info.Size() + } + return nil + }) + + if err != nil { + return nil, fmt.Errorf("error counting files: %w", err) + } + + return result, nil +} diff --git a/backend/internal/filesystem/filesystem.go b/backend/internal/filesystem/filesystem.go index 87ba6b2..35f5637 100644 --- a/backend/internal/filesystem/filesystem.go +++ b/backend/internal/filesystem/filesystem.go @@ -33,3 +33,8 @@ func (fs *FileSystem) ValidatePath(userID, workspaceID int, path string) (string return cleanPath, nil } + +// GetTotalFileStats returns the total file statistics for the file system. +func (fs *FileSystem) GetTotalFileStats() (*FileCountStats, error) { + return fs.countFilesInPath(fs.RootDir) +} diff --git a/backend/internal/handlers/admin_handlers.go b/backend/internal/handlers/admin_handlers.go index 4c78ed1..69ba0c6 100644 --- a/backend/internal/handlers/admin_handlers.go +++ b/backend/internal/handlers/admin_handlers.go @@ -3,6 +3,8 @@ package handlers import ( "encoding/json" "net/http" + "novamd/internal/db" + "novamd/internal/filesystem" "novamd/internal/httpcontext" "novamd/internal/models" "strconv" @@ -27,7 +29,7 @@ type UpdateUserRequest struct { // AdminListUsers returns a list of all users func (h *Handler) AdminListUsers() http.HandlerFunc { - return func(w http.ResponseWriter, r *http.Request) { + return func(w http.ResponseWriter, _ *http.Request) { users, err := h.DB.GetAllUsers() if err != nil { http.Error(w, "Failed to list users", http.StatusInternalServerError) @@ -202,15 +204,32 @@ func (h *Handler) AdminDeleteUser() http.HandlerFunc { } } +// SystemStats holds system-wide statistics +type SystemStats struct { + *db.UserStats + *filesystem.FileCountStats +} + // AdminGetSystemStats returns system-wide statistics for admins func (h *Handler) AdminGetSystemStats() http.HandlerFunc { - return func(w http.ResponseWriter, r *http.Request) { - stats, err := h.DB.GetSystemStats() + return func(w http.ResponseWriter, _ *http.Request) { + userStats, err := h.DB.GetSystemStats() if err != nil { - http.Error(w, "Failed to get system stats", http.StatusInternalServerError) + http.Error(w, "Failed to get user stats", http.StatusInternalServerError) return } + fileStats, err := h.FS.GetTotalFileStats() + if err != nil { + http.Error(w, "Failed to get file stats", http.StatusInternalServerError) + return + } + + stats := &SystemStats{ + UserStats: userStats, + FileCountStats: fileStats, + } + respondJSON(w, stats) } }