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 GetHash() string
HasRole(string) bool HasRole(string) bool
IsAdmin() bool IsAdmin() bool
IsActivated() bool
} }
// Authorizer handle sesssion // Authorizer handle sesssion

View File

@ -74,7 +74,13 @@ func (m *MiddlewareRole) ServeHTTP(w http.ResponseWriter, r *http.Request, next
return 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) next(w, r)
} }

View File

@ -81,8 +81,9 @@ func LoginPOSTHandler(e *web.Env, w http.ResponseWriter, r *http.Request) error
// Issued at // Issued at
"iat": time.Now().Unix(), "iat": time.Now().Unix(),
// Private claims // Private claims
"username": user.GetName(), "username": user.GetName(),
"isAdmin": user.IsAdmin(), "isAdmin": user.IsAdmin(),
"isActivated": user.IsActivated(),
}) })
// Sign the token // Sign the token

View File

@ -251,3 +251,8 @@ func (u *User) HasRole(role string) bool {
func (u *User) IsAdmin() bool { func (u *User) IsAdmin() bool {
return u.HasRole(AdminRole) 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 { return {
username: state.userStore.get("username"), username: state.userStore.get("username"),
isAdmin: state.userStore.get("isAdmin"), isAdmin: state.userStore.get("isAdmin"),
isActivated: state.userStore.get("isActivated"),
torrentCount: torrentCount, torrentCount: torrentCount,
alerts: state.alerts, alerts: state.alerts,
} }
@ -62,6 +63,7 @@ function Main(props) {
<NavBar <NavBar
username={props.username} username={props.username}
isAdmin={props.isAdmin} isAdmin={props.isAdmin}
isActivated={props.isActivated}
router={props.router} router={props.router}
torrentCount={props.torrentCount} torrentCount={props.torrentCount}
/> />

View File

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

View File

@ -3,6 +3,7 @@ import ShowList from "./components/shows/list"
import ShowDetails from "./components/shows/details" import ShowDetails from "./components/shows/details"
import UserLoginForm from "./components/users/login" import UserLoginForm from "./components/users/login"
import UserEdit from "./components/users/edit" import UserEdit from "./components/users/edit"
import UserActivation from "./components/users/activation"
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 AdminView from "./components/admins/users"
@ -42,15 +43,20 @@ function isLoggedIn() {
return false return false
} }
function isActivated() {
const state = store.getState();
return state.userStore.get("isActivated");
}
var pollingTorrentsId; var pollingTorrentsId;
const loginCheck = function(nextState, replace, next, f = null) { const loginCheck = function(nextState, replace, next, f = null) {
const loggedIn = isLoggedIn(); const loggedIn = isLoggedIn();
if (!loggedIn) { if (!loggedIn) {
replace("/users/login"); replace("/users/login");
} else if (!isActivated()) {
replace("/users/activation");
} else { } else {
if (f) { if (f) { f(); }
f();
}
// Poll torrents once logged // Poll torrents once logged
if (!pollingTorrentsId) { 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", path: "/users/logout",
onEnter: function(nextState, replace, next) { onEnter: function(nextState, replace, next) {