Store statistics on mongodb
This commit is contained in:
parent
c4373c8773
commit
206775fa6a
9 changed files with 159 additions and 52 deletions
18
admin.go
18
admin.go
|
@ -13,8 +13,7 @@ type settingsData struct {
|
|||
S Status
|
||||
}
|
||||
|
||||
func settingsHandler(w http.ResponseWriter, r *http.Request) {
|
||||
sess := GetSession(r)
|
||||
func settingsHandler(w http.ResponseWriter, r *http.Request, sess *Session) {
|
||||
if sess.User == "" {
|
||||
http.NotFound(w, r)
|
||||
return
|
||||
|
@ -39,8 +38,7 @@ func settingsHandler(w http.ResponseWriter, r *http.Request) {
|
|||
loadTemplate(w, "settings", data)
|
||||
}
|
||||
|
||||
func deleteHandler(w http.ResponseWriter, r *http.Request) {
|
||||
sess := GetSession(r)
|
||||
func deleteHandler(w http.ResponseWriter, r *http.Request, sess *Session) {
|
||||
if sess.User == "" {
|
||||
http.NotFound(w, r)
|
||||
return
|
||||
|
@ -80,8 +78,7 @@ func deleteHandler(w http.ResponseWriter, r *http.Request) {
|
|||
}
|
||||
}
|
||||
|
||||
func editHandler(w http.ResponseWriter, r *http.Request) {
|
||||
sess := GetSession(r)
|
||||
func editHandler(w http.ResponseWriter, r *http.Request, sess *Session) {
|
||||
if sess.User == "" {
|
||||
http.NotFound(w, r)
|
||||
return
|
||||
|
@ -109,8 +106,7 @@ func cleanEmptyStr(s []string) []string {
|
|||
return res
|
||||
}
|
||||
|
||||
func saveHandler(w http.ResponseWriter, r *http.Request) {
|
||||
sess := GetSession(r)
|
||||
func saveHandler(w http.ResponseWriter, r *http.Request, sess *Session) {
|
||||
if sess.User == "" {
|
||||
http.NotFound(w, r)
|
||||
return
|
||||
|
@ -162,8 +158,7 @@ type newData struct {
|
|||
Prev string
|
||||
}
|
||||
|
||||
func newHandler(w http.ResponseWriter, r *http.Request) {
|
||||
sess := GetSession(r)
|
||||
func newHandler(w http.ResponseWriter, r *http.Request, sess *Session) {
|
||||
if sess.User == "" {
|
||||
http.NotFound(w, r)
|
||||
return
|
||||
|
@ -206,8 +201,7 @@ func newHandler(w http.ResponseWriter, r *http.Request) {
|
|||
loadTemplate(w, "new", data)
|
||||
}
|
||||
|
||||
func storeHandler(w http.ResponseWriter, r *http.Request) {
|
||||
sess := GetSession(r)
|
||||
func storeHandler(w http.ResponseWriter, r *http.Request, sess *Session) {
|
||||
if sess.User == "" {
|
||||
http.NotFound(w, r)
|
||||
return
|
||||
|
|
|
@ -9,6 +9,7 @@ const (
|
|||
BOOKS_COLL = "books"
|
||||
TAGS_COLL = "tags"
|
||||
USERS_COLL = "users"
|
||||
STATS_COLL = "statistics"
|
||||
FS_BOOKS = "fs_books"
|
||||
FS_IMGS = "fs_imgs"
|
||||
|
||||
|
@ -26,4 +27,6 @@ const (
|
|||
IMG_WIDTH_BIG = 300
|
||||
IMG_WIDTH_SMALL = 60
|
||||
IMG_QUALITY = 80
|
||||
|
||||
STATS_CHAN_SIZE = 100
|
||||
)
|
||||
|
|
|
@ -44,6 +44,7 @@ type DB struct {
|
|||
books *mgo.Collection
|
||||
tags *mgo.Collection
|
||||
user *mgo.Collection
|
||||
stats *mgo.Collection
|
||||
}
|
||||
|
||||
func initDB() *DB {
|
||||
|
@ -59,6 +60,7 @@ func initDB() *DB {
|
|||
d.books = database.C(BOOKS_COLL)
|
||||
d.tags = database.C(TAGS_COLL)
|
||||
d.user = database.C(USERS_COLL)
|
||||
d.stats = database.C(STATS_COLL)
|
||||
return d
|
||||
}
|
||||
|
||||
|
@ -86,6 +88,10 @@ func (d *DB) UserValid(user string, pass string) bool {
|
|||
return n != 0
|
||||
}
|
||||
|
||||
func (d *DB) InsertStats(stats interface{}) error {
|
||||
return d.stats.Insert(stats)
|
||||
}
|
||||
|
||||
func (d *DB) InsertBook(book interface{}) error {
|
||||
return d.books.Insert(book)
|
||||
}
|
||||
|
|
14
reader.go
14
reader.go
|
@ -127,9 +127,9 @@ func listChapters(nav *epubgo.NavigationIterator, depth int) []chapter {
|
|||
return chapters
|
||||
}
|
||||
|
||||
func readStartHandler(w http.ResponseWriter, r *http.Request) {
|
||||
func readStartHandler(w http.ResponseWriter, r *http.Request, sess *Session) {
|
||||
id := mux.Vars(r)["id"]
|
||||
e, _ := openReadEpub(w, r)
|
||||
e, _ := openReadEpub(w, r, sess)
|
||||
if e == nil {
|
||||
http.NotFound(w, r)
|
||||
return
|
||||
|
@ -144,10 +144,10 @@ func readStartHandler(w http.ResponseWriter, r *http.Request) {
|
|||
http.Redirect(w, r, "/read/"+id+"/"+it.Url(), http.StatusTemporaryRedirect)
|
||||
}
|
||||
|
||||
func readHandler(w http.ResponseWriter, r *http.Request) {
|
||||
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)
|
||||
e, book := openReadEpub(w, r, sess)
|
||||
if e == nil {
|
||||
http.NotFound(w, r)
|
||||
return
|
||||
|
@ -169,7 +169,7 @@ func readHandler(w http.ResponseWriter, r *http.Request) {
|
|||
loadTemplate(w, "read", data)
|
||||
}
|
||||
|
||||
func openReadEpub(w http.ResponseWriter, r *http.Request) (*epubgo.Epub, Book) {
|
||||
func openReadEpub(w http.ResponseWriter, r *http.Request, sess *Session) (*epubgo.Epub, Book) {
|
||||
var book Book
|
||||
id := mux.Vars(r)["id"]
|
||||
books, _, err := db.GetBooks(bson.M{"_id": bson.ObjectIdHex(id)})
|
||||
|
@ -179,7 +179,6 @@ func openReadEpub(w http.ResponseWriter, r *http.Request) (*epubgo.Epub, Book) {
|
|||
|
||||
book = books[0]
|
||||
if !book.Active {
|
||||
sess := GetSession(r)
|
||||
if sess.User == "" {
|
||||
return nil, book
|
||||
}
|
||||
|
@ -191,7 +190,7 @@ func openReadEpub(w http.ResponseWriter, r *http.Request) (*epubgo.Epub, Book) {
|
|||
return e, book
|
||||
}
|
||||
|
||||
func contentHandler(w http.ResponseWriter, r *http.Request) {
|
||||
func contentHandler(w http.ResponseWriter, r *http.Request, sess *Session) {
|
||||
vars := mux.Vars(r)
|
||||
id := vars["id"]
|
||||
file := vars["file"]
|
||||
|
@ -207,7 +206,6 @@ func contentHandler(w http.ResponseWriter, r *http.Request) {
|
|||
}
|
||||
book := books[0]
|
||||
if !book.Active {
|
||||
sess := GetSession(r)
|
||||
if sess.User == "" {
|
||||
http.NotFound(w, r)
|
||||
return
|
||||
|
|
|
@ -34,7 +34,7 @@ type searchData struct {
|
|||
Prev string
|
||||
}
|
||||
|
||||
func searchHandler(w http.ResponseWriter, r *http.Request) {
|
||||
func searchHandler(w http.ResponseWriter, r *http.Request, sess *Session) {
|
||||
err := r.ParseForm()
|
||||
if err != nil {
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
|
|
11
session.go
11
session.go
|
@ -1,6 +1,7 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"encoding/hex"
|
||||
"github.com/gorilla/securecookie"
|
||||
"github.com/gorilla/sessions"
|
||||
"net/http"
|
||||
|
@ -42,6 +43,11 @@ func GetSession(r *http.Request) (s *Session) {
|
|||
s.User, _ = s.S.Values["user"].(string)
|
||||
s.Notif = getNotif(s.S)
|
||||
}
|
||||
|
||||
if s.S.IsNew {
|
||||
s.S.Values["id"] = hex.EncodeToString(securecookie.GenerateRandomKey(16))
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -63,3 +69,8 @@ func (s *Session) Notify(title, msg, tpe string) {
|
|||
func (s *Session) Save(w http.ResponseWriter, r *http.Request) {
|
||||
sesStore.Save(r, w, s.S)
|
||||
}
|
||||
|
||||
func (s *Session) Id() string {
|
||||
id, _ := s.S.Values["id"].(string)
|
||||
return id
|
||||
}
|
||||
|
|
97
stats.go
Normal file
97
stats.go
Normal file
|
@ -0,0 +1,97 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"github.com/gorilla/mux"
|
||||
"labix.org/v2/mgo/bson"
|
||||
"net/http"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
func InitStats() {
|
||||
statsChannel = make(chan statsRequest, STATS_CHAN_SIZE)
|
||||
go statsWorker()
|
||||
}
|
||||
|
||||
func GatherStats(function func(http.ResponseWriter, *http.Request, *Session)) 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 statsChannel chan statsRequest
|
||||
|
||||
type statsRequest struct {
|
||||
date time.Time
|
||||
vars map[string]string
|
||||
sess *Session
|
||||
r *http.Request
|
||||
}
|
||||
|
||||
func statsWorker() {
|
||||
for req := range statsChannel {
|
||||
stats := make(map[string]interface{})
|
||||
appendFiles(req.r, stats)
|
||||
appendMuxVars(req.vars, stats)
|
||||
appendUrl(req.r, stats)
|
||||
appendSession(req.sess, stats)
|
||||
stats["method"] = req.r.Method
|
||||
stats["date"] = req.date
|
||||
db.InsertStats(stats)
|
||||
}
|
||||
}
|
||||
|
||||
func appendFiles(r *http.Request, stats map[string]interface{}) {
|
||||
if r.Method == "POST" && r.MultipartForm.File != nil { //FIXM
|
||||
files := r.MultipartForm.File
|
||||
for key := range files {
|
||||
list := make([]string, len(files[key]))
|
||||
for i, f := range files[key] {
|
||||
list[i] = f.Filename
|
||||
}
|
||||
stats[key] = list
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func appendMuxVars(vars map[string]string, stats map[string]interface{}) {
|
||||
for key, value := range vars {
|
||||
switch {
|
||||
case key == "id":
|
||||
stats["id"] = bson.ObjectIdHex(value)
|
||||
case key == "ids":
|
||||
ids := strings.Split(value, "/")
|
||||
objectIds := make([]bson.ObjectId, len(ids))
|
||||
for i, id := range ids {
|
||||
objectIds[i] = bson.ObjectIdHex(id)
|
||||
}
|
||||
stats["ids"] = objectIds
|
||||
stats["id"] = objectIds[0]
|
||||
default:
|
||||
stats[key] = value
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func appendUrl(r *http.Request, stats map[string]interface{}) {
|
||||
for key, value := range r.URL.Query() {
|
||||
stats[key] = value
|
||||
}
|
||||
stats["host"] = r.Host
|
||||
stats["path"] = r.URL.Path
|
||||
pattern := strings.Split(r.URL.Path, "/")
|
||||
if len(pattern) > 1 && pattern[1] != "" {
|
||||
stats["section"] = pattern[1]
|
||||
} else {
|
||||
stats["section"] = "/"
|
||||
}
|
||||
}
|
||||
|
||||
func appendSession(sess *Session, stats map[string]interface{}) {
|
||||
stats["session"] = sess.Id()
|
||||
if sess.User != "" {
|
||||
stats["user"] = sess.User
|
||||
}
|
||||
}
|
52
trantor.go
52
trantor.go
|
@ -12,15 +12,14 @@ type aboutData struct {
|
|||
S Status
|
||||
}
|
||||
|
||||
func aboutHandler(w http.ResponseWriter, r *http.Request) {
|
||||
func aboutHandler(w http.ResponseWriter, r *http.Request, sess *Session) {
|
||||
var data aboutData
|
||||
data.S = GetStatus(w, r)
|
||||
data.S.About = true
|
||||
loadTemplate(w, "about", data)
|
||||
}
|
||||
|
||||
func logoutHandler(w http.ResponseWriter, r *http.Request) {
|
||||
sess := GetSession(r)
|
||||
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)
|
||||
|
@ -28,10 +27,9 @@ func logoutHandler(w http.ResponseWriter, r *http.Request) {
|
|||
http.Redirect(w, r, "/", http.StatusFound)
|
||||
}
|
||||
|
||||
func loginHandler(w http.ResponseWriter, r *http.Request) {
|
||||
func loginHandler(w http.ResponseWriter, r *http.Request, sess *Session) {
|
||||
user := r.FormValue("user")
|
||||
pass := r.FormValue("pass")
|
||||
sess := GetSession(r)
|
||||
if db.UserValid(user, pass) {
|
||||
log.Println("User", user, "log in")
|
||||
sess.LogIn(user)
|
||||
|
@ -49,7 +47,7 @@ type bookData struct {
|
|||
Book Book
|
||||
}
|
||||
|
||||
func bookHandler(w http.ResponseWriter, r *http.Request) {
|
||||
func bookHandler(w http.ResponseWriter, r *http.Request, sess *Session) {
|
||||
var data bookData
|
||||
data.S = GetStatus(w, r)
|
||||
id := bson.ObjectIdHex(mux.Vars(r)["id"])
|
||||
|
@ -63,7 +61,7 @@ func bookHandler(w http.ResponseWriter, r *http.Request) {
|
|||
loadTemplate(w, "book", data)
|
||||
}
|
||||
|
||||
func downloadHandler(w http.ResponseWriter, r *http.Request) {
|
||||
func downloadHandler(w http.ResponseWriter, r *http.Request, sess *Session) {
|
||||
id := bson.ObjectIdHex(mux.Vars(r)["id"])
|
||||
books, _, err := db.GetBooks(bson.M{"_id": id})
|
||||
if err != nil || len(books) == 0 {
|
||||
|
@ -105,7 +103,7 @@ type indexData struct {
|
|||
Tags []string
|
||||
}
|
||||
|
||||
func indexHandler(w http.ResponseWriter, r *http.Request) {
|
||||
func indexHandler(w http.ResponseWriter, r *http.Request, sess *Session) {
|
||||
var data indexData
|
||||
|
||||
data.Tags, _ = db.GetTags(TAGS_DISPLAY)
|
||||
|
@ -121,31 +119,33 @@ func main() {
|
|||
db = initDB()
|
||||
defer db.Close()
|
||||
|
||||
InitStats()
|
||||
|
||||
setUpRouter()
|
||||
panic(http.ListenAndServe(":"+PORT, nil))
|
||||
}
|
||||
|
||||
func setUpRouter() {
|
||||
r := mux.NewRouter()
|
||||
r.HandleFunc("/", indexHandler)
|
||||
r.HandleFunc("/book/{id:[0-9a-fA-F]+}", bookHandler)
|
||||
r.HandleFunc("/search/", searchHandler)
|
||||
r.HandleFunc("/upload/", uploadHandler).Methods("GET")
|
||||
r.HandleFunc("/upload/", uploadPostHandler).Methods("POST")
|
||||
r.HandleFunc("/login/", loginHandler).Methods("POST")
|
||||
r.HandleFunc("/logout/", logoutHandler)
|
||||
r.HandleFunc("/new/", newHandler)
|
||||
r.HandleFunc("/store/{ids:([0-9a-fA-F]+/)+}", storeHandler)
|
||||
r.HandleFunc("/delete/{ids:([0-9a-fA-F]+/)+}", deleteHandler)
|
||||
r.HandleFunc("/read/{id:[0-9a-fA-F]+}", readStartHandler)
|
||||
r.HandleFunc("/read/{id:[0-9a-fA-F]+}/{file:.*}", readHandler)
|
||||
r.HandleFunc("/content/{id:[0-9a-fA-F]+}/{file:.*}", contentHandler)
|
||||
r.HandleFunc("/edit/{id:[0-9a-fA-F]+}", editHandler)
|
||||
r.HandleFunc("/save/{id:[0-9a-fA-F]+}", saveHandler).Methods("POST")
|
||||
r.HandleFunc("/about/", aboutHandler)
|
||||
r.HandleFunc("/download/{id:[0-9a-fA-F]+}/{epub:.*}", downloadHandler)
|
||||
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("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("/download/{id:[0-9a-fA-F]+}/{epub:.*}", GatherStats(downloadHandler))
|
||||
r.HandleFunc("/cover/{id:[0-9a-fA-F]+}/{size}/{img:.*}", coverHandler)
|
||||
r.HandleFunc("/settings/", settingsHandler)
|
||||
r.HandleFunc("/settings/", GatherStats(settingsHandler))
|
||||
h := http.FileServer(http.Dir(IMG_PATH))
|
||||
r.Handle("/img/{img}", http.StripPrefix("/img/", h))
|
||||
h = http.FileServer(http.Dir(CSS_PATH))
|
||||
|
|
|
@ -10,9 +10,7 @@ import (
|
|||
"strings"
|
||||
)
|
||||
|
||||
func uploadPostHandler(w http.ResponseWriter, r *http.Request) {
|
||||
sess := GetSession(r)
|
||||
|
||||
func uploadPostHandler(w http.ResponseWriter, r *http.Request, sess *Session) {
|
||||
uploaded := ""
|
||||
r.ParseMultipartForm(20000000)
|
||||
filesForm := r.MultipartForm.File["epub"]
|
||||
|
@ -49,10 +47,10 @@ func uploadPostHandler(w http.ResponseWriter, r *http.Request) {
|
|||
sess.Notify("Upload successful!", "Added the books:"+uploaded+". Thank you for your contribution", "success")
|
||||
}
|
||||
|
||||
uploadHandler(w, r)
|
||||
uploadHandler(w, r, sess)
|
||||
}
|
||||
|
||||
func uploadHandler(w http.ResponseWriter, r *http.Request) {
|
||||
func uploadHandler(w http.ResponseWriter, r *http.Request, sess *Session) {
|
||||
var data uploadData
|
||||
data.S = GetStatus(w, r)
|
||||
data.S.Upload = true
|
||||
|
|
Reference in a new issue