commit
f6ad0dc85e
26
src/internal/admins/users.go
Normal file
26
src/internal/admins/users.go
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
package admin
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
"gitlab.quimbo.fr/odwrtw/canape-sql/src/internal/users"
|
||||||
|
"gitlab.quimbo.fr/odwrtw/canape-sql/src/internal/web"
|
||||||
|
|
||||||
|
"github.com/sirupsen/logrus"
|
||||||
|
)
|
||||||
|
|
||||||
|
// GetUsersHandler returns the user list
|
||||||
|
func GetUsersHandler(env *web.Env, w http.ResponseWriter, r *http.Request) error {
|
||||||
|
log := env.Log.WithFields(logrus.Fields{
|
||||||
|
"function": "admin.GetUsersHandler",
|
||||||
|
})
|
||||||
|
|
||||||
|
log.Debug("Getting users")
|
||||||
|
|
||||||
|
users, err := users.GetAll(env.Database)
|
||||||
|
if err != nil {
|
||||||
|
return env.RenderError(w, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return env.RenderJSON(w, users)
|
||||||
|
}
|
@ -24,6 +24,8 @@ const (
|
|||||||
getTokensQuery = `SELECT id, value FROM tokens WHERE user_id=$1;`
|
getTokensQuery = `SELECT id, value FROM tokens WHERE user_id=$1;`
|
||||||
checkTokenQuery = `SELECT count(*) FROM tokens WHERE user_id=$1 AND value=$2;`
|
checkTokenQuery = `SELECT count(*) FROM tokens WHERE user_id=$1 AND value=$2;`
|
||||||
deleteTokenQuery = `DELETE FROM tokens WHERE user_id=$1 AND value=$2;`
|
deleteTokenQuery = `DELETE FROM tokens WHERE user_id=$1 AND value=$2;`
|
||||||
|
|
||||||
|
getAllUsersQuery = `SELECT * FROM users;`
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@ -133,6 +135,16 @@ func Get(q sqlx.Queryer, name string) (*User, error) {
|
|||||||
return u, nil
|
return u, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetAll returns all the users
|
||||||
|
func GetAll(db *sqlx.DB) ([]*User, error) {
|
||||||
|
users := []*User{}
|
||||||
|
err := db.Select(&users, getAllUsersQuery)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return users, nil
|
||||||
|
}
|
||||||
|
|
||||||
// Add user to database or raises an error
|
// Add user to database or raises an error
|
||||||
func (u *User) Add(q sqlx.Queryer) error {
|
func (u *User) Add(q sqlx.Queryer) error {
|
||||||
var id string
|
var id string
|
||||||
|
8
src/public/js/actions/admins.js
Normal file
8
src/public/js/actions/admins.js
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
import { configureAxios, request } from "../requests"
|
||||||
|
|
||||||
|
export function getUsers() {
|
||||||
|
return request(
|
||||||
|
"ADMIN_LIST_USERS",
|
||||||
|
configureAxios().get("/admins/users")
|
||||||
|
)
|
||||||
|
}
|
@ -46,6 +46,7 @@ function mapStateToProps(state) {
|
|||||||
}
|
}
|
||||||
return {
|
return {
|
||||||
username: state.userStore.get("username"),
|
username: state.userStore.get("username"),
|
||||||
|
isAdmin: state.userStore.get("isAdmin"),
|
||||||
torrentCount: torrentCount,
|
torrentCount: torrentCount,
|
||||||
alerts: state.alerts,
|
alerts: state.alerts,
|
||||||
}
|
}
|
||||||
@ -60,6 +61,7 @@ function Main(props) {
|
|||||||
<div>
|
<div>
|
||||||
<NavBar
|
<NavBar
|
||||||
username={props.username}
|
username={props.username}
|
||||||
|
isAdmin={props.isAdmin}
|
||||||
router={props.router}
|
router={props.router}
|
||||||
torrentCount={props.torrentCount}
|
torrentCount={props.torrentCount}
|
||||||
/>
|
/>
|
||||||
|
64
src/public/js/components/admins/users.js
Normal file
64
src/public/js/components/admins/users.js
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
import React from "react"
|
||||||
|
import { connect } from "react-redux"
|
||||||
|
import { bindActionCreators } from "redux"
|
||||||
|
import { getUsers } from "../../actions/admins"
|
||||||
|
|
||||||
|
function mapStateToProps(state) {
|
||||||
|
return {
|
||||||
|
users : state.adminStore.get("users"),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
const mapDispatchToProps = (dipatch) =>
|
||||||
|
bindActionCreators({ getUsers }, dipatch)
|
||||||
|
|
||||||
|
function AdminView(props) {
|
||||||
|
return (
|
||||||
|
<UserList users={props.users} />
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function UserList(props) {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<h2 className="hidden-xs">Users</h2>
|
||||||
|
<h3 className="visible-xs">Users</h3>
|
||||||
|
<table className="table">
|
||||||
|
<thead>
|
||||||
|
<tr className="active">
|
||||||
|
<th>#</th>
|
||||||
|
<th>Name</th>
|
||||||
|
<th>Admin</th>
|
||||||
|
<th>Polochon URL</th>
|
||||||
|
<th>Polochon token</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{props.users.map(function(el, index) {
|
||||||
|
return (
|
||||||
|
<User key={index} data={el} />
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function User(props) {
|
||||||
|
const polochonConfig = props.data.get("RawConfig").get("polochon");
|
||||||
|
const polochonURL = polochonConfig ? polochonConfig.get("url") : "-";
|
||||||
|
const polochonToken = polochonConfig ? polochonConfig.get("token") : "-";
|
||||||
|
const admin = props.data.get("Admin") ? "yes" : "no";
|
||||||
|
return (
|
||||||
|
<tr>
|
||||||
|
<td>{props.data.get("id")}</td>
|
||||||
|
<td>{props.data.get("Name")}</td>
|
||||||
|
<td>{admin}</td>
|
||||||
|
<td>{polochonURL}</td>
|
||||||
|
<td>{polochonToken}</td>
|
||||||
|
<td></td>
|
||||||
|
</tr>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default connect(mapStateToProps, mapDispatchToProps)(AdminView);
|
@ -63,7 +63,7 @@ export default class AppNavBar extends React.PureComponent {
|
|||||||
{this.state.userLoggedIn &&
|
{this.state.userLoggedIn &&
|
||||||
<Torrents torrentsCount={this.props.torrentCount} />
|
<Torrents torrentsCount={this.props.torrentCount} />
|
||||||
}
|
}
|
||||||
<UserDropdown username={this.props.username} />
|
<UserDropdown username={this.props.username} isAdmin={this.props.isAdmin} />
|
||||||
{(this.state.displayMoviesSearch && this.state.userLoggedIn) &&
|
{(this.state.displayMoviesSearch && this.state.userLoggedIn) &&
|
||||||
<Search
|
<Search
|
||||||
placeholder="Search movies"
|
placeholder="Search movies"
|
||||||
@ -147,6 +147,11 @@ function UserDropdown(props) {
|
|||||||
return (
|
return (
|
||||||
<Nav pullRight>
|
<Nav pullRight>
|
||||||
<NavDropdown title={props.username} id="navbar-dropdown-right">
|
<NavDropdown title={props.username} id="navbar-dropdown-right">
|
||||||
|
{props.isAdmin &&
|
||||||
|
<LinkContainer to="/admin">
|
||||||
|
<MenuItem>Admin Panel</MenuItem>
|
||||||
|
</LinkContainer>
|
||||||
|
}
|
||||||
<LinkContainer to="/users/edit">
|
<LinkContainer to="/users/edit">
|
||||||
<MenuItem>Edit</MenuItem>
|
<MenuItem>Edit</MenuItem>
|
||||||
</LinkContainer>
|
</LinkContainer>
|
||||||
|
12
src/public/js/reducers/admins.js
Normal file
12
src/public/js/reducers/admins.js
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
import { Map, List, fromJS } from "immutable"
|
||||||
|
|
||||||
|
const defaultState = Map({
|
||||||
|
"users": List(),
|
||||||
|
});
|
||||||
|
|
||||||
|
const handlers = {
|
||||||
|
"ADMIN_LIST_USERS_FULFILLED": (state, action) => state.set("users", fromJS(action.payload.response.data)),
|
||||||
|
}
|
||||||
|
|
||||||
|
export default (state = defaultState, action) =>
|
||||||
|
handlers[action.type] ? handlers[action.type](state, action) : state;
|
@ -7,6 +7,7 @@ import showStore from "./show"
|
|||||||
import userStore from "./users"
|
import userStore from "./users"
|
||||||
import alerts from "./alerts"
|
import alerts from "./alerts"
|
||||||
import torrentStore from "./torrents"
|
import torrentStore from "./torrents"
|
||||||
|
import adminStore from "./admins"
|
||||||
|
|
||||||
const rootReducer = combineReducers({
|
const rootReducer = combineReducers({
|
||||||
routing: routerReducer,
|
routing: routerReducer,
|
||||||
@ -16,6 +17,7 @@ const rootReducer = combineReducers({
|
|||||||
userStore,
|
userStore,
|
||||||
alerts,
|
alerts,
|
||||||
torrentStore,
|
torrentStore,
|
||||||
|
adminStore,
|
||||||
})
|
})
|
||||||
|
|
||||||
export default rootReducer;
|
export default rootReducer;
|
||||||
|
@ -5,18 +5,23 @@ import UserLoginForm from "./components/users/login"
|
|||||||
import UserEdit from "./components/users/edit"
|
import UserEdit from "./components/users/edit"
|
||||||
import UserSignUp from "./components/users/signup"
|
import UserSignUp from "./components/users/signup"
|
||||||
import TorrentList from "./components/torrents/list"
|
import TorrentList from "./components/torrents/list"
|
||||||
|
import AdminView from "./components/admins/users"
|
||||||
|
|
||||||
import { fetchTorrents } from "./actions/torrents"
|
import { fetchTorrents } from "./actions/torrents"
|
||||||
import { userLogout, getUserInfos } from "./actions/users"
|
import { userLogout, getUserInfos } from "./actions/users"
|
||||||
import { fetchMovies, getMovieExploreOptions } from "./actions/movies"
|
import { fetchMovies, getMovieExploreOptions } from "./actions/movies"
|
||||||
import { fetchShows, fetchShowDetails, getShowExploreOptions } from "./actions/shows"
|
import { fetchShows, fetchShowDetails, getShowExploreOptions } from "./actions/shows"
|
||||||
|
import { getUsers } from "./actions/admins"
|
||||||
|
|
||||||
import store from "./store"
|
import store from "./store"
|
||||||
|
|
||||||
|
// Default route
|
||||||
|
const defaultRoute = "/movies/explore/yts/seeds";
|
||||||
|
|
||||||
// This function returns true if the user is logged in, false otherwise
|
// This function returns true if the user is logged in, false otherwise
|
||||||
function isLoggedIn() {
|
function isLoggedIn() {
|
||||||
const state = store.getState();
|
const state = store.getState();
|
||||||
const isLogged = state.userStore.isLogged;
|
const isLogged = state.userStore.get("isLogged");
|
||||||
let token = localStorage.getItem("token");
|
let token = localStorage.getItem("token");
|
||||||
|
|
||||||
// Let's check if the user has a token, if he does let's assume he's logged
|
// Let's check if the user has a token, if he does let's assume he's logged
|
||||||
@ -59,7 +64,16 @@ const loginCheck = function(nextState, replace, next, f = null) {
|
|||||||
next();
|
next();
|
||||||
}
|
}
|
||||||
|
|
||||||
const defaultRoute = "/movies/explore/yts/seeds";
|
const adminCheck = function(nextState, replace, next, f = null) {
|
||||||
|
const state = store.getState();
|
||||||
|
const isAdmin = state.userStore.get("isAdmin");
|
||||||
|
loginCheck(nextState, replace, next, function() {
|
||||||
|
if (!isAdmin) { replace(defaultRoute); }
|
||||||
|
if (f) { f(); }
|
||||||
|
next();
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
export default function getRoutes(App) {
|
export default function getRoutes(App) {
|
||||||
return {
|
return {
|
||||||
path: "/",
|
path: "/",
|
||||||
@ -207,6 +221,15 @@ export default function getRoutes(App) {
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
path: "/admin",
|
||||||
|
component: AdminView,
|
||||||
|
onEnter: function(nextState, replace, next) {
|
||||||
|
adminCheck(nextState, replace, next, function() {
|
||||||
|
store.dispatch(getUsers());
|
||||||
|
});
|
||||||
|
},
|
||||||
|
},
|
||||||
],
|
],
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"gitlab.quimbo.fr/odwrtw/canape-sql/src/internal/admins"
|
||||||
"gitlab.quimbo.fr/odwrtw/canape-sql/src/internal/external_medias"
|
"gitlab.quimbo.fr/odwrtw/canape-sql/src/internal/external_medias"
|
||||||
"gitlab.quimbo.fr/odwrtw/canape-sql/src/internal/movies"
|
"gitlab.quimbo.fr/odwrtw/canape-sql/src/internal/movies"
|
||||||
"gitlab.quimbo.fr/odwrtw/canape-sql/src/internal/shows"
|
"gitlab.quimbo.fr/odwrtw/canape-sql/src/internal/shows"
|
||||||
@ -56,4 +57,7 @@ func setupRoutes(env *web.Env) {
|
|||||||
|
|
||||||
// Route to refresh all movies and shows
|
// Route to refresh all movies and shows
|
||||||
env.Handle("/refresh", extmedias.RefreshHandler).WithRole(users.AdminRole).Methods("POST")
|
env.Handle("/refresh", extmedias.RefreshHandler).WithRole(users.AdminRole).Methods("POST")
|
||||||
|
|
||||||
|
// Admin routes
|
||||||
|
env.Handle("/admins/users", admin.GetUsersHandler).WithRole(users.AdminRole).Methods("GET")
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user