From 7df6fc71393904112639a266273e9c5238daffa6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gr=C3=A9goire=20Delattre?= Date: Wed, 2 Nov 2016 19:32:11 +0100 Subject: [PATCH 1/9] Add missing infos to start working on the project --- README.md | 10 ++++++++++ config.yml.exemple | 2 ++ sql/dev/101_data.up.sql | 4 ++-- 3 files changed, 14 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 30c992a..c886f12 100644 --- a/README.md +++ b/README.md @@ -36,6 +36,16 @@ To setup the dev env, run server, and auto-reload on file changes docker run -it --rm --link canape_postgresql_dev:postgres postgres:9.5 psql -h postgres -U test ``` +## Default users + +This users are defined with this parameters: +pepper: "pepper" +cost: 10 + +Users: +* Admin user: admin / admin +* Test user: test / test + ## Run the tests diff --git a/config.yml.exemple b/config.yml.exemple index 533837f..2b948bb 100644 --- a/config.yml.exemple +++ b/config.yml.exemple @@ -6,3 +6,5 @@ authorizer: pgdsn: postgres://test:test@127.0.0.1:5432/dev?sslmode=disable trakttv_client_id: my_trakttv_client_id listen_port: 3000 +templates_dir: build/templates +public_dir: build/public diff --git a/sql/dev/101_data.up.sql b/sql/dev/101_data.up.sql index c025886..74355ba 100644 --- a/sql/dev/101_data.up.sql +++ b/sql/dev/101_data.up.sql @@ -1,2 +1,2 @@ -INSERT INTO users (name, hash, admin) VALUES ('test', '$2a$10$DPsyngE6ccXzzE38.JJv3OIpvU/lSjfMyg9CR68F8h6krKIyVJYrW', false); -INSERT INTO users (name, hash, admin) VALUES ('admin', '$2a$10$e3564lLAh.0tIHQu8kfzsunViwd56AvGPeUypuCUcE3Vh09RBZci.', true); +INSERT INTO users (name, hash, admin) VALUES ('test', '$2a$10$QHx07iyuxO1RcehgtjMgjOzv03Bx2eeSKvsxkoj9oR2NJ4cklh6ue', false); +INSERT INTO users (name, hash, admin) VALUES ('admin', '$2a$10$qAbyDZsHtcnhXhjhQZkD2uKlX72eMHsX8Hi2Cnl1vJUqHQiey2qa6', true); From dab68faac6937a908b58cc452ec12e12b105d1e4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gr=C3=A9goire=20Delattre?= Date: Sat, 5 Nov 2016 14:10:02 +0100 Subject: [PATCH 2/9] Fix the user context Let's use the context in go 1.7 instead of the gorilla package. While we're here, let's add some logs too. --- src/internal/auth/middleware.go | 53 +++++++++++++++++++++++++-------- src/internal/movies/handlers.go | 2 +- src/internal/users/handlers.go | 4 +-- src/internal/web/env.go | 4 +-- src/main.go | 11 +++++-- 5 files changed, 54 insertions(+), 20 deletions(-) diff --git a/src/internal/auth/middleware.go b/src/internal/auth/middleware.go index 71af311..268ad45 100644 --- a/src/internal/auth/middleware.go +++ b/src/internal/auth/middleware.go @@ -1,23 +1,25 @@ package auth import ( + "context" "fmt" "net/http" - "github.com/gorilla/context" + "github.com/Sirupsen/logrus" ) -type key int - -const ukey key = 0 //user key - // Middleware get User from session and put it in context type Middleware struct { authorizer *Authorizer + log *logrus.Entry } -func NewMiddleware(authorizer *Authorizer) *Middleware { - return &Middleware{authorizer} +// NewMiddleware returns a new authentication middleware +func NewMiddleware(authorizer *Authorizer, log *logrus.Entry) *Middleware { + return &Middleware{ + authorizer: authorizer, + log: log.WithField("middleware", "auth"), + } } func (m *Middleware) ServeHTTP(w http.ResponseWriter, r *http.Request, next http.HandlerFunc) { @@ -25,24 +27,42 @@ func (m *Middleware) ServeHTTP(w http.ResponseWriter, r *http.Request, next http if err != nil { panic(err) } - context.Set(r, ukey, user) + + m.log.Debug("setting user in the context") + ctx := context.WithValue(r.Context(), "auth.user", user) + r = r.WithContext(ctx) + next(w, r) } +// MiddlewareRole handles the role checking for the current user type MiddlewareRole struct { authorizer *Authorizer + log *logrus.Entry role string loginPageGetter func() string } -func NewMiddlewareRole(authorizer *Authorizer, loginPageGetter func() string, role string) *MiddlewareRole { - return &MiddlewareRole{authorizer, role, loginPageGetter} +// NewMiddlewareRole returns a new MiddlewareRole +func NewMiddlewareRole(authorizer *Authorizer, log *logrus.Entry, loginPageGetter func() string, role string) *MiddlewareRole { + return &MiddlewareRole{ + authorizer: authorizer, + log: log.WithField("middleware", "role"), + role: role, + loginPageGetter: loginPageGetter, + } } func (m *MiddlewareRole) ServeHTTP(w http.ResponseWriter, r *http.Request, next http.HandlerFunc) { - user := GetCurrentUser(r) + user := GetCurrentUser(r, m.log) if user == nil || !user.HasRole(m.role) { + if user == nil { + m.log.Debug("user is nil in the context") + } else { + m.log.Debug("user doesn't have the role") + } + cookie, err := m.authorizer.Cookiejar.Get(r, "rlogin") if err != nil { panic(err) @@ -56,9 +76,13 @@ func (m *MiddlewareRole) ServeHTTP(w http.ResponseWriter, r *http.Request, next return } + m.log.Debug("user has the role, continuing") + next(w, r) } +// GetPostLoginRedirect returns the location of the page requested before the +// users was redirected to the login page func GetPostLoginRedirect(a *Authorizer, w http.ResponseWriter, r *http.Request) (string, error) { cookie, err := a.Cookiejar.Get(r, "rlogin") if err != nil { @@ -81,8 +105,11 @@ func GetPostLoginRedirect(a *Authorizer, w http.ResponseWriter, r *http.Request) } -func GetCurrentUser(r *http.Request) User { - u := context.Get(r, ukey) +// GetCurrentUser gets the current user from the request context +func GetCurrentUser(r *http.Request, log *logrus.Entry) User { + log.Debug("getting user from context") + + u := r.Context().Value("auth.user") if u == nil { return nil } diff --git a/src/internal/movies/handlers.go b/src/internal/movies/handlers.go index 238ff8a..0e66697 100644 --- a/src/internal/movies/handlers.go +++ b/src/internal/movies/handlers.go @@ -59,8 +59,8 @@ func getPolochonMovies(user *users.User) ([]*Movie, error) { } func FromPolochon(env *web.Env, w http.ResponseWriter, r *http.Request) error { + v := auth.GetCurrentUser(r, env.Log) - v := auth.GetCurrentUser(r) user, ok := v.(*users.User) if !ok { return fmt.Errorf("invalid user type") diff --git a/src/internal/users/handlers.go b/src/internal/users/handlers.go index 598b748..a8fcf03 100644 --- a/src/internal/users/handlers.go +++ b/src/internal/users/handlers.go @@ -65,7 +65,7 @@ func LogoutHandler(e *web.Env, w http.ResponseWriter, r *http.Request) error { // DetailsHandler show user details func DetailsHandler(e *web.Env, w http.ResponseWriter, r *http.Request) error { - v := auth.GetCurrentUser(r) + v := auth.GetCurrentUser(r, e.Log) user, ok := v.(*User) if !ok { return fmt.Errorf("invalid user type") @@ -84,7 +84,7 @@ func DetailsHandler(e *web.Env, w http.ResponseWriter, r *http.Request) error { // EditHandler allow editing user info and configuration func EditHandler(e *web.Env, w http.ResponseWriter, r *http.Request) error { - v := auth.GetCurrentUser(r) + v := auth.GetCurrentUser(r, e.Log) user, ok := v.(*User) if !ok { return fmt.Errorf("invalid user type") diff --git a/src/internal/web/env.go b/src/internal/web/env.go index b235168..cabc99c 100644 --- a/src/internal/web/env.go +++ b/src/internal/web/env.go @@ -7,10 +7,10 @@ import ( "gitlab.quimbo.fr/odwrtw/canape-sql/src/internal/config" "github.com/Sirupsen/logrus" - "github.com/codegangsta/negroni" "github.com/gorilla/mux" "github.com/jmoiron/sqlx" "github.com/unrolled/render" + "github.com/urfave/negroni" ) // Env describes an environement object passed to all handlers @@ -76,7 +76,7 @@ func (r *Route) Methods(methods ...string) *Route { func (r *Route) WithRole(role string) *Route { handler := r.mRoute.GetHandler() newHandler := negroni.New( - auth.NewMiddlewareRole(r.env.Auth, r.env.GetLoginRouteGetter(), role), + auth.NewMiddlewareRole(r.env.Auth, r.env.Log, r.env.GetLoginRouteGetter(), role), negroni.Wrap(handler)) r.mRoute.Handler(newHandler) return r diff --git a/src/main.go b/src/main.go index 8dfd555..3da4738 100644 --- a/src/main.go +++ b/src/main.go @@ -17,10 +17,12 @@ import ( _ "github.com/lib/pq" ) +// UserBackend represents the data backend to get the user type UserBackend struct { Database *sqlx.DB } +// Get gets the username from the UserBackend func (b *UserBackend) Get(username string) (auth.User, error) { return users.Get(b.Database, username) } @@ -32,7 +34,12 @@ func main() { cfgPath = "./config.yml" } - log := logrus.NewEntry(logrus.New()) + // Setup the logger + logger := logrus.New() + logger.Formatter = &logrus.TextFormatter{FullTimestamp: true} + logger.Level = logrus.DebugLevel + + log := logrus.NewEntry(logger) cf, err := config.Load(cfgPath) if err != nil { log.Panic(err) @@ -60,7 +67,7 @@ func main() { Config: cf, }) - authMiddleware := auth.NewMiddleware(env.Auth) + authMiddleware := auth.NewMiddleware(env.Auth, log) env.Handle("/users/login", users.LoginGETHandler).Name("users.login").Methods("GET") env.Handle("/users/login", users.LoginPOSTHandler).Name("users.login").Methods("POST") From d59064a82a10ec7d4992a09dfaad32eb0fb25d91 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gr=C3=A9goire=20Delattre?= Date: Sat, 5 Nov 2016 15:56:45 +0100 Subject: [PATCH 3/9] Render polochon movies --- src/internal/movies/handlers.go | 3 ++- src/templates/movies/library.tmpl | 40 ++++++++++++++++++++++--------- 2 files changed, 31 insertions(+), 12 deletions(-) diff --git a/src/internal/movies/handlers.go b/src/internal/movies/handlers.go index 0e66697..c701312 100644 --- a/src/internal/movies/handlers.go +++ b/src/internal/movies/handlers.go @@ -96,7 +96,8 @@ func FromPolochon(env *web.Env, w http.ResponseWriter, r *http.Request) error { env.Log.Info(movies) - return nil + web.SetData(r, "movies", movies) + return env.Rends(w, r, "movies/library") } func ExplorePopular(env *web.Env, w http.ResponseWriter, r *http.Request) error { diff --git a/src/templates/movies/library.tmpl b/src/templates/movies/library.tmpl index d31395f..7a21482 100644 --- a/src/templates/movies/library.tmpl +++ b/src/templates/movies/library.tmpl @@ -1,6 +1,10 @@ {{ if $.Data.error }} + {{ if eq $.Data.error "Invalid address"}} - + {{ end }} {{ else }} @@ -10,21 +14,35 @@
{{ range $.Data.movies }} -
- - - -
+
+ + + +
{{ end }}
- {{ range $.Data.movies}} - - {{ end}} + {{ range $.Data.movies}} + + {{ end}}
From a60528da152af77c0526790bda78c9d1969588e4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gr=C3=A9goire=20Delattre?= Date: Sun, 6 Nov 2016 20:36:12 +0100 Subject: [PATCH 4/9] Add a default image for the movies --- Makefile | 12 +++++++++--- src/public/img/noimage.png | Bin 0 -> 3417 bytes src/templates/movies/library.tmpl | 2 +- 3 files changed, 10 insertions(+), 4 deletions(-) create mode 100644 src/public/img/noimage.png diff --git a/Makefile b/Makefile index faff1ed..f7ab7cc 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,4 @@ -.PHONY: docker migration dev clean test build-prepare build-js build-css build-font build-go copy-templates watch-js watch-css watch-templates watch +.PHONY: docker migration dev clean test build-prepare build-js build-css build-font build-go copy-templates copy-images watch-js watch-css watch-templates watch DB_USER=test DB_PASS=test @@ -33,7 +33,10 @@ build-go: build-prepare copy-templates: build-prepare cp -r ./src/templates/* ./build/templates -build: build-js build-css build-font copy-templates build-go +copy-images: build-prepare + cp -r ./src/public/img/* ./build/public/img + +build: build-js build-css build-font copy-templates copy-images build-go watch-js: build-prepare node ./node_modules/.bin/nodemon -e js -w src/public/js/app.js -x 'make build-js' & @@ -44,10 +47,13 @@ watch-css: build-prepare watch-templates: build-prepare node ./node_modules/.bin/nodemon -e tmpl -w src/templates -x 'make copy-templates' & +watch-images: build-prepare + node ./node_modules/.bin/nodemon -e jpg,png -w src/public/img -x 'make copy-images' & + watch-go: build-prepare CONFIG_FILE="./config.yml" fresh -c fresh.conf -watch: watch-js watch-css watch-templates watch-go +watch: watch-js watch-css watch-templates watch-images watch-go docker: $(DOCKER_COMPOSE) up -d diff --git a/src/public/img/noimage.png b/src/public/img/noimage.png new file mode 100644 index 0000000000000000000000000000000000000000..b92876921b7242d8414d6dd54e70d66eec04cb12 GIT binary patch literal 3417 zcmchadpHyNAII0+7GVwwkyUbORaNoyl8Tbb9j9!^2*hqDnxe z2sOs~$$NQ8H}8zd7-R(j z-~gh)zXt!??Z?1>==NjapVj`*|Et;``u|oI_*n<=Z#Dk3w3hzFw*^*^t%z3-N;wy; zAvr(@*iIeXtB=V$i#^e=6wFdroKba!;5Pg`>Mn>fTY`K2-Kj4@&(!w1c8#f96YV>A z+{bRYD!34lT5U%Shpt@*rCI^gi~B;G3E;^bo)du07f)6)vJSp+MGeC;ek zA=t#Flcv`{kb0ss_nepA=i*wdC$>c(r_}zw=V14dSK5*%E5iaZc2b{4C~3PMuJRS- zJlk)tU`uC=dr-!`mFR`3$%RNgTK3CPxsSP^FsNu?UHZA4n(Fg|&96B0asm3z6o=WX zOEZsAg}Qi%?E?eR+uoRcF!+_~N~syjR7XG+Y|C_^cdHIph7tJ|XX_L>=GR$@6f?Sy z@w$^K`~vg%XDj`v6wMFZ|D(NPXCCakhZl#vVo}{twVV6()p@5vtvmJs+CWA5Z z`SWJ^QGk+lW6JGC1ai#yc6Z@`YXXnQl6&P>J22ohcp)sd@S8}3yX)5SfX9Iu4#xb5 z(vIP|xR9K83ky%4P#CkTt1X+0kUXuI>aMf|9K z{96kjrB^y4k-bvy+(bmy5V5%vYh68SoV2tP7&rZ`|dDItR3`hRM>?9|r|&MC~0Jb;-AZ!6pR6kE|OZ)k8rFd-F*0eH?{awBC?Yvddy} z=h*X&&6R)#Dqep3q_lIxPKl7ic@R*4`|TI^DR25CUno>;aIakk<2s~mr~QWNG%`Ie zt$TNw=wEwI3&$jv^Zn^`0)Fs98<~91aK83t*S_!7E>Ao3$8UPpixGL(ED}V+H;)&Y z&iHwdSm*l+3gqV(7IhrW$CCyKz!;PRrTf|>9YxzA}!*gSx)P@ z9i$X)tn8GqjHy(%R+3;Pv`-xq-%a}I{0bz``~D0XsZ~p!8J6G4;?91?+m*W~zient zpXII7$H%=FvYMsVr|*UvJ)E7Ls32Q@HRQbo;yT{j|JIS&-Db7N+~AgBzkeAXuO^+5 zTA12uzQ*IBj;P8M&hY64`OHKYO?fWnxbOxny{p)~$6?9<`8vf&%J&3*egWr~0P?hp z(|oQYJI|r$BI)e*kfI?dvi=#`Pd%KK{n0ri_Gy1eZ!UbJWs@e6z8w zh8t}<{N_zY;iWy2O^AjaiZ)&_buI2}ld4a%l!>KEj@{D>*qp7&a{^IeJDh{< zt(Pu~ze}+t8BM1wlq%N1;qVmtgtW6y3TEU>OvCu@=&6Z>0H#qtxL3-qX+wGM5PPiD zQlMA*dWG!s&{8FM@}aA6qq0^WrE@K`a8p&*%F2q1zp;;huTPZ7m_WXXxFrrm8``?h z3NSQbyzy;?_2nyKah%7>-j&gf ztLQ4Chxjm6OkT}yY;}|Olav{h&AP`} tULqMs2@KZ2V1z!lauGJ{}&v7_sReO literal 0 HcmV?d00001 diff --git a/src/templates/movies/library.tmpl b/src/templates/movies/library.tmpl index 7a21482..2513319 100644 --- a/src/templates/movies/library.tmpl +++ b/src/templates/movies/library.tmpl @@ -16,7 +16,7 @@ {{ range $.Data.movies }} {{ end }} From 81207046a57f75424a657799cfd03380f50d86ff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gr=C3=A9goire=20Delattre?= Date: Sun, 6 Nov 2016 21:40:54 +0100 Subject: [PATCH 5/9] Justify movie plots, add the imdb link --- src/public/less/app.less | 9 +++++++++ src/templates/movies/library.tmpl | 8 +++++++- 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/src/public/less/app.less b/src/public/less/app.less index 50ebdda..167d044 100644 --- a/src/public/less/app.less +++ b/src/public/less/app.less @@ -9,4 +9,13 @@ body { background-color:#f1c40f; } +.movie-plot { + .text-justify; + margin-right: 5%; +} +.movie-details-buttons { + position: fixed; + bottom: 1%; + right: 1%; +} diff --git a/src/templates/movies/library.tmpl b/src/templates/movies/library.tmpl index 2513319..69f6b11 100644 --- a/src/templates/movies/library.tmpl +++ b/src/templates/movies/library.tmpl @@ -40,7 +40,13 @@ {{ .Rating }} ({{ .Votes }} counts)

