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.

372 lines
8.4 KiB

  1. package resolver
  2. import (
  3. "context"
  4. "time"
  5. "git.aiterp.net/rpdata/api/internal/session"
  6. "git.aiterp.net/rpdata/api/model/change"
  7. "git.aiterp.net/rpdata/api/model/story"
  8. )
  9. // StoryResolver for the Story graphql type
  10. type StoryResolver struct{ S story.Story }
  11. // StoryArgs is args for story query
  12. type StoryArgs struct {
  13. ID string
  14. }
  15. // Story implements the story query
  16. func (r *QueryResolver) Story(ctx context.Context, args *StoryArgs) (*StoryResolver, error) {
  17. story, err := story.FindID(args.ID)
  18. if err != nil {
  19. return nil, err
  20. }
  21. return &StoryResolver{S: story}, nil
  22. }
  23. // StoriesArg is args for stories query
  24. type StoriesArg struct {
  25. Input *StoriesInput
  26. }
  27. // StoriesInput resolves the TagInput input
  28. type StoriesInput struct {
  29. Author *string
  30. Tags *[]TagInput
  31. EarliestFictionalDate *string
  32. LatestFictionalDate *string
  33. Limit *int32
  34. }
  35. // Stories implements the stories query
  36. func (r *QueryResolver) Stories(ctx context.Context, args *StoriesArg) ([]*StoryResolver, error) {
  37. author := ""
  38. if args.Input.Author != nil {
  39. author = *args.Input.Author
  40. }
  41. tags := make([]story.Tag, 0, 8)
  42. if args.Input.Tags != nil {
  43. for _, tagInput := range *args.Input.Tags {
  44. tags = append(tags, story.Tag{
  45. Kind: tagInput.Kind,
  46. Name: tagInput.Name,
  47. })
  48. }
  49. }
  50. earliest := time.Time{}
  51. err := error(nil)
  52. if args.Input.EarliestFictionalDate != nil {
  53. earliest, err = time.Parse(time.RFC3339Nano, *args.Input.EarliestFictionalDate)
  54. if err != nil {
  55. return nil, err
  56. }
  57. }
  58. latest := time.Time{}
  59. if args.Input.LatestFictionalDate != nil {
  60. latest, err = time.Parse(time.RFC3339Nano, *args.Input.LatestFictionalDate)
  61. if err != nil {
  62. return nil, err
  63. }
  64. }
  65. limit := 30
  66. if args.Input.Limit != nil {
  67. limit = int(*args.Input.Limit)
  68. }
  69. stories, err := story.List(author, tags, earliest, latest, limit)
  70. if err != nil {
  71. return nil, err
  72. }
  73. resolvers := make([]*StoryResolver, len(stories))
  74. for i, story := range stories {
  75. resolvers[i] = &StoryResolver{S: story}
  76. }
  77. return resolvers, nil
  78. }
  79. // StoryAddArgs is args for the addStory mutation
  80. type StoryAddArgs struct {
  81. Input *struct {
  82. Name string
  83. Category string
  84. Author *string
  85. Open *bool
  86. Listed *bool
  87. Tags *[]TagInput
  88. FictionalDate *string
  89. }
  90. }
  91. // AddStory implements the addStory mutation
  92. func (r *MutationResolver) AddStory(ctx context.Context, args *StoryAddArgs) (*StoryResolver, error) {
  93. user := session.FromContext(ctx).User()
  94. if user == nil || !user.Permitted("member", "story.add") {
  95. return nil, ErrUnauthorized
  96. }
  97. author := user.ID
  98. if args.Input.Author != nil {
  99. author = *args.Input.Author
  100. if user.ID != author && !user.Permitted("story.add") {
  101. return nil, ErrPermissionDenied
  102. }
  103. }
  104. listed := (args.Input.Listed != nil && *args.Input.Listed == true)
  105. open := (args.Input.Open != nil && *args.Input.Open == true)
  106. tags := make([]story.Tag, 0, 8)
  107. if args.Input.Tags != nil {
  108. for _, tagInput := range *args.Input.Tags {
  109. tags = append(tags, story.Tag{
  110. Kind: tagInput.Kind,
  111. Name: tagInput.Name,
  112. })
  113. }
  114. }
  115. fictionalDate := time.Time{}
  116. if args.Input.FictionalDate != nil {
  117. date, err := time.Parse(time.RFC3339Nano, *args.Input.FictionalDate)
  118. if err != nil {
  119. return nil, err
  120. }
  121. fictionalDate = date
  122. }
  123. story, err := story.New(args.Input.Name, author, args.Input.Category, listed, open, tags, time.Now(), fictionalDate)
  124. if err != nil {
  125. return nil, err
  126. }
  127. return &StoryResolver{S: story}, nil
  128. }
  129. // StoryTagArgs is args for the addStory mutation
  130. type StoryTagArgs struct {
  131. Input *struct {
  132. ID string
  133. Tag TagInput
  134. }
  135. }
  136. // AddStoryTag implements the addStoryTag mutation
  137. func (r *MutationResolver) AddStoryTag(ctx context.Context, args *StoryTagArgs) (*StoryResolver, error) {
  138. user := session.FromContext(ctx).User()
  139. if user == nil || !user.Permitted("member", "story.edit") {
  140. return nil, ErrUnauthorized
  141. }
  142. tag := story.Tag{Kind: args.Input.Tag.Kind, Name: args.Input.Tag.Name}
  143. story, err := story.FindID(args.Input.ID)
  144. if err != nil {
  145. return nil, err
  146. }
  147. if story.Author != user.ID && !user.Permitted("story.edit") {
  148. return nil, ErrPermissionDenied
  149. }
  150. err = story.AddTag(tag)
  151. if err != nil {
  152. return nil, err
  153. }
  154. change.Submit("Story", "add.tag", user.ID, story.ID, map[string]interface{}{
  155. "kind": tag.Kind,
  156. "name": tag.Name,
  157. })
  158. return &StoryResolver{S: story}, nil
  159. }
  160. // RemoveStoryTag implements the removeStoryTag mutation
  161. func (r *MutationResolver) RemoveStoryTag(ctx context.Context, args *StoryTagArgs) (*StoryResolver, error) {
  162. user := session.FromContext(ctx).User()
  163. if user == nil || !user.Permitted("member", "story.edit") {
  164. return nil, ErrUnauthorized
  165. }
  166. tag := story.Tag{Kind: args.Input.Tag.Kind, Name: args.Input.Tag.Name}
  167. story, err := story.FindID(args.Input.ID)
  168. if err != nil {
  169. return nil, err
  170. }
  171. if story.Author != user.ID && !user.Permitted("story.edit") {
  172. return nil, ErrPermissionDenied
  173. }
  174. err = story.RemoveTag(tag)
  175. if err != nil {
  176. return nil, err
  177. }
  178. change.Submit("Story", "remove.tag", user.ID, story.ID, map[string]interface{}{
  179. "kind": tag.Kind,
  180. "name": tag.Name,
  181. })
  182. return &StoryResolver{S: story}, nil
  183. }
  184. // StoryEditArgs is args for the addStory mutation
  185. type StoryEditArgs struct {
  186. Input *struct {
  187. ID string
  188. Name *string
  189. Category *string
  190. Author *string
  191. Open *bool
  192. Listed *bool
  193. FictionalDate *string
  194. }
  195. }
  196. // EditStory implements the editStory mutation
  197. func (r *MutationResolver) EditStory(ctx context.Context, args *StoryEditArgs) (*StoryResolver, error) {
  198. user := session.FromContext(ctx).User()
  199. if user == nil || !user.Permitted("member", "story.edit") {
  200. return nil, ErrUnauthorized
  201. }
  202. story, err := story.FindID(args.Input.ID)
  203. if err != nil {
  204. return nil, err
  205. }
  206. if story.Author != user.ID && !user.Permitted("story.edit") {
  207. return nil, ErrPermissionDenied
  208. }
  209. var fictionalDate *time.Time
  210. if args.Input.FictionalDate != nil {
  211. date, err := time.Parse(time.RFC3339Nano, *args.Input.FictionalDate)
  212. if err != nil {
  213. return nil, err
  214. }
  215. fictionalDate = &date
  216. }
  217. input := args.Input
  218. err = story.Edit(input.Name, input.Category, input.Listed, input.Open, fictionalDate)
  219. if err != nil {
  220. return nil, err
  221. }
  222. return &StoryResolver{S: story}, nil
  223. }
  224. // StoryRemoveArgs is args for the removeStory mutation
  225. type StoryRemoveArgs struct {
  226. ID string
  227. }
  228. // RemoveStory implements the removeStory mutation
  229. func (r *MutationResolver) RemoveStory(ctx context.Context, args *StoryRemoveArgs) (*StoryResolver, error) {
  230. user := session.FromContext(ctx).User()
  231. if user == nil || !user.Permitted("member", "story.edit") {
  232. return nil, ErrUnauthorized
  233. }
  234. story, err := story.FindID(args.ID)
  235. if err != nil {
  236. return nil, err
  237. }
  238. if story.Author != user.ID && !user.Permitted("story.remove") {
  239. return nil, ErrPermissionDenied
  240. }
  241. err = story.Remove()
  242. if err != nil {
  243. return nil, err
  244. }
  245. return &StoryResolver{S: story}, nil
  246. }
  247. // ID resolves Story.id
  248. func (r *StoryResolver) ID() string {
  249. return r.S.ID
  250. }
  251. // Author resolves Story.author
  252. func (r *StoryResolver) Author() string {
  253. return r.S.Author
  254. }
  255. // Name resolves Story.name
  256. func (r *StoryResolver) Name() string {
  257. return r.S.Name
  258. }
  259. // Category resolves Story.category
  260. func (r *StoryResolver) Category() string {
  261. return r.S.Category
  262. }
  263. // Open resolves Story.open
  264. func (r *StoryResolver) Open() bool {
  265. return r.S.Open
  266. }
  267. // Listed resolves Story.listed
  268. func (r *StoryResolver) Listed() bool {
  269. return r.S.Listed
  270. }
  271. // Tags resolves Story.tags
  272. func (r *StoryResolver) Tags() []*TagResolver {
  273. resolvers := make([]*TagResolver, len(r.S.Tags))
  274. for i, tag := range r.S.Tags {
  275. resolvers[i] = &TagResolver{T: tag}
  276. }
  277. return resolvers
  278. }
  279. // Chapters resolves Story.chapters
  280. func (r *StoryResolver) Chapters() ([]*ChapterResolver, error) {
  281. chapters, err := r.S.Chapters()
  282. if err != nil {
  283. return nil, err
  284. }
  285. resolvers := make([]*ChapterResolver, len(chapters))
  286. for i, chapter := range chapters {
  287. resolvers[i] = &ChapterResolver{C: chapter}
  288. }
  289. return resolvers, nil
  290. }
  291. // CreatedDate resolves Story.createdDate
  292. func (r *StoryResolver) CreatedDate() string {
  293. return r.S.CreatedDate.Format(time.RFC3339Nano)
  294. }
  295. // FictionalDate resolves Story.fictionalDate
  296. func (r *StoryResolver) FictionalDate() string {
  297. return r.S.FictionalDate.Format(time.RFC3339Nano)
  298. }
  299. // UpdatedDate resolves Story.updatedDate
  300. func (r *StoryResolver) UpdatedDate() string {
  301. return r.S.UpdatedDate.Format(time.RFC3339Nano)
  302. }