Merge branch 'master' into user

Conflicts:
	admin.go
	template.go
	trantor.go
This commit is contained in:
Las Zenow 2013-09-24 10:53:51 +02:00
commit 8e3b929dfe
22 changed files with 1015 additions and 385 deletions

1
.gitignore vendored
View file

@ -7,5 +7,6 @@ tools/update/update
tools/togridfs/togridfs
tools/getISBNnDesc/getISBNnDesc
tools/coverNew/coverNew
tools/addsize/addsize
tags
.*.swp

122
admin.go
View file

@ -9,29 +9,29 @@ import (
"strings"
)
func deleteHandler(w http.ResponseWriter, r *http.Request, sess *Session) {
if !sess.IsAdmin() {
notFound(w, r)
func deleteHandler(h handler) {
if !h.sess.IsAdmin() {
notFound(h)
return
}
var titles []string
var isNew bool
ids := strings.Split(mux.Vars(r)["ids"], "/")
ids := strings.Split(mux.Vars(h.r)["ids"], "/")
for _, idStr := range ids {
if !bson.IsObjectIdHex(idStr) {
continue
}
id := bson.ObjectIdHex(idStr)
books, _, err := db.GetBooks(bson.M{"_id": id})
books, _, err := h.db.GetBooks(bson.M{"_id": id})
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
}
book := books[0]
DeleteBook(book)
db.RemoveBook(id)
DeleteBook(book, h.db)
h.db.RemoveBook(id)
if !book.Active {
isNew = true
@ -39,33 +39,33 @@ func deleteHandler(w http.ResponseWriter, r *http.Request, sess *Session) {
titles = append(titles, book.Title)
}
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 {
http.Redirect(w, r, "/new/", http.StatusFound)
http.Redirect(h.w, h.r, "/new/", http.StatusFound)
} 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) {
idStr := mux.Vars(r)["id"]
if !sess.IsAdmin() || !bson.IsObjectIdHex(idStr) {
notFound(w, r)
func editHandler(h handler) {
idStr := mux.Vars(h.r)["id"]
if !h.sess.IsAdmin() || !bson.IsObjectIdHex(idStr) {
notFound(h)
return
}
id := bson.ObjectIdHex(idStr)
books, _, err := db.GetBooks(bson.M{"_id": id})
books, _, err := h.db.GetBooks(bson.M{"_id": id})
if err != nil {
notFound(w, r)
notFound(h)
return
}
var data bookData
data.Book = books[0]
data.S = GetStatus(w, r)
loadTemplate(w, "edit", data)
data.S = GetStatus(h)
loadTemplate(h.w, "edit", data)
}
func cleanEmptyStr(s []string) []string {
@ -78,21 +78,21 @@ func cleanEmptyStr(s []string) []string {
return res
}
func saveHandler(w http.ResponseWriter, r *http.Request, sess *Session) {
idStr := mux.Vars(r)["id"]
if !sess.IsAdmin() || !bson.IsObjectIdHex(idStr) {
notFound(w, r)
func saveHandler(h handler) {
idStr := mux.Vars(h.r)["id"]
if !h.sess.IsAdmin() || !bson.IsObjectIdHex(idStr) {
notFound(h)
return
}
id := bson.ObjectIdHex(idStr)
title := r.FormValue("title")
publisher := r.FormValue("publisher")
date := r.FormValue("date")
description := r.FormValue("description")
author := cleanEmptyStr(r.Form["author"])
subject := cleanEmptyStr(r.Form["subject"])
lang := cleanEmptyStr(r.Form["lang"])
title := h.r.FormValue("title")
publisher := h.r.FormValue("publisher")
date := h.r.FormValue("date")
description := h.r.FormValue("description")
author := cleanEmptyStr(h.r.Form["author"])
subject := cleanEmptyStr(h.r.Form["subject"])
lang := cleanEmptyStr(h.r.Form["lang"])
book := map[string]interface{}{"title": title,
"publisher": publisher,
"date": date,
@ -101,18 +101,18 @@ func saveHandler(w http.ResponseWriter, r *http.Request, sess *Session) {
"subject": subject,
"lang": lang}
book["keywords"] = keywords(book)
err := db.UpdateBook(id, book)
err := h.db.UpdateBook(id, book)
if err != nil {
notFound(w, r)
notFound(h)
return
}
sess.Notify("Book Modified!", "", "success")
sess.Save(w, r)
if db.BookActive(id) {
http.Redirect(w, r, "/book/"+idStr, http.StatusFound)
h.sess.Notify("Book Modified!", "", "success")
h.sess.Save(h.w, h.r)
if h.db.BookActive(id) {
http.Redirect(h.w, h.r, "/book/"+idStr, http.StatusFound)
} 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
}
func newHandler(w http.ResponseWriter, r *http.Request, sess *Session) {
if !sess.IsAdmin() {
notFound(w, r)
func newHandler(h handler) {
if !h.sess.IsAdmin() {
notFound(h)
return
}
err := r.ParseForm()
err := h.r.ParseForm()
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
http.Error(h.w, err.Error(), http.StatusInternalServerError)
return
}
page := 0
if len(r.Form["p"]) != 0 {
page, err = strconv.Atoi(r.Form["p"][0])
if len(h.r.Form["p"]) != 0 {
page, err = strconv.Atoi(h.r.Form["p"][0])
if err != nil {
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
data.S = GetStatus(w, r)
data.S = GetStatus(h)
data.Found = num
if num-NEW_ITEMS_PAGE*page < NEW_ITEMS_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 {
data.Books[i].B = b
_, data.Books[i].TitleFound, _ = db.GetBooks(buildQuery("title:"+b.Title), 1)
_, data.Books[i].AuthorFound, _ = db.GetBooks(buildQuery("author:"+strings.Join(b.Author, " author:")), 1)
_, data.Books[i].TitleFound, _ = h.db.GetBooks(buildQuery("title:"+b.Title), 1)
_, data.Books[i].AuthorFound, _ = h.db.GetBooks(buildQuery("author:"+strings.Join(b.Author, " author:")), 1)
}
data.Page = page + 1
if num > (page+1)*NEW_ITEMS_PAGE {
@ -170,40 +170,40 @@ func newHandler(w http.ResponseWriter, r *http.Request, sess *Session) {
if page > 0 {
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) {
if !sess.IsAdmin() {
notFound(w, r)
func storeHandler(h handler) {
if !h.sess.IsAdmin() {
notFound(h)
return
}
var titles []string
ids := strings.Split(mux.Vars(r)["ids"], "/")
ids := strings.Split(mux.Vars(h.r)["ids"], "/")
for _, idStr := range ids {
if !bson.IsObjectIdHex(idStr) {
continue
}
id := bson.ObjectIdHex(idStr)
books, _, err := db.GetBooks(bson.M{"_id": id})
books, _, err := h.db.GetBooks(bson.M{"_id": id})
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
}
book := books[0]
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())
continue
}
db.UpdateBook(id, bson.M{"active": true})
h.db.UpdateBook(id, bson.M{"active": true})
titles = append(titles, book.Title)
}
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)
http.Redirect(w, r, "/new/", http.StatusFound)
h.sess.Save(h.w, h.r)
http.Redirect(h.w, h.r, "/new/", http.StatusFound)
}

View file

@ -16,34 +16,32 @@ import (
"labix.org/v2/mgo"
"labix.org/v2/mgo/bson"
"log"
"net/http"
"regexp"
"strings"
)
func coverHandler(w http.ResponseWriter, r *http.Request) {
vars := mux.Vars(r)
func coverHandler(h handler) {
vars := mux.Vars(h.r)
if !bson.IsObjectIdHex(vars["id"]) {
notFound(w, r)
notFound(h)
return
}
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 {
notFound(w, r)
notFound(h)
return
}
book := books[0]
if !book.Active {
sess := GetSession(r)
if !sess.IsAdmin() {
notFound(w, r)
if !h.sess.IsAdmin() {
notFound(h)
return
}
}
fs := db.GetFS(FS_IMGS)
fs := h.db.GetFS(FS_IMGS)
var f *mgo.GridFile
if vars["size"] == "small" {
f, err = fs.OpenId(book.CoverSmall)
@ -52,24 +50,24 @@ func coverHandler(w http.ResponseWriter, r *http.Request) {
}
if err != nil {
log.Println("Error while opening image:", err)
notFound(w, r)
notFound(h)
return
}
defer f.Close()
headers := w.Header()
headers := h.w.Header()
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) {
imgId, smallId := coverFromMetadata(e, title)
func GetCover(e *epubgo.Epub, title string, db *DB) (bson.ObjectId, bson.ObjectId) {
imgId, smallId := coverFromMetadata(e, title, db)
if imgId != "" {
return imgId, smallId
}
imgId, smallId = searchCommonCoverNames(e, title)
imgId, smallId = searchCommonCoverNames(e, title, db)
if imgId != "" {
return imgId, smallId
}
@ -110,7 +108,7 @@ func GetCover(e *epubgo.Epub, title string) (bson.ObjectId, bson.ObjectId) {
img, err := e.OpenFile(url)
if err == nil {
defer img.Close()
return storeImg(img, title)
return storeImg(img, title, db)
}
}
errNext = it.Next()
@ -118,41 +116,41 @@ func GetCover(e *epubgo.Epub, title string) (bson.ObjectId, bson.ObjectId) {
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")
for _, meta := range metaList {
if meta["name"] == "cover" {
img, err := e.OpenFileId(meta["content"])
if err == nil {
defer img.Close()
return storeImg(img, title)
return storeImg(img, title, db)
}
}
}
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"} {
img, err := e.OpenFile(p)
if err == nil {
defer img.Close()
return storeImg(img, title)
return storeImg(img, title, db)
}
}
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 */
fBig, err := createCoverFile(title)
fBig, err := createCoverFile(title, db)
if err != nil {
log.Println("Error creating", title, ":", err.Error())
return "", ""
}
defer fBig.Close()
fSmall, err := createCoverFile(title + "_small")
fSmall, err := createCoverFile(title+"_small", db)
if err != nil {
log.Println("Error creating", title+"_small", ":", err.Error())
return "", ""
@ -189,7 +187,7 @@ func storeImg(img io.Reader, title string) (bson.ObjectId, bson.ObjectId) {
return idBig, idSmall
}
func createCoverFile(title string) (*mgo.GridFile, error) {
func createCoverFile(title string, db *DB) (*mgo.GridFile, error) {
fs := db.GetFS(FS_IMGS)
return fs.Create(title + ".jpg")
}

View file

@ -7,8 +7,6 @@ import (
"time"
)
var db *DB
type Book struct {
Id string `bson:"_id"`
Title string
@ -28,6 +26,7 @@ type Book struct {
Rights string
Meta string
File bson.ObjectId
FileSize int
Cover bson.ObjectId
CoverSmall bson.ObjectId
Active bool
@ -41,11 +40,6 @@ type News struct {
type DB struct {
session *mgo.Session
books *mgo.Collection
user *mgo.Collection
news *mgo.Collection
stats *mgo.Collection
mr *MR
}
func initDB() *DB {
@ -55,13 +49,6 @@ func initDB() *DB {
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
}
@ -69,6 +56,12 @@ func (d *DB) Close() {
d.session.Close()
}
func (d *DB) Copy() *DB {
dbCopy := new(DB)
dbCopy.session = d.session.Copy()
return dbCopy
}
func md5Pass(pass string) []byte {
h := md5.New()
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 {
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 {
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 {
return false
}
@ -91,7 +86,8 @@ func (d *DB) UserValid(user string, pass string) bool {
func (d *DB) AddUser(user string, pass string) error {
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 {
@ -99,7 +95,8 @@ func (d *DB) UserRole(user string) string {
Role string
}
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 {
return ""
}
@ -110,7 +107,8 @@ func (d *DB) AddNews(text string) error {
var news News
news.Text = text
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) {
@ -120,25 +118,30 @@ func (d *DB) GetNews(num int, days int) (news []News, err error) {
date := time.Now().Add(duration)
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)
return
}
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 {
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 {
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 {
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
@ -153,7 +156,8 @@ func (d *DB) GetBooks(query bson.M, r ...int) (books []Book, num int, err error)
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()
if err != nil {
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
*/
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 {
return nil, err
}
books = make([]Book, num)
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()
}
return
@ -191,14 +198,17 @@ func (d *DB) GetVisitedBooks(num int) (books []Book, err error) {
/* Get the most downloaded books
*/
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 {
return nil, err
}
books = make([]Book, num)
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()
}
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 {
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 {
return false
}
@ -226,7 +237,9 @@ func (d *DB) GetFS(prefix string) *mgo.GridFS {
}
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 {
@ -235,13 +248,19 @@ type Visits struct {
}
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) {
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) {
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)
}

View file

@ -7,30 +7,12 @@ import (
)
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
database *mgo.Database
}
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)
m.database = database
return m
}
@ -56,7 +38,8 @@ func (m *MR) GetTags(numTags int, booksColl *mgo.Collection) ([]string, error) {
var result []struct {
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 {
return nil, err
}
@ -88,7 +71,8 @@ func (m *MR) GetMostVisited(num int, statsColl *mgo.Collection) ([]bson.ObjectId
var result []struct {
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 {
return nil, err
}
@ -120,7 +104,8 @@ func (m *MR) GetMostDownloaded(num int, statsColl *mgo.Collection) ([]bson.Objec
var result []struct {
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 {
return nil, err
}
@ -157,14 +142,16 @@ func (m *MR) GetHourVisits(start time.Time, statsColl *mgo.Collection) ([]Visits
emit(this['_id']['date'], 1);
}`
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 {
return nil, err
}
}
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
}
@ -192,14 +179,16 @@ func (m *MR) GetDayVisits(start time.Time, statsColl *mgo.Collection) ([]Visits,
emit(this['_id']['date'], 1);
}`
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 {
return nil, err
}
}
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
}
@ -226,19 +215,22 @@ func (m *MR) GetMonthVisits(start time.Time, statsColl *mgo.Collection) ([]Visit
emit(this['_id']['date'], 1);
}`
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 {
return nil, err
}
}
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
}
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 {
return err
}
@ -249,14 +241,15 @@ func (m *MR) update(mr *mgo.MapReduce, query bson.M, queryColl *mgo.Collection,
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 {
var result struct {
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 {
return true
}

40
news.go
View file

@ -14,50 +14,50 @@ type newsEntry struct {
Text string
}
func newsHandler(w http.ResponseWriter, r *http.Request, sess *Session) {
err := r.ParseForm()
func newsHandler(h handler) {
err := h.r.ParseForm()
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
http.Error(h.w, err.Error(), http.StatusInternalServerError)
return
}
var data newsData
data.S = GetStatus(w, r)
data.S = GetStatus(h)
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") {
loadTxtTemplate(w, "news_rss.xml", data)
loadTxtTemplate(h.w, "news_rss.xml", data)
} else {
loadTemplate(w, "news", data)
loadTemplate(h.w, "news", data)
}
}
func editNewsHandler(w http.ResponseWriter, r *http.Request, sess *Session) {
if !sess.IsAdmin() {
notFound(w, r)
func editNewsHandler(h handler) {
if !h.sess.IsAdmin() {
notFound(h)
return
}
var data statusData
data.S = GetStatus(w, r)
data.S = GetStatus(h)
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) {
if !sess.IsAdmin() {
notFound(w, r)
func postNewsHandler(h handler) {
if !h.sess.IsAdmin() {
notFound(h)
return
}
text := r.FormValue("text")
db.AddNews(text)
http.Redirect(w, r, "/news/", http.StatusFound)
text := h.r.FormValue("text")
h.db.AddNews(text)
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)
news := make([]newsEntry, len(dbnews))
for i, n := range dbnews {

View file

@ -129,35 +129,35 @@ func listChapters(nav *epubgo.NavigationIterator, depth int) []chapter {
return chapters
}
func readStartHandler(w http.ResponseWriter, r *http.Request, sess *Session) {
id := mux.Vars(r)["id"]
e, _ := openReadEpub(w, r, sess)
func readStartHandler(h handler) {
id := mux.Vars(h.r)["id"]
e, _ := openReadEpub(h)
if e == nil {
notFound(w, r)
notFound(h)
return
}
defer e.Close()
it, err := e.Spine()
if err != nil {
notFound(w, r)
notFound(h)
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) {
id := mux.Vars(r)["id"]
file := mux.Vars(r)["file"]
e, book := openReadEpub(w, r, sess)
func readHandler(h handler) {
id := mux.Vars(h.r)["id"]
file := mux.Vars(h.r)["file"]
e, book := openReadEpub(h)
if e == nil {
notFound(w, r)
notFound(h)
return
}
defer e.Close()
var data readData
data.S = GetStatus(w, r)
data.S = GetStatus(h)
data.Book = book
if !book.Active {
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.Chapters = getChapters(e, file, id, "/read/")
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
id := mux.Vars(r)["id"]
id := mux.Vars(h.r)["id"]
if !bson.IsObjectIdHex(id) {
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 {
return nil, book
}
book = books[0]
if !book.Active {
if !sess.IsAdmin() {
if !h.sess.IsAdmin() {
return nil, book
}
}
e, err := OpenBook(book.File)
e, err := OpenBook(book.File, h.db)
if err != nil {
return nil, book
}
return e, book
}
func contentHandler(w http.ResponseWriter, r *http.Request, sess *Session) {
vars := mux.Vars(r)
func contentHandler(h handler) {
vars := mux.Vars(h.r)
id := vars["id"]
file := vars["file"]
if file == "" || !bson.IsObjectIdHex(id) {
notFound(w, r)
notFound(h)
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 {
notFound(w, r)
notFound(h)
return
}
book := books[0]
if !book.Active {
if !sess.IsAdmin() {
notFound(w, r)
if !h.sess.IsAdmin() {
notFound(h)
return
}
}
e, err := OpenBook(book.File)
e, err := OpenBook(book.File, h.db)
if err != nil {
notFound(w, r)
notFound(h)
return
}
defer e.Close()
html, err := e.OpenFile(file)
if err != nil {
notFound(w, r)
notFound(h)
return
}
defer html.Close()
io.Copy(w, html)
io.Copy(h.w, html)
}

View file

@ -35,25 +35,25 @@ type searchData struct {
Prev string
}
func searchHandler(w http.ResponseWriter, r *http.Request, sess *Session) {
err := r.ParseForm()
func searchHandler(h handler) {
err := h.r.ParseForm()
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
http.Error(h.w, err.Error(), http.StatusInternalServerError)
return
}
req := strings.Join(r.Form["q"], " ")
req := strings.Join(h.r.Form["q"], " ")
page := 0
if len(r.Form["p"]) != 0 {
page, err = strconv.Atoi(r.Form["p"][0])
if len(h.r.Form["p"]) != 0 {
page, err = strconv.Atoi(h.r.Form["p"][0])
if err != nil {
page = 0
}
}
items_page := itemsPage(r)
res, num, _ := db.GetBooks(buildQuery(req), items_page, page*items_page)
items_page := itemsPage(h.r)
res, num, _ := h.db.GetBooks(buildQuery(req), items_page, page*items_page)
var data searchData
data.S = GetStatus(w, r)
data.S = GetStatus(h)
data.S.Search = req
data.Books = res
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)
}
format := r.Form["fmt"]
format := h.r.Form["fmt"]
if (len(format) > 0) && (format[0] == "rss") {
loadTxtTemplate(w, "search_rss.xml", data)
loadTxtTemplate(h.w, "search_rss.xml", data)
} else {
loadTemplate(w, "search", data)
loadTemplate(h.w, "search", data)
}
}

View file

@ -21,7 +21,7 @@ type Session struct {
S *sessions.Session
}
func GetSession(r *http.Request) (s *Session) {
func GetSession(r *http.Request, db *DB) (s *Session) {
s = new(Session)
var err error
s.S, err = sesStore.Get(r, "session")

View file

@ -9,16 +9,30 @@ import (
"time"
)
func InitStats() {
statsChannel = make(chan statsRequest, CHAN_SIZE)
go statsWorker()
type handler struct {
w http.ResponseWriter
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) {
sess := GetSession(r)
function(w, r, sess)
statsChannel <- statsRequest{bson.Now(), mux.Vars(r), sess, r}
var h handler
h.db = database.Copy()
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
}
func statsWorker() {
func statsWorker(database *DB) {
db := database.Copy()
defer db.Close()
for req := range statsChannel {
stats := make(map[string]interface{})
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
data.S = GetStatus(w, r)
data.S = GetStatus(h)
data.S.Stats = true
data.Hourly = getHourlyVisits()
data.Daily = getDailyVisits()
data.Monthly = getMonthlyVisits()
data.Hourly = getHourlyVisits(h.db)
data.Daily = getDailyVisits(h.db)
data.Monthly = getMonthlyVisits(h.db)
loadTemplate(w, "stats", data)
loadTemplate(h.w, "stats", data)
}
type statsData struct {
@ -67,7 +84,7 @@ type visitData struct {
Count int
}
func getHourlyVisits() []visitData {
func getHourlyVisits(db *DB) []visitData {
const numDays = 2
var visits []visitData
@ -84,7 +101,7 @@ func getHourlyVisits() []visitData {
return visits
}
func getDailyVisits() []visitData {
func getDailyVisits(db *DB) []visitData {
const numDays = 30
var visits []visitData
@ -101,7 +118,7 @@ func getDailyVisits() []visitData {
return visits
}
func getMonthlyVisits() []visitData {
func getMonthlyVisits(db *DB) []visitData {
const numDays = 365
var visits []visitData

View file

@ -10,7 +10,7 @@ import (
"strings"
)
func OpenBook(id bson.ObjectId) (*epubgo.Epub, error) {
func OpenBook(id bson.ObjectId, db *DB) (*epubgo.Epub, error) {
fs := db.GetFS(FS_BOOKS)
f, err := fs.OpenId(id)
if err != nil {
@ -24,37 +24,37 @@ func OpenBook(id bson.ObjectId) (*epubgo.Epub, error) {
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)
fw, err := fs.Create(name)
if err != nil {
return "", err
return "", 0, err
}
defer fw.Close()
_, err = io.Copy(fw, file)
size, err := io.Copy(fw, file)
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)
return fs.RemoveId(id)
}
func DeleteCover(id bson.ObjectId) error {
func DeleteCover(id bson.ObjectId, db *DB) error {
fs := db.GetFS(FS_IMGS)
return fs.RemoveId(id)
}
func DeleteBook(book Book) {
func DeleteBook(book Book, db *DB) {
if book.Cover != "" {
DeleteCover(book.Cover)
DeleteCover(book.Cover, db)
}
if book.CoverSmall != "" {
DeleteCover(book.CoverSmall)
DeleteCover(book.CoverSmall, db)
}
DeleteFile(book.File)
DeleteFile(book.File, db)
}
func cleanStr(str string) string {

View file

@ -22,15 +22,14 @@ type Status struct {
Help bool
}
func GetStatus(w http.ResponseWriter, r *http.Request) Status {
func GetStatus(h handler) Status {
var s Status
sess := GetSession(r)
s.BaseURL = "http://" + r.Host
s.FullURL = s.BaseURL + r.RequestURI
s.User = sess.User
s.IsAdmin = sess.IsAdmin()
s.Notif = sess.GetNotif()
sess.Save(w, r)
s.BaseURL = "http://" + h.r.Host
s.FullURL = s.BaseURL + h.r.RequestURI
s.User = h.sess.User
s.IsAdmin = h.sess.IsAdmin()
s.Notif = h.sess.GetNotif()
h.sess.Save(h.w, h.r)
return s
}

View file

@ -1,17 +1,23 @@
{{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>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>
<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>
<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>
<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>

View file

@ -20,6 +20,7 @@
{{if .Isbn}}
<guid isPermaLink="false">ISBN: {{.Isbn}}</guid>
{{end}}
<enclosure url="{{$baseURL}}/download/{{.Id}}/{{.Title}}.epub" length="{{.FileSize}}" type="application/epub+zip" />
{{range .Subject}}
{{if .}}
<category>{{.}}</category>

View file

@ -11,3 +11,5 @@ Password:
- 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
- addsize. Add the size of the books to the book metadata

38
tools/addsize/addsize.go Normal file
View 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
View 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
View 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
View 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
}

View file

@ -13,26 +13,26 @@ type statusData struct {
S Status
}
func aboutHandler(w http.ResponseWriter, r *http.Request, sess *Session) {
func aboutHandler(h handler) {
var data statusData
data.S = GetStatus(w, r)
data.S = GetStatus(h)
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
data.S = GetStatus(w, r)
data.S = GetStatus(h)
data.S.Help = true
loadTemplate(w, "help", data)
loadTemplate(h.w, "help", data)
}
func logoutHandler(w http.ResponseWriter, r *http.Request, sess *Session) {
sess.LogOut()
sess.Notify("Log out!", "Bye bye "+sess.User, "success")
sess.Save(w, r)
log.Println("User", sess.User, "log out")
http.Redirect(w, r, "/", http.StatusFound)
func logoutHandler(h handler) {
h.sess.LogOut()
h.sess.Notify("Log out!", "Bye bye "+h.sess.User, "success")
h.sess.Save(h.w, h.r)
log.Println("User", h.sess.User, "log out")
http.Redirect(h.w, h.r, "/", http.StatusFound)
}
type bookData struct {
@ -41,62 +41,61 @@ type bookData struct {
Description []string
}
func bookHandler(w http.ResponseWriter, r *http.Request, sess *Session) {
idStr := mux.Vars(r)["id"]
func bookHandler(h handler) {
idStr := mux.Vars(h.r)["id"]
if !bson.IsObjectIdHex(idStr) {
notFound(w, r)
notFound(h)
return
}
var data bookData
data.S = GetStatus(w, r)
data.S = GetStatus(h)
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 {
notFound(w, r)
notFound(h)
return
}
data.Book = books[0]
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) {
idStr := mux.Vars(r)["id"]
func downloadHandler(h handler) {
idStr := mux.Vars(h.r)["id"]
if !bson.IsObjectIdHex(idStr) {
notFound(w, r)
notFound(h)
return
}
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 {
notFound(w, r)
notFound(h)
return
}
book := books[0]
if !book.Active {
sess := GetSession(r)
if !sess.IsAdmin() {
notFound(w, r)
if !h.sess.IsAdmin() {
notFound(h)
return
}
}
fs := db.GetFS(FS_BOOKS)
fs := h.db.GetFS(FS_BOOKS)
f, err := fs.OpenId(book.File)
if err != nil {
notFound(w, r)
notFound(h)
return
}
defer f.Close()
headers := w.Header()
headers := h.w.Header()
headers["Content-Type"] = []string{"application/epub+zip"}
headers["Content-Disposition"] = []string{"attachment; filename=\"" + f.Name() + "\""}
io.Copy(w, f)
io.Copy(h.w, f)
}
type indexData struct {
@ -109,70 +108,70 @@ type indexData struct {
News []newsEntry
}
func indexHandler(w http.ResponseWriter, r *http.Request, sess *Session) {
func indexHandler(h handler) {
var data indexData
data.Tags, _ = db.GetTags(TAGS_DISPLAY)
data.S = GetStatus(w, r)
data.Tags, _ = h.db.GetTags(TAGS_DISPLAY)
data.S = GetStatus(h)
data.S.Home = true
data.Books, data.Count, _ = db.GetBooks(bson.M{"active": true}, 6)
data.VisitedBooks, _ = db.GetVisitedBooks(6)
data.DownloadedBooks, _ = db.GetDownloadedBooks(6)
data.News = getNews(1, DAYS_NEWS_INDEXPAGE)
loadTemplate(w, "index", data)
data.Books, data.Count, _ = h.db.GetBooks(bson.M{"active": true}, 6)
data.VisitedBooks, _ = h.db.GetVisitedBooks(6)
data.DownloadedBooks, _ = h.db.GetDownloadedBooks(6)
data.News = getNews(1, DAYS_NEWS_INDEXPAGE, h.db)
loadTemplate(h.w, "index", data)
}
func notFound(w http.ResponseWriter, r *http.Request) {
func notFound(h handler) {
var data statusData
data.S = GetStatus(w, r)
w.WriteHeader(http.StatusNotFound)
loadTemplate(w, "404", data)
data.S = GetStatus(h)
h.w.WriteHeader(http.StatusNotFound)
loadTemplate(h.w, "404", data)
}
func main() {
db = initDB()
db := initDB()
defer db.Close()
InitStats()
InitUpload()
InitStats(db)
InitUpload(db)
setUpRouter()
setUpRouter(db)
panic(http.ListenAndServe(":"+PORT, nil))
}
func setUpRouter() {
func setUpRouter(db *DB) {
r := mux.NewRouter()
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.HandleFunc("/", GatherStats(indexHandler))
r.HandleFunc("/book/{id:[0-9a-fA-F]+}", GatherStats(bookHandler))
r.HandleFunc("/search/", GatherStats(searchHandler))
r.HandleFunc("/upload/", GatherStats(uploadHandler)).Methods("GET")
r.HandleFunc("/upload/", GatherStats(uploadPostHandler)).Methods("POST")
r.HandleFunc("/login/", GatherStats(loginHandler)).Methods("GET")
r.HandleFunc("/login/", GatherStats(loginPostHandler)).Methods("POST")
r.HandleFunc("/create_user/", GatherStats(createUserHandler)).Methods("POST")
r.HandleFunc("/logout/", GatherStats(logoutHandler))
r.HandleFunc("/new/", GatherStats(newHandler))
r.HandleFunc("/store/{ids:([0-9a-fA-F]+/)+}", GatherStats(storeHandler))
r.HandleFunc("/delete/{ids:([0-9a-fA-F]+/)+}", GatherStats(deleteHandler))
r.HandleFunc("/read/{id:[0-9a-fA-F]+}", GatherStats(readStartHandler))
r.HandleFunc("/read/{id:[0-9a-fA-F]+}/{file:.*}", GatherStats(readHandler))
r.HandleFunc("/content/{id:[0-9a-fA-F]+}/{file:.*}", GatherStats(contentHandler))
r.HandleFunc("/edit/{id:[0-9a-fA-F]+}", GatherStats(editHandler))
r.HandleFunc("/save/{id:[0-9a-fA-F]+}", GatherStats(saveHandler)).Methods("POST")
r.HandleFunc("/about/", GatherStats(aboutHandler))
r.HandleFunc("/help/", GatherStats(helpHandler))
r.HandleFunc("/download/{id:[0-9a-fA-F]+}/{epub:.*}", GatherStats(downloadHandler))
r.HandleFunc("/cover/{id:[0-9a-fA-F]+}/{size}/{img:.*}", coverHandler)
r.HandleFunc("/settings/", GatherStats(settingsHandler))
r.HandleFunc("/stats/", GatherStats(statsHandler))
r.HandleFunc("/news/", GatherStats(newsHandler))
r.HandleFunc("/news/edit", GatherStats(editNewsHandler)).Methods("GET")
r.HandleFunc("/news/edit", GatherStats(postNewsHandler)).Methods("POST")
r.HandleFunc("/", GatherStats(indexHandler, db))
r.HandleFunc("/book/{id:[0-9a-fA-F]+}", GatherStats(bookHandler, db))
r.HandleFunc("/search/", GatherStats(searchHandler, db))
r.HandleFunc("/upload/", GatherStats(uploadHandler, db)).Methods("GET")
r.HandleFunc("/upload/", GatherStats(uploadPostHandler, db)).Methods("POST")
r.HandleFunc("/login/", GatherStats(loginHandler, db)).Methods("GET")
r.HandleFunc("/login/", GatherStats(loginPostHandler, db)).Methods("POST")
r.HandleFunc("/create_user/", GatherStats(createUserHandler, db)).Methods("POST")
r.HandleFunc("/logout/", GatherStats(logoutHandler, db))
r.HandleFunc("/new/", GatherStats(newHandler, db))
r.HandleFunc("/store/{ids:([0-9a-fA-F]+/)+}", GatherStats(storeHandler, db))
r.HandleFunc("/delete/{ids:([0-9a-fA-F]+/)+}", GatherStats(deleteHandler, db))
r.HandleFunc("/read/{id:[0-9a-fA-F]+}", GatherStats(readStartHandler, db))
r.HandleFunc("/read/{id:[0-9a-fA-F]+}/{file:.*}", GatherStats(readHandler, db))
r.HandleFunc("/content/{id:[0-9a-fA-F]+}/{file:.*}", GatherStats(contentHandler, db))
r.HandleFunc("/edit/{id:[0-9a-fA-F]+}", GatherStats(editHandler, db))
r.HandleFunc("/save/{id:[0-9a-fA-F]+}", GatherStats(saveHandler, db)).Methods("POST")
r.HandleFunc("/about/", GatherStats(aboutHandler, db))
r.HandleFunc("/help/", GatherStats(helpHandler, db))
r.HandleFunc("/download/{id:[0-9a-fA-F]+}/{epub:.*}", GatherStats(downloadHandler, db))
r.HandleFunc("/cover/{id:[0-9a-fA-F]+}/{size}/{img:.*}", GatherStats(coverHandler, db))
r.HandleFunc("/settings/", GatherStats(settingsHandler, db))
r.HandleFunc("/stats/", GatherStats(statsHandler, db))
r.HandleFunc("/news/", GatherStats(newsHandler, db))
r.HandleFunc("/news/edit", GatherStats(editNewsHandler, db)).Methods("GET")
r.HandleFunc("/news/edit", GatherStats(postNewsHandler, db)).Methods("POST")
h := http.FileServer(http.Dir(IMG_PATH))
r.Handle("/img/{img}", http.StripPrefix("/img/", h))
h = http.FileServer(http.Dir(CSS_PATH))

View file

@ -6,13 +6,12 @@ import (
"io/ioutil"
"log"
"mime/multipart"
"net/http"
"strings"
)
func InitUpload() {
func InitUpload(database *DB) {
uploadChannel = make(chan uploadRequest, CHAN_SIZE)
go uploadWorker()
go uploadWorker(database)
}
var uploadChannel chan uploadRequest
@ -22,13 +21,16 @@ type uploadRequest struct {
filename string
}
func uploadWorker() {
func uploadWorker(database *DB) {
db := database.Copy()
defer db.Close()
for req := range uploadChannel {
processFile(req)
processFile(req, db)
}
}
func processFile(req uploadRequest) {
func processFile(req uploadRequest, db *DB) {
defer req.file.Close()
epub, err := openMultipartEpub(req.file)
@ -38,16 +40,17 @@ func processFile(req uploadRequest) {
}
defer epub.Close()
book := parseFile(epub)
book := parseFile(epub, db)
title, _ := book["title"].(string)
req.file.Seek(0, 0)
id, err := StoreNewFile(title+".epub", req.file)
id, size, err := StoreNewFile(title+".epub", req.file, db)
if err != nil {
log.Println("Error storing book (", title, "):", err)
return
}
book["file"] = id
book["filesize"] = size
err = db.InsertBook(book)
if err != nil {
log.Println("Error storing metadata (", title, "):", err)
@ -56,16 +59,16 @@ func processFile(req uploadRequest) {
log.Println("File uploaded:", req.filename)
}
func uploadPostHandler(w http.ResponseWriter, r *http.Request, sess *Session) {
func uploadPostHandler(h handler) {
problem := false
r.ParseMultipartForm(20000000)
filesForm := r.MultipartForm.File["epub"]
h.r.ParseMultipartForm(20000000)
filesForm := h.r.MultipartForm.File["epub"]
for _, f := range filesForm {
file, err := f.Open()
if err != nil {
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
continue
}
@ -74,19 +77,19 @@ func uploadPostHandler(w http.ResponseWriter, r *http.Request, sess *Session) {
if !problem {
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 {
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
data.S = GetStatus(w, r)
data.S = GetStatus(h)
data.S.Upload = true
loadTemplate(w, "upload", data)
loadTemplate(h.w, "upload", data)
}
type uploadData struct {
@ -99,7 +102,7 @@ func openMultipartEpub(file multipart.File) (*epubgo.Epub, error) {
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{}{}
for _, m := range epub.MetadataFields() {
data, err := epub.Metadata(m)
@ -132,7 +135,7 @@ func parseFile(epub *epubgo.Epub) map[string]interface{} {
}
title, _ := book["title"].(string)
book["file"] = nil
cover, coverSmall := GetCover(epub, title)
cover, coverSmall := GetCover(epub, title, db)
if cover != "" {
book["cover"] = cover
book["coversmall"] = coverSmall

74
user.go
View file

@ -5,71 +5,71 @@ import (
"net/http"
)
func loginHandler(w http.ResponseWriter, r *http.Request, sess *Session) {
func loginHandler(h handler) {
var data statusData
data.S = GetStatus(w, r)
loadTemplate(w, "login", data)
data.S = GetStatus(h)
loadTemplate(h.w, "login", data)
}
func loginPostHandler(w http.ResponseWriter, r *http.Request, sess *Session) {
user := r.FormValue("user")
pass := r.FormValue("pass")
if db.UserValid(user, pass) {
func loginPostHandler(h handler) {
user := h.r.FormValue("user")
pass := h.r.FormValue("pass")
if h.db.UserValid(user, pass) {
log.Println("User", user, "log in")
sess.LogIn(user)
sess.Notify("Successful login!", "Welcome "+user, "success")
h.sess.LogIn(user)
h.sess.Notify("Successful login!", "Welcome "+user, "success")
} else {
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)
http.Redirect(w, r, r.Referer(), http.StatusFound)
h.sess.Save(h.w, h.r)
http.Redirect(h.w, h.r, h.r.Referer(), http.StatusFound)
}
func createUserHandler(w http.ResponseWriter, r *http.Request, sess *Session) {
pass := r.FormValue("pass")
confirmPass := r.FormValue("confirmPass")
func createUserHandler(h handler) {
pass := h.r.FormValue("pass")
confirmPass := h.r.FormValue("confirmPass")
if pass != confirmPass {
sess.Notify("Registration error!", "Passwords don't match", "error")
h.sess.Notify("Registration error!", "Passwords don't match", "error")
} else {
user := r.FormValue("user")
err := db.AddUser(user, pass)
user := h.r.FormValue("user")
err := h.db.AddUser(user, pass)
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 {
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)
http.Redirect(w, r, r.Referer(), http.StatusFound)
h.sess.Save(h.w, h.r)
http.Redirect(h.w, h.r, h.r.Referer(), http.StatusFound)
}
type settingsData struct {
S Status
}
func settingsHandler(w http.ResponseWriter, r *http.Request, sess *Session) {
if sess.User == "" {
notFound(w, r)
func settingsHandler(h handler) {
if h.sess.User == "" {
notFound(h)
return
}
if r.Method == "POST" {
current_pass := r.FormValue("currpass")
pass1 := r.FormValue("password1")
pass2 := r.FormValue("password2")
if h.r.Method == "POST" {
current_pass := h.r.FormValue("currpass")
pass1 := h.r.FormValue("password1")
pass2 := h.r.FormValue("password2")
switch {
case !db.UserValid(sess.User, current_pass):
sess.Notify("Password error!", "The current password given don't match with the user password. Try again", "error")
case !h.db.UserValid(h.sess.User, current_pass):
h.sess.Notify("Password error!", "The current password given don't match with the user password. Try again", "error")
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:
db.SetPassword(sess.User, pass1)
sess.Notify("Password updated!", "Your new password is correctly set.", "success")
h.db.SetPassword(h.sess.User, pass1)
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
data.S = GetStatus(w, r)
loadTemplate(w, "settings", data)
data.S = GetStatus(h)
loadTemplate(h.w, "settings", data)
}