Implement file system stats

This commit is contained in:
2024-11-09 23:11:23 +01:00
parent 9688b2d528
commit 7b1da94e8a
4 changed files with 98 additions and 8 deletions

View File

@@ -3,8 +3,8 @@ package db
import "novamd/internal/models" import "novamd/internal/models"
// SystemStats represents system-wide statistics // UserStats represents system-wide statistics
type SystemStats struct { type UserStats struct {
TotalUsers int `json:"totalUsers"` TotalUsers int `json:"totalUsers"`
TotalWorkspaces int `json:"totalWorkspaces"` TotalWorkspaces int `json:"totalWorkspaces"`
ActiveUsers int `json:"activeUsers"` // Users with activity in last 30 days 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 // GetSystemStats returns system-wide statistics
func (db *DB) GetSystemStats() (*SystemStats, error) { func (db *DB) GetSystemStats() (*UserStats, error) {
stats := &SystemStats{} stats := &UserStats{}
// Get total users // Get total users
err := db.QueryRow("SELECT COUNT(*) FROM users").Scan(&stats.TotalUsers) err := db.QueryRow("SELECT COUNT(*) FROM users").Scan(&stats.TotalUsers)

View File

@@ -4,6 +4,7 @@ package filesystem
import ( import (
"errors" "errors"
"fmt"
"os" "os"
"path/filepath" "path/filepath"
"sort" "sort"
@@ -151,3 +152,68 @@ func (fs *FileSystem) DeleteFile(userID, workspaceID int, filePath string) error
} }
return os.Remove(fullPath) 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
}

View File

@@ -33,3 +33,8 @@ func (fs *FileSystem) ValidatePath(userID, workspaceID int, path string) (string
return cleanPath, nil return cleanPath, nil
} }
// GetTotalFileStats returns the total file statistics for the file system.
func (fs *FileSystem) GetTotalFileStats() (*FileCountStats, error) {
return fs.countFilesInPath(fs.RootDir)
}

View File

@@ -3,6 +3,8 @@ package handlers
import ( import (
"encoding/json" "encoding/json"
"net/http" "net/http"
"novamd/internal/db"
"novamd/internal/filesystem"
"novamd/internal/httpcontext" "novamd/internal/httpcontext"
"novamd/internal/models" "novamd/internal/models"
"strconv" "strconv"
@@ -27,7 +29,7 @@ type UpdateUserRequest struct {
// AdminListUsers returns a list of all users // AdminListUsers returns a list of all users
func (h *Handler) AdminListUsers() http.HandlerFunc { 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() users, err := h.DB.GetAllUsers()
if err != nil { if err != nil {
http.Error(w, "Failed to list users", http.StatusInternalServerError) 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 // AdminGetSystemStats returns system-wide statistics for admins
func (h *Handler) AdminGetSystemStats() http.HandlerFunc { func (h *Handler) AdminGetSystemStats() http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) { return func(w http.ResponseWriter, _ *http.Request) {
stats, err := h.DB.GetSystemStats() userStats, err := h.DB.GetSystemStats()
if err != nil { if err != nil {
http.Error(w, "Failed to get system stats", http.StatusInternalServerError) http.Error(w, "Failed to get user stats", http.StatusInternalServerError)
return 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) respondJSON(w, stats)
} }
} }