Merge pull request #51 from cheapy-ispp/012-valoraciones

012 valoraciones
This commit is contained in:
MartínAGR 2021-04-03 00:32:43 +02:00 committed by GitHub
commit 71f6301627
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
16 changed files with 464 additions and 38 deletions

View file

@ -37,7 +37,7 @@ public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
.antMatchers("/users/new").permitAll()
.antMatchers("/login/**").anonymous()
.antMatchers("/logout").permitAll()
.antMatchers("/logout").authenticated()
.antMatchers("/usuarios/new").permitAll()
.antMatchers("/admin/**").hasAnyAuthority("admin")
@ -53,11 +53,12 @@ public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
.antMatchers("/offersCreate").hasAuthority("client")
.antMatchers("/reviews/**").authenticated()
.and().formLogin()
.loginPage("/login").permitAll()
.loginPage("/login")
.failureUrl("/login?error")
.and().logout().logoutSuccessUrl("/login");
.and().logout().logoutSuccessUrl("/");
// Configuración para que funcione la consola de administración
// de la BD H2 (deshabilitar las cabeceras de protección contra

View file

@ -0,0 +1,56 @@
package org.springframework.cheapy.model;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.Table;
import javax.validation.constraints.NotBlank;
import org.hibernate.validator.constraints.Range;
import com.sun.istack.NotNull;
@Entity
@Table(name = "review")
public class Review extends BaseEntity{
private static final long serialVersionUID = 1L;
@NotBlank(message = "Debe rellenar la valoración de Cheapy")
@Column(length=16777215)
private String opinion;
@NotNull
@Range(min = 1, max = 5)
private Integer stars;
@ManyToOne
@JoinColumn(name = "username", referencedColumnName = "username")
private User escritor;
public User getEscritor() {
return escritor;
}
public void setEscritor(User escritor) {
this.escritor = escritor;
}
public String getOpinion() {
return opinion;
}
public void setOpinion(String opinion) {
this.opinion = opinion;
}
public Integer getStars() {
return stars;
}
public void setStars(Integer stars) {
this.stars = stars;
}
}

View file

@ -0,0 +1,22 @@
package org.springframework.cheapy.repository;
import java.util.List;
import org.springframework.cheapy.model.Review;
import org.springframework.data.repository.Repository;
import org.springframework.data.repository.query.Param;
import org.springframework.data.jpa.repository.Query;
import org.springframework.transaction.annotation.Transactional;
public interface ReviewRepository extends Repository<Review, Integer> {
@Query("SELECT r FROM Review r")
@Transactional(readOnly = true)
List<Review> findAllReviews();
void save(Review review);
@Query("SELECT r FROM Review r WHERE id =:id")
@Transactional(readOnly = true)
Review findReviewById(@Param("id") Integer id);
}

View file

@ -0,0 +1,15 @@
package org.springframework.cheapy.repository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.CrudRepository;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.cheapy.model.User;
import org.springframework.cheapy.model.Usuario;
public interface UserRepository extends CrudRepository<Usuario, String> {
@Query("SELECT u FROM User u WHERE username =:username")
@Transactional(readOnly = true)
User findByUsername(String username);
}

View file

@ -1,11 +0,0 @@
package org.springframework.cheapy.repository;
import org.springframework.data.repository.CrudRepository;
import org.springframework.cheapy.model.Usuario;
public interface UsuarioRepository extends CrudRepository<Usuario, String> {
//Usuario findByUsername(String currentPrincipalName);
}

View file

@ -0,0 +1,40 @@
package org.springframework.cheapy.service;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cheapy.model.Review;
import org.springframework.cheapy.model.StatusOffer;
import org.springframework.cheapy.model.TimeOffer;
import org.springframework.cheapy.repository.ReviewRepository;
import org.springframework.cheapy.repository.TimeOfferRepository;
import org.springframework.dao.DataAccessException;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@Service
public class ReviewService {
private ReviewRepository reviewRepository;
@Autowired
public ReviewService(final ReviewRepository reviewRepository) {
this.reviewRepository = reviewRepository;
}
@Transactional
public Review findReviewById(final int id) {
return this.reviewRepository.findReviewById(id);
}
@Transactional
public List<Review> findAllReviews() {
return this.reviewRepository.findAllReviews();
}
@Transactional
public void saveReview(final Review Review) throws DataAccessException {
this.reviewRepository.save(Review);
}
}

View file

