edu.pitt.dbmi.ccd.anno.group.GroupController.java Source code

Java tutorial

Introduction

Here is the source code for edu.pitt.dbmi.ccd.anno.group.GroupController.java

Source

/*
 * Copyright (C) 2015 University of Pittsburgh.
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
 * MA 02110-1301  USA
 */
package edu.pitt.dbmi.ccd.anno.group;

import edu.pitt.dbmi.ccd.anno.error.ForbiddenException;
import edu.pitt.dbmi.ccd.anno.error.GroupNotFoundException;
import edu.pitt.dbmi.ccd.anno.error.NotAMemberException;
import edu.pitt.dbmi.ccd.anno.error.NotFoundException;
import edu.pitt.dbmi.ccd.anno.error.UserNotFoundException;
import edu.pitt.dbmi.ccd.anno.user.UserPagedResourcesAssembler;
import edu.pitt.dbmi.ccd.anno.user.UserResource;
import edu.pitt.dbmi.ccd.anno.user.UserResourceAssembler;
import static edu.pitt.dbmi.ccd.anno.util.ControllerUtils.formatParam;
import edu.pitt.dbmi.ccd.db.entity.Group;
import edu.pitt.dbmi.ccd.db.entity.UserAccount;
import edu.pitt.dbmi.ccd.db.service.GroupService;
import edu.pitt.dbmi.ccd.db.service.UserAccountService;
import edu.pitt.dbmi.ccd.security.userDetails.UserAccountDetails;
import java.util.HashSet;
import java.util.Set;
import java.util.stream.Stream;
import javax.servlet.http.HttpServletRequest;
import javax.validation.ConstraintViolationException;
import javax.validation.Valid;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.web.PageableDefault;
import org.springframework.hateoas.ExposesResourceFor;
import org.springframework.hateoas.PagedResources;
import org.springframework.hateoas.Resources;
import org.springframework.http.HttpStatus;
import org.springframework.security.core.annotation.AuthenticationPrincipal;
import static org.springframework.util.StringUtils.isEmpty;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestController;

/**
 * Controller for Group endpoints
 *
 * @author Mark Silvis (marksilvis@pitt.edu)
 */
@RestController
@ExposesResourceFor(GroupResource.class)
@RequestMapping(value = GroupLinks.INDEX)
public class GroupController {

    // loggers
    private static final Logger LOGGER = LoggerFactory.getLogger(GroupController.class);

    // servlet
    private final HttpServletRequest request;

    // services and components
    private final GroupLinks groupLinks;
    private final GroupService groupService;
    private final UserAccountService userService;
    private final GroupResourceAssembler assembler;
    private final GroupPagedResourcesAssembler pageAssembler;
    private final UserResourceAssembler userAssembler;
    private final UserPagedResourcesAssembler userPageAssembler;

    @Autowired
    public GroupController(HttpServletRequest request, GroupLinks groupLinks, GroupService groupService,
            UserAccountService userService, GroupResourceAssembler assembler,
            GroupPagedResourcesAssembler pageAssembler, UserResourceAssembler userAssembler,
            UserPagedResourcesAssembler userPageAssembler) {
        this.request = request;
        this.groupLinks = groupLinks;
        this.groupService = groupService;
        this.userService = userService;
        this.assembler = assembler;
        this.pageAssembler = pageAssembler;
        this.userAssembler = userAssembler;
        this.userPageAssembler = userPageAssembler;
    }

    /* GET requests */
    /**
     * Get all groups
     *
     * @param pageable page request
     * @return page of groups
     */
    // @CrossOrigin
    @RequestMapping(method = RequestMethod.GET)
    @ResponseStatus(HttpStatus.OK)
    @ResponseBody
    public PagedResources<GroupResource> groups(@PageableDefault(size = 20, sort = { "name" }) Pageable pageable) {
        final Page<Group> page = groupService.findAll(pageable);
        final PagedResources<GroupResource> pagedResources = pageAssembler.toResource(page, assembler, request);
        pagedResources.add(groupLinks.search());
        return pagedResources;
    }

    /**
     * Get single group
     *
     * @param id group id
     * @return group
     */
    @RequestMapping(value = GroupLinks.GROUP, method = RequestMethod.GET)
    @ResponseStatus(HttpStatus.OK)
    @ResponseBody
    public GroupResource group(@PathVariable Long id) throws NotFoundException {
        final Group group = groupService.findById(id);
        if (group == null) {
            throw new GroupNotFoundException(id);
        }
        final GroupResource resource = assembler.toResource(group);
        return resource;
    }

