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.

526 lines
14 KiB

4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 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. "time"
  8. "git.aiterp.net/stufflog/server/graph/graphcore"
  9. "git.aiterp.net/stufflog/server/graph/loaders"
  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.ID); 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.ID); 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) CreateIssue(ctx context.Context, input graphcore.IssueCreateInput) (*models.Issue, error) {
  109. user := r.Auth.UserFromContext(ctx)
  110. if user == nil {
  111. return nil, slerrors.PermissionDenied
  112. }
  113. project, err := r.Database.Projects().Find(ctx, input.ProjectID)
  114. if err != nil {
  115. return nil, err
  116. }
  117. if perm, err := r.Auth.ProjectPermission(ctx, project.ID); err != nil || !perm.CanManageOwnIssue() {
  118. return nil, slerrors.PermissionDenied
  119. }
  120. status, err := r.Database.ProjectStatuses().Find(ctx, project.ID, input.StatusName)
  121. if err != nil {
  122. return nil, err
  123. }
  124. issue := &models.Issue{
  125. ProjectID: project.ID,
  126. OwnerID: user.ID,
  127. AssigneeID: "",
  128. StatusStage: status.Stage,
  129. StatusName: status.Name,
  130. Name: input.Name,
  131. Title: input.Name, // Title set below if it's in the input.
  132. Description: input.Description,
  133. }
  134. if input.Title != nil && *input.Title != "" {
  135. issue.Title = *input.Title
  136. }
  137. if input.DueTime != nil && !input.DueTime.IsZero() {
  138. issue.DueTime = *input.DueTime
  139. }
  140. if input.AssigneeID != nil && *input.AssigneeID != "" {
  141. issue.AssigneeID = *input.AssigneeID
  142. }
  143. issue, err = r.Database.Issues().Insert(ctx, *issue)
  144. if err != nil {
  145. return nil, err
  146. }
  147. loaders.IssueLoaderFromContext(ctx).Prime(issue.ID, issue)
  148. return issue, nil
  149. }
  150. func (r *mutationResolver) EditIssue(ctx context.Context, input graphcore.IssueEditInput) (*models.Issue, error) {
  151. user := r.Auth.UserFromContext(ctx)
  152. if user == nil {
  153. return nil, slerrors.PermissionDenied
  154. }
  155. issue, err := loaders.IssueLoaderFromContext(ctx).Load(input.IssueID)
  156. if err != nil {
  157. return nil, err
  158. }
  159. if perm, err := r.Auth.IssuePermission(ctx, *issue); err != nil || !perm.CanManageOwnIssue() {
  160. return nil, slerrors.PermissionDenied
  161. }
  162. if input.SetAssignee != nil {
  163. if *input.SetAssignee != "" {
  164. assignee, err := loaders.UserLoaderFromContext(ctx).Load(*input.SetAssignee)
  165. if err != nil {
  166. return nil, err
  167. }
  168. if perm, err := r.Auth.IssuePermission(ctx, *issue); err != nil || !perm.CanManageOwnIssue() {
  169. return nil, slerrors.Forbidden("Cannot assign to user who cannot manage their own issues.")
  170. }
  171. issue.AssigneeID = assignee.ID
  172. } else {
  173. issue.AssigneeID = ""
  174. }
  175. }
  176. if input.SetName != nil {
  177. issue.Name = *input.SetName
  178. }
  179. if input.SetTitle != nil {
  180. issue.Name = *input.SetTitle
  181. }
  182. if input.SetDueTime != nil {
  183. issue.DueTime = *input.SetDueTime
  184. }
  185. if input.SetStatusName != nil {
  186. status, err := r.Database.ProjectStatuses().Find(ctx, issue.ProjectID, *input.SetStatusName)
  187. if err != nil {
  188. return nil, err
  189. }
  190. issue.StatusName = status.Name
  191. issue.StatusStage = status.Stage
  192. }
  193. err = r.Database.Issues().Save(ctx, *issue)
  194. if err != nil {
  195. return nil, err
  196. }
  197. return issue, nil
  198. }
  199. func (r *mutationResolver) CreateIssueTask(ctx context.Context, input graphcore.IssueTaskCreateInput) (*models.IssueTask, error) {
  200. user := r.Auth.UserFromContext(ctx)
  201. if user == nil {
  202. return nil, slerrors.PermissionDenied
  203. }
  204. issue, err := loaders.IssueLoaderFromContext(ctx).Load(input.IssueID)
  205. if err != nil {
  206. return nil, err
  207. }
  208. if perm, err := r.Auth.IssuePermission(ctx, *issue); err != nil || !perm.CanManageOwnIssue() {
  209. return nil, slerrors.PermissionDenied
  210. }
  211. status, err := r.Database.ProjectStatuses().Find(ctx, issue.ProjectID, input.StatusName)
  212. if err != nil {
  213. return nil, err
  214. }
  215. activity, err := loaders.ActivityLoaderFromContext(ctx).Load(input.ActivityID)
  216. if err != nil {
  217. return nil, err
  218. } else if activity.ProjectID != issue.ProjectID {
  219. return nil, slerrors.NotFound("Activity")
  220. }
  221. issueTask := &models.IssueTask{
  222. IssueID: issue.ID,
  223. ActivityID: activity.ID,
  224. CreatedTime: time.Now(),
  225. UpdatedTime: time.Now(),
  226. StatusStage: status.Stage,
  227. StatusName: status.Name,
  228. Name: input.Name,
  229. Description: input.Description,
  230. EstimatedTime: input.EstimatedTime,
  231. PointsMultiplier: 1.0,
  232. }
  233. if input.EstimatedUnits != nil && activity.Countable && !activity.UnitIsTimeSpent {
  234. issueTask.EstimatedUnits = *input.EstimatedUnits
  235. }
  236. if input.PointsMultiplier != nil && *input.PointsMultiplier > 0 {
  237. issueTask.PointsMultiplier = *input.PointsMultiplier
  238. }
  239. issueTask, err = r.Database.IssueTasks().Insert(ctx, *issueTask)
  240. if err != nil {
  241. return nil, err
  242. }
  243. return issueTask, nil
  244. }
  245. func (r *mutationResolver) EditIssueTask(ctx context.Context, input graphcore.IssueTaskEditInput) (*models.IssueTask, error) {
  246. user := r.Auth.UserFromContext(ctx)
  247. if user == nil {
  248. return nil, slerrors.PermissionDenied
  249. }
  250. task, err := r.Database.IssueTasks().Find(ctx, input.IssueTaskID)
  251. if err != nil {
  252. return nil, err
  253. }
  254. issue, err := loaders.IssueLoaderFromContext(ctx).Load(task.IssueID)
  255. if err != nil {
  256. return nil, err
  257. }
  258. if perm, err := r.Auth.IssuePermission(ctx, *issue); err != nil || !perm.CanManageOwnIssue() {
  259. return nil, slerrors.PermissionDenied
  260. }
  261. if input.SetName != nil {
  262. task.Name = *input.SetName
  263. }
  264. if input.SetDescription != nil {
  265. task.Description = *input.SetDescription
  266. }
  267. if input.SetDueTime != nil {
  268. task.DueTime = input.SetDueTime
  269. }
  270. if input.SetEstimatedTime != nil {
  271. task.EstimatedTime = *input.SetEstimatedTime
  272. }
  273. if input.SetEstimatedUnits != nil {
  274. activity, err := loaders.ActivityLoaderFromContext(ctx).Load(task.ActivityID)
  275. if err != nil {
  276. return nil, err
  277. }
  278. if activity.Countable && !activity.UnitIsTimeSpent {
  279. task.EstimatedUnits = *input.SetEstimatedUnits
  280. }
  281. }
  282. if input.SetPointsMultiplier != nil && *input.SetPointsMultiplier > 0 {
  283. task.PointsMultiplier = *input.SetPointsMultiplier
  284. }
  285. if input.SetStatusName != nil {
  286. status, err := r.Database.ProjectStatuses().Find(ctx, issue.ProjectID, *input.SetStatusName)
  287. if err != nil {
  288. return nil, err
  289. }
  290. task.StatusName = status.Name
  291. task.StatusStage = status.Stage
  292. }
  293. err = r.Database.IssueTasks().Save(ctx, *task)
  294. if err != nil {
  295. return nil, err
  296. }
  297. return task, nil
  298. }
  299. func (r *mutationResolver) CreateLog(ctx context.Context, input graphcore.LogCreateInput) (*models.Log, error) {
  300. user := r.Auth.UserFromContext(ctx)
  301. if user == nil {
  302. return nil, slerrors.PermissionDenied
  303. }
  304. log := &models.Log{
  305. UserID: user.ID,
  306. Date: input.Date,
  307. Description: input.Description,
  308. Items: make([]models.LogItem, 0, len(input.Items)),
  309. Tasks: make([]models.LogTask, 0, len(input.Tasks)),
  310. }
  311. for _, itemInput := range input.Items {
  312. item, err := r.Database.IssueItems().Find(ctx, itemInput.IssueItemID)
  313. if err != nil {
  314. return nil, err
  315. }
  316. issue, err := loaders.IssueLoaderFromContext(ctx).Load(item.IssueID)
  317. if err != nil {
  318. return nil, err
  319. }
  320. _, err = r.Auth.IssuePermission(ctx, *issue)
  321. if err != nil {
  322. return nil, err
  323. }
  324. log.Items = append(log.Items, models.LogItem{
  325. IssueID: item.IssueID,
  326. IssueItemID: item.ID,
  327. Amount: itemInput.Amount,
  328. })
  329. }
  330. for _, taskInput := range input.Tasks {
  331. task, err := r.Database.IssueTasks().Find(ctx, taskInput.IssueTaskID)
  332. if err != nil {
  333. return nil, err
  334. }
  335. issue, err := loaders.IssueLoaderFromContext(ctx).Load(task.IssueID)
  336. if err != nil {
  337. return nil, err
  338. }
  339. _, err = r.Auth.IssuePermission(ctx, *issue)
  340. if err != nil {
  341. return nil, err
  342. }
  343. log.Tasks = append(log.Tasks, models.LogTask{
  344. IssueID: task.IssueID,
  345. IssueTaskID: task.ID,
  346. Duration: taskInput.Duration,
  347. Units: taskInput.Units,
  348. })
  349. }
  350. return r.Database.Logs().Insert(ctx, *log)
  351. }
  352. func (r *mutationResolver) EditLog(ctx context.Context, input graphcore.LogEditInput) (*models.Log, error) {
  353. user := r.Auth.UserFromContext(ctx)
  354. if user == nil {
  355. return nil, slerrors.PermissionDenied
  356. }
  357. log, err := r.Database.Logs().Find(ctx, input.LogID)
  358. if err != nil {
  359. return nil, err
  360. }
  361. removeItems := append([]string{}, input.RemoveItems...)
  362. for _, itemInput := range input.UpdateItems {
  363. removeItems = append(removeItems, itemInput.IssueItemID)
  364. }
  365. removeTasks := append([]string{}, input.RemoveTasks...)
  366. for _, taskInput := range input.UpdateTasks {
  367. removeTasks = append(removeTasks, taskInput.IssueTaskID)
  368. }
  369. if input.SetDate != nil {
  370. log.Date = *input.SetDate
  371. }
  372. if input.SetDescription != nil {
  373. log.Description = *input.SetDescription
  374. }
  375. for _, remove := range removeItems {
  376. for i, item := range log.Items {
  377. if remove == item.IssueItemID {
  378. log.Items = append(log.Items[:i], log.Items[i+1:]...)
  379. }
  380. }
  381. }
  382. for _, remove := range removeTasks {
  383. for i, task := range log.Tasks {
  384. if remove == task.IssueTaskID {
  385. log.Tasks = append(log.Tasks[:i], log.Tasks[i+1:]...)
  386. }
  387. }
  388. }
  389. for _, itemInput := range input.UpdateItems {
  390. item, err := r.Database.IssueItems().Find(ctx, itemInput.IssueItemID)
  391. if err != nil {
  392. return nil, err
  393. }
  394. issue, err := loaders.IssueLoaderFromContext(ctx).Load(item.IssueID)
  395. if err != nil {
  396. return nil, err
  397. }
  398. _, err = r.Auth.IssuePermission(ctx, *issue)
  399. if err != nil {
  400. return nil, err
  401. }
  402. log.Items = append(log.Items, models.LogItem{
  403. LogID: log.ID,
  404. IssueID: item.IssueID,
  405. IssueItemID: item.ID,
  406. Amount: itemInput.Amount,
  407. })
  408. }
  409. for _, taskInput := range input.UpdateTasks {
  410. task, err := r.Database.IssueTasks().Find(ctx, taskInput.IssueTaskID)
  411. if err != nil {
  412. return nil, err
  413. }
  414. issue, err := loaders.IssueLoaderFromContext(ctx).Load(task.IssueID)
  415. if err != nil {
  416. return nil, err
  417. }
  418. _, err = r.Auth.IssuePermission(ctx, *issue)
  419. if err != nil {
  420. return nil, err
  421. }
  422. log.Tasks = append(log.Tasks, models.LogTask{
  423. LogID: log.ID,
  424. IssueID: task.IssueID,
  425. IssueTaskID: task.ID,
  426. Duration: taskInput.Duration,
  427. Units: taskInput.Units,
  428. })
  429. }
  430. err = r.Database.Logs().Save(ctx, *log)
  431. if err != nil {
  432. return nil, err
  433. }
  434. return log, nil
  435. }
  436. func (r *mutationResolver) LoginUser(ctx context.Context, input graphcore.UserLoginInput) (*models.User, error) {
  437. return r.Auth.Login(ctx, input.Username, input.Password)
  438. }
  439. func (r *mutationResolver) LogoutUser(ctx context.Context) (*models.User, error) {
  440. return r.Auth.Logout(ctx)
  441. }
  442. func (r *mutationResolver) CreateUser(ctx context.Context, input graphcore.UserCreateInput) (*models.User, error) {
  443. active := input.Active == nil || *input.Active
  444. admin := input.Admin != nil && *input.Admin
  445. return r.Auth.CreateUser(ctx, input.Username, input.Password, input.Name, active, admin)
  446. }
  447. func (r *mutationResolver) EditUser(ctx context.Context, input graphcore.UserEditInput) (*models.User, error) {
  448. return r.Auth.EditUser(ctx, input.Username, input.SetName, input.CurrentPassword, input.SetPassword)
  449. }
  450. // Mutation returns graphcore.MutationResolver implementation.
  451. func (r *Resolver) Mutation() graphcore.MutationResolver { return &mutationResolver{r} }
  452. type mutationResolver struct{ *Resolver }