lesson
This commit is contained in:
		| @@ -0,0 +1,45 @@ | ||||
| package de.jottyfan.bico.modules.lesson; | ||||
|  | ||||
| import org.springframework.beans.factory.annotation.Autowired; | ||||
| import org.springframework.stereotype.Controller; | ||||
| import org.springframework.ui.Model; | ||||
| import org.springframework.web.bind.annotation.GetMapping; | ||||
| import org.springframework.web.bind.annotation.ModelAttribute; | ||||
| import org.springframework.web.bind.annotation.PathVariable; | ||||
| import org.springframework.web.bind.annotation.PostMapping; | ||||
| import org.springframework.web.bind.annotation.RequestParam; | ||||
|  | ||||
| import de.jottyfan.bico.db.tables.records.TLessonRecord; | ||||
| import de.jottyfan.bico.modules.CommonController; | ||||
| /** | ||||
|  * | ||||
|  * @author jotty | ||||
|  * | ||||
|  */ | ||||
| @Controller | ||||
| public class LessonController extends CommonController { | ||||
|  | ||||
| 	@Autowired | ||||
| 	private LessonService service; | ||||
|  | ||||
| 	@GetMapping("/lesson") | ||||
| 	public String getPerson(@RequestParam("slotId") Integer slotId, Model model) { | ||||
| 		model.addAttribute("bean", service.getLesson(slotId, true)); | ||||
| 		model.addAttribute("persons", service.getPersons()); | ||||
| 		model.addAttribute("slotDay", service.getSlotDay(slotId)); | ||||
| 		return "/lesson/item"; | ||||
| 	} | ||||
|  | ||||
| 	@PostMapping("/lesson/{id}") | ||||
| 	public String updateLesson(@PathVariable("id") Integer lessonId, @ModelAttribute("bean") TLessonRecord bean, Model model) { | ||||
| 		bean.setPkLesson(lessonId); | ||||
| 		service.updateLesson(bean); | ||||
| 		return "redirect:/sheet"; | ||||
| 	} | ||||
|  | ||||
| 	@GetMapping("/lesson/{id}/remove") | ||||
| 	public String removeLesson(@PathVariable("id") Integer lessonId) { | ||||
| 		service.removeLesson(lessonId); | ||||
| 		return "redirect:/sheet"; | ||||
| 	} | ||||
| } | ||||
| @@ -0,0 +1,100 @@ | ||||
| package de.jottyfan.bico.modules.lesson; | ||||
|  | ||||
| import static de.jottyfan.bico.db.Tables.T_LESSON; | ||||
| import static de.jottyfan.bico.db.Tables.T_PERSON; | ||||
| import static de.jottyfan.bico.db.Tables.T_SLOT; | ||||
|  | ||||
| import java.time.LocalDate; | ||||
| import java.util.List; | ||||
|  | ||||
| import org.apache.logging.log4j.LogManager; | ||||
| import org.apache.logging.log4j.Logger; | ||||
| import org.jooq.DSLContext; | ||||
| import org.jooq.DeleteConditionStep; | ||||
| import org.jooq.InsertResultStep; | ||||
| import org.jooq.Record1; | ||||
| import org.jooq.SelectConditionStep; | ||||
| import org.jooq.SelectWhereStep; | ||||
| import org.jooq.UpdateConditionStep; | ||||
| import org.springframework.beans.factory.annotation.Autowired; | ||||
| import org.springframework.stereotype.Repository; | ||||
|  | ||||
| import de.jottyfan.bico.db.tables.records.TLessonRecord; | ||||
| import de.jottyfan.bico.db.tables.records.TPersonRecord; | ||||
|  | ||||
| /** | ||||
| * | ||||
| * @author jotty | ||||
| * | ||||
| */ | ||||
| @Repository | ||||
| public class LessonRepository { | ||||
| 	private final static Logger LOGGER = LogManager.getLogger(LessonRepository.class); | ||||
|  | ||||
| 	@Autowired | ||||
| 	private DSLContext jooq; | ||||
|  | ||||
| 	public TLessonRecord getLesson(Integer slotId, Boolean createIfNecessary) { | ||||
| 		SelectConditionStep<TLessonRecord> sql = jooq | ||||
| 		// @formatter:off | ||||
| 			.selectFrom(T_LESSON) | ||||
| 			.where(T_LESSON.FK_SLOT.eq(slotId)); | ||||
| 		// @formatter:on | ||||
| 		LOGGER.trace(sql); | ||||
| 		TLessonRecord r = sql.fetchOne(); | ||||
| 		if (r == null && createIfNecessary) { | ||||
| 			InsertResultStep<TLessonRecord> sql2 = jooq | ||||
| 			// @formatter:off | ||||
| 				.insertInto(T_LESSON, | ||||
| 						        T_LESSON.FK_SLOT) | ||||
| 				.values(slotId) | ||||
| 				.returning(T_LESSON.PK_LESSON); | ||||
| 			// @formatter:on | ||||
| 			LOGGER.trace(sql); | ||||
| 			Integer pkLesson = sql2.fetchOne(T_LESSON.PK_LESSON); | ||||
| 			r = new TLessonRecord(); | ||||
| 			r.setPkLesson(pkLesson); | ||||
| 			r.setFkSlot(slotId); | ||||
| 		} | ||||
| 		return r; | ||||
| 	} | ||||
|  | ||||
| 	public List<TPersonRecord> getPersons() { | ||||
| 		SelectWhereStep<TPersonRecord> sql = jooq.selectFrom(T_PERSON); | ||||
| 		LOGGER.trace(sql); | ||||
| 		return sql.fetchStream().toList(); | ||||
| 	} | ||||
|  | ||||
| 	public LocalDate getSlotDay(Integer slotId) { | ||||
| 		SelectConditionStep<Record1<LocalDate>> sql = jooq | ||||
| 		// @formatter:off | ||||
| 			.select(T_SLOT.SLOT_DAY) | ||||
| 			.from(T_SLOT) | ||||
| 			.where(T_SLOT.PK_SLOT.eq(slotId)); | ||||
| 		// @formatter:on | ||||
| 		LOGGER.trace(sql); | ||||
| 		return sql.fetchOne(T_SLOT.SLOT_DAY); | ||||
| 	} | ||||
|  | ||||
| 	public void updateLesson(TLessonRecord bean) { | ||||
| 		UpdateConditionStep<TLessonRecord> sql = jooq | ||||
| 		// @formatter:off | ||||
| 			.update(T_LESSON) | ||||
| 			.set(T_LESSON.NOTES, bean.getNotes()) | ||||
| 			.set(T_LESSON.FK_PERSON, bean.getFkPerson()) | ||||
| 			.where(T_LESSON.PK_LESSON.eq(bean.getPkLesson())); | ||||
| 		// @formatter:on | ||||
| 		LOGGER.trace(sql); | ||||
| 		sql.execute(); | ||||
| 	} | ||||
|  | ||||
| 	public void removeLesson(Integer lessonId) { | ||||
| 		DeleteConditionStep<TLessonRecord> sql = jooq | ||||
| 		// @formatter:off | ||||
| 			.deleteFrom(T_LESSON) | ||||
| 			.where(T_LESSON.PK_LESSON.eq(lessonId)); | ||||
| 		// @formatter:on | ||||
| 		LOGGER.trace(sql); | ||||
| 		sql.execute(); | ||||
| 	} | ||||
| } | ||||
| @@ -0,0 +1,42 @@ | ||||
| package de.jottyfan.bico.modules.lesson; | ||||
|  | ||||
| import java.time.LocalDate; | ||||
| import java.util.List; | ||||
|  | ||||
| import org.springframework.beans.factory.annotation.Autowired; | ||||
| import org.springframework.stereotype.Service; | ||||
|  | ||||
| import de.jottyfan.bico.db.tables.records.TLessonRecord; | ||||
| import de.jottyfan.bico.db.tables.records.TPersonRecord; | ||||
|  | ||||
| /** | ||||
|  * | ||||
|  * @author jotty | ||||
|  * | ||||
|  */ | ||||
| @Service | ||||
| public class LessonService { | ||||
|  | ||||
| 	@Autowired | ||||
| 	private LessonRepository repository; | ||||
|  | ||||
| 	public TLessonRecord getLesson(Integer slotId, Boolean createIfNecessary) { | ||||
| 		return repository.getLesson(slotId, createIfNecessary); | ||||
| 	} | ||||
|  | ||||
| 	public List<TPersonRecord> getPersons() { | ||||
| 		return repository.getPersons(); | ||||
| 	} | ||||
|  | ||||
| 	public LocalDate getSlotDay(Integer slotId) { | ||||
| 		return repository.getSlotDay(slotId); | ||||
| 	} | ||||
|  | ||||
| 	public void updateLesson(TLessonRecord bean) { | ||||
| 		repository.updateLesson(bean); | ||||
| 	} | ||||
|  | ||||
| 	public void removeLesson(Integer lessonId) { | ||||
| 		repository.removeLesson(lessonId); | ||||
| 	} | ||||
| } | ||||
| @@ -32,6 +32,7 @@ public class SlotController extends CommonController { | ||||
| 	@GetMapping("/slot/{id}") | ||||
| 	public String load(@PathVariable Integer id, Model model) { | ||||
| 		model.addAttribute("bean", id == null ? new SlotBean() : service.loadSlot(id)); | ||||
| 		model.addAttribute("hasLesson", service.slotHasLesson(id)); | ||||
| 		return "/slot/item"; | ||||
| 	} | ||||
|  | ||||
|   | ||||
| @@ -126,4 +126,20 @@ public class SlotRepository { | ||||
| 			return null; | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	/** | ||||
| 	 * return true if this slot already has at least one lesson | ||||
| 	 * | ||||
| 	 * @param slotId the ID of the slot | ||||
| 	 * @return true or false | ||||
| 	 */ | ||||
| 	public Boolean getHasLesson(Integer slotId) { | ||||
| 		SelectConditionStep<TLessonRecord> sql = jooq | ||||
| 		// @formatter:off | ||||
| 			.selectFrom(T_LESSON) | ||||
| 			.where(T_LESSON.FK_SLOT.eq(slotId)); | ||||
| 		// @formatter:on | ||||
| 		LOGGER.trace(sql); | ||||
| 		return sql.fetch().size() > 0; | ||||
| 	} | ||||
| } | ||||
|   | ||||
| @@ -36,4 +36,8 @@ public class SlotService { | ||||
| 	public SlotBean loadDeletableSlot(Integer id) { | ||||
| 		return repository.getSlotIfDeletable(id); | ||||
| 	} | ||||
|  | ||||
| 	public Boolean slotHasLesson(Integer id) { | ||||
| 		return id == null ? false : repository.getHasLesson(id); | ||||
| 	} | ||||
| } | ||||
|   | ||||
| @@ -1,16 +1,9 @@ | ||||
| /* | ||||
| html { | ||||
| 	width: 100%; | ||||
| 	height: 100%; | ||||
| } | ||||
| */ | ||||
|  | ||||
| body { | ||||
| 	background-color: #abc; | ||||
| } | ||||
|  | ||||
| [data-bs-theme=dark] body { | ||||
| 	background-color: rgb(36, 31, 49); | ||||
| 	background-color: #001213; | ||||
| } | ||||
|  | ||||
| .borderdist { | ||||
| @@ -23,4 +16,22 @@ body { | ||||
|  | ||||
| [data-bs-theme=dark] .borderdist { | ||||
| 	background-color: #333; | ||||
| } | ||||
|  | ||||
| .headerback { | ||||
| 	background-color: #eee; | ||||
| 	border-bottom: 1px solid silver; | ||||
| } | ||||
|  | ||||
| [data-bs-theme=dark] .headerback { | ||||
| 	background-color: #333; | ||||
| } | ||||
|  | ||||
| .rightaligned { | ||||
| 	right: 5px; | ||||
| 	position: absolute; | ||||
| } | ||||
|  | ||||
| .rightpadding64 { | ||||
| 	margin-right: 64px; | ||||
| } | ||||
							
								
								
									
										41
									
								
								src/main/resources/templates/lesson/item.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										41
									
								
								src/main/resources/templates/lesson/item.html
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,41 @@ | ||||
| <!DOCTYPE html> | ||||
| <html xmlns:th="http://www.thymeleaf.org" layout:decorate="~{template}" xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout" xmlns:sec="http://www.thymeleaf.org/extras/spring-security"> | ||||
| <body> | ||||
| 	<th:block layout:fragment="content"> | ||||
| 		<div class="borderdist"> | ||||
| 			<div class="container"> | ||||
| 				<div class="row g-2"> | ||||
| 					<div class="col-sm-12"> | ||||
| 						<h2>Dozent-Reservierung</h2> | ||||
| 					</div> | ||||
| 				</div> | ||||
| 				<form th:action="@{/lesson/{id}(id=${bean.pkLesson})}" method="post" th:object="${bean}"> | ||||
| 					<div class="row g-3"> | ||||
| 						<div class="col-sm-3">Tag</div> | ||||
| 						<div class="col-sm-9"> | ||||
| 							<span th:text="${#temporals.format(slotDay, 'dd.MM.yyyy')}"></span> | ||||
| 						</div> | ||||
| 						<div class="col-sm-3">Dozent</div> | ||||
| 						<div class="col-sm-9"> | ||||
| 							<select th:field="*{fkPerson}" class="form-select"> | ||||
| 								<option value="">--- bitte wählen ---</option> | ||||
| 								<option th:each="p : ${persons}" th:value="${p.pkPerson}" th:text="${p.forename + ' ' + p.surname}"></option> | ||||
| 							</select> | ||||
| 						</div> | ||||
| 						<div class="col-sm-3">Anmerkungen</div> | ||||
| 						<div class="col-sm-9"> | ||||
| 							<textarea th:field="*{notes}" class="form-control"></textarea> | ||||
| 						</div> | ||||
| 						<div class="col-sm-3"></div> | ||||
| 						<div class="col-sm-9"> | ||||
| 							<button type="submit" class="btn btn-outline-success">Speichern</button>  | ||||
| 							<a th:href="@{/}" class="btn btn-outline-secondary">Abbrechen</a>  | ||||
| 							<a th:href="@{/lesson/{id}/remove(id=${bean.pkLesson})}" class="btn btn-outline-danger">Löschen</a> | ||||
| 						</div> | ||||
| 					</div> | ||||
| 				</form> | ||||
| 			</div> | ||||
| 		</div> | ||||
| 	</th:block> | ||||
| </body> | ||||
| </html> | ||||
| @@ -7,29 +7,26 @@ | ||||
| 				<thead> | ||||
| 					<tr> | ||||
| 						<th>Tag</th> | ||||
| 						<th>Kürzel</th> | ||||
| 						<th>Wer</th> | ||||
| 						<th>Thema</th> | ||||
| 						<th>Notiz</th> | ||||
| 						<th></th> | ||||
| 					</tr> | ||||
| 				</thead> | ||||
| 				<tbody> | ||||
| 					<tr th:each="s : ${list}"> | ||||
| 						<td><span th:text="${#temporals.format(s.slotDay, 'yyyy-MM-dd')}" th:if="${s.pkLesson}"></span> <a th:href="@{/slot/{id}(id=${s.pkSlot})}" | ||||
| 							th:text="${#temporals.format(s.slotDay, 'yyyy-MM-dd')}" class="btn btn-outline-secondary" th:unless="${s.pkLesson}"></a></td> | ||||
| 						<td><a th:href="@{/person?slotId={id}(id=${s.pkSlot})}" class="btn btn-outline-secondary"> <span th:text="${s.abbreviation}" th:if="${s.abbreviation}"></span> <i | ||||
| 						<td><span th:text="${#temporals.format(s.slotDay, 'yyyy-MM-dd')}"></span></td> | ||||
| 						<td><a th:href="@{/lesson?slotId={id}(id=${s.pkSlot})}" class="btn btn-outline-secondary"> <span th:text="${s.abbreviation}" th:if="${s.abbreviation}"></span> <i | ||||
| 								class="bi bi-pencil" th:if="${s.abbreviation == null || s.abbreviation.isBlank()}"></i> | ||||
| 						</a></td> | ||||
| 						<td th:text="${s.theme}"></td> | ||||
| 						<td><a th:href="@{/slot/{id}(id=${s.pkSlot})}" class="btn btn-outline-secondary"> <span th:text="${s.slotNotes}"></span> <i class="bi bi-pencil" | ||||
| 								th:if="${s.slotNotes == null || s.slotNotes.isBlank()}"></i> | ||||
| 						</a></td> | ||||
| 						<td> | ||||
| 						<td><div th:text="${s.theme}"></div> | ||||
| 							<div th:text="${s.subtheme}"></div></td> | ||||
| 						<td><span th:text="${s.slotNotes}" class="rightpadding64"></span><a th:href="@{/slot/{id}(id=${s.pkSlot})}" class="btn btn-outline-secondary rightaligned"><i | ||||
| 								class="bi bi-pencil"></i></a></td> | ||||
| 					</tr> | ||||
| 				</tbody> | ||||
| 				<tfoot> | ||||
| 					<tr> | ||||
| 						<td colspan="5"><a th:href="@{/slot}" class="btn btn-outline-success">einen neues Datum anlegen</a></td> | ||||
| 						<td colspan="4"><a th:href="@{/slot}" class="btn btn-outline-success">einen neues Datum anlegen</a></td> | ||||
| 					</tr> | ||||
| 				</tfoot> | ||||
| 			</table> | ||||
|   | ||||
| @@ -4,6 +4,11 @@ | ||||
| 	<th:block layout:fragment="content"> | ||||
| 		<div class="borderdist"> | ||||
| 			<div class="container"> | ||||
| 				<div class="row g-2"> | ||||
| 					<div class="col-sm-12"> | ||||
| 						<h2>Terminfestlegung</h2> | ||||
| 					</div> | ||||
| 				</div> | ||||
| 				<form th:action="@{/slot/save}" th:object="${bean}" method="post"> | ||||
| 					<input type="hidden" th:field="*{pkSlot}" /> | ||||
| 					<div class="row g-2"> | ||||
| @@ -19,7 +24,15 @@ | ||||
| 						<div class="col-sm-2"></div> | ||||
| 						<div class="col-sm-10"> | ||||
| 							<button type="submit" class="btn btn-outline-primary">Speichern</button> | ||||
| 							<a th:href="@{/slot/{id}/delete(id=${bean.pkSlot})}" class="btn btn-outline-danger" th:if="${bean.pkSlot}">Löschen</a> | ||||
| 							<th:block th:unless="${hasLesson}"> | ||||
| 								<a th:href="@{/slot/{id}/delete(id=${bean.pkSlot})}" class="btn btn-outline-danger" th:if="${bean.pkSlot}">Löschen</a> | ||||
| 							</th:block> | ||||
| 						</div> | ||||
| 						<div class="col-sm-2" th:if="${hasLesson}">Hinweis</div> | ||||
| 						<div class="col-sm-10" th:if="${hasLesson}"> | ||||
| 							<div class="alert alert-primary">Termine, die bereits für einen Dozenten reserviert wurden, können nicht gelöscht werden. | ||||
| 								<a th:href="@{/lesson?slotId={id}(id=${bean.pkSlot})}" class="btn btn-outline-secondary">Reservierung bearbeiten</a> | ||||
| 							</div> | ||||
| 						</div> | ||||
| 					</div> | ||||
| 				</form> | ||||
|   | ||||
| @@ -15,14 +15,14 @@ | ||||
| <script th:src="@{/js/stylehelp.js}"></script> | ||||
| </head> | ||||
| <body> | ||||
| 	<nav class="navbar sticky-top navbar-expand-lg headerlayout"> | ||||
| 	<nav class="navbar sticky-top navbar-expand-lg headerlayout headerback"> | ||||
| 		<button class="navbar-toggler" style="margin-right: 40px" type="button" data-bs-toggle="collapse" data-bs-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" | ||||
| 			aria-expanded="false"> | ||||
| 			<span class="navbar-toggler-icon"></span> | ||||
| 		</button> | ||||
| 		<div class="collapse navbar-collapse" id="navbarSupportedContent" style="margin-right: 20px"> | ||||
| 			<ul class="navbar-nav mb-2 mb-lg-0"> | ||||
| 				<li class="nav-item"><a class="btn btn-outline-secondary" th:href="@{/}">Startseite</a></li> | ||||
| 				<li class="nav-item"><a class="btn btn-outline-secondary" th:href="@{/}" style="margin-left: 12px">Startseite</a></li> | ||||
| 			</ul> | ||||
| 			<ul layout:fragment="header"></ul> | ||||
| 			<ul class="nav navbar-nav ms-auto"> | ||||
|   | ||||
		Reference in New Issue
	
	Block a user