diff --git a/jams-react-client/build_deploy_jams_client.sh b/jams-react-client/build_deploy_jams_client.sh index de41b240d804a063972be11dff7c909c38316f97..fcd2b78046f4902b823266f0002a88340ca3e2fb 100755 --- a/jams-react-client/build_deploy_jams_client.sh +++ b/jams-react-client/build_deploy_jams_client.sh @@ -19,7 +19,7 @@ sed -i 's/material-dashboard-react\///g' $WEBAPP"index.html" #rm config.json cd .. -mvn clean package -DskipTests +#mvn clean package -DskipTests mvn package -DskipTests cd $JAMS diff --git a/jams-react-client/src/api.js b/jams-react-client/src/api.js index 72de6e6a44e4970ef530a5e387c999f5c58373d5..a54545b245d0a9d491e0074fc5da3c09db7fe34f 100644 --- a/jams-react-client/src/api.js +++ b/jams-react-client/src/api.js @@ -32,6 +32,7 @@ import { api_path_get_install_lastKnownStep, api_path_get_auth_user_search, api_path_get_auth_devices, + api_path_delete_admin_user_revoke, api_path_delete_auth_user_revoke, api_path_delete_auth_device_revoke, api_path_rename_device, @@ -89,11 +90,11 @@ export default function configApiCall(api_path, request_type, data, credentials) // search dataType if (isSearch) { - if(request_type == 'post'){ - config['data'] = data; + if(request_type == 'GET' || request_type == 'DELETE'){ + config['params'] = data } else { - config['params'] = data + config['data'] = data; } } diff --git a/jams-react-client/src/assets/jss/material-dashboard-react/components/cardStyle.js b/jams-react-client/src/assets/jss/material-dashboard-react/components/cardStyle.js index 33bc10edc1da2a93e9b44eb19f7729c1aaa880a9..28778131827d0d72bd6c9f44cf0b4b96a71478f7 100644 --- a/jams-react-client/src/assets/jss/material-dashboard-react/components/cardStyle.js +++ b/jams-react-client/src/assets/jss/material-dashboard-react/components/cardStyle.js @@ -37,6 +37,9 @@ const cardStyle = { }, "&:hover": { boxShadow: "0 1px 4px 0 rgba(" + hexToRgb(blackColor) + ", 0.54)", + }, + "& a": { + color: blackColor } }, cardPlain: { diff --git a/jams-react-client/src/globalUrls.js b/jams-react-client/src/globalUrls.js index 1ff0ef9ba7ba9319174999e3c9f68b0365a0a7fe..918bb413be9ce833cb1b0850524725c5b13aec6d 100644 --- a/jams-react-client/src/globalUrls.js +++ b/jams-react-client/src/globalUrls.js @@ -10,8 +10,11 @@ const api_path_post_install_auth = '/api/install/auth'; const api_path_post_install_server = '/api/install/settings'; const api_path_get_install_lastKnownStep = '/api/install/lastStep'; const api_path_get_auth_user_search = '/api/auth/users'; +const api_path_get_admin_devices = '/api/admin/devices'; const api_path_get_auth_devices = '/api/auth/devices'; +const api_path_delete_admin_user_revoke = '/api/admin/user'; const api_path_delete_auth_user_revoke = '/api/auth/user'; +const api_path_delete_admin_device_revoke = '/api/admin/device'; const api_path_delete_auth_device_revoke = '/api/auth/device'; const api_path_rename_device = '/api/auth/device'; const api_path_get_server_status = '/api/info'; @@ -24,10 +27,11 @@ const api_path_get_directories = '/api/auth/directories'; const api_path_get_needs_update = '/api/admin/update'; const api_path_get_start_update = '/api/admin/update'; const api_path_post_create_user = '/api/admin/user'; -const api_path_get_user = '/api/auth/user'; +const api_path_get_auth_user = '/api/auth/user'; +const api_path_get_admin_user = '/api/admin/user'; const api_path_post_update_user = '/api/auth/user'; const api_path_get_exists_user = '/api/admin/user'; -const api_path_get_user_directory_search = '/api/auth/directory/search'; +const api_path_get_user_directory_search ='/api/auth/directory/search'; const api_path_post_create_user_profile = '/api/admin/directory/entry'; const api_path_put_update_user_profile = '/api/admin/directory/entry'; const api_path_get_user_search = '/api/admin/users'; @@ -45,8 +49,11 @@ module.exports = { api_path_post_install_server, api_path_get_install_lastKnownStep, api_path_get_auth_user_search, + api_path_get_admin_devices, api_path_get_auth_devices, + api_path_delete_admin_user_revoke, api_path_delete_auth_user_revoke, + api_path_delete_admin_device_revoke, api_path_delete_auth_device_revoke, api_path_rename_device, api_path_get_server_status, @@ -59,7 +66,8 @@ module.exports = { api_path_get_needs_update, api_path_get_start_update, api_path_post_create_user, - api_path_get_user, + api_path_get_auth_user, + api_path_get_admin_user, api_path_post_update_user, api_path_get_exists_user, api_path_get_user_directory_search, diff --git a/jams-react-client/src/views/Users/Users.js b/jams-react-client/src/views/Users/Users.js index bf524c105c752716f41682124d5abe375c67354e..4c9cc6cd36ccb5da4f938fee8d7cccbbb7590186 100644 --- a/jams-react-client/src/views/Users/Users.js +++ b/jams-react-client/src/views/Users/Users.js @@ -14,16 +14,28 @@ import CardAvatar from "components/Card/CardAvatar.js"; import CardBody from "components/Card/CardBody.js"; import CardFooter from "components/Card/CardFooter.js"; import UserProfile from "views/UserProfile/UserProfile.js" +import Divider from '@material-ui/core/Divider'; +import Dialog from '@material-ui/core/Dialog'; +import DialogActions from '@material-ui/core/DialogActions'; +import DialogContent from '@material-ui/core/DialogContent'; +import DialogContentText from '@material-ui/core/DialogContentText'; +import DialogTitle from '@material-ui/core/DialogTitle'; + import PersonIcon from '@material-ui/icons/Person'; import PermIdentityIcon from '@material-ui/icons/PermIdentity'; import PhoneOutlinedIcon from '@material-ui/icons/PhoneOutlined'; import BusinessOutlinedIcon from '@material-ui/icons/BusinessOutlined'; +import DeleteIcon from '@material-ui/icons/Delete'; +import IconButton from '@material-ui/core/IconButton'; import MailOutlineIcon from '@material-ui/icons/MailOutline'; import axios from "axios"; import configApiCall from "api.js"; -import auth from "auth.js" -import { api_path_get_user_directory_search } from "globalUrls"; +import auth from 'auth.js' +import { + api_path_get_user_directory_search, + api_path_delete_admin_user_revoke + } from "globalUrls"; import AddCircleOutlineIcon from '@material-ui/icons/AddCircleOutline'; import KeyboardReturnIcon from '@material-ui/icons/KeyboardReturn'; @@ -47,6 +59,9 @@ const styles = { fontFamily: "'Roboto', 'Helvetica', 'Arial', sans-serif", marginBottom: "3px", textDecoration: "none" + }, + deleteIcon : { + float: "right" } }; @@ -55,8 +70,11 @@ const useStyles = makeStyles(styles); export default function Users() { const classes = useStyles(); const [users, setUsers] = React.useState([]) + const [open, setOpen] = React.useState(false); + const [revokedUser, setRevokedUser] = React.useState(''); useEffect(() => { + setRevokedUser('') axios(configApiCall(api_path_get_user_directory_search, 'GET', {"queryString":"*"}, null)).then((response)=>{ setUsers(response.data) } @@ -76,15 +94,29 @@ export default function Users() { setSelectedProfile(false); } - function dataURLtoFile(dataurl, filename) { - var arr = dataurl.split(','), mime = arr[0].match(/:(.*?);/)[1], - bstr = atob(arr[1]), n = bstr.length, u8arr = new Uint8Array(n); - while(n--){ - u8arr[n] = bstr.charCodeAt(n); + function revokeUser(){ + + const data = { + 'username': revokedUser } - return new File([u8arr], filename, {type:mime}); + + axios(configApiCall(api_path_delete_admin_user_revoke, 'DELETE', data, null)).then((result)=>{ + console.log("Revoked user: " + revokedUser); + }).catch((error)=> { + console.log("Error revoking user: " + revokedUser + ' with error: ' + error); + }); + setOpen(false); } + const handleClickOpen = (username) => { + setRevokedUser(username) + setOpen(true); + }; + + const handleClose = () => { + setOpen(false); + }; + if (selectedProfile || !auth.hasAdminScope()) { return ( <div> @@ -97,6 +129,27 @@ export default function Users() { } else { return ( <div> + <Dialog + open={open} + onClose={handleClose} + aria-labelledby="alert-dialog-title" + aria-describedby="alert-dialog-description" + > + <DialogTitle id="alert-dialog-title">{"Revoke user account"}</DialogTitle> + <DialogContent> + <DialogContentText id="alert-dialog-description"> + Are you sure you want to revoke <strong>{revokedUser}</strong> ? + </DialogContentText> + </DialogContent> + <DialogActions> + <Button onClick={handleClose} color="primary"> + Cancel + </Button> + <Button onClick={revokeUser} color="danger" autoFocus> + Revoke + </Button> + </DialogActions> + </Dialog> <GridContainer> <GridItem xs={12} sm={12} md={12}> <Button variant="contained" color="primary" href="#contained-buttons"> @@ -106,20 +159,27 @@ export default function Users() { { users.map(user => <GridItem xs={12} sm={12} md={2} key={user.username}> - <a href="#" onClick={redirectToUserProfile}> + <Card profile> <CardBody profile> + <a href="#" onClick={redirectToUserProfile}> <CardAvatar profile> <img src={user.profilePicture ? ('data:image/png;base64, ' + user.profilePicture) : noProfilePicture} alt="..." /> </CardAvatar> + <h4 className={classes.cardTitle}>{user.firstName} {user.lastName}</h4> <ul> <li><img src={jami} width="20" alt="Jami" /> {user.username}</li> <li><BusinessOutlinedIcon fontSize='small' /> {user.organization ? user.organization : 'No organization'}</li> </ul> + </a> + <Divider variant="middle" /> + <IconButton aria-label="delete" className={classes.deleteIcon} onClick={() => handleClickOpen(user.username)}> + <DeleteIcon fontSize="small" color="error" /> + </IconButton> </CardBody> </Card> - </a> + </GridItem>) } </GridContainer>