This repository has been archived by the owner on Dec 4, 2024. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #5 from 7SOATSquad30/feature/product
feat: add product resource
- Loading branch information
Showing
10 changed files
with
366 additions
and
1 deletion.
There are no files selected for viewing
28 changes: 28 additions & 0 deletions
28
src/main/java/br/com/fiap/grupo30/fastfood/dto/ProductDTO.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
package br.com.fiap.grupo30.fastfood.dto; | ||
|
||
import br.com.fiap.grupo30.fastfood.entities.Product; | ||
import lombok.AllArgsConstructor; | ||
import lombok.Data; | ||
import lombok.NoArgsConstructor; | ||
|
||
@Data | ||
@NoArgsConstructor | ||
@AllArgsConstructor | ||
public class ProductDTO { | ||
|
||
private Long id; | ||
private String name; | ||
private String description; | ||
private Double price; | ||
private String imgUrl; | ||
private CategoryDTO category; | ||
|
||
public ProductDTO(Product entity) { | ||
id = entity.getId(); | ||
name = entity.getName(); | ||
description = entity.getDescription(); | ||
price = entity.getPrice(); | ||
imgUrl = entity.getImgUrl(); | ||
category = new CategoryDTO(entity.getCategory()); | ||
} | ||
} |
79 changes: 79 additions & 0 deletions
79
src/main/java/br/com/fiap/grupo30/fastfood/entities/Product.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,79 @@ | ||
package br.com.fiap.grupo30.fastfood.entities; | ||
|
||
import jakarta.persistence.*; | ||
import java.time.Instant; | ||
import lombok.EqualsAndHashCode; | ||
import lombok.Getter; | ||
import lombok.NoArgsConstructor; | ||
|
||
@Getter | ||
@NoArgsConstructor | ||
@EqualsAndHashCode | ||
@Entity | ||
@Table(name = "product") | ||
public class Product { | ||
|
||
@Id | ||
@GeneratedValue(strategy = GenerationType.IDENTITY) | ||
private Long id; | ||
|
||
private String name; | ||
|
||
@Column(columnDefinition = "TEXT") | ||
private String description; | ||
|
||
private Double price; | ||
private String imgUrl; | ||
|
||
@ManyToOne | ||
@JoinColumn(name = "category_id") | ||
private Category category; | ||
|
||
@Column(columnDefinition = "TIMESTAMP WITHOUT TIME ZONE") | ||
private Instant createdAt; | ||
|
||
@Column(columnDefinition = "TIMESTAMP WITHOUT TIME ZONE") | ||
private Instant updatedAt; | ||
|
||
@Column(columnDefinition = "TIMESTAMP WITHOUT TIME ZONE") | ||
private Instant deletedAt; | ||
|
||
public void setId(Long id) { | ||
this.id = id; | ||
} | ||
|
||
public void setName(String name) { | ||
this.name = name; | ||
} | ||
|
||
public void setDescription(String description) { | ||
this.description = description; | ||
} | ||
|
||
public void setPrice(Double price) { | ||
this.price = price; | ||
} | ||
|
||
public void setImgUrl(String imgUrl) { | ||
this.imgUrl = imgUrl; | ||
} | ||
|
||
public void setCategory(Category category) { | ||
this.category = category; | ||
} | ||
|
||
@PrePersist | ||
public void prePersist() { | ||
createdAt = Instant.now(); | ||
} | ||
|
||
@PreUpdate | ||
public void preUpdate() { | ||
updatedAt = Instant.now(); | ||
} | ||
|
||
@PreRemove | ||
public void preRemove() { | ||
deletedAt = Instant.now(); | ||
} | ||
} |
16 changes: 16 additions & 0 deletions
16
src/main/java/br/com/fiap/grupo30/fastfood/repositories/ProductRepository.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
package br.com.fiap.grupo30.fastfood.repositories; | ||
|
||
import br.com.fiap.grupo30.fastfood.entities.Product; | ||
import java.util.List; | ||
import org.springframework.data.jpa.repository.JpaRepository; | ||
import org.springframework.data.jpa.repository.Query; | ||
import org.springframework.stereotype.Repository; | ||
|
||
@Repository | ||
public interface ProductRepository extends JpaRepository<Product, Long> { | ||
|
||
@Query( | ||
"SELECT obj FROM Product obj " | ||
+ "WHERE (:category IS NULL OR obj.category.id = :category)") | ||
List<Product> findProductsByCategoryId(Long category); | ||
} |
55 changes: 55 additions & 0 deletions
55
src/main/java/br/com/fiap/grupo30/fastfood/resources/ProductResource.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
package br.com.fiap.grupo30.fastfood.resources; | ||
|
||
import br.com.fiap.grupo30.fastfood.dto.ProductDTO; | ||
import br.com.fiap.grupo30.fastfood.services.ProductService; | ||
import java.net.URI; | ||
import java.util.List; | ||
import org.springframework.beans.factory.annotation.Autowired; | ||
import org.springframework.http.ResponseEntity; | ||
import org.springframework.web.bind.annotation.*; | ||
import org.springframework.web.servlet.support.ServletUriComponentsBuilder; | ||
|
||
@RestController | ||
@RequestMapping(value = "/products") | ||
public class ProductResource { | ||
|
||
private static final String PATH_VARIABLE_ID = "/{id}"; | ||
|
||
@Autowired private ProductService service; | ||
|
||
@GetMapping | ||
public ResponseEntity<List<ProductDTO>> findAll( | ||
@RequestParam(value = "categoryId", defaultValue = "0") Long categoryId) { | ||
List<ProductDTO> list = service.findAll(categoryId); | ||
return ResponseEntity.ok().body(list); | ||
} | ||
|
||
@GetMapping(value = PATH_VARIABLE_ID) | ||
public ResponseEntity<ProductDTO> findById(@PathVariable Long id) { | ||
ProductDTO dto = service.findById(id); | ||
return ResponseEntity.ok().body(dto); | ||
} | ||
|
||
@PostMapping | ||
public ResponseEntity<ProductDTO> insert(@RequestBody ProductDTO dto) { | ||
ProductDTO dtoCreated = service.insert(dto); | ||
URI uri = | ||
ServletUriComponentsBuilder.fromCurrentRequest() | ||
.path(PATH_VARIABLE_ID) | ||
.buildAndExpand(dto.getId()) | ||
.toUri(); | ||
return ResponseEntity.created(uri).body(dtoCreated); | ||
} | ||
|
||
@PutMapping(value = PATH_VARIABLE_ID) | ||
public ResponseEntity<ProductDTO> update(@PathVariable Long id, @RequestBody ProductDTO dto) { | ||
ProductDTO dtoUpdated = service.update(id, dto); | ||
return ResponseEntity.ok().body(dtoUpdated); | ||
} | ||
|
||
@DeleteMapping(value = PATH_VARIABLE_ID) | ||
public ResponseEntity<Void> delete(@PathVariable Long id) { | ||
service.delete(id); | ||
return ResponseEntity.noContent().build(); | ||
} | ||
} |
15 changes: 15 additions & 0 deletions
15
src/main/java/br/com/fiap/grupo30/fastfood/resources/StandardError.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
package br.com.fiap.grupo30.fastfood.resources; | ||
|
||
import java.time.Instant; | ||
import lombok.Data; | ||
import lombok.NoArgsConstructor; | ||
|
||
@Data | ||
@NoArgsConstructor | ||
public class StandardError { | ||
private Instant timestamp; | ||
private Integer status; | ||
private String error; | ||
private String message; | ||
private String path; | ||
} |
40 changes: 40 additions & 0 deletions
40
...main/java/br/com/fiap/grupo30/fastfood/resources/exceptions/ResourceExceptionHandler.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
package br.com.fiap.grupo30.fastfood.resources.exceptions; | ||
|
||
import br.com.fiap.grupo30.fastfood.resources.StandardError; | ||
import br.com.fiap.grupo30.fastfood.services.exceptions.DatabaseException; | ||
import br.com.fiap.grupo30.fastfood.services.exceptions.ResourceNotFoundException; | ||
import jakarta.servlet.http.HttpServletRequest; | ||
import java.time.Instant; | ||
import org.springframework.http.HttpStatus; | ||
import org.springframework.http.ResponseEntity; | ||
import org.springframework.web.bind.annotation.ControllerAdvice; | ||
import org.springframework.web.bind.annotation.ExceptionHandler; | ||
|
||
@ControllerAdvice | ||
public class ResourceExceptionHandler { | ||
|
||
@ExceptionHandler(ResourceNotFoundException.class) | ||
public ResponseEntity<StandardError> entityNotFound( | ||
ResourceNotFoundException e, HttpServletRequest request) { | ||
HttpStatus status = HttpStatus.NOT_FOUND; | ||
StandardError err = new StandardError(); | ||
err.setTimestamp(Instant.now()); | ||
err.setStatus(status.value()); | ||
err.setError("Resource not found"); | ||
err.setMessage(e.getMessage()); | ||
err.setPath(request.getRequestURI()); | ||
return ResponseEntity.status(status).body(err); | ||
} | ||
|
||
@ExceptionHandler(DatabaseException.class) | ||
public ResponseEntity<StandardError> database(DatabaseException e, HttpServletRequest request) { | ||
HttpStatus status = HttpStatus.BAD_REQUEST; | ||
StandardError err = new StandardError(); | ||
err.setTimestamp(Instant.now()); | ||
err.setStatus(status.value()); | ||
err.setError("Database exception"); | ||
err.setMessage(e.getMessage()); | ||
err.setPath(request.getRequestURI()); | ||
return ResponseEntity.status(status).body(err); | ||
} | ||
} |
77 changes: 77 additions & 0 deletions
77
src/main/java/br/com/fiap/grupo30/fastfood/services/ProductService.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,77 @@ | ||
package br.com.fiap.grupo30.fastfood.services; | ||
|
||
import br.com.fiap.grupo30.fastfood.dto.ProductDTO; | ||
import br.com.fiap.grupo30.fastfood.entities.Category; | ||
import br.com.fiap.grupo30.fastfood.entities.Product; | ||
import br.com.fiap.grupo30.fastfood.repositories.CategoryRepository; | ||
import br.com.fiap.grupo30.fastfood.repositories.ProductRepository; | ||
import br.com.fiap.grupo30.fastfood.services.exceptions.DatabaseException; | ||
import br.com.fiap.grupo30.fastfood.services.exceptions.ResourceNotFoundException; | ||
import jakarta.persistence.EntityNotFoundException; | ||
import java.util.List; | ||
import java.util.Optional; | ||
import org.springframework.beans.factory.annotation.Autowired; | ||
import org.springframework.dao.DataIntegrityViolationException; | ||
import org.springframework.dao.EmptyResultDataAccessException; | ||
import org.springframework.stereotype.Service; | ||
import org.springframework.transaction.annotation.Transactional; | ||
|
||
@Service | ||
public class ProductService { | ||
|
||
@Autowired private ProductRepository repository; | ||
|
||
@Autowired private CategoryRepository categoryRepository; | ||
|
||
@Transactional(readOnly = true) | ||
public List<ProductDTO> findAll(Long categoryId) { | ||
Long category = categoryId == 0 ? null : categoryId; | ||
return repository.findProductsByCategoryId(category).stream().map(ProductDTO::new).toList(); | ||
} | ||
|
||
@Transactional(readOnly = true) | ||
public ProductDTO findById(Long id) { | ||
Optional<Product> obj = repository.findById(id); | ||
Product entity = obj.orElseThrow(() -> new ResourceNotFoundException("Entity not found")); | ||
return new ProductDTO(entity); | ||
} | ||
|
||
@Transactional | ||
public ProductDTO insert(ProductDTO dto) { | ||
Product entity = new Product(); | ||
copyDtoToEntity(dto, entity); | ||
entity = repository.save(entity); | ||
return new ProductDTO(entity); | ||
} | ||
|
||
@Transactional | ||
public ProductDTO update(Long id, ProductDTO dto) { | ||
try { | ||
Product entity = repository.getReferenceById(id); | ||
copyDtoToEntity(dto, entity); | ||
entity = repository.save(entity); | ||
return new ProductDTO(entity); | ||
} catch (EntityNotFoundException e) { | ||
throw new ResourceNotFoundException("Id not found " + id, e); | ||
} | ||
} | ||
|
||
public void delete(Long id) { | ||
try { | ||
repository.deleteById(id); | ||
} catch (EmptyResultDataAccessException e) { | ||
throw new ResourceNotFoundException("Id not found " + id, e); | ||
} catch (DataIntegrityViolationException e) { | ||
throw new DatabaseException("Integrity violation", e); | ||
} | ||
} | ||
|
||
private void copyDtoToEntity(ProductDTO dto, Product entity) { | ||
entity.setName(dto.getName()); | ||
entity.setDescription(dto.getDescription()); | ||
entity.setImgUrl(dto.getImgUrl()); | ||
entity.setPrice(dto.getPrice()); | ||
Category category = categoryRepository.getReferenceById(dto.getCategory().getId()); | ||
entity.setCategory(category); | ||
} | ||
} |
11 changes: 11 additions & 0 deletions
11
src/main/java/br/com/fiap/grupo30/fastfood/services/exceptions/DatabaseException.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
package br.com.fiap.grupo30.fastfood.services.exceptions; | ||
|
||
import java.io.Serial; | ||
|
||
public class DatabaseException extends RuntimeException { | ||
@Serial private static final long serialVersionUID = 1L; | ||
|
||
public DatabaseException(String msg, Throwable exception) { | ||
super(msg, exception); | ||
} | ||
} |
16 changes: 16 additions & 0 deletions
16
...main/java/br/com/fiap/grupo30/fastfood/services/exceptions/ResourceNotFoundException.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
package br.com.fiap.grupo30.fastfood.services.exceptions; | ||
|
||
import java.io.Serial; | ||
|
||
public class ResourceNotFoundException extends RuntimeException { | ||
|
||
@Serial private static final long serialVersionUID = 1L; | ||
|
||
public ResourceNotFoundException(String msg) { | ||
super(msg); | ||
} | ||
|
||
public ResourceNotFoundException(String msg, Throwable exception) { | ||
super(msg, exception); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,32 @@ | ||
INSERT INTO category(name, created_at) VALUES ('Snacks', NOW()); | ||
INSERT INTO category(name, created_at) VALUES ('Drinks', NOW()); | ||
INSERT INTO category(name, created_at) VALUES ('Desserts', NOW()); | ||
INSERT INTO category(name, created_at) VALUES ('Side Dishes', NOW()); | ||
INSERT INTO category(name, created_at) VALUES ('Sides', NOW()); | ||
|
||
INSERT INTO product (name, price, category_id, description, img_url, created_at) VALUES ('X-Burguer', 14.9, 1, 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus vulputate rutrum ullamcorper.', 'https://', NOW()); | ||
INSERT INTO product (name, price, category_id, description, img_url, created_at) VALUES ('X-Bacon', 12.9, 1, 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus vulputate rutrum ullamcorper.', 'https://', NOW()); | ||
INSERT INTO product (name, price, category_id, description, img_url, created_at) VALUES ('X-Chicken', 14.9, 1, 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus vulputate rutrum ullamcorper.', 'https://', NOW()); | ||
INSERT INTO product (name, price, category_id, description, img_url, created_at) VALUES ('X-Fish', 15.9, 1, 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus vulputate rutrum ullamcorper.', 'https://', NOW()); | ||
INSERT INTO product (name, price, category_id, description, img_url, created_at) VALUES ('CheeseBurguer', 12.9, 1, 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus vulputate rutrum ullamcorper.', 'https://', NOW()); | ||
INSERT INTO product (name, price, category_id, description, img_url, created_at) VALUES ('Coca-Cola', 9.9, 2, 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus vulputate rutrum ullamcorper.', 'https://', NOW()); | ||
INSERT INTO product (name, price, category_id, description, img_url, created_at) VALUES ('Lemonade', 10.9, 2, 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus vulputate rutrum ullamcorper.', 'https://', NOW()); | ||
INSERT INTO product (name, price, category_id, description, img_url, created_at) VALUES ('Orange Juice', 11.9, 2, 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus vulputate rutrum ullamcorper.', 'https://', NOW()); | ||
INSERT INTO product (name, price, category_id, description, img_url, created_at) VALUES ('Water', 7.9, 2, 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus vulputate rutrum ullamcorper.', 'https://', NOW()); | ||
INSERT INTO product (name, price, category_id, description, img_url, created_at) VALUES ('Ice Tea', 10.9, 2, 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus vulputate rutrum ullamcorper.', 'https://', NOW()); | ||
INSERT INTO product (name, price, category_id, description, img_url, created_at) VALUES ('Vanilla Sundae', 8.9, 3, 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus vulputate rutrum ullamcorper.', 'https://', NOW()); | ||
INSERT INTO product (name, price, category_id, description, img_url, created_at) VALUES ('Strawberry Sundae', 8.9, 3, 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus vulputate rutrum ullamcorper.', 'https://', NOW()); | ||
INSERT INTO product (name, price, category_id, description, img_url, created_at) VALUES ('Chocolate Sundae', 8.9, 3, 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus vulputate rutrum ullamcorper.', 'https://', NOW()); | ||
INSERT INTO product (name, price, category_id, description, img_url, created_at) VALUES ('Vanilla Shake', 13.9, 3, 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus vulputate rutrum ullamcorper.', 'https://', NOW()); | ||
INSERT INTO product (name, price, category_id, description, img_url, created_at) VALUES ('Strawberry Shake', 13.9, 3, 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus vulputate rutrum ullamcorper.', 'https://', NOW()); | ||
INSERT INTO product (name, price, category_id, description, img_url, created_at) VALUES ('Chocolate Shake', 13.9, 3, 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus vulputate rutrum ullamcorper.', 'https://', NOW()); | ||
INSERT INTO product (name, price, category_id, description, img_url, created_at) VALUES ('Vanilla Cone', 5.9, 3, 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus vulputate rutrum ullamcorper.', 'https://', NOW()); | ||
INSERT INTO product (name, price, category_id, description, img_url, created_at) VALUES ('Chocolate Cone', 5.9, 3, 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus vulputate rutrum ullamcorper.', 'https://', NOW()); | ||
INSERT INTO product (name, price, category_id, description, img_url, created_at) VALUES ('Mixed Cone', 5.9, 3, 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus vulputate rutrum ullamcorper.', 'https://', NOW()); | ||
INSERT INTO product (name, price, category_id, description, img_url, created_at) VALUES ('Banana Pie', 7.9, 3, 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus vulputate rutrum ullamcorper.', 'https://', NOW()); | ||
INSERT INTO product (name, price, category_id, description, img_url, created_at) VALUES ('Apple Cone', 7.9, 3, 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus vulputate rutrum ullamcorper.', 'https://', NOW()); | ||
INSERT INTO product (name, price, category_id, description, img_url, created_at) VALUES ('French Fries', 8.9, 4, 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus vulputate rutrum ullamcorper.', 'https://', NOW()); | ||
INSERT INTO product (name, price, category_id, description, img_url, created_at) VALUES ('Mustard', 1.9, 4, 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus vulputate rutrum ullamcorper.', 'https://', NOW()); | ||
INSERT INTO product (name, price, category_id, description, img_url, created_at) VALUES ('Ketchup', 1.9, 4, 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus vulputate rutrum ullamcorper.', 'https://', NOW()); | ||
INSERT INTO product (name, price, category_id, description, img_url, created_at) VALUES ('Mayonnaise', 1.9, 4, 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus vulputate rutrum ullamcorper.', 'https://', NOW()); | ||
INSERT INTO product (name, price, category_id, description, img_url, created_at) VALUES ('Barbeque Sauce', 1.9, 4, 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus vulputate rutrum ullamcorper.', 'https://', NOW()); | ||
INSERT INTO product (name, price, category_id, description, img_url, created_at) VALUES ('Chicken Nuggets', 10.9, 4, 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus vulputate rutrum ullamcorper.', 'https://', NOW()); |