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;`
|
||||
checkTokenQuery = `SELECT count(*) 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 (
|
||||
@ -133,6 +135,16 @@ func Get(q sqlx.Queryer, name string) (*User, error) {
|
||||
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
|
||||
func (u *User) Add(q sqlx.Queryer) error {
|
||||
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 {
|
||||
username: state.userStore.get("username"),
|
||||
isAdmin: state.userStore.get("isAdmin"),
|
||||
torrentCount: torrentCount,
|
||||
alerts: state.alerts,
|
||||
}
|
||||
@ -60,6 +61,7 @@ function Main(props) {
|
||||
<div>
|
||||
<NavBar
|
||||
username={props.username}
|
||||
isAdmin={props.isAdmin}
|
||||
router={props.router}
|
||||
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 &&
|
||||
<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) &&
|
||||
<Search
|
||||
placeholder="Search movies"
|
||||
@ -147,6 +147,11 @@ function UserDropdown(props) {
|
||||
return (
|
||||
<Nav pullRight>
|
||||
<NavDropdown title={props.username} id="navbar-dropdown-right">
|
||||
{props.isAdmin &&
|
||||
<LinkContainer to="/admin">
|
||||
<MenuItem>Admin Panel</MenuItem>
|
||||
</LinkContainer>
|
||||
}
|
||||
<LinkContainer to="/users/edit">
|
||||
<MenuItem>Edit</MenuItem>
|
||||
</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 alerts from "./alerts"
|
||||
import torrentStore from "./torrents"
|
||||
import adminStore from "./admins"
|
||||
|
||||
const rootReducer = combineReducers({
|
||||
routing: routerReducer,
|
||||
@ -16,6 +17,7 @@ const rootReducer = combineReducers({
|
||||
userStore,
|
||||
alerts,
|
||||
torrentStore,
|
||||
adminStore,
|
||||
})
|
||||
|
||||
export default rootReducer;
|
||||
|
@ -5,18 +5,23 @@ import UserLoginForm from "./components/users/login"
|
||||
import UserEdit from "./components/users/edit"
|
||||
import UserSignUp from "./components/users/signup"
|
||||
import TorrentList from "./components/torrents/list"
|
||||
import AdminView from "./components/admins/users"
|
||||
|
||||
import { fetchTorrents } from "./actions/torrents"
|
||||
import { userLogout, getUserInfos } from "./actions/users"
|
||||
import { fetchMovies, getMovieExploreOptions } from "./actions/movies"
|
||||
import { fetchShows, fetchShowDetails, getShowExploreOptions } from "./actions/shows"
|
||||
import { getUsers } from "./actions/admins"
|
||||
|
||||
import store from "./store"
|
||||
|
||||
// Default route
|
||||
const defaultRoute = "/movies/explore/yts/seeds";
|
||||
|
||||
// This function returns true if the user is logged in, false otherwise
|
||||
function isLoggedIn() {
|
||||
const state = store.getState();
|
||||
const isLogged = state.userStore.isLogged;
|
||||
const isLogged = state.userStore.get("isLogged");
|
||||
let token = localStorage.getItem("token");
|
||||
|
||||
// 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();
|
||||
}
|
||||
|
||||
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) {
|
||||
return {
|
||||
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
|
||||
|
||||
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/movies"
|
||||
"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
|
||||
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