Merge pull request 'Allow employees to trigger cronjobs manually' (#74) from feature/manual_cronjobs into master
Reviewed-by: Jannik Seiler <seil0@mosad.xyz>
This commit is contained in:
commit
8199bd8a23
|
@ -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<ManualCronjob> listAllCronjobs() {
|
||||
ArrayList<ManualCronjob> entries = new ArrayList<>();
|
||||
for (Entry<String, ICronjob> 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";
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -47,6 +47,8 @@
|
|||
</ul>
|
||||
</li>
|
||||
|
||||
<li><a th:href="@{/intern/cronjobs/}">Cronjobs</a></li>
|
||||
|
||||
</ul>
|
||||
</ul>
|
||||
</nav>
|
||||
|
|
|
@ -0,0 +1,60 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="de" dir="ltr" xmlns:th="http://www.thymeleaf.org">
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=0.75, user-scalable=no">
|
||||
|
||||
<title>Cronjobs</title>
|
||||
<script th:src="@{/js/filterTable.js}"></script>
|
||||
<link rel="stylesheet" th:href="@{/css/ecom.css}"/>
|
||||
<link rel="stylesheet" th:href="@{/css/manual-cronjobs.css}"/>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<nav th:replace="fragments/header :: header">Header</nav>
|
||||
<div class="sidebar-layout content-width">
|
||||
<nav></nav>
|
||||
<div>
|
||||
<h1>Cronjobs</h1>
|
||||
</div>
|
||||
</div>
|
||||
<main class="sidebar-layout content-width">
|
||||
<nav th:replace="fragments/intern :: sidebar"></nav>
|
||||
<div class="content-width">
|
||||
<h3>Manuelle Ausführung von Cronjobs</h3>
|
||||
<div class="alert"><span>
|
||||
WARNUNG<br>
|
||||
Manuelles Triggern von Cronjobs kann zu unerwartetem Verhalten führen!<br>
|
||||
Diese Seite ist nur für Debugging-Zwecke gedacht.
|
||||
</span></div>
|
||||
|
||||
<p>
|
||||
<table id="main-table">
|
||||
<tr>
|
||||
<th colspan="7">
|
||||
<input type="text" placeholder="Filtern" class="smaller jsFilterTable full-width"
|
||||
data-target-id="main-table"></input>
|
||||
</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Cronjob</th>
|
||||
<th></th>
|
||||
</tr>
|
||||
<tr th:each="job: ${jobs}">
|
||||
<td th:text="${job.visibleName}"></td>
|
||||
<td>
|
||||
<form th:action="@{/intern/cronjobs/run/{identifier}(identifier = ${job.identifier})}" method="post">
|
||||
<input class="button smaller" type="submit" value="Ausführen" />
|
||||
</form>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</p>
|
||||
|
||||
</div>
|
||||
</main>
|
||||
<footer th:replace="fragments/footer :: footer"></footer>
|
||||
</body>
|
||||
|
||||
</html>
|
Reference in New Issue