142 lines
3.1 KiB
Go
142 lines
3.1 KiB
Go
package lib
|
|
|
|
import (
|
|
"encoding/json"
|
|
"os"
|
|
"path/filepath"
|
|
)
|
|
|
|
// Project entity. In addition to the JSON properties as defined by the specification, it holds activities of the
|
|
// project organized by title and by ID in a map.
|
|
type Project struct {
|
|
ID string `json:"id"`
|
|
Title string `json:"title"`
|
|
activitiesByTitle map[string]*Activity
|
|
activitiesByID map[string]*Activity
|
|
activitiesLoaded bool
|
|
}
|
|
|
|
// NewProject creates a new project instance.
|
|
func NewProject() *Project {
|
|
return &Project{
|
|
activitiesByID: make(map[string]*Activity),
|
|
activitiesByTitle: make(map[string]*Activity),
|
|
}
|
|
}
|
|
|
|
// GetProjects retrieves all stored project instances. It does not load related data like activities or times.
|
|
func GetProjects() ([]*Project, error) {
|
|
folder, folderErr := getProjectFolder()
|
|
if folderErr != nil {
|
|
return nil, folderErr
|
|
}
|
|
|
|
dirErr := os.MkdirAll(folder, 0o750)
|
|
if dirErr != nil {
|
|
return nil, dirErr
|
|
}
|
|
|
|
files, filesErr := os.ReadDir(folder)
|
|
if filesErr != nil {
|
|
return nil, filesErr
|
|
}
|
|
|
|
projects := []*Project{}
|
|
for _, file := range files {
|
|
project, fileErr := readProject(filepath.Join(folder, file.Name()))
|
|
if fileErr != nil {
|
|
return nil, fileErr
|
|
}
|
|
projects = append(projects, project)
|
|
}
|
|
|
|
return projects, nil
|
|
}
|
|
|
|
// GetProject retrieves a single project by its ID. It does not load related data like activities or times.
|
|
func GetProject(id string) (*Project, error) {
|
|
file, fileErr := getProjectFile(id)
|
|
if fileErr != nil {
|
|
return nil, fileErr
|
|
}
|
|
project, err := readProject(file)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
project.ID = id
|
|
|
|
return project, nil
|
|
}
|
|
|
|
// SetProject persists a project.
|
|
func SetProject(project *Project) error {
|
|
uuid, uuidErr := newUUID()
|
|
if uuidErr != nil {
|
|
return uuidErr
|
|
}
|
|
|
|
project.ID = uuid
|
|
|
|
file, fileErr := getProjectFile(uuid)
|
|
if fileErr != nil {
|
|
return fileErr
|
|
}
|
|
|
|
return writeProject(file, project)
|
|
}
|
|
|
|
// readProject reads a project from a file and converts it into an entity instance.
|
|
func readProject(filename string) (*Project, error) {
|
|
file, err := os.Open(filename)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
defer file.Close()
|
|
|
|
project := NewProject()
|
|
if err := json.NewDecoder(file).Decode(&project); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return project, nil
|
|
}
|
|
|
|
// writeProject writes a project instance to a file.
|
|
func writeProject(filename string, project *Project) error {
|
|
dirErr := os.MkdirAll(filepath.Dir(filename), 0o750)
|
|
if dirErr != nil {
|
|
return dirErr
|
|
}
|
|
|
|
file, fileErr := os.Create(filename)
|
|
if fileErr != nil {
|
|
return fileErr
|
|
}
|
|
defer file.Close()
|
|
|
|
encoder := json.NewEncoder(file)
|
|
encoder.SetIndent("", " ")
|
|
|
|
jsonErr := encoder.Encode(project)
|
|
if jsonErr != nil {
|
|
return jsonErr
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// getProjectFolder returns the folder to store project entity files in.
|
|
func getProjectFolder() (string, error) {
|
|
return getDataDir("projects")
|
|
}
|
|
|
|
// getProjectFile returns the file name for a project entity instance.
|
|
func getProjectFile(name string) (string, error) {
|
|
folder, err := getProjectFolder()
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
|
|
return filepath.Join(folder, name+".json"), nil
|
|
}
|