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.

345 lines
9.5 KiB

5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
  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. "fmt"
  8. "time"
  9. "git.aiterp.net/stufflog/server/graph/graphcore"
  10. "git.aiterp.net/stufflog/server/internal/slerrors"
  11. "git.aiterp.net/stufflog/server/models"
  12. )
  13. func (r *mutationResolver) CreateProject(ctx context.Context, input graphcore.ProjectCreateInput) (*models.Project, error) {
  14. user := r.Auth.UserFromContext(ctx)
  15. if user == nil {
  16. return nil, slerrors.PermissionDenied
  17. }
  18. project := &models.Project{
  19. ID: input.ID,
  20. Name: input.Name,
  21. Description: input.Description,
  22. DailyPoints: input.DailyPoints,
  23. }
  24. if !project.ValidKey() {
  25. return nil, errors.New("the project must have a valid ID (only uppercase allowed)")
  26. }
  27. if project.Name == "" || project.Description == "" {
  28. return nil, errors.New("name and description cannot be left empty")
  29. }
  30. project, err := r.Database.Projects().Insert(ctx, *project)
  31. if err != nil {
  32. return nil, err
  33. }
  34. err = r.Database.Projects().SetPermission(ctx, models.ProjectPermission{
  35. ProjectID: project.ID,
  36. UserID: user.ID,
  37. Level: models.ProjectPermissionLevelOwner,
  38. })
  39. return project, nil
  40. }
  41. func (r *mutationResolver) CreateActivity(ctx context.Context, input graphcore.ActivityCreateInput) (*models.Activity, error) {
  42. user := r.Auth.UserFromContext(ctx)
  43. if user == nil {
  44. return nil, slerrors.PermissionDenied
  45. }
  46. project, err := r.Database.Projects().Find(ctx, input.ProjectID)
  47. if err != nil {
  48. return nil, err
  49. }
  50. if perm, err := r.Auth.ProjectPermission(ctx, *project); err != nil || !perm.CanManageActivities() {
  51. return nil, slerrors.PermissionDenied
  52. }
  53. activity := &models.Activity{
  54. ProjectID: project.ID,
  55. Name: input.Name,
  56. Countable: input.Countable != nil && *input.Countable,
  57. UnitIsTimeSpent: input.UnitIsTimeSpent != nil && *input.UnitIsTimeSpent,
  58. BaseValue: input.BaseValue,
  59. }
  60. if !activity.UnitIsTimeSpent && activity.Countable {
  61. if input.UnitName != nil {
  62. activity.UnitName = *input.UnitName
  63. } else {
  64. return nil, errors.New("unit name is required for countable non-time-spent activities")
  65. }
  66. }
  67. if activity.UnitIsTimeSpent || activity.Countable {
  68. if input.UnitValue != nil {
  69. activity.UnitValue = *input.UnitValue
  70. }
  71. }
  72. return r.Database.Activities().Insert(ctx, *activity)
  73. }
  74. func (r *mutationResolver) EditActivity(ctx context.Context, input graphcore.ActivityEditInput) (*models.Activity, error) {
  75. user := r.Auth.UserFromContext(ctx)
  76. if user == nil {
  77. return nil, slerrors.PermissionDenied
  78. }
  79. activity, err := r.Database.Activities().Find(ctx, input.ActivityID)
  80. if err != nil {
  81. return nil, err
  82. }
  83. project, err := r.Database.Projects().Find(ctx, activity.ProjectID)
  84. if err != nil {
  85. return nil, err
  86. }
  87. if perm, err := r.Auth.ProjectPermission(ctx, *project); err != nil || !perm.CanManageActivities() {
  88. return nil, slerrors.PermissionDenied
  89. }
  90. if input.SetName != nil {
  91. activity.Name = *input.SetName
  92. }
  93. if input.SetBaseValue != nil {
  94. activity.BaseValue = *input.SetBaseValue
  95. }
  96. if input.SetUnitName != nil {
  97. activity.UnitName = *input.SetUnitName
  98. }
  99. if input.SetUnitValue != nil {
  100. activity.UnitValue = *input.SetUnitValue
  101. }
  102. err = r.Database.Activities().Save(ctx, *activity)
  103. if err != nil {
  104. return nil, err
  105. }
  106. return activity, nil
  107. }
  108. func (r *mutationResolver) CreateItem(ctx context.Context, input *graphcore.ItemCreateInput) (*models.Item, error) {
  109. user := r.Auth.UserFromContext(ctx)
  110. if user == nil {
  111. return nil, slerrors.PermissionDenied
  112. }
  113. if input.Name == "" {
  114. return nil, errors.New("name cannot be blank")
  115. }
  116. if input.Description == "" {
  117. return nil, errors.New("name cannot be blank")
  118. }
  119. if len(input.Tags) == 0 {
  120. return nil, errors.New("at least one tag is required")
  121. }
  122. if input.Image != nil {
  123. panic("todo: implement image upload")
  124. }
  125. item := models.Item{
  126. Name: input.Name,
  127. Description: input.Description,
  128. Tags: input.Tags,
  129. QuantityUnit: input.QuantityUnit,
  130. ImageURL: nil,
  131. }
  132. return r.Database.Items().Insert(ctx, item)
  133. }
  134. func (r *mutationResolver) EditItem(ctx context.Context, input *graphcore.ItemEditInput) (*models.Item, error) {
  135. panic(fmt.Errorf("not implemented"))
  136. }
  137. func (r *mutationResolver) CreateIssue(ctx context.Context, input graphcore.IssueCreateInput) (*models.Issue, error) {
  138. user := r.Auth.UserFromContext(ctx)
  139. if user == nil {
  140. return nil, slerrors.PermissionDenied
  141. }
  142. project, err := r.Database.Projects().Find(ctx, input.ProjectID)
  143. if err != nil {
  144. return nil, err
  145. }
  146. if perm, err := r.Auth.ProjectPermission(ctx, *project); err != nil || !perm.CanManageOwnIssue() {
  147. return nil, slerrors.PermissionDenied
  148. }
  149. status, err := r.Database.ProjectStatuses().Find(ctx, project.ID, input.StatusName)
  150. if err != nil {
  151. return nil, err
  152. }
  153. issue := &models.Issue{
  154. ProjectID: project.ID,
  155. OwnerID: user.ID,
  156. AssigneeID: "",
  157. StatusStage: status.Stage,
  158. StatusName: status.Name,
  159. Name: input.Name,
  160. Title: input.Name, // Title set below if it's in the input.
  161. Description: input.Description,
  162. }
  163. if input.Title != nil && *input.Title != "" {
  164. issue.Title = *input.Title
  165. }
  166. if input.DueTime != nil && !input.DueTime.IsZero() {
  167. issue.DueTime = *input.DueTime
  168. }
  169. if input.AssigneeID != nil && *input.AssigneeID != "" {
  170. issue.AssigneeID = *input.AssigneeID
  171. }
  172. issue, err = r.Database.Issues().Insert(ctx, *issue)
  173. if err != nil {
  174. return nil, err
  175. }
  176. return issue, nil
  177. }
  178. func (r *mutationResolver) CreateIssueTask(ctx context.Context, input graphcore.IssueTaskCreateInput) (*models.IssueTask, error) {
  179. user := r.Auth.UserFromContext(ctx)
  180. if user == nil {
  181. return nil, slerrors.PermissionDenied
  182. }
  183. issue, err := r.Database.Issues().Find(ctx, input.IssueID)
  184. if err != nil {
  185. return nil, err
  186. }
  187. if perm, err := r.Auth.IssuePermission(ctx, *issue); err != nil || !perm.CanManageOwnIssue() {
  188. return nil, slerrors.PermissionDenied
  189. }
  190. status, err := r.Database.ProjectStatuses().Find(ctx, issue.ProjectID, input.StatusName)
  191. if err != nil {
  192. return nil, err
  193. }
  194. activity, err := r.Database.Activities().Find(ctx, input.ActivityID)
  195. if err != nil {
  196. return nil, err
  197. } else if activity.ProjectID != issue.ProjectID {
  198. return nil, slerrors.NotFound("Activity")
  199. }
  200. issueTask := &models.IssueTask{
  201. IssueID: issue.ID,
  202. ActivityID: activity.ID,
  203. CreatedTime: time.Now(),
  204. UpdatedTime: time.Now(),
  205. StatusStage: status.Stage,
  206. StatusName: status.Name,
  207. Name: input.Name,
  208. Description: input.Description,
  209. PointsMultiplier: 1.0,
  210. }
  211. if input.EstimatedUnits != nil && activity.Countable && !activity.UnitIsTimeSpent {
  212. issueTask.EstimatedUnits = *input.EstimatedUnits
  213. }
  214. if input.PointsMultiplier != nil && *input.PointsMultiplier > 0 {
  215. issueTask.PointsMultiplier = *input.PointsMultiplier
  216. }
  217. issueTask, err = r.Database.IssueTasks().Insert(ctx, *issueTask)
  218. if err != nil {
  219. return nil, err
  220. }
  221. return issueTask, nil
  222. }
  223. func (r *mutationResolver) EditIssueTask(ctx context.Context, input graphcore.IssueTaskEditInput) (*models.IssueTask, error) {
  224. user := r.Auth.UserFromContext(ctx)
  225. if user == nil {
  226. return nil, slerrors.PermissionDenied
  227. }
  228. task, err := r.Database.IssueTasks().Find(ctx, input.IssueTaskID)
  229. if err != nil {
  230. return nil, err
  231. }
  232. issue, err := r.Database.Issues().Find(ctx, task.IssueID)
  233. if err != nil {
  234. return nil, err
  235. }
  236. if perm, err := r.Auth.IssuePermission(ctx, *issue); err != nil || !perm.CanManageOwnIssue() {
  237. return nil, slerrors.PermissionDenied
  238. }
  239. if input.SetName != nil {
  240. task.Name = *input.SetName
  241. }
  242. if input.SetDescription != nil {
  243. task.Description = *input.SetDescription
  244. }
  245. if input.SetDueTime != nil {
  246. task.DueTime = input.SetDueTime
  247. }
  248. if input.SetEstimatedTime != nil {
  249. task.EstimatedTime = *input.SetEstimatedTime
  250. }
  251. if input.SetEstimatedUnits != nil {
  252. activity, err := r.Database.Activities().Find(ctx, task.ActivityID)
  253. if err != nil {
  254. return nil, err
  255. }
  256. if activity.Countable && !activity.UnitIsTimeSpent {
  257. task.EstimatedUnits = *input.SetEstimatedUnits
  258. }
  259. }
  260. if input.SetPointsMultiplier != nil && *input.SetPointsMultiplier > 0 {
  261. task.PointsMultiplier = *input.SetPointsMultiplier
  262. }
  263. if input.SetStatusName != nil {
  264. status, err := r.Database.ProjectStatuses().Find(ctx, issue.ProjectID, *input.SetStatusName)
  265. if err != nil {
  266. return nil, err
  267. }
  268. task.StatusName = status.Name
  269. task.StatusStage = status.Stage
  270. }
  271. err = r.Database.IssueTasks().Save(ctx, *task)
  272. if err != nil {
  273. return nil, err
  274. }
  275. return task, nil
  276. }
  277. func (r *mutationResolver) LoginUser(ctx context.Context, input graphcore.UserLoginInput) (*models.User, error) {
  278. return r.Auth.Login(ctx, input.Username, input.Password)
  279. }
  280. func (r *mutationResolver) LogoutUser(ctx context.Context) (*models.User, error) {
  281. return r.Auth.Logout(ctx)
  282. }
  283. func (r *mutationResolver) CreateUser(ctx context.Context, input graphcore.UserCreateInput) (*models.User, error) {
  284. active := input.Active == nil || *input.Active
  285. admin := input.Admin != nil && *input.Admin
  286. return r.Auth.CreateUser(ctx, input.Username, input.Password, input.Name, active, admin)
  287. }
  288. func (r *mutationResolver) EditUser(ctx context.Context, input graphcore.UserEditInput) (*models.User, error) {
  289. return r.Auth.EditUser(ctx, input.Username, input.SetName, input.CurrentPassword, input.SetPassword)
  290. }
  291. // Mutation returns graphcore.MutationResolver implementation.
  292. func (r *Resolver) Mutation() graphcore.MutationResolver { return &mutationResolver{r} }
  293. type mutationResolver struct{ *Resolver }