Merge branch 'dev/defaultImage' into 'master'
refactoring_greg See merge request !15
This commit is contained in:
commit
5fce5eecde
14
Makefile
14
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_USER=test
|
||||||
DB_PASS=test
|
DB_PASS=test
|
||||||
@ -33,7 +33,10 @@ build-go: build-prepare
|
|||||||
copy-templates: build-prepare
|
copy-templates: build-prepare
|
||||||
cp -r ./src/templates/* ./build/templates
|
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
|
watch-js: build-prepare
|
||||||
node ./node_modules/.bin/nodemon -e js -w src/public/js/app.js -x 'make build-js' &
|
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
|
watch-templates: build-prepare
|
||||||
node ./node_modules/.bin/nodemon -e tmpl -w src/templates -x 'make copy-templates' &
|
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
|
watch-go: build-prepare
|
||||||
CONFIG_FILE="./config.yml" fresh -c fresh.conf
|
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:
|
||||||
$(DOCKER_COMPOSE) up -d
|
$(DOCKER_COMPOSE) up -d
|
||||||
@ -61,7 +67,7 @@ migration-dev-data: docker migration-schema
|
|||||||
|
|
||||||
migration: migration-schema migration-dev-data
|
migration: migration-schema migration-dev-data
|
||||||
|
|
||||||
dev: docker migration watch
|
dev: docker migration build-font watch
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
-rm -r ./build
|
-rm -r ./build
|
||||||
|
10
README.md
10
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
|
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
|
## Run the tests
|
||||||
|
|
||||||
|
|
||||||
|
@ -5,4 +5,7 @@ authorizer:
|
|||||||
cost: 10
|
cost: 10
|
||||||
pgdsn: postgres://test:test@127.0.0.1:5432/dev?sslmode=disable
|
pgdsn: postgres://test:test@127.0.0.1:5432/dev?sslmode=disable
|
||||||
trakttv_client_id: my_trakttv_client_id
|
trakttv_client_id: my_trakttv_client_id
|
||||||
|
tmdb_api_key: my_tmdb_key
|
||||||
listen_port: 3000
|
listen_port: 3000
|
||||||
|
templates_dir: build/templates
|
||||||
|
public_dir: build/public
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
{
|
{
|
||||||
"modules": [
|
"modules": [
|
||||||
"bootstrap"
|
"bootstrap",
|
||||||
|
"font-awesome"
|
||||||
],
|
],
|
||||||
"dest": "build/public"
|
"dest": "build/public"
|
||||||
}
|
}
|
||||||
|
@ -11,6 +11,7 @@
|
|||||||
"license": "ISC",
|
"license": "ISC",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"bootstrap": "^3.3.6",
|
"bootstrap": "^3.3.6",
|
||||||
|
"font-awesome": "^4.7.0",
|
||||||
"jquery": "^2.2.4"
|
"jquery": "^2.2.4"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
@ -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 ('test', '$2a$10$QHx07iyuxO1RcehgtjMgjOzv03Bx2eeSKvsxkoj9oR2NJ4cklh6ue', false);
|
||||||
INSERT INTO users (name, hash, admin) VALUES ('admin', '$2a$10$e3564lLAh.0tIHQu8kfzsunViwd56AvGPeUypuCUcE3Vh09RBZci.', true);
|
INSERT INTO users (name, hash, admin) VALUES ('admin', '$2a$10$qAbyDZsHtcnhXhjhQZkD2uKlX72eMHsX8Hi2Cnl1vJUqHQiey2qa6', true);
|
||||||
|
@ -1,23 +1,25 @@
|
|||||||
package auth
|
package auth
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
"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
|
// Middleware get User from session and put it in context
|
||||||
type Middleware struct {
|
type Middleware struct {
|
||||||
authorizer *Authorizer
|
authorizer *Authorizer
|
||||||
|
log *logrus.Entry
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewMiddleware(authorizer *Authorizer) *Middleware {
|
// NewMiddleware returns a new authentication middleware
|
||||||
return &Middleware{authorizer}
|
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) {
|
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 {
|
if err != nil {
|
||||||
panic(err)
|
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)
|
next(w, r)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// MiddlewareRole handles the role checking for the current user
|
||||||
type MiddlewareRole struct {
|
type MiddlewareRole struct {
|
||||||
authorizer *Authorizer
|
authorizer *Authorizer
|
||||||
|
log *logrus.Entry
|
||||||
role string
|
role string
|
||||||
loginPageGetter func() string
|
loginPageGetter func() string
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewMiddlewareRole(authorizer *Authorizer, loginPageGetter func() string, role string) *MiddlewareRole {
|
// NewMiddlewareRole returns a new MiddlewareRole
|
||||||
return &MiddlewareRole{authorizer, role, loginPageGetter}
|
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) {
|
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 || !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")
|
cookie, err := m.authorizer.Cookiejar.Get(r, "rlogin")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
@ -56,9 +76,13 @@ func (m *MiddlewareRole) ServeHTTP(w http.ResponseWriter, r *http.Request, next
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
m.log.Debug("user has the role, continuing")
|
||||||
|
|
||||||
next(w, r)
|
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) {
|
func GetPostLoginRedirect(a *Authorizer, w http.ResponseWriter, r *http.Request) (string, error) {
|
||||||
cookie, err := a.Cookiejar.Get(r, "rlogin")
|
cookie, err := a.Cookiejar.Get(r, "rlogin")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -81,8 +105,11 @@ func GetPostLoginRedirect(a *Authorizer, w http.ResponseWriter, r *http.Request)
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetCurrentUser(r *http.Request) User {
|
// GetCurrentUser gets the current user from the request context
|
||||||
u := context.Get(r, ukey)
|
func GetCurrentUser(r *http.Request, log *logrus.Entry) User {
|
||||||
|
log.Debug("getting user from context")
|
||||||
|
|
||||||
|
u := r.Context().Value("auth.user")
|
||||||
if u == nil {
|
if u == nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -4,6 +4,9 @@ import (
|
|||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
|
polochon "github.com/odwrtw/polochon/lib"
|
||||||
|
"github.com/odwrtw/polochon/modules/tmdb"
|
||||||
|
|
||||||
"gopkg.in/yaml.v2"
|
"gopkg.in/yaml.v2"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -14,6 +17,10 @@ type Config struct {
|
|||||||
TraktTVClientID string `yaml:"trakttv_client_id"`
|
TraktTVClientID string `yaml:"trakttv_client_id"`
|
||||||
TemplatesDir string `yaml:"templates_dir"`
|
TemplatesDir string `yaml:"templates_dir"`
|
||||||
PublicDir string `yaml:"public_dir"`
|
PublicDir string `yaml:"public_dir"`
|
||||||
|
|
||||||
|
// TODO improve the detailers configurations
|
||||||
|
TmdbAPIKey string `yaml:"tmdb_api_key"`
|
||||||
|
MovieDetailers []polochon.Detailer
|
||||||
}
|
}
|
||||||
|
|
||||||
type AuthorizerConfig struct {
|
type AuthorizerConfig struct {
|
||||||
@ -42,5 +49,14 @@ func Load(path string) (*Config, error) {
|
|||||||
return nil, err
|
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
|
return cf, nil
|
||||||
}
|
}
|
||||||
|
@ -5,12 +5,9 @@ import (
|
|||||||
"net"
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
"path/filepath"
|
|
||||||
|
|
||||||
|
"github.com/gorilla/mux"
|
||||||
"github.com/odwrtw/papi"
|
"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"
|
"github.com/odwrtw/trakttv"
|
||||||
|
|
||||||
"gitlab.quimbo.fr/odwrtw/canape-sql/src/internal/auth"
|
"gitlab.quimbo.fr/odwrtw/canape-sql/src/internal/auth"
|
||||||
@ -59,8 +56,8 @@ func getPolochonMovies(user *users.User) ([]*Movie, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func FromPolochon(env *web.Env, w http.ResponseWriter, r *http.Request) 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)
|
user, ok := v.(*users.User)
|
||||||
if !ok {
|
if !ok {
|
||||||
return fmt.Errorf("invalid user type")
|
return fmt.Errorf("invalid user type")
|
||||||
@ -79,16 +76,8 @@ func FromPolochon(env *web.Env, w http.ResponseWriter, r *http.Request) error {
|
|||||||
return err
|
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 {
|
for _, m := range movies {
|
||||||
m.Detailers = []polochon.Detailer{detailer}
|
err := m.GetDetails(env, false)
|
||||||
err := m.GetDetails(env.Database, filepath.Join(env.Config.PublicDir, "img", "movies"), env.Log)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
env.Log.Error(err)
|
env.Log.Error(err)
|
||||||
}
|
}
|
||||||
@ -96,10 +85,12 @@ func FromPolochon(env *web.Env, w http.ResponseWriter, r *http.Request) error {
|
|||||||
|
|
||||||
env.Log.Info(movies)
|
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 {
|
func ExplorePopular(env *web.Env, w http.ResponseWriter, r *http.Request) error {
|
||||||
|
log := env.Log.WithField("function", "movies.ExplorePopular")
|
||||||
|
|
||||||
queryOption := trakttv.QueryOption{
|
queryOption := trakttv.QueryOption{
|
||||||
ExtendedInfos: []trakttv.ExtendedInfo{
|
ExtendedInfos: []trakttv.ExtendedInfo{
|
||||||
@ -112,22 +103,19 @@ func ExplorePopular(env *web.Env, w http.ResponseWriter, r *http.Request) error
|
|||||||
}
|
}
|
||||||
trakt := trakttv.New(env.Config.TraktTVClientID)
|
trakt := trakttv.New(env.Config.TraktTVClientID)
|
||||||
trakt.Endpoint = trakttv.ProductionEndpoint
|
trakt.Endpoint = trakttv.ProductionEndpoint
|
||||||
|
|
||||||
|
log.Debug("getting movies from trakttv")
|
||||||
tmovies, err := trakt.PopularMovies(queryOption)
|
tmovies, err := trakt.PopularMovies(queryOption)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
log.Debugf("got %d movies from trakttv", len(tmovies))
|
||||||
detailer, err := traktdetailer.New(&traktdetailer.Params{env.Config.TraktTVClientID})
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
movies := []*Movie{}
|
movies := []*Movie{}
|
||||||
ids := []string{}
|
ids := []string{}
|
||||||
for _, m := range tmovies {
|
for _, m := range tmovies {
|
||||||
movie := New(m.IDs.ImDB)
|
movie := New(m.IDs.ImDB)
|
||||||
movie.Detailers = []polochon.Detailer{detailer}
|
err := movie.GetDetails(env, false)
|
||||||
err := movie.GetDetails(env.Database, filepath.Join(env.Config.PublicDir, "img", "movies"), env.Log)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
env.Log.Error(err)
|
env.Log.Error(err)
|
||||||
continue
|
continue
|
||||||
|
@ -17,6 +17,11 @@ const (
|
|||||||
VALUES (:imdbid, :title, :rating, :votes, :plot, :tmdbid, :year, :originaltitle, :runtime, :sorttitle, :tagline)
|
VALUES (:imdbid, :title, :rating, :votes, :plot, :tmdbid, :year, :originaltitle, :runtime, :sorttitle, :tagline)
|
||||||
RETURNING id;`
|
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 = `
|
getMovieQueryByImdbID = `
|
||||||
SELECT
|
SELECT
|
||||||
id, imdb_id AS imdbid, title, rating, votes, plot,
|
id, imdb_id AS imdbid, title, rating, votes, plot,
|
||||||
@ -74,38 +79,67 @@ func (m *Movie) Get(db *sqlx.DB) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetDetails retrieves details for the movie, first try to
|
// GetDetails retrieves details for the movie, first try to get info from db,
|
||||||
// get info from db, if not exists, use polochon.Detailer
|
// if not exists, use polochon.Detailer and save informations in the database
|
||||||
// and save informations in the database for future use
|
// for future use
|
||||||
func (m *Movie) GetDetails(db *sqlx.DB, imgPath string, log *logrus.Entry) error {
|
//
|
||||||
var err error
|
// If force is used, the detailer will be used even if the movie is found in
|
||||||
err = m.Get(db)
|
// database
|
||||||
if err == nil {
|
func (m *Movie) GetDetails(env *web.Env, force bool) error {
|
||||||
// found ok
|
if len(m.Detailers) == 0 {
|
||||||
return nil
|
m.Detailers = env.Config.MovieDetailers
|
||||||
}
|
}
|
||||||
if err != ErrNotFound {
|
|
||||||
|
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)
|
||||||
|
switch err {
|
||||||
|
case nil:
|
||||||
|
log.Debug("movie found in database")
|
||||||
|
dbFunc = m.Update
|
||||||
|
if !force {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
case ErrNotFound:
|
||||||
|
dbFunc = m.Add
|
||||||
|
log.Debug("movie not found in database")
|
||||||
|
default:
|
||||||
// Unexpected error
|
// Unexpected error
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// so we got ErrNotFound so GetDetails from a detailer
|
// so we got ErrNotFound so GetDetails from a detailer
|
||||||
err = m.Movie.GetDetails(log)
|
err = m.Movie.GetDetails(env.Log)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
err = m.Add(db)
|
log.Debug("got details from detailers")
|
||||||
|
|
||||||
|
err = dbFunc(env.Database)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
log.Debug("movie added in database")
|
||||||
|
|
||||||
// Download poster
|
// 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 {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
log.Debug("poster downloaded")
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -124,6 +158,12 @@ func (m *Movie) Add(db *sqlx.DB) error {
|
|||||||
return nil
|
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
|
// Delete movie from database
|
||||||
func (m *Movie) Delete(db *sqlx.DB) error {
|
func (m *Movie) Delete(db *sqlx.DB) error {
|
||||||
r, err := db.Exec(deleteMovieQuery, m.ID)
|
r, err := db.Exec(deleteMovieQuery, m.ID)
|
||||||
|
@ -65,7 +65,7 @@ func LogoutHandler(e *web.Env, w http.ResponseWriter, r *http.Request) error {
|
|||||||
|
|
||||||
// DetailsHandler show user details
|
// DetailsHandler show user details
|
||||||
func DetailsHandler(e *web.Env, w http.ResponseWriter, r *http.Request) error {
|
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)
|
user, ok := v.(*User)
|
||||||
if !ok {
|
if !ok {
|
||||||
return fmt.Errorf("invalid user type")
|
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
|
// EditHandler allow editing user info and configuration
|
||||||
func EditHandler(e *web.Env, w http.ResponseWriter, r *http.Request) error {
|
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)
|
user, ok := v.(*User)
|
||||||
if !ok {
|
if !ok {
|
||||||
return fmt.Errorf("invalid user type")
|
return fmt.Errorf("invalid user type")
|
||||||
|
@ -7,10 +7,10 @@ import (
|
|||||||
"gitlab.quimbo.fr/odwrtw/canape-sql/src/internal/config"
|
"gitlab.quimbo.fr/odwrtw/canape-sql/src/internal/config"
|
||||||
|
|
||||||
"github.com/Sirupsen/logrus"
|
"github.com/Sirupsen/logrus"
|
||||||
"github.com/codegangsta/negroni"
|
|
||||||
"github.com/gorilla/mux"
|
"github.com/gorilla/mux"
|
||||||
"github.com/jmoiron/sqlx"
|
"github.com/jmoiron/sqlx"
|
||||||
"github.com/unrolled/render"
|
"github.com/unrolled/render"
|
||||||
|
"github.com/urfave/negroni"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Env describes an environement object passed to all handlers
|
// 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 {
|
func (r *Route) WithRole(role string) *Route {
|
||||||
handler := r.mRoute.GetHandler()
|
handler := r.mRoute.GetHandler()
|
||||||
newHandler := negroni.New(
|
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))
|
negroni.Wrap(handler))
|
||||||
r.mRoute.Handler(newHandler)
|
r.mRoute.Handler(newHandler)
|
||||||
return r
|
return r
|
||||||
|
11
src/main.go
11
src/main.go
@ -17,10 +17,12 @@ import (
|
|||||||
_ "github.com/lib/pq"
|
_ "github.com/lib/pq"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// UserBackend represents the data backend to get the user
|
||||||
type UserBackend struct {
|
type UserBackend struct {
|
||||||
Database *sqlx.DB
|
Database *sqlx.DB
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Get gets the username from the UserBackend
|
||||||
func (b *UserBackend) Get(username string) (auth.User, error) {
|
func (b *UserBackend) Get(username string) (auth.User, error) {
|
||||||
return users.Get(b.Database, username)
|
return users.Get(b.Database, username)
|
||||||
}
|
}
|
||||||
@ -32,7 +34,12 @@ func main() {
|
|||||||
cfgPath = "./config.yml"
|
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)
|
cf, err := config.Load(cfgPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Panic(err)
|
log.Panic(err)
|
||||||
@ -60,7 +67,7 @@ func main() {
|
|||||||
Config: cf,
|
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.LoginGETHandler).Name("users.login").Methods("GET")
|
||||||
env.Handle("/users/login", users.LoginPOSTHandler).Name("users.login").Methods("POST")
|
env.Handle("/users/login", users.LoginPOSTHandler).Name("users.login").Methods("POST")
|
||||||
|
BIN
src/public/img/noimage.png
Normal file
BIN
src/public/img/noimage.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 3.3 KiB |
@ -1,4 +1,5 @@
|
|||||||
@import "bootstrap/less/bootstrap.less";
|
@import "bootstrap/less/bootstrap.less";
|
||||||
|
@import "font-awesome/less/font-awesome.less";
|
||||||
|
|
||||||
body {
|
body {
|
||||||
padding-top: 70px;
|
padding-top: 70px;
|
||||||
@ -9,4 +10,13 @@ body {
|
|||||||
background-color:#f1c40f;
|
background-color:#f1c40f;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.movie-plot {
|
||||||
|
.text-justify;
|
||||||
|
margin-right: 5%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.movie-details-buttons {
|
||||||
|
position: fixed;
|
||||||
|
bottom: 1%;
|
||||||
|
right: 1%;
|
||||||
|
}
|
||||||
|
@ -1,6 +1,10 @@
|
|||||||
{{ if $.Data.error }}
|
{{ if $.Data.error }}
|
||||||
|
|
||||||
{{ if eq $.Data.error "Invalid address"}}
|
{{ if eq $.Data.error "Invalid address"}}
|
||||||
<div class="alert alert-danger" role="alert">The polochon API adress specified in your configuration is invalid or unreachable, <a href="{{ URL "users.edit"}}">change it</a></div>
|
<div class="alert alert-danger" role="alert">
|
||||||
|
The polochon API adress specified in your configuration is invalid or unreachable,
|
||||||
|
<a href="{{ URL "users.edit"}}">change it</a>
|
||||||
|
</div>
|
||||||
{{ end }}
|
{{ end }}
|
||||||
|
|
||||||
{{ else }}
|
{{ else }}
|
||||||
@ -10,21 +14,41 @@
|
|||||||
<div class="col-xs-5 col-md-8">
|
<div class="col-xs-5 col-md-8">
|
||||||
<div class="row">
|
<div class="row">
|
||||||
{{ range $.Data.movies }}
|
{{ range $.Data.movies }}
|
||||||
<div class="col-xs-12 col-md-3">
|
<div class="col-xs-12 col-md-3">
|
||||||
<a href="#" class="thumbnail" data-imdbid="{{.ImdbID}}">
|
<a href="#" class="thumbnail" data-imdbid="{{.ImdbID}}">
|
||||||
<img src="/img/movies/{{.ImdbID}}.jpg">
|
<img src="/img/movies/{{.ImdbID}}.jpg" onerror="this.onerror=null;this.src='/img/noimage.png';">
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
{{ end }}
|
{{ end }}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="col-xs-7 col-md-4">
|
<div class="col-xs-7 col-md-4">
|
||||||
{{ range $.Data.movies}}
|
{{ range $.Data.movies}}
|
||||||
<div id="{{.ImdbID}}-detail" class="hidden movie-detail affix">
|
<div id="{{.ImdbID}}-detail" class="hidden movie-detail affix">
|
||||||
<h1>{{.Title}}</h1>
|
<h1 class="hidden-xs">{{ .Title }}</h1>
|
||||||
</div>
|
<h3 class="visible-xs">{{ .Title }}</h3>
|
||||||
{{ end}}
|
<h4 class="hidden-xs">{{ .Year }}</h4>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
<i class="fa fa-clock-o"></i>
|
||||||
|
{{ .Runtime }} min
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
<i class="fa fa-star-o"></i>
|
||||||
|
{{ .Rating }} <small>({{ .Votes }} counts)</small>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p class="movie-plot">{{ .Plot }}</p>
|
||||||
|
|
||||||
|
<div class="movie-details-buttons">
|
||||||
|
<a id="imdb-link" type="button" class="btn btn-warning" href="http://www.imdb.com/title/{{ .ImdbID }}">
|
||||||
|
<i class="fa fa-external-link"></i> IMDB
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{{ end}}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user