ClubDelLibroController.java
package it.unisa.c07.biblionet.clubDelLibro.controller;
import java.io.IOException;
import java.time.LocalDateTime;
import java.util.*;
import java.util.function.Consumer;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PathVariable;
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.SessionAttributes;
import org.springframework.web.server.ResponseStatusException;
import it.unisa.c07.biblionet.clubDelLibro.service.ClubDelLibroService;
import it.unisa.c07.biblionet.gestioneEventi.service.GestioneEventiService;
import it.unisa.c07.biblionet.model.entity.ClubDelLibro;
import it.unisa.c07.biblionet.model.entity.Evento;
import it.unisa.c07.biblionet.model.entity.Genere;
import it.unisa.c07.biblionet.model.entity.utente.Esperto;
import it.unisa.c07.biblionet.model.entity.utente.Lettore;
import it.unisa.c07.biblionet.model.entity.utente.UtenteRegistrato;
import it.unisa.c07.biblionet.model.form.ClubForm;
import it.unisa.c07.biblionet.model.form.EventoForm;
import it.unisa.c07.biblionet.utils.validazione.ValidazioneEvento;
import lombok.RequiredArgsConstructor;
/**
* Implementa il controller per il sottosistema
* ClubDelLibro.
* @author Viviana Pentangelo
* @author Gianmario Voria
* @author Nicola Pagliara
* @author Luca Topo
*/
@Controller
@RequiredArgsConstructor
@RequestMapping("/club-del-libro")
@SessionAttributes("loggedUser")
public class ClubDelLibroController {
/**
* Il service per effettuare le operazioni di persistenza.
*/
private final ClubDelLibroService clubService;
/**
* Il service per effettuare le operazioni di persistenza
* degli eventi.
*/
private final GestioneEventiService eventiService;
/**
* Metodo di utilità che modifica o crea un evento, validando
* i dati.
* @param eventoForm Il form con i dati da modificare
* @param view La view da restituire se l'operazione va a buon fine.
* @param idClub L'id del club del libro in cui inserire l'evento.
* @param idEvento L'id dell'evento, che può essere vuoto per ottenere
* l'autoassegnazione.
* @param operazione L'operazione, tra creazione e modifica, che si vuole
* effettuare.
* @return La view inserita.
*/
private String modificaCreaEvento(final EventoForm eventoForm,
final String view,
final int idClub,
final Optional<Integer> idEvento,
final Consumer<Evento> operazione) {
var club = this.clubService.getClubByID(idClub);
if (club == null) {
throw new ResponseStatusException(
HttpStatus.BAD_REQUEST,
"Club del Libro Inesistente"
);
}
var evento = new Evento();
if (idEvento.isPresent()) {
evento.setIdEvento(idEvento.get());
}
evento.setClub(club);
if (!ValidazioneEvento.isNomeValido(eventoForm.getNome())) {
throw new ResponseStatusException(
HttpStatus.BAD_REQUEST,
"Lunghezza del nome non valida."
);
}
evento.setNomeEvento(eventoForm.getNome());
if (!ValidazioneEvento.
isDescrizioneValida(eventoForm.getDescrizione())) {
throw new ResponseStatusException(
HttpStatus.BAD_REQUEST,
"Lunghezza della descrizione non valida."
);
}
evento.setDescrizione(eventoForm.getDescrizione());
var dataOra =
LocalDateTime.of(eventoForm.getData(), eventoForm.getOra());
if (dataOra.isBefore(LocalDateTime.now())) {
throw new ResponseStatusException(
HttpStatus.BAD_REQUEST,
"Data non valida."
);
}
evento.setDataOra(dataOra);
if (eventoForm.getLibro() != null) {
var libro =
this.eventiService.getLibroById(eventoForm.getLibro());
if (libro.isEmpty()) {
throw new ResponseStatusException(
HttpStatus.BAD_REQUEST,
"Il libro inserito non è valido."
);
}
evento.setLibro(libro.get());
}
operazione.accept(evento);
return view;
}
/**
* Implementa la funzionalità che permette
* di visualizzare i Club del Libro
* presenti nel Database.
* @param model L'oggetto model usato per inserire gli attributi
* @param generi Un Optional che contiene una lista di generi per cui
* filtrare
* @param citta Un Optional che contiene una lista di possibili città
* @return La pagina di visualizzazione
*/
@RequestMapping(value = "", method = RequestMethod.GET)
public String visualizzaListaClubs(@RequestParam(value = "generi")
final Optional<List<String>>
generi,
@RequestParam(value = "citta")
final Optional<List<String>>
citta,
final Model model) {
// Molto più pulito della concatenazione con gli stream
Predicate<ClubDelLibro> filtroGenere = x -> true;
if (generi.isPresent()) {
filtroGenere = x -> false;
var generiDaDB =
clubService.getGeneri(generi.get());
for (Genere genere: generiDaDB) {
filtroGenere = filtroGenere.or(
c -> c.getGeneri().contains(genere)
);
}
}
Predicate<ClubDelLibro> filtroCitta = x -> true;
if (citta.isPresent()) {
filtroCitta = x -> false;
for (String cittaSingola: citta.get()) {
filtroCitta = filtroCitta.or(
c -> clubService.getCittaFromClubDelLibro(c)
.equals(cittaSingola)
);
}
}
List<ClubDelLibro> listaClubs = clubService.visualizzaClubsDelLibro(
filtroCitta.and(filtroGenere)
);
// Necessito di un oggetto anonimo per evitare problemi con JS
model.addAttribute("listaClubs", listaClubs.stream().map(
club -> new Object() {
public final String nome = club.getNome();
public final String descrizione =
club.getDescrizione();
public final String nomeEsperto = club.getEsperto()
.getNome()
+ " "
+ club.getEsperto()
.getCognome();
public final String immagineCopertina =
club.getImmagineCopertina();
public final Set<String> generi =
club.getGeneri()
.stream()
.map(Genere::getNome)
.collect(Collectors.toSet());
public final int idClub = club.getIdClub();
public final int iscritti = club.getLettori().size();
public final String email =
club.getEsperto().getEmail();
}
).collect(Collectors.toList()));
model.addAttribute("generi", this.clubService.getTuttiGeneri());
model.addAttribute("citta", this.clubService.getCitta());
return "club-del-libro/visualizza-clubs";
}
/**
* Implementa la funzionalità di visualizzare la pagina di creazione di
* un club del libro.
* @param model L'oggetto model usato per inserire gli attributi
* @param club Il form in cui inserire i dati del club
* @return La pagina del Club
*/
@RequestMapping(value = "crea", method = RequestMethod.GET)
public String visualizzaCreaClubDelLibro(final Model model,
final @ModelAttribute
ClubForm club) {
var utente = (UtenteRegistrato) model.getAttribute("loggedUser");
if (utente == null || !utente.getTipo().equals("Esperto")) {
throw new ResponseStatusException(HttpStatus.UNAUTHORIZED);
}
model.addAttribute("generi", this.clubService.getTuttiGeneri());
model.addAttribute("club", club);
return "club-del-libro/creazione-club";
}
/**
* Implementa la funzionalità di creazione di un club del libro.
* @param model L'oggetto model usato per inserire gli attributi
* @param club Il club che si vuole creare
* @return la pagina del Club
*/
@RequestMapping(value = "/crea", method = RequestMethod.POST)
public String creaClubDelLibro(final Model model,
final @ModelAttribute ClubForm club) {
UtenteRegistrato utente =
(UtenteRegistrato) model.getAttribute("loggedUser");
if (utente == null || !utente.getTipo().equals("Esperto")) {
throw new ResponseStatusException(HttpStatus.UNAUTHORIZED);
}
var esperto = (Esperto) utente;
ClubDelLibro cdl = new ClubDelLibro();
cdl.setNome(club.getNome());
cdl.setDescrizione(club.getDescrizione());
cdl.setEsperto(esperto);
if (club.getCopertina() != null && !club.getCopertina().isEmpty()) {
try {
byte[] imageBytes = club.getCopertina().getBytes();
String base64Image =
Base64.getEncoder().encodeToString(imageBytes);
cdl.setImmagineCopertina(base64Image);
} catch (IOException e) {
e.printStackTrace();
}
}
cdl.setGeneri(Arrays.asList(new Genere[] {}));
if (club.getGeneri() != null) {
cdl.setGeneri(
this.clubService.getGeneri(
club.getGeneri()
)
);
}
this.clubService.creaClubDelLibro(cdl);
return "redirect:/club-del-libro/";
}
/**
* Implementa la funzionalità che permette
* di re-indirizzare alla pagina di modifica
* dei dati di un Club del Libro.
* @param id l'ID del Club da modificare
* @param club Il club che si vuole creare
* @param model l'oggetto model usato per inserire gli attributi
* @return La view che visualizza il form di modifica dati
*/
@RequestMapping(value = "/{id}/modifica", method = RequestMethod.GET)
public String visualizzaModificaDatiClub(final @PathVariable int id,
final @ModelAttribute
ClubForm club,
final Model model) {
var esperto = (UtenteRegistrato) model.getAttribute("loggedUser");
var cdl = this.clubService.getClubByID(id);
if (cdl == null) {
throw new ResponseStatusException(HttpStatus.NOT_FOUND);
}
if (esperto == null
|| !cdl.getEsperto().getEmail().equals(esperto.getEmail())) {
throw new ResponseStatusException(HttpStatus.UNAUTHORIZED);
}
club.setNome(cdl.getNome());
club.setDescrizione(cdl.getDescrizione());
club.setGeneri(cdl.getGeneri().stream().map(Genere::getNome).
collect(Collectors.toList()));
model.addAttribute("club", club);
model.addAttribute("id", id);
model.addAttribute("generi", this.clubService.getTuttiGeneri());
return "club-del-libro/modifica-club";
}
/**
* Implementa la funzionalità per la modifica dei dati di un Club.
* @param id Lo Id del Club
* @param club Il form dove inserire i nuovi dati
* @return La schermata del club
*/
@RequestMapping(value = "/{id}/modifica",
method = RequestMethod.POST)
public String modificaDatiClub(final @PathVariable int id,
final @ModelAttribute ClubForm club) {
ClubDelLibro clubPers = this.clubService.getClubByID(id);
if (!club.getCopertina().isEmpty()) {
try {
byte[] imageBytes = club.getCopertina().getBytes();
String base64Image = Base64.getEncoder()
.encodeToString(imageBytes);
clubPers.setImmagineCopertina(base64Image);
} catch (IOException e) {
e.printStackTrace();
}
}
if (club.getGeneri() != null) {
List<Genere> gList = clubService.getGeneri(club.getGeneri());
clubPers.setGeneri(gList);
}
clubPers.setNome(club.getNome());
clubPers.setDescrizione(club.getDescrizione());
this.clubService.modificaDatiClub(clubPers);
return "redirect:/club-del-libro/";
}
/**
* Implementa la funzionalità che permette
* l'iscrizione di un lettore ad un
* Club del Libro.
* @param id l'ID del Club a cui iscriversi
* @param model Il model da passare alla view
* @return La view che visualizza la lista dei club
*/
@RequestMapping(value = "/{id}/iscrizione", method = RequestMethod.POST)
public String partecipaClub(final @PathVariable int id,
final Model model) {
UtenteRegistrato lettore =
(UtenteRegistrato) model.getAttribute("loggedUser");
if (lettore == null || !lettore.getTipo().equals("Lettore")) {
throw new ResponseStatusException(HttpStatus.UNAUTHORIZED);
}
ClubDelLibro clubDelLibro = this.clubService.getClubByID(id);
if (clubDelLibro.getLettori().contains(lettore)) {
throw new ResponseStatusException(HttpStatus.NOT_ACCEPTABLE);
}
this.clubService.partecipaClub(
clubDelLibro,
(Lettore) lettore);
return "redirect:/club-del-libro/";
}
/**
* Implementa la funzionalità che permette
* la visualizzazione della modifica dei dati di
* un evento di un Club del Libro.
* @param idClub l'ID del Club
* @param idEvento l'ID dell'evento
* @param evento il form dell'evento
* @param model Il model da passare alla view
* @return La view che visualizza la lista dei club
*/
@RequestMapping(
value = "/{idClub}/eventi/{idEvento}/modifica",
method = RequestMethod.GET
)
public String visualizzaModificaEvento(final @PathVariable int idClub,
final @PathVariable int idEvento,
final @ModelAttribute
EventoForm evento,
final Model model) {
var eventoBaseOpt =
this.eventiService.getEventoById(idEvento);
var esperto = (UtenteRegistrato) model.getAttribute("loggedUser");
if (eventoBaseOpt.isEmpty()) {
throw new ResponseStatusException(
HttpStatus.NOT_FOUND,
"Evento Inesistente"
);
}
if (esperto != null && !eventoBaseOpt.get().getClub().getEsperto()
.getEmail().equals(esperto.getEmail())) {
throw new ResponseStatusException(HttpStatus.UNAUTHORIZED);
}
var eventoBase = eventoBaseOpt.get();
if (eventoBase.getClub().getIdClub() != idClub) {
throw new ResponseStatusException(
HttpStatus.BAD_REQUEST,
"L'evento con id " + idEvento
+ "non è associato al club con id "
+ idClub + "."
);
}
evento.setNome(eventoBase.getNomeEvento());
evento.setData(eventoBase.getDataOra().toLocalDate());
evento.setOra(eventoBase.getDataOra().toLocalTime());
evento.setDescrizione(eventoBase.getDescrizione());
if (eventoBase.getLibro() != null) {
evento.setLibro(eventoBase.getLibro().getIdLibro());
}
model.addAttribute("evento", evento);
model.addAttribute("club", eventoBase.getClub());
model.addAttribute("id", eventoBase.getIdEvento());
return "club-del-libro/modifica-evento";
}
/**
* Implementa la funzionalità che permette
* di gestire la chiamata POST
* per creare un evento un club del libro.
* @param id l'id dell'evento
* @param eventoForm il form dell'evento
* @return la view della lista degli eventi
*/
@RequestMapping(value = "/{id}/eventi/crea", method = RequestMethod.POST)
public String creaEvento(final @PathVariable int id,
final @ModelAttribute EventoForm eventoForm) {
return this.modificaCreaEvento(
eventoForm,
"redirect:/club-del-libro/" + id,
id,
Optional.empty(),
this.eventiService::creaEvento
);
}
/**
* Implementa la funzionalità che permette la modifica di un evento.
* @param idClub l'ID del club
* @param idEvento l'ID dell'evento
* @param eventoForm il form dell'evento
* @return la view che visualizza la lista degli eventi
*/
@RequestMapping(value = "/{idClub}/eventi/{idEvento}/modifica",
method = RequestMethod.POST)
public String modificaEvento(final @PathVariable int idClub,
final @PathVariable int idEvento,
final @ModelAttribute EventoForm eventoForm) {
return this.modificaCreaEvento(
eventoForm,
"redirect:/club-del-libro/" + idClub,
idClub,
Optional.of(idEvento),
evento -> {
var statusModifica =
this.eventiService.modificaEvento(evento);
if (statusModifica.isEmpty()) {
throw new ResponseStatusException(
HttpStatus.BAD_REQUEST,
"L'evento con id " + idEvento
+ "non è associato al club con id "
+ idClub + "."
);
}
}
);
}
/**
* Implementa la funzionalità che permette
* la creazione da parte di un Esperto
* di un Evento.
* @param id l'ID dell'evento
* @param evento il form dell'evento
* @param model il model da passare alla view
* @return La view che visualizza il form di creazione Evento
*/
@RequestMapping(value = "/{id}/eventi/crea", method = RequestMethod.GET)
public String visualizzaCreaEvento(final @PathVariable int id,
final @ModelAttribute EventoForm evento,
final Model model) {
var club = this.clubService.getClubByID(id);
if (club == null) {
throw new ResponseStatusException(
HttpStatus.NOT_FOUND,
"Club del Libro Inesistente"
);
}
model.addAttribute("club", club);
model.addAttribute("evento", evento);
return "club-del-libro/aggiungi-evento";
}
/**
* Implementa la funzionalità che permette di gestire
* la visualizzazione dei dati di un Club del Libro.
* @param id l'ID del Club di cui visualizzare i dati
* @param model il model per il passaggio dei dati
* @return La view che visualizza i dati
*/
@RequestMapping(value = "/{id}",
method = RequestMethod.GET)
public String visualizzaDatiClub(final @PathVariable int id,
final Model model) {
model.addAttribute("club", clubService.getClubByID(id));
return "club-del-libro/visualizza-singolo-club";
}
/**
* Implementa la funzionalità che permette di eliminare
* un evento.
* @param club L'identificativo del Club dell'evento
* @param id L'identificativo dell'evento da eliminare
* @return La view della lista degli eventi
*/
@RequestMapping(value = "/{club}/eventi/{id}",
method = RequestMethod.GET)
public String eliminaEvento(final @PathVariable int club,
final @PathVariable int id) {
Optional<Evento> eventoEliminato =
this.eventiService.eliminaEvento(id);
System.out.println(eventoEliminato);
if (eventoEliminato.isEmpty()) {
throw new ResponseStatusException(
HttpStatus.NOT_FOUND,
"Evento Inesistente"
);
}
return "redirect:/club-del-libro/" + club;
}
/**
* Implementa la funzionalità che permette di visualizzare
* la lista degli iscritti a un club.
* @param id L'identificativo del club
* @param model il model la passare alla view
* @return La view della lista degli iscritti
*/
@RequestMapping(value = "/{id}/iscritti",
method = RequestMethod.GET)
public String visualizzaIscrittiClub(final @PathVariable int id,
final Model model) {
model.addAttribute("club", clubService.getClubByID(id));
return "club-del-libro/visualizza-iscritti";
}
/**
* Implementa la funzionalità che permette di visualizzare
* la lista degli eventi di un club.
* @param id l'ID del club
* @param model il mdoel da passare alla view
* @return la view che visualizza gli eventi
*/
@RequestMapping(value = "/{id}/eventi",
method = RequestMethod.GET)
public String visualizzaListaEventiClub(final @PathVariable int id,
final Model model) {
if (clubService.getClubByID(id) == null) {
throw new ResponseStatusException(HttpStatus.NOT_FOUND);
}
UtenteRegistrato utente =
(UtenteRegistrato) model.getAttribute("loggedUser");
if (utente == null || !utente.getTipo().equals("Lettore")) {
throw new ResponseStatusException(HttpStatus.UNAUTHORIZED);
}
Lettore l = (Lettore) utente;
List<Evento> tutti = clubService.getClubByID(id).getEventi();
List<Evento> mieiEventi = l.getEventi();
List<Evento> mieiEventiClub = new ArrayList<>();
for (Evento e : mieiEventi) {
if (e.getClub().getIdClub() == id) {
mieiEventiClub.add(e);
}
}
for (Evento e : mieiEventiClub) {
if (tutti.contains(e)) {
tutti.remove(e);
}
}
model.addAttribute("club", clubService.getClubByID(id));
model.addAttribute("eventi", tutti);
model.addAttribute("mieiEventi", mieiEventiClub);
return "club-del-libro/visualizza-eventi";
}
/**
* Implementa la funzionalità che permette di iscriversi
* ad uno degli eventi presenti nella lista relativa ad
* un Club del Libro.
* @param idEvento l'evento a cui partecipare
* @param idClub il club dell'evento
* @param model l'oggetto Model da cui ottenere il lettore autenticato
* @return la view che visualizza la lista degli eventi
*/
@RequestMapping(value = "/{idClub}/eventi/{idEvento}/iscrizione",
method = RequestMethod.GET)
public String partecipaEvento(final @PathVariable int idEvento,
final @PathVariable int idClub,
final Model model) {
UtenteRegistrato utente =
(UtenteRegistrato) model.getAttribute("loggedUser");
if (utente == null || !utente.getTipo().equals("Lettore")) {
throw new ResponseStatusException(HttpStatus.UNAUTHORIZED);
}
model.addAttribute("loggedUser",
eventiService.partecipaEvento(utente.getEmail(), idEvento));
return "redirect:/club-del-libro/" + idClub + "/eventi";
}
/**
* Implementa la funzionalità che permette di disiscriversi
* ad uno degli eventi presenti nella lista relativa ad
* un Club del Libro a cui ci si era precedentemente iscritti.
* @param idEvento l'evento a cui disiscriversi
* @param idClub il club dell'evento
* @param model l'oggetto Model da cui ottenere il lettore autenticato
* @return la view che visualizza la lista degli eventi
*/
@RequestMapping(value = "/{idClub}/eventi/{idEvento}/abbandono",
method = RequestMethod.GET)
public String abbandonaEvento(final @PathVariable int idEvento,
final @PathVariable int idClub,
final Model model) {
UtenteRegistrato utente =
(UtenteRegistrato) model.getAttribute("loggedUser");
if (utente == null || !utente.getTipo().equals("Lettore")) {
throw new ResponseStatusException(HttpStatus.UNAUTHORIZED);
}
model.addAttribute("loggedUser",
eventiService.abbandonaEvento(utente.getEmail(), idEvento));
return "redirect:/club-del-libro/" + idClub + "/eventi";
}
}