If an unsoported lang is setted in the language override the document will fail on inserting in the database, causing it to be lost.
235 lines
5.4 KiB
Go
235 lines
5.4 KiB
Go
package database
|
|
|
|
import (
|
|
log "github.com/cihub/seelog"
|
|
|
|
"strings"
|
|
"time"
|
|
|
|
"gopkg.in/mgo.v2"
|
|
"gopkg.in/mgo.v2/bson"
|
|
)
|
|
|
|
const (
|
|
books_coll = "books"
|
|
)
|
|
|
|
type Book struct {
|
|
Id string
|
|
Title string
|
|
Author []string
|
|
Contributor string
|
|
Publisher string
|
|
Description string
|
|
Subject []string
|
|
Date string
|
|
Lang []string
|
|
Isbn string
|
|
Type string
|
|
Format string
|
|
Source string
|
|
Relation string
|
|
Coverage string
|
|
Rights string
|
|
Meta string
|
|
FileSize int
|
|
Cover bool
|
|
Active bool
|
|
BadQuality int `bad_quality`
|
|
BadQualityReporters []string `bad_quality_reporters`
|
|
}
|
|
|
|
type history struct {
|
|
Date time.Time
|
|
Changes bson.M
|
|
}
|
|
|
|
func indexBooks(coll *mgo.Collection) {
|
|
indexes := []mgo.Index{
|
|
{
|
|
Key: []string{"id"},
|
|
Unique: true,
|
|
Background: true,
|
|
},
|
|
{
|
|
Key: []string{"active", "-_id"},
|
|
Background: true,
|
|
},
|
|
{
|
|
Key: []string{"active", "-bad_quality", "-_id"},
|
|
Background: true,
|
|
},
|
|
{
|
|
Key: []string{"$text:title", "$text:author", "$text:contributor",
|
|
"$text:publisher", "$text:subject", "$text:description"},
|
|
Weights: map[string]int{"title": 20, "author": 20, "contributor": 15,
|
|
"publisher": 15, "subject": 10, "description": 5},
|
|
|
|
LanguageOverride: "_lang",
|
|
Background: true,
|
|
},
|
|
}
|
|
for _, k := range []string{"lang", "title", "author", "subject"} {
|
|
idx := mgo.Index{
|
|
Key: []string{"active", k, "-_id"},
|
|
Background: true,
|
|
}
|
|
indexes = append(indexes, idx)
|
|
}
|
|
|
|
for _, idx := range indexes {
|
|
err := coll.EnsureIndex(idx)
|
|
if err != nil {
|
|
log.Error("Error indexing books: ", err)
|
|
}
|
|
}
|
|
}
|
|
|
|
func addBook(coll *mgo.Collection, book map[string]interface{}) error {
|
|
book["_lang"] = metadataLang(book)
|
|
return coll.Insert(book)
|
|
}
|
|
|
|
func getBooks(coll *mgo.Collection, query string, length int, start int) (books []Book, num int, err error) {
|
|
return _getBooks(coll, buildQuery(query), length, start)
|
|
}
|
|
|
|
func getNewBooks(coll *mgo.Collection, length int, start int) (books []Book, num int, err error) {
|
|
return _getBooks(coll, bson.M{"$nor": []bson.M{{"active": true}}}, length, start)
|
|
}
|
|
|
|
func getBooksIter(coll *mgo.Collection, query string) Iter {
|
|
q := getBookQuery(coll, buildQuery(query))
|
|
return q.Iter()
|
|
}
|
|
|
|
func _getBooks(coll *mgo.Collection, query bson.M, length int, start int) (books []Book, num int, err error) {
|
|
q := getBookQuery(coll, query)
|
|
num, err = q.Count()
|
|
if err != nil {
|
|
return
|
|
}
|
|
if start != 0 {
|
|
q = q.Skip(start)
|
|
}
|
|
if length != 0 {
|
|
q = q.Limit(length)
|
|
}
|
|
|
|
err = q.All(&books)
|
|
return
|
|
}
|
|
|
|
func getBookQuery(coll *mgo.Collection, query bson.M) *mgo.Query {
|
|
sort := []string{"$textScore:score"}
|
|
if _, present := query["bad_quality"]; present {
|
|
sort = append(sort, "-bad_quality")
|
|
}
|
|
sort = append(sort, "-_id")
|
|
|
|
return coll.Find(query).Select(bson.M{"score": bson.M{"$meta": "textScore"}}).Sort(sort...)
|
|
}
|
|
|
|
func getBookId(coll *mgo.Collection, id string) (Book, error) {
|
|
var book Book
|
|
err := coll.Find(bson.M{"id": id}).One(&book)
|
|
return book, err
|
|
}
|
|
|
|
func deleteBook(coll *mgo.Collection, id string) error {
|
|
return coll.Remove(bson.M{"id": id})
|
|
}
|
|
|
|
func updateBook(coll *mgo.Collection, id string, data map[string]interface{}) error {
|
|
var book map[string]interface{}
|
|
record := history{time.Now(), bson.M{}}
|
|
|
|
err := coll.Find(bson.M{"id": id}).One(&book)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
for k, _ := range data {
|
|
record.Changes[k] = book[k]
|
|
if k == "lang" {
|
|
data["_lang"] = metadataLang(data)
|
|
}
|
|
}
|
|
|
|
return coll.Update(bson.M{"id": id}, bson.M{"$set": data, "$push": bson.M{"history": record}})
|
|
}
|
|
|
|
func flagBadQuality(coll *mgo.Collection, id string, user string) error {
|
|
b, err := getBookId(coll, id)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
for _, reporter := range b.BadQualityReporters {
|
|
if reporter == user {
|
|
return nil
|
|
}
|
|
}
|
|
return coll.Update(
|
|
bson.M{"id": id},
|
|
bson.M{
|
|
"$inc": bson.M{"bad_quality": 1},
|
|
"$addToSet": bson.M{"bad_quality_reporters": user},
|
|
},
|
|
)
|
|
}
|
|
|
|
func activeBook(coll *mgo.Collection, id string) error {
|
|
data := map[string]interface{}{"active": true}
|
|
return coll.Update(bson.M{"id": id}, bson.M{"$set": data})
|
|
}
|
|
|
|
func isBookActive(coll *mgo.Collection, id string) bool {
|
|
var book Book
|
|
err := coll.Find(bson.M{"id": id}).One(&book)
|
|
if err != nil {
|
|
return false
|
|
}
|
|
return book.Active
|
|
}
|
|
|
|
func buildQuery(q string) bson.M {
|
|
text := ""
|
|
query := bson.M{"active": true}
|
|
words := strings.Split(q, " ")
|
|
for _, w := range words {
|
|
tag := strings.SplitN(w, ":", 2)
|
|
if len(tag) > 1 {
|
|
if tag[0] == "flag" {
|
|
query[tag[1]] = bson.M{"$gt": 0}
|
|
} else {
|
|
query[tag[0]] = bson.RegEx{tag[1], "i"} //FIXME: this should be a list
|
|
}
|
|
} else {
|
|
if len(text) != 0 {
|
|
text += " "
|
|
}
|
|
text += w
|
|
}
|
|
}
|
|
if len(text) > 0 {
|
|
query["$text"] = bson.M{"$search": text}
|
|
}
|
|
return query
|
|
}
|
|
|
|
func metadataLang(book map[string]interface{}) string {
|
|
text_search_langs := map[string]bool{
|
|
"da": true, "nl": true, "en": true, "fi": true, "fr": true, "de": true,
|
|
"hu": true, "it": true, "nb": true, "pt": true, "ro": true, "ru": true,
|
|
"es": true, "sv": true, "tr": true}
|
|
|
|
lang, ok := book["lang"].([]string)
|
|
if !ok || len(lang) == 0 || len(lang[0]) < 2 {
|
|
return "none"
|
|
}
|
|
lcode := strings.ToLower(lang[0][0:2])
|
|
if text_search_langs[lcode] {
|
|
return lcode
|
|
}
|
|
return "none"
|
|
}
|