RiderApplicationController.java

package edu.ucsb.cs156.gauchoride.controllers;

import edu.ucsb.cs156.gauchoride.entities.RiderApplication;
import edu.ucsb.cs156.gauchoride.errors.EntityNotFoundException;
import edu.ucsb.cs156.gauchoride.repositories.RiderApplicationRepository;

import io.swagger.v3.oas.annotations.tags.Tag;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.oauth2.jwt.NimbusReactiveJwtDecoder.SecretKeyReactiveJwtDecoderBuilder;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import jakarta.validation.Valid;

import java.sql.Date;
import java.time.LocalDate;
import java.util.ArrayList;
import java.util.List;


@Tag(name = "Rider Application")
@RequestMapping("/api")
@RestController

public class RiderApplicationController extends ApiController {

    @Autowired
    RiderApplicationRepository riderApplicationRepository;
    

    // // Endpoints for ROLE_MEMBER

    //Endpoints for members
    @Operation(summary = "Create a new rider application with the current user as the requester")
    @PreAuthorize("hasRole('ROLE_MEMBER')")
    @PostMapping("/riderApplication/new")
    public RiderApplication postRiderApplication(
        @Parameter(name="perm_number", description="String, Perm number consisting of 7 characters", example = "1234567", required = true) 
        @RequestParam String perm_number,
        @Parameter(name="description", description="String, Please describe the mobility limitations that cause you to need to use the Gauchoride service. ", example = "My legs are broken", required = true) 
        @RequestParam String description
    )
    {
        RiderApplication riderApplication = new RiderApplication();
        // Get the current date
        LocalDate localDate = LocalDate.now();
        Date currentDate = Date.valueOf(localDate);

        riderApplication.setStatus("pending");
        riderApplication.setUserId(getCurrentUser().getUser().getId());
        riderApplication.setPerm_number(perm_number);
        riderApplication.setCreated_date(currentDate);
        riderApplication.setUpdated_date(currentDate);
        riderApplication.setDescription(description);
        riderApplication.setNotes("");
        riderApplication.setEmail(getCurrentUser().getUser().getEmail());

        RiderApplication savedApplication = riderApplicationRepository.save(riderApplication);
        return savedApplication;
    };

    @Operation(summary = "Get all rider requests owned by the current user")
    @PreAuthorize("hasRole('ROLE_MEMBER')")
    @GetMapping("/rider")
    public Iterable<RiderApplication> allApplications()
    {
        Iterable<RiderApplication> applications;
        applications = riderApplicationRepository.findAllByUserId(getCurrentUser().getUser().getId());
        return applications;
    };

    @Operation(summary = "Get a single rider application but only if owned by the current user")
    @PreAuthorize("hasRole('ROLE_MEMBER')")
    @GetMapping("/riderApplication")
    public RiderApplication getById(
                    @Parameter(name="id", description = "Long, Id of the RiderApplication to get", 
                    required = true)  
                    @RequestParam Long id)
    {
        RiderApplication application;
        application = riderApplicationRepository.findByIdAndUserId(id, getCurrentUser().getUser().getId())
                    .orElseThrow(() -> new EntityNotFoundException(RiderApplication.class, id));
        return application;
    };    

    @Operation(summary = "Edit an existing rider application but only if it is owned by the current user and the application is in the correct status")
    @PreAuthorize("hasRole('ROLE_MEMBER')")
    @PutMapping("/riderApplication")
    public ResponseEntity<Object> updateApplication(
                            @Parameter(name="id", description="long, Id of the Application to be edited", 
                            required = true)
                            @RequestParam Long id,
                            @RequestBody @Valid RiderApplication incoming)
    {
        RiderApplication application;

        application = riderApplicationRepository.findByIdAndUserId(id, getCurrentUser().getUser().getId())
                    .orElseThrow(() -> new EntityNotFoundException(RiderApplication.class, id));

        if ("pending".equals(application.getStatus()))
        {
            // Get the current date
            LocalDate localDate = LocalDate.now();
            Date currentDate = Date.valueOf(localDate);

            application.setPerm_number(incoming.getPerm_number());
            application.setUpdated_date(currentDate);
            application.setDescription(incoming.getDescription());
            application.setNotes(incoming.getNotes());
            application.setStatus(incoming.getStatus());
            riderApplicationRepository.save(application);
            return ResponseEntity.ok(application);
        } 
        else if ("accepted".equals(application.getStatus()))
        {
            // Get the current date
            LocalDate localDate = LocalDate.now();
            Date currentDate = Date.valueOf(localDate);

            application.setPerm_number(incoming.getPerm_number());
            application.setUpdated_date(currentDate);
            application.setDescription(incoming.getDescription());
            application.setNotes(incoming.getNotes());
            application.setStatus(incoming.getStatus());
            riderApplicationRepository.save(application);
            return ResponseEntity.ok(application);
        } 
        else
        {
            String errorMessage = "RiderApplication with \"" + application.getStatus() + "\" status cannot be updated";
            return ResponseEntity.badRequest().body(errorMessage);
        }
    }; 