-

{{ .Plot }}

+

{{ .Plot }}

+ + {{ end}} From b4be290888f4df9d9b2ac8e588a76e23ee6f8284 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gr=C3=A9goire=20Delattre?= Date: Sun, 6 Nov 2016 21:51:47 +0100 Subject: [PATCH 6/9] Add font-awesome --- Makefile | 2 +- fontify.json | 3 ++- package.json | 1 + src/public/less/app.less | 1 + src/templates/movies/library.tmpl | 2 +- 5 files changed, 6 insertions(+), 3 deletions(-) diff --git a/Makefile b/Makefile index f7ab7cc..77dfd66 100644 --- a/Makefile +++ b/Makefile @@ -67,7 +67,7 @@ migration-dev-data: docker migration-schema migration: migration-schema migration-dev-data -dev: docker migration watch +dev: docker migration build-font watch clean: -rm -r ./build diff --git a/fontify.json b/fontify.json index 24e7778..02bb6a3 100644 --- a/fontify.json +++ b/fontify.json @@ -1,6 +1,7 @@ { "modules": [ - "bootstrap" + "bootstrap", + "font-awesome" ], "dest": "build/public" } diff --git a/package.json b/package.json index c76c19b..8772268 100644 --- a/package.json +++ b/package.json @@ -11,6 +11,7 @@ "license": "ISC", "dependencies": { "bootstrap": "^3.3.6", + "font-awesome": "^4.7.0", "jquery": "^2.2.4" }, "devDependencies": { diff --git a/src/public/less/app.less b/src/public/less/app.less index 167d044..85cb97c 100644 --- a/src/public/less/app.less +++ b/src/public/less/app.less @@ -1,4 +1,5 @@ @import "bootstrap/less/bootstrap.less"; +@import "font-awesome/less/font-awesome.less"; body { padding-top: 70px; diff --git a/src/templates/movies/library.tmpl b/src/templates/movies/library.tmpl index 69f6b11..3005c89 100644 --- a/src/templates/movies/library.tmpl +++ b/src/templates/movies/library.tmpl @@ -44,7 +44,7 @@ From b9bfa5f625ee62e0b291bc5e32f1830971d8b966 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gr=C3=A9goire=20Delattre?= Date: Sun, 6 Nov 2016 23:38:14 +0100 Subject: [PATCH 7/9] Add tmdb in the config file and use it as detailer Until the detailers are available in the configuration file, let's use tmdb as the default detailer for the movies --- config.yml.exemple | 1 + src/internal/config/canape.go | 16 ++++++++++++++++ src/internal/movies/handlers.go | 15 +++------------ src/internal/movies/movies.go | 26 ++++++++++++++++++++------ 4 files changed, 40 insertions(+), 18 deletions(-) diff --git a/config.yml.exemple b/config.yml.exemple index 2b948bb..07a4295 100644 --- a/config.yml.exemple +++ b/config.yml.exemple @@ -5,6 +5,7 @@ authorizer: cost: 10 pgdsn: postgres://test:test@127.0.0.1:5432/dev?sslmode=disable trakttv_client_id: my_trakttv_client_id +tmdb_api_key: my_tmdb_key listen_port: 3000 templates_dir: build/templates public_dir: build/public diff --git a/src/internal/config/canape.go b/src/internal/config/canape.go index beacf47..55ff3bf 100644 --- a/src/internal/config/canape.go +++ b/src/internal/config/canape.go @@ -4,6 +4,9 @@ import ( "io/ioutil" "os" + polochon "github.com/odwrtw/polochon/lib" + "github.com/odwrtw/polochon/modules/tmdb" + "gopkg.in/yaml.v2" ) @@ -14,6 +17,10 @@ type Config struct { TraktTVClientID string `yaml:"trakttv_client_id"` TemplatesDir string `yaml:"templates_dir"` PublicDir string `yaml:"public_dir"` + + // TODO improve the detailers configurations + TmdbAPIKey string `yaml:"tmdb_api_key"` + MovieDetailers []polochon.Detailer } type AuthorizerConfig struct { @@ -42,5 +49,14 @@ func Load(path string) (*Config, error) { return nil, err } + cf.MovieDetailers = []polochon.Detailer{} + if cf.TmdbAPIKey != "" { + d, err := tmdb.New(&tmdb.Params{cf.TmdbAPIKey}) + if err != nil { + return nil, err + } + cf.MovieDetailers = append(cf.MovieDetailers, d) + } + return cf, nil } diff --git a/src/internal/movies/handlers.go b/src/internal/movies/handlers.go index c701312..a5af68d 100644 --- a/src/internal/movies/handlers.go +++ b/src/internal/movies/handlers.go @@ -5,11 +5,10 @@ import ( "net" "net/http" "net/url" - "path/filepath" + "github.com/gorilla/mux" "github.com/odwrtw/papi" "github.com/odwrtw/polochon/lib" - "github.com/odwrtw/polochon/modules/mock" traktdetailer "github.com/odwrtw/polochon/modules/trakttv" "github.com/odwrtw/trakttv" @@ -79,16 +78,8 @@ func FromPolochon(env *web.Env, w http.ResponseWriter, r *http.Request) error { return err } - //TODO use configurable detailer - // detailer, err := tmdb.New(&tmdb.Params{"57be344f84917b3f32c68a678f1482eb"}) - detailer, _ := mock.NewDetailer(nil) - if err != nil { - return err - } - for _, m := range movies { - m.Detailers = []polochon.Detailer{detailer} - err := m.GetDetails(env.Database, filepath.Join(env.Config.PublicDir, "img", "movies"), env.Log) + err := m.GetDetails(env) if err != nil { env.Log.Error(err) } @@ -128,7 +119,7 @@ func ExplorePopular(env *web.Env, w http.ResponseWriter, r *http.Request) error for _, m := range tmovies { movie := New(m.IDs.ImDB) movie.Detailers = []polochon.Detailer{detailer} - err := movie.GetDetails(env.Database, filepath.Join(env.Config.PublicDir, "img", "movies"), env.Log) + err := movie.GetDetails(env) if err != nil { env.Log.Error(err) continue diff --git a/src/internal/movies/movies.go b/src/internal/movies/movies.go index b1e0157..b0ec930 100644 --- a/src/internal/movies/movies.go +++ b/src/internal/movies/movies.go @@ -77,35 +77,49 @@ func (m *Movie) Get(db *sqlx.DB) error { // GetDetails retrieves details for the movie, first try to // get info from db, if not exists, use polochon.Detailer // and save informations in the database for future use -func (m *Movie) GetDetails(db *sqlx.DB, imgPath string, log *logrus.Entry) error { +func (m *Movie) GetDetails(env *web.Env) error { + m.Detailers = env.Config.MovieDetailers + + log := env.Log.WithFields(logrus.Fields{ + "imdb_id": m.ImdbID, + "function": "movies.GetDetails", + }) var err error - err = m.Get(db) + err = m.Get(env.Database) if err == nil { - // found ok + log.Debug("movie found in database") return nil } if err != ErrNotFound { // Unexpected error + log.Debug("movie not found in database") return err } // so we got ErrNotFound so GetDetails from a detailer - err = m.Movie.GetDetails(log) + err = m.Movie.GetDetails(env.Log) if err != nil { return err } - err = m.Add(db) + log.Debug("got details from detailers") + + err = m.Add(env.Database) if err != nil { return err } + log.Debug("movie added in database") + // Download poster - err = web.Download(m.Thumb, filepath.Join(imgPath, m.ImdbID+".jpg")) + imgPath := filepath.Join(env.Config.PublicDir, "img", "movies", m.ImdbID+".jpg") + err = web.Download(m.Thumb, imgPath) if err != nil { return err } + log.Debug("poster downloaded") + return nil } From 403ca081cc0d31200460fdeddd54081f6a7d5f98 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gr=C3=A9goire=20Delattre?= Date: Mon, 7 Nov 2016 16:51:02 +0100 Subject: [PATCH 8/9] Allow movies.GetDetails to be forced To check from the internet even if the movie is already in the database --- src/internal/movies/handlers.go | 4 +-- src/internal/movies/movies.go | 48 +++++++++++++++++++++++++-------- 2 files changed, 39 insertions(+), 13 deletions(-) diff --git a/src/internal/movies/handlers.go b/src/internal/movies/handlers.go index a5af68d..4e4b177 100644 --- a/src/internal/movies/handlers.go +++ b/src/internal/movies/handlers.go @@ -79,7 +79,7 @@ func FromPolochon(env *web.Env, w http.ResponseWriter, r *http.Request) error { } for _, m := range movies { - err := m.GetDetails(env) + err := m.GetDetails(env, false) if err != nil { env.Log.Error(err) } @@ -119,7 +119,7 @@ func ExplorePopular(env *web.Env, w http.ResponseWriter, r *http.Request) error for _, m := range tmovies { movie := New(m.IDs.ImDB) movie.Detailers = []polochon.Detailer{detailer} - err := movie.GetDetails(env) + err := movie.GetDetails(env, false) if err != nil { env.Log.Error(err) continue diff --git a/src/internal/movies/movies.go b/src/internal/movies/movies.go index b0ec930..54eebd2 100644 --- a/src/internal/movies/movies.go +++ b/src/internal/movies/movies.go @@ -17,6 +17,11 @@ const ( VALUES (:imdbid, :title, :rating, :votes, :plot, :tmdbid, :year, :originaltitle, :runtime, :sorttitle, :tagline) RETURNING id;` + updateMovieQuery = ` + UPDATE movies + SET imdb_id=:imdbid, title=:title, rating=:rating, votes=:votes, plot=:plot, tmdb_id=:tmdbid, year=:year, original_title=:originaltitle, runtime=:runtime, sort_title=:sorttitle, tagline=:tagline + WHERE ID = :id;` + getMovieQueryByImdbID = ` SELECT id, imdb_id AS imdbid, title, rating, votes, plot, @@ -74,25 +79,40 @@ func (m *Movie) Get(db *sqlx.DB) error { return nil } -// GetDetails retrieves details for the movie, first try to -// get info from db, if not exists, use polochon.Detailer -// and save informations in the database for future use -func (m *Movie) GetDetails(env *web.Env) error { - m.Detailers = env.Config.MovieDetailers +// GetDetails retrieves details for the movie, first try to get info from db, +// if not exists, use polochon.Detailer and save informations in the database +// for future use +// +// If force is used, the detailer will be used even if the movie is found in +// database +func (m *Movie) GetDetails(env *web.Env, force bool) error { + if len(m.Detailers) == 0 { + m.Detailers = env.Config.MovieDetailers + } log := env.Log.WithFields(logrus.Fields{ "imdb_id": m.ImdbID, "function": "movies.GetDetails", }) + + // If the movie is not in db, we should add it, otherwise we should update + // it + var dbFunc func(db *sqlx.DB) error + var err error err = m.Get(env.Database) - if err == nil { + switch err { + case nil: log.Debug("movie found in database") - return nil - } - if err != ErrNotFound { - // Unexpected error + dbFunc = m.Update + if !force { + return nil + } + case ErrNotFound: + dbFunc = m.Add log.Debug("movie not found in database") + default: + // Unexpected error return err } @@ -104,7 +124,7 @@ func (m *Movie) GetDetails(env *web.Env) error { log.Debug("got details from detailers") - err = m.Add(env.Database) + err = dbFunc(env.Database) if err != nil { return err } @@ -138,6 +158,12 @@ func (m *Movie) Add(db *sqlx.DB) error { return nil } +// Update a movie in the database +func (m *Movie) Update(db *sqlx.DB) error { + _, err := db.NamedQuery(updateMovieQuery, m) + return err +} + // Delete movie from database func (m *Movie) Delete(db *sqlx.DB) error { r, err := db.Exec(deleteMovieQuery, m.ID) From 190571bc2450a4a782c038ed4c0b7422119f2c5a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gr=C3=A9goire=20Delattre?= Date: Mon, 7 Nov 2016 17:07:31 +0100 Subject: [PATCH 9/9] Use tmdb as the default detailer even in ExplorePopular --- src/internal/movies/handlers.go | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/src/internal/movies/handlers.go b/src/internal/movies/handlers.go index 4e4b177..7bd8bcf 100644 --- a/src/internal/movies/handlers.go +++ b/src/internal/movies/handlers.go @@ -8,8 +8,6 @@ import ( "github.com/gorilla/mux" "github.com/odwrtw/papi" - "github.com/odwrtw/polochon/lib" - traktdetailer "github.com/odwrtw/polochon/modules/trakttv" "github.com/odwrtw/trakttv" "gitlab.quimbo.fr/odwrtw/canape-sql/src/internal/auth" @@ -92,6 +90,7 @@ func FromPolochon(env *web.Env, w http.ResponseWriter, r *http.Request) error { } func ExplorePopular(env *web.Env, w http.ResponseWriter, r *http.Request) error { + log := env.Log.WithField("function", "movies.ExplorePopular") queryOption := trakttv.QueryOption{ ExtendedInfos: []trakttv.ExtendedInfo{ @@ -104,21 +103,18 @@ func ExplorePopular(env *web.Env, w http.ResponseWriter, r *http.Request) error } trakt := trakttv.New(env.Config.TraktTVClientID) trakt.Endpoint = trakttv.ProductionEndpoint + + log.Debug("getting movies from trakttv") tmovies, err := trakt.PopularMovies(queryOption) if err != nil { return err } - - detailer, err := traktdetailer.New(&traktdetailer.Params{env.Config.TraktTVClientID}) - if err != nil { - return err - } + log.Debugf("got %d movies from trakttv", len(tmovies)) movies := []*Movie{} ids := []string{} for _, m := range tmovies { movie := New(m.IDs.ImDB) - movie.Detailers = []polochon.Detailer{detailer} err := movie.GetDetails(env, false) if err != nil { env.Log.Error(err)