Merge branch 'master' into user
Conflicts: admin.go template.go trantor.go
This commit is contained in:
commit
8e3b929dfe
22 changed files with 1015 additions and 385 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -7,5 +7,6 @@ tools/update/update
|
||||||
tools/togridfs/togridfs
|
tools/togridfs/togridfs
|
||||||
tools/getISBNnDesc/getISBNnDesc
|
tools/getISBNnDesc/getISBNnDesc
|
||||||
tools/coverNew/coverNew
|
tools/coverNew/coverNew
|
||||||
|
tools/addsize/addsize
|
||||||
tags
|
tags
|
||||||
.*.swp
|
.*.swp
|
||||||
|
|
122
admin.go
122
admin.go
|
@ -9,29 +9,29 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
func deleteHandler(w http.ResponseWriter, r *http.Request, sess *Session) {
|
func deleteHandler(h handler) {
|
||||||
if !sess.IsAdmin() {
|
if !h.sess.IsAdmin() {
|
||||||
notFound(w, r)
|
notFound(h)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
var titles []string
|
var titles []string
|
||||||
var isNew bool
|
var isNew bool
|
||||||
ids := strings.Split(mux.Vars(r)["ids"], "/")
|
ids := strings.Split(mux.Vars(h.r)["ids"], "/")
|
||||||
for _, idStr := range ids {
|
for _, idStr := range ids {
|
||||||
if !bson.IsObjectIdHex(idStr) {
|
if !bson.IsObjectIdHex(idStr) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
id := bson.ObjectIdHex(idStr)
|
id := bson.ObjectIdHex(idStr)
|
||||||
books, _, err := db.GetBooks(bson.M{"_id": id})
|
books, _, err := h.db.GetBooks(bson.M{"_id": id})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
sess.Notify("Book not found!", "The book with id '"+idStr+"' is not there", "error")
|
h.sess.Notify("Book not found!", "The book with id '"+idStr+"' is not there", "error")
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
book := books[0]
|
book := books[0]
|
||||||
DeleteBook(book)
|
DeleteBook(book, h.db)
|
||||||
db.RemoveBook(id)
|
h.db.RemoveBook(id)
|
||||||
|
|
||||||
if !book.Active {
|
if !book.Active {
|
||||||
isNew = true
|
isNew = true
|
||||||
|
@ -39,33 +39,33 @@ func deleteHandler(w http.ResponseWriter, r *http.Request, sess *Session) {
|
||||||
titles = append(titles, book.Title)
|
titles = append(titles, book.Title)
|
||||||
}
|
}
|
||||||
if titles != nil {
|
if titles != nil {
|
||||||
sess.Notify("Removed books!", "The books "+strings.Join(titles, ", ")+" are completly removed", "success")
|
h.sess.Notify("Removed books!", "The books "+strings.Join(titles, ", ")+" are completly removed", "success")
|
||||||
}
|
}
|
||||||
sess.Save(w, r)
|
h.sess.Save(h.w, h.r)
|
||||||
if isNew {
|
if isNew {
|
||||||
http.Redirect(w, r, "/new/", http.StatusFound)
|
http.Redirect(h.w, h.r, "/new/", http.StatusFound)
|
||||||
} else {
|
} else {
|
||||||
http.Redirect(w, r, "/", http.StatusFound)
|
http.Redirect(h.w, h.r, "/", http.StatusFound)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func editHandler(w http.ResponseWriter, r *http.Request, sess *Session) {
|
func editHandler(h handler) {
|
||||||
idStr := mux.Vars(r)["id"]
|
idStr := mux.Vars(h.r)["id"]
|
||||||
if !sess.IsAdmin() || !bson.IsObjectIdHex(idStr) {
|
if !h.sess.IsAdmin() || !bson.IsObjectIdHex(idStr) {
|
||||||
notFound(w, r)
|
notFound(h)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
id := bson.ObjectIdHex(idStr)
|
id := bson.ObjectIdHex(idStr)
|
||||||
books, _, err := db.GetBooks(bson.M{"_id": id})
|
books, _, err := h.db.GetBooks(bson.M{"_id": id})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
notFound(w, r)
|
notFound(h)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
var data bookData
|
var data bookData
|
||||||
data.Book = books[0]
|
data.Book = books[0]
|
||||||
data.S = GetStatus(w, r)
|
data.S = GetStatus(h)
|
||||||
loadTemplate(w, "edit", data)
|
loadTemplate(h.w, "edit", data)
|
||||||
}
|
}
|
||||||
|
|
||||||
func cleanEmptyStr(s []string) []string {
|
func cleanEmptyStr(s []string) []string {
|
||||||
|
@ -78,21 +78,21 @@ func cleanEmptyStr(s []string) []string {
|
||||||
return res
|
return res
|
||||||
}
|
}
|
||||||
|
|
||||||
func saveHandler(w http.ResponseWriter, r *http.Request, sess *Session) {
|
func saveHandler(h handler) {
|
||||||
idStr := mux.Vars(r)["id"]
|
idStr := mux.Vars(h.r)["id"]
|
||||||
if !sess.IsAdmin() || !bson.IsObjectIdHex(idStr) {
|
if !h.sess.IsAdmin() || !bson.IsObjectIdHex(idStr) {
|
||||||
notFound(w, r)
|
notFound(h)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
id := bson.ObjectIdHex(idStr)
|
id := bson.ObjectIdHex(idStr)
|
||||||
title := r.FormValue("title")
|
title := h.r.FormValue("title")
|
||||||
publisher := r.FormValue("publisher")
|
publisher := h.r.FormValue("publisher")
|
||||||
date := r.FormValue("date")
|
date := h.r.FormValue("date")
|
||||||
description := r.FormValue("description")
|
description := h.r.FormValue("description")
|
||||||
author := cleanEmptyStr(r.Form["author"])
|
author := cleanEmptyStr(h.r.Form["author"])
|
||||||
subject := cleanEmptyStr(r.Form["subject"])
|
subject := cleanEmptyStr(h.r.Form["subject"])
|
||||||
lang := cleanEmptyStr(r.Form["lang"])
|
lang := cleanEmptyStr(h.r.Form["lang"])
|
||||||
book := map[string]interface{}{"title": title,
|
book := map[string]interface{}{"title": title,
|
||||||
"publisher": publisher,
|
"publisher": publisher,
|
||||||
"date": date,
|
"date": date,
|
||||||
|
@ -101,18 +101,18 @@ func saveHandler(w http.ResponseWriter, r *http.Request, sess *Session) {
|
||||||
"subject": subject,
|
"subject": subject,
|
||||||
"lang": lang}
|
"lang": lang}
|
||||||
book["keywords"] = keywords(book)
|
book["keywords"] = keywords(book)
|
||||||
err := db.UpdateBook(id, book)
|
err := h.db.UpdateBook(id, book)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
notFound(w, r)
|
notFound(h)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
sess.Notify("Book Modified!", "", "success")
|
h.sess.Notify("Book Modified!", "", "success")
|
||||||
sess.Save(w, r)
|
h.sess.Save(h.w, h.r)
|
||||||
if db.BookActive(id) {
|
if h.db.BookActive(id) {
|
||||||
http.Redirect(w, r, "/book/"+idStr, http.StatusFound)
|
http.Redirect(h.w, h.r, "/book/"+idStr, http.StatusFound)
|
||||||
} else {
|
} else {
|
||||||
http.Redirect(w, r, "/new/", http.StatusFound)
|
http.Redirect(h.w, h.r, "/new/", http.StatusFound)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -130,28 +130,28 @@ type newData struct {
|
||||||
Prev string
|
Prev string
|
||||||
}
|
}
|
||||||
|
|
||||||
func newHandler(w http.ResponseWriter, r *http.Request, sess *Session) {
|
func newHandler(h handler) {
|
||||||
if !sess.IsAdmin() {
|
if !h.sess.IsAdmin() {
|
||||||
notFound(w, r)
|
notFound(h)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
err := r.ParseForm()
|
err := h.r.ParseForm()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
http.Error(h.w, err.Error(), http.StatusInternalServerError)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
page := 0
|
page := 0
|
||||||
if len(r.Form["p"]) != 0 {
|
if len(h.r.Form["p"]) != 0 {
|
||||||
page, err = strconv.Atoi(r.Form["p"][0])
|
page, err = strconv.Atoi(h.r.Form["p"][0])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
page = 0
|
page = 0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
res, num, _ := db.GetNewBooks(NEW_ITEMS_PAGE, page*NEW_ITEMS_PAGE)
|
res, num, _ := h.db.GetNewBooks(NEW_ITEMS_PAGE, page*NEW_ITEMS_PAGE)
|
||||||
|
|
||||||
var data newData
|
var data newData
|
||||||
data.S = GetStatus(w, r)
|
data.S = GetStatus(h)
|
||||||
data.Found = num
|
data.Found = num
|
||||||
if num-NEW_ITEMS_PAGE*page < NEW_ITEMS_PAGE {
|
if num-NEW_ITEMS_PAGE*page < NEW_ITEMS_PAGE {
|
||||||
data.Books = make([]newBook, num-NEW_ITEMS_PAGE*page)
|
data.Books = make([]newBook, num-NEW_ITEMS_PAGE*page)
|
||||||
|
@ -160,8 +160,8 @@ func newHandler(w http.ResponseWriter, r *http.Request, sess *Session) {
|
||||||
}
|
}
|
||||||
for i, b := range res {
|
for i, b := range res {
|
||||||
data.Books[i].B = b
|
data.Books[i].B = b
|
||||||
_, data.Books[i].TitleFound, _ = db.GetBooks(buildQuery("title:"+b.Title), 1)
|
_, data.Books[i].TitleFound, _ = h.db.GetBooks(buildQuery("title:"+b.Title), 1)
|
||||||
_, data.Books[i].AuthorFound, _ = db.GetBooks(buildQuery("author:"+strings.Join(b.Author, " author:")), 1)
|
_, data.Books[i].AuthorFound, _ = h.db.GetBooks(buildQuery("author:"+strings.Join(b.Author, " author:")), 1)
|
||||||
}
|
}
|
||||||
data.Page = page + 1
|
data.Page = page + 1
|
||||||
if num > (page+1)*NEW_ITEMS_PAGE {
|
if num > (page+1)*NEW_ITEMS_PAGE {
|
||||||
|
@ -170,40 +170,40 @@ func newHandler(w http.ResponseWriter, r *http.Request, sess *Session) {
|
||||||
if page > 0 {
|
if page > 0 {
|
||||||
data.Prev = "/new/?p=" + strconv.Itoa(page-1)
|
data.Prev = "/new/?p=" + strconv.Itoa(page-1)
|
||||||
}
|
}
|
||||||
loadTemplate(w, "new", data)
|
loadTemplate(h.w, "new", data)
|
||||||
}
|
}
|
||||||
|
|
||||||
func storeHandler(w http.ResponseWriter, r *http.Request, sess *Session) {
|
func storeHandler(h handler) {
|
||||||
if !sess.IsAdmin() {
|
if !h.sess.IsAdmin() {
|
||||||
notFound(w, r)
|
notFound(h)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
var titles []string
|
var titles []string
|
||||||
ids := strings.Split(mux.Vars(r)["ids"], "/")
|
ids := strings.Split(mux.Vars(h.r)["ids"], "/")
|
||||||
for _, idStr := range ids {
|
for _, idStr := range ids {
|
||||||
if !bson.IsObjectIdHex(idStr) {
|
if !bson.IsObjectIdHex(idStr) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
id := bson.ObjectIdHex(idStr)
|
id := bson.ObjectIdHex(idStr)
|
||||||
books, _, err := db.GetBooks(bson.M{"_id": id})
|
books, _, err := h.db.GetBooks(bson.M{"_id": id})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
sess.Notify("Book not found!", "The book with id '"+idStr+"' is not there", "error")
|
h.sess.Notify("Book not found!", "The book with id '"+idStr+"' is not there", "error")
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
book := books[0]
|
book := books[0]
|
||||||
if err != nil {
|
if err != nil {
|
||||||
sess.Notify("An error ocurred!", err.Error(), "error")
|
h.sess.Notify("An error ocurred!", err.Error(), "error")
|
||||||
log.Println("Error storing book '", book.Title, "': ", err.Error())
|
log.Println("Error storing book '", book.Title, "': ", err.Error())
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
db.UpdateBook(id, bson.M{"active": true})
|
h.db.UpdateBook(id, bson.M{"active": true})
|
||||||
titles = append(titles, book.Title)
|
titles = append(titles, book.Title)
|
||||||
}
|
}
|
||||||
if titles != nil {
|
if titles != nil {
|
||||||
sess.Notify("Store books!", "The books '"+strings.Join(titles, ", ")+"' are stored for public download", "success")
|
h.sess.Notify("Store books!", "The books '"+strings.Join(titles, ", ")+"' are stored for public download", "success")
|
||||||
}
|
}
|
||||||
sess.Save(w, r)
|
h.sess.Save(h.w, h.r)
|
||||||
http.Redirect(w, r, "/new/", http.StatusFound)
|
http.Redirect(h.w, h.r, "/new/", http.StatusFound)
|
||||||
}
|
}
|
||||||
|
|
48
cover.go
48
cover.go
|
@ -16,34 +16,32 @@ import (
|
||||||
"labix.org/v2/mgo"
|
"labix.org/v2/mgo"
|
||||||
"labix.org/v2/mgo/bson"
|
"labix.org/v2/mgo/bson"
|
||||||
"log"
|
"log"
|
||||||
"net/http"
|
|
||||||
"regexp"
|
"regexp"
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
func coverHandler(w http.ResponseWriter, r *http.Request) {
|
func coverHandler(h handler) {
|
||||||
vars := mux.Vars(r)
|
vars := mux.Vars(h.r)
|
||||||
if !bson.IsObjectIdHex(vars["id"]) {
|
if !bson.IsObjectIdHex(vars["id"]) {
|
||||||
notFound(w, r)
|
notFound(h)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
id := bson.ObjectIdHex(vars["id"])
|
id := bson.ObjectIdHex(vars["id"])
|
||||||
books, _, err := db.GetBooks(bson.M{"_id": id})
|
books, _, err := h.db.GetBooks(bson.M{"_id": id})
|
||||||
if err != nil || len(books) == 0 {
|
if err != nil || len(books) == 0 {
|
||||||
notFound(w, r)
|
notFound(h)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
book := books[0]
|
book := books[0]
|
||||||
|
|
||||||
if !book.Active {
|
if !book.Active {
|
||||||
sess := GetSession(r)
|
if !h.sess.IsAdmin() {
|
||||||
if !sess.IsAdmin() {
|
notFound(h)
|
||||||
notFound(w, r)
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fs := db.GetFS(FS_IMGS)
|
fs := h.db.GetFS(FS_IMGS)
|
||||||
var f *mgo.GridFile
|
var f *mgo.GridFile
|
||||||
if vars["size"] == "small" {
|
if vars["size"] == "small" {
|
||||||
f, err = fs.OpenId(book.CoverSmall)
|
f, err = fs.OpenId(book.CoverSmall)
|
||||||
|
@ -52,24 +50,24 @@ func coverHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Println("Error while opening image:", err)
|
log.Println("Error while opening image:", err)
|
||||||
notFound(w, r)
|
notFound(h)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
defer f.Close()
|
defer f.Close()
|
||||||
|
|
||||||
headers := w.Header()
|
headers := h.w.Header()
|
||||||
headers["Content-Type"] = []string{"image/jpeg"}
|
headers["Content-Type"] = []string{"image/jpeg"}
|
||||||
|
|
||||||
io.Copy(w, f)
|
io.Copy(h.w, f)
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetCover(e *epubgo.Epub, title string) (bson.ObjectId, bson.ObjectId) {
|
func GetCover(e *epubgo.Epub, title string, db *DB) (bson.ObjectId, bson.ObjectId) {
|
||||||
imgId, smallId := coverFromMetadata(e, title)
|
imgId, smallId := coverFromMetadata(e, title, db)
|
||||||
if imgId != "" {
|
if imgId != "" {
|
||||||
return imgId, smallId
|
return imgId, smallId
|
||||||
}
|
}
|
||||||
|
|
||||||
imgId, smallId = searchCommonCoverNames(e, title)
|
imgId, smallId = searchCommonCoverNames(e, title, db)
|
||||||
if imgId != "" {
|
if imgId != "" {
|
||||||
return imgId, smallId
|
return imgId, smallId
|
||||||
}
|
}
|
||||||
|
@ -110,7 +108,7 @@ func GetCover(e *epubgo.Epub, title string) (bson.ObjectId, bson.ObjectId) {
|
||||||
img, err := e.OpenFile(url)
|
img, err := e.OpenFile(url)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
defer img.Close()
|
defer img.Close()
|
||||||
return storeImg(img, title)
|
return storeImg(img, title, db)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
errNext = it.Next()
|
errNext = it.Next()
|
||||||
|
@ -118,41 +116,41 @@ func GetCover(e *epubgo.Epub, title string) (bson.ObjectId, bson.ObjectId) {
|
||||||
return "", ""
|
return "", ""
|
||||||
}
|
}
|
||||||
|
|
||||||
func coverFromMetadata(e *epubgo.Epub, title string) (bson.ObjectId, bson.ObjectId) {
|
func coverFromMetadata(e *epubgo.Epub, title string, db *DB) (bson.ObjectId, bson.ObjectId) {
|
||||||
metaList, _ := e.MetadataAttr("meta")
|
metaList, _ := e.MetadataAttr("meta")
|
||||||
for _, meta := range metaList {
|
for _, meta := range metaList {
|
||||||
if meta["name"] == "cover" {
|
if meta["name"] == "cover" {
|
||||||
img, err := e.OpenFileId(meta["content"])
|
img, err := e.OpenFileId(meta["content"])
|
||||||
if err == nil {
|
if err == nil {
|
||||||
defer img.Close()
|
defer img.Close()
|
||||||
return storeImg(img, title)
|
return storeImg(img, title, db)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return "", ""
|
return "", ""
|
||||||
}
|
}
|
||||||
|
|
||||||
func searchCommonCoverNames(e *epubgo.Epub, title string) (bson.ObjectId, bson.ObjectId) {
|
func searchCommonCoverNames(e *epubgo.Epub, title string, db *DB) (bson.ObjectId, bson.ObjectId) {
|
||||||
for _, p := range []string{"cover.jpg", "Images/cover.jpg", "images/cover.jpg", "cover.jpeg", "cover1.jpg", "cover1.jpeg"} {
|
for _, p := range []string{"cover.jpg", "Images/cover.jpg", "images/cover.jpg", "cover.jpeg", "cover1.jpg", "cover1.jpeg"} {
|
||||||
img, err := e.OpenFile(p)
|
img, err := e.OpenFile(p)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
defer img.Close()
|
defer img.Close()
|
||||||
return storeImg(img, title)
|
return storeImg(img, title, db)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return "", ""
|
return "", ""
|
||||||
}
|
}
|
||||||
|
|
||||||
func storeImg(img io.Reader, title string) (bson.ObjectId, bson.ObjectId) {
|
func storeImg(img io.Reader, title string, db *DB) (bson.ObjectId, bson.ObjectId) {
|
||||||
/* open the files */
|
/* open the files */
|
||||||
fBig, err := createCoverFile(title)
|
fBig, err := createCoverFile(title, db)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Println("Error creating", title, ":", err.Error())
|
log.Println("Error creating", title, ":", err.Error())
|
||||||
return "", ""
|
return "", ""
|
||||||
}
|
}
|
||||||
defer fBig.Close()
|
defer fBig.Close()
|
||||||
|
|
||||||
fSmall, err := createCoverFile(title + "_small")
|
fSmall, err := createCoverFile(title+"_small", db)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Println("Error creating", title+"_small", ":", err.Error())
|
log.Println("Error creating", title+"_small", ":", err.Error())
|
||||||
return "", ""
|
return "", ""
|
||||||
|
@ -189,7 +187,7 @@ func storeImg(img io.Reader, title string) (bson.ObjectId, bson.ObjectId) {
|
||||||
return idBig, idSmall
|
return idBig, idSmall
|
||||||
}
|
}
|
||||||
|
|
||||||
func createCoverFile(title string) (*mgo.GridFile, error) {
|
func createCoverFile(title string, db *DB) (*mgo.GridFile, error) {
|
||||||
fs := db.GetFS(FS_IMGS)
|
fs := db.GetFS(FS_IMGS)
|
||||||
return fs.Create(title + ".jpg")
|
return fs.Create(title + ".jpg")
|
||||||
}
|
}
|
||||||
|
|
87
database.go
87
database.go
|
@ -7,8 +7,6 @@ import (
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
var db *DB
|
|
||||||
|
|
||||||
type Book struct {
|
type Book struct {
|
||||||
Id string `bson:"_id"`
|
Id string `bson:"_id"`
|
||||||
Title string
|
Title string
|
||||||
|
@ -28,6 +26,7 @@ type Book struct {
|
||||||
Rights string
|
Rights string
|
||||||
Meta string
|
Meta string
|
||||||
File bson.ObjectId
|
File bson.ObjectId
|
||||||
|
FileSize int
|
||||||
Cover bson.ObjectId
|
Cover bson.ObjectId
|
||||||
CoverSmall bson.ObjectId
|
CoverSmall bson.ObjectId
|
||||||
Active bool
|
Active bool
|
||||||
|
@ -41,11 +40,6 @@ type News struct {
|
||||||
|
|
||||||
type DB struct {
|
type DB struct {
|
||||||
session *mgo.Session
|
session *mgo.Session
|
||||||
books *mgo.Collection
|
|
||||||
user *mgo.Collection
|
|
||||||
news *mgo.Collection
|
|
||||||
stats *mgo.Collection
|
|
||||||
mr *MR
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func initDB() *DB {
|
func initDB() *DB {
|
||||||
|
@ -55,13 +49,6 @@ func initDB() *DB {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
database := d.session.DB(DB_NAME)
|
|
||||||
d.books = database.C(BOOKS_COLL)
|
|
||||||
d.user = database.C(USERS_COLL)
|
|
||||||
d.news = database.C(NEWS_COLL)
|
|
||||||
d.stats = database.C(STATS_COLL)
|
|
||||||
d.mr = NewMR(database)
|
|
||||||
return d
|
return d
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -69,6 +56,12 @@ func (d *DB) Close() {
|
||||||
d.session.Close()
|
d.session.Close()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (d *DB) Copy() *DB {
|
||||||
|
dbCopy := new(DB)
|
||||||
|
dbCopy.session = d.session.Copy()
|
||||||
|
return dbCopy
|
||||||
|
}
|
||||||
|
|
||||||
func md5Pass(pass string) []byte {
|
func md5Pass(pass string) []byte {
|
||||||
h := md5.New()
|
h := md5.New()
|
||||||
hash := h.Sum(([]byte)(PASS_SALT + pass))
|
hash := h.Sum(([]byte)(PASS_SALT + pass))
|
||||||
|
@ -77,12 +70,14 @@ func md5Pass(pass string) []byte {
|
||||||
|
|
||||||
func (d *DB) SetPassword(user string, pass string) error {
|
func (d *DB) SetPassword(user string, pass string) error {
|
||||||
hash := md5Pass(pass)
|
hash := md5Pass(pass)
|
||||||
return d.user.Update(bson.M{"user": user}, bson.M{"$set": bson.M{"pass": hash}})
|
userColl := d.session.DB(DB_NAME).C(USERS_COLL)
|
||||||
|
return userColl.Update(bson.M{"user": user}, bson.M{"$set": bson.M{"pass": hash}})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *DB) UserValid(user string, pass string) bool {
|
func (d *DB) UserValid(user string, pass string) bool {
|
||||||
hash := md5Pass(pass)
|
hash := md5Pass(pass)
|
||||||
n, err := d.user.Find(bson.M{"user": user, "pass": hash}).Count()
|
userColl := d.session.DB(DB_NAME).C(USERS_COLL)
|
||||||
|
n, err := userColl.Find(bson.M{"user": user, "pass": hash}).Count()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
@ -91,7 +86,8 @@ func (d *DB) UserValid(user string, pass string) bool {
|
||||||
|
|
||||||
func (d *DB) AddUser(user string, pass string) error {
|
func (d *DB) AddUser(user string, pass string) error {
|
||||||
hash := md5Pass(pass)
|
hash := md5Pass(pass)
|
||||||
return d.user.Insert(bson.M{"user": user, "pass": hash, "role": ""})
|
userColl := d.session.DB(DB_NAME).C(USERS_COLL)
|
||||||
|
return userColl.Insert(bson.M{"user": user, "pass": hash, "role": ""})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *DB) UserRole(user string) string {
|
func (d *DB) UserRole(user string) string {
|
||||||
|
@ -99,7 +95,8 @@ func (d *DB) UserRole(user string) string {
|
||||||
Role string
|
Role string
|
||||||
}
|
}
|
||||||
res := result{}
|
res := result{}
|
||||||
err := d.user.Find(bson.M{"user": user}).One(&res)
|
userColl := d.session.DB(DB_NAME).C(USERS_COLL)
|
||||||
|
err := userColl.Find(bson.M{"user": user}).One(&res)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
@ -110,7 +107,8 @@ func (d *DB) AddNews(text string) error {
|
||||||
var news News
|
var news News
|
||||||
news.Text = text
|
news.Text = text
|
||||||
news.Date = time.Now()
|
news.Date = time.Now()
|
||||||
return d.news.Insert(news)
|
newsColl := d.session.DB(DB_NAME).C(NEWS_COLL)
|
||||||
|
return newsColl.Insert(news)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *DB) GetNews(num int, days int) (news []News, err error) {
|
func (d *DB) GetNews(num int, days int) (news []News, err error) {
|
||||||
|
@ -120,25 +118,30 @@ func (d *DB) GetNews(num int, days int) (news []News, err error) {
|
||||||
date := time.Now().Add(duration)
|
date := time.Now().Add(duration)
|
||||||
query = bson.M{"date": bson.M{"$gt": date}}
|
query = bson.M{"date": bson.M{"$gt": date}}
|
||||||
}
|
}
|
||||||
q := d.news.Find(query).Sort("-date").Limit(num)
|
newsColl := d.session.DB(DB_NAME).C(NEWS_COLL)
|
||||||
|
q := newsColl.Find(query).Sort("-date").Limit(num)
|
||||||
err = q.All(&news)
|
err = q.All(&news)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *DB) InsertStats(stats interface{}) error {
|
func (d *DB) InsertStats(stats interface{}) error {
|
||||||
return d.stats.Insert(stats)
|
statsColl := d.session.DB(DB_NAME).C(STATS_COLL)
|
||||||
|
return statsColl.Insert(stats)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *DB) InsertBook(book interface{}) error {
|
func (d *DB) InsertBook(book interface{}) error {
|
||||||
return d.books.Insert(book)
|
booksColl := d.session.DB(DB_NAME).C(BOOKS_COLL)
|
||||||
|
return booksColl.Insert(book)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *DB) RemoveBook(id bson.ObjectId) error {
|
func (d *DB) RemoveBook(id bson.ObjectId) error {
|
||||||
return d.books.Remove(bson.M{"_id": id})
|
booksColl := d.session.DB(DB_NAME).C(BOOKS_COLL)
|
||||||
|
return booksColl.Remove(bson.M{"_id": id})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *DB) UpdateBook(id bson.ObjectId, data interface{}) error {
|
func (d *DB) UpdateBook(id bson.ObjectId, data interface{}) error {
|
||||||
return d.books.Update(bson.M{"_id": id}, bson.M{"$set": data})
|
booksColl := d.session.DB(DB_NAME).C(BOOKS_COLL)
|
||||||
|
return booksColl.Update(bson.M{"_id": id}, bson.M{"$set": data})
|
||||||
}
|
}
|
||||||
|
|
||||||
/* optional parameters: length and start index
|
/* optional parameters: length and start index
|
||||||
|
@ -153,7 +156,8 @@ func (d *DB) GetBooks(query bson.M, r ...int) (books []Book, num int, err error)
|
||||||
start = r[1]
|
start = r[1]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
q := d.books.Find(query).Sort("-_id")
|
booksColl := d.session.DB(DB_NAME).C(BOOKS_COLL)
|
||||||
|
q := booksColl.Find(query).Sort("-_id")
|
||||||
num, err = q.Count()
|
num, err = q.Count()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
|
@ -175,14 +179,17 @@ func (d *DB) GetBooks(query bson.M, r ...int) (books []Book, num int, err error)
|
||||||
/* Get the most visited books
|
/* Get the most visited books
|
||||||
*/
|
*/
|
||||||
func (d *DB) GetVisitedBooks(num int) (books []Book, err error) {
|
func (d *DB) GetVisitedBooks(num int) (books []Book, err error) {
|
||||||
bookId, err := d.mr.GetMostVisited(num, d.stats)
|
statsColl := d.session.DB(DB_NAME).C(STATS_COLL)
|
||||||
|
mr := NewMR(d.session.DB(DB_NAME))
|
||||||
|
bookId, err := mr.GetMostVisited(num, statsColl)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
books = make([]Book, num)
|
books = make([]Book, num)
|
||||||
for i, id := range bookId {
|
for i, id := range bookId {
|
||||||
d.books.Find(bson.M{"_id": id}).One(&books[i])
|
booksColl := d.session.DB(DB_NAME).C(BOOKS_COLL)
|
||||||
|
booksColl.Find(bson.M{"_id": id}).One(&books[i])
|
||||||
books[i].Id = bson.ObjectId(books[i].Id).Hex()
|
books[i].Id = bson.ObjectId(books[i].Id).Hex()
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
|
@ -191,14 +198,17 @@ func (d *DB) GetVisitedBooks(num int) (books []Book, err error) {
|
||||||
/* Get the most downloaded books
|
/* Get the most downloaded books
|
||||||
*/
|
*/
|
||||||
func (d *DB) GetDownloadedBooks(num int) (books []Book, err error) {
|
func (d *DB) GetDownloadedBooks(num int) (books []Book, err error) {
|
||||||
bookId, err := d.mr.GetMostDownloaded(num, d.stats)
|
statsColl := d.session.DB(DB_NAME).C(STATS_COLL)
|
||||||
|
mr := NewMR(d.session.DB(DB_NAME))
|
||||||
|
bookId, err := mr.GetMostDownloaded(num, statsColl)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
books = make([]Book, num)
|
books = make([]Book, num)
|
||||||
for i, id := range bookId {
|
for i, id := range bookId {
|
||||||
d.books.Find(bson.M{"_id": id}).One(&books[i])
|
booksColl := d.session.DB(DB_NAME).C(BOOKS_COLL)
|
||||||
|
booksColl.Find(bson.M{"_id": id}).One(&books[i])
|
||||||
books[i].Id = bson.ObjectId(books[i].Id).Hex()
|
books[i].Id = bson.ObjectId(books[i].Id).Hex()
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
|
@ -214,7 +224,8 @@ func (d *DB) GetNewBooks(r ...int) (books []Book, num int, err error) {
|
||||||
|
|
||||||
func (d *DB) BookActive(id bson.ObjectId) bool {
|
func (d *DB) BookActive(id bson.ObjectId) bool {
|
||||||
var book Book
|
var book Book
|
||||||
err := d.books.Find(bson.M{"_id": id}).One(&book)
|
booksColl := d.session.DB(DB_NAME).C(BOOKS_COLL)
|
||||||
|
err := booksColl.Find(bson.M{"_id": id}).One(&book)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
@ -226,7 +237,9 @@ func (d *DB) GetFS(prefix string) *mgo.GridFS {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *DB) GetTags(numTags int) ([]string, error) {
|
func (d *DB) GetTags(numTags int) ([]string, error) {
|
||||||
return d.mr.GetTags(numTags, d.books)
|
booksColl := d.session.DB(DB_NAME).C(BOOKS_COLL)
|
||||||
|
mr := NewMR(d.session.DB(DB_NAME))
|
||||||
|
return mr.GetTags(numTags, booksColl)
|
||||||
}
|
}
|
||||||
|
|
||||||
type Visits struct {
|
type Visits struct {
|
||||||
|
@ -235,13 +248,19 @@ type Visits struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *DB) GetHourVisits(start time.Time) ([]Visits, error) {
|
func (d *DB) GetHourVisits(start time.Time) ([]Visits, error) {
|
||||||
return d.mr.GetHourVisits(start, d.stats)
|
statsColl := d.session.DB(DB_NAME).C(STATS_COLL)
|
||||||
|
mr := NewMR(d.session.DB(DB_NAME))
|
||||||
|
return mr.GetHourVisits(start, statsColl)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *DB) GetDayVisits(start time.Time) ([]Visits, error) {
|
func (d *DB) GetDayVisits(start time.Time) ([]Visits, error) {
|
||||||
return d.mr.GetDayVisits(start, d.stats)
|
statsColl := d.session.DB(DB_NAME).C(STATS_COLL)
|
||||||
|
mr := NewMR(d.session.DB(DB_NAME))
|
||||||
|
return mr.GetDayVisits(start, statsColl)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *DB) GetMonthVisits(start time.Time) ([]Visits, error) {
|
func (d *DB) GetMonthVisits(start time.Time) ([]Visits, error) {
|
||||||
return d.mr.GetMonthVisits(start, d.stats)
|
statsColl := d.session.DB(DB_NAME).C(STATS_COLL)
|
||||||
|
mr := NewMR(d.session.DB(DB_NAME))
|
||||||
|
return mr.GetMonthVisits(start, statsColl)
|
||||||
}
|
}
|
||||||
|
|
57
mapreduce.go
57
mapreduce.go
|
@ -7,30 +7,12 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
type MR struct {
|
type MR struct {
|
||||||
meta *mgo.Collection
|
database *mgo.Database
|
||||||
tags *mgo.Collection
|
|
||||||
visited *mgo.Collection
|
|
||||||
downloaded *mgo.Collection
|
|
||||||
hourly_raw *mgo.Collection
|
|
||||||
daily_raw *mgo.Collection
|
|
||||||
monthly_raw *mgo.Collection
|
|
||||||
hourly *mgo.Collection
|
|
||||||
daily *mgo.Collection
|
|
||||||
monthly *mgo.Collection
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewMR(database *mgo.Database) *MR {
|
func NewMR(database *mgo.Database) *MR {
|
||||||
m := new(MR)
|
m := new(MR)
|
||||||
m.meta = database.C(META_COLL)
|
m.database = database
|
||||||
m.tags = database.C(TAGS_COLL)
|
|
||||||
m.visited = database.C(VISITED_COLL)
|
|
||||||
m.downloaded = database.C(DOWNLOADED_COLL)
|
|
||||||
m.hourly_raw = database.C(HOURLY_VISITS_COLL + "_raw")
|
|
||||||
m.daily_raw = database.C(DAILY_VISITS_COLL + "_raw")
|
|
||||||
m.monthly_raw = database.C(MONTHLY_VISITS_COLL + "_raw")
|
|
||||||
m.hourly = database.C(HOURLY_VISITS_COLL)
|
|
||||||
m.daily = database.C(DAILY_VISITS_COLL)
|
|
||||||
m.monthly = database.C(MONTHLY_VISITS_COLL)
|
|
||||||
return m
|
return m
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -56,7 +38,8 @@ func (m *MR) GetTags(numTags int, booksColl *mgo.Collection) ([]string, error) {
|
||||||
var result []struct {
|
var result []struct {
|
||||||
Tag string "_id"
|
Tag string "_id"
|
||||||
}
|
}
|
||||||
err := m.tags.Find(nil).Sort("-value").Limit(numTags).All(&result)
|
tagsColl := m.database.C(TAGS_COLL)
|
||||||
|
err := tagsColl.Find(nil).Sort("-value").Limit(numTags).All(&result)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -88,7 +71,8 @@ func (m *MR) GetMostVisited(num int, statsColl *mgo.Collection) ([]bson.ObjectId
|
||||||
var result []struct {
|
var result []struct {
|
||||||
Book bson.ObjectId "_id"
|
Book bson.ObjectId "_id"
|
||||||
}
|
}
|
||||||
err := m.visited.Find(nil).Sort("-value").Limit(num).All(&result)
|
visitedColl := m.database.C(VISITED_COLL)
|
||||||
|
err := visitedColl.Find(nil).Sort("-value").Limit(num).All(&result)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -120,7 +104,8 @@ func (m *MR) GetMostDownloaded(num int, statsColl *mgo.Collection) ([]bson.Objec
|
||||||
var result []struct {
|
var result []struct {
|
||||||
Book bson.ObjectId "_id"
|
Book bson.ObjectId "_id"
|
||||||
}
|
}
|
||||||
err := m.downloaded.Find(nil).Sort("-value").Limit(num).All(&result)
|
downloadedColl := m.database.C(DOWNLOADED_COLL)
|
||||||
|
err := downloadedColl.Find(nil).Sort("-value").Limit(num).All(&result)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -157,14 +142,16 @@ func (m *MR) GetHourVisits(start time.Time, statsColl *mgo.Collection) ([]Visits
|
||||||
emit(this['_id']['date'], 1);
|
emit(this['_id']['date'], 1);
|
||||||
}`
|
}`
|
||||||
mr2.Reduce = reduce
|
mr2.Reduce = reduce
|
||||||
err = m.update(&mr2, bson.M{}, m.hourly_raw, HOURLY_VISITS_COLL)
|
hourly_raw := m.database.C(HOURLY_VISITS_COLL + "_raw")
|
||||||
|
err = m.update(&mr2, bson.M{}, hourly_raw, HOURLY_VISITS_COLL)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var result []Visits
|
var result []Visits
|
||||||
err := m.hourly.Find(nil).All(&result)
|
hourlyColl := m.database.C(HOURLY_VISITS_COLL)
|
||||||
|
err := hourlyColl.Find(nil).All(&result)
|
||||||
return result, err
|
return result, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -192,14 +179,16 @@ func (m *MR) GetDayVisits(start time.Time, statsColl *mgo.Collection) ([]Visits,
|
||||||
emit(this['_id']['date'], 1);
|
emit(this['_id']['date'], 1);
|
||||||
}`
|
}`
|
||||||
mr2.Reduce = reduce
|
mr2.Reduce = reduce
|
||||||
err = m.update(&mr2, bson.M{}, m.daily_raw, DAILY_VISITS_COLL)
|
daily_raw := m.database.C(DAILY_VISITS_COLL + "_raw")
|
||||||
|
err = m.update(&mr2, bson.M{}, daily_raw, DAILY_VISITS_COLL)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var result []Visits
|
var result []Visits
|
||||||
err := m.daily.Find(nil).All(&result)
|
dailyColl := m.database.C(DAILY_VISITS_COLL)
|
||||||
|
err := dailyColl.Find(nil).All(&result)
|
||||||
return result, err
|
return result, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -226,19 +215,22 @@ func (m *MR) GetMonthVisits(start time.Time, statsColl *mgo.Collection) ([]Visit
|
||||||
emit(this['_id']['date'], 1);
|
emit(this['_id']['date'], 1);
|
||||||
}`
|
}`
|
||||||
mr2.Reduce = reduce
|
mr2.Reduce = reduce
|
||||||
err = m.update(&mr2, bson.M{}, m.monthly_raw, MONTHLY_VISITS_COLL)
|
monthly_raw := m.database.C(MONTHLY_VISITS_COLL + "_raw")
|
||||||
|
err = m.update(&mr2, bson.M{}, monthly_raw, MONTHLY_VISITS_COLL)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var result []Visits
|
var result []Visits
|
||||||
err := m.monthly.Find(nil).All(&result)
|
monthlyColl := m.database.C(MONTHLY_VISITS_COLL)
|
||||||
|
err := monthlyColl.Find(nil).All(&result)
|
||||||
return result, err
|
return result, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *MR) update(mr *mgo.MapReduce, query bson.M, queryColl *mgo.Collection, storeColl string) error {
|
func (m *MR) update(mr *mgo.MapReduce, query bson.M, queryColl *mgo.Collection, storeColl string) error {
|
||||||
_, err := m.meta.RemoveAll(bson.M{"type": storeColl})
|
metaColl := m.database.C(META_COLL)
|
||||||
|
_, err := metaColl.RemoveAll(bson.M{"type": storeColl})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -249,14 +241,15 @@ func (m *MR) update(mr *mgo.MapReduce, query bson.M, queryColl *mgo.Collection,
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
return m.meta.Insert(bson.M{"type": storeColl})
|
return metaColl.Insert(bson.M{"type": storeColl})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *MR) isOutdated(coll string, minutes float64) bool {
|
func (m *MR) isOutdated(coll string, minutes float64) bool {
|
||||||
var result struct {
|
var result struct {
|
||||||
Id bson.ObjectId `bson:"_id"`
|
Id bson.ObjectId `bson:"_id"`
|
||||||
}
|
}
|
||||||
err := m.meta.Find(bson.M{"type": coll}).One(&result)
|
metaColl := m.database.C(META_COLL)
|
||||||
|
err := metaColl.Find(bson.M{"type": coll}).One(&result)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
40
news.go
40
news.go
|
@ -14,50 +14,50 @@ type newsEntry struct {
|
||||||
Text string
|
Text string
|
||||||
}
|
}
|
||||||
|
|
||||||
func newsHandler(w http.ResponseWriter, r *http.Request, sess *Session) {
|
func newsHandler(h handler) {
|
||||||
err := r.ParseForm()
|
err := h.r.ParseForm()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
http.Error(h.w, err.Error(), http.StatusInternalServerError)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
var data newsData
|
var data newsData
|
||||||
data.S = GetStatus(w, r)
|
data.S = GetStatus(h)
|
||||||
data.S.News = true
|
data.S.News = true
|
||||||
data.News = getNews(NUM_NEWS, 0)
|
data.News = getNews(NUM_NEWS, 0, h.db)
|
||||||
|
|
||||||
format := r.Form["fmt"]
|
format := h.r.Form["fmt"]
|
||||||
if (len(format) > 0) && (format[0] == "rss") {
|
if (len(format) > 0) && (format[0] == "rss") {
|
||||||
loadTxtTemplate(w, "news_rss.xml", data)
|
loadTxtTemplate(h.w, "news_rss.xml", data)
|
||||||
} else {
|
} else {
|
||||||
loadTemplate(w, "news", data)
|
loadTemplate(h.w, "news", data)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func editNewsHandler(w http.ResponseWriter, r *http.Request, sess *Session) {
|
func editNewsHandler(h handler) {
|
||||||
if !sess.IsAdmin() {
|
if !h.sess.IsAdmin() {
|
||||||
notFound(w, r)
|
notFound(h)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
var data statusData
|
var data statusData
|
||||||
data.S = GetStatus(w, r)
|
data.S = GetStatus(h)
|
||||||
data.S.News = true
|
data.S.News = true
|
||||||
loadTemplate(w, "edit_news", data)
|
loadTemplate(h.w, "edit_news", data)
|
||||||
}
|
}
|
||||||
|
|
||||||
func postNewsHandler(w http.ResponseWriter, r *http.Request, sess *Session) {
|
func postNewsHandler(h handler) {
|
||||||
if !sess.IsAdmin() {
|
if !h.sess.IsAdmin() {
|
||||||
notFound(w, r)
|
notFound(h)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
text := r.FormValue("text")
|
text := h.r.FormValue("text")
|
||||||
db.AddNews(text)
|
h.db.AddNews(text)
|
||||||
http.Redirect(w, r, "/news/", http.StatusFound)
|
http.Redirect(h.w, h.r, "/news/", http.StatusFound)
|
||||||
}
|
}
|
||||||
|
|
||||||
func getNews(num int, days int) []newsEntry {
|
func getNews(num int, days int, db *DB) []newsEntry {
|
||||||
dbnews, _ := db.GetNews(num, days)
|
dbnews, _ := db.GetNews(num, days)
|
||||||
news := make([]newsEntry, len(dbnews))
|
news := make([]newsEntry, len(dbnews))
|
||||||
for i, n := range dbnews {
|
for i, n := range dbnews {
|
||||||
|
|
58
reader.go
58
reader.go
|
@ -129,35 +129,35 @@ func listChapters(nav *epubgo.NavigationIterator, depth int) []chapter {
|
||||||
return chapters
|
return chapters
|
||||||
}
|
}
|
||||||
|
|
||||||
func readStartHandler(w http.ResponseWriter, r *http.Request, sess *Session) {
|
func readStartHandler(h handler) {
|
||||||
id := mux.Vars(r)["id"]
|
id := mux.Vars(h.r)["id"]
|
||||||
e, _ := openReadEpub(w, r, sess)
|
e, _ := openReadEpub(h)
|
||||||
if e == nil {
|
if e == nil {
|
||||||
notFound(w, r)
|
notFound(h)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
defer e.Close()
|
defer e.Close()
|
||||||
|
|
||||||
it, err := e.Spine()
|
it, err := e.Spine()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
notFound(w, r)
|
notFound(h)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
http.Redirect(w, r, "/read/"+id+"/"+it.URL(), http.StatusTemporaryRedirect)
|
http.Redirect(h.w, h.r, "/read/"+id+"/"+it.URL(), http.StatusTemporaryRedirect)
|
||||||
}
|
}
|
||||||
|
|
||||||
func readHandler(w http.ResponseWriter, r *http.Request, sess *Session) {
|
func readHandler(h handler) {
|
||||||
id := mux.Vars(r)["id"]
|
id := mux.Vars(h.r)["id"]
|
||||||
file := mux.Vars(r)["file"]
|
file := mux.Vars(h.r)["file"]
|
||||||
e, book := openReadEpub(w, r, sess)
|
e, book := openReadEpub(h)
|
||||||
if e == nil {
|
if e == nil {
|
||||||
notFound(w, r)
|
notFound(h)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
defer e.Close()
|
defer e.Close()
|
||||||
|
|
||||||
var data readData
|
var data readData
|
||||||
data.S = GetStatus(w, r)
|
data.S = GetStatus(h)
|
||||||
data.Book = book
|
data.Book = book
|
||||||
if !book.Active {
|
if !book.Active {
|
||||||
data.Back = "/new/"
|
data.Back = "/new/"
|
||||||
|
@ -168,66 +168,66 @@ func readHandler(w http.ResponseWriter, r *http.Request, sess *Session) {
|
||||||
data.Next, data.Prev = getNextPrev(e, file, id, "/read/")
|
data.Next, data.Prev = getNextPrev(e, file, id, "/read/")
|
||||||
data.Chapters = getChapters(e, file, id, "/read/")
|
data.Chapters = getChapters(e, file, id, "/read/")
|
||||||
data.Content = genLink(id, "/content/", file)
|
data.Content = genLink(id, "/content/", file)
|
||||||
loadTemplate(w, "read", data)
|
loadTemplate(h.w, "read", data)
|
||||||
}
|
}
|
||||||
|
|
||||||
func openReadEpub(w http.ResponseWriter, r *http.Request, sess *Session) (*epubgo.Epub, Book) {
|
func openReadEpub(h handler) (*epubgo.Epub, Book) {
|
||||||
var book Book
|
var book Book
|
||||||
id := mux.Vars(r)["id"]
|
id := mux.Vars(h.r)["id"]
|
||||||
if !bson.IsObjectIdHex(id) {
|
if !bson.IsObjectIdHex(id) {
|
||||||
return nil, book
|
return nil, book
|
||||||
}
|
}
|
||||||
books, _, err := db.GetBooks(bson.M{"_id": bson.ObjectIdHex(id)})
|
books, _, err := h.db.GetBooks(bson.M{"_id": bson.ObjectIdHex(id)})
|
||||||
if err != nil || len(books) == 0 {
|
if err != nil || len(books) == 0 {
|
||||||
return nil, book
|
return nil, book
|
||||||
}
|
}
|
||||||
|
|
||||||
book = books[0]
|
book = books[0]
|
||||||
if !book.Active {
|
if !book.Active {
|
||||||
if !sess.IsAdmin() {
|
if !h.sess.IsAdmin() {
|
||||||
return nil, book
|
return nil, book
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
e, err := OpenBook(book.File)
|
e, err := OpenBook(book.File, h.db)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, book
|
return nil, book
|
||||||
}
|
}
|
||||||
return e, book
|
return e, book
|
||||||
}
|
}
|
||||||
|
|
||||||
func contentHandler(w http.ResponseWriter, r *http.Request, sess *Session) {
|
func contentHandler(h handler) {
|
||||||
vars := mux.Vars(r)
|
vars := mux.Vars(h.r)
|
||||||
id := vars["id"]
|
id := vars["id"]
|
||||||
file := vars["file"]
|
file := vars["file"]
|
||||||
if file == "" || !bson.IsObjectIdHex(id) {
|
if file == "" || !bson.IsObjectIdHex(id) {
|
||||||
notFound(w, r)
|
notFound(h)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
books, _, err := db.GetBooks(bson.M{"_id": bson.ObjectIdHex(id)})
|
books, _, err := h.db.GetBooks(bson.M{"_id": bson.ObjectIdHex(id)})
|
||||||
if err != nil || len(books) == 0 {
|
if err != nil || len(books) == 0 {
|
||||||
notFound(w, r)
|
notFound(h)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
book := books[0]
|
book := books[0]
|
||||||
if !book.Active {
|
if !book.Active {
|
||||||
if !sess.IsAdmin() {
|
if !h.sess.IsAdmin() {
|
||||||
notFound(w, r)
|
notFound(h)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
e, err := OpenBook(book.File)
|
e, err := OpenBook(book.File, h.db)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
notFound(w, r)
|
notFound(h)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
defer e.Close()
|
defer e.Close()
|
||||||
|
|
||||||
html, err := e.OpenFile(file)
|
html, err := e.OpenFile(file)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
notFound(w, r)
|
notFound(h)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
defer html.Close()
|
defer html.Close()
|
||||||
io.Copy(w, html)
|
io.Copy(h.w, html)
|
||||||
}
|
}
|
||||||
|
|
24
search.go
24
search.go
|
@ -35,25 +35,25 @@ type searchData struct {
|
||||||
Prev string
|
Prev string
|
||||||
}
|
}
|
||||||
|
|
||||||
func searchHandler(w http.ResponseWriter, r *http.Request, sess *Session) {
|
func searchHandler(h handler) {
|
||||||
err := r.ParseForm()
|
err := h.r.ParseForm()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
http.Error(h.w, err.Error(), http.StatusInternalServerError)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
req := strings.Join(r.Form["q"], " ")
|
req := strings.Join(h.r.Form["q"], " ")
|
||||||
page := 0
|
page := 0
|
||||||
if len(r.Form["p"]) != 0 {
|
if len(h.r.Form["p"]) != 0 {
|
||||||
page, err = strconv.Atoi(r.Form["p"][0])
|
page, err = strconv.Atoi(h.r.Form["p"][0])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
page = 0
|
page = 0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
items_page := itemsPage(r)
|
items_page := itemsPage(h.r)
|
||||||
res, num, _ := db.GetBooks(buildQuery(req), items_page, page*items_page)
|
res, num, _ := h.db.GetBooks(buildQuery(req), items_page, page*items_page)
|
||||||
|
|
||||||
var data searchData
|
var data searchData
|
||||||
data.S = GetStatus(w, r)
|
data.S = GetStatus(h)
|
||||||
data.S.Search = req
|
data.S.Search = req
|
||||||
data.Books = res
|
data.Books = res
|
||||||
data.ItemsPage = items_page
|
data.ItemsPage = items_page
|
||||||
|
@ -66,11 +66,11 @@ func searchHandler(w http.ResponseWriter, r *http.Request, sess *Session) {
|
||||||
data.Prev = "/search/?q=" + req + "&p=" + strconv.Itoa(page-1) + "&num=" + strconv.Itoa(items_page)
|
data.Prev = "/search/?q=" + req + "&p=" + strconv.Itoa(page-1) + "&num=" + strconv.Itoa(items_page)
|
||||||
}
|
}
|
||||||
|
|
||||||
format := r.Form["fmt"]
|
format := h.r.Form["fmt"]
|
||||||
if (len(format) > 0) && (format[0] == "rss") {
|
if (len(format) > 0) && (format[0] == "rss") {
|
||||||
loadTxtTemplate(w, "search_rss.xml", data)
|
loadTxtTemplate(h.w, "search_rss.xml", data)
|
||||||
} else {
|
} else {
|
||||||
loadTemplate(w, "search", data)
|
loadTemplate(h.w, "search", data)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -21,7 +21,7 @@ type Session struct {
|
||||||
S *sessions.Session
|
S *sessions.Session
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetSession(r *http.Request) (s *Session) {
|
func GetSession(r *http.Request, db *DB) (s *Session) {
|
||||||
s = new(Session)
|
s = new(Session)
|
||||||
var err error
|
var err error
|
||||||
s.S, err = sesStore.Get(r, "session")
|
s.S, err = sesStore.Get(r, "session")
|
||||||
|
|
51
stats.go
51
stats.go
|
@ -9,16 +9,30 @@ import (
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
func InitStats() {
|
type handler struct {
|
||||||
statsChannel = make(chan statsRequest, CHAN_SIZE)
|
w http.ResponseWriter
|
||||||
go statsWorker()
|
r *http.Request
|
||||||
|
sess *Session
|
||||||
|
db *DB
|
||||||
}
|
}
|
||||||
|
|
||||||
func GatherStats(function func(http.ResponseWriter, *http.Request, *Session)) func(http.ResponseWriter, *http.Request) {
|
func InitStats(database *DB) {
|
||||||
|
statsChannel = make(chan statsRequest, CHAN_SIZE)
|
||||||
|
go statsWorker(database)
|
||||||
|
}
|
||||||
|
|
||||||
|
func GatherStats(function func(handler), database *DB) func(http.ResponseWriter, *http.Request) {
|
||||||
return func(w http.ResponseWriter, r *http.Request) {
|
return func(w http.ResponseWriter, r *http.Request) {
|
||||||
sess := GetSession(r)
|
var h handler
|
||||||
function(w, r, sess)
|
h.db = database.Copy()
|
||||||
statsChannel <- statsRequest{bson.Now(), mux.Vars(r), sess, r}
|
defer h.db.Close()
|
||||||
|
|
||||||
|
h.w = w
|
||||||
|
h.r = r
|
||||||
|
h.sess = GetSession(r, h.db)
|
||||||
|
function(h)
|
||||||
|
|
||||||
|
statsChannel <- statsRequest{bson.Now(), mux.Vars(r), h.sess, r}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -31,7 +45,10 @@ type statsRequest struct {
|
||||||
r *http.Request
|
r *http.Request
|
||||||
}
|
}
|
||||||
|
|
||||||
func statsWorker() {
|
func statsWorker(database *DB) {
|
||||||
|
db := database.Copy()
|
||||||
|
defer db.Close()
|
||||||
|
|
||||||
for req := range statsChannel {
|
for req := range statsChannel {
|
||||||
stats := make(map[string]interface{})
|
stats := make(map[string]interface{})
|
||||||
appendFiles(req.r, stats)
|
appendFiles(req.r, stats)
|
||||||
|
@ -44,15 +61,15 @@ func statsWorker() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func statsHandler(w http.ResponseWriter, r *http.Request, sess *Session) {
|
func statsHandler(h handler) {
|
||||||
var data statsData
|
var data statsData
|
||||||
data.S = GetStatus(w, r)
|
data.S = GetStatus(h)
|
||||||
data.S.Stats = true
|
data.S.Stats = true
|
||||||
data.Hourly = getHourlyVisits()
|
data.Hourly = getHourlyVisits(h.db)
|
||||||
data.Daily = getDailyVisits()
|
data.Daily = getDailyVisits(h.db)
|
||||||
data.Monthly = getMonthlyVisits()
|
data.Monthly = getMonthlyVisits(h.db)
|
||||||
|
|
||||||
loadTemplate(w, "stats", data)
|
loadTemplate(h.w, "stats", data)
|
||||||
}
|
}
|
||||||
|
|
||||||
type statsData struct {
|
type statsData struct {
|
||||||
|
@ -67,7 +84,7 @@ type visitData struct {
|
||||||
Count int
|
Count int
|
||||||
}
|
}
|
||||||
|
|
||||||
func getHourlyVisits() []visitData {
|
func getHourlyVisits(db *DB) []visitData {
|
||||||
const numDays = 2
|
const numDays = 2
|
||||||
var visits []visitData
|
var visits []visitData
|
||||||
|
|
||||||
|
@ -84,7 +101,7 @@ func getHourlyVisits() []visitData {
|
||||||
return visits
|
return visits
|
||||||
}
|
}
|
||||||
|
|
||||||
func getDailyVisits() []visitData {
|
func getDailyVisits(db *DB) []visitData {
|
||||||
const numDays = 30
|
const numDays = 30
|
||||||
var visits []visitData
|
var visits []visitData
|
||||||
|
|
||||||
|
@ -101,7 +118,7 @@ func getDailyVisits() []visitData {
|
||||||
return visits
|
return visits
|
||||||
}
|
}
|
||||||
|
|
||||||
func getMonthlyVisits() []visitData {
|
func getMonthlyVisits(db *DB) []visitData {
|
||||||
const numDays = 365
|
const numDays = 365
|
||||||
var visits []visitData
|
var visits []visitData
|
||||||
|
|
||||||
|
|
22
store.go
22
store.go
|
@ -10,7 +10,7 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
func OpenBook(id bson.ObjectId) (*epubgo.Epub, error) {
|
func OpenBook(id bson.ObjectId, db *DB) (*epubgo.Epub, error) {
|
||||||
fs := db.GetFS(FS_BOOKS)
|
fs := db.GetFS(FS_BOOKS)
|
||||||
f, err := fs.OpenId(id)
|
f, err := fs.OpenId(id)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -24,37 +24,37 @@ func OpenBook(id bson.ObjectId) (*epubgo.Epub, error) {
|
||||||
return epubgo.Load(reader, int64(len(buff)))
|
return epubgo.Load(reader, int64(len(buff)))
|
||||||
}
|
}
|
||||||
|
|
||||||
func StoreNewFile(name string, file io.Reader) (bson.ObjectId, error) {
|
func StoreNewFile(name string, file io.Reader, db *DB) (bson.ObjectId, int64, error) {
|
||||||
fs := db.GetFS(FS_BOOKS)
|
fs := db.GetFS(FS_BOOKS)
|
||||||
fw, err := fs.Create(name)
|
fw, err := fs.Create(name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", 0, err
|
||||||
}
|
}
|
||||||
defer fw.Close()
|
defer fw.Close()
|
||||||
|
|
||||||
_, err = io.Copy(fw, file)
|
size, err := io.Copy(fw, file)
|
||||||
id, _ := fw.Id().(bson.ObjectId)
|
id, _ := fw.Id().(bson.ObjectId)
|
||||||
return id, err
|
return id, size, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func DeleteFile(id bson.ObjectId) error {
|
func DeleteFile(id bson.ObjectId, db *DB) error {
|
||||||
fs := db.GetFS(FS_BOOKS)
|
fs := db.GetFS(FS_BOOKS)
|
||||||
return fs.RemoveId(id)
|
return fs.RemoveId(id)
|
||||||
}
|
}
|
||||||
|
|
||||||
func DeleteCover(id bson.ObjectId) error {
|
func DeleteCover(id bson.ObjectId, db *DB) error {
|
||||||
fs := db.GetFS(FS_IMGS)
|
fs := db.GetFS(FS_IMGS)
|
||||||
return fs.RemoveId(id)
|
return fs.RemoveId(id)
|
||||||
}
|
}
|
||||||
|
|
||||||
func DeleteBook(book Book) {
|
func DeleteBook(book Book, db *DB) {
|
||||||
if book.Cover != "" {
|
if book.Cover != "" {
|
||||||
DeleteCover(book.Cover)
|
DeleteCover(book.Cover, db)
|
||||||
}
|
}
|
||||||
if book.CoverSmall != "" {
|
if book.CoverSmall != "" {
|
||||||
DeleteCover(book.CoverSmall)
|
DeleteCover(book.CoverSmall, db)
|
||||||
}
|
}
|
||||||
DeleteFile(book.File)
|
DeleteFile(book.File, db)
|
||||||
}
|
}
|
||||||
|
|
||||||
func cleanStr(str string) string {
|
func cleanStr(str string) string {
|
||||||
|
|
15
template.go
15
template.go
|
@ -22,15 +22,14 @@ type Status struct {
|
||||||
Help bool
|
Help bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetStatus(w http.ResponseWriter, r *http.Request) Status {
|
func GetStatus(h handler) Status {
|
||||||
var s Status
|
var s Status
|
||||||
sess := GetSession(r)
|
s.BaseURL = "http://" + h.r.Host
|
||||||
s.BaseURL = "http://" + r.Host
|
s.FullURL = s.BaseURL + h.r.RequestURI
|
||||||
s.FullURL = s.BaseURL + r.RequestURI
|
s.User = h.sess.User
|
||||||
s.User = sess.User
|
s.IsAdmin = h.sess.IsAdmin()
|
||||||
s.IsAdmin = sess.IsAdmin()
|
s.Notif = h.sess.GetNotif()
|
||||||
s.Notif = sess.GetNotif()
|
h.sess.Save(h.w, h.r)
|
||||||
sess.Save(w, r)
|
|
||||||
return s
|
return s
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,17 +1,23 @@
|
||||||
{{template "header.html" .S}}
|
{{template "header.html" .S}}
|
||||||
|
|
||||||
<p>The <strong>Imperial Library of Trantor</strong> (also known as <em>Galactic Library</em>) is a repository of ebooks on ePub format.</p>
|
<p>The <strong>Imperial Library of Trantor</strong> (also known as <em>Galactic Library</em>) is a repository of DRM-free ebooks on ePub format.</p>
|
||||||
|
|
||||||
<p>You can <a href="/upload/">upload</a> your books. And one of our librarians will take care to store them on our vast bookshelfs and make it available for the rest of the galaxy.</p>
|
<p>You can <a href="/upload/">upload</a> your books. And one of our librarians will take care to store them on our vast bookshelfs and make it available for the rest of the galaxy.</p>
|
||||||
|
|
||||||
<p>We like to pay the authors, but not the corporations that make profit from them. We won't listen to any content remove request from corporations, editorials, right management organizations or any other blood-suckers.<p>
|
|
||||||
|
|
||||||
<h4>Status</h4>
|
<h4>Status</h4>
|
||||||
|
|
||||||
<p>The Imperial Library of Trantor it's in beta-status. We are working to provide a good user experience, but it's still in early development.</p>
|
<p>The Imperial Library of Trantor it's in beta-status. We are working to provide a good user experience, but it's still in early development.</p>
|
||||||
|
|
||||||
<p><b>Any help is welcome</b>. You can write us comments to our email address (zenow@riseup.net), upload your epubs, download our <a href="https://gitorious.org/trantor">source code</a> hack it and send us patches, ...</p>
|
<p><b>Any help is welcome</b>. You can write us comments to our email address (zenow@riseup.net), upload your epubs, download our <a href="https://gitorious.org/trantor">source code</a> hack it and send us patches, ...</p>
|
||||||
|
|
||||||
|
<h4>Copyright</h4>
|
||||||
|
|
||||||
|
<p>Copyright laws are obsolete. With the technology to copy books without cost we can finally have universal access to the culture. We can provide the tools to allow everybody read any book without dependence on their monetary resources.</p>
|
||||||
|
|
||||||
|
<p>Of course we have to feed the authors, but with the capitalist way of commercialize culture now we are doing a really bad job at that. We are feeding big corporations, not the authors.</p>
|
||||||
|
|
||||||
|
<p>The Imperial Library of Trantor won't listen to any content remove request from corporations, editorials, right management organizations or any other blood-suckers.<p>
|
||||||
|
|
||||||
<h4>Donations</h4>
|
<h4>Donations</h4>
|
||||||
|
|
||||||
<p>If you feel like donate some bitcoins we'll gladly accept them. You can request one bitcoin key for you or use our public bitcoin key:</p>
|
<p>If you feel like donate some bitcoins we'll gladly accept them. You can request one bitcoin key for you or use our public bitcoin key:</p>
|
||||||
|
|
|
@ -20,6 +20,7 @@
|
||||||
{{if .Isbn}}
|
{{if .Isbn}}
|
||||||
<guid isPermaLink="false">ISBN: {{.Isbn}}</guid>
|
<guid isPermaLink="false">ISBN: {{.Isbn}}</guid>
|
||||||
{{end}}
|
{{end}}
|
||||||
|
<enclosure url="{{$baseURL}}/download/{{.Id}}/{{.Title}}.epub" length="{{.FileSize}}" type="application/epub+zip" />
|
||||||
{{range .Subject}}
|
{{range .Subject}}
|
||||||
{{if .}}
|
{{if .}}
|
||||||
<category>{{.}}</category>
|
<category>{{.}}</category>
|
||||||
|
|
|
@ -11,3 +11,5 @@ Password:
|
||||||
- getISBNnDesc (31/5/2013). Import the ISBN and the description with changes of lines to the database
|
- getISBNnDesc (31/5/2013). Import the ISBN and the description with changes of lines to the database
|
||||||
|
|
||||||
- coverNew. Reload the cover from all the new books
|
- coverNew. Reload the cover from all the new books
|
||||||
|
|
||||||
|
- addsize. Add the size of the books to the book metadata
|
||||||
|
|
38
tools/addsize/addsize.go
Normal file
38
tools/addsize/addsize.go
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"labix.org/v2/mgo/bson"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
db = initDB()
|
||||||
|
defer db.Close()
|
||||||
|
books, _, _ := db.GetBooks(bson.M{})
|
||||||
|
|
||||||
|
for _, book := range books {
|
||||||
|
size, err := getSize(book.File)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
err = db.UpdateBook(bson.ObjectIdHex(book.Id), bson.M{"filesize": size})
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type file struct {
|
||||||
|
Length int
|
||||||
|
}
|
||||||
|
|
||||||
|
func getSize(id bson.ObjectId) (int, error) {
|
||||||
|
fs := db.GetFS(FS_BOOKS)
|
||||||
|
var f file
|
||||||
|
err := fs.Find(bson.M{"_id": id}).One(&f)
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
return f.Length, nil
|
||||||
|
}
|
45
tools/addsize/config.go
Normal file
45
tools/addsize/config.go
Normal file
|
@ -0,0 +1,45 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
const (
|
||||||
|
PORT = "8080"
|
||||||
|
|
||||||
|
DB_IP = "127.0.0.1"
|
||||||
|
DB_NAME = "trantor"
|
||||||
|
META_COLL = "meta"
|
||||||
|
BOOKS_COLL = "books"
|
||||||
|
TAGS_COLL = "tags"
|
||||||
|
VISITED_COLL = "visited"
|
||||||
|
DOWNLOADED_COLL = "downloaded"
|
||||||
|
HOURLY_VISITS_COLL = "visits.hourly"
|
||||||
|
DAILY_VISITS_COLL = "visits.daily"
|
||||||
|
MONTHLY_VISITS_COLL = "visits.monthly"
|
||||||
|
USERS_COLL = "users"
|
||||||
|
NEWS_COLL = "news"
|
||||||
|
STATS_COLL = "statistics"
|
||||||
|
FS_BOOKS = "fs_books"
|
||||||
|
FS_IMGS = "fs_imgs"
|
||||||
|
|
||||||
|
PASS_SALT = "ImperialLibSalt"
|
||||||
|
MINUTES_UPDATE_TAGS = 11
|
||||||
|
MINUTES_UPDATE_VISITED = 41
|
||||||
|
MINUTES_UPDATE_DOWNLOADED = 47
|
||||||
|
MINUTES_UPDATE_HOURLY = 31
|
||||||
|
MINUTES_UPDATE_DAILY = 60*12 + 7
|
||||||
|
MINUTES_UPDATE_MONTHLY = 60*24 + 11
|
||||||
|
TAGS_DISPLAY = 50
|
||||||
|
SEARCH_ITEMS_PAGE = 20
|
||||||
|
NEW_ITEMS_PAGE = 50
|
||||||
|
NUM_NEWS = 10
|
||||||
|
DAYS_NEWS_INDEXPAGE = 15
|
||||||
|
|
||||||
|
TEMPLATE_PATH = "templates/"
|
||||||
|
CSS_PATH = "css/"
|
||||||
|
JS_PATH = "js/"
|
||||||
|
IMG_PATH = "img/"
|
||||||
|
|
||||||
|
IMG_WIDTH_BIG = 300
|
||||||
|
IMG_WIDTH_SMALL = 60
|
||||||
|
IMG_QUALITY = 80
|
||||||
|
|
||||||
|
CHAN_SIZE = 100
|
||||||
|
)
|
243
tools/addsize/database.go
Normal file
243
tools/addsize/database.go
Normal file
|
@ -0,0 +1,243 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/md5"
|
||||||
|
"labix.org/v2/mgo"
|
||||||
|
"labix.org/v2/mgo/bson"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
var db *DB
|
||||||
|
|
||||||
|
type Book struct {
|
||||||
|
Id string `bson:"_id"`
|
||||||
|
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
|
||||||
|
File bson.ObjectId
|
||||||
|
FileSize int
|
||||||
|
Cover bson.ObjectId
|
||||||
|
CoverSmall bson.ObjectId
|
||||||
|
Active bool
|
||||||
|
Keywords []string
|
||||||
|
}
|
||||||
|
|
||||||
|
type News struct {
|
||||||
|
Date time.Time
|
||||||
|
Text string
|
||||||
|
}
|
||||||
|
|
||||||
|
type DB struct {
|
||||||
|
session *mgo.Session
|
||||||
|
books *mgo.Collection
|
||||||
|
user *mgo.Collection
|
||||||
|
news *mgo.Collection
|
||||||
|
stats *mgo.Collection
|
||||||
|
mr *MR
|
||||||
|
}
|
||||||
|
|
||||||
|
func initDB() *DB {
|
||||||
|
var err error
|
||||||
|
d := new(DB)
|
||||||
|
d.session, err = mgo.Dial(DB_IP)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
database := d.session.DB(DB_NAME)
|
||||||
|
d.books = database.C(BOOKS_COLL)
|
||||||
|
d.user = database.C(USERS_COLL)
|
||||||
|
d.news = database.C(NEWS_COLL)
|
||||||
|
d.stats = database.C(STATS_COLL)
|
||||||
|
d.mr = NewMR(database)
|
||||||
|
return d
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *DB) Close() {
|
||||||
|
d.session.Close()
|
||||||
|
}
|
||||||
|
|
||||||
|
func md5Pass(pass string) []byte {
|
||||||
|
h := md5.New()
|
||||||
|
hash := h.Sum(([]byte)(PASS_SALT + pass))
|
||||||
|
return hash
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *DB) SetPassword(user string, pass string) error {
|
||||||
|
hash := md5Pass(pass)
|
||||||
|
return d.user.Update(bson.M{"user": user}, bson.M{"$set": bson.M{"pass": hash}})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *DB) UserValid(user string, pass string) bool {
|
||||||
|
hash := md5Pass(pass)
|
||||||
|
n, err := d.user.Find(bson.M{"user": user, "pass": hash}).Count()
|
||||||
|
if err != nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return n != 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *DB) UserRole(user string) string {
|
||||||
|
type result struct {
|
||||||
|
Role string
|
||||||
|
}
|
||||||
|
res := result{}
|
||||||
|
err := d.user.Find(bson.M{"user": user}).One(&res)
|
||||||
|
if err != nil {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
return res.Role
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *DB) AddNews(text string) error {
|
||||||
|
var news News
|
||||||
|
news.Text = text
|
||||||
|
news.Date = time.Now()
|
||||||
|
return d.news.Insert(news)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *DB) GetNews(num int, days int) (news []News, err error) {
|
||||||
|
query := bson.M{}
|
||||||
|
if days != 0 {
|
||||||
|
duration := time.Duration(-24*days) * time.Hour
|
||||||
|
date := time.Now().Add(duration)
|
||||||
|
query = bson.M{"date": bson.M{"$gt": date}}
|
||||||
|
}
|
||||||
|
q := d.news.Find(query).Sort("-date").Limit(num)
|
||||||
|
err = q.All(&news)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *DB) InsertStats(stats interface{}) error {
|
||||||
|
return d.stats.Insert(stats)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *DB) InsertBook(book interface{}) error {
|
||||||
|
return d.books.Insert(book)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *DB) RemoveBook(id bson.ObjectId) error {
|
||||||
|
return d.books.Remove(bson.M{"_id": id})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *DB) UpdateBook(id bson.ObjectId, data interface{}) error {
|
||||||
|
return d.books.Update(bson.M{"_id": id}, bson.M{"$set": data})
|
||||||
|
}
|
||||||
|
|
||||||
|
/* optional parameters: length and start index
|
||||||
|
*
|
||||||
|
* Returns: list of books, number found and err
|
||||||
|
*/
|
||||||
|
func (d *DB) GetBooks(query bson.M, r ...int) (books []Book, num int, err error) {
|
||||||
|
var start, length int
|
||||||
|
if len(r) > 0 {
|
||||||
|
length = r[0]
|
||||||
|
if len(r) > 1 {
|
||||||
|
start = r[1]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
q := d.books.Find(query).Sort("-_id")
|
||||||
|
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)
|
||||||
|
for i, b := range books {
|
||||||
|
books[i].Id = bson.ObjectId(b.Id).Hex()
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Get the most visited books
|
||||||
|
*/
|
||||||
|
func (d *DB) GetVisitedBooks(num int) (books []Book, err error) {
|
||||||
|
bookId, err := d.mr.GetMostVisited(num, d.stats)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
books = make([]Book, num)
|
||||||
|
for i, id := range bookId {
|
||||||
|
d.books.Find(bson.M{"_id": id}).One(&books[i])
|
||||||
|
books[i].Id = bson.ObjectId(books[i].Id).Hex()
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Get the most downloaded books
|
||||||
|
*/
|
||||||
|
func (d *DB) GetDownloadedBooks(num int) (books []Book, err error) {
|
||||||
|
bookId, err := d.mr.GetMostDownloaded(num, d.stats)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
books = make([]Book, num)
|
||||||
|
for i, id := range bookId {
|
||||||
|
d.books.Find(bson.M{"_id": id}).One(&books[i])
|
||||||
|
books[i].Id = bson.ObjectId(books[i].Id).Hex()
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
/* optional parameters: length and start index
|
||||||
|
*
|
||||||
|
* Returns: list of books, number found and err
|
||||||
|
*/
|
||||||
|
func (d *DB) GetNewBooks(r ...int) (books []Book, num int, err error) {
|
||||||
|
return d.GetBooks(bson.M{"$nor": []bson.M{{"active": true}}}, r...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *DB) BookActive(id bson.ObjectId) bool {
|
||||||
|
var book Book
|
||||||
|
err := d.books.Find(bson.M{"_id": id}).One(&book)
|
||||||
|
if err != nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return book.Active
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *DB) GetFS(prefix string) *mgo.GridFS {
|
||||||
|
return d.session.DB(DB_NAME).GridFS(prefix)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *DB) GetTags(numTags int) ([]string, error) {
|
||||||
|
return d.mr.GetTags(numTags, d.books)
|
||||||
|
}
|
||||||
|
|
||||||
|
type Visits struct {
|
||||||
|
Date int64 "_id"
|
||||||
|
Count int "value"
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *DB) GetHourVisits(start time.Time) ([]Visits, error) {
|
||||||
|
return d.mr.GetHourVisits(start, d.stats)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *DB) GetDayVisits(start time.Time) ([]Visits, error) {
|
||||||
|
return d.mr.GetDayVisits(start, d.stats)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *DB) GetMonthVisits(start time.Time) ([]Visits, error) {
|
||||||
|
return d.mr.GetMonthVisits(start, d.stats)
|
||||||
|
}
|
266
tools/addsize/mapreduce.go
Normal file
266
tools/addsize/mapreduce.go
Normal file
|
@ -0,0 +1,266 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"labix.org/v2/mgo"
|
||||||
|
"labix.org/v2/mgo/bson"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
type MR struct {
|
||||||
|
meta *mgo.Collection
|
||||||
|
tags *mgo.Collection
|
||||||
|
visited *mgo.Collection
|
||||||
|
downloaded *mgo.Collection
|
||||||
|
hourly_raw *mgo.Collection
|
||||||
|
daily_raw *mgo.Collection
|
||||||
|
monthly_raw *mgo.Collection
|
||||||
|
hourly *mgo.Collection
|
||||||
|
daily *mgo.Collection
|
||||||
|
monthly *mgo.Collection
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewMR(database *mgo.Database) *MR {
|
||||||
|
m := new(MR)
|
||||||
|
m.meta = database.C(META_COLL)
|
||||||
|
m.tags = database.C(TAGS_COLL)
|
||||||
|
m.visited = database.C(VISITED_COLL)
|
||||||
|
m.downloaded = database.C(DOWNLOADED_COLL)
|
||||||
|
m.hourly_raw = database.C(HOURLY_VISITS_COLL + "_raw")
|
||||||
|
m.daily_raw = database.C(DAILY_VISITS_COLL + "_raw")
|
||||||
|
m.monthly_raw = database.C(MONTHLY_VISITS_COLL + "_raw")
|
||||||
|
m.hourly = database.C(HOURLY_VISITS_COLL)
|
||||||
|
m.daily = database.C(DAILY_VISITS_COLL)
|
||||||
|
m.monthly = database.C(MONTHLY_VISITS_COLL)
|
||||||
|
return m
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *MR) GetTags(numTags int, booksColl *mgo.Collection) ([]string, error) {
|
||||||
|
if m.isOutdated(TAGS_COLL, MINUTES_UPDATE_TAGS) {
|
||||||
|
var mr mgo.MapReduce
|
||||||
|
mr.Map = `function() {
|
||||||
|
if (this.subject) {
|
||||||
|
this.subject.forEach(function(s) { emit(s, 1); });
|
||||||
|
}
|
||||||
|
}`
|
||||||
|
mr.Reduce = `function(tag, vals) {
|
||||||
|
var count = 0;
|
||||||
|
vals.forEach(function() { count += 1; });
|
||||||
|
return count;
|
||||||
|
}`
|
||||||
|
err := m.update(&mr, bson.M{"active": true}, booksColl, TAGS_COLL)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var result []struct {
|
||||||
|
Tag string "_id"
|
||||||
|
}
|
||||||
|
err := m.tags.Find(nil).Sort("-value").Limit(numTags).All(&result)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
tags := make([]string, len(result))
|
||||||
|
for i, r := range result {
|
||||||
|
tags[i] = r.Tag
|
||||||
|
}
|
||||||
|
return tags, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *MR) GetMostVisited(num int, statsColl *mgo.Collection) ([]bson.ObjectId, error) {
|
||||||
|
if m.isOutdated(VISITED_COLL, MINUTES_UPDATE_VISITED) {
|
||||||
|
var mr mgo.MapReduce
|
||||||
|
mr.Map = `function() {
|
||||||
|
emit(this.id, 1);
|
||||||
|
}`
|
||||||
|
mr.Reduce = `function(tag, vals) {
|
||||||
|
var count = 0;
|
||||||
|
vals.forEach(function() { count += 1; });
|
||||||
|
return count;
|
||||||
|
}`
|
||||||
|
err := m.update(&mr, bson.M{"section": "book"}, statsColl, VISITED_COLL)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var result []struct {
|
||||||
|
Book bson.ObjectId "_id"
|
||||||
|
}
|
||||||
|
err := m.visited.Find(nil).Sort("-value").Limit(num).All(&result)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
books := make([]bson.ObjectId, len(result))
|
||||||
|
for i, r := range result {
|
||||||
|
books[i] = r.Book
|
||||||
|
}
|
||||||
|
return books, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *MR) GetMostDownloaded(num int, statsColl *mgo.Collection) ([]bson.ObjectId, error) {
|
||||||
|
if m.isOutdated(DOWNLOADED_COLL, MINUTES_UPDATE_DOWNLOADED) {
|
||||||
|
var mr mgo.MapReduce
|
||||||
|
mr.Map = `function() {
|
||||||
|
emit(this.id, 1);
|
||||||
|
}`
|
||||||
|
mr.Reduce = `function(tag, vals) {
|
||||||
|
var count = 0;
|
||||||
|
vals.forEach(function() { count += 1; });
|
||||||
|
return count;
|
||||||
|
}`
|
||||||
|
err := m.update(&mr, bson.M{"section": "download"}, statsColl, DOWNLOADED_COLL)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var result []struct {
|
||||||
|
Book bson.ObjectId "_id"
|
||||||
|
}
|
||||||
|
err := m.downloaded.Find(nil).Sort("-value").Limit(num).All(&result)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
books := make([]bson.ObjectId, len(result))
|
||||||
|
for i, r := range result {
|
||||||
|
books[i] = r.Book
|
||||||
|
}
|
||||||
|
return books, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *MR) GetHourVisits(start time.Time, statsColl *mgo.Collection) ([]Visits, error) {
|
||||||
|
if m.isOutdated(HOURLY_VISITS_COLL, MINUTES_UPDATE_HOURLY) {
|
||||||
|
const reduce = `function(date, vals) {
|
||||||
|
var count = 0;
|
||||||
|
vals.forEach(function(v) { count += v; });
|
||||||
|
return count;
|
||||||
|
}`
|
||||||
|
var mr mgo.MapReduce
|
||||||
|
mr.Map = `function() {
|
||||||
|
var date = Date.UTC(this.date.getUTCFullYear(),
|
||||||
|
this.date.getUTCMonth(),
|
||||||
|
this.date.getUTCDate(),
|
||||||
|
this.date.getUTCHours());
|
||||||
|
emit({date: date, session: this.session}, 1);
|
||||||
|
}`
|
||||||
|
mr.Reduce = reduce
|
||||||
|
err := m.update(&mr, bson.M{"date": bson.M{"$gte": start}}, statsColl, HOURLY_VISITS_COLL+"_raw")
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
var mr2 mgo.MapReduce
|
||||||
|
mr2.Map = `function() {
|
||||||
|
emit(this['_id']['date'], 1);
|
||||||
|
}`
|
||||||
|
mr2.Reduce = reduce
|
||||||
|
err = m.update(&mr2, bson.M{}, m.hourly_raw, HOURLY_VISITS_COLL)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var result []Visits
|
||||||
|
err := m.hourly.Find(nil).All(&result)
|
||||||
|
return result, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *MR) GetDayVisits(start time.Time, statsColl *mgo.Collection) ([]Visits, error) {
|
||||||
|
if m.isOutdated(DAILY_VISITS_COLL, MINUTES_UPDATE_DAILY) {
|
||||||
|
const reduce = `function(date, vals) {
|
||||||
|
var count = 0;
|
||||||
|
vals.forEach(function(v) { count += v; });
|
||||||
|
return count;
|
||||||
|
}`
|
||||||
|
var mr mgo.MapReduce
|
||||||
|
mr.Map = `function() {
|
||||||
|
var date = Date.UTC(this.date.getUTCFullYear(),
|
||||||
|
this.date.getUTCMonth(),
|
||||||
|
this.date.getUTCDate());
|
||||||
|
emit({date: date, session: this.session}, 1);
|
||||||
|
}`
|
||||||
|
mr.Reduce = reduce
|
||||||
|
err := m.update(&mr, bson.M{"date": bson.M{"$gte": start}}, statsColl, DAILY_VISITS_COLL+"_raw")
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
var mr2 mgo.MapReduce
|
||||||
|
mr2.Map = `function() {
|
||||||
|
emit(this['_id']['date'], 1);
|
||||||
|
}`
|
||||||
|
mr2.Reduce = reduce
|
||||||
|
err = m.update(&mr2, bson.M{}, m.daily_raw, DAILY_VISITS_COLL)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var result []Visits
|
||||||
|
err := m.daily.Find(nil).All(&result)
|
||||||
|
return result, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *MR) GetMonthVisits(start time.Time, statsColl *mgo.Collection) ([]Visits, error) {
|
||||||
|
if m.isOutdated(MONTHLY_VISITS_COLL, MINUTES_UPDATE_MONTHLY) {
|
||||||
|
const reduce = `function(date, vals) {
|
||||||
|
var count = 0;
|
||||||
|
vals.forEach(function(v) { count += v; });
|
||||||
|
return count;
|
||||||
|
}`
|
||||||
|
var mr mgo.MapReduce
|
||||||
|
mr.Map = `function() {
|
||||||
|
var date = Date.UTC(this.date.getUTCFullYear(),
|
||||||
|
this.date.getUTCMonth());
|
||||||
|
emit({date: date, session: this.session}, 1);
|
||||||
|
}`
|
||||||
|
mr.Reduce = reduce
|
||||||
|
err := m.update(&mr, bson.M{"date": bson.M{"$gte": start}}, statsColl, MONTHLY_VISITS_COLL+"_raw")
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
var mr2 mgo.MapReduce
|
||||||
|
mr2.Map = `function() {
|
||||||
|
emit(this['_id']['date'], 1);
|
||||||
|
}`
|
||||||
|
mr2.Reduce = reduce
|
||||||
|
err = m.update(&mr2, bson.M{}, m.monthly_raw, MONTHLY_VISITS_COLL)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var result []Visits
|
||||||
|
err := m.monthly.Find(nil).All(&result)
|
||||||
|
return result, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *MR) update(mr *mgo.MapReduce, query bson.M, queryColl *mgo.Collection, storeColl string) error {
|
||||||
|
_, err := m.meta.RemoveAll(bson.M{"type": storeColl})
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
mr.Out = bson.M{"replace": storeColl}
|
||||||
|
_, err = queryColl.Find(query).MapReduce(mr, nil)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return m.meta.Insert(bson.M{"type": storeColl})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *MR) isOutdated(coll string, minutes float64) bool {
|
||||||
|
var result struct {
|
||||||
|
Id bson.ObjectId `bson:"_id"`
|
||||||
|
}
|
||||||
|
err := m.meta.Find(bson.M{"type": coll}).One(&result)
|
||||||
|
if err != nil {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
lastUpdate := result.Id.Time()
|
||||||
|
return time.Since(lastUpdate).Minutes() > minutes
|
||||||
|
}
|
149
trantor.go
149
trantor.go
|
@ -13,26 +13,26 @@ type statusData struct {
|
||||||
S Status
|
S Status
|
||||||
}
|
}
|
||||||
|
|
||||||
func aboutHandler(w http.ResponseWriter, r *http.Request, sess *Session) {
|
func aboutHandler(h handler) {
|
||||||
var data statusData
|
var data statusData
|
||||||
data.S = GetStatus(w, r)
|
data.S = GetStatus(h)
|
||||||
data.S.About = true
|
data.S.About = true
|
||||||
loadTemplate(w, "about", data)
|
loadTemplate(h.w, "about", data)
|
||||||
}
|
}
|
||||||
|
|
||||||
func helpHandler(w http.ResponseWriter, r *http.Request, sess *Session) {
|
func helpHandler(h handler) {
|
||||||
var data statusData
|
var data statusData
|
||||||
data.S = GetStatus(w, r)
|
data.S = GetStatus(h)
|
||||||
data.S.Help = true
|
data.S.Help = true
|
||||||
loadTemplate(w, "help", data)
|
loadTemplate(h.w, "help", data)
|
||||||
}
|
}
|
||||||
|
|
||||||
func logoutHandler(w http.ResponseWriter, r *http.Request, sess *Session) {
|
func logoutHandler(h handler) {
|
||||||
sess.LogOut()
|
h.sess.LogOut()
|
||||||
sess.Notify("Log out!", "Bye bye "+sess.User, "success")
|
h.sess.Notify("Log out!", "Bye bye "+h.sess.User, "success")
|
||||||
sess.Save(w, r)
|
h.sess.Save(h.w, h.r)
|
||||||
log.Println("User", sess.User, "log out")
|
log.Println("User", h.sess.User, "log out")
|
||||||
http.Redirect(w, r, "/", http.StatusFound)
|
http.Redirect(h.w, h.r, "/", http.StatusFound)
|
||||||
}
|
}
|
||||||
|
|
||||||
type bookData struct {
|
type bookData struct {
|
||||||
|
@ -41,62 +41,61 @@ type bookData struct {
|
||||||
Description []string
|
Description []string
|
||||||
}
|
}
|
||||||
|
|
||||||
func bookHandler(w http.ResponseWriter, r *http.Request, sess *Session) {
|
func bookHandler(h handler) {
|
||||||
idStr := mux.Vars(r)["id"]
|
idStr := mux.Vars(h.r)["id"]
|
||||||
if !bson.IsObjectIdHex(idStr) {
|
if !bson.IsObjectIdHex(idStr) {
|
||||||
notFound(w, r)
|
notFound(h)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
var data bookData
|
var data bookData
|
||||||
data.S = GetStatus(w, r)
|
data.S = GetStatus(h)
|
||||||
id := bson.ObjectIdHex(idStr)
|
id := bson.ObjectIdHex(idStr)
|
||||||
books, _, err := db.GetBooks(bson.M{"_id": id})
|
books, _, err := h.db.GetBooks(bson.M{"_id": id})
|
||||||
if err != nil || len(books) == 0 {
|
if err != nil || len(books) == 0 {
|
||||||
notFound(w, r)
|
notFound(h)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
data.Book = books[0]
|
data.Book = books[0]
|
||||||
data.Description = strings.Split(data.Book.Description, "\n")
|
data.Description = strings.Split(data.Book.Description, "\n")
|
||||||
loadTemplate(w, "book", data)
|
loadTemplate(h.w, "book", data)
|
||||||
}
|
}
|
||||||
|
|
||||||
func downloadHandler(w http.ResponseWriter, r *http.Request, sess *Session) {
|
func downloadHandler(h handler) {
|
||||||
idStr := mux.Vars(r)["id"]
|
idStr := mux.Vars(h.r)["id"]
|
||||||
if !bson.IsObjectIdHex(idStr) {
|
if !bson.IsObjectIdHex(idStr) {
|
||||||
notFound(w, r)
|
notFound(h)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
id := bson.ObjectIdHex(idStr)
|
id := bson.ObjectIdHex(idStr)
|
||||||
books, _, err := db.GetBooks(bson.M{"_id": id})
|
books, _, err := h.db.GetBooks(bson.M{"_id": id})
|
||||||
if err != nil || len(books) == 0 {
|
if err != nil || len(books) == 0 {
|
||||||
notFound(w, r)
|
notFound(h)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
book := books[0]
|
book := books[0]
|
||||||
|
|
||||||
if !book.Active {
|
if !book.Active {
|
||||||
sess := GetSession(r)
|
if !h.sess.IsAdmin() {
|
||||||
if !sess.IsAdmin() {
|
notFound(h)
|
||||||
notFound(w, r)
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fs := db.GetFS(FS_BOOKS)
|
fs := h.db.GetFS(FS_BOOKS)
|
||||||
f, err := fs.OpenId(book.File)
|
f, err := fs.OpenId(book.File)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
notFound(w, r)
|
notFound(h)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
defer f.Close()
|
defer f.Close()
|
||||||
|
|
||||||
headers := w.Header()
|
headers := h.w.Header()
|
||||||
headers["Content-Type"] = []string{"application/epub+zip"}
|
headers["Content-Type"] = []string{"application/epub+zip"}
|
||||||
headers["Content-Disposition"] = []string{"attachment; filename=\"" + f.Name() + "\""}
|
headers["Content-Disposition"] = []string{"attachment; filename=\"" + f.Name() + "\""}
|
||||||
|
|
||||||
io.Copy(w, f)
|
io.Copy(h.w, f)
|
||||||
}
|
}
|
||||||
|
|
||||||
type indexData struct {
|
type indexData struct {
|
||||||
|
@ -109,70 +108,70 @@ type indexData struct {
|
||||||
News []newsEntry
|
News []newsEntry
|
||||||
}
|
}
|
||||||
|
|
||||||
func indexHandler(w http.ResponseWriter, r *http.Request, sess *Session) {
|
func indexHandler(h handler) {
|
||||||
var data indexData
|
var data indexData
|
||||||
|
|
||||||
data.Tags, _ = db.GetTags(TAGS_DISPLAY)
|
data.Tags, _ = h.db.GetTags(TAGS_DISPLAY)
|
||||||
data.S = GetStatus(w, r)
|
data.S = GetStatus(h)
|
||||||
data.S.Home = true
|
data.S.Home = true
|
||||||
data.Books, data.Count, _ = db.GetBooks(bson.M{"active": true}, 6)
|
data.Books, data.Count, _ = h.db.GetBooks(bson.M{"active": true}, 6)
|
||||||
data.VisitedBooks, _ = db.GetVisitedBooks(6)
|
data.VisitedBooks, _ = h.db.GetVisitedBooks(6)
|
||||||
data.DownloadedBooks, _ = db.GetDownloadedBooks(6)
|
data.DownloadedBooks, _ = h.db.GetDownloadedBooks(6)
|
||||||
data.News = getNews(1, DAYS_NEWS_INDEXPAGE)
|
data.News = getNews(1, DAYS_NEWS_INDEXPAGE, h.db)
|
||||||
loadTemplate(w, "index", data)
|
loadTemplate(h.w, "index", data)
|
||||||
}
|
}
|
||||||
|
|
||||||
func notFound(w http.ResponseWriter, r *http.Request) {
|
func notFound(h handler) {
|
||||||
var data statusData
|
var data statusData
|
||||||
|
|
||||||
data.S = GetStatus(w, r)
|
data.S = GetStatus(h)
|
||||||
w.WriteHeader(http.StatusNotFound)
|
h.w.WriteHeader(http.StatusNotFound)
|
||||||
loadTemplate(w, "404", data)
|
loadTemplate(h.w, "404", data)
|
||||||
}
|
}
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
db = initDB()
|
db := initDB()
|
||||||
defer db.Close()
|
defer db.Close()
|
||||||
|
|
||||||
InitStats()
|
InitStats(db)
|
||||||
InitUpload()
|
InitUpload(db)
|
||||||
|
|
||||||
setUpRouter()
|
setUpRouter(db)
|
||||||
panic(http.ListenAndServe(":"+PORT, nil))
|
panic(http.ListenAndServe(":"+PORT, nil))
|
||||||
}
|
}
|
||||||
|
|
||||||
func setUpRouter() {
|
func setUpRouter(db *DB) {
|
||||||
r := mux.NewRouter()
|
r := mux.NewRouter()
|
||||||
var notFoundHandler http.HandlerFunc
|
var notFoundHandler http.HandlerFunc
|
||||||
notFoundHandler = GatherStats(func(w http.ResponseWriter, r *http.Request, sess *Session) { notFound(w, r) })
|
notFoundHandler = GatherStats(notFound, db)
|
||||||
r.NotFoundHandler = notFoundHandler
|
r.NotFoundHandler = notFoundHandler
|
||||||
|
|
||||||
r.HandleFunc("/", GatherStats(indexHandler))
|
r.HandleFunc("/", GatherStats(indexHandler, db))
|
||||||
r.HandleFunc("/book/{id:[0-9a-fA-F]+}", GatherStats(bookHandler))
|
r.HandleFunc("/book/{id:[0-9a-fA-F]+}", GatherStats(bookHandler, db))
|
||||||
r.HandleFunc("/search/", GatherStats(searchHandler))
|
r.HandleFunc("/search/", GatherStats(searchHandler, db))
|
||||||
r.HandleFunc("/upload/", GatherStats(uploadHandler)).Methods("GET")
|
r.HandleFunc("/upload/", GatherStats(uploadHandler, db)).Methods("GET")
|
||||||
r.HandleFunc("/upload/", GatherStats(uploadPostHandler)).Methods("POST")
|
r.HandleFunc("/upload/", GatherStats(uploadPostHandler, db)).Methods("POST")
|
||||||
r.HandleFunc("/login/", GatherStats(loginHandler)).Methods("GET")
|
r.HandleFunc("/login/", GatherStats(loginHandler, db)).Methods("GET")
|
||||||
r.HandleFunc("/login/", GatherStats(loginPostHandler)).Methods("POST")
|
r.HandleFunc("/login/", GatherStats(loginPostHandler, db)).Methods("POST")
|
||||||
r.HandleFunc("/create_user/", GatherStats(createUserHandler)).Methods("POST")
|
r.HandleFunc("/create_user/", GatherStats(createUserHandler, db)).Methods("POST")
|
||||||
r.HandleFunc("/logout/", GatherStats(logoutHandler))
|
r.HandleFunc("/logout/", GatherStats(logoutHandler, db))
|
||||||
r.HandleFunc("/new/", GatherStats(newHandler))
|
r.HandleFunc("/new/", GatherStats(newHandler, db))
|
||||||
r.HandleFunc("/store/{ids:([0-9a-fA-F]+/)+}", GatherStats(storeHandler))
|
r.HandleFunc("/store/{ids:([0-9a-fA-F]+/)+}", GatherStats(storeHandler, db))
|
||||||
r.HandleFunc("/delete/{ids:([0-9a-fA-F]+/)+}", GatherStats(deleteHandler))
|
r.HandleFunc("/delete/{ids:([0-9a-fA-F]+/)+}", GatherStats(deleteHandler, db))
|
||||||
r.HandleFunc("/read/{id:[0-9a-fA-F]+}", GatherStats(readStartHandler))
|
r.HandleFunc("/read/{id:[0-9a-fA-F]+}", GatherStats(readStartHandler, db))
|
||||||
r.HandleFunc("/read/{id:[0-9a-fA-F]+}/{file:.*}", GatherStats(readHandler))
|
r.HandleFunc("/read/{id:[0-9a-fA-F]+}/{file:.*}", GatherStats(readHandler, db))
|
||||||
r.HandleFunc("/content/{id:[0-9a-fA-F]+}/{file:.*}", GatherStats(contentHandler))
|
r.HandleFunc("/content/{id:[0-9a-fA-F]+}/{file:.*}", GatherStats(contentHandler, db))
|
||||||
r.HandleFunc("/edit/{id:[0-9a-fA-F]+}", GatherStats(editHandler))
|
r.HandleFunc("/edit/{id:[0-9a-fA-F]+}", GatherStats(editHandler, db))
|
||||||
r.HandleFunc("/save/{id:[0-9a-fA-F]+}", GatherStats(saveHandler)).Methods("POST")
|
r.HandleFunc("/save/{id:[0-9a-fA-F]+}", GatherStats(saveHandler, db)).Methods("POST")
|
||||||
r.HandleFunc("/about/", GatherStats(aboutHandler))
|
r.HandleFunc("/about/", GatherStats(aboutHandler, db))
|
||||||
r.HandleFunc("/help/", GatherStats(helpHandler))
|
r.HandleFunc("/help/", GatherStats(helpHandler, db))
|
||||||
r.HandleFunc("/download/{id:[0-9a-fA-F]+}/{epub:.*}", GatherStats(downloadHandler))
|
r.HandleFunc("/download/{id:[0-9a-fA-F]+}/{epub:.*}", GatherStats(downloadHandler, db))
|
||||||
r.HandleFunc("/cover/{id:[0-9a-fA-F]+}/{size}/{img:.*}", coverHandler)
|
r.HandleFunc("/cover/{id:[0-9a-fA-F]+}/{size}/{img:.*}", GatherStats(coverHandler, db))
|
||||||
r.HandleFunc("/settings/", GatherStats(settingsHandler))
|
r.HandleFunc("/settings/", GatherStats(settingsHandler, db))
|
||||||
r.HandleFunc("/stats/", GatherStats(statsHandler))
|
r.HandleFunc("/stats/", GatherStats(statsHandler, db))
|
||||||
r.HandleFunc("/news/", GatherStats(newsHandler))
|
r.HandleFunc("/news/", GatherStats(newsHandler, db))
|
||||||
r.HandleFunc("/news/edit", GatherStats(editNewsHandler)).Methods("GET")
|
r.HandleFunc("/news/edit", GatherStats(editNewsHandler, db)).Methods("GET")
|
||||||
r.HandleFunc("/news/edit", GatherStats(postNewsHandler)).Methods("POST")
|
r.HandleFunc("/news/edit", GatherStats(postNewsHandler, db)).Methods("POST")
|
||||||
h := http.FileServer(http.Dir(IMG_PATH))
|
h := http.FileServer(http.Dir(IMG_PATH))
|
||||||
r.Handle("/img/{img}", http.StripPrefix("/img/", h))
|
r.Handle("/img/{img}", http.StripPrefix("/img/", h))
|
||||||
h = http.FileServer(http.Dir(CSS_PATH))
|
h = http.FileServer(http.Dir(CSS_PATH))
|
||||||
|
|
43
upload.go
43
upload.go
|
@ -6,13 +6,12 @@ import (
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"log"
|
"log"
|
||||||
"mime/multipart"
|
"mime/multipart"
|
||||||
"net/http"
|
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
func InitUpload() {
|
func InitUpload(database *DB) {
|
||||||
uploadChannel = make(chan uploadRequest, CHAN_SIZE)
|
uploadChannel = make(chan uploadRequest, CHAN_SIZE)
|
||||||
go uploadWorker()
|
go uploadWorker(database)
|
||||||
}
|
}
|
||||||
|
|
||||||
var uploadChannel chan uploadRequest
|
var uploadChannel chan uploadRequest
|
||||||
|
@ -22,13 +21,16 @@ type uploadRequest struct {
|
||||||
filename string
|
filename string
|
||||||
}
|
}
|
||||||
|
|
||||||
func uploadWorker() {
|
func uploadWorker(database *DB) {
|
||||||
|
db := database.Copy()
|
||||||
|
defer db.Close()
|
||||||
|
|
||||||
for req := range uploadChannel {
|
for req := range uploadChannel {
|
||||||
processFile(req)
|
processFile(req, db)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func processFile(req uploadRequest) {
|
func processFile(req uploadRequest, db *DB) {
|
||||||
defer req.file.Close()
|
defer req.file.Close()
|
||||||
|
|
||||||
epub, err := openMultipartEpub(req.file)
|
epub, err := openMultipartEpub(req.file)
|
||||||
|
@ -38,16 +40,17 @@ func processFile(req uploadRequest) {
|
||||||
}
|
}
|
||||||
defer epub.Close()
|
defer epub.Close()
|
||||||
|
|
||||||
book := parseFile(epub)
|
book := parseFile(epub, db)
|
||||||
title, _ := book["title"].(string)
|
title, _ := book["title"].(string)
|
||||||
req.file.Seek(0, 0)
|
req.file.Seek(0, 0)
|
||||||
id, err := StoreNewFile(title+".epub", req.file)
|
id, size, err := StoreNewFile(title+".epub", req.file, db)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Println("Error storing book (", title, "):", err)
|
log.Println("Error storing book (", title, "):", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
book["file"] = id
|
book["file"] = id
|
||||||
|
book["filesize"] = size
|
||||||
err = db.InsertBook(book)
|
err = db.InsertBook(book)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Println("Error storing metadata (", title, "):", err)
|
log.Println("Error storing metadata (", title, "):", err)
|
||||||
|
@ -56,16 +59,16 @@ func processFile(req uploadRequest) {
|
||||||
log.Println("File uploaded:", req.filename)
|
log.Println("File uploaded:", req.filename)
|
||||||
}
|
}
|
||||||
|
|
||||||
func uploadPostHandler(w http.ResponseWriter, r *http.Request, sess *Session) {
|
func uploadPostHandler(h handler) {
|
||||||
problem := false
|
problem := false
|
||||||
|
|
||||||
r.ParseMultipartForm(20000000)
|
h.r.ParseMultipartForm(20000000)
|
||||||
filesForm := r.MultipartForm.File["epub"]
|
filesForm := h.r.MultipartForm.File["epub"]
|
||||||
for _, f := range filesForm {
|
for _, f := range filesForm {
|
||||||
file, err := f.Open()
|
file, err := f.Open()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Println("Can not open uploaded file", f.Filename, ":", err)
|
log.Println("Can not open uploaded file", f.Filename, ":", err)
|
||||||
sess.Notify("Upload problem!", "There was a problem with book "+f.Filename, "error")
|
h.sess.Notify("Upload problem!", "There was a problem with book "+f.Filename, "error")
|
||||||
problem = true
|
problem = true
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
@ -74,19 +77,19 @@ func uploadPostHandler(w http.ResponseWriter, r *http.Request, sess *Session) {
|
||||||
|
|
||||||
if !problem {
|
if !problem {
|
||||||
if len(filesForm) > 0 {
|
if len(filesForm) > 0 {
|
||||||
sess.Notify("Upload successful!", "Thank you for your contribution", "success")
|
h.sess.Notify("Upload successful!", "Thank you for your contribution", "success")
|
||||||
} else {
|
} else {
|
||||||
sess.Notify("Upload problem!", "No books where uploaded.", "error")
|
h.sess.Notify("Upload problem!", "No books where uploaded.", "error")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
uploadHandler(w, r, sess)
|
uploadHandler(h)
|
||||||
}
|
}
|
||||||
|
|
||||||
func uploadHandler(w http.ResponseWriter, r *http.Request, sess *Session) {
|
func uploadHandler(h handler) {
|
||||||
var data uploadData
|
var data uploadData
|
||||||
data.S = GetStatus(w, r)
|
data.S = GetStatus(h)
|
||||||
data.S.Upload = true
|
data.S.Upload = true
|
||||||
loadTemplate(w, "upload", data)
|
loadTemplate(h.w, "upload", data)
|
||||||
}
|
}
|
||||||
|
|
||||||
type uploadData struct {
|
type uploadData struct {
|
||||||
|
@ -99,7 +102,7 @@ func openMultipartEpub(file multipart.File) (*epubgo.Epub, error) {
|
||||||
return epubgo.Load(reader, int64(len(buff)))
|
return epubgo.Load(reader, int64(len(buff)))
|
||||||
}
|
}
|
||||||
|
|
||||||
func parseFile(epub *epubgo.Epub) map[string]interface{} {
|
func parseFile(epub *epubgo.Epub, db *DB) map[string]interface{} {
|
||||||
book := map[string]interface{}{}
|
book := map[string]interface{}{}
|
||||||
for _, m := range epub.MetadataFields() {
|
for _, m := range epub.MetadataFields() {
|
||||||
data, err := epub.Metadata(m)
|
data, err := epub.Metadata(m)
|
||||||
|
@ -132,7 +135,7 @@ func parseFile(epub *epubgo.Epub) map[string]interface{} {
|
||||||
}
|
}
|
||||||
title, _ := book["title"].(string)
|
title, _ := book["title"].(string)
|
||||||
book["file"] = nil
|
book["file"] = nil
|
||||||
cover, coverSmall := GetCover(epub, title)
|
cover, coverSmall := GetCover(epub, title, db)
|
||||||
if cover != "" {
|
if cover != "" {
|
||||||
book["cover"] = cover
|
book["cover"] = cover
|
||||||
book["coversmall"] = coverSmall
|
book["coversmall"] = coverSmall
|
||||||
|
|
74
user.go
74
user.go
|
@ -5,71 +5,71 @@ import (
|
||||||
"net/http"
|
"net/http"
|
||||||
)
|
)
|
||||||
|
|
||||||
func loginHandler(w http.ResponseWriter, r *http.Request, sess *Session) {
|
func loginHandler(h handler) {
|
||||||
var data statusData
|
var data statusData
|
||||||
data.S = GetStatus(w, r)
|
data.S = GetStatus(h)
|
||||||
loadTemplate(w, "login", data)
|
loadTemplate(h.w, "login", data)
|
||||||
}
|
}
|
||||||
|
|
||||||
func loginPostHandler(w http.ResponseWriter, r *http.Request, sess *Session) {
|
func loginPostHandler(h handler) {
|
||||||
user := r.FormValue("user")
|
user := h.r.FormValue("user")
|
||||||
pass := r.FormValue("pass")
|
pass := h.r.FormValue("pass")
|
||||||
if db.UserValid(user, pass) {
|
if h.db.UserValid(user, pass) {
|
||||||
log.Println("User", user, "log in")
|
log.Println("User", user, "log in")
|
||||||
sess.LogIn(user)
|
h.sess.LogIn(user)
|
||||||
sess.Notify("Successful login!", "Welcome "+user, "success")
|
h.sess.Notify("Successful login!", "Welcome "+user, "success")
|
||||||
} else {
|
} else {
|
||||||
log.Println("User", user, "bad user or password")
|
log.Println("User", user, "bad user or password")
|
||||||
sess.Notify("Invalid login!", "user or password invalid", "error")
|
h.sess.Notify("Invalid login!", "user or password invalid", "error")
|
||||||
}
|
}
|
||||||
sess.Save(w, r)
|
h.sess.Save(h.w, h.r)
|
||||||
http.Redirect(w, r, r.Referer(), http.StatusFound)
|
http.Redirect(h.w, h.r, h.r.Referer(), http.StatusFound)
|
||||||
}
|
}
|
||||||
|
|
||||||
func createUserHandler(w http.ResponseWriter, r *http.Request, sess *Session) {
|
func createUserHandler(h handler) {
|
||||||
pass := r.FormValue("pass")
|
pass := h.r.FormValue("pass")
|
||||||
confirmPass := r.FormValue("confirmPass")
|
confirmPass := h.r.FormValue("confirmPass")
|
||||||
if pass != confirmPass {
|
if pass != confirmPass {
|
||||||
sess.Notify("Registration error!", "Passwords don't match", "error")
|
h.sess.Notify("Registration error!", "Passwords don't match", "error")
|
||||||
} else {
|
} else {
|
||||||
user := r.FormValue("user")
|
user := h.r.FormValue("user")
|
||||||
err := db.AddUser(user, pass)
|
err := h.db.AddUser(user, pass)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
sess.Notify("Account created!", "Welcome "+user+". Now you can login", "success")
|
h.sess.Notify("Account created!", "Welcome "+user+". Now you can login", "success")
|
||||||
} else {
|
} else {
|
||||||
sess.Notify("Registration error!", "There was some database problem, if it keeps happening please inform me", "error")
|
h.sess.Notify("Registration error!", "There was some database problem, if it keeps happening please inform me", "error")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
sess.Save(w, r)
|
h.sess.Save(h.w, h.r)
|
||||||
http.Redirect(w, r, r.Referer(), http.StatusFound)
|
http.Redirect(h.w, h.r, h.r.Referer(), http.StatusFound)
|
||||||
}
|
}
|
||||||
|
|
||||||
type settingsData struct {
|
type settingsData struct {
|
||||||
S Status
|
S Status
|
||||||
}
|
}
|
||||||
|
|
||||||
func settingsHandler(w http.ResponseWriter, r *http.Request, sess *Session) {
|
func settingsHandler(h handler) {
|
||||||
if sess.User == "" {
|
if h.sess.User == "" {
|
||||||
notFound(w, r)
|
notFound(h)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if r.Method == "POST" {
|
if h.r.Method == "POST" {
|
||||||
current_pass := r.FormValue("currpass")
|
current_pass := h.r.FormValue("currpass")
|
||||||
pass1 := r.FormValue("password1")
|
pass1 := h.r.FormValue("password1")
|
||||||
pass2 := r.FormValue("password2")
|
pass2 := h.r.FormValue("password2")
|
||||||
switch {
|
switch {
|
||||||
case !db.UserValid(sess.User, current_pass):
|
case !h.db.UserValid(h.sess.User, current_pass):
|
||||||
sess.Notify("Password error!", "The current password given don't match with the user password. Try again", "error")
|
h.sess.Notify("Password error!", "The current password given don't match with the user password. Try again", "error")
|
||||||
case pass1 != pass2:
|
case pass1 != pass2:
|
||||||
sess.Notify("Passwords don't match!", "The new password and the confirmation password don't match. Try again", "error")
|
h.sess.Notify("Passwords don't match!", "The new password and the confirmation password don't match. Try again", "error")
|
||||||
default:
|
default:
|
||||||
db.SetPassword(sess.User, pass1)
|
h.db.SetPassword(h.sess.User, pass1)
|
||||||
sess.Notify("Password updated!", "Your new password is correctly set.", "success")
|
h.sess.Notify("Password updated!", "Your new password is correctly set.", "success")
|
||||||
}
|
}
|
||||||
sess.Save(w, r)
|
h.sess.Save(h.w, h.r)
|
||||||
}
|
}
|
||||||
|
|
||||||
var data settingsData
|
var data settingsData
|
||||||
data.S = GetStatus(w, r)
|
data.S = GetStatus(h)
|
||||||
loadTemplate(w, "settings", data)
|
loadTemplate(h.w, "settings", data)
|
||||||
}
|
}
|
||||||
|
|
Reference in a new issue