@ -0,0 +1,29 @@
package org.springframework.cheapy.service;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cheapy.model.User;
import org.springframework.cheapy.repository.UserRepository;
import org.springframework.dao.DataAccessException;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@Service
public class UserService {
private UserRepository userRepository;
@Autowired
public UserService(final UserRepository userRepository) {
this.userRepository = userRepository;
}
@Transactional
public User getCurrentUser() throws DataAccessException {
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
String username = authentication.getName();
return this.userRepository.findByUsername(username);
}
}

View file

@ -0,0 +1,115 @@
package org.springframework.cheapy.web;
import java.util.List;
import java.util.Map;
import javax.validation.Valid;
import org.springframework.cheapy.model.Review;
import org.springframework.cheapy.model.User;
import org.springframework.cheapy.service.ReviewService;
import org.springframework.cheapy.service.UserService;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
@Controller
public class ReviewController {
private static final String VIEWS_REVIEWS_CREATE_OR_UPDATE_FORM = "reviews/createOrUpdateReviewForm";
private final ReviewService reviewService;
private final UserService userService;
public ReviewController(final ReviewService reviewService, final UserService userService) {
this.reviewService = reviewService;
this.userService = userService;
}
private boolean checkIdentity(final int reviewId) {
boolean res = false;
User user = this.userService.getCurrentUser();
Review review = this.reviewService.findReviewById(reviewId);
User reviewsAuthor = review.getEscritor();
if (user.equals(reviewsAuthor)) {
res = true;
}
return res;
}
@GetMapping("/reviews")
public String processFindForm( Map<String, Object> model) {
List<Review> reviewsLs=this.reviewService.findAllReviews();
model.put("reviewsLs", reviewsLs);
return "reviews/reviewsList";
}
@GetMapping("/reviews/new")
public String initCreationForm(Map<String, Object> model) {
Review review = new Review();
model.put("review", review);
return VIEWS_REVIEWS_CREATE_OR_UPDATE_FORM;
}
@PostMapping("/reviews/new")
public String processCreationForm(@Valid Review review, BindingResult result) {
if (result.hasErrors()) {
return VIEWS_REVIEWS_CREATE_OR_UPDATE_FORM;
} else {
User escritor = this.userService.getCurrentUser();
review.setEscritor(escritor);
this.reviewService.saveReview(review);
return "redirect:/reviews/" + review.getId();
}
}
@GetMapping("/reviews/{reviewId}")
public String processShowForm(@PathVariable("reviewId") int reviewId, Map<String, Object> model) {
Review review = this.reviewService.findReviewById(reviewId);
model.put("review", review);
return "reviews/reviewsShow";
}
@GetMapping(value = "/reviews/{reviewId}/edit")
public String updateReview(@PathVariable("reviewId") final int reviewId, final ModelMap model) {
if (!this.checkIdentity(reviewId)) {
return "error";
}
Review review = this.reviewService.findReviewById(reviewId);
model.addAttribute("review", review);
return ReviewController.VIEWS_REVIEWS_CREATE_OR_UPDATE_FORM;
}
@PostMapping(value = "/reviews/{reviewId}/edit")
public String updateReview(@Valid final Review reviewEdit, final BindingResult result, final ModelMap model) {
if (!this.checkIdentity(reviewEdit.getId())) {
return "error";
}
if (result.hasErrors()) {
model.addAttribute("review", reviewEdit);
return ReviewController.VIEWS_REVIEWS_CREATE_OR_UPDATE_FORM;
} else {
User escritor = this.userService.getCurrentUser();
reviewEdit.setEscritor(escritor);
this.reviewService.saveReview(reviewEdit);
return "redirect:/reviews/" + reviewEdit.getId();
}
}
}

View file

@ -16,7 +16,7 @@ spring.jpa.properties.javax.persistence.schema-generation.drop-script-source=dro
# Internationalization
spring.messages.basename=messages/messages
spring.messages.encoding=UTF-8
# Views
spring.mvc.view.prefix: /WEB-INF/jsp/
@ -33,4 +33,4 @@ logging.level.org.springframework=INFO
# logging.level.org.springframework.context.annotation=TRACE
# Maximum time static resources should be cached
spring.resources.cache.cachecontrol.max-age=12h
spring.resources.cache.cachecontrol.max-age=12h

View file

@ -37,8 +37,13 @@ nonNumeric=Solo debe contener números
duplicateFormSubmission=No se permite el envío de formularios duplicados
typeMismatch.date=Fecha inválida
typeMismatch.birthDate=Fecha inválida
createFoodOffers= Crear ofertas por plato espec<65>fico
createNuOffers= Crear ofertas por n<>mero de comensales
review= Reseña
reviews= Reseñas
stars= Estrellas
opinion= Opinión
user = Nombre de usuario
createFoodOffers= Crear ofertas por plato específico
createNuOffers= Crear ofertas por número de comensales
createSpeedOffers= Crear ofertas por rapidez comiendo
createTimeOffers= Crear ofertas por franja horaria
init= Inicio del intervalo

