stufflog graphql server
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

126 lines
3.6 KiB

  1. package resolvers
  2. // This file will be automatically regenerated based on the schema, any resolver implementations
  3. // will be copied through when generating and any unknown code will be moved to the end.
  4. import (
  5. "context"
  6. "errors"
  7. "strings"
  8. "time"
  9. "git.aiterp.net/stufflog/server/graph/graphcore"
  10. "git.aiterp.net/stufflog/server/graph/graphutil"
  11. "git.aiterp.net/stufflog/server/graph/loaders"
  12. "git.aiterp.net/stufflog/server/internal/slerrors"
  13. "git.aiterp.net/stufflog/server/models"
  14. )
  15. func (r *issueTaskResolver) EstimatedUnits(ctx context.Context, obj *models.IssueTask) (*int, error) {
  16. // TODO: Data loader
  17. activity, err := loaders.ActivityLoaderFromContext(ctx).Load(obj.ActivityID)
  18. if err != nil {
  19. return nil, err
  20. }
  21. if !activity.Countable || activity.UnitIsTimeSpent {
  22. return nil, nil
  23. }
  24. return &obj.EstimatedUnits, nil
  25. }
  26. func (r *issueTaskResolver) Issue(ctx context.Context, obj *models.IssueTask) (*models.Issue, error) {
  27. return loaders.IssueLoaderFromContext(ctx).Load(obj.IssueID)
  28. }
  29. func (r *issueTaskResolver) Activity(ctx context.Context, obj *models.IssueTask) (*models.Activity, error) {
  30. return loaders.ActivityLoaderFromContext(ctx).Load(obj.ActivityID)
  31. }
  32. func (r *issueTaskResolver) Status(ctx context.Context, obj *models.IssueTask) (*models.ProjectStatus, error) {
  33. // The project ID is always the prefix before the first dash in the issue ID.
  34. split := strings.SplitN(obj.IssueID, "-", 2)
  35. if len(split) == 0 {
  36. return nil, errors.New("invalid issue ID")
  37. }
  38. projectID := split[0]
  39. // Shortcut: if description isn't needed, resolve this with issue's properties.
  40. if !graphutil.SelectsAnyField(ctx, "description") {
  41. return &models.ProjectStatus{
  42. ProjectID: projectID,
  43. Stage: obj.StatusStage,
  44. Name: obj.StatusName,
  45. Description: "FAKE",
  46. }, nil
  47. }
  48. // Find it in the database. TODO: DataLoader
  49. status, err := r.Database.ProjectStatuses().Find(ctx, projectID, obj.StatusName)
  50. if slerrors.IsNotFound(err) {
  51. return &models.ProjectStatus{
  52. ProjectID: projectID,
  53. Stage: obj.StatusStage,
  54. Name: obj.StatusName,
  55. Description: "(Deleted or unknown status)",
  56. }, nil
  57. } else if err != nil {
  58. return nil, err
  59. }
  60. // If the stage doesn't match, sneakily correct it for next time.
  61. if status.Stage != obj.StatusStage {
  62. updatedTask := *obj
  63. updatedTask.StatusStage = status.Stage
  64. _ = r.Database.IssueTasks().Save(ctx, updatedTask)
  65. }
  66. return status, nil
  67. }
  68. func (r *issueTaskResolver) RemainingTime(ctx context.Context, obj *models.IssueTask) (time.Duration, error) {
  69. loader := loaders.LogsByIssueLoaderFromContext(ctx)
  70. logs, err := loader.Load(obj.IssueID)
  71. if err != nil {
  72. return 0, err
  73. }
  74. remaining := obj.EstimatedTime
  75. for _, log := range logs {
  76. if task := log.Task(obj.ID); task != nil {
  77. remaining -= task.Duration
  78. }
  79. }
  80. return remaining, nil
  81. }
  82. func (r *issueTaskResolver) RemainingUnits(ctx context.Context, obj *models.IssueTask) (*int, error) {
  83. activity, err := loaders.ActivityLoaderFromContext(ctx).Load(obj.ActivityID)
  84. if err != nil {
  85. return nil, err
  86. }
  87. if !activity.Countable || activity.UnitIsTimeSpent {
  88. return nil, nil
  89. }
  90. loader := loaders.LogsByIssueLoaderFromContext(ctx)
  91. logs, err := loader.Load(obj.IssueID)
  92. if err != nil {
  93. return nil, err
  94. }
  95. remaining := obj.EstimatedUnits
  96. for _, log := range logs {
  97. if task := log.Task(obj.ID); task != nil && task.Units != nil {
  98. remaining -= *task.Units
  99. }
  100. }
  101. return &remaining, nil
  102. }
  103. // IssueTask returns graphcore.IssueTaskResolver implementation.
  104. func (r *Resolver) IssueTask() graphcore.IssueTaskResolver { return &issueTaskResolver{r} }
  105. type issueTaskResolver struct{ *Resolver }