    /**
     * Get group mods
     *
     * @param id group id
     * @return mods
     */
    @RequestMapping(value = GroupLinks.MODS, method = RequestMethod.GET)
    @ResponseStatus(HttpStatus.OK)
    @ResponseBody
    public PagedResources<UserResource> mods(@AuthenticationPrincipal UserAccountDetails principal,
            @PathVariable Long id, @PageableDefault(size = 20, sort = { "username" }) Pageable pageable)
            throws NotFoundException {
        final UserAccount requester = principal.getUserAccount();
        final Group group = groupService.findById(id);
        if (group == null) {
            throw new GroupNotFoundException(id);
        }
        if (Stream.concat(group.getMembers().stream(), group.getModerators().stream()).map(UserAccount::getId)
                .anyMatch(u -> u.equals(requester.getId()))) {
            final Page<UserAccount> page = userService.findByGroupModeration(group, pageable);
            final PagedResources<UserResource> pagedResources = userPageAssembler.toResource(page, userAssembler,
                    request);
            return pagedResources;
        } else {
            throw new ForbiddenException(requester, request);
        }
    }

    /**
     * Get group members
     *
     * @param id group id
     * @return members
     */
    @RequestMapping(value = GroupLinks.MEMBERS, method = RequestMethod.GET)
    @ResponseStatus(HttpStatus.OK)
    @ResponseBody
    public PagedResources<UserResource> members(@AuthenticationPrincipal UserAccountDetails principal,
            @PathVariable Long id, @PageableDefault(size = 20, sort = { "username" }) Pageable pageable)
            throws NotFoundException {
        final UserAccount requester = principal.getUserAccount();
        final Group group = groupService.findById(id);
        if (group == null) {
            throw new GroupNotFoundException(id);
        }
        if (Stream.concat(group.getMembers().stream(), group.getModerators().stream()).map(UserAccount::getId)
                .anyMatch(u -> u.equals(requester.getId()))) {
            final Page<UserAccount> page = userService.findByGroupMembership(group, pageable);
            final PagedResources<UserResource> pagedResources = userPageAssembler.toResource(page, userAssembler,
                    request);
            return pagedResources;
        } else {
            throw new ForbiddenException(requester, request);
        }
    }

    /**
     * Get group requests
     *
     * @param id group id
     * @return requesters
     */
    @RequestMapping(value = GroupLinks.REQUESTS, method = RequestMethod.GET)
    @ResponseStatus(HttpStatus.OK)
    @ResponseBody
    public Resources<UserResource> requests(@AuthenticationPrincipal UserAccountDetails principal,
            @PathVariable Long id, @PageableDefault(size = 20, sort = { "username" }) Pageable pageable)
            throws NotFoundException {
        final UserAccount requester = principal.getUserAccount();
        final Group group = groupService.findById(id);
        if (group == null) {
            throw new GroupNotFoundException(id);
        }
        if (group.getModerators().stream().map(UserAccount::getId).anyMatch(u -> u.equals(requester.getId()))) {
            final Page<UserAccount> page = userService.findByGroupRequests(group, pageable);
            final PagedResources<UserResource> pagedResources = userPageAssembler.toResource(page, userAssembler,
                    request);
            return pagedResources;
        } else {
            throw new ForbiddenException(requester, request);
        }
    }

    /**
     * Search for groups
     *
     * @param query search terms (nullable)
     * @param not negated search terms (nullable)
     * @param pageable page request
     * @return page of groups matching parameters
     */
    @RequestMapping(value = GroupLinks.SEARCH, method = RequestMethod.GET)
    @ResponseStatus(HttpStatus.OK)
    @ResponseBody
    public PagedResources<GroupResource> search(@RequestParam(value = "query", required = false) String query,
            @RequestParam(value = "not", required = false) String not, Pageable pageable) {
        final Set<String> matches = (query != null) ? new HashSet<>(formatParam(query)) : null;
        final Set<String> nots = (not != null) ? new HashSet<>(formatParam(not)) : null;
        final Page<Group> page = groupService.search(matches, nots, pageable);
        final PagedResources<GroupResource> pagedResources = pageAssembler.toResource(page, assembler, request);
        return pagedResources;
    }