View file

@ -6,7 +6,7 @@
<%@ taglib prefix="cheapy" tagdir="/WEB-INF/tags" %>
<link href='https://fonts.googleapis.com/css?family=Lobster' rel='stylesheet'>
<cheapy:layout pageName="myOffers">
<cheapy:layout pageName="ofertasM">
<h2 style="text-align:center;padding:5px"><fmt:message key="foodOffers"/></h2>
<c:if test="${empty foodOfferLs }">
<p id="vacio" >No hay ninguna oferta por plato específico activa.</p>

View file

@ -0,0 +1,32 @@
<%@ page session="false" trimDirectiveWhitespaces="true" %>
<%@ taglib prefix="spring" uri="http://www.springframework.org/tags" %>
<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %>
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %>
<%@ taglib prefix="cheapy" tagdir="/WEB-INF/tags" %>
<cheapy:layout pageName="reviewsN">
<h2>
<c:if test="${review['new']}">Nueva </c:if> Reseña
</h2>
<form:form modelAttribute="review" class="form-horizontal" id="add-review-form">
<div class="form-group has-feedback">
<form:hidden path="id"/>
<cheapy:textAreaField label="Opinión" name="opinion"/>
<cheapy:inputField label="Estrellas" name="stars"/>
</div>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
<c:choose>
<c:when test="${review['new']}">
<button class="btn btn-default" type="submit">Crear Reseña</button>
</c:when>
<c:otherwise>
<button class="btn btn-default" type="submit">Modificar Reseña</button>
</c:otherwise>
</c:choose>
</div>
</div>
</form:form>
</cheapy:layout>

View file

@ -0,0 +1,59 @@
<%@ page session="false" trimDirectiveWhitespaces="true" %>
<%@ taglib prefix="spring" uri="http://www.springframework.org/tags" %>
<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %>
<%@ taglib prefix="cheapy" tagdir="/WEB-INF/tags" %>
<link href='https://fonts.googleapis.com/css?family=Lobster' rel='stylesheet'>
<cheapy:layout pageName="reviews">
<h2 style="text-align:center;padding:5px"><fmt:message key="reviews"/></h2>
<table id="reviewTable" class="table table-striped">
<thead>
<tr>
<!-- <th style="width: 150px;">Restaurante</th> -->
<th><fmt:message key="user"/></th>
<th><fmt:message key="stars"/></th>
<th><fmt:message key="opinion"/></th>
<th> </th>
</tr>
</thead>
<tbody>
<c:choose>
<c:when test="${fn:length(reviewsLs) == 0}">
<tr><td colspan="4"><em><c:out value="No se ha realizado ninguna valoración por el momento."/></em></td></tr>
</c:when>
<c:otherwise>
<c:forEach items="${reviewsLs}" var="review">
<tr>
<!-- <td> -->
<%-- <c:out value="nombre por definir"/> <!-- ${review.usuario.nombre},${review.usuario.apellidos} --> --%>
<!-- </td> -->
<td>
<c:out value="${review.escritor.username}"/>
</td>
<td>
<c:out value="${review.stars}"/>
</td>
<td>
<c:out value="${review.opinion}"/>
</td>
<td>
<spring:url value="/reviews/{reviewId}" var="reviewUrl">
<spring:param name="reviewId" value="${review.id}"/>
</spring:url>
<div class="btn-detalles">
<button type="button" role="link" onclick="window.location='${fn:escapeXml(reviewUrl)}'" style="font-family: 'Lobster'; font-size: 20px;">
<span class="glyphicon glyphicon-info-sign" aria-hidden="true" style="padding: 5px"> </span>
<fmt:message key="details"/></button>
</div>
</td>
</tr>
</c:forEach>
</c:otherwise>
</c:choose>
</tbody>
</table>
</cheapy:layout>

View file

