package fi.otavanopisto.muikku.rest.user;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.stream.Collectors;
import javax.ejb.Stateful;
import javax.enterprise.context.RequestScoped;
import javax.enterprise.inject.Any;
import javax.enterprise.inject.Instance;
import javax.inject.Inject;
import javax.ws.rs.DefaultValue;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.Response.Status;
import org.apache.commons.lang3.StringUtils;
import fi.otavanopisto.muikku.model.users.UserEntity;
import fi.otavanopisto.muikku.model.users.UserGroupEntity;
import fi.otavanopisto.muikku.rest.AbstractRESTService;
import fi.otavanopisto.muikku.rest.RESTPermitUnimplemented;
import fi.otavanopisto.muikku.schooldata.SchoolDataIdentifier;
import fi.otavanopisto.muikku.schooldata.entity.UserGroup;
import fi.otavanopisto.muikku.search.SearchProvider;
import fi.otavanopisto.muikku.search.SearchResult;
import fi.otavanopisto.muikku.security.MuikkuPermissions;
import fi.otavanopisto.muikku.security.RoleFeatures;
import fi.otavanopisto.muikku.session.SessionController;
import fi.otavanopisto.muikku.users.UserEntityController;
import fi.otavanopisto.muikku.users.UserGroupController;
import fi.otavanopisto.muikku.users.UserGroupEntityController;
@Stateful
@RequestScoped
@Path("/usergroup")
@Produces("application/json")
public class UserGroupRESTService extends AbstractRESTService {
@Inject
private SessionController sessionController;
@Inject
private UserGroupEntityController userGroupEntityController;
@Inject
private UserEntityController userEntityController;
@Inject
private UserGroupController userGroupController;
@Inject
@Any
private Instance<SearchProvider> searchProviders;
@Inject
private Logger logger;
@GET
@Path("/groups")
@RESTPermitUnimplemented
public Response searchUserGroups(
@QueryParam("userIdentifier") String userIdentifier,
@QueryParam("searchString") String searchString,
@QueryParam("firstResult") @DefaultValue("0") Integer firstResult,
@QueryParam("maxResults") @DefaultValue("10") Integer maxResults) {
if (!sessionController.isLoggedIn()) {
return Response.status(Status.FORBIDDEN).build();
}
List<UserGroupEntity> entities = new ArrayList<>();
if (userIdentifier != null) {
SchoolDataIdentifier identifier = SchoolDataIdentifier.fromId(userIdentifier);
if (identifier == null) {
Response.status(Status.BAD_REQUEST).entity("Malformed userIdentifier").build();
}
UserEntity loggedUserEntity = sessionController.getLoggedUserEntity();
UserEntity userEntity = userEntityController.findUserEntityByUserIdentifier(identifier);
if (userEntity == null) {
return Response.status(Status.NOT_FOUND).build();
}
// Check for group-user-only roles - no shared groups, no rights
if (sessionController.hasEnvironmentPermission(RoleFeatures.ACCESS_ONLY_GROUP_STUDENTS) && !userGroupEntityController.haveSharedUserGroups(loggedUserEntity, userEntity)) {
return Response.status(Status.FORBIDDEN).build();
}
if (!(loggedUserEntity.getId().equals(userEntity.getId()) || sessionController.hasEnvironmentPermission(MuikkuPermissions.LIST_USER_USERGROUPS))) {
return Response.status(Status.FORBIDDEN).build();
}
if (identifier != null) {
entities = userGroupEntityController.listUserGroupsByUserIdentifier(identifier);
// For someone with the role feature the group entities are not necessarily accessible
if (sessionController.hasEnvironmentPermission(RoleFeatures.ACCESS_ONLY_GROUP_STUDENTS)) {
List<UserGroupEntity> guiderGroups = userGroupEntityController.listUserGroupsByUserEntity(loggedUserEntity);
Set<Long> guiderGroupIds = guiderGroups.stream().map(UserGroupEntity::getId).collect(Collectors.toSet());
entities = entities.stream().filter((UserGroupEntity uge) -> guiderGroupIds.contains(uge.getId())).collect(Collectors.toList());
}
}
} else {
SearchProvider elasticSearchProvider = getProvider("elastic-search");
if (elasticSearchProvider != null) {
String[] fields = new String[] { "name" };
SearchResult result = null;
if (StringUtils.isBlank(searchString)) {
result = elasticSearchProvider.matchAllSearch(firstResult, maxResults, UserGroup.class);
} else {
result = elasticSearchProvider.search(searchString, fields, firstResult, maxResults, UserGroup.class);
}
List<Map<String, Object>> results = result.getResults();
if (!results.isEmpty()) {
for (Map<String, Object> o : results) {
String[] id = ((String) o.get("id")).split("/", 2);
UserGroupEntity userGroupEntity = userGroupEntityController.findUserGroupEntityByDataSourceAndIdentifier(
id[1], id[0]);
if (userGroupEntity != null) {
entities.add(userGroupEntity);
}
}
}
}
}
if (entities.isEmpty()) {
return Response.noContent().build();
} else {
List<fi.otavanopisto.muikku.rest.model.UserGroup> ret = new ArrayList<fi.otavanopisto.muikku.rest.model.UserGroup>();
for (UserGroupEntity entity : entities) {
Long userCount = userGroupEntityController.getGroupUserCount(entity);
UserGroup group = userGroupController.findUserGroup(entity);
if (group != null)
ret.add(new fi.otavanopisto.muikku.rest.model.UserGroup(entity.getId(), group.getName(), userCount));
else
logger.log(Level.WARNING, "Group not found");
}
return Response.ok(ret).build();
}
}
@GET
@Path("/groups/{ID}")
@RESTPermitUnimplemented
public Response findById(@PathParam("ID") Long groupId) {
if (!sessionController.isLoggedIn()) {
return Response.status(Status.FORBIDDEN).build();
}
UserGroupEntity userGroupEntity = userGroupEntityController.findUserGroupEntityById(groupId);
if (userGroupEntity == null) {
return Response.status(Status.NOT_FOUND).build();
}
UserGroup userGroup = userGroupController.findUserGroup(userGroupEntity);
if (userGroup == null) {
logger.severe("UserGroupEntity without UserGroup");
return Response.status(Status.NOT_FOUND).build();
}
Long userCount = userGroupEntityController.getGroupUserCount(userGroupEntity);
return Response.ok(
new fi.otavanopisto.muikku.rest.model.UserGroup(userGroupEntity.getId(), userGroup.getName(), userCount))
.build();
}
@GET
@Path("/groups/{ID}/users")
public Response listGroupUsersByGroup(@PathParam("ID") Long groupId) {
return null;
}
private SearchProvider getProvider(String name) {
Iterator<SearchProvider> i = searchProviders.iterator();
while (i.hasNext()) {
SearchProvider provider = i.next();
if (name.equals(provider.getName())) {
return provider;
}
}
return null;
}
}