package models
import (
"errors"
"path/filepath"
"strings"
"theskyscape.com/repo/skykit"
)
type File struct {
skykit.Model
OwnerID string
Path string // e.g., "main.go" or "projects/myapp/main.go"
Content string
Language string
}
func (f *File) GetModel() *skykit.Model {
return &f.Model
}
// NormalizePath cleans the path
func NormalizePath(path string) string {
p := strings.TrimSpace(path)
p = strings.TrimPrefix(p, "/")
p = filepath.Clean(p)
if p == "." {
return ""
}
return p
}
// DetectLanguage from file extension
func DetectLanguage(path string) string {
ext := strings.ToLower(filepath.Ext(path))
switch ext {
case ".go":
return "go"
case ".js":
return "javascript"
case ".ts":
return "typescript"
case ".py":
return "python"
case ".json":
return "json"
case ".html":
return "html"
case ".css":
return "css"
case ".md":
return "markdown"
case ".yaml", ".yml":
return "yaml"
case ".sh":
return "shell"
case ".sql":
return "sql"
case ".xml":
return "xml"
case ".rs":
return "rust"
case ".rb":
return "ruby"
case ".php":
return "php"
case ".java":
return "java"
case ".c", ".h":
return "c"
case ".cpp", ".hpp", ".cc":
return "cpp"
default:
return "plaintext"
}
}
// GetFile retrieves a file for a user
func GetFile(ownerID, path string) (*File, error) {
path = NormalizePath(path)
if path == "" {
return nil, errors.New("path required")
}
return Files.First("WHERE OwnerID = ? AND Path = ?", ownerID, path)
}
// SaveFile creates or updates a file
func SaveFile(ownerID, path, content string) (*File, error) {
path = NormalizePath(path)
if path == "" {
return nil, errors.New("path required")
}
existing, err := GetFile(ownerID, path)
if err == nil && existing != nil {
// Update existing
existing.Content = content
existing.Language = DetectLanguage(path)
return existing, Files.Update(existing)
}
// Create new
file := Files.New()
file.OwnerID = ownerID
file.Path = path
file.Content = content
file.Language = DetectLanguage(path)
return Files.Insert(file)
}
// ListFiles returns all files for a user
func ListFiles(ownerID string) []*File {
files, _ := Files.Search("WHERE OwnerID = ? ORDER BY Path ASC", ownerID)
return files
}
// DeleteFile removes a file
func DeleteFile(ownerID, path string) error {
path = NormalizePath(path)
file, err := GetFile(ownerID, path)
if err != nil {
return err
}
return Files.Delete(file)
}
// RenameFile renames a file
func RenameFile(ownerID, oldPath, newPath string) error {
oldPath = NormalizePath(oldPath)
newPath = NormalizePath(newPath)
if newPath == "" {
return errors.New("new path required")
}
file, err := GetFile(ownerID, oldPath)
if err != nil {
return err
}
// Check if new path already exists
if existing, _ := GetFile(ownerID, newPath); existing != nil {
return errors.New("file already exists at new path")
}
file.Path = newPath
file.Language = DetectLanguage(newPath)
return Files.Update(file)
}