@RequestMapping("/resendInvitation.shtml")
  public String resendInvitation(ModelMap modelMap, HttpServletRequest request) {
    Person person = (Person) request.getSession().getAttribute(LoginInterceptor.PERSON_SESSION_KEY);
    Invitation invitation = getAllInvitationByRequest(request);
    if (invitation == null) {
      throw new IllegalArgumentException(
          "Cannot find the invitation. Invitations expire after 14 days.");
    }

    Member member = grouperTeamService.findMember(invitation.getTeamId(), person.getId());
    if (member == null) {
      throw new SecurityException("You are not a member of this team");
    }
    Set<Role> roles = member.getRoles();
    if (!(roles.contains(Role.Admin) || roles.contains(Role.Manager))) {
      throw new SecurityException("You have insufficient rights to perform this action.");
    }

    modelMap.addAttribute("invitation", invitation);
    Role[] inviteRoles = {Role.Member, Role.Manager, Role.Admin};
    modelMap.addAttribute("roles", inviteRoles);
    InvitationMessage invitationMessage = invitation.getLatestInvitationMessage();
    if (invitationMessage != null) {
      modelMap.addAttribute("messageText", invitationMessage.getMessage());
    }
    ViewUtil.addViewToModelMap(request, modelMap);
    return "resendinvitation";
  }
  /**
   * RequestMapping to delete an invitation as admin
   *
   * @param request {@link javax.servlet.http.HttpServletRequest}
   * @return redirect to detailteam if everything is okay
   * @throws UnsupportedEncodingException in the rare condition utf-8 is not supported
   */
  @RequestMapping(value = "/deleteInvitation.shtml")
  public RedirectView deleteInvitation(
      HttpServletRequest request,
      @ModelAttribute(TokenUtil.TOKENCHECK) String sessionToken,
      @RequestParam() String token,
      SessionStatus status,
      ModelMap modelMap)
      throws UnsupportedEncodingException {
    TokenUtil.checkTokens(sessionToken, token, status);
    Person person = (Person) request.getSession().getAttribute(LoginInterceptor.PERSON_SESSION_KEY);
    if (person == null) {
      status.setComplete();
      return new RedirectView("landingpage.shtml");
    }
    Invitation invitation = getAllInvitationByRequest(request);
    String teamId = invitation.getTeamId();
    teamInviteService.delete(invitation);
    AuditLog.log(
        "User {} deleted invitation for email {} for team {} with intended role {}",
        person.getId(),
        invitation.getEmail(),
        invitation.getTeamId(),
        invitation.getIntendedRole());

    status.setComplete();
    modelMap.clear();
    return new RedirectView(
        "detailteam.shtml?team="
            + URLEncoder.encode(teamId, "utf-8")
            + "&view="
            + ViewUtil.getView(request));
  }
  /**
   * RequestMapping to accept an invitation. If everything is okay, it redirects to your new team
   * detail view.
   *
   * @param request {@link HttpServletRequest}
   * @return detail view of your new team
   * @throws UnsupportedEncodingException if the server does not support utf-8
   */
  @RequestMapping(value = "/doAcceptInvitation.shtml")
  public RedirectView doAccept(HttpServletRequest request) throws UnsupportedEncodingException {
    Person person = (Person) request.getSession().getAttribute(LoginInterceptor.PERSON_SESSION_KEY);

    Invitation invitation = getInvitationByRequest(request);
    if (invitation == null) {
      throw new IllegalArgumentException(
          "Cannot find your invitation. Invitations expire after 14 days.");
    }
    if (invitation.isDeclined()) {
      throw new RuntimeException("Invitation is Declined");
    }
    if (invitation.isAccepted()) {
      throw new IllegalStateException("Invitation is already Accepted");
    }
    String teamId = invitation.getTeamId();
    if (!StringUtils.hasText(teamId)) {
      throw new RuntimeException("Invalid invitation");
    }
    controllerUtil.getTeamById(teamId);

    String memberId = person.getId();
    grouperTeamService.addMember(teamId, person);

    Role intendedRole = invitation.getIntendedRole();
    if (isGuest(person) && Role.Admin.equals(intendedRole)) {
      // cannot make a guest Admin
      invitation.setIntendedRole(Role.Manager);
    }
    intendedRole = invitation.getIntendedRole();
    grouperTeamService.addMemberRole(
        teamId, memberId, intendedRole, teamEnvironment.getGrouperPowerUser());
    AuditLog.log(
        "User {} accepted invitation for team {} with intended role {}",
        person.getId(),
        teamId,
        intendedRole);
    invitation.setAccepted(true);
    teamInviteService.saveOrUpdate(invitation);

    return new RedirectView(
        "detailteam.shtml?team="
            + URLEncoder.encode(teamId, "utf-8")
            + "&view="
            + ViewUtil.getView(request));
  }
  /**
   * RequestMapping to decline an invitation as receiver. This URL is bypassed in {@link
   * LoginInterceptor}
   *
   * @param modelMap {@link ModelMap}
   * @param request {@link HttpServletRequest}
   * @return view for decline result
   */
  @RequestMapping(value = "/declineInvitation.shtml")
  public String decline(ModelMap modelMap, HttpServletRequest request) {
    String viewTemplate = "invitationdeclined";

    Person person = (Person) request.getSession().getAttribute(LoginInterceptor.PERSON_SESSION_KEY);

    Invitation invitation = getInvitationByRequest(request);

    if (invitation == null) {
      // even if we can't find the invitation, we'll display success!
      return viewTemplate;
    }

    invitation.setDeclined(true);
    teamInviteService.saveOrUpdate(invitation);
    AuditLog.log(
        "User {} declined invitation for team {} with intended role {}",
        person.getId(),
        invitation.getTeamId(),
        invitation.getIntendedRole());
    ViewUtil.addViewToModelMap(request, modelMap);
    return viewTemplate;
  }