Browse Source
Fixed log service bugs with importing and character list not updating.
thegreatrefactor
Fixed log service bugs with importing and character list not updating.
thegreatrefactor
Gisle Aune
5 years ago
10 changed files with 32 additions and 417 deletions
-
2database/mongodb/posts.go
-
55models/logs/add.go
-
48models/logs/db.go
-
50models/logs/edit.go
-
16models/logs/find.go
-
70models/logs/list.go
-
22models/logs/remove.go
-
138models/logs/update-characters.go
-
5services/channels.go
-
43services/logs.go
@ -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() |
|
||||
} |
|
Write
Preview
Loading…
Cancel
Save
Reference in new issue