Browse Source

masi error validasi

athrainsky 1 year ago
parent
commit
930fe50308
26 changed files with 635 additions and 131 deletions
  1. 11 2
      pom.xml
  2. 0 1
      src/main/kotlin/com/server/alb/configs/MvcConfig.kt
  3. 8 6
      src/main/kotlin/com/server/alb/configs/WebSecurityConfig.kt
  4. 222 50
      src/main/kotlin/com/server/alb/controllers/BugController.kt
  5. 0 1
      src/main/kotlin/com/server/alb/models/ListBug.kt
  6. 12 2
      src/main/kotlin/com/server/alb/models/Project.kt
  7. 11 1
      src/main/kotlin/com/server/alb/models/User.kt
  8. 24 0
      src/main/kotlin/com/server/alb/models/UserRole.kt
  9. 2 2
      src/main/kotlin/com/server/alb/repositories/ListBugRepository.kt
  10. 3 5
      src/main/kotlin/com/server/alb/repositories/PlatformRepository.kt
  11. 6 2
      src/main/kotlin/com/server/alb/repositories/ProjectRepository.kt
  12. 7 0
      src/main/kotlin/com/server/alb/repositories/RoleRepository.kt
  13. 3 2
      src/main/kotlin/com/server/alb/repositories/UserRepository.kt
  14. 0 18
      src/main/kotlin/com/server/alb/services/PlatformService.kt
  15. 9 0
      src/main/kotlin/com/server/alb/services/ProjectService.kt
  16. 16 5
      src/main/kotlin/com/server/alb/services/UserService.kt
  17. 34 0
      src/main/resources/templates/add_proj.html
  18. 5 3
      src/main/resources/templates/edit_bug.html
  19. 39 0
      src/main/resources/templates/edit_proj.html
  20. 50 0
      src/main/resources/templates/edit_user.html
  21. 11 12
      src/main/resources/templates/inPro.html
  22. 10 12
      src/main/resources/templates/index.html
  23. 4 7
      src/main/resources/templates/login.html
  24. 55 0
      src/main/resources/templates/projList.html
  25. 42 0
      src/main/resources/templates/reg.html
  26. 51 0
      src/main/resources/templates/userList.html

+ 11 - 2
pom.xml

@@ -54,7 +54,11 @@
 			<groupId>org.thymeleaf.extras</groupId>
 			<artifactId>thymeleaf-extras-springsecurity6</artifactId>
 		</dependency>
-
+<!--		<dependency>-->
+<!--			<groupId>org.hibernate</groupId>-->
+<!--			<artifactId>hibernate-validator</artifactId>-->
+<!--			<version>6.0.10.Final</version>-->
+<!--		</dependency>-->
 		<dependency>
 			<groupId>com.mysql</groupId>
 			<artifactId>mysql-connector-j</artifactId>
@@ -70,7 +74,12 @@
 			<artifactId>spring-security-test</artifactId>
 			<scope>test</scope>
 		</dependency>
-	</dependencies>
+        <dependency>
+            <groupId>org.hibernate.orm</groupId>
+            <artifactId>hibernate-core</artifactId>
+            <version>6.2.9.Final</version>
+        </dependency>
+    </dependencies>
 
 	<build>
 		<sourceDirectory>${project.basedir}/src/main/kotlin</sourceDirectory>

+ 0 - 1
src/main/kotlin/com/server/alb/configs/MvcConfig.kt

@@ -10,6 +10,5 @@ class MvcConfig : WebMvcConfigurer {
     override fun addViewControllers(registry: ViewControllerRegistry) {
         registry.addViewController("/403").setViewName("403")
         registry.addViewController("/login").setViewName("login")
-        registry.addViewController("/inPro").setViewName("inPro")
     }
 }

+ 8 - 6
src/main/kotlin/com/server/alb/configs/WebSecurityConfig.kt

