From c5604d3ce87225e65ed9d9b5713298cc0b79ae59 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rg=20Henke?= Date: Thu, 15 Jan 2026 17:52:36 +0100 Subject: [PATCH] preparations for app assignment --- .../config/SecurityConfiguration.java | 2 +- .../projectmanagement/AppController.java | 44 +++++++ .../projectmanagement/AppRepository.java | 82 ++++++++++++ .../modules/projectmanagement/AppService.java | 32 +++++ .../projectmanagement/model/AppBean.java | 118 ++++++++++++++++++ src/main/resources/application.properties | 3 + src/main/resources/templates/layout/main.html | 15 ++- .../projectmanagement/app/assign.html | 19 +++ .../templates/projectmanagement/app/list.html | 46 +++++++ .../projectmanagement/dashboard.html | 14 ++- 10 files changed, 363 insertions(+), 12 deletions(-) create mode 100644 src/main/java/de/jottyfan/timetrack/modules/projectmanagement/AppController.java create mode 100644 src/main/java/de/jottyfan/timetrack/modules/projectmanagement/AppRepository.java create mode 100644 src/main/java/de/jottyfan/timetrack/modules/projectmanagement/AppService.java create mode 100644 src/main/java/de/jottyfan/timetrack/modules/projectmanagement/model/AppBean.java create mode 100644 src/main/resources/templates/projectmanagement/app/assign.html create mode 100644 src/main/resources/templates/projectmanagement/app/list.html diff --git a/src/main/java/de/jottyfan/timetrack/config/SecurityConfiguration.java b/src/main/java/de/jottyfan/timetrack/config/SecurityConfiguration.java index d0a7b6f..536c8fa 100644 --- a/src/main/java/de/jottyfan/timetrack/config/SecurityConfiguration.java +++ b/src/main/java/de/jottyfan/timetrack/config/SecurityConfiguration.java @@ -45,7 +45,7 @@ public class SecurityConfiguration { // @formatter:off .oauth2Login(o -> o.defaultSuccessUrl("/")) .logout(o -> o.logoutSuccessHandler(new OidcClientInitiatedLogoutSuccessHandler(crr))) - .authorizeHttpRequests(o -> o.requestMatchers("/public/**", "/theme/**").permitAll().anyRequest().authenticated()) + .authorizeHttpRequests(o -> o.requestMatchers("/public/**", "/theme/**", "/webjars/**").permitAll().anyRequest().authenticated()) .oauth2ResourceServer(o -> o.jwt(Customizer.withDefaults())) .sessionManagement(o -> o.init(sec)); // @formatter:on diff --git a/src/main/java/de/jottyfan/timetrack/modules/projectmanagement/AppController.java b/src/main/java/de/jottyfan/timetrack/modules/projectmanagement/AppController.java new file mode 100644 index 0000000..cb70535 --- /dev/null +++ b/src/main/java/de/jottyfan/timetrack/modules/projectmanagement/AppController.java @@ -0,0 +1,44 @@ +package de.jottyfan.timetrack.modules.projectmanagement; + +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.PathVariable; + +import de.jottyfan.timetrack.modules.CommonController; +import jakarta.annotation.security.RolesAllowed; + +/** + * + * @author jotty + * + */ +@Controller +public class AppController extends CommonController { + + @Autowired + private AppService service; + + @RolesAllowed("timetrack_user") + @GetMapping("/projectmanagement/apps") + public String getAllApps(final Model model) { + model.addAttribute("apps", service.getAppsOf(null)); + return "/projectmanagement/app/list"; + } + + @RolesAllowed("timetrack_user") + @GetMapping("/projectmanagement/workpackage/{pkWorkpackage}/apps") + public String getAppsOfWorkpackage(@PathVariable("pkWorkpackage") Integer pkWorkpackage, final Model model) { + model.addAttribute("apps", service.getAppsOf(pkWorkpackage)); + return "/projectmanagement/app/list"; + } + + @RolesAllowed("timetrack_user") + @GetMapping("/projectmanagement/app/{pkApp}/assign") + public String loadAssignmentToolForApp(@PathVariable("pkApp") Integer pkApp, final Model model) { + model.addAttribute("app", service.getApp(pkApp)); + model.addAttribute("workpackages", service.getWorkpackages()); + return "/projectmanagement/app/assign"; + } +} diff --git a/src/main/java/de/jottyfan/timetrack/modules/projectmanagement/AppRepository.java b/src/main/java/de/jottyfan/timetrack/modules/projectmanagement/AppRepository.java new file mode 100644 index 0000000..13c94b3 --- /dev/null +++ b/src/main/java/de/jottyfan/timetrack/modules/projectmanagement/AppRepository.java @@ -0,0 +1,82 @@ +package de.jottyfan.timetrack.modules.projectmanagement; + +import static de.jottyfan.timetrack.db.project.Tables.T_APP; +import static de.jottyfan.timetrack.db.project.Tables.T_WORKPACKAGE_APP; +import static de.jottyfan.timetrack.db.project.Tables.T_WORKPACKAGE; + +import java.util.List; + +import org.jooq.DSLContext; +import org.jooq.Record7; +import org.jooq.SelectConditionStep; +import org.jooq.impl.DSL; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Repository; + +import de.jottyfan.timetrack.modules.projectmanagement.model.AppBean; +import de.jottyfan.timetrack.modules.projectmanagement.model.WorkpackageBean; + +/** + * + * @author jotty + */ +@Repository +public class AppRepository { + + @Autowired + private DSLContext jooq; + + /** + * get all app beans for that workpackage + * + * @param fkWorkpackage the workpackage ID; if null, return all app beans + * @return the list of app beans; an empty list at least + */ + public List getAllAppBeans(Integer fkWorkpackage) { + SelectConditionStep> sql = jooq + // @formatter:off + .select(T_APP.PK_APP, + T_APP.FK_BUNDLE, + T_APP.BASIC_FUNCTIONALITY, + T_APP.NAME, + T_APP.DESCRIPTION, + T_APP.FK_REPLACED_BY_APP, + T_APP.REPOSITORY_URL) + .from(T_APP) + .leftJoin(T_WORKPACKAGE_APP).on(T_WORKPACKAGE_APP.FK_APP.eq(T_APP.PK_APP)) + .where(fkWorkpackage == null ? DSL.trueCondition() : T_WORKPACKAGE_APP.FK_WORKPACKAGE.eq(fkWorkpackage)); + // @formatter:on + return sql.fetchInto(AppBean.class); + } + + /** + * get the app + * + * @param pkApp the ID of the app + * @return the app bean or null + */ + public AppBean getApp(Integer pkApp) { + SelectConditionStep> sql = jooq + // @formatter:off + .select(T_APP.PK_APP, + T_APP.FK_BUNDLE, + T_APP.BASIC_FUNCTIONALITY, + T_APP.NAME, + T_APP.DESCRIPTION, + T_APP.FK_REPLACED_BY_APP, + T_APP.REPOSITORY_URL) + .from(T_APP) + .where(T_APP.PK_APP.eq(pkApp)); + // @formatter:on + return sql.fetchOneInto(AppBean.class); + } + + /** + * get all work packages + * + * @return the list; an empty list at least + */ + public List getWorkpackages() { + return jooq.selectFrom(T_WORKPACKAGE).fetchInto(WorkpackageBean.class); + } +} diff --git a/src/main/java/de/jottyfan/timetrack/modules/projectmanagement/AppService.java b/src/main/java/de/jottyfan/timetrack/modules/projectmanagement/AppService.java new file mode 100644 index 0000000..957ea4d --- /dev/null +++ b/src/main/java/de/jottyfan/timetrack/modules/projectmanagement/AppService.java @@ -0,0 +1,32 @@ +package de.jottyfan.timetrack.modules.projectmanagement; + +import java.util.List; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import de.jottyfan.timetrack.modules.projectmanagement.model.AppBean; +import de.jottyfan.timetrack.modules.projectmanagement.model.WorkpackageBean; + +/** + * + * @author jotty + * + */ +@Service +public class AppService { + @Autowired + private AppRepository repository; + + public List getAppsOf(Integer fkWorkpackage) { + return repository.getAllAppBeans(fkWorkpackage); + } + + public AppBean getApp(Integer pkApp) { + return repository.getApp(pkApp); + } + + public List getWorkpackages() { + return repository.getWorkpackages(); + } +} diff --git a/src/main/java/de/jottyfan/timetrack/modules/projectmanagement/model/AppBean.java b/src/main/java/de/jottyfan/timetrack/modules/projectmanagement/model/AppBean.java new file mode 100644 index 0000000..7d146d6 --- /dev/null +++ b/src/main/java/de/jottyfan/timetrack/modules/projectmanagement/model/AppBean.java @@ -0,0 +1,118 @@ +package de.jottyfan.timetrack.modules.projectmanagement.model; + +import java.io.Serializable; + +/** + * + * @author jotty + * + */ +public class AppBean implements Serializable { + private static final long serialVersionUID = 1L; + + private Integer pkApp; + private Integer fkBundle; + private String basicFunctionality; + private String name; + private String description; + private Integer fkReplacedByApp; + private String repositoryUrl; + + /** + * @return the pkApp + */ + public Integer getPkApp() { + return pkApp; + } + + /** + * @param pkApp the pkApp to set + */ + public void setPkApp(Integer pkApp) { + this.pkApp = pkApp; + } + + /** + * @return the fkBundle + */ + public Integer getFkBundle() { + return fkBundle; + } + + /** + * @param fkBundle the fkBundle to set + */ + public void setFkBundle(Integer fkBundle) { + this.fkBundle = fkBundle; + } + + /** + * @return the basicFunctionality + */ + public String getBasicFunctionality() { + return basicFunctionality; + } + + /** + * @param basicFunctionality the basicFunctionality to set + */ + public void setBasicFunctionality(String basicFunctionality) { + this.basicFunctionality = basicFunctionality; + } + + /** + * @return the name + */ + public String getName() { + return name; + } + + /** + * @param name the name to set + */ + public void setName(String name) { + this.name = name; + } + + /** + * @return the description + */ + public String getDescription() { + return description; + } + + /** + * @param description the description to set + */ + public void setDescription(String description) { + this.description = description; + } + + /** + * @return the fkReplacedByApp + */ + public Integer getFkReplacedByApp() { + return fkReplacedByApp; + } + + /** + * @param fkReplacedByApp the fkReplacedByApp to set + */ + public void setFkReplacedByApp(Integer fkReplacedByApp) { + this.fkReplacedByApp = fkReplacedByApp; + } + + /** + * @return the repositoryUrl + */ + public String getRepositoryUrl() { + return repositoryUrl; + } + + /** + * @param repositoryUrl the repositoryUrl to set + */ + public void setRepositoryUrl(String repositoryUrl) { + this.repositoryUrl = repositoryUrl; + } +} diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index 79aacb7..59f65e8 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -22,3 +22,6 @@ spring.security.oauth2.client.provider.keycloak.user-name-attribute = preferred_ # application server.port = ${server.port} server.servlet.context-path = /timetrack + +spring.mvc.contentnegotiation.favor-parameter=false +spring.mvc.contentnegotiation.media-types.css=text/css diff --git a/src/main/resources/templates/layout/main.html b/src/main/resources/templates/layout/main.html index 2dc451c..10f3938 100644 --- a/src/main/resources/templates/layout/main.html +++ b/src/main/resources/templates/layout/main.html @@ -8,19 +8,18 @@ - - - - - - - - + + + + + + + diff --git a/src/main/resources/templates/projectmanagement/app/assign.html b/src/main/resources/templates/projectmanagement/app/assign.html new file mode 100644 index 0000000..689d966 --- /dev/null +++ b/src/main/resources/templates/projectmanagement/app/assign.html @@ -0,0 +1,19 @@ + + + +Projektmanagement + + + Projekt + +
+
+
+ TODO: assign app to workpackage and store it +
+ + \ No newline at end of file diff --git a/src/main/resources/templates/projectmanagement/app/list.html b/src/main/resources/templates/projectmanagement/app/list.html new file mode 100644 index 0000000..d65ef38 --- /dev/null +++ b/src/main/resources/templates/projectmanagement/app/list.html @@ -0,0 +1,46 @@ + + + +Projektmanagement + + + Projekt + +
+
+ + + + + + + + + + + + + + + + + +
NameBeschreibungURL
gitlabzuordnen
+ +
+
+ + \ No newline at end of file diff --git a/src/main/resources/templates/projectmanagement/dashboard.html b/src/main/resources/templates/projectmanagement/dashboard.html index 2f27e81..0713915 100644 --- a/src/main/resources/templates/projectmanagement/dashboard.html +++ b/src/main/resources/templates/projectmanagement/dashboard.html @@ -16,19 +16,27 @@
- : - + : edit
+
+
+
Alles
+
+ alle apps +
+
+