    @Operation(summary = "Cancel an existing rider application but only if it is owned by the current user and the application is in the correct status")
    @PreAuthorize("hasRole('ROLE_MEMBER')")
    @PutMapping("/riderApplication/cancel")
    public Object cancelApplication(
                            @Parameter(name="id", description="long, Id of the Application to be edited", 
                            required = true)
                            @RequestParam Long id)
                            
    {
        RiderApplication application;

        application = riderApplicationRepository.findByIdAndUserId(id, getCurrentUser().getUser().getId())
                    .orElseThrow(() -> new EntityNotFoundException(RiderApplication.class, id));
        
        if ("pending".equals(application.getStatus()))
        {
            // Get the current date
            LocalDate localDate = LocalDate.now();
            Date currentDate = Date.valueOf(localDate);

            application.setStatus("cancelled");
            application.setUpdated_date(currentDate);
            application.setCancelled_date(currentDate);
            riderApplicationRepository.save(application);

            return genericMessage("Application with id %s is cancelled".formatted(id));
        }
        else
        {
            return genericMessage("Application with \"%s\" status cannot be cancelled".formatted(application.getStatus()));
        }
    };


    // // Endpoints for ROLE_ADMIN

    @Operation(summary = "Get all rider applications")
    @PreAuthorize("hasRole('ROLE_ADMIN')")
    @GetMapping("/rider/admin/all")
    public Iterable<RiderApplication> allApplicationsAdmin()
    {
        Iterable<RiderApplication> applications;
        applications = riderApplicationRepository.findAll();
        return applications;
    };

    @Operation(summary = "Get all pending rider applications")
    @PreAuthorize("hasRole('ROLE_ADMIN')")
    @GetMapping("/rider/admin/pending")
    public Iterable<RiderApplication> allPendingApplications()
    {
        Iterable<RiderApplication> pendingApplications;
        pendingApplications = riderApplicationRepository.findAllByStatus("pending");

        return pendingApplications;
    };

    @Operation(summary = "Get a specific rider application")
    @PreAuthorize("hasRole('ROLE_ADMIN')")
    @GetMapping("/rider/admin")
    public RiderApplication specificApplication(
                            @Parameter(name="id", description="long, Id of the Application to find", 
                            required = true)
                            @RequestParam Long id)
    {
        RiderApplication application;
        application = riderApplicationRepository.findById(id)
                .orElseThrow(() -> new EntityNotFoundException(RiderApplication.class, id));
        return application;
    };

    @Operation(summary = "Update the status/notes field of an application")
    @PreAuthorize("hasRole('ROLE_ADMIN')")
    @PutMapping("/rider/admin")
    public RiderApplication updateApplicationAdmin(
                            @Parameter(name="id", description="long, Id of the Application to be updated", 
                            required = true)
                            @RequestParam Long id,

                            @Parameter(name="status", description="String, New Status of the Application", 
                                        required = false)
                            @RequestParam String status,

                            @Parameter(name="notes", description="String, Notes to notify the Applicant", 
                                        required = false)
                            @RequestParam String notes)
    {
        RiderApplication application;
        application = riderApplicationRepository.findById(id)
                .orElseThrow(() -> new EntityNotFoundException(RiderApplication.class, id));

        if (!status.isEmpty())
        {
            application.setStatus(status);
        }

        if (!notes.isEmpty())
        {
            application.setNotes(notes);
        }      
        
        riderApplicationRepository.save(application);
        return application;
    };

}