diff --git a/datastore/src/main/java/net/jami/datastore/dao/ContactDao.java b/datastore/src/main/java/net/jami/datastore/dao/ContactDao.java index c80855d9c2cf51689d85e9991528d91bcb2c28e9..df1a2cbf2d27561ce93f266be5b2f5af59b59cf4 100644 --- a/datastore/src/main/java/net/jami/datastore/dao/ContactDao.java +++ b/datastore/src/main/java/net/jami/datastore/dao/ContactDao.java @@ -25,6 +25,7 @@ package net.jami.datastore.dao; import lombok.extern.slf4j.Slf4j; import net.jami.datastore.main.DataStore; +import net.jami.jams.common.dao.StatementList; import net.jami.jams.common.dao.connectivity.SQLConnection; import net.jami.jams.common.objects.contacts.Contact; @@ -81,4 +82,21 @@ public class ContactDao extends AbstractDao<Contact> { DataStore.connectionPool.returnConnection(connection); } } + + @Override + public boolean deleteObject(StatementList constraints) { + SQLConnection connection = DataStore.connectionPool.getConnection(); + + try { + PreparedStatement ps = connection.getConnection().prepareStatement("DELETE FROM contacts WHERE owner = ? AND uri = ?"); + ps.setString(1, constraints.getStatements().get(0).getValue()); + ps.setString(2, constraints.getStatements().get(1).getValue()); + return ps.executeUpdate() != 0; + } catch (SQLException e){ + log.error("Could not delete contact: " + e.toString()); + return false; + } finally { + DataStore.connectionPool.returnConnection(connection); + } + } } diff --git a/jams-react-client/src/components/Drawer/Drawer.js b/jams-react-client/src/components/Drawer/Drawer.js index 783b20c6f87ab03746a0ec3fecacc1654d2d853a..0b3f473ed0b24f3b18703c6c3419db703771d68a 100644 --- a/jams-react-client/src/components/Drawer/Drawer.js +++ b/jams-react-client/src/components/Drawer/Drawer.js @@ -3,26 +3,18 @@ import clsx from 'clsx'; import { makeStyles } from '@material-ui/core/styles'; import CustomInput from "components/CustomInput/CustomInput.js"; import Drawer from '@material-ui/core/Drawer'; -import Search from "@material-ui/icons/Search"; -import Button from '@material-ui/core/Button'; import List from '@material-ui/core/List'; import Divider from '@material-ui/core/Divider'; import ListItem from '@material-ui/core/ListItem'; -import ListItemIcon from '@material-ui/core/ListItemIcon'; import ListItemText from '@material-ui/core/ListItemText'; -import InboxIcon from '@material-ui/icons/MoveToInbox'; -import MailIcon from '@material-ui/icons/Mail'; import AddCircleOutlineIcon from '@material-ui/icons/AddCircleOutline'; -import LinearProgress from '@material-ui/core/LinearProgress'; - -import {api_path_get_user_directory_search, api_path_get_auth_contacts, api_path_put_update_group} from 'globalUrls' +import {api_path_get_user_directory_search, api_path_get_auth_contacts, api_path_get_admin_contacts, api_path_put_update_group} from 'globalUrls' import { useHistory } from 'react-router-dom'; import axios from "axios"; import configApiCall from "api.js"; import auth from 'auth.js' import { debounce } from "lodash"; -import {api_path_get_list_group} from "../../globalUrls"; const useStyles = makeStyles({ list: { @@ -63,14 +55,37 @@ export default function TemporaryDrawer(props) { }); }, [userAdded]) - const addContactToUser = (jamiId) => { - axios(configApiCall(api_path_get_auth_contacts, 'PUT', {"uri": "jami://" + jamiId}, null)).then((response)=>{ - props.setOpenDrawer(false) - props.getAllUsers() - }).catch((error) =>{ - console.log("Error adding user: " + error) - props.setOpenDrawer(false) - }); + const addContactToUser = (firstName, lastName, jamiId) => { + var displayName= firstName+" "+ lastName; + var owner = props.username; + const data = { + "owner": owner, + "uri": jamiId, + "displayName": displayName, + "timestamp": "", + "status": '', + "banned": false, + "confirmed": false + }; + if(props.isAdmin){ + axios(configApiCall(api_path_get_admin_contacts+"?username="+props.username,'PUT', data, null)).then((response)=>{ + props.setOpenDrawer(false) + props.getAllUsers() + }).catch((error) =>{ + console.log("Error adding user: " + error) + props.setOpenDrawer(false) + }); + } + else { + axios(configApiCall(api_path_get_auth_contacts, 'PUT', data, null)).then((response)=>{ + props.setOpenDrawer(false) + props.getAllUsers() + }).catch((error) =>{ + console.log("Error adding user: " + error) + props.setOpenDrawer(false) + }); + } + } const addUserToGroup = (username) => { @@ -78,7 +93,6 @@ export default function TemporaryDrawer(props) { if(props.selectedBlueprint == ''){ url = api_path_put_update_group+"?groupName="+props.groupName+"&newName="+props.groupName+"&blueprintName=&groupMembers="+username; }else{ - console.log(props.blueprintsOptions) url = api_path_put_update_group+"?groupName="+props.groupName+"&newName="+props.groupName+"&blueprintName="+props.blueprintsOptions[props.selectedBlueprint].label+"&groupMembers="+username; } @@ -115,11 +129,11 @@ export default function TemporaryDrawer(props) { addingToGroup ? <ListItem button key={user.username} onClick={() => {addUserToGroup(user.username)}} > - <AddCircleOutlineIcon style={{ marginRight: "10px"}} /><ListItemText primary={user.username} /> + <AddCircleOutlineIcon style={{ marginRight: "10px"}} /><ListItemText primary={user.firstName+" "+user.lastName} /> </ListItem> : - <ListItem button key={user.username} onClick={() => {addContactToUser(user.jamiId)}} > - <AddCircleOutlineIcon style={{ marginRight: "10px"}} /><ListItemText primary={user.username} /> + <ListItem button key={user.username} onClick={() => {addContactToUser(user.firstName, user.lastName, user.id)}} > + <AddCircleOutlineIcon style={{ marginRight: "10px"}} /><ListItemText primary={user.firstName+" "+user.lastName} /> </ListItem> )) diff --git a/jams-react-client/src/globalUrls.js b/jams-react-client/src/globalUrls.js index e31c392a2dcd1e929d31398038d499f8cdbc2b58..e3caeb494095d69f3aa8f939fc83dd5942c08a42 100644 --- a/jams-react-client/src/globalUrls.js +++ b/jams-react-client/src/globalUrls.js @@ -40,7 +40,9 @@ 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'; const api_path_get_auth_contacts = '/api/auth/contacts'; +const api_path_get_admin_contacts = '/api/admin/contacts'; const api_path_delete_auth_contacts = '/api/auth/contacts'; +const api_path_delete_admin_contacts = '/api/admin/contacts' const api_path_blueprints = '/api/admin/policy'; module.exports = { @@ -82,7 +84,9 @@ module.exports = { api_path_put_update_user_profile, api_path_get_user_search, api_path_get_auth_contacts, + api_path_get_admin_contacts, api_path_delete_auth_contacts, + api_path_delete_admin_contacts, api_path_delete_group, api_path_get_list_group, api_path_post_create_group, diff --git a/jams-react-client/src/views/Contacts/Contacts.js b/jams-react-client/src/views/Contacts/Contacts.js index a77c82db84829eef24fb70c10b73787b6f23f1e7..5ff7a978029ee2c61e356d0486b907f0a374675d 100644 --- a/jams-react-client/src/views/Contacts/Contacts.js +++ b/jams-react-client/src/views/Contacts/Contacts.js @@ -28,7 +28,7 @@ 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_auth_contacts, api_path_delete_auth_contacts } from "globalUrls"; +import { api_path_get_auth_contacts, api_path_get_admin_contacts, api_path_delete_auth_contacts, api_path_delete_admin_contacts } from "globalUrls"; import AddCircleOutlineIcon from '@material-ui/icons/AddCircleOutline'; import KeyboardReturnIcon from '@material-ui/icons/KeyboardReturn'; @@ -93,24 +93,46 @@ export default function Users(props) { const [open, setOpen] = React.useState(false) const getAllContacts = () => { - axios(configApiCall(api_path_get_auth_contacts, 'GET', null, null)).then((response)=>{ - /* - TODO: Include the username of the user of witch we want to display contacts - at the moment the admin sees his contacts in each user profile he visits - */ - let orginalUsers = response.data - orginalUsers.map((user) => { - user.display = "" - }) - setContacts(orginalUsers) - setLoading(false) - }).catch((error) =>{ - console.log(error); - if(error.response.status == 401){ - auth.authenticated = false - history.push('/') - } - }); + if(auth.hasAdminScope()){ + axios(configApiCall(api_path_get_admin_contacts+"?username="+props.username, 'GET', null, null)).then((response)=>{ + /* + TODO: Include the username of the user of witch we want to display contacts + at the moment the admin sees his contacts in each user profile he visits + */ + let orginalContacts = response.data + orginalContacts.map((contact) => { + contact.display = "" + }) + setContacts(orginalContacts) + setLoading(false) + }).catch((error) =>{ + console.log(error); + if(error.response.status == 401){ + auth.authenticated = false + history.push('/') + } + }); + } + else{ + axios(configApiCall(api_path_get_auth_contacts, 'GET', null, null)).then((response)=>{ + /* + TODO: Include the username of the user of witch we want to display contacts + at the moment the admin sees his contacts in each user profile he visits + */ + let orginalContacts = response.data + orginalContacts.map((contact) => { + contact.display = "" + }) + setContacts(orginalContacts) + setLoading(false) + }).catch((error) =>{ + console.log(error); + if(error.response.status == 401){ + auth.authenticated = false + history.push('/') + } + }); + } } useEffect(() => { @@ -129,14 +151,25 @@ export default function Users(props) { return () => { clearInterval(timer); }; - }, []); + }, [openDrawer]); const removeContact = () => { - axios(configApiCall(api_path_delete_auth_contacts, 'DELETE', {"uri": removedContact.replace("jami://", "")}, null)).then((response)=>{ - getAllContacts() - }).catch((error) =>{ - alert("Uri: " + removedContact + " was not removed " + error) - }); + if(auth.hasAdminScope()){ + axios(configApiCall(api_path_delete_admin_contacts+"?username="+props.username+"&uri="+removedContact.replace("jami://", ""), 'DELETE', null, null)).then((response)=>{ + setOpen(false); + getAllContacts() + }).catch((error) =>{ + alert("Uri: " + removedContact + " was not removed " + error) + }); + } + else{ + axios(configApiCall(api_path_delete_auth_contacts+"?uri="+removedContact.replace("jami://", ""), 'DELETE', null, null)).then((response)=>{ + setOpen(false); + getAllContacts() + }).catch((error) =>{ + alert("Uri: " + removedContact + " was not removed " + error) + }); + } } const handleRemoveContact = (uri) => { @@ -146,7 +179,7 @@ export default function Users(props) { return( <div> - <TemporaryDrawer openDrawer={openDrawer} setOpenDrawer={setOpenDrawer} getAllContacts={getAllContacts} direction="right"/> + <TemporaryDrawer isAdmin={auth.hasAdminScope()} username={props.username} openDrawer={openDrawer} setOpenDrawer={setOpenDrawer} getAllContacts={getAllContacts} direction="right"/> <Dialog open={open} onClose={() => setOpen(false)} @@ -199,23 +232,22 @@ export default function Users(props) { else if((data.uri != null ) && data.uri.toLowerCase().includes(searchValue.toLowerCase())){ return data } - }).map(user => - <GridItem xs={12} sm={12} md={2} key={user.username} style={{display: user.display}}> + }).map(contact => + <GridItem xs={12} sm={12} md={2} key={contact.uri} style={{display: contact.display}}> <Card profile> <CardBody profile> <CardAvatar profile> - <img src={user.profilePicture ? ('data:image/png;base64, ' + user.profilePicture) : noProfilePicture} alt="..." /> + <img src={contact.profilePicture ? ('data:image/png;base64, ' + contact.profilePicture) : noProfilePicture} alt="..." /> </CardAvatar> - <h4 className={classes.cardTitle}>{user.firstName} {user.lastName}</h4> + <h4 className={classes.cardTitle}>{contact.displayName}</h4> <ul> - <li><img src={jami} width="20" alt="Jami" style={{marginRight: "10px"}} /> {user.username ? user.username : 'No username'}</li> - <li><BusinessOutlinedIcon fontSize='small' style={{marginRight: "10px"}} /> {user.organization ? user.organization : 'No organization'}</li> - {/* <li><img src={jami} width="20" alt="Jami" style={{marginRight: "10px"}} /> {user.uri}</li> */} + <li><img src={jami} width="20" alt="Jami" style={{marginRight: "10px"}} /> {contact.displayName ? contact.displayName : 'No name'}</li> + <li><img src={jami} width="20" alt="Jami" style={{marginRight: "10px"}} /><span style={{maxWidth: "100%"}}> {contact.uri}</span></li> </ul> </CardBody> <CardFooter> - <IconButton color="secondary" onClick={ () => {handleRemoveContact(user.uri)}}><DeleteOutlineIcon /></IconButton> + <IconButton color="secondary" onClick={ () => {handleRemoveContact(contact.uri)}}><DeleteOutlineIcon /></IconButton> </CardFooter> </Card> </GridItem> diff --git a/jams-server/src/main/java/net/jami/jams/server/servlets/api/admin/contacts/ContactServlet.java b/jams-server/src/main/java/net/jami/jams/server/servlets/api/admin/contacts/ContactServlet.java index 57738bca9ddab80d7ea4a48dbf8803788e8dd253..3d01f8203c2dff9333bed9821ba216fa977cde48 100644 --- a/jams-server/src/main/java/net/jami/jams/server/servlets/api/admin/contacts/ContactServlet.java +++ b/jams-server/src/main/java/net/jami/jams/server/servlets/api/admin/contacts/ContactServlet.java @@ -36,11 +36,13 @@ import net.jami.jams.common.objects.contacts.Contact; import net.jami.jams.common.objects.user.AccessLevel; import net.jami.jams.common.serialization.tomcat.TomcatCustomErrorHandler; import net.jami.jams.common.utils.ContactMerger; +import org.json.JSONObject; import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; import java.util.List; +import java.util.Scanner; import static net.jami.jams.server.Server.dataStore; @@ -94,11 +96,16 @@ public class ContactServlet extends HttpServlet { @Override @ScopedServletMethod(securityGroups = {AccessLevel.ADMIN}) protected void doPut(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { - Contact contact = JsonIterator.deserialize(req.getInputStream().readAllBytes(),Contact.class); + Scanner s = new Scanner(req.getInputStream()).useDelimiter("\\A"); + String res = s.hasNext() ? s.next() : ""; + final JSONObject obj = new JSONObject(res); + Contact contact = new Contact(); //TODO: Replace with mergetool. + contact.setDisplayName(obj.get("displayName").toString()); contact.setTimestamp(System.currentTimeMillis()); contact.setStatus('A'); - contact.setOwner(req.getAttribute("username").toString()); + contact.setOwner(req.getParameter("username")); + contact.setUri(obj.get("uri").toString()); StatementList statementList = new StatementList(); statementList.addStatement(new StatementElement("owner","=",req.getParameter("username").toString(),"")); List<Contact> localList = dataStore.getContactDao().getObjects(statementList); @@ -126,14 +133,14 @@ public class ContactServlet extends HttpServlet { StatementList statementList = new StatementList(); statementList.addStatement(new StatementElement("owner","=",req.getParameter("username").toString(),"AND")); statementList.addStatement(new StatementElement("uri","=",req.getParameter("uri"),"")); - List<Contact> remoteList = dataStore.getContactDao().getObjects(statementList); + /*List<Contact> remoteList = dataStore.getContactDao().getObjects(statementList); remoteList.get(0).setStatus('D'); remoteList.get(0).setTimestamp(System.currentTimeMillis()); statementList = new StatementList(); - statementList.addStatement(new StatementElement("owner","=",req.getParameter("username").toString(),"AND")); + statementList.addStatement(new StatementElement("owner","=",req.getParameter("username").toString(),"")); List<Contact> localList = dataStore.getContactDao().getObjects(statementList); - List<Contact> result = ContactMerger.mergeContacts(localList,remoteList); - if(dataStore.getContactDao().storeContactList(result)) resp.setStatus(200); + List<Contact> result = ContactMerger.mergeContacts(localList,remoteList);*/ + if(dataStore.getContactDao().deleteObject(statementList)) resp.setStatus(200); else TomcatCustomErrorHandler.sendCustomError(resp,500,"could not delete a contact due to server-side error"); } diff --git a/jams-server/src/main/java/net/jami/jams/server/servlets/api/auth/contacts/ContactServlet.java b/jams-server/src/main/java/net/jami/jams/server/servlets/api/auth/contacts/ContactServlet.java index 72a2a760c2151f1bf432ce2036cd3625687d3aaa..71be58cab28f88f92cee23e994574f656f1792f2 100644 --- a/jams-server/src/main/java/net/jami/jams/server/servlets/api/auth/contacts/ContactServlet.java +++ b/jams-server/src/main/java/net/jami/jams/server/servlets/api/auth/contacts/ContactServlet.java @@ -34,11 +34,13 @@ import net.jami.jams.common.dao.StatementList; import net.jami.jams.common.objects.contacts.Contact; import net.jami.jams.common.serialization.tomcat.TomcatCustomErrorHandler; import net.jami.jams.common.utils.ContactMerger; +import org.json.JSONObject; import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; import java.util.List; +import java.util.Scanner; import static net.jami.jams.server.Server.dataStore; @@ -90,11 +92,16 @@ public class ContactServlet extends HttpServlet { */ @Override protected void doPut(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { - Contact contact = JsonIterator.deserialize(req.getInputStream().readAllBytes(),Contact.class); + Scanner s = new Scanner(req.getInputStream()).useDelimiter("\\A"); + String res = s.hasNext() ? s.next() : ""; + final JSONObject obj = new JSONObject(res); + Contact contact = new Contact(); //TODO: Replace with mergetool. + contact.setDisplayName(obj.get("displayName").toString()); contact.setTimestamp(System.currentTimeMillis()); contact.setStatus('A'); contact.setOwner(req.getAttribute("username").toString()); + contact.setUri(obj.get("uri").toString()); StatementList statementList = new StatementList(); statementList.addStatement(new StatementElement("owner","=",req.getAttribute("username").toString(),"")); List<Contact> localList = dataStore.getContactDao().getObjects(statementList); @@ -121,14 +128,14 @@ public class ContactServlet extends HttpServlet { StatementList statementList = new StatementList(); statementList.addStatement(new StatementElement("owner","=",req.getAttribute("username").toString(),"AND")); statementList.addStatement(new StatementElement("uri","=",req.getParameter("uri"),"")); - List<Contact> remoteList = dataStore.getContactDao().getObjects(statementList); + /*List<Contact> remoteList = dataStore.getContactDao().getObjects(statementList); remoteList.get(0).setStatus('D'); remoteList.get(0).setTimestamp(System.currentTimeMillis()); statementList = new StatementList(); - statementList.addStatement(new StatementElement("owner","=",req.getAttribute("username").toString(),"AND")); + statementList.addStatement(new StatementElement("owner","=",req.getAttribute("username").toString(),"")); List<Contact> localList = dataStore.getContactDao().getObjects(statementList); - List<Contact> result = ContactMerger.mergeContacts(localList,remoteList); - if(dataStore.getContactDao().storeContactList(result)) resp.setStatus(200); + List<Contact> result = ContactMerger.mergeContacts(localList,remoteList);*/ + if(dataStore.getContactDao().deleteObject(statementList)) resp.setStatus(200); else TomcatCustomErrorHandler.sendCustomError(resp,500,"could not delete a contact due to server-side error"); }