@ -0,0 +1,38 @@
<%@ page session="false" trimDirectiveWhitespaces="true" %>
<%@ taglib prefix="spring" uri="http://www.springframework.org/tags" %>
<%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ taglib prefix="cheapy" tagdir="/WEB-INF/tags" %>
<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>
<link href='https://fonts.googleapis.com/css?family=Lobster' rel='stylesheet'>
<cheapy:layout pageName="review">
<h2 style="text-align:center;padding:5px"><fmt:message key="review"/></h2>
<table class="table table-striped" id="review-table">
<tr>
<th><fmt:message key="stars"/></th>
<td><c:out value="${review.stars}"/></td>
</tr>
<tr>
<th><fmt:message key="opinion"/></th>
<td><c:out value="${review.opinion}"/></td>
</tr>
</table>
<div class="btn-return">
<button type="button" role="link" onclick="window.location='/reviews'" style="font-family: 'Lobster'; font-size: 20px;">
<span class="glyphicon glyphicon-arrow-left" aria-hidden="true" style="padding: 5px"> </span>
<fmt:message key="return"/> </button>
</div>
<spring:url value="{reviewId}/edit" var="editUrl">
<spring:param name="reviewId" value="${review.id}"/>
</spring:url>
<a href="${fn:escapeXml(editUrl)}" class="btn btn-default">Editar opinión</a>
</cheapy:layout>

View file

@ -34,30 +34,30 @@
</cheapy:menuItem>
<sec:authorize access="hasAnyAuthority('client')">
<cheapy:menuItem active="${name eq 'ofertass'}" url="/myOffers" title="misOfertas">
<span class="glyphicon glyphicon-cutlery" aria-hidden="true"></span>
<span>Mis ofertas</span>
</cheapy:menuItem>
</sec:authorize>
<sec:authorize access="hasAnyAuthority('usuario')">
<cheapy:menuItem active="${name eq 'ofertas'}" url="/myOffers" title="valoranos">
<span class="glyphicon glyphicon-star" aria-hidden="true"></span>
<span>Valóranos</span>
</cheapy:menuItem>
<cheapy:menuItem active="${name eq 'ofertasM'}" url="/myOffers" title="misOfertas">
<span class="glyphicon glyphicon-cutlery" aria-hidden="true"></span>
<span>Mis ofertas</span>
</cheapy:menuItem>
</sec:authorize>
<!--
<cheapy:menuItem active="${name eq 'contactanos'}" url="/contactanos"
title="contactanos">
<span class="glyphicon glyphicon-earphone" aria-hidden="true"></span>
<span>Contáctanos</span>
<span>Cont�ctanos</span>
</cheapy:menuItem>
-->
<sec:authorize access="isAuthenticated()">
<cheapy:menuItem active="${name eq 'reviews'}" url="/reviews" title="opiniones">
<span class="glyphicon glyphicon-list-alt" aria-hidden="true"></span>
<span>Reseñas</span>
</cheapy:menuItem>
<cheapy:menuItem active="${name eq 'reviewsN'}" url="/reviews/new" title="valóranos">
<span class="glyphicon glyphicon-pencil" aria-hidden="true"></span>
<span>Valóranos</span>
</cheapy:menuItem>
</sec:authorize>
</ul>
<ul class="nav navbar-nav navbar-right">
<sec:authorize access="!isAuthenticated()">
<li><a href="<c:url value="/login" />">Iniciar sesión</a></li>
@ -65,7 +65,7 @@
</sec:authorize>
<sec:authorize access="isAuthenticated()">
<li class="dropdown"><a href="#" class="dropdown-toggle"
data-toggle="dropdown"> <span class="glyphicon glyphicon-user"></span> 
data-toggle="dropdown"> <span class="glyphicon glyphicon-user"></span>
<strong><sec:authentication property="name" /></strong> <span
class="glyphicon glyphicon-chevron-down"></span>
</a>
@ -110,8 +110,5 @@
</sec:authorize>
</ul>
</div>
</div>
</nav>

View file

@ -0,0 +1,28 @@
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ taglib prefix="spring" uri="http://www.springframework.org/tags" %>
<%@ attribute name="name" required="true" rtexprvalue="true"
description="Name of corresponding property in bean object" %>
<%@ attribute name="label" required="true" rtexprvalue="true"
description="Label appears in red color if input is considered as invalid after submission" %>
<%@ attribute name="placeholder" required="false" rtexprvalue="true"
description="Example for input field" %>
<spring:bind path="${name}">
<c:set var="cssGroup" value="form-group ${status.error ? 'has-error' : '' }"/>
<c:set var="valid" value="${not status.error and not empty status.actualValue}"/>
<div class="${cssGroup}">
<label class="col-sm-2 control-label">${label}</label>
<div class="col-sm-10">
<form:textarea class="form-control" rows = "5" cols = "30" path="${name}"/>
<c:if test="${valid}">
<span class="glyphicon glyphicon-ok form-control-feedback" aria-hidden="true"></span>
</c:if>
<c:if test="${status.error}">
<span class="glyphicon glyphicon-remove form-control-feedback" aria-hidden="true"></span>
<span class="help-inline">${status.errorMessage}</span>
</c:if>
</div>
</div>
</spring:bind>