Skip to content

Commit

Permalink
External product url (#430)
Browse files Browse the repository at this point in the history
* Add external product URL to Event

* Add rendering of external URL when there is one

* Add rendering of external URL on event page

* Fix double text in external product url field

* Add validation checking for both products and url in one event

* Add validation checking for both products and url in one event in admin panel

* Add migration for external_product_url in event table

* Update script.min

* Remove description from external url event in webshop overview
  • Loading branch information
robertdijk authored and JoepdeJong committed Oct 11, 2023
1 parent d0aee28 commit 2f72176
Show file tree
Hide file tree
Showing 12 changed files with 130 additions and 4 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,9 @@ public String create(RedirectAttributes redirect, @ModelAttribute Event event, @
if (file.getSize() > 0) {
eventService.addDocumentImage(event, documentService.storeDocument(file));
}
if (event.getExternalProductUrl() != null && event.getExternalProductUrl().length() == 0){
event.setExternalProductUrl(null);
}
eventService.create(event);
redirect.addFlashAttribute(FLASH_SUCCESS, "Event " + event.getTitle() + " has been created!");

Expand Down Expand Up @@ -204,6 +207,9 @@ public String update(
eventService.addDocumentImage(event, documentService.storeDocument(file));
}
event.setKey(key);
if (event.getExternalProductUrl() != null && event.getExternalProductUrl().length() == 0){
event.setExternalProductUrl(null);
}
eventService.update(event);
redirect.addFlashAttribute(FLASH_SUCCESS, "Event changes saved!");

Expand Down
15 changes: 15 additions & 0 deletions src/main/java/ch/wisv/events/core/model/event/Event.java
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,11 @@ public class Event {
*/
private String imageUrl;

/**
* Field externalProductUrl link to external url for registering for the Event.
*/
private String externalProductUrl;

/**
* Product that are related to this event and can be sold. OneToMany so one Product can be used by one Event, but
* an Event can contain multiple Products.
Expand Down Expand Up @@ -237,4 +242,14 @@ private double calcProgress(double reserved) {
public boolean isSoldOut() {
return this.maxSold != null && this.getSold() >= this.maxSold;
}

/**
* Check if the event has an external ticker URL configured
*
* @return boolean
*/

public boolean hasExternalProductUrl() {
return this.externalProductUrl != null && this.externalProductUrl.length() > 0;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,7 @@ public void update(Event event) throws EventNotFoundException, EventInvalidExcep
update.setPublished(event.getPublished());
update.setOrganizedBy(event.getOrganizedBy());
update.setCategories(event.getCategories());
update.setExternalProductUrl(event.getExternalProductUrl());

if (event.getImageUrl() != null) {
update.setImageUrl(event.getImageUrl());
Expand Down Expand Up @@ -251,6 +252,10 @@ private void assertIsValidEvent(Event event) throws EventInvalidException {
if (event.getProducts().stream().distinct().count() != event.getProducts().size()) {
throw new EventInvalidException("It is not possible to add the same product twice or more!");
}

if (event.getProducts().size() > 0 && event.hasExternalProductUrl()) {
throw new EventInvalidException("It is not possible to use products when using an external product URL.");
}
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ public Event filterEventProductNotSalable(Event event) {
@Override
public List<Event> filterEventProductNotSalable(List<Event> events) {
return events.stream().map(this::filterEventProductNotSalable)
.filter(event -> event.getProducts().size() > 0)
.filter(event -> event.getProducts().size() > 0 || event.hasExternalProductUrl())
.collect(Collectors.toList());
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package db.migration;

import org.flywaydb.core.api.migration.BaseJavaMigration;
import org.flywaydb.core.api.migration.Context;

import java.sql.Statement;


/**
* DB migration which adds an external product URL to an event.
* If it is present, the event will have a button to this URL instead of normal prducts.
*/
public class V202304016__Add_external_product_url_to_event extends BaseJavaMigration {

/**
* Executes this migration. The execution will automatically take place within a transaction, when the underlying
* database supports it.
*
* @param context of type Context
* @throws Exception when something is wrong
*/
public void migrate(Context context) throws Exception {
try (Statement select = context.getConnection().createStatement()) {
select.execute("ALTER TABLE public.event ADD COLUMN external_product_url varchar(255)");
select.execute("UPDATE public.event SET external_product_url = NULL");
}
}

}
21 changes: 21 additions & 0 deletions src/main/resources/static/js/events/script.js
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,21 @@ $(document).ready(function () {
}
});

const externalProductUrlField = document.getElementById("externalProductUrl");

function validateExternalProductUrlField() {
let products = $("#products");
let productsSize = products.children().length;

if (productsSize > 0 && externalProductUrlField.value !== "") {
externalProductUrlField.setCustomValidity("It is not possible to use products when using an external product URL.");
} else {
externalProductUrlField.setCustomValidity("");
}
}

externalProductUrlField.addEventListener("input", validateExternalProductUrlField);

$('.remove-product').on('click', function (e) {
e.preventDefault();

Expand All @@ -118,6 +133,9 @@ $(document).ready(function () {
followingProduct.attr('id', 'products' + (i - 1));
followingProduct.attr('name', 'products[' + (i - 1) + ']');
}

// After changing the amount of products, recheck that there is not both an external product url and products
validateExternalProductUrlField();
});

$("#createNewProductButton").on('click', function (e) {
Expand Down Expand Up @@ -193,6 +211,9 @@ $(document).ready(function () {
$("#noProducts").remove();

initTooltips();

// After changing the amount of products, recheck that there is not both an external product url and products
validateExternalProductUrlField();
}

function initTooltips() {
Expand Down
2 changes: 1 addition & 1 deletion src/main/resources/static/js/events/script.min.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

9 changes: 9 additions & 0 deletions src/main/resources/templates/admin/events/event.html
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,15 @@ <h6 class="card-header">Information</h6>
th:text="${event.getDescription()}" required></textarea>
</label>
</div>
<div class="form-group col-12">
<label>External Product URL
<input type="url" pattern="https://.*" class="form-control"
th:field="*{externalProductUrl}">
<small class="form-text text-muted">
Replaces the products with a button to this URL. URL must start with <b>https://</b>. Keep empty if you want to use the products.
</small>
</label>
</div>
<div class="col-12">
<div class="row">
<div class="form-group col-6">
Expand Down
7 changes: 7 additions & 0 deletions src/main/resources/templates/admin/events/view.html
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,13 @@ <h6 class="card-header">Information</h6>
readonly></textarea>
</label>
</div>
<div class="form-group col-12">
<label>External Product URL
<input type="text" class="form-control"
th:value="${event.getExternalProductUrl()}"
readonly>
</label>
</div>
<div class="form-group col-12">
<label>Image</label>
<img th:src="${event.getImageUrl()}"
Expand Down
15 changes: 14 additions & 1 deletion src/main/resources/templates/webshop/event.html
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ <h1 class="mb-3" th:text="${event.getTitle()}"></h1>

<div th:replace="fragments/messages :: messages"></div>

<div class="card-deck">
<div class="card-deck" th:if="${!event.hasExternalProductUrl()}">
<div class="card mb-3" th:each="product : ${event.getProducts()}">
<div class="card-header bg-light text-center">
<h4 class="card-title my-1" th:text="${product.getTitle()}"></h4>
Expand Down Expand Up @@ -146,6 +146,19 @@ <h1 th:if="${product.getCost() == 0}">FREE</h1>
</div>
</div>
</div>
<div class="card mb-3" th:if="${event.hasExternalProductUrl()}">
<div class="card-body bg-transparent my-4" style="background-color: #f1f3f7;">
<span th:text="${event.getDescription()}"
th:data-markdown="enable"></span>
</div>
<div class="card-footer">
<a th:href="${event.getExternalProductUrl()}"
target="_blank"
class="btn btn-primary btn-block">
Register here
</a>
</div>
</div>
</main>
</div>
</div>
Expand Down
11 changes: 10 additions & 1 deletion src/main/resources/templates/webshop/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ <h5 class="col-12 card-title mb-1" th:text="${event.getTitle()}"></h5>
</div>
</div>
<div th:id="${event.getKey()}" class="carousel slide align-self-end w-100 "
th:if="${!event.hasExternalProductUrl()}"
data-ride="carousel">
<ol class="carousel-indicators">
<li th:data-target="'#' + ${event.getKey()}"
Expand Down Expand Up @@ -146,7 +147,15 @@ <h1 th:if="${product.getCost() == 0}">FREE</h1>
<span class="sr-only">Next</span>
</a>
</div>

<div th:id="${event.getKey()}"
class="col-12 align-self-end"
th:if="${event.hasExternalProductUrl()}">
<a th:href="${event.getExternalProductUrl()}"
target="_blank"
class="btn btn-primary btn-block">
Register here
</a>
</div>
</div>
</div>
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -208,6 +208,18 @@ public void testCreateInvalidDoubleProduct() throws EventInvalidException {
service.create(this.event);
}

@Test
public void testCreateInvalidExternalURLWithProduct() throws EventInvalidException{
Product product = new Product();
this.event.addProduct(product);
this.event.setExternalProductUrl("https://example.com");

thrown.expect(EventInvalidException.class);
thrown.expectMessage("It is not possible to use products when using an external product URL.");

service.create(this.event);
}

@Test
public void testGetByKey() throws Exception {
when(repository.findByKey(this.event.getKey())).thenReturn(Optional.of(this.event));
Expand Down

0 comments on commit 2f72176

Please sign in to comment.