package fr.ippon.tatami.web.rest;
import com.yammer.metrics.annotation.Timed;
import fr.ippon.tatami.domain.Group;
import fr.ippon.tatami.domain.User;
import fr.ippon.tatami.security.AuthenticationService;
import fr.ippon.tatami.service.GroupService;
import fr.ippon.tatami.service.SuggestionService;
import fr.ippon.tatami.service.TimelineService;
import fr.ippon.tatami.service.UserService;
import fr.ippon.tatami.service.dto.StatusDTO;
import fr.ippon.tatami.service.dto.UserGroupDTO;
import fr.ippon.tatami.service.util.DomainUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
import javax.inject.Inject;
import javax.servlet.http.HttpServletResponse;
import java.util.ArrayList;
import java.util.Collection;
/**
* REST controller for managing groups.
*
* @author Julien Dubois
*/
@Controller
public class GroupController {
private final Logger log = LoggerFactory.getLogger(GroupController.class);
@Inject
private TimelineService timelineService;
@Inject
private GroupService groupService;
@Inject
private AuthenticationService authenticationService;
@Inject
private UserService userService;
@Inject
private SuggestionService suggestionService;
/**
* Get groups of the current user.
*/
@RequestMapping(value = "/rest/groups",
method = RequestMethod.GET,
produces = "application/json")
@ResponseBody
@Timed
public Collection<Group> getGroups() {
User currentUser = authenticationService.getCurrentUser();
return groupService.getGroupsForUser(currentUser);
}
/**
* GET /group/:groupId -> returns the group with the requested id
*/
@RequestMapping(value = "/rest/groups/{groupId}",
method = RequestMethod.GET,
produces = "application/json")
@ResponseBody
@Timed
public Group getGroup(@PathVariable("groupId") String groupId) {
User currentUser = authenticationService.getCurrentUser();
String domain = DomainUtil.getDomainFromLogin(currentUser.getLogin());
Group publicGroup = groupService.getGroupById(domain, groupId);
if (publicGroup != null && publicGroup.isPublicGroup()) {
Group result = getGroupFromUser(currentUser, groupId);
Group groupClone = (Group) publicGroup.clone();
if (result != null) {
groupClone.setMember(true);
}
if (isGroupManagedByCurrentUser(publicGroup)) {
groupClone.setAdministrator(true);
}
return groupClone;
} else {
Group result = getGroupFromUser(currentUser, groupId);
Group groupClone = null;
if (result == null) {
log.info("Permission denied! User {} tried to access group ID = {} ", currentUser.getLogin(), groupId);
return null;
} else {
groupClone = (Group) result.clone();
groupClone.setMember(true);
if (isGroupManagedByCurrentUser(publicGroup)) {
groupClone.setAdministrator(true);
}
}
return groupClone;
}
}
/**
* PUT /group/:groupId -> update the group with the requested id
*/
@RequestMapping(value = "/rest/groups/{groupId}",
method = RequestMethod.PUT,
produces = "application/json")
@ResponseBody
@Timed
public Group updateGroup(@PathVariable("groupId") String groupId, @RequestBody Group groupEdit, HttpServletResponse response) {
Group group = getGroup(groupId);
if (group != null) {
if (!isGroupManagedByCurrentUser(group)) {
response.setStatus(HttpServletResponse.SC_FORBIDDEN);
return null;
} else {
group.setDomain(authenticationService.getCurrentUser().getDomain());
group.setName(groupEdit.getName());
group.setDescription(groupEdit.getDescription());
group.setArchivedGroup(groupEdit.isArchivedGroup());
groupService.editGroup(group);
return group;
}
} else {
response.setStatus(HttpServletResponse.SC_NOT_FOUND);
return null;
}
}
@RequestMapping(value = "/rest/groups/{groupId}/timeline",
method = RequestMethod.GET,
produces = "application/json")
@ResponseBody
@Timed
public Collection<StatusDTO> listStatusForGroup(@PathVariable(value = "groupId") String groupId,
@RequestParam(required = false) Integer count,
@RequestParam(required = false) String start,
@RequestParam(required = false) String finish) {
log.debug("REST request to get statuses for group : {}", groupId);
if (groupId == null) {
return new ArrayList<StatusDTO>();
}
if (count == null) {
count = 20;
}
Group group = this.getGroup(groupId);
if (group == null) {
return new ArrayList<StatusDTO>();
} else {
return timelineService.getGroupline(groupId, count, start, finish);
}
}
/**
* GET /groupmemberships/lookup -> return extended data about the user's groups
*/
@RequestMapping(value = "/rest/groupmemberships/lookup",
method = RequestMethod.GET,
produces = "application/json")
@ResponseBody
@Timed
public Collection<Group> getUserGroups(@RequestParam("screen_name") String username) {
User user = userService.getUserByUsername(username);
if (user == null) {
log.debug("Trying to find group for non-existing username = {}", username);
return new ArrayList<Group>();
}
return groupService.getGroupsForUser(user);
}
/**
* Get groups where the current user is admin.
*/
@RequestMapping(value = "/rest/admin/groups",
method = RequestMethod.GET,
produces = "application/json")
@ResponseBody
@Timed
public Collection<Group> getAdminGroups() {
return groupService.getGroupsWhereCurrentUserIsAdmin();
}
/**
* POST create new group.
*/
@RequestMapping(value = "/rest/groups",
method = RequestMethod.POST,
produces = "application/json")
@ResponseBody
@Timed
public Group createGroup(HttpServletResponse response, @RequestBody Group group) {
if (group.getName() != null && !group.getName().equals("")) {
groupService.createGroup(group.getName(), group.getDescription(), group.isPublicGroup());
} else {
response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
}
return group;
}
/**
* GET /groupmemberships/suggestions -> suggest groups to join
*/
@RequestMapping(value = "/rest/groupmemberships/suggestions",
method = RequestMethod.GET,
produces = "application/json")
@ResponseBody
@Timed
public Collection<Group> suggestions() {
String login = authenticationService.getCurrentUser().getLogin();
return groupService.buildGroupList(suggestionService.suggestGroups(login));
}
/**
* GET /groups/{groupId}/members/ -> members of the group
*/
@RequestMapping(value = "/rest/groups/{groupId}/members/",
method = RequestMethod.GET,
produces = "application/json")
@ResponseBody
@Timed
public Collection<UserGroupDTO> getGroupsUsers(HttpServletResponse response, @PathVariable("groupId") String groupId) {
User currentUser = authenticationService.getCurrentUser();
Group currentGroup = groupService.getGroupById(currentUser.getDomain(), groupId);
Collection<UserGroupDTO> users = null;
if (currentUser == null) {
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED); // Authentication required
} else if (currentGroup == null) {
response.setStatus(HttpServletResponse.SC_NOT_FOUND); // Resource not found
} else {
users = groupService.getMembersForGroup(groupId, currentUser.getLogin());
}
return users;
}
/**
* GET /groups/{groupId}/members/{userUsername} -> get a member to group status
*/
@RequestMapping(value = "/rest/groups/{groupId}/members/{username}",
method = RequestMethod.GET,
produces = "application/json")
@ResponseBody
@Timed
public UserGroupDTO getUserToGroup(HttpServletResponse response, @PathVariable("groupId") String groupId, @PathVariable("username") String username) {
User currentUser = authenticationService.getCurrentUser();
Group currentGroup = groupService.getGroupById(currentUser.getDomain(), groupId);
Collection<UserGroupDTO> users = null;
if (currentUser == null) {
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED); // Authentication required
} else if (currentGroup == null) {
response.setStatus(HttpServletResponse.SC_NOT_FOUND); // Resource not found
} else {
users = groupService.getMembersForGroup(groupId, currentUser.getLogin());
}
for (UserGroupDTO user : users) {
if (user.getLogin().equals(currentUser.getLogin())) {
return user;
}
}
UserGroupDTO currentUserDTO = new UserGroupDTO();
currentUserDTO.setLogin(currentUser.getLogin());
currentUserDTO.setUsername(currentUser.getUsername());
currentUserDTO.setAvatar(currentUser.getAvatar());
currentUserDTO.setFirstName(currentUser.getFirstName());
currentUserDTO.setLastName(currentUser.getLastName());
currentUserDTO.setIsMember(false);
return currentUserDTO;
}
/**
* PUT /groups/{groupId}/members/{userUsername} -> add a member to group
*/
@RequestMapping(value = "/rest/groups/{groupId}/members/{username}",
method = RequestMethod.PUT,
produces = "application/json")
@ResponseBody
@Timed
public UserGroupDTO addUserToGroup(HttpServletResponse response, @PathVariable("groupId") String groupId, @PathVariable("username") String username) {
User currentUser = authenticationService.getCurrentUser();
Group currentGroup = groupService.getGroupById(currentUser.getDomain(), groupId);
User userToAdd = userService.getUserByUsername(username);
UserGroupDTO dto = null;
if (currentUser == null) {
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED); // Authentication required
} else if (currentGroup == null || userToAdd == null) {
response.setStatus(HttpServletResponse.SC_NOT_FOUND); // Resource not found
} else if (isChangeUserGroupForbidden(currentGroup, currentUser, userToAdd)) {
response.setStatus(HttpServletResponse.SC_FORBIDDEN);
} else {
groupService.addMemberToGroup(userToAdd, currentGroup);
dto = groupService.getMembersForGroup(groupId, userToAdd);
}
return dto;
}
/**
* DELETE /groups/{groupId}/members/{userUsername} -> remove a member to group
*/
@RequestMapping(value = "/rest/groups/{groupId}/members/{username}",
method = RequestMethod.DELETE,
produces = "application/json")
@ResponseBody
@Timed
public boolean removeUserFromGroup(HttpServletResponse response, @PathVariable("groupId") String groupId, @PathVariable("username") String username) {
User currentUser = authenticationService.getCurrentUser();
Group currentGroup = groupService.getGroupById(currentUser.getDomain(), groupId);
User userToremove = userService.getUserByUsername(username);
if (currentUser == null) {
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED); // Authentication required
return false;
} else if (currentGroup == null || userToremove == null) {
response.setStatus(HttpServletResponse.SC_NOT_FOUND); // Resource not found
return false;
} else if (isChangeUserGroupForbidden(currentGroup, currentUser, userToremove)) {
response.setStatus(HttpServletResponse.SC_FORBIDDEN);
return false;
}
groupService.removeMemberFromGroup(userToremove, currentGroup);
groupService.getMembersForGroup(groupId, userToremove);
return true;
}
/**
* Tells if the current user cannot change userToChange status for current group.
* @param currentGroup Current group.
* @param currentUser Current user.
* @param userToChange User to add or remove.
* @return {@code true} if the change is forbidden.
*/
private boolean isChangeUserGroupForbidden(Group currentGroup, User currentUser, User userToChange) {
return isGroupManagedByCurrentUser(currentGroup) ? currentUser.equals(userToChange) :
!currentGroup.isPublicGroup() || !currentUser.equals(userToChange);
}
private boolean isGroupManagedByCurrentUser(Group group) {
Collection<Group> groups = groupService.getGroupsWhereCurrentUserIsAdmin();
boolean isGroupManagedByCurrentUser = false;
for (Group testGroup : groups) {
if (testGroup.getGroupId().equals(group.getGroupId())) {
isGroupManagedByCurrentUser = true;
break;
}
}
return isGroupManagedByCurrentUser;
}
private Group getGroupFromUser(User currentUser, String groupId) {
Collection<Group> groups = groupService.getGroupsForUser(currentUser);
for (Group testGroup : groups) {
if (testGroup.getGroupId().equals(groupId)) {
return testGroup;
}
}
return null;
}
}