    /* POST requests */
    /**
     * Create new group with name and description Creator is added to list of
     * administrators
     *
     * @param principal requester
     * @param form group data
     * @return new group resource
     */
    @RequestMapping(method = RequestMethod.POST)
    @ResponseStatus(HttpStatus.CREATED)
    @ResponseBody
    public GroupResource create(@AuthenticationPrincipal UserAccountDetails principal,
            @RequestBody @Valid GroupForm form) throws DuplicateKeyException {
        final UserAccount requester = principal.getUserAccount();
        final String name = form.getName();
        final String description = form.getDescription();

        // throw exception if non-unique name
        if (groupService.findByName(name) != null) {
            throw new DuplicateKeyException("Group already exists with name: " + name);
        }
        Group group = new Group(name, description);
        group.addMember(requester);
        group.addModerator(requester);
        group = groupService.save(group);
        GroupResource resource = assembler.toResource(group);
        return resource;
    }

    @RequestMapping(value = GroupLinks.REQUESTS, method = RequestMethod.POST)
    @ResponseStatus(HttpStatus.NO_CONTENT)
    @ResponseBody
    public void requestResponse(@AuthenticationPrincipal UserAccountDetails principal, @PathVariable String name,
            @RequestParam(value = "accept", required = false) String accept,
            @RequestParam(value = "deny", required = false) String deny,
            @RequestParam(value = "mod", required = false) Boolean mod) throws NotFoundException {
        final UserAccount requester = principal.getUserAccount();
        final Group group = groupService.findByName(name);
        if (group == null) {
            throw new GroupNotFoundException(name);
        }
        if (group.getModerators().stream().map(UserAccount::getId).anyMatch(u -> u.equals(requester.getId()))) {
            if (!isEmpty(accept)) {
                final UserAccount user = userService.findByUsername(accept);
                if (user == null) {
                    throw new UserNotFoundException(accept);
                }
                if (group.hasRequester(user)) {
                    group.removeRequester(user);
                    group.addMember(user);
                    if (mod != null && mod) {
                        group.addModerator(user);
                    }
                    groupService.save(group);
                }
            }

            if (!isEmpty(deny)) {
                final UserAccount user = userService.findByUsername(accept);
                if (user == null) {
                    throw new UserNotFoundException(accept);
                }
                if (group.hasRequester(user)) {
                    group.removeRequester(user);
                    groupService.save(group);
                }
            }
        } else {
            throw new ForbiddenException(requester, request);
        }
    }

    @RequestMapping(value = GroupLinks.JOIN, method = RequestMethod.POST)
    @ResponseStatus(HttpStatus.NO_CONTENT)
    @ResponseBody
    public void join(@AuthenticationPrincipal UserAccountDetails principal, @PathVariable String name)
            throws NotFoundException {
        final UserAccount requester = principal.getUserAccount();
        final Group group = groupService.findByName(name);
        if (group == null) {
            throw new GroupNotFoundException(name);
        }
        if (Stream.concat(group.getModerators().stream(), group.getMembers().stream()).map(UserAccount::getId)
                .noneMatch(u -> u.equals(requester.getId()))) {
            group.addRequester(requester);
            groupService.save(group);
        }
    }

    @RequestMapping(value = GroupLinks.LEAVE, method = RequestMethod.POST)
    @ResponseStatus(HttpStatus.NO_CONTENT)
    @ResponseBody
    public void leave(@AuthenticationPrincipal UserAccountDetails principal, @PathVariable String name)
            throws NotFoundException {
        UserAccount requester = principal.getUserAccount();
        final Group group = groupService.findByName(name);
        if (group == null) {
            throw new GroupNotFoundException(name);
        } // remove if moderator
        group.getModerators().stream().filter(u -> u.getId().equals(requester.getId())).findFirst()
                .ifPresent(u -> group.removeModerator(u));

        // remove if member
        group.getMembers().stream().filter(u -> u.getId().equals(requester.getId())).findFirst()
                .ifPresent(u -> group.removeMember(u));

        // remove if requester
        group.getRequesters().stream().filter(u -> u.getId().equals(requester.getId())).findFirst()
                .ifPresent(u -> group.removeRequester(u));

        groupService.save(group);
    }

