Rename filesystem interfaces and structs

This commit is contained in:
2024-11-14 21:13:45 +01:00
parent 5311d2e144
commit e4510298ed
16 changed files with 206 additions and 128 deletions

View File

@@ -17,8 +17,8 @@ import (
"novamd/internal/auth"
"novamd/internal/config"
"novamd/internal/db"
"novamd/internal/filesystem"
"novamd/internal/handlers"
"novamd/internal/storage"
)
func main() {
@@ -45,7 +45,7 @@ func main() {
}
// Initialize filesystem
fs := filesystem.New(cfg.WorkDir)
s := storage.NewService(cfg.WorkDir)
// Initialize JWT service
jwtService, err := auth.NewJWTService(auth.JWTConfig{
@@ -95,7 +95,7 @@ func main() {
// Set up routes
r.Route("/api/v1", func(r chi.Router) {
r.Use(httprate.LimitByIP(cfg.RateLimitRequests, cfg.RateLimitWindow))
api.SetupRoutes(r, database, fs, authMiddleware, sessionService)
api.SetupRoutes(r, database, s, authMiddleware, sessionService)
})
// Handle all other routes with static file server

View File

@@ -4,19 +4,19 @@ package api
import (
"novamd/internal/auth"
"novamd/internal/db"
"novamd/internal/filesystem"
"novamd/internal/handlers"
"novamd/internal/middleware"
"novamd/internal/storage"
"github.com/go-chi/chi/v5"
)
// SetupRoutes configures the API routes
func SetupRoutes(r chi.Router, db *db.DB, s *filesystem.Storage, authMiddleware *auth.Middleware, sessionService *auth.SessionService) {
func SetupRoutes(r chi.Router, db *db.DB, s storage.Manager, authMiddleware *auth.Middleware, sessionService *auth.SessionService) {
handler := &handlers.Handler{
DB: db,
S: s,
DB: db,
Storage: s,
}
// Public routes (no authentication required)

View File

@@ -1,58 +0,0 @@
package filesystem
import (
"fmt"
"novamd/internal/gitutils"
"path/filepath"
"strings"
)
// Storage represents the file system structure.
type Storage struct {
fs fileSystem
RootDir string
GitRepos map[int]map[int]*gitutils.GitRepo // map[userID]map[workspaceID]*gitutils.GitRepo
}
// New creates a new Storage instance.
// Parameters:
// - rootDir: the root directory for the storage
// Returns:
// - result: the new Storage instance
func New(rootDir string) *Storage {
return NewWithFS(rootDir, &osFS{})
}
// NewWithFS creates a new Storage instance with the given filesystem.
// Parameters:
// - rootDir: the root directory for the storage
// - fs: the filesystem implementation to use
// Returns:
// - result: the new Storage instance
func NewWithFS(rootDir string, fs fileSystem) *Storage {
return &Storage{
fs: fs,
RootDir: rootDir,
GitRepos: make(map[int]map[int]*gitutils.GitRepo),
}
}
// ValidatePath validates the given path and returns the cleaned path if it is valid.
// Parameters:
// - userID: the ID of the user who owns the workspace
// - workspaceID: the ID of the workspace to validate the path for
// - path: the path to validate
// Returns:
// - result: the cleaned path if it is valid
// - error: any error that occurred during validation
func (s *Storage) ValidatePath(userID, workspaceID int, path string) (string, error) {
workspacePath := s.GetWorkspacePath(userID, workspaceID)
fullPath := filepath.Join(workspacePath, path)
cleanPath := filepath.Clean(fullPath)
if !strings.HasPrefix(cleanPath, workspacePath) {
return "", fmt.Errorf("invalid path: outside of workspace")
}
return cleanPath, nil
}

View File

@@ -4,9 +4,9 @@ import (
"encoding/json"
"net/http"
"novamd/internal/db"
"novamd/internal/filesystem"
"novamd/internal/httpcontext"
"novamd/internal/models"
"novamd/internal/storage"
"strconv"
"time"
@@ -91,7 +91,7 @@ func (h *Handler) AdminCreateUser() http.HandlerFunc {
}
// Initialize user workspace
if err := h.S.InitializeUserWorkspace(insertedUser.ID, insertedUser.LastWorkspaceID); err != nil {
if err := h.Storage.InitializeUserWorkspace(insertedUser.ID, insertedUser.LastWorkspaceID); err != nil {
http.Error(w, "Failed to initialize user workspace", http.StatusInternalServerError)
return
}
@@ -218,7 +218,7 @@ type WorkspaceStats struct {
WorkspaceID int `json:"workspaceID"`
WorkspaceName string `json:"workspaceName"`
WorkspaceCreatedAt time.Time `json:"workspaceCreatedAt"`
*filesystem.FileCountStats
*storage.FileCountStats
}
// AdminListWorkspaces returns a list of all workspaces and their stats
@@ -248,7 +248,7 @@ func (h *Handler) AdminListWorkspaces() http.HandlerFunc {
workspaceData.WorkspaceName = ws.Name
workspaceData.WorkspaceCreatedAt = ws.CreatedAt
fileStats, err := h.S.GetFileStats(ws.UserID, ws.ID)
fileStats, err := h.Storage.GetFileStats(ws.UserID, ws.ID)
if err != nil {
http.Error(w, "Failed to get file stats", http.StatusInternalServerError)
return
@@ -266,7 +266,7 @@ func (h *Handler) AdminListWorkspaces() http.HandlerFunc {
// SystemStats holds system-wide statistics
type SystemStats struct {
*db.UserStats
*filesystem.FileCountStats
*storage.FileCountStats
}
// AdminGetSystemStats returns system-wide statistics for admins
@@ -278,7 +278,7 @@ func (h *Handler) AdminGetSystemStats() http.HandlerFunc {
return
}
fileStats, err := h.S.GetTotalFileStats()
fileStats, err := h.Storage.GetTotalFileStats()
if err != nil {
http.Error(w, "Failed to get file stats", http.StatusInternalServerError)
return

View File

@@ -17,7 +17,7 @@ func (h *Handler) ListFiles() http.HandlerFunc {
return
}
files, err := h.S.ListFilesRecursively(ctx.UserID, ctx.Workspace.ID)
files, err := h.Storage.ListFilesRecursively(ctx.UserID, ctx.Workspace.ID)
if err != nil {
http.Error(w, "Failed to list files", http.StatusInternalServerError)
return
@@ -40,7 +40,7 @@ func (h *Handler) LookupFileByName() http.HandlerFunc {
return
}
filePaths, err := h.S.FindFileByName(ctx.UserID, ctx.Workspace.ID, filename)
filePaths, err := h.Storage.FindFileByName(ctx.UserID, ctx.Workspace.ID, filename)
if err != nil {
http.Error(w, "File not found", http.StatusNotFound)
return
@@ -58,7 +58,7 @@ func (h *Handler) GetFileContent() http.HandlerFunc {
}
filePath := chi.URLParam(r, "*")
content, err := h.S.GetFileContent(ctx.UserID, ctx.Workspace.ID, filePath)
content, err := h.Storage.GetFileContent(ctx.UserID, ctx.Workspace.ID, filePath)
if err != nil {
http.Error(w, "Failed to read file", http.StatusNotFound)
return
@@ -83,7 +83,7 @@ func (h *Handler) SaveFile() http.HandlerFunc {
return
}
err = h.S.SaveFile(ctx.UserID, ctx.Workspace.ID, filePath, content)
err = h.Storage.SaveFile(ctx.UserID, ctx.Workspace.ID, filePath, content)
if err != nil {
http.Error(w, "Failed to save file", http.StatusInternalServerError)
return
@@ -101,7 +101,7 @@ func (h *Handler) DeleteFile() http.HandlerFunc {
}
filePath := chi.URLParam(r, "*")
err := h.S.DeleteFile(ctx.UserID, ctx.Workspace.ID, filePath)
err := h.Storage.DeleteFile(ctx.UserID, ctx.Workspace.ID, filePath)
if err != nil {
http.Error(w, "Failed to delete file", http.StatusInternalServerError)
return
@@ -125,7 +125,7 @@ func (h *Handler) GetLastOpenedFile() http.HandlerFunc {
return
}
if _, err := h.S.ValidatePath(ctx.UserID, ctx.Workspace.ID, filePath); err != nil {
if _, err := h.Storage.ValidatePath(ctx.UserID, ctx.Workspace.ID, filePath); err != nil {
http.Error(w, "Invalid file path", http.StatusBadRequest)
return
}
@@ -152,7 +152,7 @@ func (h *Handler) UpdateLastOpenedFile() http.HandlerFunc {
// Validate the file path exists in the workspace
if requestBody.FilePath != "" {
if _, err := h.S.ValidatePath(ctx.UserID, ctx.Workspace.ID, requestBody.FilePath); err != nil {
if _, err := h.Storage.ValidatePath(ctx.UserID, ctx.Workspace.ID, requestBody.FilePath); err != nil {
http.Error(w, "Invalid file path", http.StatusBadRequest)
return
}

View File

@@ -28,7 +28,7 @@ func (h *Handler) StageCommitAndPush() http.HandlerFunc {
return
}
err := h.S.StageCommitAndPush(ctx.UserID, ctx.Workspace.ID, requestBody.Message)
err := h.Storage.StageCommitAndPush(ctx.UserID, ctx.Workspace.ID, requestBody.Message)
if err != nil {
http.Error(w, "Failed to stage, commit, and push changes: "+err.Error(), http.StatusInternalServerError)
return
@@ -45,7 +45,7 @@ func (h *Handler) PullChanges() http.HandlerFunc {
return
}
err := h.S.Pull(ctx.UserID, ctx.Workspace.ID)
err := h.Storage.Pull(ctx.UserID, ctx.Workspace.ID)
if err != nil {
http.Error(w, "Failed to pull changes: "+err.Error(), http.StatusInternalServerError)
return

View File

@@ -4,20 +4,20 @@ import (
"encoding/json"
"net/http"
"novamd/internal/db"
"novamd/internal/filesystem"
"novamd/internal/storage"
)
// Handler provides common functionality for all handlers
type Handler struct {
DB *db.DB
S *filesystem.Storage
DB *db.DB
Storage storage.Manager
}
// NewHandler creates a new handler with the given dependencies
func NewHandler(db *db.DB, fs *filesystem.Storage) *Handler {
func NewHandler(db *db.DB, s storage.Manager) *Handler {
return &Handler{
DB: db,
S: fs,
DB: db,
Storage: s,
}
}

View File

@@ -200,7 +200,7 @@ func (h *Handler) DeleteAccount() http.HandlerFunc {
// Delete workspace directories
for _, workspace := range workspaces {
if err := h.S.DeleteUserWorkspace(ctx.UserID, workspace.ID); err != nil {
if err := h.Storage.DeleteUserWorkspace(ctx.UserID, workspace.ID); err != nil {
http.Error(w, "Failed to delete workspace files", http.StatusInternalServerError)
return
}

View File

@@ -45,7 +45,7 @@ func (h *Handler) CreateWorkspace() http.HandlerFunc {
return
}
if err := h.S.InitializeUserWorkspace(workspace.UserID, workspace.ID); err != nil {
if err := h.Storage.InitializeUserWorkspace(workspace.UserID, workspace.ID); err != nil {
http.Error(w, "Failed to initialize workspace directory", http.StatusInternalServerError)
return
}
@@ -107,7 +107,7 @@ func (h *Handler) UpdateWorkspace() http.HandlerFunc {
// Handle Git repository setup/teardown if Git settings changed
if gitSettingsChanged(&workspace, ctx.Workspace) {
if workspace.GitEnabled {
if err := h.S.SetupGitRepo(
if err := h.Storage.SetupGitRepo(
ctx.UserID,
ctx.Workspace.ID,
workspace.GitURL,
@@ -119,7 +119,7 @@ func (h *Handler) UpdateWorkspace() http.HandlerFunc {
}
} else {
h.S.DisableGitRepo(ctx.UserID, ctx.Workspace.ID)
h.Storage.DisableGitRepo(ctx.UserID, ctx.Workspace.ID)
}
}

View File

@@ -1,6 +1,6 @@
// Package filesystem provides functionalities to interact with the file system,
// Package storage provides functionalities to interact with the file system,
// including listing files, finding files by name, getting file content, saving files, and deleting files.
package filesystem
package storage
import (
"fmt"
@@ -10,12 +10,23 @@ import (
"strings"
)
// StorageNode represents a file or directory in the storage.
type StorageNode struct {
ID string `json:"id"`
Name string `json:"name"`
Path string `json:"path"`
Children []StorageNode `json:"children,omitempty"`
// FileManager provides functionalities to interact with files in the storage.
type FileManager interface {
ListFilesRecursively(userID, workspaceID int) ([]FileNode, error)
FindFileByName(userID, workspaceID int, filename string) ([]string, error)
GetFileContent(userID, workspaceID int, filePath string) ([]byte, error)
SaveFile(userID, workspaceID int, filePath string, content []byte) error
DeleteFile(userID, workspaceID int, filePath string) error
GetFileStats(userID, workspaceID int) (*FileCountStats, error)
GetTotalFileStats() (*FileCountStats, error)
}
// FileNode represents a file or directory in the storage.
type FileNode struct {
ID string `json:"id"`
Name string `json:"name"`
Path string `json:"path"`
Children []FileNode `json:"children,omitempty"`
}
// ListFilesRecursively returns a list of all files in the workspace directory and its subdirectories.
@@ -25,13 +36,13 @@ type StorageNode struct {
// Returns:
// - nodes: a list of files and directories in the workspace
// - error: any error that occurred during listing
func (s *Storage) ListFilesRecursively(userID, workspaceID int) ([]StorageNode, error) {
func (s *Service) ListFilesRecursively(userID, workspaceID int) ([]FileNode, error) {
workspacePath := s.GetWorkspacePath(userID, workspaceID)
return s.walkDirectory(workspacePath, "")
}
// walkDirectory recursively walks the directory and returns a list of files and directories.
func (s *Storage) walkDirectory(dir, prefix string) ([]StorageNode, error) {
func (s *Service) walkDirectory(dir, prefix string) ([]FileNode, error) {
entries, err := s.fs.ReadDir(dir)
if err != nil {
return nil, err
@@ -56,7 +67,7 @@ func (s *Storage) walkDirectory(dir, prefix string) ([]StorageNode, error) {
})
// Create combined slice with directories first, then files
nodes := make([]StorageNode, 0, len(entries))
nodes := make([]FileNode, 0, len(entries))
// Add directories first
for _, entry := range dirs {
@@ -69,7 +80,7 @@ func (s *Storage) walkDirectory(dir, prefix string) ([]StorageNode, error) {
return nil, err
}
node := StorageNode{
node := FileNode{
ID: path,
Name: name,
Path: path,
@@ -83,7 +94,7 @@ func (s *Storage) walkDirectory(dir, prefix string) ([]StorageNode, error) {
name := entry.Name()
path := filepath.Join(prefix, name)
node := StorageNode{
node := FileNode{
ID: path,
Name: name,
Path: path,
@@ -102,7 +113,7 @@ func (s *Storage) walkDirectory(dir, prefix string) ([]StorageNode, error) {
// Returns:
// - foundPaths: a list of file paths that match the filename
// - error: any error that occurred during the search
func (s *Storage) FindFileByName(userID, workspaceID int, filename string) ([]string, error) {
func (s *Service) FindFileByName(userID, workspaceID int, filename string) ([]string, error) {
var foundPaths []string
workspacePath := s.GetWorkspacePath(userID, workspaceID)
@@ -141,7 +152,7 @@ func (s *Storage) FindFileByName(userID, workspaceID int, filename string) ([]st
// Returns:
// - content: the content of the file
// - error: any error that occurred during reading
func (s *Storage) GetFileContent(userID, workspaceID int, filePath string) ([]byte, error) {
func (s *Service) GetFileContent(userID, workspaceID int, filePath string) ([]byte, error) {
fullPath, err := s.ValidatePath(userID, workspaceID, filePath)
if err != nil {
return nil, err
@@ -157,7 +168,7 @@ func (s *Storage) GetFileContent(userID, workspaceID int, filePath string) ([]by
// - content: the content to write to the file
// Returns:
// - error: any error that occurred during saving
func (s *Storage) SaveFile(userID, workspaceID int, filePath string, content []byte) error {
func (s *Service) SaveFile(userID, workspaceID int, filePath string, content []byte) error {
fullPath, err := s.ValidatePath(userID, workspaceID, filePath)
if err != nil {
return err
@@ -178,7 +189,7 @@ func (s *Storage) SaveFile(userID, workspaceID int, filePath string, content []b
// - filePath: the path of the file to delete
// Returns:
// - error: any error that occurred during deletion
func (s *Storage) DeleteFile(userID, workspaceID int, filePath string) error {
func (s *Service) DeleteFile(userID, workspaceID int, filePath string) error {
fullPath, err := s.ValidatePath(userID, workspaceID, filePath)
if err != nil {
return err
@@ -199,7 +210,7 @@ type FileCountStats struct {
// Returns:
// - result: statistics about the files in the workspace
// - error: any error that occurred during counting
func (s *Storage) GetFileStats(userID, workspaceID int) (*FileCountStats, error) {
func (s *Service) GetFileStats(userID, workspaceID int) (*FileCountStats, error) {
workspacePath := s.GetWorkspacePath(userID, workspaceID)
// Check if workspace exists
@@ -214,12 +225,12 @@ func (s *Storage) GetFileStats(userID, workspaceID int) (*FileCountStats, error)
// GetTotalFileStats returns the total file statistics for the storage.
// Returns:
// - result: statistics about the files in the storage
func (s *Storage) GetTotalFileStats() (*FileCountStats, error) {
func (s *Service) GetTotalFileStats() (*FileCountStats, error) {
return s.countFilesInPath(s.RootDir)
}
// countFilesInPath counts the total number of files and the total size of files in the given directory.
func (s *Storage) countFilesInPath(directoryPath string) (*FileCountStats, error) {
func (s *Service) countFilesInPath(directoryPath string) (*FileCountStats, error) {
result := &FileCountStats{}
err := filepath.WalkDir(directoryPath, func(path string, d os.DirEntry, err error) error {

View File

@@ -1,4 +1,4 @@
package filesystem
package storage
import (
"io/fs"

View File

@@ -0,0 +1,46 @@
package storage_test
import (
"io/fs"
"os"
"testing/fstest"
)
// mapFS adapts testing.MapFS to implement our fileSystem interface
type mapFS struct {
fstest.MapFS
}
func NewMapFS() *mapFS {
return &mapFS{
MapFS: make(fstest.MapFS),
}
}
// Only implement the methods that MapFS doesn't already provide
func (m *mapFS) WriteFile(path string, data []byte, perm fs.FileMode) error {
m.MapFS[path] = &fstest.MapFile{
Data: data,
Mode: perm,
}
return nil
}
func (m *mapFS) Remove(path string) error {
delete(m.MapFS, path)
return nil
}
func (m *mapFS) MkdirAll(_ string, _ fs.FileMode) error {
// For MapFS, we don't actually need to create directories
return nil
}
func (m *mapFS) RemoveAll(path string) error {
delete(m.MapFS, path)
return nil
}
func (m *mapFS) IsNotExist(err error) bool {
return os.IsNotExist(err)
}

View File

@@ -1,10 +1,18 @@
package filesystem
package storage
import (
"fmt"
"novamd/internal/gitutils"
)
// RepositoryManager defines the interface for managing Git repositories.
type RepositoryManager interface {
SetupGitRepo(userID, workspaceID int, gitURL, gitUser, gitToken string) error
DisableGitRepo(userID, workspaceID int)
StageCommitAndPush(userID, workspaceID int, message string) error
Pull(userID, workspaceID int) error
}
// SetupGitRepo sets up a Git repository for the given user and workspace IDs.
// Parameters:
// - userID: the ID of the user who owns the workspace
@@ -14,7 +22,7 @@ import (
// - gitToken: the access token for the Git repository
// Returns:
// - error: any error that occurred during setup
func (s *Storage) SetupGitRepo(userID, workspaceID int, gitURL, gitUser, gitToken string) error {
func (s *Service) SetupGitRepo(userID, workspaceID int, gitURL, gitUser, gitToken string) error {
workspacePath := s.GetWorkspacePath(userID, workspaceID)
if _, ok := s.GitRepos[userID]; !ok {
s.GitRepos[userID] = make(map[int]*gitutils.GitRepo)
@@ -27,7 +35,7 @@ func (s *Storage) SetupGitRepo(userID, workspaceID int, gitURL, gitUser, gitToke
// Parameters:
// - userID: the ID of the user who owns the workspace
// - workspaceID: the ID of the workspace to disable the Git repository for
func (s *Storage) DisableGitRepo(userID, workspaceID int) {
func (s *Service) DisableGitRepo(userID, workspaceID int) {
if userRepos, ok := s.GitRepos[userID]; ok {
delete(userRepos, workspaceID)
if len(userRepos) == 0 {
@@ -43,7 +51,7 @@ func (s *Storage) DisableGitRepo(userID, workspaceID int) {
// - message: the commit message
// Returns:
// - error: any error that occurred during the operation
func (s *Storage) StageCommitAndPush(userID, workspaceID int, message string) error {
func (s *Service) StageCommitAndPush(userID, workspaceID int, message string) error {
repo, ok := s.getGitRepo(userID, workspaceID)
if !ok {
return fmt.Errorf("git settings not configured for this workspace")
@@ -62,7 +70,7 @@ func (s *Storage) StageCommitAndPush(userID, workspaceID int, message string) er
// - workspaceID: the ID of the workspace to pull changes for
// Returns:
// - error: any error that occurred during the operation
func (s *Storage) Pull(userID, workspaceID int) error {
func (s *Service) Pull(userID, workspaceID int) error {
repo, ok := s.getGitRepo(userID, workspaceID)
if !ok {
return fmt.Errorf("git settings not configured for this workspace")
@@ -72,7 +80,7 @@ func (s *Storage) Pull(userID, workspaceID int) error {
}
// getGitRepo returns the Git repository for the given user and workspace IDs.
func (s *Storage) getGitRepo(userID, workspaceID int) (*gitutils.GitRepo, bool) {
func (s *Service) getGitRepo(userID, workspaceID int) (*gitutils.GitRepo, bool) {
userRepos, ok := s.GitRepos[userID]
if !ok {
return nil, false

View File

@@ -0,0 +1,42 @@
package storage
import (
"novamd/internal/gitutils"
)
// Manager interface combines all storage interfaces.
type Manager interface {
FileManager
WorkspaceManager
RepositoryManager
}
// Service represents the file system structure.
type Service struct {
fs fileSystem
RootDir string
GitRepos map[int]map[int]*gitutils.GitRepo // map[userID]map[workspaceID]*gitutils.GitRepo
}
// NewService creates a new Storage instance.
// Parameters:
// - rootDir: the root directory for the storage
// Returns:
// - result: the new Storage instance
func NewService(rootDir string) *Service {
return NewServiceWithFS(rootDir, &osFS{})
}
// NewServiceWithFS creates a new Storage instance with the given filesystem.
// Parameters:
// - rootDir: the root directory for the storage
// - fs: the filesystem implementation to use
// Returns:
// - result: the new Storage instance
func NewServiceWithFS(rootDir string, fs fileSystem) *Service {
return &Service{
fs: fs,
RootDir: rootDir,
GitRepos: make(map[int]map[int]*gitutils.GitRepo),
}
}

View File

@@ -1,17 +1,46 @@
package filesystem
package storage
import (
"fmt"
"path/filepath"
"strings"
)
// WorkspaceManager provides functionalities to interact with workspaces in the storage.
type WorkspaceManager interface {
ValidatePath(userID, workspaceID int, path string) (string, error)
GetWorkspacePath(userID, workspaceID int) string
InitializeUserWorkspace(userID, workspaceID int) error
DeleteUserWorkspace(userID, workspaceID int) error
}
// ValidatePath validates the given path and returns the cleaned path if it is valid.
// Parameters:
// - userID: the ID of the user who owns the workspace
// - workspaceID: the ID of the workspace to validate the path for
// - path: the path to validate
// Returns:
// - result: the cleaned path if it is valid
// - error: any error that occurred during validation
func (s *Service) ValidatePath(userID, workspaceID int, path string) (string, error) {
workspacePath := s.GetWorkspacePath(userID, workspaceID)
fullPath := filepath.Join(workspacePath, path)
cleanPath := filepath.Clean(fullPath)
if !strings.HasPrefix(cleanPath, workspacePath) {
return "", fmt.Errorf("invalid path: outside of workspace")
}
return cleanPath, nil
}
// GetWorkspacePath returns the path to the workspace directory for the given user and workspace IDs.
// Parameters:
// - userID: the ID of the user who owns the workspace
// - workspaceID: the ID of the workspace
// Returns:
// - result: the path to the workspace directory
func (s *Storage) GetWorkspacePath(userID, workspaceID int) string {
func (s *Service) GetWorkspacePath(userID, workspaceID int) string {
return filepath.Join(s.RootDir, fmt.Sprintf("%d", userID), fmt.Sprintf("%d", workspaceID))
}
@@ -21,7 +50,7 @@ func (s *Storage) GetWorkspacePath(userID, workspaceID int) string {
// - workspaceID: the ID of the workspace to initialize
// Returns:
// - error: any error that occurred during the operation
func (s *Storage) InitializeUserWorkspace(userID, workspaceID int) error {
func (s *Service) InitializeUserWorkspace(userID, workspaceID int) error {
workspacePath := s.GetWorkspacePath(userID, workspaceID)
err := s.fs.MkdirAll(workspacePath, 0755)
if err != nil {
@@ -37,7 +66,7 @@ func (s *Storage) InitializeUserWorkspace(userID, workspaceID int) error {
// - workspaceID: the ID of the workspace to delete
// Returns:
// - error: any error that occurred during the operation
func (s *Storage) DeleteUserWorkspace(userID, workspaceID int) error {
func (s *Service) DeleteUserWorkspace(userID, workspaceID int) error {
workspacePath := s.GetWorkspacePath(userID, workspaceID)
err := s.fs.RemoveAll(workspacePath)
if err != nil {

View File

@@ -8,19 +8,19 @@ import (
"golang.org/x/crypto/bcrypt"
"novamd/internal/db"
"novamd/internal/filesystem"
"novamd/internal/models"
"novamd/internal/storage"
)
type UserService struct {
DB *db.DB
FS *filesystem.Storage
DB *db.DB
Storage storage.Manager
}
func NewUserService(database *db.DB, fs *filesystem.Storage) *UserService {
func NewUserService(database *db.DB, s storage.Manager) *UserService {
return &UserService{
DB: database,
FS: fs,
DB: database,
Storage: s,
}
}
@@ -53,7 +53,7 @@ func (s *UserService) SetupAdminUser(adminEmail, adminPassword string) (*models.
}
// Initialize workspace directory
err = s.FS.InitializeUserWorkspace(createdUser.ID, createdUser.LastWorkspaceID)
err = s.Storage.InitializeUserWorkspace(createdUser.ID, createdUser.LastWorkspaceID)
if err != nil {
return nil, fmt.Errorf("failed to initialize admin workspace: %w", err)
}