diff --git a/prototype/src/main/java/org/hso/ecommerce/components/AdminInitializer.java b/prototype/src/main/java/org/hso/ecommerce/components/AdminInitializer.java new file mode 100644 index 0000000..7b473c0 --- /dev/null +++ b/prototype/src/main/java/org/hso/ecommerce/components/AdminInitializer.java @@ -0,0 +1,37 @@ +package org.hso.ecommerce.components; + +import org.hso.ecommerce.entities.booking.PaymentMethod; +import org.hso.ecommerce.entities.user.User; +import org.hso.ecommerce.repos.user.UserRepository; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import java.sql.Timestamp; +import java.util.Optional; + +import javax.annotation.PostConstruct; + +@Component +public class AdminInitializer { + + @Autowired + private final UserRepository userRepository = null; + + @PostConstruct + public void init() { + Optional numberOfEmployees = userRepository.numberOfEmployees(); + if (numberOfEmployees.orElse(0) == 0) { + // create first admin user + User firstAdmin = new User(); + firstAdmin.created = new Timestamp(System.currentTimeMillis()); + firstAdmin.name = "admin"; + firstAdmin.defaultPayment = new PaymentMethod(); + firstAdmin.defaultPayment.creditCardNumber = ""; //set empty number + firstAdmin.email = "admin"; + firstAdmin.isActive = true; + firstAdmin.isEmployee = true; + firstAdmin.setPassword("admin"); + userRepository.save(firstAdmin); //save to DB + } + } +} diff --git a/prototype/src/main/java/org/hso/ecommerce/components/SlotInitializer.java b/prototype/src/main/java/org/hso/ecommerce/components/SlotInitializer.java index ae9f572..df32144 100644 --- a/prototype/src/main/java/org/hso/ecommerce/components/SlotInitializer.java +++ b/prototype/src/main/java/org/hso/ecommerce/components/SlotInitializer.java @@ -11,8 +11,8 @@ import javax.annotation.PostConstruct; @Component public class SlotInitializer { - @Autowired - private final SlotRepository slotRepository = null; + @Autowired + private final SlotRepository slotRepository = null; @Autowired private final AppSettings appSettings = null; diff --git a/prototype/src/main/java/org/hso/ecommerce/controller/RegisterController.java b/prototype/src/main/java/org/hso/ecommerce/controller/RegisterController.java index 36fcdef..008cd0b 100644 --- a/prototype/src/main/java/org/hso/ecommerce/controller/RegisterController.java +++ b/prototype/src/main/java/org/hso/ecommerce/controller/RegisterController.java @@ -26,8 +26,6 @@ public class RegisterController { @RequestParam("username") String username, @RequestParam("password") String password, @RequestParam("password2") String password2, @RequestParam("salutation") String salutation, @RequestParam("name") String name, @RequestParam("address") String address, - @RequestParam("type") String type, // TODO store - @RequestParam("ad") String ad, // TODO store HttpSession session) { Optional user = userRepository.findByEmail(username); if (user.isPresent()) { diff --git a/prototype/src/main/java/org/hso/ecommerce/controller/cronjob/CronjobController.java b/prototype/src/main/java/org/hso/ecommerce/controller/cronjob/CronjobController.java index 0f54221..dbf7c6c 100644 --- a/prototype/src/main/java/org/hso/ecommerce/controller/cronjob/CronjobController.java +++ b/prototype/src/main/java/org/hso/ecommerce/controller/cronjob/CronjobController.java @@ -1,6 +1,7 @@ package org.hso.ecommerce.controller.cronjob; import java.sql.Timestamp; +import java.util.ArrayList; import java.util.Calendar; import java.util.Collections; import java.util.GregorianCalendar; @@ -37,6 +38,11 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; +import org.springframework.ui.Model; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestMapping; interface ICronjob { /** @@ -63,10 +69,22 @@ interface ICronjob { * @param controller Back-reference that allows to use repositories. */ void executeAt(Calendar time, CronjobController controller); + + /** + * Get a name for this cronjob, that can be presented to the user in the frontend. + * + * @return A german name of this cronjob. + */ + String getDisplayName(); } @Component class Reorder implements ICronjob { + @Override + public String getDisplayName() { + return "Nachbestellung"; + } + @Override public Calendar nextExecution(Calendar reference) { if (reference.get(Calendar.HOUR_OF_DAY) >= 8) { @@ -215,6 +233,7 @@ class ScheduledCronjob { } @Component +@RequestMapping("intern/cronjobs") class CronjobController { private static final Logger log = LoggerFactory.getLogger(CronjobController.class); @@ -328,4 +347,42 @@ class CronjobController { public void onPostConstruct() { new Thread(this::runCronjobExecutionLoop).start(); } + + class ManualCronjob { + public final String identifier; + public final String visibleName; + + public ManualCronjob(String identifier, String visibleName) { + this.identifier = identifier; + this.visibleName = visibleName; + } + } + + private List listAllCronjobs() { + ArrayList entries = new ArrayList<>(); + for (Entry job : cronjobs.entrySet()) { + entries.add(new ManualCronjob(job.getKey(), job.getValue().getDisplayName())); + } + return entries; + } + + @GetMapping("/") + public String cronjobOverview(Model model) { + model.addAttribute("jobs", listAllCronjobs()); + return "intern/cronjobs/index"; + } + + @PostMapping("/run/{identifier}") + public String runCronjob(Model model, @PathVariable("identifier") String identifier) { + ICronjob jobToExecute = cronjobs.get(identifier); + if (jobToExecute != null) { + jobToExecute.executeAt(new GregorianCalendar(), this); + model.addAttribute("info", + String.format("Der Cronjob \"%s\" wurde ausgeführt.", jobToExecute.getDisplayName())); + } else { + model.addAttribute("error", "Der Cronjob konnte nicht gefunden werden."); + } + model.addAttribute("jobs", listAllCronjobs()); + return "intern/cronjobs/index"; + } } diff --git a/prototype/src/main/java/org/hso/ecommerce/repos/user/UserRepository.java b/prototype/src/main/java/org/hso/ecommerce/repos/user/UserRepository.java index 9477763..c48b9af 100644 --- a/prototype/src/main/java/org/hso/ecommerce/repos/user/UserRepository.java +++ b/prototype/src/main/java/org/hso/ecommerce/repos/user/UserRepository.java @@ -10,9 +10,9 @@ import java.util.Optional; @Repository public interface UserRepository extends JpaRepository { - @Query("SELECT c FROM User c WHERE c.email = :email") - Optional findByEmail(String email); + @Query("SELECT c FROM User c WHERE c.email = :email") + Optional findByEmail(String email); + @Query("SELECT count(*) FROM User WHERE isEmployee = true") + Optional numberOfEmployees(); } - - diff --git a/prototype/src/main/resources/static/css/manual-cronjobs.css b/prototype/src/main/resources/static/css/manual-cronjobs.css new file mode 100644 index 0000000..19205d5 --- /dev/null +++ b/prototype/src/main/resources/static/css/manual-cronjobs.css @@ -0,0 +1,35 @@ +.alert { + display: block; + text-transform: uppercase; + background: #c0392b; + color: white; + animation: blinking 1s linear infinite; + overflow: hidden; +} + +.alert > span { + display: inline-block; + padding-left: 100%; + animation: marquee 10s linear infinite; + white-space: nowrap; +} + +@keyframes marquee { + 0% { transform: translateX(0); } + 100% { transform: translateX(-100%); } +} + +@keyframes blinking { + 60% { + color: white; + } + 75% { + color: #c0392b; + } + 85% { + color: #c0392b; + } + 100% { + color: white; + } +} diff --git a/prototype/src/main/resources/templates/fragments/intern.html b/prototype/src/main/resources/templates/fragments/intern.html index 22de534..eee1c8d 100644 --- a/prototype/src/main/resources/templates/fragments/intern.html +++ b/prototype/src/main/resources/templates/fragments/intern.html @@ -47,6 +47,8 @@ +
  • Cronjobs
  • + diff --git a/prototype/src/main/resources/templates/intern/cronjobs/index.html b/prototype/src/main/resources/templates/intern/cronjobs/index.html new file mode 100644 index 0000000..ef7e681 --- /dev/null +++ b/prototype/src/main/resources/templates/intern/cronjobs/index.html @@ -0,0 +1,60 @@ + + + + + + + + Cronjobs + + + + + + + + +
    + +
    +

    Manuelle Ausführung von Cronjobs

    +
    + WARNUNG
    + Manuelles Triggern von Cronjobs kann zu unerwartetem Verhalten führen!
    + Diese Seite ist nur für Debugging-Zwecke gedacht. +
    + +

    + + + + + + + + + + + + +
    + +
    Cronjob
    +
    + +
    +
    +

    + +
    +
    +
    + + + diff --git a/prototype/src/main/resources/templates/register.html b/prototype/src/main/resources/templates/register.html index de4b839..3920e65 100644 --- a/prototype/src/main/resources/templates/register.html +++ b/prototype/src/main/resources/templates/register.html @@ -54,23 +54,6 @@ -
    - -
    - -
    -
    -
    -

    Werbung

    -
    -
    -
    - -
    - -
    -
    -
    diff --git a/supplier/config/mda.json b/supplier/config/mda.json new file mode 100644 index 0000000..de2d9f6 --- /dev/null +++ b/supplier/config/mda.json @@ -0,0 +1,50 @@ +{ + "id" : "mda", + "name" : "MDA", + "discount" : { + "minimumDailySalesVolumeNetCent": 20, + "percentDiscount": 3 + }, + "articles": [ + { + "title": "MDA Nezyr 7", + "manufacturer": "MDA", + "articleNumber": "n7", + "vatPercent": 19, + "pricePerUnitNet": 29990, + "shouldBeAdvertised": true + }, + { + "title": "MDA Nezyr 5", + "manufacturer": "MDA", + "articleNumber": "n5", + "vatPercent": 19, + "pricePerUnitNet": 19700, + "shouldBeAdvertised": true + }, + { + "title": "MDA Nezyr 3", + "manufacturer": "MDA", + "articleNumber": "n3", + "vatPercent": 19, + "pricePerUnitNet": 8990, + "shouldBeAdvertised": false + }, + { + "title": "MDA Nezyr Threadcracker 3990", + "manufacturer": "MDA", + "articleNumber": "ntc3990", + "vatPercent": 19, + "pricePerUnitNet": 404900, + "shouldBeAdvertised": true + }, + { + "title": "MDA Radon RX 5700", + "manufacturer": "MDA", + "articleNumber": "rrx5700", + "vatPercent": 19, + "pricePerUnitNet": 43624, + "shouldBeAdvertised": true + } + ] +} \ No newline at end of file diff --git a/supplier/config/nanosoft.json b/supplier/config/nanosoft.json new file mode 100644 index 0000000..4d978b7 --- /dev/null +++ b/supplier/config/nanosoft.json @@ -0,0 +1,34 @@ +{ + "id" : "nanosoft", + "name" : "Nanosoft", + "discount" : { + "minimumDailySalesVolumeNetCent": 50, + "percentDiscount": 0.5 + }, + "articles": [ + { + "title": "Nanosoft Doors 10", + "manufacturer": "Nanosoft", + "articleNumber": "d10", + "vatPercent": 7, + "pricePerUnitNet": 2099, + "shouldBeAdvertised": true + }, + { + "title": "Nanosoft Interior Pro 7", + "manufacturer": "Nanosoft", + "articleNumber": "ip7", + "vatPercent": 19, + "pricePerUnitNet": 90780, + "shouldBeAdvertised": false + }, + { + "title": "Nanosoft Ybox Two", + "manufacturer": "Nanosoft", + "articleNumber": "ybox2", + "vatPercent": 19, + "pricePerUnitNet": 23500, + "shouldBeAdvertised": true + } + ] +} \ No newline at end of file diff --git a/supplier/config/outtel.json b/supplier/config/outtel.json new file mode 100644 index 0000000..10c14b7 --- /dev/null +++ b/supplier/config/outtel.json @@ -0,0 +1,42 @@ +{ + "id" : "outtel", + "name" : "Outtel", + "discount" : { + "minimumDailySalesVolumeNetCent": 20, + "percentDiscount": 1 + }, + "articles": [ + { + "title": "Outtel Core o7", + "manufacturer": "Outtel", + "articleNumber": "o7", + "vatPercent": 19, + "pricePerUnitNet": 40000, + "shouldBeAdvertised": true + }, + { + "title": "Outtel Core o5", + "manufacturer": "Outtel", + "articleNumber": "o5", + "vatPercent": 19, + "pricePerUnitNet": 25000, + "shouldBeAdvertised": true + }, + { + "title": "Outtel Core o3", + "manufacturer": "Outtel", + "articleNumber": "o3", + "vatPercent": 7, + "pricePerUnitNet": 8000, + "shouldBeAdvertised": false + }, + { + "title": "Outtel Core o9", + "manufacturer": "Outtel", + "articleNumber": "o9", + "vatPercent": 19, + "pricePerUnitNet": 55000, + "shouldBeAdvertised": true + } + ] +} \ No newline at end of file diff --git a/supplier/config/pear.json b/supplier/config/pear.json new file mode 100644 index 0000000..f0f3dfe --- /dev/null +++ b/supplier/config/pear.json @@ -0,0 +1,50 @@ +{ + "id" : "pear", + "name" : "Pear", + "discount" : { + "minimumDailySalesVolumeNetCent": 100, + "percentDiscount": 2 + }, + "articles": [ + { + "title": "Pear iMobile 10", + "manufacturer": "Pear", + "articleNumber": "iM10", + "vatPercent": 19, + "pricePerUnitNet": 31500, + "shouldBeAdvertised": true + }, + { + "title": "Pear iPlate Plus", + "manufacturer": "Pear", + "articleNumber": "ipp", + "vatPercent": 19, + "pricePerUnitNet": 44900, + "shouldBeAdvertised": true + }, + { + "title": "Pear iDonalds 9", + "manufacturer": "Pear", + "articleNumber": "id9", + "vatPercent": 19, + "pricePerUnitNet": 234800, + "shouldBeAdvertised": true + }, + { + "title": "Pear GroundPods", + "manufacturer": "Pear", + "articleNumber": "gp", + "vatPercent": 7, + "pricePerUnitNet": 13599, + "shouldBeAdvertised": true + }, + { + "title": "Pear Donalsbook Pro", + "manufacturer": "Pear", + "articleNumber": "dbp", + "vatPercent": 7, + "pricePerUnitNet": 145900, + "shouldBeAdvertised": true + } + ] +} \ No newline at end of file diff --git a/supplier/config/sumsang.json b/supplier/config/sumsang.json new file mode 100644 index 0000000..0b024ae --- /dev/null +++ b/supplier/config/sumsang.json @@ -0,0 +1,42 @@ +{ + "id" : "sumsang", + "name" : "Sumsang", + "discount" : { + "minimumDailySalesVolumeNetCent": 300, + "percentDiscount": 2 + }, + "articles": [ + { + "title": "Sumsang Universe S10", + "manufacturer": "Sumsang", + "articleNumber": "us10", + "vatPercent": 19, + "pricePerUnitNet": 59000, + "shouldBeAdvertised": true + }, + { + "title": "Sumsang Universe S10e", + "manufacturer": "Sumsang", + "articleNumber": "us10e", + "vatPercent": 19, + "pricePerUnitNet": 70231, + "shouldBeAdvertised": false + }, + { + "title": "Sumsang DumbTV", + "manufacturer": "Sumsang", + "articleNumber": "dtv", + "vatPercent": 19, + "pricePerUnitNet": 38395, + "shouldBeAdvertised": true + }, + { + "title": "Sumsang UniverseWatch", + "manufacturer": "Sumsang", + "articleNumber": "uw", + "vatPercent": 19, + "pricePerUnitNet": 20494, + "shouldBeAdvertised": true + } + ] +} \ No newline at end of file diff --git a/supplier/config/techdealer.json b/supplier/config/techdealer.json new file mode 100644 index 0000000..ea00422 --- /dev/null +++ b/supplier/config/techdealer.json @@ -0,0 +1,58 @@ +{ + "id" : "techdealer", + "name" : "Tech Dealer", + "discount" : { + "minimumDailySalesVolumeNetCent": 100, + "percentDiscount": 2 + }, + "articles": [ + { + "title": "TROPIC Gehäuselüfter", + "manufacturer": "TROPIC", + "articleNumber": "tgl", + "vatPercent": 19, + "pricePerUnitNet": 459, + "shouldBeAdvertised": true + }, + { + "title": "Pirate PC-Netzteil", + "manufacturer": "Pirate", + "articleNumber": "ppcn", + "vatPercent": 19, + "pricePerUnitNet": 9355, + "shouldBeAdvertised": true + }, + { + "title": "Pirate Void Elite RGB Wireless Gaming Headset", + "manufacturer": "Pirate", + "articleNumber": "pvergbwgh", + "vatPercent": 7, + "pricePerUnitNet": 10999, + "shouldBeAdvertised": false + }, + { + "title": "Aeroheat CYLON PC-Gehäuse", + "manufacturer": "Aeroheat", + "articleNumber": "acpcg", + "vatPercent": 19, + "pricePerUnitNet": 3999, + "shouldBeAdvertised": true + }, + { + "title": "Illogitech C270 Webcam", + "manufacturer": "Illogitech", + "articleNumber": "ic270w", + "vatPercent": 19, + "pricePerUnitNet": 3499, + "shouldBeAdvertised": true + }, + { + "title": "Illogitech Z607 Surround Sound Lautsprecher", + "manufacturer": "Illogitech", + "articleNumber": "iz607ssl", + "vatPercent": 19, + "pricePerUnitNet": 9495, + "shouldBeAdvertised": false + } + ] +} \ No newline at end of file