This commit is contained in:
@@ -1,55 +0,0 @@
|
||||
package logs
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"git.aiterp.net/rpdata/api/internal/counter"
|
||||
"git.aiterp.net/rpdata/api/models"
|
||||
"git.aiterp.net/rpdata/api/models/channels"
|
||||
"github.com/globalsign/mgo/bson"
|
||||
)
|
||||
|
||||
// Add creates a new Log
|
||||
func Add(date time.Time, channelName, title, eventName, description string, open bool) (models.Log, error) {
|
||||
nextID, err := counter.Next("auto_increment", "Log")
|
||||
if err != nil {
|
||||
return models.Log{}, errors.New("Failed to allocate short ID: " + err.Error())
|
||||
}
|
||||
|
||||
_, err = channels.Ensure(channelName, open)
|
||||
if err != nil {
|
||||
return models.Log{}, errors.New("Failed to ensure channel: " + err.Error())
|
||||
}
|
||||
|
||||
log := models.Log{
|
||||
ID: makeLogID(date, channelName),
|
||||
ShortID: "L" + strconv.Itoa(nextID),
|
||||
Date: date,
|
||||
ChannelName: channelName,
|
||||
Title: title,
|
||||
EventName: eventName,
|
||||
Description: description,
|
||||
Open: open,
|
||||
CharacterIDs: nil,
|
||||
}
|
||||
|
||||
err = collection.Insert(log)
|
||||
if err != nil {
|
||||
return models.Log{}, err
|
||||
}
|
||||
|
||||
// There can be only one open log in the same channel. TODO: Transaction
|
||||
if open {
|
||||
query := bson.M{
|
||||
"_id": bson.M{"$ne": log.ID},
|
||||
"open": true,
|
||||
"channel": log.ChannelName,
|
||||
}
|
||||
|
||||
go collection.UpdateAll(query, bson.M{"$set": bson.M{"open": false}})
|
||||
}
|
||||
|
||||
return log, nil
|
||||
}
|
||||
@@ -1,48 +0,0 @@
|
||||
package logs
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"git.aiterp.net/rpdata/api/internal/store"
|
||||
"git.aiterp.net/rpdata/api/models"
|
||||
"github.com/globalsign/mgo"
|
||||
)
|
||||
|
||||
var collection *mgo.Collection
|
||||
var postCollection *mgo.Collection
|
||||
|
||||
func find(query interface{}) (models.Log, error) {
|
||||
log := models.Log{}
|
||||
err := collection.Find(query).One(&log)
|
||||
if err != nil {
|
||||
return models.Log{}, err
|
||||
}
|
||||
|
||||
return log, nil
|
||||
}
|
||||
|
||||
func list(query interface{}, limit int) ([]models.Log, error) {
|
||||
logs := make([]models.Log, 0, 64)
|
||||
err := collection.Find(query).Limit(limit).Sort("-date").All(&logs)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return logs, nil
|
||||
}
|
||||
|
||||
func iter(query interface{}, limit int) *mgo.Iter {
|
||||
return collection.Find(query).Sort("-date").Limit(limit).Batch(8).Iter()
|
||||
}
|
||||
|
||||
func makeLogID(date time.Time, channel string) string {
|
||||
return fmt.Sprintf("%s%03d_%s", date.UTC().Format("2006-01-02_150405"), (date.Nanosecond() / int(time.Millisecond/time.Nanosecond)), channel[1:])
|
||||
}
|
||||
|
||||
func init() {
|
||||
store.HandleInit(func(db *mgo.Database) {
|
||||
collection = db.C("logbot3.logs")
|
||||
postCollection = db.C("logbot3.posts")
|
||||
})
|
||||
}
|
||||
@@ -1,50 +0,0 @@
|
||||
package logs
|
||||
|
||||
import (
|
||||
"git.aiterp.net/rpdata/api/models"
|
||||
"github.com/globalsign/mgo/bson"
|
||||
)
|
||||
|
||||
// Edit sets a log's meta-data.
|
||||
func Edit(log models.Log, title *string, event *string, description *string, open *bool) (models.Log, error) {
|
||||
changes := bson.M{}
|
||||
|
||||
if title != nil && *title != log.Title {
|
||||
changes["title"] = *title
|
||||
log.Title = *title
|
||||
}
|
||||
if event != nil && *event != log.EventName {
|
||||
changes["event"] = *event
|
||||
log.EventName = *event
|
||||
}
|
||||
if description != nil && *description != log.Description {
|
||||
changes["description"] = *description
|
||||
log.Description = *description
|
||||
}
|
||||
if open != nil && *open != log.Open {
|
||||
changes["open"] = *open
|
||||
log.Open = *open
|
||||
}
|
||||
|
||||
if len(changes) == 0 {
|
||||
return log, nil
|
||||
}
|
||||
|
||||
err := collection.UpdateId(log.ID, bson.M{"$set": changes})
|
||||
if err != nil {
|
||||
return models.Log{}, err
|
||||
}
|
||||
|
||||
// There can be only one open log. TODO: Transaction
|
||||
if changes["open"] != nil && *open {
|
||||
query := bson.M{
|
||||
"_id": bson.M{"$ne": log.ID},
|
||||
"open": true,
|
||||
"channel": log.ChannelName,
|
||||
}
|
||||
|
||||
go collection.UpdateAll(query, bson.M{"$set": bson.M{"open": false}})
|
||||
}
|
||||
|
||||
return log, nil
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
package logs
|
||||
|
||||
import (
|
||||
"git.aiterp.net/rpdata/api/models"
|
||||
"github.com/globalsign/mgo/bson"
|
||||
)
|
||||
|
||||
// FindID finds a log either by it's ID or short ID.
|
||||
func FindID(id string) (models.Log, error) {
|
||||
return find(bson.M{
|
||||
"$or": []bson.M{
|
||||
bson.M{"_id": id},
|
||||
bson.M{"shortId": id},
|
||||
},
|
||||
})
|
||||
}
|
||||
@@ -1,70 +0,0 @@
|
||||
package logs
|
||||
|
||||
import (
|
||||
"git.aiterp.net/rpdata/api/models"
|
||||
"github.com/globalsign/mgo/bson"
|
||||
)
|
||||
|
||||
// Filter for the List() function
|
||||
type Filter struct {
|
||||
Search *string
|
||||
Characters *[]string
|
||||
Channels *[]string
|
||||
Events *[]string
|
||||
Open *bool
|
||||
Limit int
|
||||
}
|
||||
|
||||
// List lists all logs
|
||||
func List(filter *Filter) ([]models.Log, error) {
|
||||
query := bson.M{}
|
||||
limit := 0
|
||||
|
||||
if filter != nil {
|
||||
// Run a text search
|
||||
if filter.Search != nil {
|
||||
searchResults, err := search(*filter.Search)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Posts always use shortId to refer to the log
|
||||
query["shortId"] = bson.M{"$in": searchResults}
|
||||
}
|
||||
|
||||
// Find logs including any of the specified events and channels
|
||||
if filter.Channels != nil {
|
||||
query["channel"] = bson.M{"$in": *filter.Channels}
|
||||
}
|
||||
if filter.Events != nil {
|
||||
query["event"] = bson.M{"$in": *filter.Events}
|
||||
}
|
||||
|
||||
// Find logs including all of the specified character IDs.
|
||||
if filter.Characters != nil {
|
||||
query["characterIds"] = bson.M{"$all": *filter.Characters}
|
||||
}
|
||||
|
||||
// Limit to only open logs
|
||||
if filter.Open != nil {
|
||||
query["open"] = *filter.Open
|
||||
}
|
||||
|
||||
// Set the limit from the filter
|
||||
limit = filter.Limit
|
||||
}
|
||||
|
||||
return list(query, limit)
|
||||
}
|
||||
|
||||
func search(text string) ([]string, error) {
|
||||
query := bson.M{
|
||||
"$text": bson.M{"$search": text},
|
||||
"logId": bson.M{"$ne": nil},
|
||||
}
|
||||
|
||||
ids := make([]string, 0, 64)
|
||||
err := postCollection.Find(query).Distinct("logId", &ids)
|
||||
|
||||
return ids, err
|
||||
}
|
||||
@@ -1,22 +0,0 @@
|
||||
package logs
|
||||
|
||||
import (
|
||||
"errors"
|
||||
|
||||
"git.aiterp.net/rpdata/api/models"
|
||||
"git.aiterp.net/rpdata/api/models/posts"
|
||||
)
|
||||
|
||||
// Remove removes the log.
|
||||
func Remove(log models.Log) (models.Log, error) {
|
||||
err := collection.RemoveId(log.ID)
|
||||
if err != nil {
|
||||
return models.Log{}, err
|
||||
}
|
||||
|
||||
if err := posts.RemoveAllInLog(log); err != nil {
|
||||
return models.Log{}, errors.New("The log was removed, but its posts couldn't be: " + err.Error())
|
||||
}
|
||||
|
||||
return log, nil
|
||||
}
|
||||
@@ -1,138 +0,0 @@
|
||||
package logs
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"git.aiterp.net/rpdata/api/internal/task"
|
||||
"git.aiterp.net/rpdata/api/models"
|
||||
"git.aiterp.net/rpdata/api/models/characters"
|
||||
"git.aiterp.net/rpdata/api/models/posts"
|
||||
"git.aiterp.net/rpdata/api/models/unknownnicks"
|
||||
"github.com/globalsign/mgo/bson"
|
||||
)
|
||||
|
||||
var updateTask = task.New(time.Second*60, RunFullUpdate)
|
||||
|
||||
// UpdateCharacters updates the characters for the given log.
|
||||
func UpdateCharacters(log models.Log, unknowns map[string]int) (models.Log, error) {
|
||||
posts, err := posts.List(&posts.Filter{LogID: &log.ShortID, Kind: []string{"action", "text", "chars"}, Limit: 0})
|
||||
if err != nil {
|
||||
return models.Log{}, err
|
||||
}
|
||||
|
||||
counts := make(map[string]int)
|
||||
added := make(map[string]bool)
|
||||
removed := make(map[string]bool)
|
||||
for _, post := range posts {
|
||||
if post.Kind == "text" || post.Kind == "action" {
|
||||
if strings.HasPrefix(post.Text, "(") || strings.Contains(post.Nick, "(") || strings.Contains(post.Nick, "[E]") || strings.HasSuffix(post.Nick, "|") {
|
||||
continue
|
||||
}
|
||||
|
||||
// Clean up the nick (remove possessive suffix, comma, formatting stuff)
|
||||
if strings.HasSuffix(post.Nick, "'s") || strings.HasSuffix(post.Nick, "`s") {
|
||||
post.Nick = post.Nick[:len(post.Nick)-2]
|
||||
} else if strings.HasSuffix(post.Nick, "'") || strings.HasSuffix(post.Nick, "`") || strings.HasSuffix(post.Nick, ",") || strings.HasSuffix(post.Nick, "\x0f") {
|
||||
post.Nick = post.Nick[:len(post.Nick)-1]
|
||||
}
|
||||
|
||||
added[post.Nick] = true
|
||||
counts[post.Nick]++
|
||||
}
|
||||
if post.Kind == "chars" {
|
||||
tokens := strings.Fields(post.Text)
|
||||
for _, token := range tokens {
|
||||
if strings.HasPrefix(token, "-") {
|
||||
removed[token[1:]] = true
|
||||
} else {
|
||||
added[strings.Replace(token, "+", "", 1)] = true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
nicks := make([]string, 0, len(added))
|
||||
for nick := range added {
|
||||
if added[nick] && !removed[nick] {
|
||||
nicks = append(nicks, nick)
|
||||
}
|
||||
}
|
||||
|
||||
characters, err := characters.List(&characters.Filter{Nicks: nicks})
|
||||
if err != nil {
|
||||
return models.Log{}, err
|
||||
}
|
||||
|
||||
characterIDs := make([]string, len(characters))
|
||||
for i, char := range characters {
|
||||
if char.Name == "(Hidden)" {
|
||||
continue
|
||||
}
|
||||
|
||||
characterIDs[i] = char.ID
|
||||
}
|
||||
|
||||
err = collection.UpdateId(log.ID, bson.M{"$set": bson.M{"characterIds": characterIDs}})
|
||||
if err != nil {
|
||||
return models.Log{}, err
|
||||
}
|
||||
|
||||
log.CharacterIDs = characterIDs
|
||||
|
||||
if len(nicks) > 0 && unknowns != nil {
|
||||
NickLoop:
|
||||
for nick := range added {
|
||||
if !added[nick] {
|
||||
continue
|
||||
}
|
||||
|
||||
for _, character := range characters {
|
||||
if character.HasNick(nick) {
|
||||
continue NickLoop
|
||||
}
|
||||
}
|
||||
|
||||
unknowns[nick] += counts[nick]
|
||||
}
|
||||
}
|
||||
|
||||
return log, nil
|
||||
}
|
||||
|
||||
// RunFullUpdate runs a full update on all logs.
|
||||
func RunFullUpdate() error {
|
||||
iter := iter(bson.M{}, 0)
|
||||
err := iter.Err()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
unknowns := make(map[string]int, 256)
|
||||
|
||||
log := models.Log{}
|
||||
for iter.Next(&log) {
|
||||
_, err = UpdateCharacters(log, unknowns)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
err = iter.Err()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = unknownnicks.Update(unknowns)
|
||||
if err != nil {
|
||||
return errors.New("Failed to commit unknown nicks update: " + err.Error())
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// ScheduleFullUpdate runs a full character update within the next 60 seconds.
|
||||
func ScheduleFullUpdate() {
|
||||
updateTask.Schedule()
|
||||
}
|
||||
Reference in New Issue
Block a user