ApiController.java

package edu.ucsb.cs156.frontiers.controllers;

import edu.ucsb.cs156.frontiers.errors.EntityNotFoundException;
import edu.ucsb.cs156.frontiers.errors.NoLinkedOrganizationException;
import edu.ucsb.cs156.frontiers.models.CurrentUser;
import edu.ucsb.cs156.frontiers.services.CurrentUserService;
import java.util.Collection;
import java.util.Map;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.security.access.hierarchicalroles.RoleHierarchy;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseStatus;

/** This is an abstract class that provides common functionality for all API controllers. */
@Slf4j
public abstract class ApiController {
  @Autowired private CurrentUserService currentUserService;

  @Autowired RoleHierarchy roleHierarchy;

  /**
   * This method returns the current user.
   *
   * @return the current user
   */
  protected CurrentUser getCurrentUser() {
    return currentUserService.getCurrentUser();
  }

  /**
   * This method checks if the current user has the given role
   *
   * @return true if the current user has the role, false otherwise
   * @param role the role to check
   */
  protected boolean doesCurrentUserHaveRole(String roleToCheck) {
    CurrentUser currentUser = getCurrentUser();
    Collection<? extends GrantedAuthority> authorities = currentUser.getRoles();

    Collection<? extends GrantedAuthority> extendedAuthorities =
        roleHierarchy.getReachableGrantedAuthorities(authorities);

    return extendedAuthorities.stream().anyMatch(role -> role.getAuthority().equals(roleToCheck));
  }

  /**
   * This method checks if the current user is an admin.
   *
   * @return true if the current user is an admin, false otherwise
   */
  protected boolean isCurrentUserAdmin() {
    return doesCurrentUserHaveRole("ROLE_ADMIN");
  }

  /**
   * This method returns a generic message.
   *
   * @param message the message
   * @return a map with the message
   */
  protected Object genericMessage(String message) {
    return Map.of("message", message);
  }

  /**
   * This method handles the EntityNotFoundException. This maps to a 404/Not Found.
   *
   * @param e the exception
   * @return a map with the type and message of the exception
   */
  @ExceptionHandler({EntityNotFoundException.class})
  @ResponseStatus(HttpStatus.NOT_FOUND)
  public Object handleEntityNotFoundException(Throwable e) {
    return Map.of(
        "type", e.getClass().getSimpleName(),
        "message", e.getMessage());
  }

  /**
   * This method handles the NoLinkedOrganizationException. This maps to a 400/Bad Request.
   *
   * @param e the exception
   * @return a map with the type and message of the exception
   */
  @ExceptionHandler({NoLinkedOrganizationException.class})
  @ResponseStatus(HttpStatus.BAD_REQUEST)
  public Object handleNoLinkedOrgException(Throwable e) {
    return Map.of(
        "type", e.getClass().getSimpleName(),
        "message", e.getMessage());
  }

  /**
   * This method handles the UnsupportedOperationException. This maps to a 403/Forbidden.
   *
   * @param e the exception
   * @return a map with the type and message of the exception
   */
  @ExceptionHandler(UnsupportedOperationException.class)
  public ResponseEntity<Map<String, String>> handleUnsupportedOperation(
      UnsupportedOperationException ex) {
    return ResponseEntity.status(HttpStatus.FORBIDDEN).body(Map.of("message", ex.getMessage()));
  }

  /**
   * This method handles the IllegalArgumentException. This maps to a 400/Bad Request.
   *
   * @param e the exception
   * @return a map with the type and message of the exception
   */
  @ExceptionHandler({IllegalArgumentException.class})
  @ResponseStatus(HttpStatus.BAD_REQUEST)
  public Object handleIllegalArgument(Throwable e) {
    return Map.of(
        "type", e.getClass().getSimpleName(),
        "message", e.getMessage());
  }
}