diff --git a/.idea/codeStyles/codeStyleConfig.xml b/.idea/codeStyles/codeStyleConfig.xml
new file mode 100644
index 0000000..a55e7a1
--- /dev/null
+++ b/.idea/codeStyles/codeStyleConfig.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/inspectionProfiles/Project_Default.xml b/.idea/inspectionProfiles/Project_Default.xml
new file mode 100644
index 0000000..1b22473
--- /dev/null
+++ b/.idea/inspectionProfiles/Project_Default.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/cmd/rpdata-server/main.go b/cmd/rpdata-server/main.go
index fd3fdac..e235cb6 100644
--- a/cmd/rpdata-server/main.go
+++ b/cmd/rpdata-server/main.go
@@ -16,7 +16,6 @@ import (
"git.aiterp.net/rpdata/api/internal/loader"
"git.aiterp.net/rpdata/api/internal/store"
"git.aiterp.net/rpdata/api/models"
- "git.aiterp.net/rpdata/api/models/changes"
"git.aiterp.net/rpdata/api/models/logs"
"git.aiterp.net/rpdata/api/services"
"github.com/99designs/gqlgen/handler"
@@ -52,13 +51,13 @@ func main() {
log.Println("Characters updated")
}()
- go logListedChanges()
+ go logListedChanges(services.Changes)
log.Fatal(http.ListenAndServe(":8081", nil))
}
-func logListedChanges() {
- sub := changes.Subscribe(context.Background(), nil, true)
+func logListedChanges(changes *services.ChangeService) {
+ sub := changes.Subscribe(context.Background(), models.ChangeFilter{PassAll: true})
for change := range sub {
log.Printf("Change: Author=%#+v Model=%#+v Op=%#+v", change.Author, change.Model, change.Op)
diff --git a/database/mongodb/changes.go b/database/mongodb/changes.go
new file mode 100644
index 0000000..3c3cdb9
--- /dev/null
+++ b/database/mongodb/changes.go
@@ -0,0 +1,104 @@
+package mongodb
+
+import (
+ "context"
+ "git.aiterp.net/rpdata/api/models"
+ "git.aiterp.net/rpdata/api/repositories"
+ "github.com/globalsign/mgo"
+ "github.com/globalsign/mgo/bson"
+ "strconv"
+ "time"
+)
+
+type changeRepository struct {
+ changes *mgo.Collection
+ idCounter *counter
+}
+
+func (r *changeRepository) Find(ctx context.Context, id string) (*models.Change, error) {
+ change := new(models.Change)
+ err := r.changes.FindId(id).One(change)
+ if err != nil {
+ return nil, err
+ }
+
+ return change, nil
+}
+
+func (r *changeRepository) List(ctx context.Context, filter models.ChangeFilter) ([]*models.Change, error) {
+ query := bson.M{}
+ limit := 0
+ if filter.EarliestDate != nil && !filter.EarliestDate.IsZero() {
+ query["date"] = bson.M{"$gte": *filter.EarliestDate}
+ }
+ if len(filter.Keys) > 0 {
+ query["keys"] = bson.M{"$in": filter.Keys}
+ }
+ if filter.Author != nil && *filter.Author != "" {
+ query["author"] = *filter.Author
+ }
+ if filter.Limit != nil {
+ limit = *filter.Limit
+ }
+
+ initialSize := 64
+ if limit > 0 && limit < 256 {
+ initialSize = limit
+ }
+
+ changes := make([]*models.Change, 0, initialSize)
+ err := r.changes.Find(query).All(&changes)
+ if err != nil {
+ return nil, err
+ }
+
+ return changes, nil
+}
+
+func (r *changeRepository) Insert(ctx context.Context, change models.Change) (*models.Change, error) {
+ next, err := r.idCounter.Increment(1)
+ if err != nil {
+ return nil, err
+ }
+
+ change.ID = "Change_" + strconv.Itoa(next)
+
+ err = r.changes.Insert(change)
+ if err != nil {
+ return nil, err
+ }
+
+ return &change, nil
+}
+
+func (r *changeRepository) Remove(ctx context.Context, change models.Change) error {
+ return r.changes.RemoveId(change.ID)
+}
+
+func newChangeRepository(db *mgo.Database) (repositories.ChangeRepository, error) {
+ collection := db.C("common.changes")
+
+ err := collection.EnsureIndex(mgo.Index{
+ Name: "expiry",
+ Key: []string{"date"},
+ ExpireAfter: time.Hour * 2400, // 100 days
+ })
+ if err != nil {
+ return nil, err
+ }
+
+ err = collection.EnsureIndexKey("author")
+ if err != nil {
+ return nil, err
+ }
+
+ err = collection.EnsureIndexKey("keys")
+ if err != nil {
+ return nil, err
+ }
+
+ return &changeRepository{
+ changes: collection,
+ idCounter: newCounter(db, "auto_increment", "Change"),
+ }, nil
+}
diff --git a/database/mongodb/db.go b/database/mongodb/db.go
index 8e42b20..5a19e03 100644
--- a/database/mongodb/db.go
+++ b/database/mongodb/db.go
@@ -38,8 +38,15 @@ func Init(cfg config.Database) (bundle *repositories.Bundle, closeFn func() erro
return nil, nil, err
}
+ changes, err := newChangeRepository(db)
+ if err != nil {
+ session.Close()
+ return nil, nil, err
+ }
+
bundle = &repositories.Bundle{
Characters: characters,
+ Changes: changes,
Tags: newTagRepository(db),
}
@@ -73,6 +80,22 @@ func (c *counter) WithName(name string) *counter {
}
}
+func (c *counter) WithCategory(category string) *counter {
+ return &counter{
+ coll: c.coll,
+ category: category,
+ name: c.name,
+ }
+}
+
+func (c *counter) With(category, name string) *counter {
+ return &counter{
+ coll: c.coll,
+ category: category,
+ name: name,
+ }
+}
+
func (c *counter) Increment(amount int) (int, error) {
type counterDoc struct {
ID string `bson:"_id"`
diff --git a/graph2/complexity.go b/graph2/complexity.go
index b3f4e1c..f68ec85 100644
--- a/graph2/complexity.go
+++ b/graph2/complexity.go
@@ -3,7 +3,6 @@ package graph2
import (
"git.aiterp.net/rpdata/api/graph2/graphcore"
"git.aiterp.net/rpdata/api/models"
- "git.aiterp.net/rpdata/api/models/changes"
"git.aiterp.net/rpdata/api/models/channels"
"git.aiterp.net/rpdata/api/models/files"
"git.aiterp.net/rpdata/api/models/logs"
@@ -71,7 +70,7 @@ func complexity() (cr graphcore.ComplexityRoot) {
cr.Query.Files = func(childComplexity int, filter *files.Filter) int {
return childComplexity + listComplexity
}
- cr.Query.Changes = func(childComplexity int, filter *changes.Filter) int {
+ cr.Query.Changes = func(childComplexity int, filter *models.ChangeFilter) int {
return childComplexity + listComplexity
}
cr.Query.Token = func(childComplexity int) int {
diff --git a/graph2/gqlgen.yml b/graph2/gqlgen.yml
index a28d8f5..a23d927 100644
--- a/graph2/gqlgen.yml
+++ b/graph2/gqlgen.yml
@@ -62,7 +62,7 @@ models:
ChangeKeyInput: # It's the same as ChangeKey
model: git.aiterp.net/rpdata/api/models.ChangeKey
ChangesFilter:
- model: git.aiterp.net/rpdata/api/models/changes.Filter
+ model: git.aiterp.net/rpdata/api/models.ChangeFilter
Token:
model: git.aiterp.net/rpdata/api/models.Token
User:
diff --git a/graph2/resolvers/changes.go b/graph2/resolvers/changes.go
index d8379a4..a87e123 100644
--- a/graph2/resolvers/changes.go
+++ b/graph2/resolvers/changes.go
@@ -2,39 +2,25 @@ package resolvers
import (
"context"
- "errors"
-
"git.aiterp.net/rpdata/api/models"
- "git.aiterp.net/rpdata/api/models/changes"
)
/// Queries
-func (r *queryResolver) Changes(ctx context.Context, filter *changes.Filter) ([]*models.Change, error) {
- changes, err := changes.List(filter)
- if err != nil {
- return nil, err
- }
-
- changes2 := make([]*models.Change, len(changes))
- for i := range changes {
- changes2[i] = &changes[i]
+func (r *queryResolver) Changes(ctx context.Context, filter *models.ChangeFilter) ([]*models.Change, error) {
+ if filter == nil {
+ filter = &models.ChangeFilter{}
}
- return changes2, nil
+ return r.s.Changes.List(ctx, *filter)
}
/// Subscriptions
-func (r *subscriptionResolver) Changes(ctx context.Context, keys []*models.ChangeKey) (<-chan *models.Change, error) {
- if len(keys) == 0 {
- return nil, errors.New("At least one key is required for a subscription")
- }
-
- keys2 := make([]models.ChangeKey, len(keys))
- for i := range keys {
- keys2[i] = *keys[i]
+func (r *subscriptionResolver) Changes(ctx context.Context, filter *models.ChangeFilter) (<-chan *models.Change, error) {
+ if filter == nil {
+ filter = &models.ChangeFilter{}
}
- return changes.Subscribe(ctx, keys2, false), nil
+ return r.s.Changes.Subscribe(ctx, *filter), nil
}
diff --git a/graph2/schema/root.gql b/graph2/schema/root.gql
index bb00b30..5e9a03b 100644
--- a/graph2/schema/root.gql
+++ b/graph2/schema/root.gql
@@ -164,7 +164,7 @@ type Subscription {
"""
Changes subscribes to the changes matching the following keys.
"""
- changes(keys: [ChangeKeyInput!]!): Change!
+ changes(filter: ChangesFilter): Change!
}
# A Time represents a RFC3339 encoded date with up to millisecond precision.
diff --git a/graph2/schema/types/Change.gql b/graph2/schema/types/Change.gql
index 28326d7..e702274 100644
--- a/graph2/schema/types/Change.gql
+++ b/graph2/schema/types/Change.gql
@@ -73,9 +73,12 @@ input ChangesFilter {
"The keys to query for."
keys: [ChangeKeyInput!]
+ "Only show changes by this author"
+ author: String
+
"Only show changes more recent than this date."
earliestDate: Time
- "Limit the amount of results."
+ "Limit the amount of results. This even goes for subscriptions!"
limit: Int
}
\ No newline at end of file
diff --git a/internal/auth/token.go b/internal/auth/token.go
index 209431d..73036c7 100644
--- a/internal/auth/token.go
+++ b/internal/auth/token.go
@@ -114,20 +114,24 @@ func CheckToken(tokenString string) (token models.Token, err error) {
return models.Token{}, ErrDeletedUser
}
- acceptedPermissions := make([]string, 0, 8)
- for _, permission := range permissions {
- found := false
-
- for _, userPermission := range user.Permissions {
- if permission == userPermission {
- found = true
- break
+ acceptedPermissions := make([]string, 0, len(user.Permissions))
+ if len(permissions) > 0 {
+ for _, permission := range permissions {
+ found := false
+
+ for _, userPermission := range user.Permissions {
+ if permission == userPermission {
+ found = true
+ break
+ }
}
- }
- if found {
- acceptedPermissions = append(acceptedPermissions, permission)
+ if found {
+ acceptedPermissions = append(acceptedPermissions, permission)
+ }
}
+ } else {
+ acceptedPermissions = append(acceptedPermissions, user.Permissions...)
}
return models.Token{UserID: user.ID, Permissions: acceptedPermissions}, nil
@@ -153,10 +157,10 @@ func parseClaims(jwtClaims jwt.Claims) (userid string, permissions []string, err
permissions = append(permissions, permission)
}
}
- }
- if len(permissions) == 0 {
- return "", nil, ErrInvalidClaims
+ if len(permissions) == 0 {
+ return "", nil, ErrInvalidClaims
+ }
}
return
diff --git a/internal/notifier/notifier.go b/internal/notifier/notifier.go
new file mode 100644
index 0000000..d1958e2
--- /dev/null
+++ b/internal/notifier/notifier.go
@@ -0,0 +1,44 @@
+package notifier
+
+import (
+ "context"
+ "sync"
+)
+
+// A Notifier is a synchronization primitive for waking upp all listeners at once.
+type Notifier struct {
+ mutex sync.Mutex
+ ch chan struct{}
+}
+
+// Broadcast wakes all listeners if there are any.
+func (notifier *Notifier) Broadcast() {
+ notifier.mutex.Lock()
+ if notifier.ch != nil {
+ close(notifier.ch)
+ notifier.ch = nil
+ }
+ notifier.mutex.Unlock()
+}
+
+// C gets the channel that'll close on the next notification.
+func (notifier *Notifier) C() <-chan struct{} {
+ notifier.mutex.Lock()
+ if notifier.ch == nil {
+ notifier.ch = make(chan struct{})
+ }
+ ch := notifier.ch
+ notifier.mutex.Unlock()
+
+ return ch
+}
+
+// Wait waits for the next `Broadcast` call, or the context's termination.
+func (notifier *Notifier) Wait(ctx context.Context) error {
+ select {
+ case <-notifier.C():
+ return nil
+ case <-ctx.Done():
+ return ctx.Err()
+ }
+}
diff --git a/models/change.go b/models/change.go
index 1bd9601..be22981 100644
--- a/models/change.go
+++ b/models/change.go
@@ -1,6 +1,9 @@
package models
-import "time"
+import (
+ "reflect"
+ "time"
+)
// Change represents a change in the rpdata history through the API.
type Change struct {
@@ -22,15 +25,55 @@ type Change struct {
Comments []Comment `bson:"comments"`
}
-// ChangeKey is a key for a change that can be used when subscribing to them.
-type ChangeKey struct {
- Model ChangeModel `bson:"model"`
- ID string `bson:"id"`
+// AddObject adds the model into the appropriate array.
+func (change *Change) AddObject(object interface{}) bool {
+ if v := reflect.ValueOf(object); v.Kind() == reflect.Ptr {
+ return change.AddObject(v.Elem().Interface())
+ }
+
+ switch object := object.(type) {
+ case Log:
+ change.Logs = append(change.Logs, object)
+ case []Log:
+ change.Logs = append(change.Logs, object...)
+ case Character:
+ change.Characters = append(change.Characters, object)
+ case []Character:
+ change.Characters = append(change.Characters, object...)
+ case Channel:
+ change.Channels = append(change.Channels, object)
+ case []Channel:
+ change.Channels = append(change.Channels, object...)
+ case Post:
+ change.Posts = append(change.Posts, object)
+ case []Post:
+ change.Posts = append(change.Posts, object...)
+ case Story:
+ change.Stories = append(change.Stories, object)
+ case []Story:
+ change.Stories = append(change.Stories, object...)
+ case Tag:
+ change.Tags = append(change.Tags, object)
+ case []Tag:
+ change.Tags = append(change.Tags, object...)
+ case Chapter:
+ change.Chapters = append(change.Chapters, object)
+ case []Chapter:
+ change.Chapters = append(change.Chapters, object...)
+ case Comment:
+ change.Comments = append(change.Comments, object)
+ case []Comment:
+ change.Comments = append(change.Comments, object...)
+ default:
+ return false
+ }
+
+ return true
}
// Objects makes a combined, mixed array of all the models stored in this change.
func (change *Change) Objects() []interface{} {
- data := make([]interface{}, 0, len(change.Logs)+len(change.Characters)+len(change.Channels)+len(change.Posts)+len(change.Stories)+len(change.Tags)+len(change.Chapters)+len(change.Comments))
+ data := make([]interface{}, 0, 8)
for _, log := range change.Logs {
data = append(data, &log)
@@ -59,3 +102,76 @@ func (change *Change) Objects() []interface{} {
return data
}
+
+func (change *Change) PassesFilter(filter ChangeFilter) bool {
+ if filter.PassAll {
+ return true
+ }
+
+ if filter.Author != nil && change.Author != *filter.Author {
+ return false
+ }
+
+ // For unlisted changes, pass it only if the filter refers to the specific index.
+ if !change.Listed {
+ hasSpecificKey := false
+
+ KeyFindLoop:
+ for _, key := range filter.Keys {
+ if key.ID == "*" {
+ continue
+ }
+
+ for _, changeKey := range change.Keys {
+ if changeKey.Model == key.Model && changeKey.ID == key.ID {
+ hasSpecificKey = true
+ break KeyFindLoop
+ }
+ }
+ }
+
+ if !hasSpecificKey {
+ return false
+ }
+ }
+
+ if filter.EarliestDate != nil && filter.EarliestDate.Before(change.Date) {
+ return false
+ }
+
+ if len(filter.Keys) > 0 {
+ foundKey := false
+
+ KeyFindLoop2:
+ for _, key := range filter.Keys {
+ for _, changeKey := range change.Keys {
+ if changeKey == key {
+ foundKey = true
+ break KeyFindLoop2
+ }
+ }
+ }
+
+ if !foundKey {
+ return false
+ }
+ }
+
+ return true
+}
+
+// ChangeKey is a key for a change that can be used when subscribing to them.
+type ChangeKey struct {
+ Model ChangeModel `bson:"model"`
+ ID string `bson:"id"`
+}
+
+// ChangeFilter is a filter for listing changes.
+type ChangeFilter struct {
+ Keys []ChangeKey
+ EarliestDate *time.Time
+ Author *string
+ Limit *int
+
+ PassAll bool // DO NOT EXPOSE
+}
diff --git a/models/changes/db.go b/models/changes/db.go
index 4564511..53eff29 100644
--- a/models/changes/db.go
+++ b/models/changes/db.go
@@ -1,14 +1,11 @@
package changes
import (
- "log"
- "sync"
- "time"
-
"git.aiterp.net/rpdata/api/internal/store"
"git.aiterp.net/rpdata/api/models"
"github.com/globalsign/mgo"
"github.com/globalsign/mgo/bson"
+ "sync"
)
var collection *mgo.Collection
@@ -24,18 +21,5 @@ func list(query bson.M, limit int) ([]models.Change, error) {
func init() {
store.HandleInit(func(db *mgo.Database) {
collection = db.C("common.changes")
-
- collection.EnsureIndexKey("date")
- collection.EnsureIndexKey("author")
- collection.EnsureIndexKey("keys")
-
- err := collection.EnsureIndex(mgo.Index{
- Name: "expiry",
- Key: []string{"date"},
- ExpireAfter: time.Hour * 2400, // 100 days
- })
- if err != nil {
- log.Fatalln(err)
- }
})
}
diff --git a/repositories/change.go b/repositories/change.go
new file mode 100644
index 0000000..0ff3e22
--- /dev/null
+++ b/repositories/change.go
@@ -0,0 +1,13 @@
+package repositories
+
+import (
+ "context"
+ "git.aiterp.net/rpdata/api/models"
+)
+
+type ChangeRepository interface {
+ Find(ctx context.Context, id string) (*models.Change, error)
+ List(ctx context.Context, filter models.ChangeFilter) ([]*models.Change, error)
+ Insert(ctx context.Context, change models.Change) (*models.Change, error)
+ Remove(ctx context.Context, change models.Change) error
+}
diff --git a/repositories/repository.go b/repositories/repository.go
index 3661dfe..1005c9a 100644
--- a/repositories/repository.go
+++ b/repositories/repository.go
@@ -5,6 +5,7 @@ import "errors"
// A Bundle is a set of repositories.
type Bundle struct {
Characters CharacterRepository
+ Changes ChangeRepository
Tags TagRepository
}
diff --git a/services/changes.go b/services/changes.go
new file mode 100644
index 0000000..1b37220
--- /dev/null
+++ b/services/changes.go
@@ -0,0 +1,133 @@
+package services
+
+import (
+ "context"
+ "git.aiterp.net/rpdata/api/internal/auth"
+ "git.aiterp.net/rpdata/api/internal/notifier"
+ "git.aiterp.net/rpdata/api/models"
+ "git.aiterp.net/rpdata/api/repositories"
+ "log"
+ "sync"
+ "time"
+)
+
+type ChangeService struct {
+ changes repositories.ChangeRepository
+
+ mutex sync.RWMutex
+ buffer []models.Change
+ offset uint64
+ notifier notifier.Notifier
+ submitQueue chan *models.Change
+ loopStarted bool
+}
+
+func (s *ChangeService) Find(ctx context.Context, id string) (*models.Change, error) {
+ return s.changes.Find(ctx, id)
+}
+
+func (s *ChangeService) List(ctx context.Context, filter models.ChangeFilter) ([]*models.Change, error) {
+ return s.changes.List(ctx, filter)
+}
+
+func (s *ChangeService) Submit(ctx context.Context, model models.ChangeModel, op string, listed bool, keys []models.ChangeKey, objects ...interface{}) {
+ token := auth.TokenFromContext(ctx)
+ if token == nil {
+ panic("no token!")
+ }
+
+ change := &models.Change{
+ Model: model,
+ Op: op,
+ Author: token.UserID,
+ Listed: listed,
+ Keys: keys,
+ }
+
+ for _, obj := range objects {
+ if !change.AddObject(obj) {
+ log.Printf("Cannot add object of type %T to change", obj)
+ }
+ }
+
+ s.mutex.Lock()
+ if !s.loopStarted {
+ s.loopStarted = true
+ s.submitQueue = make(chan *models.Change, 64)
+ go s.loop()
+ }
+ s.mutex.Unlock()
+
+ s.submitQueue <- change
+}
+
+func (s *ChangeService) Subscribe(ctx context.Context, filter models.ChangeFilter) <-chan *models.Change {
+ channel := make(chan *models.Change)
+
+ go func() {
+ defer close(channel)
+
+ s.mutex.RLock()
+ pos := s.offset + uint64(len(s.buffer))
+ slice := make([]models.Change, 32)
+ s.mutex.RUnlock()
+
+ count := 0
+
+ for {
+ s.mutex.RLock()
+ nextPos := s.offset + uint64(len(s.buffer))
+ length := nextPos - pos
+ if length > 0 {
+ index := pos - s.offset
+
+ pos = nextPos
+ copy(slice, s.buffer[index:])
+ }
+ ch := s.notifier.C()
+ s.mutex.RUnlock()
+
+ for _, change := range slice[:length] {
+ if change.PassesFilter(filter) {
+ channel <- &change
+
+ count++
+ if filter.Limit != nil && count == *filter.Limit {
+ return
+ }
+ }
+ }
+
+ select {
+ case <-ch:
+ case <-ctx.Done():
+ return
+ }
+ }
+ }()
+
+ return channel
+}
+
+func (s *ChangeService) loop() {
+ for change := range s.submitQueue {
+ timeout, cancel := context.WithTimeout(context.Background(), time.Second*15)
+
+ change, err := s.changes.Insert(timeout, *change)
+ if err != nil {
+ log.Println("Failed to submit change:")
+ }
+
+ s.mutex.Lock()
+ s.buffer = append(s.buffer, *change)
+ if len(s.buffer) > 16 {
+ copy(s.buffer, s.buffer[8:])
+ s.buffer = s.buffer[:len(s.buffer)-8]
+ s.offset += 8
+ }
+ s.mutex.Unlock()
+ s.notifier.Broadcast()
+
+ cancel()
+ }
+}
diff --git a/services/characters.go b/services/characters.go
index 067d527..f4431b2 100644
--- a/services/characters.go
+++ b/services/characters.go
@@ -6,7 +6,6 @@ import (
"git.aiterp.net/rpdata/api/internal/auth"
"git.aiterp.net/rpdata/api/models"
"git.aiterp.net/rpdata/api/models/changekeys"
- "git.aiterp.net/rpdata/api/models/changes"
"git.aiterp.net/rpdata/api/repositories"
"git.aiterp.net/rpdata/api/services/loaders"
"sort"
@@ -14,8 +13,9 @@ import (
)
type CharacterService struct {
- characters repositories.CharacterRepository
- loader *loaders.CharacterLoader
+ characters repositories.CharacterRepository
+ loader *loaders.CharacterLoader
+ changeService *ChangeService
}
// Find uses the loader to find the character by the ID.
@@ -101,8 +101,7 @@ func (s *CharacterService) Create(ctx context.Context, nick, name, shortName, au
return nil, err
}
- //TODO: New change submit system
- go changes.Submit("Character", "add", token.UserID, true, changekeys.Listed(character), character)
+ s.changeService.Submit(ctx, "Character", "add", true, changekeys.Listed(character), character)
return character, nil
}
@@ -130,9 +129,7 @@ func (s *CharacterService) Update(ctx context.Context, id string, name, shortNam
s.loader.Clear(character.ID)
s.loader.Prime(character.ID, character)
- //TODO: New change submit system
- token := auth.TokenFromContext(ctx)
- go changes.Submit("Character", "edit", token.UserID, true, changekeys.Listed(character), character)
+ s.changeService.Submit(ctx, "Character", "edit", true, changekeys.Listed(character), character)
return character, nil
}
@@ -153,9 +150,7 @@ func (s *CharacterService) AddNick(ctx context.Context, id string, nick string)
return nil, err
}
- //TODO: New change submit system
- token := auth.TokenFromContext(ctx)
- go changes.Submit("Character", "edit", token.UserID, true, changekeys.Listed(character), character)
+ s.changeService.Submit(ctx, "Character", "edit", true, changekeys.Listed(character), character)
return character, nil
}
@@ -176,9 +171,7 @@ func (s *CharacterService) RemoveNick(ctx context.Context, id string, nick strin
return nil, err
}
- //TODO: New change submit system
- token := auth.TokenFromContext(ctx)
- go changes.Submit("Character", "edit", token.UserID, true, changekeys.Listed(character), character)
+ s.changeService.Submit(ctx, "Character", "edit", true, changekeys.Listed(character), character)
return character, nil
}
@@ -199,9 +192,7 @@ func (s *CharacterService) Delete(ctx context.Context, id string) (*models.Chara
return nil, err
}
- //TODO: New change submit system
- token := auth.TokenFromContext(ctx)
- go changes.Submit("Character", "remove", token.UserID, true, changekeys.Listed(character), character)
+ s.changeService.Submit(ctx, "Character", "remove", true, changekeys.Listed(character), character)
return character, nil
}
diff --git a/services/services.go b/services/services.go
index 45c7f3f..23173c7 100644
--- a/services/services.go
+++ b/services/services.go
@@ -9,16 +9,21 @@ import (
type Bundle struct {
Tags *TagService
Characters *CharacterService
+ Changes *ChangeService
}
// NewBundle creates a new bundle.
func NewBundle(repos *repositories.Bundle) *Bundle {
bundle := &Bundle{}
+ bundle.Changes = &ChangeService{
+ changes: repos.Changes,
+ }
bundle.Tags = &TagService{tags: repos.Tags}
bundle.Characters = &CharacterService{
- characters: repos.Characters,
- loader: loaders.CharacterLoaderFromRepository(repos.Characters),
+ characters: repos.Characters,
+ loader: loaders.CharacterLoaderFromRepository(repos.Characters),
+ changeService: bundle.Changes,
}
return bundle