Only show the activation page for unactivated users

This commit is contained in:
Grégoire Delattre 2017-08-13 09:00:18 +02:00
parent 9aebee2c4a
commit 3f2fd35195
9 changed files with 79 additions and 17 deletions

View File

@ -30,6 +30,7 @@ type User interface {
GetHash() string
HasRole(string) bool
IsAdmin() bool
IsActivated() bool
}
// Authorizer handle sesssion

View File

@ -74,7 +74,13 @@ func (m *MiddlewareRole) ServeHTTP(w http.ResponseWriter, r *http.Request, next
return
}
m.log.Debug("user has the role, continuing")
if !user.IsActivated() {
// return unauthorized
http.Error(w, "User is not activated", http.StatusUnauthorized)
return
}
m.log.Debug("user has the role and is activated, continuing")
next(w, r)
}

View File

@ -83,6 +83,7 @@ func LoginPOSTHandler(e *web.Env, w http.ResponseWriter, r *http.Request) error
// Private claims
"username": user.GetName(),
"isAdmin": user.IsAdmin(),
"isActivated": user.IsActivated(),
})
// Sign the token

View File

@ -251,3 +251,8 @@ func (u *User) HasRole(role string) bool {
func (u *User) IsAdmin() bool {
return u.HasRole(AdminRole)
}
// IsActivated checks if a user is activated
func (u *User) IsActivated() bool {
return u.Activated
}

View File

@ -47,6 +47,7 @@ function mapStateToProps(state) {
return {
username: state.userStore.get("username"),
isAdmin: state.userStore.get("isAdmin"),
isActivated: state.userStore.get("isActivated"),
torrentCount: torrentCount,
alerts: state.alerts,
}
@ -62,6 +63,7 @@ function Main(props) {
<NavBar
username={props.username}
isAdmin={props.isAdmin}
isActivated={props.isActivated}
router={props.router}
torrentCount={props.torrentCount}
/>

View File

@ -41,6 +41,9 @@ export default class AppNavBar extends React.PureComponent {
this.setState({ expanded: value });
}
render() {
const loggedAndActivated = (this.state.userLoggedIn && this.props.isActivated);
const displayShowsSearch = (this.state.displayShowsSearch && loggedAndActivated);
const displayMoviesSearch = (this.state.displayMoviesSearch && loggedAndActivated);
return (
<div>
<Navbar fluid fixedTop collapseOnSelect expanded={this.state.expanded} onToggle={this.setExpanded}>
@ -51,20 +54,24 @@ export default class AppNavBar extends React.PureComponent {
<Navbar.Toggle />
</Navbar.Header>
<Navbar.Collapse>
{this.state.userLoggedIn &&
{loggedAndActivated &&
<MoviesDropdown />
}
{this.state.userLoggedIn &&
{loggedAndActivated &&
<ShowsDropdown />
}
{this.state.userLoggedIn &&
{loggedAndActivated &&
<WishlistDropdown />
}
{this.state.userLoggedIn &&
{loggedAndActivated &&
<Torrents torrentsCount={this.props.torrentCount} />
}
<UserDropdown username={this.props.username} isAdmin={this.props.isAdmin} />
{(this.state.displayMoviesSearch && this.state.userLoggedIn) &&
<UserDropdown
username={this.props.username}
isAdmin={this.props.isAdmin}
isActivated={this.props.isActivated}
/>
{displayMoviesSearch &&
<Search
placeholder="Search movies"
router={this.props.router}
@ -72,7 +79,7 @@ export default class AppNavBar extends React.PureComponent {
setExpanded={this.setExpanded}
/>
}
{(this.state.displayShowsSearch && this.state.userLoggedIn) &&
{displayShowsSearch &&
<Search
placeholder="Search shows"
router={this.props.router}
@ -152,9 +159,11 @@ function UserDropdown(props) {
<MenuItem>Admin Panel</MenuItem>
</LinkContainer>
}
{props.isActivated &&
<LinkContainer to="/users/edit">
<MenuItem>Edit</MenuItem>
</LinkContainer>
}
<LinkContainer to="/users/logout">
<MenuItem>Logout</MenuItem>
</LinkContainer>

View File

@ -0,0 +1,16 @@
import React from "react"
function UserActivation(props) {
return (
<div className="container">
<div className="content-fluid">
<div className="col-md-8 col-md-offset-2 col-xs-12">
<h2>Waiting for activation</h2>
<hr />
<h3>Hang tight! Your user will soon be activated by the administrators of this site.</h3>
</div>
</div>
</div>
);
}
export default UserActivation;

View File

@ -7,6 +7,7 @@ const defaultState = Map({
loading: false,
username: "",
isAdmin: false,
isActivated: false,
isLogged: false,
polochonToken: "",
polochonUrl: "",
@ -46,6 +47,7 @@ function updateFromToken(state, token) {
userLoading: false,
isLogged: true,
isAdmin: decodedToken.isAdmin,
isActivated: decodedToken.isActivated,
username: decodedToken.username,
}))
}

View File

@ -3,6 +3,7 @@ import ShowList from "./components/shows/list"
import ShowDetails from "./components/shows/details"
import UserLoginForm from "./components/users/login"
import UserEdit from "./components/users/edit"
import UserActivation from "./components/users/activation"
import UserSignUp from "./components/users/signup"
import TorrentList from "./components/torrents/list"
import AdminView from "./components/admins/users"
@ -42,15 +43,20 @@ function isLoggedIn() {
return false
}
function isActivated() {
const state = store.getState();
return state.userStore.get("isActivated");
}
var pollingTorrentsId;
const loginCheck = function(nextState, replace, next, f = null) {
const loggedIn = isLoggedIn();
if (!loggedIn) {
replace("/users/login");
} else if (!isActivated()) {
replace("/users/activation");
} else {
if (f) {
f();
}
if (f) { f(); }
// Poll torrents once logged
if (!pollingTorrentsId) {
@ -104,6 +110,20 @@ export default function getRoutes(App) {
});
},
},
{
path: "/users/activation",
component: UserActivation,
onEnter: function(nextState, replace, next) {
if (!isLoggedIn()) {
replace('/users/login');
}
if (isActivated()) {
// User is already activated, redirect him to the default route
replace(defaultRoute);
}
next();
},
},
{
path: "/users/logout",
onEnter: function(nextState, replace, next) {