@@ -20,13 +20,15 @@ class WebSecurityConfig {
     @Throws(Exception::class)
     fun securityFilterChain(http: HttpSecurity): SecurityFilterChain {
         http.authorizeHttpRequests { requests ->
-            requests.requestMatchers("/").hasAnyAuthority("QC", "PROGRAMMER", "ADMIN")
-            requests.requestMatchers("/inPro").hasAnyAuthority("QC", "PROGRAMMER", "ADMIN")
-            requests.requestMatchers("/new").hasAnyAuthority("ADMIN", "QC")
-            requests.requestMatchers("/edit/**").hasAnyAuthority("ADMIN", "QC", "PROGRAMMER")
-            requests.requestMatchers("/delete/**").hasAnyAuthority("ADMIN", "QC").anyRequest().authenticated()
+            requests.requestMatchers("/reg", "/login").permitAll()
+            requests.requestMatchers("/index/**", "/inPro/**", "/userList", "/proj")
+                .hasAnyAuthority("QC", "PROGRAMMER", "ADMIN")
+            requests.requestMatchers("/userList/edit/**", "/userList/delete/**", "/projNew", "/proj/edit/**")
+                .hasAnyAuthority("ADMIN")
+            requests.requestMatchers("/new", "/edit/**", "/delete/**").hasAnyAuthority("ADMIN", "QC").anyRequest()
+                .authenticated()
         }.formLogin { form ->
-            form.loginPage("/login").permitAll().defaultSuccessUrl("/")
+            form.loginPage("/login").permitAll().successForwardUrl("/proj")
         }.logout { logout ->
             logout.permitAll()
         }.exceptionHandling { customizer ->

+ 222 - 50
src/main/kotlin/com/server/alb/controllers/BugController.kt

@@ -1,19 +1,19 @@
 package com.server.alb.controllers
 
 import com.server.alb.models.*
-import com.server.alb.repositories.ListBugRepository
-import com.server.alb.repositories.PlatformRepository
-import com.server.alb.repositories.ProjectRepository
-import com.server.alb.repositories.UserRepository
+import com.server.alb.repositories.*
 import com.server.alb.services.BugService
 import com.server.alb.services.BugValidationService.Companion.isValid
-import com.server.alb.services.PlatformService
+import com.server.alb.services.ProjectService
 import com.server.alb.services.UserService
 import jakarta.servlet.http.HttpServletRequest
+import jakarta.validation.ConstraintViolation
 import jakarta.validation.Valid
+import jakarta.validation.Validator
 import org.springframework.security.authentication.AnonymousAuthenticationToken
 import org.springframework.security.core.Authentication
 import org.springframework.security.core.context.SecurityContextHolder
+import org.springframework.security.crypto.password.PasswordEncoder
 import org.springframework.stereotype.Controller
 import org.springframework.ui.Model
 import org.springframework.validation.BindingResult
@@ -29,53 +29,159 @@ class BugController(
     private val listBugRepository: ListBugRepository,
     private val projectRepository: ProjectRepository,
     private val platformRepository: PlatformRepository,
-    private val service: BugService,
-    private val serUser: UserService,
-    private val serPlatform: PlatformService
+    private val roleRepository: RoleRepository,
+    private val bugService: BugService,
+    private val userService: UserService,
+    private val projectService: ProjectService,
+    private val passwordEncoder: PasswordEncoder,
+    private val validator: Validator
 ) {
     val qcResultType = Status.QCResultType.values()
     val worList = Status.WorkedType.values()
     val wStList = Status.WorkedStatusType.values()
     val dStList = Status.DevStatusType.values()
-    val project: MutableIterable<Project> = this.projectRepository.findAll()
-    var proj1: String = "1"
-    var platform: MutableIterable<Platform> = this.platformRepository.findAll()
-    val user: MutableIterable<User> = this.userRepository.findAll()
+
+    private fun getProject(): MutableList<Project> {
+        return this.projectRepository.findAll()
+    }
+
+    private fun getPlatform(): MutableList<Platform> {
+        return this.platformRepository.findAll()
+    }
+
+    private fun getUser(): MutableList<User> {
+        return this.userRepository.findAll()
+    }
+
+    private fun getRole(): MutableList<Role> {
+        return this.roleRepository.findAll()
+    }
 
     @GetMapping(value = ["/login"])
     fun showLoginForm(model: Model): String {
         val authentication: Authentication? = SecurityContextHolder.getContext().authentication
         return if (authentication == null || authentication is AnonymousAuthenticationToken) {
             "login"
-        } else "redirect:/inPro"
+        } else "redirect:/proj"
+    }
+
+    @GetMapping(value = ["/reg"])
+    fun showRegister(model: Model): String {
+        val userRole = UserRole()
+        model.addAttribute("userRole", userRole)
+        model.addAttribute("role", getRole())
+        //println(1)
+        return "reg"
     }
 
-    @RequestMapping(value = ["/"])
-    fun viewHomePage(model: Model, pForm: String? = "", programmer: String? = "", proj: String? = proj1): String {
-        val listBugs = this.listBugRepository.done(pForm ?: "", programmer ?: "", proj ?: proj1).sortedBy { it.date }
+    @PostMapping(value = ["/reg"])
+    fun saveRegister(
+        @Valid @ModelAttribute("userRole") userRole: UserRole, model: Model, bindingResult: BindingResult,
+        redirectAttributes: RedirectAttributes,
+    ): String {//println(2)
+        //todo validasi user kosong
+        val newUser = User()
+        newUser.username = userRole.username
+        newUser.password = passwordEncoder.encode(userRole.password)
+        newUser.roles = userRole.role
+        newUser.isEnabled = true
+        println(newUser)
+        val result: Set<ConstraintViolation<UserRole>> = validator.validate(userRole)
+        return if (result.isNotEmpty()) {
+            model.addAttribute("role", getRole())
+            "reg"
+        } else {
+            userRepository.save(newUser)
+            redirectAttributes.addFlashAttribute("successMessage", "Success save user")
+            return "redirect:/login"
+        }
+//        return if (bindingResult.hasErrors()) {
+//            model.addAttribute("role", getRole())
+//            "reg"
+//        } else {
+//            userRepository.save(newUser)
+//            redirectAttributes.addFlashAttribute("successMessage", "Success save User")
+//            "redirect:/login"
+//        }
+    }
+
+    @RequestMapping(value = ["/userList"])
+    fun viewUser(model: Model): String {
+        model.addAttribute("user", getUser())
+        return "userList"
+    }
+
+    @RequestMapping(value = ["/proj"])
+    fun viewProject(model: Model): String {
+        model.addAttribute("project", getProject())
+        return "projList"
+    }
+
+    @GetMapping(value = ["/projNew"])
+    fun addProject(model: Model): String {
+        val project = Project()
         model.addAttribute("project", project)
-        model.addAttribute("platform", platform)
-        model.addAttribute("user", user)
+        return "add_proj"
+    }
+
+    @PostMapping(value = ["/projNew"])
+    fun saveProject(
+        @Valid @ModelAttribute("project") project: Project, model: Model, bindingResult: BindingResult,
+        redirectAttributes: RedirectAttributes,
+    ): String {
+        //todo validasi save project
+        println(bindingResult)
+        return if (bindingResult.hasErrors()) {
+            model.addAttribute("project", project)
+            println(project)
+            "add_proj"
+        } else {
+            projectRepository.save(project)
+            redirectAttributes.addFlashAttribute("successMessage", "Success save project")
+            return "redirect:/proj"
+        }
+    }
+
+    @RequestMapping(value = ["/index/{proj}"])
+    fun viewHomePage(
+        model: Model,
+        pForm: String? = "",
+        programmer: String? = "",
+        @PathVariable(name = "proj") proj: String,
+        request: HttpServletRequest
+    ): String {
+        val listBugs = this.listBugRepository.done(pForm ?: "", programmer ?: "", proj).sortedBy { it.date }
+        val url = request.requestURL.split("/")
+        model.addAttribute("project", url.last())
+        model.addAttribute("platform", getPlatform())
+        model.addAttribute("user", getUser())
         model.addAttribute("listBugs", listBugs)
         return "index"
     }
 
-    @RequestMapping(value = ["/inPro"])
-    fun viewInProgress(model: Model, pForm: String? = "", programmer: String? = "", proj: String? = proj1): String {
-        val listBugs = this.listBugRepository.inPro(pForm ?: "", programmer ?: "", proj ?: proj1).sortedBy { it.date }
-        model.addAttribute("project", project)
-        model.addAttribute("platform", platform)
-        model.addAttribute("user", user)
+    @RequestMapping(value = ["/inPro/{proj}"])
+    fun viewInProgress(
+        model: Model,
+        pForm: String? = "",
+        programmer: String? = "",
+        @PathVariable(name = "proj") proj: String,
+        request: HttpServletRequest
+    ): String {
+        val listBugs = this.listBugRepository.inPro(pForm ?: "", programmer ?: "", proj).sortedBy { it.date }
+        val url = request.requestURL.split("/")
+        model.addAttribute("project", url.last())
+        model.addAttribute("platform", getPlatform())
+        model.addAttribute("user", getUser())
         model.addAttribute("listBugs", listBugs)
         return "inPro"
     }
 
     @GetMapping(value = ["/new"])
-    fun showNewBugForm(model: Model, proj: String? = proj1): String {
+    fun showNewBugForm(model: Model): String {
         val bug = ListBug()
         model.addAttribute("bug", bug)
-        model.addAttribute("user", user)
-        model.addAttribute("platform", platform)
+        model.addAttribute("user", getUser())
+        model.addAttribute("platform", getPlatform())
         model.addAttribute("qcResultType", qcResultType)
         return "add_bug"
     }
@@ -85,8 +191,7 @@ class BugController(
         @Valid @ModelAttribute("bug") bug: ListBug,
         bindingResult: BindingResult,
         redirectAttributes: RedirectAttributes,
-        model: Model,
-        proj: String? = proj1
+        model: Model
     ): String {
         if (bug.qcId == null) {
             val myUserDetails = SecurityContextHolder.getContext().authentication.name
@@ -96,15 +201,17 @@ class BugController(
             }
         }
         println(bug)
+        println(bindingResult)
         return if (bindingResult.hasErrors()) {
-            model.addAttribute("user", user)
-            model.addAttribute("platform", platform)
+            model.addAttribute("user", getUser())
+            model.addAttribute("platform", getPlatform())
             model.addAttribute("qcResultType", qcResultType)
             "add_bug"
         } else {
-            service.save(bug)
+            bugService.save(bug)
+            val project = this.projectRepository.findProjectById(bug.id.toString())
             redirectAttributes.addFlashAttribute("successMessage", "Success save bug")
-            "redirect:/inPro"
+            "redirect:/inPro/$project"
         }
     }
 
@@ -113,9 +220,10 @@ class BugController(
         @Valid @ModelAttribute("bug") bug: ListBug,
         redirectAttributes: RedirectAttributes,
         result: BindingResult,
-        request: HttpServletRequest
+        request: HttpServletRequest,
     ): String {
         val referer: String = request.getHeader("Referer")
+        val url = referer.split("=")
         if (bug.qcId == null) {
             val myUserDetails = SecurityContextHolder.getContext().authentication.name
             val userLogin = userRepository.findByUsername(myUserDetails)
@@ -124,25 +232,46 @@ class BugController(
             }
         }
         val successMessage: String = if (isValid(bug)) {
-            service.save(bug)
+            bugService.save(bug)
             "Success save bug"
         } else {
             "Failed ! Please try again"
         }
         redirectAttributes.addFlashAttribute("successMessage", successMessage)
-        return if (referer.endsWith("=index")) "redirect:/" else "redirect:/inPro"
+        return if (referer.endsWith("=index")) "redirect:/" + url.last() else "redirect:/" + url.last()
+    }
+
+    @RequestMapping(value = ["/saveUser"], method = [RequestMethod.POST])
+    fun saveUserEdit(@Valid @ModelAttribute("userRole") userRole: UserRole): String {
+        val existUser = userService[userRole.id]
+        val editUser = User()
+        editUser.id = userRole.id
+        editUser.username = userRole.username
+        editUser.password = passwordEncoder.encode(userRole.password)
+        editUser.roles = userRole.role
+        editUser.isEnabled = true
+        if (userService.checkIfValidOldPassword(userRole.oldPass, existUser.password)) {
+            userService.save(editUser)
+        }
+        return "redirect:/userList"
+    }
+
+    @RequestMapping(value = ["/saveProj"], method = [RequestMethod.POST])
+    fun saveProjEdit(@Valid @ModelAttribute("project") project: Project): String {
+        projectService.save(project)
+        return "redirect:/proj"
     }
 
     @RequestMapping("/edit/{id}")
-    fun showEditBugForm(@PathVariable(name = "id") id: Long, @RequestParam page: String): ModelAndView {
+    fun showEditBugForm(
+        @PathVariable(name = "id") id: Long,
+        @RequestParam page: String,
+    ): ModelAndView {
         val mav = ModelAndView("edit_bug")
-        val bug: ListBug = service[id]
-        val userQc: User = serUser[bug.qcId?.id]
-        val userPro: User = serUser[bug.proId?.id]
-        val plat: Platform = serPlatform[bug.platform!!.id]
-        mav.addObject("listQc", userQc)
-        mav.addObject("listPro", userPro)
-        mav.addObject("platform", plat)
+        val bug: ListBug = bugService[id]
+        mav.addObject("listQc", getUser())
+        mav.addObject("listPro", getUser())
+        mav.addObject("platform", getPlatform())
         mav.addObject("bug", bug)
         mav.addObject("worList", worList)
         mav.addObject("wStList", wStList)
@@ -151,18 +280,61 @@ class BugController(
         return mav
     }
 
+    @RequestMapping("/userList/edit/{id}")
+    fun editUser(@PathVariable(name = "id") id: Long): ModelAndView {
+        val mav = ModelAndView("edit_user")
+        val user: User = userService[id]
+        val userRole = UserRole()
+        userRole.id = user.id
+        userRole.username = user.username
+        userRole.password = user.password
+        userRole.role = user.roles
+        mav.addObject("userRole", userRole)
+        mav.addObject("role", getRole())
+        return mav
+    }
+
+    @RequestMapping("/proj/edit/{id}")
+    fun editProject(@PathVariable(name = "id") id: Long): ModelAndView {
+        val mav = ModelAndView("edit_proj")
+        val project: Project = projectService[id]
+        mav.addObject("project", project)
+        return mav
+    }
+
+    @RequestMapping("/userList/delete/{id}")
+    fun deleteUser(@PathVariable(name = "id") id: Long): String {
+        val user = userService[id]
+        userService.delete(user)
+        return "redirect:/userList"
+    }
+
+    @RequestMapping("/proj/delete/{id}")
+    fun deleteProj(@PathVariable(name = "id") id: Long): String {
+        projectService[id]
+        projectService.delete(id)
+        return "redirect:/proj"
+    }
+
     @RequestMapping("/delete/{id}")
     fun deleteBug(@PathVariable(name = "id") id: Long): String {
-        service[id]
-        service.delete(id)
-        return "redirect:/"
+        val project = this.projectRepository.findProjectById(id.toString())
+        bugService[id]
+        bugService.delete(id)
+        return "redirect:/index/$project"
     }
 
     @RequestMapping("/delete2/{id}")
     fun delete2Bug(@PathVariable(name = "id") id: Long): String {
-        service[id]
-        service.delete(id)
-        return "redirect:/inPro"
+        val project = this.projectRepository.findProjectById(id.toString())
+        bugService[id]
+        bugService.delete(id)
+        return "redirect:/inPro/$project"
+    }
+
+    @RequestMapping("/")
+    fun redirect(): String {
+        return "redirect:/proj"
     }
 
 }

+ 0 - 1
src/main/kotlin/com/server/alb/models/ListBug.kt

@@ -73,7 +73,6 @@ class ListBug {
         _displayWorkStat = Status.WorkedStatusType.valueOf(workStat).display
         _displayDevStat = Status.DevStatusType.valueOf(devStat).display
         _displayResult = Status.QCResultType.valueOf(result!!).display
-
     }
 
     override fun toString(): String {

+ 12 - 2
src/main/kotlin/com/server/alb/models/Project.kt

@@ -1,6 +1,7 @@
 package com.server.alb.models
 
 import jakarta.persistence.*
+import jakarta.validation.constraints.NotBlank
 
 @Entity
 @Table(name = "projects")
@@ -9,9 +10,18 @@ class Project {
     @Column(name = "project_id")
     @GeneratedValue(strategy = GenerationType.IDENTITY)
     var id: Long = 0
-    var name: String = ""
-    var description: String = ""
+
+//    @Max(value = 2, message = "Maksimum 2 karakter")
+    @NotBlank(message = "Project Name tidak boleh kosong")
+    var name: String? = null
+
+    @NotBlank(message = "Project Description tidak boleh kosong")
+    var description: String? = null
 
     @OneToMany(mappedBy = "project", cascade = [CascadeType.ALL], orphanRemoval = true)
     var project: List<Platform> = mutableListOf()
+
+    override fun toString(): String {
+        return ("Project [id=$id,name=$name, description=$description]")
+    }
 }

+ 11 - 1
src/main/kotlin/com/server/alb/models/User.kt

@@ -5,7 +5,7 @@ import jakarta.persistence.*
 
 @Entity
 @Table(name = "users")
-class User {
+class User() {
 
     @Id
     @Column(name = "user_id")
@@ -29,4 +29,14 @@ class User {
     @OneToMany(mappedBy = "proId", cascade = [CascadeType.ALL], orphanRemoval = true)
     var proId: List<ListBug> = mutableListOf()
 
+    @Transient
+    var roleName: Role? = null
+
+    @PostLoad
+    fun onLoad() {
+        for (role in roles) {
+            roleName = role
+        }
+    }
+
 }

+ 24 - 0
src/main/kotlin/com/server/alb/models/UserRole.kt

@@ -0,0 +1,24 @@
+package com.server.alb.models
+
+import jakarta.validation.constraints.NotBlank
+import jakarta.validation.constraints.NotNull
+
+class UserRole {
+    var id: Long = 0
+
+    @NotBlank(message = "User Name tidak boleh kosong")
+    var username: String = ""
+
+    @NotBlank(message = "Password tidak boleh kosong")
+    var password: String = ""
+
+    @NotNull(message = "Role tidak boleh kosong")
+    var role: Set<Role> = HashSet()
+    var isEnabled = false
+
+    var oldPass: String = ""
+
+    override fun toString(): String {
+        return ("UserRole [id=$id,username=$username, password=$password, isEnabled=$isEnabled, role=$role, oldPass=$oldPass]")
+    }
+}

+ 2 - 2
src/main/kotlin/com/server/alb/repositories/ListBugRepository.kt

@@ -6,9 +6,9 @@ import org.springframework.data.jpa.repository.Query
 
 interface ListBugRepository : JpaRepository<ListBug, Long> {
 
-    @Query("SELECT b.* FROM list_bug b WHERE (b.dev_stat = 'FALSE' AND b.work_stat = 'FALSE') AND platform LIKE %?1% AND pro_id LIKE %?2% AND platform IN (SELECT platform_id FROM platforms WHERE project LIKE %?3%)", nativeQuery = true)
+    @Query("SELECT b.* FROM list_bug b WHERE (b.dev_stat = 'FALSE' AND b.work_stat = 'FALSE') AND platform LIKE %?1% AND pro_id LIKE %?2% AND platform IN (SELECT platform_id FROM platforms WHERE project = ?3)", nativeQuery = true)
     fun inPro(pForm: String?, programmer: String?, project: String?): MutableList<ListBug>
 
-    @Query("SELECT b.* FROM list_bug b WHERE (b.dev_stat <> 'FALSE' OR b.work_stat <> 'FALSE') AND platform LIKE %?1% AND pro_id LIKE %?2% AND platform IN (SELECT platform_id FROM platforms WHERE project LIKE %?3%)", nativeQuery = true)
+    @Query("SELECT b.* FROM list_bug b WHERE (b.dev_stat <> 'FALSE' OR b.work_stat <> 'FALSE') AND platform LIKE %?1% AND pro_id LIKE %?2% AND platform IN (SELECT platform_id FROM platforms WHERE project = ?3)", nativeQuery = true)
     fun done(pForm: String?, programmer: String?, project: String?): MutableList<ListBug>
 }

+ 3 - 5
src/main/kotlin/com/server/alb/repositories/PlatformRepository.kt

@@ -1,11 +1,9 @@
 package com.server.alb.repositories
 
 import com.server.alb.models.Platform
-import org.springframework.data.jpa.repository.Query
-import org.springframework.data.repository.CrudRepository
+import org.springframework.data.jpa.repository.JpaRepository
+
+interface PlatformRepository : JpaRepository<Platform, Long> {
 
-interface PlatformRepository : CrudRepository<Platform, Long> {
 
-    @Query("SELECT b.* FROM platforms b WHERE b.project LIKE %?1%", nativeQuery = true)
-    fun findByProject(project: String?): MutableList<Platform>
 }

+ 6 - 2
src/main/kotlin/com/server/alb/repositories/ProjectRepository.kt

@@ -1,6 +1,10 @@
 package com.server.alb.repositories
 
 import com.server.alb.models.Project
-import org.springframework.data.repository.CrudRepository
+import org.springframework.data.jpa.repository.JpaRepository
+import org.springframework.data.jpa.repository.Query
 
-interface ProjectRepository : CrudRepository<Project, Long>
+interface ProjectRepository : JpaRepository<Project, Long> {
+    @Query("SELECT j.project_id FROM list_bug lb LEFT JOIN platforms f ON lb.platform = f.platform_id LEFT JOIN projects j ON f.project=j.project_id WHERE lb.bug_id=?1", nativeQuery = true)
+    fun findProjectById(id: String?): String
+}

+ 7 - 0
src/main/kotlin/com/server/alb/repositories/RoleRepository.kt

@@ -0,0 +1,7 @@
+package com.server.alb.repositories
+
+import com.server.alb.models.Role
+import org.springframework.data.jpa.repository.JpaRepository
+
+interface RoleRepository : JpaRepository<Role, Long> {
+}

+ 3 - 2
src/main/kotlin/com/server/alb/repositories/UserRepository.kt

@@ -1,14 +1,15 @@
 package com.server.alb.repositories
 
 import com.server.alb.models.User
+import org.springframework.data.jpa.repository.JpaRepository
 import org.springframework.data.jpa.repository.Query
-import org.springframework.data.repository.CrudRepository
 import java.util.*
 
-interface UserRepository : CrudRepository<User, Long> {
+interface UserRepository : JpaRepository<User, Long> {
 
     @Query("SELECT u FROM User u WHERE u.username = :username")
     fun getUserByUsername(username: String): User
 
     fun findByUsername(username: String): Optional<User>
+
 }

+ 0 - 18
src/main/kotlin/com/server/alb/services/PlatformService.kt

@@ -1,18 +0,0 @@
-package com.server.alb.services
-
-import com.server.alb.models.Platform
-import com.server.alb.repositories.PlatformRepository
-import org.springframework.beans.factory.annotation.Autowired
-import org.springframework.stereotype.Service
-
-
-@Service
-class PlatformService {
-    @Autowired
-    private val repo: PlatformRepository? = null
-
-    operator fun get(id: Long): Platform {
-        return repo!!.findById(id).get()
-    }
-
-}

+ 9 - 0
src/main/kotlin/com/server/alb/services/ProjectService.kt

@@ -15,4 +15,13 @@ class ProjectService {
         return repo!!.findById(id).get()
     }
 
+    fun save(project: Project?) {
+        if (project != null) {
+            repo!!.save(project)
+        }
+    }
+
+    fun delete(id: Long?) {
+        repo!!.deleteById(id!!)
+    }
 }

+ 16 - 5
src/main/kotlin/com/server/alb/services/UserService.kt

@@ -2,17 +2,28 @@ package com.server.alb.services
 
 import com.server.alb.models.User
 import com.server.alb.repositories.UserRepository
-import org.springframework.beans.factory.annotation.Autowired
+import org.springframework.security.crypto.password.PasswordEncoder
 import org.springframework.stereotype.Service
 
 
 @Service
-class UserService {
-    @Autowired
-    private val repo: UserRepository? = null
+class UserService(private val userRepository: UserRepository, private val passwordEncoder: PasswordEncoder) {
+
+    fun save(user: User?) {
+        userRepository.save(user!!)
+    }
 
     operator fun get(id: Long?): User {
-        return repo!!.findById(id!!).get()
+        return userRepository.findById(id!!).get()
+    }
+
+    fun delete(id: User) {
+        id.roles = setOf()
+        userRepository.delete(id)
+    }
+
+    fun checkIfValidOldPassword(oldPassword: String?, newPassword: String?): Boolean {
+        return passwordEncoder.matches(oldPassword, newPassword)
     }
 
 }

+ 34 - 0
src/main/resources/templates/add_proj.html

@@ -0,0 +1,34 @@
+<!DOCTYPE html>
+<html xmlns:th="http://www.thymeleaf.org">
+<head>
+    <meta charset="ISO-8859-1">
+    <title>Add Project</title>
+    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.1/dist/css/bootstrap.min.css" rel="stylesheet"
+          integrity="sha384-4bw+/aepP/YC94hEpVNVgiZdgIC5+VKNBQNGCHeKRQN+PtmoHDEXuppvnDJzQIu9" crossorigin="anonymous">
+</head>
+<body>
+<div class="container py-5 h-100">
+    <h1>Add Project</h1>
+    <br/>
+    <form action="#" th:action="@{/projNew}" th:object="${project}" method="post">
+        <table>
+            <tr>
+                <td>Project Name:</td>
+                <td><input type="text" th:field="*{name}" class="form-control"/></td>
+                <td th:if="${#fields.hasErrors('name')}" th:errors="*{name}" style="color:red">name Error</td>
+            </tr>
+            <tr>
+                <td>Description:</td>
+                <td><input type="text" th:field="*{description}" class="form-control"/></td>
+                <td th:if="${#fields.hasErrors('description')}" th:errors="*{description}" style="color:red">description Error</td>
+            </tr>
+            <tr>
+                <td colspan="2">
+                    <button type="submit">Save</button>
+                </td>
+            </tr>
+        </table>
+    </form>
+</div>
+</body>
+</html>

+ 5 - 3
src/main/resources/templates/edit_bug.html

@@ -11,6 +11,8 @@
 <div class="container py-5 h-100">
     <h1>Edit Bug</h1>
     <br/>
+    <div th:each="project: ${project}">
+    </div>
     <form action="#" th:action="@{/save}" th:object="${bug}" method="post">
         <table>
             <tr>
@@ -18,7 +20,7 @@
                 <td><input type="text" th:field="*{id}" class="form-control"/></td>
             </tr>
             <tr>
-                <td>Tanggal QC</td>
+                <td>Tanggal QC:</td>
                 <td><input type="date" pattern="dd-MM-yyyy" th:field="*{date}" class="form-control">
                 </td>
             </tr>
@@ -85,9 +87,9 @@
                 <td><input type="text" th:field="*{development}"
                            class="form-control"/></td>
             </tr>
-            <tr>
+            <tr sec:authorize="hasAnyAuthority('ADMIN', 'QC')">
                 <td>QC:</td>
-                <td sec:authorize="hasAnyAuthority('ADMIN', 'QC')">
+                <td>
                     <select th:field="*{devStat}">
                         <option th:each="dStList: ${dStList}" th:value="${dStList}"
                                 th:text="${dStList.display}"></option>

+ 39 - 0
src/main/resources/templates/edit_proj.html

@@ -0,0 +1,39 @@
+<!DOCTYPE html>
+<html xmlns:th="http://www.thymeleaf.org"
+>
+<head>
+    <meta charset="ISO-8859-1">
+    <title>Edit Project</title>
+    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.1/dist/css/bootstrap.min.css" rel="stylesheet"
+          integrity="sha384-4bw+/aepP/YC94hEpVNVgiZdgIC5+VKNBQNGCHeKRQN+PtmoHDEXuppvnDJzQIu9" crossorigin="anonymous">
+</head>
+<body>
+<div class="container py-5 h-100">
+    <h1>Edit Project</h1>
+    <br/>
+    <form action="#" th:action="@{/saveProj}" th:object="${project}" method="post">
+        <table>
+            <tr>
+                <td>Project ID:</td>
+                <td><input type="text" th:field="*{id}" class="form-control" readonly="readonly"/></td>
+            </tr>
+            <tr>
+                <td>Project Name:</td>
+                <td><input type="text" th:field="*{name}" class="form-control">
+                </td>
+            </tr>
+            <tr>
+                <td>Description:</td>
+                <td><input type="text" th:field="*{description}" class="form-control">
+                </td>
+            </tr>
+            <tr>
+                <td colspan="2">
+                    <button type="submit">Save</button>
+                </td>
+            </tr>
+        </table>
+    </form>
+</div>
+</body>
+</html>

+ 50 - 0
src/main/resources/templates/edit_user.html

@@ -0,0 +1,50 @@
+<!DOCTYPE html>
+<html xmlns:th="http://www.thymeleaf.org"
+>
+<head>
+    <meta charset="ISO-8859-1">
+    <title>Edit User</title>
+    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.1/dist/css/bootstrap.min.css" rel="stylesheet"
+          integrity="sha384-4bw+/aepP/YC94hEpVNVgiZdgIC5+VKNBQNGCHeKRQN+PtmoHDEXuppvnDJzQIu9" crossorigin="anonymous">
+</head>
+<body>
+<div class="container py-5 h-100">
+    <h1>Edit User</h1>
+    <br/>
+    <form action="#" th:action="@{/saveUser}" th:object="${userRole}" method="post">
+        <table>
+            <tr>
+                <td>User ID:</td>
+                <td><input type="text" th:field="*{id}" class="form-control" readonly="readonly"/></td>
+            </tr>
+            <tr>
+                <td>User Name:</td>
+                <td><input type="text" th:field="*{username}" class="form-control">
+                </td>
+            </tr>
+            <tr>
+                <td>Old Password:</td>
+                <td><input id="oldPass" type="password" th:field="*{oldPass}" class="form-control">
+                </td>
+            </tr>
+            <tr>
+                <td>New Password:</td>
+                <td><input id="password" type="password" th:field="*{password}" class="form-control">
+                </td>
+            </tr>
+            <tr>
+                <td>Role:</td>
+                <td><select th:field="*{role}">
+                    <option th:each="role: ${role}" th:value="${role.id}" th:text="${role.name}"></option>
+                </select></td>
+            </tr>
+            <tr>
+                <td colspan="2">
+                    <button type="submit">Save</button>
+                </td>
+            </tr>
+        </table>
+    </form>
+</div>
+</body>
+</html>

+ 11 - 12
src/main/resources/templates/inPro.html

@@ -8,12 +8,14 @@
           integrity="sha384-4bw+/aepP/YC94hEpVNVgiZdgIC5+VKNBQNGCHeKRQN+PtmoHDEXuppvnDJzQIu9" crossorigin="anonymous">
 </head>
 <body>
+
 <div>
     <div class="text-center">
         <div sec:authorize="isAuthenticated()">
             Welcome <b><span sec:authentication="name">Username</span></b>
             &nbsp;
             <i><span sec:authentication="principal.authorities">Roles</span></i>
+            <a href="/proj">List Project</a>
         </div>
 
         <form th:action="@{/logout}" method="post">
@@ -22,18 +24,15 @@
 
         <h1>Aplikasi List Bug</h1>
         <div sec:authorize="hasAnyAuthority('QC', 'ADMIN')">
-            <a href="new">Add New Bug</a>
-<!--            <form th:action="@{'/new?proj=${project.id}'}"><input type="submit" value="Add New Bug"/></form>-->
+            <a href="/new">Add New Bug</a>
         </div>
-        <div>
-            List InProgress | <a href="/">List Done</a>
+        <div th:each="project: ${project}">
+            List InProgress | <a  th:href="@{'/index/' + ${project}}">List Done</a>
         </div>
         <span th:text="${successMessage}" style="color:green"></span>
-        <form th:action="@{'/inPro' + '?pForm=${platform.id}&programmer=${user.id}&proj=${project.id}'}">
-            <div>Project <select name="proj">
-                <option value="">Pilih</option>
-                <option th:each="project: ${project}" th:value="${project.id}" th:text="${project.name}"/>
-            </select> | Platform <select name="pForm">
+        <form th:action="@{'/inPro/' + ${project} + '?pForm=${platform.id}&programmer=${user.id}'}">
+            <div>
+                Platform <select name="pForm">
                 <option value="">Pilih</option>
                 <option th:each="platform: ${platform}" th:value="${platform.id}" th:text="${platform.name}"/>
             </select> | Programmer <select name="programmer">
@@ -60,7 +59,7 @@
             <th scope="col">QC</th>
             <th scope="col">Development</th>
             <th scope="col">QC</th>
-            <th scope="col">Actions</th>
+            <th scope="col" sec:authorize="hasAnyAuthority('ADMIN', 'QC')">Actions</th>
         </tr>
         </thead>
         <tbody>
@@ -79,8 +78,8 @@
             <td th:text="${bug.development}">Development</td>
             <td th:text="${bug._displayDevStat}">QC</td>
             <td sec:authorize="hasAnyAuthority('ADMIN', 'QC')">
-                <a th:href="@{'/edit/' + ${bug.id} + '?page=inPro'}">Edit</a> &nbsp;&nbsp;&nbsp;&nbsp;
-                <a sec:authorize="hasAnyAuthority('ADMIN', 'QC')" th:href="@{'/delete2/' + ${bug.id}}">Delete</a>
+                <a th:href="@{'/edit/' + ${bug.id} + '?page=inPro' +${project}}">Edit</a> &nbsp;&nbsp;&nbsp;&nbsp;
+                <a th:href="@{'/delete2/' + ${bug.id}}">Delete</a>
             </td>
         </tr>
         </tbody>

+ 10 - 12
src/main/resources/templates/index.html

@@ -14,6 +14,7 @@
             Welcome <b><span sec:authentication="name">Username</span></b>
             &nbsp;
             <i><span sec:authentication="principal.authorities">Roles</span></i>
+            <a href="/proj">List Project</a>
         </div>
 
         <form th:action="@{/logout}" method="post">
@@ -22,18 +23,15 @@
 
         <h1>Aplikasi List Bug</h1>
         <div sec:authorize="hasAnyAuthority('QC', 'ADMIN')">
-            <a href="new">Add New Bug</a>
-<!--            <form th:action="@{'/new?proj=${project.id}'}"><input type="submit" value="Add New Bug"/></form>-->
+            <a href="/new">Add New Bug</a>
         </div>
-        <div>
-            <a href="inPro">List InProgress</a> | List Done
+        <div th:each="project: ${project}">
+            <a th:href="@{'/inPro/' + ${project}}">List InProgress</a> | List Done
         </div>
         <span th:text="${successMessage}" style="color:green"></span>
-        <form th:action="@{'/' + '?pForm=${platform.id}&programmer=${user.id}&proj=${project.id}'}">
-            <div>Project <select name="proj">
-                <option value="">Pilih</option>
-                <option th:each="project: ${project}" th:value="${project.id}" th:text="${project.name}"/>
-            </select> | Platform <select name="pForm">
+        <form th:action="@{'/index/' + ${project} + '?pForm=${platform.id}&programmer=${user.id}'}">
+            <div>
+                Platform <select name="pForm">
                 <option value="">Pilih</option>
                 <option th:each="platform: ${platform}" th:value="${platform.id}" th:text="${platform.name}"/>
             </select> | Programmer <select name="programmer">
@@ -60,7 +58,7 @@
             <th scope="col">QC</th>
             <th scope="col">Development</th>
             <th scope="col">QC</th>
-            <th scope="col">Actions</th>
+            <th scope="col" sec:authorize="hasAnyAuthority('ADMIN', 'QC')">Actions</th>
         </tr>
         </thead>
         <tbody>
@@ -79,8 +77,8 @@
             <td th:text="${bug.development}">Development</td>
             <td th:text="${bug._displayDevStat}">QC</td>
             <td sec:authorize="hasAnyAuthority('ADMIN', 'QC')">
-                <a th:href="@{'/edit/' + ${bug.id} + '?page=index'}">Edit</a> &nbsp;&nbsp;&nbsp;&nbsp;
-                <a sec:authorize="hasAnyAuthority('ADMIN', 'QC')" th:href="@{'/delete/' + ${bug.id}}">Delete</a>
+                <a th:href="@{'/edit/' + ${bug.id} + '?page=index/' +${project}}">Edit</a> &nbsp;&nbsp;&nbsp;&nbsp;
+                <a th:href="@{'/delete/' + ${bug.id}}">Delete</a>
             </td>
         </tr>
         </tbody>

+ 4 - 7
src/main/resources/templates/login.html

@@ -15,6 +15,7 @@
         <div th:if="${param.logout}">
             <p style="color:red">You have been logged out.</p>
         </div>
+        <span th:text="${successMessage}" style="color:green"></span>
         <form th:action="@{/login}" method="post">
             <h2 class="fw-bold mb-2 text-uppercase">Login</h2>
             <p class="text-black-50 mb-5">Please Sign In!</p>
@@ -24,13 +25,9 @@
             <div class="form-outline mb-4"><label class="form-label"> Password: <input type="password" name="password"
                                                                                        class="form-control"/> </label>
             </div>
-<!--            <div class="form-outline mb-4"><label class="form-label"> Project:-->
-<!--                <select name="proj">-->
-<!--                    <option value="">Pilih</option>-->
-<!--                    <option th:each="proj: ${proj}" th:value="${proj.id}" th:text="${proj.description}"/>-->
-<!--                </select>-->
-<!--            </label></div>-->
-            <div class="form-outline mb-4"><input type="submit" value="Sign In"/></div>
+            <div class="form-outline mb-4"><input type="submit" value="Sign In"/>
+            </div>
+            <div><a href="/reg">Register</a> </div>
 
         </form>
     </div>

+ 55 - 0
src/main/resources/templates/projList.html

@@ -0,0 +1,55 @@
+<!DOCTYPE html>
+<html lang="en" xmlns:th="http://www.thymeleaf.org"
+      xmlns:sec="https://www.thymeleaf.org/thymeleaf-extras-springsecurity5">
+<head>
+    <meta charset="UTF-8">
+    <title>Project List</title>
+    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.1/dist/css/bootstrap.min.css" rel="stylesheet"
+          integrity="sha384-4bw+/aepP/YC94hEpVNVgiZdgIC5+VKNBQNGCHeKRQN+PtmoHDEXuppvnDJzQIu9" crossorigin="anonymous">
+</head>
+<body>
+<div>
+    <div class="text-center">
+        <div sec:authorize="isAuthenticated()">
+            Welcome <b><span sec:authentication="name">Username</span></b>
+            &nbsp;
+            <i><span sec:authentication="principal.authorities">Roles</span></i>
+            <a href="/userList">List User</a>
+        </div>
+
+        <form th:action="@{/logout}" method="post">
+            <input type="submit" value="Logout"/>
+        </form>
+
+        <h1>Pilih Project</h1>
+        <div sec:authorize="hasAnyAuthority('ADMIN')">
+            <a href="/projNew">Add Project</a>
+        </div>
+        <span th:text="${successMessage}" style="color:green"></span>
+    </div>
+    <br/><br/>
+    <table class="table table table-striped">
+        <thead>
+        <tr>
+            <th scope="col">No</th>
+            <th scope="col">Name</th>
+            <th scope="col">Description</th>
+            <th scope="col">Actions</th>
+        </tr>
+        </thead>
+        <tbody>
+        <tr th:each="project : ${project}">
+            <td th:text="${project.id}">Project ID</td>
+            <td th:text="${project.name}">Name</td>
+            <td th:text="${project.description}">Description</td>
+            <td>
+                <a th:href="@{'/inPro/' + ${project.id}}">Pilih</a> &nbsp;&nbsp;&nbsp;&nbsp;
+                <a sec:authorize="hasAnyAuthority('ADMIN')" th:href="@{'/proj/edit/' + ${project.id}}">Edit</a> &nbsp;&nbsp;&nbsp;&nbsp;
+                <a sec:authorize="hasAnyAuthority('ADMIN')" th:href="@{'/proj/delete/' + ${project.id}}">Delete</a>
+            </td>
+        </tr>
+        </tbody>
+    </table>
+</div>
+</body>
+</html>

+ 42 - 0
src/main/resources/templates/reg.html

@@ -0,0 +1,42 @@
+<!DOCTYPE html>
+<html xmlns:th="http://www.thymeleaf.org">
+<head>
+    <meta charset="ISO-8859-1">
+    <title>Registration</title>
+    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.1/dist/css/bootstrap.min.css" rel="stylesheet"
+          integrity="sha384-4bw+/aepP/YC94hEpVNVgiZdgIC5+VKNBQNGCHeKRQN+PtmoHDEXuppvnDJzQIu9" crossorigin="anonymous">
+</head>
+<body>
+<div class="container py-5 h-100">
+    <h1>Add User</h1>
+    <br/>
+    <form action="#" th:action="@{/reg}" th:object="${userRole}" method="post">
+        <table>
+            <tr>
+                <td>User Name:</td>
+                <td><input type="text" th:field="*{username}" class="form-control"/></td>
+                <td th:if="${#fields.hasErrors('username')}" th:errors="*{username}" style="color:red">username Error</td>
+            </tr>
+            <tr>
+                <td>Password:</td>
+                <td><input type="password" th:field="*{password}" class="form-control"/></td>
+                <td th:if="${#fields.hasErrors('password')}" th:errors="*{password}" style="color:red">password Error</td>
+            </tr>
+            <tr>
+                <td>Role:</td>
+                <td><select th:field="*{role}">
+                    <option value="">Pilih</option>
+                    <option th:each="role: ${role}" th:value="${role.id}" th:text="${role.name}"></option>
+                    <td th:if="${#fields.hasErrors('role')}" th:errors="*{role}" style="color:red">role Error</td>
+                </select></td>
+            </tr>
+            <tr>
+                <td colspan="2">
+                    <button type="submit">Save</button>
+                </td>
+            </tr>
+        </table>
+    </form>
+</div>
+</body>
+</html>

+ 51 - 0
src/main/resources/templates/userList.html

@@ -0,0 +1,51 @@
+<!DOCTYPE html>
+<html lang="en" xmlns:th="http://www.thymeleaf.org"
+      xmlns:sec="https://www.thymeleaf.org/thymeleaf-extras-springsecurity5">
+<head>
+    <meta charset="UTF-8">
+    <title>List User</title>
+    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.1/dist/css/bootstrap.min.css" rel="stylesheet"
+          integrity="sha384-4bw+/aepP/YC94hEpVNVgiZdgIC5+VKNBQNGCHeKRQN+PtmoHDEXuppvnDJzQIu9" crossorigin="anonymous">
+</head>
+<body>
+<div>
+    <div class="text-center">
+        <div sec:authorize="isAuthenticated()">
+            Welcome <b><span sec:authentication="name">Username</span></b>
+            &nbsp;
+            <i><span sec:authentication="principal.authorities">Roles</span></i>
+            &nbsp;List User
+            <a href="/proj">List Project</a>
+        </div>
+
+        <form th:action="@{/logout}" method="post">
+            <input type="submit" value="Logout"/>
+        </form>
+
+        <h1>List User</h1>
+    </div>
+    <br/><br/>
+    <table class="table table table-striped">
+        <thead>
+        <tr>
+            <th scope="col">User ID</th>
+            <th scope="col">User Name</th>
+            <th scope="col">Role</th>
+            <th scope="col" sec:authorize="hasAnyAuthority('ADMIN')">Actions</th>
+        </tr>
+        </thead>
+        <tbody>
+        <tr th:each="user : ${user}">
+            <td th:text="${user.id}">User ID</td>
+            <td th:text="${user.username}">User Name</td>
+            <td th:text="${user.roleName.name}">Role</td>
+            <td sec:authorize="hasAnyAuthority('ADMIN')">
+                <a th:href="@{'/userList/edit/' + ${user.id}}">Edit</a> &nbsp;&nbsp;&nbsp;&nbsp;
+                <a th:href="@{'/userList/delete/' + ${user.id}}">Delete</a>
+            </td>
+        </tr>
+        </tbody>
+    </table>
+</div>
+</body>
+</html>