Add movie search

This commit is contained in:
Grégoire Delattre 2017-01-06 22:01:04 +01:00
parent 9d55743720
commit 74b2f351bd
7 changed files with 72 additions and 7 deletions

View File

@ -1,6 +1,7 @@
package movies package movies
import ( import (
"encoding/json"
"errors" "errors"
"fmt" "fmt"
"net" "net"
@ -113,15 +114,21 @@ func GetDetailsHandler(env *web.Env, w http.ResponseWriter, r *http.Request) err
// SearchMovie will search movie // SearchMovie will search movie
func SearchMovie(env *web.Env, w http.ResponseWriter, r *http.Request) error { func SearchMovie(env *web.Env, w http.ResponseWriter, r *http.Request) error {
key := r.FormValue("key") var data struct {
if key == "" { Key string `json:"key"`
}
if err := json.NewDecoder(r.Body).Decode(&data); err != nil {
return err
}
if data.Key == "" {
return env.RenderError(w, errors.New("no given key")) return env.RenderError(w, errors.New("no given key"))
} }
var movies []*polochon.Movie var movies []*polochon.Movie
searchers := env.Config.MovieSearchers searchers := env.Config.MovieSearchers
for _, searcher := range searchers { for _, searcher := range searchers {
result, err := searcher.SearchMovie(key, env.Log) result, err := searcher.SearchMovie(data.Key, env.Log)
if err != nil { if err != nil {
env.Log.Errorf("error while searching movie : %s", err) env.Log.Errorf("error while searching movie : %s", err)
continue continue
@ -129,7 +136,7 @@ func SearchMovie(env *web.Env, w http.ResponseWriter, r *http.Request) error {
movies = append(movies, result...) movies = append(movies, result...)
} }
env.Log.Debugf("got %d movies doing search %q", len(movies), key) env.Log.Debugf("got %d movies doing search %q", len(movies), data.Key)
movieList := []*Movie{} movieList := []*Movie{}
for _, m := range movies { for _, m := range movies {
movie := New(m.ImdbID) movie := New(m.ImdbID)

View File

@ -80,7 +80,7 @@ func main() {
env.Handle("/movies/{id:tt[0-9]+}/get_details", movies.GetDetailsHandler).WithRole(users.UserRole) env.Handle("/movies/{id:tt[0-9]+}/get_details", movies.GetDetailsHandler).WithRole(users.UserRole)
env.Handle("/movies/explore", extmedias.Explore) env.Handle("/movies/explore", extmedias.Explore)
env.Handle("/movies/refresh", extmedias.Refresh) env.Handle("/movies/refresh", extmedias.Refresh)
env.Handle("/movies/search", movies.SearchMovie) env.Handle("/movies/search", movies.SearchMovie).Methods("POST")
// env.Handle("/shows/polochon", shows.FromPolochon).WithRole(users.UserRole) // env.Handle("/shows/polochon", shows.FromPolochon).WithRole(users.UserRole)
env.Handle("/shows/{id:tt[0-9]+}", shows.GetDetailsHandler) env.Handle("/shows/{id:tt[0-9]+}", shows.GetDetailsHandler)

View File

@ -80,6 +80,13 @@ export function selectMovie(imdbId) {
} }
} }
export function searchMovies(search) {
return request(
'SEARCH_MOVIES',
configureAxios().post('/movies/search', search)
)
}
export function getMovieDetails(imdbId) { export function getMovieDetails(imdbId) {
return request( return request(
'MOVIE_GET_DETAILS', 'MOVIE_GET_DETAILS',

View File

@ -83,6 +83,9 @@ const MovieListPopular = (props) => (
const MovieListPolochon = (props) => ( const MovieListPolochon = (props) => (
<MovieList {...props} moviesUrl='/movies/polochon'/> <MovieList {...props} moviesUrl='/movies/polochon'/>
) )
const MovieListSearch = (props) => (
<MovieList {...props} />
)
const ShowListPopular = (props) => ( const ShowListPopular = (props) => (
<ShowList {...props} showsUrl='/shows/explore'/> <ShowList {...props} showsUrl='/shows/explore'/>
@ -100,6 +103,7 @@ ReactDOM.render((
<Route path="/users/login" component={UserLoginForm} /> <Route path="/users/login" component={UserLoginForm} />
<Route path="/users/signup" component={UserSignUp} /> <Route path="/users/signup" component={UserSignUp} />
<Route path="/users/edit" component={UserIsAuthenticated(UserEdit)} /> <Route path="/users/edit" component={UserIsAuthenticated(UserEdit)} />
<Route path="/movies/search/:search" component={UserIsAuthenticated(MovieListSearch)} />
<Route path="/movies/popular" component={UserIsAuthenticated(MovieListPopular)} /> <Route path="/movies/popular" component={UserIsAuthenticated(MovieListPopular)} />
<Route path="/movies/polochon(/:page)" component={UserIsAuthenticated(MovieListPolochon)} /> <Route path="/movies/polochon(/:page)" component={UserIsAuthenticated(MovieListPolochon)} />
<Route path="/shows/popular" component={UserIsAuthenticated(ShowListPopular)} /> <Route path="/shows/popular" component={UserIsAuthenticated(ShowListPopular)} />

View File

@ -53,7 +53,24 @@ class MovieButtons extends React.Component {
export default class MovieList extends React.Component { export default class MovieList extends React.Component {
componentWillMount() { componentWillMount() {
this.props.fetchMovies(this.props.moviesUrl); if (this.props.moviesUrl) {
this.props.fetchMovies(this.props.moviesUrl);
} else if (this.props.params && this.props.params.search != "") {
this.props.searchMovies({
key: this.props.params.search
});
}
}
componentWillUpdate(nextProps, nextState) {
if (!nextProps.params || nextProps.params.search === "") {
return
}
if (this.props.params.search === nextProps.params.search) {
return
}
this.props.searchMovies({
key: nextProps.params.search
});
} }
render() { render() {
const movies = this.props.movieStore.movies; const movies = this.props.movieStore.movies;

View File

@ -1,15 +1,28 @@
import React from 'react' import React from 'react'
import { Link } from 'react-router'
import { store } from '../store' import { store } from '../store'
import { isUserLoggedIn } from '../actions/actionCreators' import { isUserLoggedIn } from '../actions/actionCreators'
import { Nav, Navbar, NavItem, NavDropdown, MenuItem } from 'react-bootstrap' import { Nav, Navbar, NavItem, NavDropdown, MenuItem } from 'react-bootstrap'
import { LinkContainer } from 'react-router-bootstrap' import { LinkContainer } from 'react-router-bootstrap'
import { Control, Form } from 'react-redux-form';
export default class NavBar extends React.Component { export default class NavBar extends React.Component {
constructor(props) {
super(props);
this.handleMovieSearch = this.handleMovieSearch.bind(this);
}
handleMovieSearch() {
this.props.router.push(`/movies/search/${encodeURI(this.props.movieStore.search)}`)
}
render() { render() {
const username = this.props.userStore.username; const username = this.props.userStore.username;
const isLoggedIn = username !== "" ? true : false; const isLoggedIn = username !== "" ? true : false;
const location = this.props.router.getCurrentLocation().pathname;
let displayMovieSearch = false;
if (isLoggedIn && location.indexOf("movies") > -1)
{
displayMovieSearch = true;
}
return ( return (
<div> <div>
<Navbar fluid fixedTop collapseOnSelect> <Navbar fluid fixedTop collapseOnSelect>
@ -53,6 +66,18 @@ export default class NavBar extends React.Component {
</NavDropdown> </NavDropdown>
} }
</Nav> </Nav>
{displayMovieSearch &&
<Navbar.Form pullRight>
<Form model="movieStore" className="input-group" onSubmit={() => this.handleMovieSearch()}>
<Control.text
model="movieStore.search"
className="form-control"
placeholder="Search"
updateOn="change"
/>
</Form>
</Navbar.Form>
}
</Navbar.Collapse> </Navbar.Collapse>
</Navbar> </Navbar>
</div> </div>

View File

@ -4,6 +4,7 @@ const defaultState = {
perPage: 30, perPage: 30,
selectedImdbId: "", selectedImdbId: "",
fetchingDetails: false, fetchingDetails: false,
search: "",
}; };
export default function movieStore(state = defaultState, action) { export default function movieStore(state = defaultState, action) {
@ -18,6 +19,10 @@ export default function movieStore(state = defaultState, action) {
movies: action.payload.data, movies: action.payload.data,
selectedImdbId: selectedImdbId, selectedImdbId: selectedImdbId,
}) })
case 'SEARCH_MOVIES_FULFILLED':
return Object.assign({}, state, {
movies: action.payload.data,
})
case 'MOVIE_GET_DETAILS_PENDING': case 'MOVIE_GET_DETAILS_PENDING':
return Object.assign({}, state, { return Object.assign({}, state, {
fetchingDetails: true, fetchingDetails: true,