Skip to content
Snippets Groups Projects
Commit 546b1123 authored by Larbi Gharib's avatar Larbi Gharib
Browse files

Manage moderator in blueprints

Change-Id: Ie88b1eb6397a5ddf840ca8b06ac91af015ea2581
parent b4d34806
No related branches found
No related tags found
No related merge requests found
Showing
with 192 additions and 14 deletions
File added
File added
File added
File added
#Wed Feb 03 17:11:57 WEST 2021
gradle.version=6.7
File added
......@@ -236,5 +236,8 @@
"add_user_to_a_group": "Add user to a group",
"remove_from_group": "Remove from group",
"myprofile": "My profile",
"select_blueprint": "Select a blueprint"
"select_blueprint": "Select a blueprint",
"add_moderator_to_blueprint": "Add moderator to blueprint ...",
"add_moderator_to": "Add moderator to",
"remove_moderator": "Remove moderator"
}
......@@ -236,5 +236,8 @@
"add_user_to_a_group": "Ajouter l'utilisateur à un groupe",
"remove_from_group": "Retirer du groupe",
"myprofile": "Mon profil",
"select_blueprint": "Select a blueprint"
"select_blueprint": "Select a blueprint",
"add_moderator_to_blueprint": "Add moderator to blueprint ...",
"add_moderator_to": "Add moderator to",
"remove_moderator": "Remove moderator"
}
......@@ -44,7 +44,7 @@ export default function TemporaryDrawer(props) {
const listUsers = () => (
<List>
{props.type === "user" ? ( props.targets && props.targets.map((target) => (
{props.type === "user" ? ( props.targets && props.targets.filter((target) => !props.existingTargets.some(t => target.username == t.username)).map((target) => (
<ListItem
button
key={target.username}
......@@ -72,7 +72,7 @@ export default function TemporaryDrawer(props) {
}
/>
</ListItem>
))) : ( props.targets && props.targets.map((target) => (
))) : ( props.targets && props.targets.filter((target) => !props.existingTargets.some(t => target.name == t.name)).map((target) => (
<ListItem
button
key={target.name}
......
import React from "react";
import { Link, useHistory } from "react-router-dom";
// @material-ui/core components
import { makeStyles } from "@material-ui/core/styles";
import Checkbox from "@material-ui/core/Checkbox";
import classnames from "classnames";
// core components
import Grid from "@material-ui/core/Grid";
import GridItem from "components/Grid/GridItem.js";
......@@ -12,6 +15,17 @@ import CardIcon from "components/Card/CardIcon.js";
import CardBody from "components/Card/CardBody.js";
import FormGroup from "@material-ui/core/FormGroup";
import FormControlLabel from "@material-ui/core/FormControlLabel";
import Button from "components/CustomButtons/Button.js";
import AddCircleOutlineIcon from '@material-ui/icons/AddCircleOutline';
import Avatar from "@material-ui/core/Avatar";
import Table from "@material-ui/core/Table";
import TableHead from '@material-ui/core/TableHead';
import TableRow from "@material-ui/core/TableRow";
import TableBody from "@material-ui/core/TableBody";
import TableCell from "@material-ui/core/TableCell";
import Snackbar from "@material-ui/core/Snackbar";
......@@ -19,9 +33,18 @@ import { hexToRgb, blackColor } from "assets/jss/material-dashboard-react.js";
import PriorityHighOutlinedIcon from "@material-ui/icons/PriorityHighOutlined";
import noProfilePicture from "assets/img/faces/no-profile-picture.png";
import axios from "axios";
import configApiCall from "../../api";
import { api_path_blueprints } from "../../globalUrls";
import {
api_path_blueprints,
api_path_get_user_directory_search,
api_path_get_ns_name_from_addr,
api_path_get_user_profile
} from "../../globalUrls";
import TemporaryDrawer from "components/Drawer/Drawer"
import dashboardStyle from "assets/jss/material-dashboard-react/views/dashboardStyle.js";
......@@ -29,6 +52,8 @@ import MuiAlert from "@material-ui/lab/Alert";
import i18next from "i18next";
import auth from "auth.js";
const styles = (theme) => ({
...dashboardStyle,
root: {
......@@ -92,12 +117,20 @@ function Alert(props) {
export default function EditBlueprintPermissions(props) {
const classes = useStyles();
const history = useHistory();
const tableCellClasses = classnames(classes.tableCell);
const [openDrawer, setOpenDrawer] = React.useState(false);
const [users, setUsers] = React.useState([]);
const [blueprintModerators, setBlueprintModerators] = React.useState([]);
const [videoEnabled, setVideoEnabled] = React.useState(true);
const [publicInCalls, setPublicInCalls] = React.useState(true);
const [autoAnswer, setAutoAnswer] = React.useState(false);
const [peerDiscovery, setPeerDiscovery] = React.useState(true);
const [rendezVous, setRendezVous] = React.useState(false);
const [defaultModerators, setDefaultModerators] = React.useState("");
const [upnpEnabled, setUpnpEnabled] = React.useState(true);
const [turnEnabled, setTurnEnabled] = React.useState(true);
......@@ -112,7 +145,39 @@ export default function EditBlueprintPermissions(props) {
const [message, setMessage] = React.useState(false);
const [severity, setSeverity] = React.useState("success");
const searchUsers = (value) => {
axios(
configApiCall(
api_path_get_user_directory_search,
"GET",
{ queryString: value ? value : "*", page: "1" },
null
)
)
.then((response) => {
let profiles = [];
const profilesResults = response.data.profiles;
profilesResults.forEach((profile) =>{
let existingUser = false;
users.forEach((user)=>{
if(profile.username === user.username) existingUser = true;
})
if(!existingUser) profiles.push(profile);
})
setUsers(profiles);
})
.catch((error) => {
console.log(error);
setUsers([]);
if (error.response.status === 401) {
auth.authenticated = false;
history.push("/");
}
});
};
React.useEffect(() => {
searchUsers();
axios(
configApiCall(
api_path_blueprints + "?name=" + props.blueprintName,
......@@ -128,6 +193,7 @@ export default function EditBlueprintPermissions(props) {
setAutoAnswer(policyData["autoAnswer"]);
setPeerDiscovery(policyData["peerDiscovery"]);
setRendezVous(policyData["rendezVous"]);
setDefaultModerators(policyData["defaultModerators"]);
setUpnpEnabled(policyData["upnpEnabled"]);
setTurnEnabled(policyData["turnEnabled"]);
......@@ -137,6 +203,23 @@ export default function EditBlueprintPermissions(props) {
setProxyEnabled(policyData["proxyEnabled"]);
setProxyServer(policyData["proxyServer"]);
setDhtProxyListUrl(policyData["dhtProxyListUrl"]);
policyData["defaultModerators"].split("/").forEach((id) => {
if(id !== "undefined" && id !== ""){
axios(configApiCall(api_path_get_ns_name_from_addr + id), null, null).then((usernameResponse) => {
let username = usernameResponse.data.name;
axios(configApiCall(api_path_get_user_profile + username), null, null).then((userProfileResponse) => {
let userProfiles = blueprintModerators;
userProfileResponse.data["id"] = id;
userProfiles.push(userProfileResponse.data)
setBlueprintModerators(userProfiles);
// This state update is added to refresh the list of moderators
setOpenDrawer(true);
setOpenDrawer(false);
});
});
}
})
})
.catch((error) => {
console.log(
......@@ -157,6 +240,7 @@ export default function EditBlueprintPermissions(props) {
accountDiscovery: peerDiscovery,
accountPublish: peerDiscovery,
rendezVous: rendezVous,
defaultModerators: defaultModerators,
upnpEnabled: upnpEnabled,
turnEnabled: turnEnabled,
turnServer: turnServer,
......@@ -214,6 +298,28 @@ export default function EditBlueprintPermissions(props) {
setOpen(false);
};
const addModeratorToBlueprint = (user) => {
if(defaultModerators.includes(user.id)){
alert(`${user.username} is already a moderator of ${props.blueprintName}`);
}
else {
handleUpdatePermissions("defaultModerators", defaultModerators + user.id + "/");
setDefaultModerators(defaultModerators + user.id + "/");
let newBlueprintModerators = blueprintModerators;
newBlueprintModerators.push(user);
setBlueprintModerators(newBlueprintModerators);
}
}
const removeModeratorFromBlueprint = (user) => {
let newDefaultModerators = defaultModerators.replace( user.id + "/", "")
handleUpdatePermissions("defaultModerators", newDefaultModerators);
setDefaultModerators(newDefaultModerators);
let newBlueprintModerators = blueprintModerators;
newBlueprintModerators.splice(newBlueprintModerators.indexOf(user), 1);
setBlueprintModerators(newBlueprintModerators);
}
return (
<div>
<Snackbar
......@@ -227,6 +333,17 @@ export default function EditBlueprintPermissions(props) {
{message}
</Alert>
</Snackbar>
<TemporaryDrawer
openDrawer={openDrawer}
setOpenDrawer={setOpenDrawer}
direction="right"
placeholder={i18next.t("add_moderator_to_blueprint", "Add moderator to blueprint ...")}
searchTargets={searchUsers}
targets={users}
existingTargets={blueprintModerators}
addElementToTarget={addModeratorToBlueprint}
type="user"
/>
<GridContainer>
<GridItem xs={12} sm={12} md={6}>
<Card profile>
......@@ -342,6 +459,51 @@ export default function EditBlueprintPermissions(props) {
</CardBody>
</Card>
</GridItem>
<GridItem xs={12} sm={12} md={12}>
<Button color="primary" onClick={() => {setOpenDrawer(true)}}><AddCircleOutlineIcon /> {i18next.t("add_moderator_to", "Add moderator to")} {props.blueprintName}</Button>
<Table className={classes.table}>
<TableHead>
<TableRow>
<TableCell align="left"></TableCell>
<TableCell align="left">{i18next.t("username", "Username")}</TableCell>
<TableCell align="left">{i18next.t("first_name", "First name")}</TableCell>
<TableCell align="left">{i18next.t("last_name", "Last name")}</TableCell>
<TableCell align="right">{i18next.t("action", "Action")}</TableCell>
</TableRow>
</TableHead>
<TableBody>
{blueprintModerators.map(user =>
<TableRow key={user.username} className={classes.tableRow}>
<TableCell className={tableCellClasses}>
<Link to={`/user/${user.username}`}>
<Avatar
style={{ marginRight: "10px" }}
alt={user.username}
src={
user.profilePicture
? "data:image/png;base64, " + user.profilePicture
: noProfilePicture
}
/>
</Link>
</TableCell>
<TableCell className={tableCellClasses}>
<Link to={`/user/${user.username}`}>{user.username}</Link>
</TableCell>
<TableCell className={tableCellClasses}>
<Link to={`/user/${user.username}`}>{user.firstName}</Link>
</TableCell>
<TableCell className={tableCellClasses}>
<Link to={`/user/${user.username}`}>{user.lastName}</Link>
</TableCell>
<TableCell align="right" className={classes.tableActions}>
<Button color="primary" onClick={() => removeModeratorFromBlueprint(user)}>{i18next.t("remove_moderator", "Remove moderator")}</Button>
</TableCell>
</TableRow>
)}
</TableBody>
</Table>
</GridItem>
</GridContainer>
</div>
);
......
......@@ -188,6 +188,7 @@ export default function Blueprints() {
accountDiscovery: true,
accountPublish: true,
rendezVous: false,
defaultModerators: "",
upnpEnabled: true,
};
......
......@@ -148,10 +148,10 @@ export default function Users(props) {
null
)
).then((response) => {
contact.name = response.data.name;
contact.username = response.data.name;
axios(
configApiCall(
api_path_get_user_profile + contact.name,
api_path_get_user_profile + contact.username,
"GET",
null,
null
......@@ -191,10 +191,10 @@ export default function Users(props) {
null
)
).then((response) => {
contact.name = response.data.name;
contact.username = response.data.name;
axios(
configApiCall(
api_path_get_user_profile + contact.name,
api_path_get_user_profile + contact.username,
"GET",
null,
null
......@@ -336,6 +336,7 @@ export default function Users(props) {
placeholder={i18next.t("add_contact", "Add contact…")}
searchTargets={searchContacts}
targets={users}
existingTargets={contacts}
addElementToTarget={addContactToUser}
targetName={props.username}
type="user"
......@@ -418,8 +419,8 @@ export default function Users(props) {
key={contact.uri}
style={{ display: contact.display }}
>
{contact.name && <Card profile>
<a href={`/user/${contact.name}`}>
{contact.username && <Card profile>
<a href={`/user/${contact.username}`}>
<CardBody profile>
<CardAvatar profile>
<img
......@@ -436,13 +437,13 @@ export default function Users(props) {
</h4>
<ul>
<li>
{contact.name && <img
{contact.username && <img
src={jami}
width="20"
alt="Jami"
style={{ marginRight: "10px" }}
/>}
{contact.name && ` ${contact.name}`}
{contact.username && ` ${contact.username}`}
</li>
<li>
{contact.organization && <BusinessOutlinedIcon
......@@ -458,7 +459,7 @@ export default function Users(props) {
<IconButton
color="secondary"
onClick={() => {
handleRemoveContact(contact.uri, contact.name);
handleRemoveContact(contact.uri, contact.username);
}}
>
<DeleteOutlineIcon />
......
......@@ -352,6 +352,7 @@ export default function EditGroup(props) {
placeholder={i18next.t("add_user_to_group", "Add user to group ...")}
searchTargets={searchUsers}
targets={users}
existingTargets={groupMembers}
addElementToTarget={addUserInGroup}
targetName={name}
type="user"
......
......@@ -535,6 +535,7 @@ export default function DisplayUserProfile(props) {
placeholder={i18next.t("add_user_to_group", "Add user to group ...")}
searchTargets={searchGroups}
targets={groups}
existingTargets={groupMemberships}
addElementToTarget={addUserToGroup}
targetName={props.username}
type="group"
......
......@@ -193,6 +193,10 @@ public class DeviceServlet extends HttpServlet {
obj.add("Account.displayName", obj.get("displayName"));
obj.remove("displayName");
}
if (obj.get("defaultModerators") != null) {
obj.add("Account.defaultModerators", obj.get("defaultModerators"));
obj.remove("defaultModerators");
}
resp.getOutputStream().write((obj.toString()).getBytes());
}
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment