This commit is contained in:
@@ -45,6 +45,21 @@ func (s *ChangeService) Submit(ctx context.Context, model models.ChangeModel, op
|
||||
Date: time.Now(),
|
||||
}
|
||||
|
||||
// Do not allow * keys in unlisted objects, but allow laziness on the
|
||||
// call site to not bloat the code too much.
|
||||
if !listed {
|
||||
deleteList := make([]int, 0, 2)
|
||||
for i, key := range keys {
|
||||
if key.ID == "*" {
|
||||
deleteList = append(deleteList, i-len(deleteList))
|
||||
}
|
||||
}
|
||||
|
||||
for _, index := range deleteList {
|
||||
change.Keys = append(change.Keys[:index], change.Keys[index+1:]...)
|
||||
}
|
||||
}
|
||||
|
||||
for _, obj := range objects {
|
||||
if !change.AddObject(obj) {
|
||||
log.Printf("Cannot add object of type %T to change", obj)
|
||||
|
||||
@@ -0,0 +1,152 @@
|
||||
package services
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"git.aiterp.net/rpdata/api/internal/auth"
|
||||
"git.aiterp.net/rpdata/api/internal/generate"
|
||||
"git.aiterp.net/rpdata/api/models"
|
||||
"git.aiterp.net/rpdata/api/models/changekeys"
|
||||
"git.aiterp.net/rpdata/api/repositories"
|
||||
"time"
|
||||
)
|
||||
|
||||
// StoryService is a service governing all operations on stories and child objects.
|
||||
type StoryService struct {
|
||||
stories repositories.StoryRepository
|
||||
chapters repositories.ChapterRepository
|
||||
comments repositories.CommentRepository
|
||||
changeService *ChangeService
|
||||
}
|
||||
|
||||
func (s *StoryService) FindStory(ctx context.Context, id string) (*models.Story, error) {
|
||||
return s.stories.Find(ctx, id)
|
||||
}
|
||||
|
||||
func (s *StoryService) ListStories(ctx context.Context, filter models.StoryFilter) ([]*models.Story, error) {
|
||||
return s.stories.List(ctx, filter)
|
||||
}
|
||||
|
||||
func (s *StoryService) ListChapters(ctx context.Context, story models.Story) ([]*models.Chapter, error) {
|
||||
return s.chapters.List(ctx, models.ChapterFilter{StoryID: &story.ID, Limit: 0})
|
||||
}
|
||||
|
||||
func (s *StoryService) ListComments(ctx context.Context, chapter models.Chapter, limit int) ([]*models.Comment, error) {
|
||||
return s.comments.List(ctx, models.CommentFilter{ChapterID: &chapter.ID, Limit: limit})
|
||||
}
|
||||
|
||||
func (s *StoryService) CreateStory(ctx context.Context, name, author string, category models.StoryCategory, listed, open bool, tags []models.Tag, createdDate, fictionalDate time.Time) (*models.Story, error) {
|
||||
story := &models.Story{
|
||||
Name: name,
|
||||
Author: author,
|
||||
Category: category,
|
||||
Listed: listed,
|
||||
Open: open,
|
||||
Tags: tags,
|
||||
CreatedDate: createdDate,
|
||||
FictionalDate: fictionalDate,
|
||||
UpdatedDate: createdDate,
|
||||
}
|
||||
|
||||
if err := auth.CheckPermission(ctx, "add", story); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
story, err := s.stories.Insert(ctx, *story)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
s.changeService.Submit(ctx, "Story", "add", story.Listed, changekeys.Listed(story), story)
|
||||
|
||||
return story, nil
|
||||
}
|
||||
|
||||
func (s *StoryService) CreateChapter(ctx context.Context, story models.Story, title, author, source string, createdDate time.Time, fictionalDate *time.Time, commentMode models.ChapterCommentMode) (*models.Chapter, error) {
|
||||
chapter := &models.Chapter{
|
||||
ID: generate.ChapterID(),
|
||||
StoryID: story.ID,
|
||||
Title: title,
|
||||
Author: author,
|
||||
Source: source,
|
||||
CreatedDate: createdDate,
|
||||
EditedDate: createdDate,
|
||||
CommentMode: commentMode,
|
||||
CommentsLocked: false,
|
||||
}
|
||||
if fictionalDate != nil {
|
||||
chapter.FictionalDate = *fictionalDate
|
||||
}
|
||||
|
||||
if story.Open {
|
||||
if !auth.TokenFromContext(ctx).Permitted("member", "chapter.add") {
|
||||
return nil, auth.ErrUnauthorized
|
||||
}
|
||||
} else {
|
||||
if err := auth.CheckPermission(ctx, "add", chapter); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
chapter, err := s.chapters.Insert(ctx, *chapter)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if createdDate.After(story.UpdatedDate) {
|
||||
_, _ = s.stories.Update(ctx, story, models.StoryUpdate{UpdatedDate: &createdDate})
|
||||
}
|
||||
|
||||
s.changeService.Submit(ctx, "Chapter", "add", story.Listed, changekeys.Many(story, chapter), chapter)
|
||||
|
||||
return chapter, nil
|
||||
}
|
||||
|
||||
// CreateComment adds a comment.
|
||||
func (s *StoryService) CreateComment(ctx context.Context, chapter models.Chapter, subject, author, source, characterName string, character *models.Character, createdDate time.Time, fictionalDate time.Time) (*models.Comment, error) {
|
||||
characterID := ""
|
||||
if character != nil {
|
||||
characterID = character.ID
|
||||
}
|
||||
|
||||
if !chapter.CanComment() {
|
||||
return nil, errors.New("comments are locked or disabled")
|
||||
}
|
||||
|
||||
if author == "" {
|
||||
if token := auth.TokenFromContext(ctx); token != nil {
|
||||
author = token.UserID
|
||||
} else {
|
||||
return nil, auth.ErrUnauthenticated
|
||||
}
|
||||
}
|
||||
|
||||
comment := &models.Comment{
|
||||
ID: generate.CommentID(),
|
||||
ChapterID: chapter.ID,
|
||||
Subject: subject,
|
||||
Author: author,
|
||||
CharacterName: characterName,
|
||||
CharacterID: characterID,
|
||||
FictionalDate: fictionalDate,
|
||||
CreatedDate: createdDate,
|
||||
EditedDate: createdDate,
|
||||
Source: source,
|
||||
}
|
||||
if err := auth.CheckPermission(ctx, "add", comment); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
comment, err := s.comments.Insert(ctx, *comment)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if story, err := s.stories.Find(ctx, chapter.StoryID); err == nil {
|
||||
s.changeService.Submit(ctx, "Comment", "add", story.Listed, changekeys.Many(story, chapter, comment), comment)
|
||||
} else {
|
||||
s.changeService.Submit(ctx, "Comment", "add", false, changekeys.Many(chapter, comment), comment)
|
||||
}
|
||||
|
||||
return comment, nil
|
||||
}
|
||||
Reference in New Issue
Block a user