AnnouncementsController.java
package edu.ucsb.cs156.happiercows.controllers;
import com.fasterxml.jackson.databind.ObjectMapper;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.extern.slf4j.Slf4j;
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.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.web.bind.annotation.*;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;
import org.springframework.format.annotation.DateTimeFormat;
import java.util.Date;
import edu.ucsb.cs156.happiercows.errors.EntityNotFoundException;
import edu.ucsb.cs156.happiercows.entities.Announcement;
import edu.ucsb.cs156.happiercows.entities.Commons;
import edu.ucsb.cs156.happiercows.repositories.AnnouncementRepository;
import edu.ucsb.cs156.happiercows.entities.User;
import edu.ucsb.cs156.happiercows.entities.UserCommons;
import edu.ucsb.cs156.happiercows.models.CreateAnnouncementParams;
import edu.ucsb.cs156.happiercows.models.CreateCommonsParams;
import edu.ucsb.cs156.happiercows.repositories.UserCommonsRepository;
import edu.ucsb.cs156.happiercows.strategies.CowHealthUpdateStrategies;
import org.springframework.security.core.Authentication;
import java.text.SimpleDateFormat;
import java.util.TimeZone;
import java.util.Calendar;
import java.util.Date;
import java.util.Optional;
import javax.validation.Valid;
@Tag(name = "Announcements")
@RequestMapping("/api/announcements")
@RestController
@Slf4j
public class AnnouncementsController extends ApiController{
@Autowired
private AnnouncementRepository announcementRepository;
@Autowired
private UserCommonsRepository userCommonsRepository;
@Autowired
ObjectMapper mapper;
@Operation(summary = "Create an announcement", description = "Create an announcement associated with a specific commons")
@PreAuthorize("hasAnyRole('ROLE_USER', 'ROLE_ADMIN')")
@PostMapping("/post/{commonsId}")
public ResponseEntity<Object> createAnnouncement(
@Parameter(description = "The id of the common") @PathVariable Long commonsId,
@Parameter(description = "The datetime at which the announcement will be shown (defaults to current time)")
@RequestParam(required = false) @DateTimeFormat(pattern = "yyyy-MM-dd")
Date startDate,
@Parameter(description = "The datetime at which the announcement will stop being shown (optional)")
@RequestParam(required = false) @DateTimeFormat(pattern = "yyyy-MM-dd")
Date endDate,
@Parameter(description = "The announcement to be sent out") @RequestParam String announcementText) {
User user = getCurrentUser().getUser();
Long userId = user.getId();
// Make sure the user is part of the commons or is an admin
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
if (!auth.getAuthorities().stream().anyMatch(a -> a.getAuthority().equals("ROLE_ADMIN"))){
log.info("User is not an admin");
Optional<UserCommons> userCommonsLookup = userCommonsRepository.findByCommonsIdAndUserId(commonsId, userId);
if (!userCommonsLookup.isPresent()) {
return ResponseEntity.badRequest().body("Commons_id must exist.");
}
}
// Fix timezone difference for PST
if (startDate != null) {
Calendar calendar = Calendar.getInstance();
calendar.setTime(startDate);
calendar.set(Calendar.HOUR_OF_DAY, 8);
startDate = calendar.getTime();
}
else {
log.info("Start date not specified. Defaulting to current date.");
startDate = new Date();
}
// Fix timezone difference for PST
if (endDate != null) {
Calendar calendar = Calendar.getInstance();
calendar.setTime(endDate);
calendar.set(Calendar.HOUR_OF_DAY, 8);
endDate = calendar.getTime();
}
if (announcementText == "") {
return ResponseEntity.badRequest().body("Announcement cannot be empty.");
}
if (endDate != null && startDate.after(endDate)) {
return ResponseEntity.badRequest().body("Start date must be before end date.");
}
// Create the announcement
Announcement announcementObj = Announcement.builder()
.commonsId(commonsId)
.startDate(startDate)
.endDate(endDate)
.announcementText(announcementText)
.build();
// Save the announcement
announcementRepository.save(announcementObj);
return ResponseEntity.ok(announcementObj);
}
@Operation(summary = "Get all announcements", description = "Get all announcements associated with a specific commons.")
@PreAuthorize("hasAnyRole('ROLE_USER', 'ROLE_ADMIN')")
@GetMapping("/getbycommonsid")
public ResponseEntity<Object> getAnnouncements(@Parameter(description = "The id of the common") @RequestParam Long commonsId) {
// Make sure the user is part of the commons or is an admin
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
if (!auth.getAuthorities().stream().anyMatch(a -> a.getAuthority().equals("ROLE_ADMIN"))){
log.info("User is not an admin");
User user = getCurrentUser().getUser();
Long userId = user.getId();
Optional<UserCommons> userCommonsLookup = userCommonsRepository.findByCommonsIdAndUserId(commonsId, userId);
if (!userCommonsLookup.isPresent()) {
return ResponseEntity.badRequest().body("Commons_id must exist.");
}
}
int MAX_ANNOUNCEMENTS = 1000;
Page<Announcement> announcements = announcementRepository.findByCommonsId(commonsId, PageRequest.of(0, MAX_ANNOUNCEMENTS, Sort.by("startDate").descending()));
return ResponseEntity.ok(announcements);
}
@Operation(summary = "Get announcements by id", description = "Get announcement by its id.")
@PreAuthorize("hasAnyRole('ROLE_USER', 'ROLE_ADMIN')")
@GetMapping("/getbyid")
public ResponseEntity<Object> getAnnouncementById(@Parameter(description = "The id of the announcement") @RequestParam Long id) {
Optional<Announcement> announcementLookup = announcementRepository.findByAnnouncementId(id);
if (!announcementLookup.isPresent()) {
return ResponseEntity.badRequest().body("Cannot find announcement. id is invalid.");
}
return ResponseEntity.ok(announcementLookup.get());
}
@Operation(summary = "Edit an announcement", description = "Edit an announcement by its id.")
@PreAuthorize("hasAnyRole('ROLE_ADMIN')")
@PutMapping("/put")
public ResponseEntity<Object> editAnnouncement(
@Parameter(name="id") @RequestParam long id,
@Parameter(name="request body") @RequestBody CreateAnnouncementParams params) {
Optional<Announcement> existing = announcementRepository.findByAnnouncementId(id);
Announcement updated;
HttpStatus status;
// Error 404: Not found
if (existing.isPresent()) {
updated = existing.get();
status = HttpStatus.OK;
} else {
updated = new Announcement();
throw new EntityNotFoundException(Announcement.class, id);
}
// Default start date is OK...
if (params.getStartDate() == null) {
log.info("Start date not specified. Defaulting to current date.");
updated.setStartDate(new Date());
}
else {
updated.setStartDate(params.getStartDate());
}
// ...But a start date after an end date is not OK.
// This error only occurs if the user provides an end date.
// Otherwise, the end date is NULL and the start date could be any date.
if(params.getEndDate() != null) {
if (updated.getStartDate().after(params.getEndDate())) {
throw new IllegalArgumentException("The start date may not be after the end date.");
}
else {
updated.setEndDate(params.getEndDate());
}
}
// The provided announcement text must not be empty or missing.
if (params.getAnnouncementText() == null || params.getAnnouncementText().equals("")) {
throw new IllegalArgumentException("Announcement Text cannot be empty.");
}
else {
updated.setAnnouncementText(params.getAnnouncementText());
}
announcementRepository.save(updated);
return ResponseEntity.ok(updated);
}
@Operation(summary = "Delete an announcement", description = "Delete an announcement associated with an id")
@PreAuthorize("hasAnyRole('ROLE_ADMIN')")
@DeleteMapping("/delete")
public ResponseEntity<Object> deleteAnnouncement(@Parameter(description = "The id of the chat message") @RequestParam Long id) {
// Try to get the chat message
Optional<Announcement> announcementLookup = announcementRepository.findByAnnouncementId(id);
if (!announcementLookup.isPresent()) {
return ResponseEntity.badRequest().body("Cannot find announcement. id is invalid.");
}
Announcement announcementObj = announcementLookup.get();
User user = getCurrentUser().getUser();
Long userId = user.getId();
// Hide the message
announcementRepository.delete(announcementObj);
return ResponseEntity.ok(announcementObj);
}
}