-
Notifications
You must be signed in to change notification settings - Fork 1
Events integration #64
Changes from 10 commits
3ffcd29
d8b17c2
1e0ef37
14b1b1d
c2f70e7
0e72338
ce07036
7a49557
3ea6260
14e1226
b9e45db
af590d2
b8d8976
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
package ch.wisv.payments.model.eventsync; | ||
|
||
import lombok.Data; | ||
import lombok.Getter; | ||
|
||
@Data | ||
class EventsSync { | ||
|
||
@Getter | ||
private String trigger; | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
package ch.wisv.payments.model.eventsync; | ||
|
||
import lombok.Data; | ||
import lombok.EqualsAndHashCode; | ||
|
||
@EqualsAndHashCode(callSuper = false) | ||
@Data | ||
public class ProductEventsSync extends EventsSync { | ||
|
||
/** | ||
* Price of the product. | ||
*/ | ||
private Double price; | ||
|
||
/** | ||
* Description of the product. | ||
*/ | ||
private String description; | ||
|
||
/** | ||
* Title of the product. | ||
*/ | ||
private String title; | ||
|
||
/** | ||
* UUID of the product. | ||
*/ | ||
private String key; | ||
|
||
/** | ||
* Enum string of the organizing Committee. | ||
*/ | ||
private String organizedBy; | ||
|
||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
package ch.wisv.payments.rest.eventsync; | ||
|
||
import ch.wisv.payments.model.eventsync.ProductEventsSync; | ||
|
||
public interface EventsSyncProductService { | ||
|
||
/** | ||
* Create a Product from a ProductEventsSync model. | ||
* | ||
* @param productEventsSync of type ProductEventsSync | ||
*/ | ||
void createProduct(ProductEventsSync productEventsSync); | ||
|
||
/** | ||
* Edit a Product from a ProductEventsSync model. | ||
* | ||
* @param productEventsSync of type ProductEventsSync | ||
*/ | ||
void editProduct(ProductEventsSync productEventsSync); | ||
|
||
/** | ||
* Delete a Product from a ProductEventsSync model. | ||
* | ||
* @param productEventsSync of type ProductEventsSync | ||
*/ | ||
void deleteProduct(ProductEventsSync productEventsSync); | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,116 @@ | ||
package ch.wisv.payments.rest.eventsync; | ||
|
||
import ch.wisv.payments.admin.committees.CommitteeRepository; | ||
import ch.wisv.payments.exception.ProductNotFoundException; | ||
import ch.wisv.payments.model.Committee; | ||
import ch.wisv.payments.model.CommitteeEnum; | ||
import ch.wisv.payments.model.Product; | ||
import ch.wisv.payments.model.eventsync.ProductEventsSync; | ||
import ch.wisv.payments.rest.repository.ProductRepository; | ||
import org.springframework.stereotype.Service; | ||
|
||
@Service | ||
public class EventsSyncProductServiceImpl implements EventsSyncProductService { | ||
|
||
/** | ||
* ProductRepository. | ||
*/ | ||
private final ProductRepository productRepository; | ||
|
||
/** | ||
* CommitteeRepository. | ||
*/ | ||
private final CommitteeRepository committeeRepository; | ||
|
||
/** | ||
* Constructor. | ||
* | ||
* @param productRepository of type ProductRepository | ||
* @param committeeRepository of type CommitteeRepository | ||
*/ | ||
public EventsSyncProductServiceImpl(ProductRepository productRepository, CommitteeRepository committeeRepository) { | ||
this.productRepository = productRepository; | ||
this.committeeRepository = committeeRepository; | ||
} | ||
|
||
/** | ||
* @param productEventsSync of type ProductEventsSync | ||
*/ | ||
@Override | ||
public void createProduct(ProductEventsSync productEventsSync) { | ||
Product product = new Product(); | ||
product.setKey(productEventsSync.getKey()); | ||
|
||
this.changeProductValues(product, productEventsSync); | ||
|
||
productRepository.save(product); | ||
} | ||
|
||
/** | ||
* @param productEventsSync of type ProductEventsSync | ||
*/ | ||
@Override | ||
public void editProduct(ProductEventsSync productEventsSync) { | ||
Product product = this.getProductByKey(productEventsSync.getKey()); | ||
|
||
this.changeProductValues(product, productEventsSync); | ||
|
||
productRepository.save(product); | ||
} | ||
|
||
/** | ||
* Change the Product values using a ProductEventsSync model. | ||
* | ||
* @param product of type Product. | ||
* @param productEventsSync of type ProductEventsSync. | ||
*/ | ||
private void changeProductValues(Product product, ProductEventsSync productEventsSync) { | ||
if (product.getCommittee() == null || product.getCommittee().toString().equals(productEventsSync.getOrganizedBy())) { | ||
this.changeProductCommittee(product, productEventsSync); | ||
} | ||
|
||
product.setDescription(productEventsSync.getDescription()); | ||
product.setName(productEventsSync.getTitle()); | ||
product.setPrice(productEventsSync.getPrice().floatValue()); | ||
} | ||
|
||
/** | ||
* Change the Committee of Product. | ||
* | ||
* @param product of type Product | ||
* @param productEventsSync of type ProductEventsSync | ||
*/ | ||
private void changeProductCommittee(Product product, ProductEventsSync productEventsSync) { | ||
CommitteeEnum committeeEnum = CommitteeEnum.valueOf(productEventsSync.getOrganizedBy()); | ||
int year = 2017; | ||
|
||
Committee committee = committeeRepository.findOneByNameAndYear(committeeEnum, year) | ||
.orElse(new Committee(committeeEnum, year)); | ||
|
||
if (committee.getId() == 0) { | ||
committeeRepository.save(committee); | ||
} | ||
|
||
product.setCommittee(committee); | ||
} | ||
|
||
/** | ||
* @param productEventsSync of type ProductEventsSync | ||
*/ | ||
@Override | ||
public void deleteProduct(ProductEventsSync productEventsSync) { | ||
Product product = this.getProductByKey(productEventsSync.getKey()); | ||
|
||
productRepository.delete(product.getId()); | ||
} | ||
|
||
/** | ||
* Get a Product by its key. | ||
* | ||
* @param key of type Key | ||
* @return Product | ||
*/ | ||
private Product getProductByKey(String key) { | ||
return productRepository.findOneByKey(key).orElseThrow(ProductNotFoundException::new); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,111 @@ | ||
package ch.wisv.payments.rest.eventsync; | ||
|
||
import ch.wisv.payments.admin.products.ProductService; | ||
import ch.wisv.payments.exception.ProductNotFoundException; | ||
import ch.wisv.payments.model.eventsync.ProductEventsSync; | ||
import org.springframework.beans.factory.annotation.Value; | ||
import org.springframework.http.HttpStatus; | ||
import org.springframework.http.ResponseEntity; | ||
import org.springframework.validation.annotation.Validated; | ||
import org.springframework.web.bind.annotation.*; | ||
|
||
import javax.servlet.http.HttpServletRequest; | ||
import javax.validation.constraints.NotNull; | ||
import java.nio.charset.Charset; | ||
import java.util.Base64; | ||
|
||
import static ch.wisv.payments.util.ResponseEntityBuilder.createResponseEntity; | ||
|
||
@RestController | ||
@CrossOrigin | ||
@RequestMapping(value = "/api/chevents/sync") | ||
@Validated | ||
public class EventsSyncRestController { | ||
|
||
@Value("${events.username}") | ||
@NotNull | ||
private String username; | ||
|
||
@Value("${events.password}") | ||
@NotNull | ||
private String password; | ||
|
||
/** | ||
* ProductService. | ||
*/ | ||
private final ProductService productService; | ||
|
||
private final EventsSyncProductService eventsSyncProductService; | ||
|
||
/** | ||
* Constructor ProductService. | ||
* | ||
* @param productService of type ProductService | ||
* @param eventsSyncProductService of type EventsSyncProductService | ||
*/ | ||
public EventsSyncRestController(ProductService productService, EventsSyncProductService eventsSyncProductService) { | ||
this.productService = productService; | ||
this.eventsSyncProductService = eventsSyncProductService; | ||
} | ||
|
||
|
||
@PostMapping("/product/") | ||
public ResponseEntity<?> eventSync(HttpServletRequest request, @RequestBody ProductEventsSync productEventsSync) { | ||
String[] credentials = this.decryptBasicAuthHeader(request.getHeader("Authorization")); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This feels ugly, but it's quick and effective I guess... I'd prefer a more native Spring way using filters and an in-memory events user. |
||
|
||
if (!this.authChEvents(credentials)) { | ||
return createResponseEntity(HttpStatus.UNAUTHORIZED, "User is not authorized", null); | ||
} | ||
|
||
switch (productEventsSync.getTrigger()) { | ||
case "PRODUCT_CREATE_EDIT": | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Let's turn magic strings into Enums? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Fix in af590d2 |
||
this.determineCreateOrUpdate(productEventsSync); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You're not determining anything, you're creating or updating it. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Fix in commit b9e45db |
||
break; | ||
case "PRODUCT_DELETE": | ||
eventsSyncProductService.deleteProduct(productEventsSync); | ||
break; | ||
default: | ||
return createResponseEntity(HttpStatus.BAD_REQUEST, "Events trigger not supported!", null); | ||
} | ||
|
||
return createResponseEntity(HttpStatus.OK, null, null); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This should be more specific, with HttpStatus.CREATED when a new product is created There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This should be a HttpStatus.OK, otherwise CH events thinks the sync failed. |
||
} | ||
|
||
/** | ||
* Check if user is CH Events. | ||
* | ||
* @param credentials of type String[] | ||
*/ | ||
private boolean authChEvents(String[] credentials) { | ||
return credentials[0].equals(this.username) && credentials[1].equals(this.password); | ||
} | ||
|
||
/** | ||
* Determine if a Product should be updated or created. | ||
* | ||
* @param productEventsSync of type ProductEventsSync | ||
*/ | ||
private void determineCreateOrUpdate(ProductEventsSync productEventsSync) { | ||
try { | ||
productService.getProductByKey(productEventsSync.getKey()); | ||
|
||
eventsSyncProductService.editProduct(productEventsSync); | ||
} catch (ProductNotFoundException e) { | ||
eventsSyncProductService.createProduct(productEventsSync); | ||
} | ||
} | ||
|
||
/** | ||
* Decrypt the Basic Auth header. | ||
* | ||
* @param basicAuth of type String | ||
* @return String[] with username and password | ||
*/ | ||
private String[] decryptBasicAuthHeader(String basicAuth) { | ||
String base64Credentials = basicAuth.substring("Basic".length()).trim(); | ||
String credentials = new String(Base64.getDecoder().decode(base64Credentials), | ||
Charset.forName("UTF-8")); | ||
|
||
return credentials.split(":", 2); | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should be dynamic!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Issue #65