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.
215 lines
5.0 KiB
215 lines
5.0 KiB
package mongodb
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"git.aiterp.net/rpdata/api/internal/generate"
|
|
"git.aiterp.net/rpdata/api/models"
|
|
"github.com/globalsign/mgo"
|
|
"github.com/globalsign/mgo/bson"
|
|
"strconv"
|
|
"sync"
|
|
)
|
|
|
|
type logRepository struct {
|
|
openMutex sync.Mutex
|
|
restoreIds bool
|
|
|
|
logs *mgo.Collection
|
|
posts *mgo.Collection
|
|
shortIdCounter *counter
|
|
}
|
|
|
|
func newLogRepository(db *mgo.Database, restoreIds bool) (*logRepository, error) {
|
|
logs := db.C("logbot3.logs")
|
|
posts := db.C("logbot3.posts")
|
|
|
|
err := logs.EnsureIndexKey("date")
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
err = logs.EnsureIndexKey("channel")
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
err = logs.EnsureIndexKey("characterIds")
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
err = logs.EnsureIndexKey("event")
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
err = logs.EnsureIndex(mgo.Index{Key: []string{"channel", "open"}})
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
err = logs.EnsureIndex(mgo.Index{
|
|
Key: []string{"shortId"},
|
|
Unique: true,
|
|
DropDups: true,
|
|
})
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return &logRepository{
|
|
restoreIds: restoreIds,
|
|
logs: logs,
|
|
posts: posts,
|
|
shortIdCounter: newCounter(db, "auto_increment", "Log"),
|
|
}, nil
|
|
}
|
|
|
|
func (r *logRepository) Find(ctx context.Context, id string) (*models.Log, error) {
|
|
log := new(models.Log)
|
|
err := r.logs.Find(bson.M{"$or": []bson.M{{"_id": id}, {"shortId": id}}}).One(log)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return log, nil
|
|
}
|
|
|
|
func (r *logRepository) List(ctx context.Context, filter models.LogFilter) ([]*models.Log, error) {
|
|
query := bson.M{}
|
|
if filter.Search != nil {
|
|
searchQuery := bson.M{
|
|
"$text": bson.M{"$search": *filter.Search},
|
|
"logId": bson.M{"$ne": nil},
|
|
}
|
|
|
|
logIds := make([]string, 0, 64)
|
|
err := r.posts.Find(searchQuery).Distinct("logId", &logIds)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
query["shortId"] = bson.M{"$in": logIds}
|
|
}
|
|
if filter.Open != nil {
|
|
r.openMutex.Lock()
|
|
defer r.openMutex.Unlock()
|
|
|
|
query["open"] = filter.Open
|
|
}
|
|
if len(filter.Characters) > 0 {
|
|
query["characterIds"] = bson.M{"$all": filter.Characters}
|
|
}
|
|
if len(filter.Channels) > 0 {
|
|
query["channel"] = bson.M{"$in": filter.Channels}
|
|
}
|
|
if len(filter.Events) > 0 {
|
|
query["event"] = bson.M{"$in": filter.Events}
|
|
}
|
|
if filter.MinDate != nil && filter.MaxDate != nil {
|
|
query["date"] = bson.M{"$gte": *filter.MinDate, "$lte": *filter.MaxDate}
|
|
} else if filter.MinDate != nil {
|
|
query["date"] = bson.M{"$gte": *filter.MinDate}
|
|
} else if filter.MaxDate != nil {
|
|
query["date"] = bson.M{"$lt": *filter.MaxDate}
|
|
}
|
|
|
|
logs := make([]*models.Log, 0, 32)
|
|
err := r.logs.Find(query).Sort("-date").Limit(filter.Limit).All(&logs)
|
|
if err != nil {
|
|
if err == mgo.ErrNotFound {
|
|
return logs, nil
|
|
}
|
|
|
|
return nil, err
|
|
}
|
|
|
|
return logs, nil
|
|
}
|
|
|
|
func (r *logRepository) Insert(ctx context.Context, log models.Log) (*models.Log, error) {
|
|
if !r.restoreIds || log.ID == "" || log.ShortID == "" {
|
|
nextShortId, err := r.shortIdCounter.Increment(1)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
log.ID = generate.LogID(log)
|
|
log.ShortID = "L" + strconv.Itoa(nextShortId)
|
|
} else {
|
|
n, err := strconv.Atoi(log.ShortID[1:])
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
_ = r.shortIdCounter.Bump(n)
|
|
}
|
|
|
|
if log.Open {
|
|
// There can be only one open log in the same channel.
|
|
r.openMutex.Lock()
|
|
defer r.openMutex.Unlock()
|
|
|
|
_, err := r.logs.UpdateAll(bson.M{"channel": log.ChannelName, "open": true}, bson.M{"$set": bson.M{"open": false}})
|
|
if err != nil {
|
|
return nil, errors.New("Cannot close other logs: " + err.Error())
|
|
}
|
|
}
|
|
|
|
err := r.logs.Insert(&log)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return &log, nil
|
|
}
|
|
|
|
func (r *logRepository) Update(ctx context.Context, log models.Log, update models.LogUpdate) (*models.Log, error) {
|
|
updateBson := bson.M{}
|
|
if update.Open != nil {
|
|
if *update.Open == true {
|
|
// There can be only one open log in the same channel.
|
|
r.openMutex.Lock()
|
|
defer r.openMutex.Unlock()
|
|
|
|
_, err := r.logs.UpdateAll(bson.M{"channel": log.ChannelName, "open": true}, bson.M{"$set": bson.M{"open": false}})
|
|
if err != nil {
|
|
return nil, errors.New("Cannot close other logs: " + err.Error())
|
|
}
|
|
}
|
|
|
|
updateBson["open"] = *update.Open
|
|
log.Open = *update.Open
|
|
}
|
|
if update.Title != nil {
|
|
updateBson["title"] = *update.Title
|
|
log.Title = *update.Title
|
|
}
|
|
if update.Description != nil {
|
|
updateBson["description"] = *update.Description
|
|
log.Description = *update.Description
|
|
}
|
|
if update.EventName != nil {
|
|
updateBson["event"] = *update.EventName
|
|
log.EventName = *update.EventName
|
|
}
|
|
if update.CharacterIDs != nil {
|
|
updateBson["characterIds"] = update.CharacterIDs
|
|
log.CharacterIDs = update.CharacterIDs
|
|
}
|
|
|
|
err := r.logs.UpdateId(log.ID, bson.M{"$set": updateBson})
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return &log, nil
|
|
}
|
|
|
|
func (r *logRepository) Delete(ctx context.Context, log models.Log) error {
|
|
err := r.logs.RemoveId(log.ID)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
_, _ = r.posts.RemoveAll(bson.M{"logId": log.ShortID})
|
|
|
|
return nil
|
|
}
|