first commit
This commit is contained in:
@@ -0,0 +1,508 @@
|
||||
package services
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/AchievementNetwork/stringset"
|
||||
"github.com/gissleh/stufflog/database"
|
||||
"github.com/gissleh/stufflog/internal/auth"
|
||||
"github.com/gissleh/stufflog/internal/slerrors"
|
||||
"github.com/gissleh/stufflog/models"
|
||||
"golang.org/x/sync/errgroup"
|
||||
)
|
||||
|
||||
// Loader loads the stuff.
|
||||
type Loader struct {
|
||||
DB database.Database
|
||||
}
|
||||
|
||||
func (l *Loader) FindGroup(ctx context.Context, id string) (*models.GroupResult, error) {
|
||||
group, err := l.DB.Groups().Find(ctx, id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if group.UserID != auth.UserID(ctx) {
|
||||
return nil, slerrors.NotFound("Goal")
|
||||
}
|
||||
|
||||
result := &models.GroupResult{Group: *group}
|
||||
result.Items, err = l.DB.Items().List(ctx, models.ItemFilter{
|
||||
UserID: auth.UserID(ctx),
|
||||
GroupIDs: []string{group.ID},
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func (l *Loader) ListGroups(ctx context.Context, filter models.GroupFilter) ([]*models.GroupResult, error) {
|
||||
filter.UserID = auth.UserID(ctx)
|
||||
groups, err := l.DB.Groups().List(ctx, filter)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
groupIDs := make([]string, 0, len(groups))
|
||||
for _, group := range groups {
|
||||
groupIDs = append(groupIDs, group.ID)
|
||||
}
|
||||
items, err := l.DB.Items().List(ctx, models.ItemFilter{
|
||||
UserID: auth.UserID(ctx),
|
||||
GroupIDs: groupIDs,
|
||||
})
|
||||
|
||||
results := make([]*models.GroupResult, len(groups))
|
||||
for i, group := range groups {
|
||||
results[i] = &models.GroupResult{Group: *group, Items: []*models.Item{}}
|
||||
for _, item := range items {
|
||||
if item.GroupID == group.ID {
|
||||
results[i].Items = append(results[i].Items, item)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return results, nil
|
||||
}
|
||||
|
||||
func (l *Loader) FindItem(ctx context.Context, id string) (*models.ItemResult, error) {
|
||||
item, err := l.DB.Items().Find(ctx, id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if item.UserID != auth.UserID(ctx) {
|
||||
return nil, slerrors.NotFound("Item")
|
||||
}
|
||||
|
||||
result := &models.ItemResult{Item: *item}
|
||||
result.Group, err = l.DB.Groups().Find(ctx, item.GroupID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func (l *Loader) ListItems(ctx context.Context, filter models.ItemFilter) ([]*models.ItemResult, error) {
|
||||
filter.UserID = auth.UserID(ctx)
|
||||
items, err := l.DB.Items().List(ctx, filter)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
groupIDs := make([]string, 0, len(items))
|
||||
for _, item := range items {
|
||||
groupIDs = append(groupIDs, item.GroupID)
|
||||
}
|
||||
groups, err := l.DB.Groups().List(ctx, models.GroupFilter{
|
||||
UserID: auth.UserID(ctx),
|
||||
IDs: groupIDs,
|
||||
})
|
||||
|
||||
results := make([]*models.ItemResult, len(items))
|
||||
for i, item := range items {
|
||||
results[i] = &models.ItemResult{Item: *item}
|
||||
for _, group := range groups {
|
||||
if item.GroupID == group.ID {
|
||||
results[i].Group = group
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return results, nil
|
||||
}
|
||||
|
||||
func (l *Loader) FindLog(ctx context.Context, id string) (*models.LogResult, error) {
|
||||
log, err := l.DB.Logs().Find(ctx, id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if log.UserID != auth.UserID(ctx) {
|
||||
return nil, slerrors.NotFound("Goal")
|
||||
}
|
||||
result := &models.LogResult{
|
||||
Log: *log,
|
||||
Task: nil,
|
||||
}
|
||||
|
||||
result.Task, _ = l.DB.Tasks().Find(ctx, id)
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func (l *Loader) ListLogs(ctx context.Context, filter models.LogFilter) ([]*models.LogResult, error) {
|
||||
filter.UserID = auth.UserID(ctx)
|
||||
logs, err := l.DB.Logs().List(ctx, filter)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
taskIDs := stringset.New()
|
||||
for _, log := range logs {
|
||||
taskIDs.Add(log.TaskID)
|
||||
}
|
||||
tasks, err := l.DB.Tasks().List(ctx, models.TaskFilter{
|
||||
UserID: auth.UserID(ctx),
|
||||
IDs: taskIDs.Strings(),
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
results := make([]*models.LogResult, len(logs))
|
||||
for i, log := range logs {
|
||||
results[i] = &models.LogResult{
|
||||
Log: *log,
|
||||
Task: nil,
|
||||
}
|
||||
|
||||
for _, task := range tasks {
|
||||
if task.ID == log.TaskID {
|
||||
results[i].Task = task
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return results, nil
|
||||
}
|
||||
|
||||
func (l *Loader) FindProject(ctx context.Context, id string) (*models.ProjectResult, error) {
|
||||
project, err := l.DB.Projects().Find(ctx, id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if project.UserID != auth.UserID(ctx) {
|
||||
return nil, slerrors.NotFound("Goal")
|
||||
}
|
||||
result := &models.ProjectResult{Project: *project}
|
||||
|
||||
tasks, err := l.DB.Tasks().List(ctx, models.TaskFilter{
|
||||
UserID: auth.UserID(ctx),
|
||||
ProjectIDs: []string{project.ID},
|
||||
})
|
||||
taskIDs := make([]string, 0, len(tasks))
|
||||
itemIDs := stringset.New()
|
||||
for _, task := range tasks {
|
||||
taskIDs = append(taskIDs, task.ID)
|
||||
itemIDs.Add(task.ItemID)
|
||||
}
|
||||
|
||||
logs, err := l.DB.Logs().List(ctx, models.LogFilter{
|
||||
UserID: auth.UserID(ctx),
|
||||
IDs: taskIDs,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
items, err := l.DB.Items().List(ctx, models.ItemFilter{
|
||||
UserID: auth.UserID(ctx),
|
||||
IDs: itemIDs.Strings(),
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
result.Tasks = make([]*models.TaskResult, len(tasks))
|
||||
for i, task := range tasks {
|
||||
result.Tasks[i] = &models.TaskResult{
|
||||
Logs: []*models.Log{},
|
||||
}
|
||||
result.Tasks[i].Task = *task
|
||||
for _, log := range logs {
|
||||
if log.TaskID == task.ID {
|
||||
result.Tasks[i].Logs = append(result.Tasks[i].Logs, log)
|
||||
}
|
||||
}
|
||||
for _, item := range items {
|
||||
if item.ID == task.ItemID {
|
||||
result.Tasks[i].Item = item
|
||||
break
|
||||
}
|
||||
}
|
||||
result.Tasks[i].CompletedAmount = len(result.Tasks[i].Logs)
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func (l *Loader) ListProjects(ctx context.Context, filter models.ProjectFilter) ([]*models.ProjectResult, error) {
|
||||
filter.UserID = auth.UserID(ctx)
|
||||
projects, err := l.DB.Projects().List(ctx, filter)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
projectIDs := make([]string, 0, len(projects))
|
||||
for _, project := range projects {
|
||||
projectIDs = append(projectIDs, project.ID)
|
||||
}
|
||||
|
||||
tasks, err := l.DB.Tasks().List(ctx, models.TaskFilter{
|
||||
UserID: auth.UserID(ctx),
|
||||
ProjectIDs: projectIDs,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
taskIDs := make([]string, 0, len(tasks))
|
||||
itemIDs := stringset.New()
|
||||
for _, task := range tasks {
|
||||
taskIDs = append(taskIDs, task.ID)
|
||||
itemIDs.Add(task.ItemID)
|
||||
}
|
||||
|
||||
logs, err := l.DB.Logs().List(ctx, models.LogFilter{
|
||||
UserID: auth.UserID(ctx),
|
||||
IDs: taskIDs,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
items, err := l.DB.Items().List(ctx, models.ItemFilter{
|
||||
UserID: auth.UserID(ctx),
|
||||
IDs: itemIDs.Strings(),
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
results := make([]*models.ProjectResult, len(projects))
|
||||
for i, project := range projects {
|
||||
results[i] = &models.ProjectResult{Project: *project}
|
||||
results[i].Tasks = make([]*models.TaskResult, 0, 16)
|
||||
for _, task := range tasks {
|
||||
if task.ProjectID != project.ID {
|
||||
continue
|
||||
}
|
||||
|
||||
taskResult := &models.TaskResult{
|
||||
Task: *task,
|
||||
Logs: []*models.Log{},
|
||||
}
|
||||
for _, log := range logs {
|
||||
if log.TaskID == task.ID {
|
||||
taskResult.Logs = append(taskResult.Logs, log)
|
||||
}
|
||||
}
|
||||
for _, item := range items {
|
||||
if item.ID == task.ItemID {
|
||||
taskResult.Item = item
|
||||
break
|
||||
}
|
||||
}
|
||||
taskResult.CompletedAmount = len(taskResult.Logs)
|
||||
|
||||
results[i].Tasks = append(results[i].Tasks, taskResult)
|
||||
}
|
||||
}
|
||||
|
||||
return results, nil
|
||||
}
|
||||
|
||||
func (l *Loader) FindTask(ctx context.Context, id string) (*models.TaskResult, error) {
|
||||
task, err := l.DB.Tasks().Find(ctx, id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if task.UserID != auth.UserID(ctx) {
|
||||
return nil, slerrors.NotFound("Goal")
|
||||
}
|
||||
result := &models.TaskResult{Task: *task}
|
||||
|
||||
result.Item, _ = l.DB.Items().Find(ctx, task.ItemID)
|
||||
result.Logs, err = l.DB.Logs().List(ctx, models.LogFilter{
|
||||
UserID: task.UserID,
|
||||
IDs: []string{task.ID},
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
result.CompletedAmount = len(result.Logs)
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func (l *Loader) ListTasks(ctx context.Context, filter models.TaskFilter) ([]*models.TaskResult, error) {
|
||||
filter.UserID = auth.UserID(ctx)
|
||||
tasks, err := l.DB.Tasks().List(ctx, filter)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if len(tasks) == 0 {
|
||||
return []*models.TaskResult{}, nil
|
||||
}
|
||||
|
||||
taskIDs := make([]string, 0, len(tasks))
|
||||
itemIDs := stringset.New()
|
||||
for _, task := range tasks {
|
||||
taskIDs = append(taskIDs, task.ID)
|
||||
itemIDs.Add(task.ItemID)
|
||||
}
|
||||
|
||||
logs, err := l.DB.Logs().List(ctx, models.LogFilter{
|
||||
UserID: auth.UserID(ctx),
|
||||
IDs: taskIDs,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
items, err := l.DB.Items().List(ctx, models.ItemFilter{
|
||||
UserID: auth.UserID(ctx),
|
||||
IDs: itemIDs.Strings(),
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
results := make([]*models.TaskResult, 0, len(tasks))
|
||||
for _, task := range tasks {
|
||||
result := &models.TaskResult{
|
||||
Task: *task,
|
||||
Logs: []*models.Log{},
|
||||
}
|
||||
|
||||
for _, log := range logs {
|
||||
if log.TaskID != task.ID {
|
||||
result.Logs = append(result.Logs, log)
|
||||
}
|
||||
}
|
||||
|
||||
for _, item := range items {
|
||||
if item.ID == task.ItemID {
|
||||
result.Item = item
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
result.CompletedAmount = len(result.Logs)
|
||||
|
||||
results = append(results, result)
|
||||
}
|
||||
|
||||
return results, nil
|
||||
}
|
||||
|
||||
func (l *Loader) FindGoal(ctx context.Context, id string) (*models.GoalResult, error) {
|
||||
goal, err := l.DB.Goals().Find(ctx, id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if goal.UserID != auth.UserID(ctx) {
|
||||
return nil, slerrors.NotFound("Goal")
|
||||
}
|
||||
|
||||
return l.populateGoals(ctx, goal)
|
||||
}
|
||||
|
||||
func (l *Loader) ListGoals(ctx context.Context, filter models.GoalFilter) ([]*models.GoalResult, error) {
|
||||
filter.UserID = auth.UserID(ctx)
|
||||
|
||||
goals, err := l.DB.Goals().List(ctx, filter)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
results := make([]*models.GoalResult, len(goals))
|
||||
eg := errgroup.Group{}
|
||||
for i := range results {
|
||||
index := i // Required to avoid race condition.
|
||||
|
||||
eg.Go(func() error {
|
||||
res, err := l.populateGoals(ctx, goals[index])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
results[index] = res
|
||||
|
||||
return nil
|
||||
})
|
||||
}
|
||||
err = eg.Wait()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return results, nil
|
||||
}
|
||||
|
||||
func (l *Loader) populateGoals(ctx context.Context, goal *models.Goal) (*models.GoalResult, error) {
|
||||
userID := auth.UserID(ctx)
|
||||
result := &models.GoalResult{
|
||||
Goal: *goal,
|
||||
Group: nil,
|
||||
Items: nil,
|
||||
Logs: nil,
|
||||
CompletedAmount: 0,
|
||||
}
|
||||
|
||||
result.Group, _ = l.DB.Groups().Find(ctx, goal.GroupID)
|
||||
if result.Group != nil {
|
||||
// Get items
|
||||
items, err := l.DB.Items().List(ctx, models.ItemFilter{
|
||||
UserID: userID,
|
||||
GroupIDs: []string{goal.GroupID},
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
itemIDs := make([]string, 0, len(items))
|
||||
for _, item := range items {
|
||||
result.Items = append(result.Items, &models.GoalResultItem{
|
||||
Item: *item,
|
||||
CompletedAmount: 0,
|
||||
})
|
||||
|
||||
itemIDs = append(itemIDs, item.ID)
|
||||
}
|
||||
|
||||
// Get logs
|
||||
logs, err := l.DB.Logs().List(ctx, models.LogFilter{
|
||||
UserID: userID,
|
||||
ItemIDs: itemIDs,
|
||||
MinTime: &goal.StartTime,
|
||||
MaxTime: &goal.EndTime,
|
||||
})
|
||||
|
||||
// Get tasks
|
||||
taskIDs := make([]string, 0, len(result.Logs))
|
||||
for _, log := range logs {
|
||||
taskIDs = append(taskIDs, log.TaskID)
|
||||
}
|
||||
tasks, err := l.DB.Tasks().List(ctx, models.TaskFilter{
|
||||
UserID: userID,
|
||||
IDs: taskIDs,
|
||||
})
|
||||
|
||||
// Apply logs
|
||||
result.Logs = make([]*models.LogResult, 0, len(logs))
|
||||
for _, log := range logs {
|
||||
resultLog := &models.LogResult{
|
||||
Log: *log,
|
||||
}
|
||||
|
||||
for _, task := range tasks {
|
||||
if task.ID == log.TaskID {
|
||||
resultLog.Task = task
|
||||
|
||||
for _, item := range result.Items {
|
||||
if task.ItemID == item.ID {
|
||||
item.CompletedAmount += 1
|
||||
result.CompletedAmount += item.GroupWeight
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
break
|
||||
}
|
||||
}
|
||||
result.Logs = append(result.Logs, resultLog)
|
||||
}
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
Reference in New Issue
Block a user