Improve request abstraction
This commit is contained in:
parent
977f67e38a
commit
30b57ded50
51
db/stat.go
51
db/stat.go
|
@ -1,19 +1,10 @@
|
||||||
package db
|
package db
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"net/http"
|
|
||||||
"strconv"
|
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
type (
|
type (
|
||||||
StatRequest struct {
|
|
||||||
Org string
|
|
||||||
Team string
|
|
||||||
User string
|
|
||||||
From int64
|
|
||||||
To int64
|
|
||||||
}
|
|
||||||
StatItem struct {
|
StatItem struct {
|
||||||
Item string `json:"item"`
|
Item string `json:"item"`
|
||||||
Value int `json:"value"`
|
Value int `json:"value"`
|
||||||
|
@ -110,54 +101,32 @@ where
|
||||||
group by item
|
group by item
|
||||||
order by value desc`
|
order by value desc`
|
||||||
|
|
||||||
func StatOrgReposTop(r *StatRequest) (res []StatItem) {
|
func StatOrgReposTop(org string, from, to int64) (res []StatItem) {
|
||||||
defer measure("StatOrgReposTop", time.Now())
|
defer measure("StatOrgReposTop", time.Now())
|
||||||
mustSelect(&res, orgReposTopQuery, r.Org, r.From, r.To)
|
mustSelect(&res, orgReposTopQuery, org, from, to)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func StatOrgReposActivity(r *StatRequest) (res []StatPoint) {
|
func StatOrgReposActivity(org string, from, to int64) (res []StatPoint) {
|
||||||
defer measure("StatOrgReposActivity", time.Now())
|
defer measure("StatOrgReposActivity", time.Now())
|
||||||
mustSelect(&res, orgReposActivityQuery, r.Org, r.From, r.To)
|
mustSelect(&res, orgReposActivityQuery, org, from, to)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func StatOrgTeamsTop(r *StatRequest) (res []StatItem) {
|
func StatOrgTeamsTop(org string, from, to int64) (res []StatItem) {
|
||||||
defer measure("StatOrgTeamsTop", time.Now())
|
defer measure("StatOrgTeamsTop", time.Now())
|
||||||
mustSelect(&res, orgTeamsTopQuery, r.Org, r.From, r.To)
|
mustSelect(&res, orgTeamsTopQuery, org, from, to)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func StatOrgTeamsActivity(r *StatRequest) (res []StatPoint) {
|
func StatOrgTeamsActivity(org string, from, to int64) (res []StatPoint) {
|
||||||
defer measure("StatOrgTeamsActivity", time.Now())
|
defer measure("StatOrgTeamsActivity", time.Now())
|
||||||
mustSelect(&res, orgTeamsActivityQuery, r.Org, r.From, r.To)
|
mustSelect(&res, orgTeamsActivityQuery, org, from, to)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func StatOrgUsersTop(r *StatRequest) (res []StatItem) {
|
func StatOrgUsersTop(org string, from, to int64) (res []StatItem) {
|
||||||
defer measure("StatOrgUsersTop", time.Now())
|
defer measure("StatOrgUsersTop", time.Now())
|
||||||
mustSelect(&res, orgUsersTopQuery, r.Org, r.From, r.To)
|
mustSelect(&res, orgUsersTopQuery, org, from, to)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func ParseRequest(r *http.Request) *StatRequest {
|
|
||||||
var err error
|
|
||||||
var from, to int64
|
|
||||||
if len(r.FormValue("from")) > 0 {
|
|
||||||
if from, err = strconv.ParseInt(r.FormValue("from"), 10, 64); err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if len(r.FormValue("to")) > 0 {
|
|
||||||
if to, err = strconv.ParseInt(r.FormValue("to"), 10, 64); err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return &StatRequest{
|
|
||||||
Org: r.FormValue("org"),
|
|
||||||
Team: r.FormValue("team"),
|
|
||||||
User: r.FormValue("user"),
|
|
||||||
From: from,
|
|
||||||
To: to,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -7,17 +7,19 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
func apiOrgsHandler(w http.ResponseWriter, r *http.Request) {
|
func apiOrgsHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
login := sessionUser(r)
|
req, _ := parseRequest(w, r)
|
||||||
orgs := db.UserOrgs(login)
|
orgs := db.UserOrgs(req.login)
|
||||||
respondWith(w, orgs)
|
req.respondWith(orgs)
|
||||||
}
|
}
|
||||||
|
|
||||||
func apiTeamsHandler(w http.ResponseWriter, r *http.Request) {
|
func apiTeamsHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
teams := db.OrgTeams(r.FormValue("org"))
|
req, stat := parseRequest(w, r)
|
||||||
respondWith(w, teams)
|
teams := db.OrgTeams(stat.org)
|
||||||
|
req.respondWith(teams)
|
||||||
}
|
}
|
||||||
|
|
||||||
func apiReposHandler(w http.ResponseWriter, r *http.Request) {
|
func apiReposHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
repos := db.OrgRepos(r.FormValue("org"))
|
req, stat := parseRequest(w, r)
|
||||||
respondWith(w, repos)
|
repos := db.OrgRepos(stat.org)
|
||||||
|
req.respondWith(repos)
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,6 +18,7 @@ func authSigninHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func authCallbackHandler(w http.ResponseWriter, r *http.Request) {
|
func authCallbackHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
|
req, _ := parseRequest(w, r)
|
||||||
if r.FormValue("error") != "" {
|
if r.FormValue("error") != "" {
|
||||||
w.Write([]byte(r.FormValue("error_description")))
|
w.Write([]byte(r.FormValue("error_description")))
|
||||||
return
|
return
|
||||||
|
@ -25,15 +26,16 @@ func authCallbackHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
|
|
||||||
code := r.FormValue("code")
|
code := r.FormValue("code")
|
||||||
log.Printf("Got code %q\n", code)
|
log.Printf("Got code %q\n", code)
|
||||||
|
|
||||||
if _, login, err := task.Authenticate(code); err == nil {
|
if _, login, err := task.Authenticate(code); err == nil {
|
||||||
createSession(r, login)
|
req.authorize(login)
|
||||||
} else {
|
} else {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func authHandler(w http.ResponseWriter, r *http.Request) {
|
func authHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
if sessionUser(r) == "" {
|
if req, _ := parseRequest(w, r); req.login == "" {
|
||||||
http.Redirect(w, r, "/auth/hello", 302)
|
http.Redirect(w, r, "/", 302)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,92 @@
|
||||||
|
package server
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"net/http"
|
||||||
|
"strconv"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"code.google.com/p/go-uuid/uuid"
|
||||||
|
|
||||||
|
"github.com/garyburd/redigo/redis"
|
||||||
|
)
|
||||||
|
|
||||||
|
type (
|
||||||
|
request struct {
|
||||||
|
r *http.Request
|
||||||
|
w http.ResponseWriter
|
||||||
|
sessionID string
|
||||||
|
login string
|
||||||
|
}
|
||||||
|
statRequest struct {
|
||||||
|
org string
|
||||||
|
team string
|
||||||
|
user string
|
||||||
|
from int64
|
||||||
|
to int64
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
func parseRequest(w http.ResponseWriter, r *http.Request) (*request, *statRequest) {
|
||||||
|
setCookie(w, r)
|
||||||
|
cook, _ := r.Cookie(cookieName)
|
||||||
|
login, _ := redis.String(redisPool.Get().Do("HGET", "sessions", cook.Value))
|
||||||
|
req := &request{
|
||||||
|
r: r,
|
||||||
|
w: w,
|
||||||
|
sessionID: cook.Value,
|
||||||
|
login: login,
|
||||||
|
}
|
||||||
|
return req, parseStatRequest(r)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *request) authorize(login string) {
|
||||||
|
redisPool.Get().Do("HSET", "sessions", r.sessionID, login)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *request) respondWith(resp interface{}) {
|
||||||
|
b, err := json.Marshal(resp)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
r.w.Header().Set("Access-Control-Allow-Origin", "*")
|
||||||
|
r.w.Header().Set("Content-Type", "application/json; charset=utf8")
|
||||||
|
r.w.Write(b)
|
||||||
|
}
|
||||||
|
|
||||||
|
func parseStatRequest(r *http.Request) *statRequest {
|
||||||
|
var err error
|
||||||
|
var from, to int64
|
||||||
|
if r.FormValue("from") != "" {
|
||||||
|
if from, err = strconv.ParseInt(r.FormValue("from"), 10, 64); err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if r.FormValue("to") != "" {
|
||||||
|
if to, err = strconv.ParseInt(r.FormValue("to"), 10, 64); err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return &statRequest{
|
||||||
|
org: r.FormValue("org"),
|
||||||
|
team: r.FormValue("team"),
|
||||||
|
user: r.FormValue("user"),
|
||||||
|
from: from,
|
||||||
|
to: to,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func setCookie(w http.ResponseWriter, r *http.Request) {
|
||||||
|
if cook, err := r.Cookie(cookieName); err != nil {
|
||||||
|
cook = &http.Cookie{
|
||||||
|
Name: cookieName,
|
||||||
|
Value: uuid.New(),
|
||||||
|
Path: "/",
|
||||||
|
Expires: time.Now().Add(365 * 24 * time.Hour),
|
||||||
|
HttpOnly: true,
|
||||||
|
}
|
||||||
|
http.SetCookie(w, cook)
|
||||||
|
r.AddCookie(cook)
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,13 +1,21 @@
|
||||||
package server
|
package server
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
|
||||||
"log"
|
"log"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/garyburd/redigo/redis"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
cookieName = "session_id"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
redisPool = redis.NewPool(dialRedis, 10)
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
http.HandleFunc("/", sessionHandler)
|
|
||||||
http.HandleFunc("/auth/signin", authSigninHandler)
|
http.HandleFunc("/auth/signin", authSigninHandler)
|
||||||
http.HandleFunc("/auth/callback", authCallbackHandler)
|
http.HandleFunc("/auth/callback", authCallbackHandler)
|
||||||
http.HandleFunc("/api/", authHandler)
|
http.HandleFunc("/api/", authHandler)
|
||||||
|
@ -26,13 +34,6 @@ func Start() {
|
||||||
http.ListenAndServe(":8080", nil)
|
http.ListenAndServe(":8080", nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
func respondWith(w http.ResponseWriter, resp interface{}) {
|
func dialRedis() (redis.Conn, error) {
|
||||||
b, err := json.Marshal(resp)
|
return redis.Dial("tcp", ":6379")
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
w.Header().Set("Access-Control-Allow-Origin", "*")
|
|
||||||
w.Header().Set("Content-Type", "application/json; charset=utf8")
|
|
||||||
w.Write(b)
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,48 +0,0 @@
|
||||||
package server
|
|
||||||
|
|
||||||
import (
|
|
||||||
"net/http"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"code.google.com/p/go-uuid/uuid"
|
|
||||||
"github.com/garyburd/redigo/redis"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
cookieName = "session_id"
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
redisPool = redis.NewPool(dialRedis, 10)
|
|
||||||
)
|
|
||||||
|
|
||||||
func sessionHandler(w http.ResponseWriter, r *http.Request) {
|
|
||||||
if cook, err := r.Cookie(cookieName); err != nil {
|
|
||||||
cook = &http.Cookie{
|
|
||||||
Name: cookieName,
|
|
||||||
Value: uuid.New(),
|
|
||||||
Path: "/",
|
|
||||||
Expires: time.Now().Add(365 * 24 * time.Hour),
|
|
||||||
HttpOnly: true,
|
|
||||||
}
|
|
||||||
http.SetCookie(w, cook)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func createSession(r *http.Request, login string) {
|
|
||||||
redisPool.Get().Do("HSET", "sessions", sessionID(r), login)
|
|
||||||
}
|
|
||||||
|
|
||||||
func sessionID(r *http.Request) string {
|
|
||||||
cook, _ := r.Cookie(cookieName)
|
|
||||||
return cook.Value
|
|
||||||
}
|
|
||||||
|
|
||||||
func sessionUser(r *http.Request) (login string) {
|
|
||||||
login, _ = redis.String(redisPool.Get().Do("HGET", "sessions", sessionID(r)))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func dialRedis() (redis.Conn, error) {
|
|
||||||
return redis.Dial("tcp", ":6379")
|
|
||||||
}
|
|
|
@ -7,26 +7,31 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
func statOrgReposTop(w http.ResponseWriter, r *http.Request) {
|
func statOrgReposTop(w http.ResponseWriter, r *http.Request) {
|
||||||
top := db.StatOrgReposTop(db.ParseRequest(r))
|
req, stat := parseRequest(w, r)
|
||||||
respondWith(w, top)
|
top := db.StatOrgReposTop(stat.org, stat.from, stat.to)
|
||||||
|
req.respondWith(top)
|
||||||
}
|
}
|
||||||
|
|
||||||
func statOrgReposActivity(w http.ResponseWriter, r *http.Request) {
|
func statOrgReposActivity(w http.ResponseWriter, r *http.Request) {
|
||||||
activity := db.StatOrgReposActivity(db.ParseRequest(r))
|
req, stat := parseRequest(w, r)
|
||||||
respondWith(w, activity)
|
activity := db.StatOrgReposActivity(stat.org, stat.from, stat.to)
|
||||||
|
req.respondWith(activity)
|
||||||
}
|
}
|
||||||
|
|
||||||
func statOrgTeamsTop(w http.ResponseWriter, r *http.Request) {
|
func statOrgTeamsTop(w http.ResponseWriter, r *http.Request) {
|
||||||
top := db.StatOrgTeamsTop(db.ParseRequest(r))
|
req, stat := parseRequest(w, r)
|
||||||
respondWith(w, top)
|
top := db.StatOrgTeamsTop(stat.org, stat.from, stat.to)
|
||||||
|
req.respondWith(top)
|
||||||
}
|
}
|
||||||
|
|
||||||
func statOrgTeamsActivity(w http.ResponseWriter, r *http.Request) {
|
func statOrgTeamsActivity(w http.ResponseWriter, r *http.Request) {
|
||||||
activity := db.StatOrgTeamsActivity(db.ParseRequest(r))
|
req, stat := parseRequest(w, r)
|
||||||
respondWith(w, activity)
|
activity := db.StatOrgTeamsActivity(stat.org, stat.from, stat.to)
|
||||||
|
req.respondWith(activity)
|
||||||
}
|
}
|
||||||
|
|
||||||
func statOrgUsersTop(w http.ResponseWriter, r *http.Request) {
|
func statOrgUsersTop(w http.ResponseWriter, r *http.Request) {
|
||||||
top := db.StatOrgUsersTop(db.ParseRequest(r))
|
req, stat := parseRequest(w, r)
|
||||||
respondWith(w, top)
|
top := db.StatOrgUsersTop(stat.org, stat.from, stat.to)
|
||||||
|
req.respondWith(top)
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue