From 8142b2ce3140e62113e535727b0af21eb9832128 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gr=C3=A9goire=20Delattre?= Date: Fri, 20 Jan 2017 19:59:43 +0100 Subject: [PATCH 1/4] Group movie action buttons --- src/public/js/components/movies/actions.js | 45 ++++++++++++++ src/public/js/components/movies/list.js | 70 ++++++++-------------- 2 files changed, 71 insertions(+), 44 deletions(-) create mode 100644 src/public/js/components/movies/actions.js diff --git a/src/public/js/components/movies/actions.js b/src/public/js/components/movies/actions.js new file mode 100644 index 0000000..3af81d9 --- /dev/null +++ b/src/public/js/components/movies/actions.js @@ -0,0 +1,45 @@ +import React from 'react' + +import { DropdownButton, MenuItem } from 'react-bootstrap' + +export default function ActionsButton(props) { + return ( + + + + ); +} + +class RefreshButton extends React.Component { + constructor(props) { + super(props); + this.handleClick = this.handleClick.bind(this); + } + handleClick(e) { + e.preventDefault(); + if (this.props.fetching) { + return + } + this.props.getDetails(this.props.movieId); + } + render() { + return ( + + {this.props.fetching || + + Refresh + + } + {this.props.fetching && + + Refreshing + + } + + ); + } +} diff --git a/src/public/js/components/movies/list.js b/src/public/js/components/movies/list.js index a2aa0f2..1834b7f 100644 --- a/src/public/js/components/movies/list.js +++ b/src/public/js/components/movies/list.js @@ -1,57 +1,39 @@ import React from 'react' import TorrentsButton from './torrents' +import ActionsButton from './actions' import ListPosters from '../list/posters' import ListDetails from '../list/details' import Loader from '../loader/loader' -class MovieButtons extends React.Component { - constructor(props) { - super(props); - this.handleClick = this.handleClick.bind(this); - } - handleClick(e) { - e.preventDefault(); - if (this.props.fetching) { - return - } - this.props.getMovieDetails(this.props.movie.imdb_id); - } - render() { - const imdb_link = `http://www.imdb.com/title/${this.props.movie.imdb_id}`; - return ( -
- - {this.props.fetching || - - Refresh - - } - {this.props.fetching && - - Refreshing - - } +function MovieButtons(props) { + const imdb_link = `http://www.imdb.com/title/${props.movie.imdb_id}`; + return ( +
+ {props.movie.polochon_url !== "" && + + Download - {this.props.movie.polochon_url !== "" && - - Download - - } + } - {this.props.movie.torrents && - - } + {props.movie.torrents && + + } - - IMDB - -
- ); - } + + + + IMDB + +
+ ); } export default class MovieList extends React.Component { From fe81c968f461fbbb20898ab928306678ee2abeb5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gr=C3=A9goire=20Delattre?= Date: Fri, 20 Jan 2017 22:55:55 +0100 Subject: [PATCH 2/4] Add movie delete handler --- src/internal/movies/handlers.go | 36 +++++++++++++++++++++++++++++++++ src/main.go | 1 + 2 files changed, 37 insertions(+) diff --git a/src/internal/movies/handlers.go b/src/internal/movies/handlers.go index 9416a4c..982fb88 100644 --- a/src/internal/movies/handlers.go +++ b/src/internal/movies/handlers.go @@ -8,6 +8,7 @@ import ( "net/http" "net/url" + "github.com/Sirupsen/logrus" "github.com/gorilla/mux" "github.com/odwrtw/papi" polochon "github.com/odwrtw/polochon/lib" @@ -191,3 +192,38 @@ func SearchMovie(env *web.Env, w http.ResponseWriter, r *http.Request) error { return env.RenderJSON(w, movieList) } + +// DeleteHandler deletes the movie from polochon +func DeleteHandler(env *web.Env, w http.ResponseWriter, r *http.Request) error { + vars := mux.Vars(r) + id := vars["id"] + + log := env.Log.WithFields(logrus.Fields{ + "imdb_id": id, + "function": "movies.DeleteHandler", + }) + log.Debugf("deleting movie") + + v := auth.GetCurrentUser(r, env.Log) + user, ok := v.(*users.User) + if !ok { + return fmt.Errorf("invalid user type") + } + + var polochonConfig config.UserPolochon + err := user.GetConfig("polochon", &polochonConfig) + if err != nil { + return err + } + + client, err := papi.New(polochonConfig.URL) + if err != nil { + return err + } + + if polochonConfig.Token != "" { + client.SetToken(polochonConfig.Token) + } + + return client.Delete(&papi.Movie{ImdbID: id}) +} diff --git a/src/main.go b/src/main.go index cbea35a..f0d8982 100644 --- a/src/main.go +++ b/src/main.go @@ -78,6 +78,7 @@ func main() { env.Handle("/movies/polochon", movies.FromPolochon).WithRole(users.UserRole).Methods("GET") env.Handle("/movies/{id:tt[0-9]+}/get_details", movies.GetDetailsHandler).WithRole(users.UserRole).Methods("GET") + env.Handle("/movies/{id:tt[0-9]+}", movies.DeleteHandler).WithRole(users.AdminRole).Methods("DELETE") env.Handle("/movies/explore", extmedias.Explore).WithRole(users.UserRole).Methods("GET") env.Handle("/movies/refresh", extmedias.Refresh).WithRole(users.UserRole).Methods("POST") env.Handle("/movies/search", movies.SearchMovie).WithRole(users.UserRole).Methods("POST") From 4e3613c1c84d6a4042c87c9af1dce1bd1e31a118 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gr=C3=A9goire=20Delattre?= Date: Fri, 20 Jan 2017 23:12:47 +0100 Subject: [PATCH 3/4] Add delete movie button --- src/public/js/actions/actionCreators.js | 26 +++++++++++++++++++-- src/public/js/components/movies/actions.js | 27 ++++++++++++++++++++++ src/public/js/components/movies/list.js | 8 ++++++- src/public/js/reducers/movies.js | 5 ++++ src/public/js/requests.js | 13 ++++------- 5 files changed, 68 insertions(+), 11 deletions(-) diff --git a/src/public/js/actions/actionCreators.js b/src/public/js/actions/actionCreators.js index 32354e6..c630e2a 100644 --- a/src/public/js/actions/actionCreators.js +++ b/src/public/js/actions/actionCreators.js @@ -61,7 +61,9 @@ export function updateUser(config) { return request( 'USER_UPDATE', configureAxios().post('/users/edit', config), - "User updated", + [ + addAlertOk("User updated"), + ], ) } @@ -90,6 +92,13 @@ export function selectMovie(imdbId) { } } +export function deleteMovieFromStore(imdbId) { + return { + type: 'DELETE_MOVIE', + imdbId + } +} + export function searchMovies(search) { return request( 'SEARCH_MOVIES', @@ -104,6 +113,17 @@ export function getMovieDetails(imdbId) { ) } +export function deleteMovie(imdbId) { + return request( + 'MOVIE_DELETE', + configureAxios().delete(`/movies/${imdbId}`), + [ + addAlertOk("Movie deleted"), + deleteMovieFromStore(imdbId), + ], + ) +} + export function fetchMovies(url) { return request( 'MOVIE_LIST_FETCH', @@ -153,6 +173,8 @@ export function addTorrent(url) { configureAxios().post('/torrents', { url: url, }), - "Torrent added", + [ + addAlertOk("Torrent added"), + ], ) } diff --git a/src/public/js/components/movies/actions.js b/src/public/js/components/movies/actions.js index 3af81d9..e78e634 100644 --- a/src/public/js/components/movies/actions.js +++ b/src/public/js/components/movies/actions.js @@ -10,6 +10,13 @@ export default function ActionsButton(props) { movieId={props.movieId} getDetails={props.getDetails} /> + {(props.isUserAdmin && props.hasMovie) && + + } ); } @@ -43,3 +50,23 @@ class RefreshButton extends React.Component { ); } } + +class DeleteButton extends React.Component { + constructor(props) { + super(props); + this.handleClick = this.handleClick.bind(this); + } + handleClick(e) { + e.preventDefault(); + this.props.deleteMovie(this.props.movieId); + } + render() { + return ( + + + Delete + + + ); + } +} diff --git a/src/public/js/components/movies/list.js b/src/public/js/components/movies/list.js index 1834b7f..37866b7 100644 --- a/src/public/js/components/movies/list.js +++ b/src/public/js/components/movies/list.js @@ -8,9 +8,10 @@ import Loader from '../loader/loader' function MovieButtons(props) { const imdb_link = `http://www.imdb.com/title/${props.movie.imdb_id}`; + const hasMovie = (props.movie.polochon_url !== "") return (
- {props.movie.polochon_url !== "" && + {hasMovie && Download @@ -27,6 +28,9 @@ function MovieButtons(props) { fetching={props.fetching} movieId={props.movie.imdb_id} getDetails={props.getMovieDetails} + deleteMovie={props.deleteMovie} + isUserAdmin={props.isUserAdmin} + hasMovie={hasMovie} /> @@ -91,6 +95,8 @@ export default class MovieList extends React.Component { fetching={this.props.movieStore.fetchingDetails} getMovieDetails={this.props.getMovieDetails} addTorrent={this.props.addTorrent} + deleteMovie={this.props.deleteMovie} + isUserAdmin={this.props.userStore.isAdmin} /> } diff --git a/src/public/js/reducers/movies.js b/src/public/js/reducers/movies.js index a05da07..83f9bd1 100644 --- a/src/public/js/reducers/movies.js +++ b/src/public/js/reducers/movies.js @@ -46,6 +46,11 @@ export default function movieStore(state = defaultState, action) { movies: movies, fetchingDetails: false, }) + case 'DELETE_MOVIE': + return Object.assign({}, state, { + movies: state.movies.filter((e) => (e.imdb_id !== action.imdbId)), + fetchingDetails: false, + }) case 'SELECT_MOVIE': // Don't select the movie if we're fetching another movie's details if (state.fetchingDetails) { diff --git a/src/public/js/requests.js b/src/public/js/requests.js index cf64b98..25424c8 100644 --- a/src/public/js/requests.js +++ b/src/public/js/requests.js @@ -16,7 +16,7 @@ export function configureAxios(headers = {}) { // This function takes en event prefix to dispatch evens during the life of the // request, it also take a promise (axios request) -export function request(eventPrefix, promise, successMessage = null) { +export function request(eventPrefix, promise, callbackEvents = null) { // Events const pending = `${eventPrefix}_PENDING`; const fulfilled = `${eventPrefix}_FULFILLED`; @@ -40,13 +40,10 @@ export function request(eventPrefix, promise, successMessage = null) { type: fulfilled, payload: response.data, }) - if (successMessage) { - dispatch({ - type: 'ADD_ALERT_OK', - payload: { - message: successMessage, - }, - }) + if (callbackEvents) { + for (let event of callbackEvents) { + dispatch(event); + } } }) .catch(error => { From 041c656c673b9cc96908d2e0a6aeaa18b18dd13d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gr=C3=A9goire=20Delattre?= Date: Sat, 21 Jan 2017 00:13:45 +0100 Subject: [PATCH 4/4] Refactor navbar in modules --- src/public/js/components/navbar.js | 202 ++++++++++++++++------------- 1 file changed, 114 insertions(+), 88 deletions(-) diff --git a/src/public/js/components/navbar.js b/src/public/js/components/navbar.js index a21ec94..3f9bbab 100644 --- a/src/public/js/components/navbar.js +++ b/src/public/js/components/navbar.js @@ -6,102 +6,128 @@ import { Nav, Navbar, NavItem, NavDropdown, MenuItem } from 'react-bootstrap' import { LinkContainer } from 'react-router-bootstrap' import { Control, Form } from 'react-redux-form'; -export default class NavBar extends React.Component { +export default function NavBar(props) { + return ( +
+ + + + Canapé + + + + + + + + + + + +
+ ); +} + +class Search extends React.Component { constructor(props) { super(props); - this.handleMovieSearch = this.handleMovieSearch.bind(this); - this.handleShowSearch = this.handleShowSearch.bind(this); + this.handleSearch = this.handleSearch.bind(this); } - handleMovieSearch() { - this.props.router.push(`/movies/search/${encodeURI(this.props.movieStore.search)}`) - } - handleShowSearch() { - this.props.router.push(`/shows/search/${encodeURI(this.props.showStore.search)}`) + handleSearch() { + this.props.router.push(`${this.props.path}/${encodeURI(this.props.search)}`) } render() { - const username = this.props.userStore.username; - const isLoggedIn = username !== "" ? true : false; const location = this.props.router.getCurrentLocation().pathname; - let displayMovieSearch = false; - let displayShowSearch = false; - if (isLoggedIn && location.indexOf("movies") > -1) + if (location.indexOf(this.props.pathMatch) === -1) { - displayMovieSearch = true; + return null; } - if (isLoggedIn && location.indexOf("shows") > -1) - { - displayShowSearch = true; - } - return ( -
- - - - Canapé - - - - - - - {displayMovieSearch && - -
this.handleMovieSearch()}> - - -
- } - {displayShowSearch && - -
this.handleShowSearch()}> - - -
- } -
-
-
+ + return( + +
+ + +
+ ); + } +} + +function MoviesDropdown(props) { + return( + + ); +} + +function ShowsDropdown(props) { + return( + + ); +} + +function UserDropdown(props) { + if (props.username !== "") { + return ( + + ); + } else { + return( + ); } }