    @RequestMapping(value = GroupLinks.MODS, method = RequestMethod.POST)
    @ResponseStatus(HttpStatus.OK)
    @ResponseBody
    public void makeMod(@AuthenticationPrincipal UserAccountDetails principal, @PathVariable String name,
            @RequestParam(value = "user", required = true) String user) throws NotFoundException {
        UserAccount requester = principal.getUserAccount();
        final Group group = groupService.findByName(name);
        if (group == null) {
            throw new GroupNotFoundException(name);
        }
        if (group.getModerators().stream().map(UserAccount::getId).anyMatch(u -> u.equals(requester.getId()))) {
            final UserAccount mod = userService.findByUsername(user);
            if (user == null) {
                throw new UserNotFoundException(user);
            }
            if (group.hasMember(mod)) {
                group.addModerator(mod);
                groupService.save(group);
            } else {
                throw new NotAMemberException(group, mod);
            }
        } else {
            throw new ForbiddenException(requester, request);
        }
    }

    /* PUT requests */
    //
    //    /**
    //     * Alias for newGroup with HTTP method PUT
    //     * @param  principal requester
    //     * @param  form      group data
    //     * @return           new group resource
    //     */
    //    @RequestMapping(method=RequestMethod.PUT)
    //    @ResponseStatus(HttpStatus.CREATED)
    //    @ResponseBody
    //    public GroupResource newGroupPUT(@AuthenticationPrincipal UserAccount principal, @RequestBody @Valid GroupForm form) {
    //        return create(principal, form);
    //    }
    /**
     * Edit group
     *
     * @param name group name
     * @return group
     */
    @RequestMapping(value = GroupLinks.GROUP, method = RequestMethod.PUT)
    @ResponseStatus(HttpStatus.OK)
    @ResponseBody
    public GroupResource editGroup(@AuthenticationPrincipal UserAccountDetails principal, @PathVariable String name,
            @RequestBody @Valid GroupForm form)
            throws NotFoundException, DuplicateKeyException, ForbiddenException, ConstraintViolationException {
        UserAccount requester = principal.getUserAccount();
        final Group group = groupService.findByName(name);
        if (group == null) {
            throw new GroupNotFoundException(name);
        }
        if (group.getModerators().stream().map(UserAccount::getId).anyMatch(u -> u.equals(requester.getId()))) {
            final String newName = form.getName();
            final String newDescription = form.getDescription();
            if (!group.getName().equalsIgnoreCase(newName)) {
                if (groupService.findByName(newName) != null) {
                    throw new DuplicateKeyException("Group already exists with name: " + newName);
                }
            }
            group.setName(newName);
            if (!group.getDescription().equalsIgnoreCase(newDescription)) {
                group.setDescription(newDescription);
            }
            final Group updated = groupService.save(group);
            final GroupResource resource = assembler.toResource(updated);
            return resource;
        } else {
            throw new ForbiddenException(requester, request);
        }
    }
    //
    //    @RequestMapping(value=GroupLinks.MODS, method=RequestMethod.PUT)
    //    @ResponseStatus(HttpStatus.OK)
    //    @ResponseBody
    //    public void makeModPUT(@AuthenticationPrincipal UserAccount principal, @PathVariable String name, @RequestParam(value="user", required=true) String user) {
    //        makeMod(principal, name, user);
    //    }

    /* PATCH requests */
    /**
     * Patch group
     *
     * @param principal [description]
     * @param name [description]
     * @param form [description]
     * @return [description]
     */
    @RequestMapping(value = GroupLinks.GROUP, method = RequestMethod.PATCH)
    @ResponseStatus(HttpStatus.OK)
    @ResponseBody
    public GroupResource patchGroup(@AuthenticationPrincipal UserAccountDetails principal,
            @PathVariable String name, @RequestBody GroupForm form)
            throws NotFoundException, DuplicateKeyException, ConstraintViolationException {
        UserAccount requester = principal.getUserAccount();
        final Group group = groupService.findByName(name);
        if (group == null) {
            throw new GroupNotFoundException(name);
        }
        if (group.getModerators().stream().map(UserAccount::getId).anyMatch(u -> u.equals(requester.getId()))) {
            final String newName = form.getName();
            final String newDescription = form.getDescription();
            if (!isEmpty(newName) && !group.getName().equalsIgnoreCase(newName)) {
                if (groupService.findByName(newName) != null) {
                    throw new DuplicateKeyException("Group already exists with name: " + newName);
                }
                group.setName(newName);
            }
            if (!isEmpty(newDescription) && !group.getDescription().equalsIgnoreCase(newDescription)) {
                group.setDescription(newDescription);
            }
            final Group patched = groupService.save(group);
            final GroupResource resource = assembler.toResource(patched);
            return resource;
        } else {
            throw new ForbiddenException(requester, request);
        }
    }
}