GraphQL API and utilities for the rpdata project
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.

211 lines
5.3 KiB

  1. package services
  2. import (
  3. "context"
  4. "errors"
  5. "git.aiterp.net/rpdata/api/models"
  6. "git.aiterp.net/rpdata/api/models/changekeys"
  7. "git.aiterp.net/rpdata/api/repositories"
  8. "git.aiterp.net/rpdata/api/services/loaders"
  9. "sort"
  10. "strings"
  11. )
  12. type CharacterService struct {
  13. characters repositories.CharacterRepository
  14. loader *loaders.CharacterLoader
  15. changeService *ChangeService
  16. authService *AuthService
  17. }
  18. // Find uses the loader to find the character by the ID.
  19. func (s *CharacterService) Find(ctx context.Context, id string) (*models.Character, error) {
  20. return s.loader.Load(id)
  21. }
  22. // Find uses the loader to find the character by the ID.
  23. func (s *CharacterService) FindNick(ctx context.Context, nick string) (*models.Character, error) {
  24. return s.characters.FindNick(ctx, nick)
  25. }
  26. // List lists the characters. If the only filter active is `IDs`, the loader is used to batch together requests.
  27. func (s *CharacterService) List(ctx context.Context, filter models.CharacterFilter) ([]*models.Character, error) {
  28. if len(filter.IDs) > 0 && len(filter.Names) == 0 && len(filter.Nicks) == 0 && filter.Author == nil && filter.Search == nil {
  29. characters, errs := s.loader.LoadAll(filter.IDs)
  30. if len(characters) == 0 && len(errs) > 0 {
  31. if errs[0] == repositories.ErrNotFound {
  32. return []*models.Character{}, nil
  33. } else {
  34. return nil, errs[0]
  35. }
  36. }
  37. if err := ctx.Err(); err != nil {
  38. return nil, err
  39. }
  40. var badIndices []int
  41. for i, character := range characters {
  42. if character == nil {
  43. badIndices = append(badIndices, i-len(badIndices))
  44. }
  45. }
  46. for _, index := range badIndices {
  47. characters = append(characters[:index], characters[index+1:]...)
  48. }
  49. sort.Slice(characters, func(i, j int) bool {
  50. return strings.Compare(characters[i].ID, characters[j].ID) < 0
  51. })
  52. return characters, nil
  53. }
  54. return s.characters.List(ctx, filter)
  55. }
  56. func (s *CharacterService) Create(ctx context.Context, nick, name, shortName, author, description string) (*models.Character, error) {
  57. token := s.authService.TokenFromContext(ctx)
  58. if token == nil {
  59. return nil, ErrUnauthenticated
  60. }
  61. if name == "" {
  62. return nil, errors.New("name cannot be empty")
  63. }
  64. // Insert nick into existing if character already exists.
  65. if character, err := s.characters.FindName(ctx, name); err == nil && character.Name == name {
  66. return s.AddNick(ctx, character.ID, nick)
  67. }
  68. if author == "" {
  69. author = token.UserID
  70. }
  71. if shortName == "" {
  72. split := strings.SplitN(name, " ", 2)
  73. shortName = split[0]
  74. }
  75. character := &models.Character{
  76. Name: name,
  77. ShortName: shortName,
  78. Author: author,
  79. Nicks: []string{nick},
  80. Description: description,
  81. }
  82. err := s.authService.CheckPermission(ctx, "add", character)
  83. if err != nil {
  84. return nil, err
  85. }
  86. character, err = s.characters.Insert(ctx, *character)
  87. if err != nil {
  88. return nil, err
  89. }
  90. s.changeService.Submit(ctx, "Character", "add", true, changekeys.Listed(character), character)
  91. return character, nil
  92. }
  93. func (s *CharacterService) Update(ctx context.Context, id string, name, shortName, description *string) (*models.Character, error) {
  94. character, err := s.characters.Find(ctx, id)
  95. if err != nil {
  96. return nil, err
  97. }
  98. err = s.authService.CheckPermission(ctx, "edit", character)
  99. if err != nil {
  100. return nil, err
  101. }
  102. character, err = s.characters.Update(ctx, *character, models.CharacterUpdate{
  103. Name: name,
  104. ShortName: shortName,
  105. Description: description,
  106. })
  107. if err != nil {
  108. return nil, err
  109. }
  110. s.loader.Clear(character.ID)
  111. s.loader.Prime(character.ID, character)
  112. s.changeService.Submit(ctx, "Character", "edit", true, changekeys.Listed(character), character)
  113. return character, nil
  114. }
  115. func (s *CharacterService) AddNick(ctx context.Context, id string, nick string) (*models.Character, error) {
  116. character, err := s.characters.Find(ctx, id)
  117. if err != nil {
  118. return nil, err
  119. }
  120. err = s.authService.CheckPermission(ctx, "edit", character)
  121. if err != nil {
  122. return nil, err
  123. }
  124. character, err = s.characters.AddNick(ctx, *character, nick)
  125. if err != nil {
  126. return nil, err
  127. }
  128. s.loader.Clear(character.ID)
  129. s.loader.Prime(character.ID, character)
  130. s.changeService.Submit(ctx, "Character", "edit", true, changekeys.Listed(character), character)
  131. return character, nil
  132. }
  133. func (s *CharacterService) RemoveNick(ctx context.Context, id string, nick string) (*models.Character, error) {
  134. character, err := s.characters.Find(ctx, id)
  135. if err != nil {
  136. return nil, err
  137. }
  138. err = s.authService.CheckPermission(ctx, "edit", character)
  139. if err != nil {
  140. return nil, err
  141. }
  142. character, err = s.characters.RemoveNick(ctx, *character, nick)
  143. if err != nil {
  144. return nil, err
  145. }
  146. s.loader.Clear(character.ID)
  147. s.loader.Prime(character.ID, character)
  148. s.changeService.Submit(ctx, "Character", "edit", true, changekeys.Listed(character), character)
  149. return character, nil
  150. }
  151. func (s *CharacterService) Delete(ctx context.Context, id string) (*models.Character, error) {
  152. character, err := s.characters.Find(ctx, id)
  153. if err != nil {
  154. return nil, err
  155. }
  156. err = s.authService.CheckPermission(ctx, "edit", character)
  157. if err != nil {
  158. return nil, err
  159. }
  160. err = s.characters.Delete(ctx, *character)
  161. if err != nil {
  162. return nil, err
  163. }
  164. s.loader.Clear(character.ID)
  165. s.changeService.Submit(ctx, "Character", "remove", true, changekeys.Listed(character), character)
  166. return character, nil
  167. }