terminado eliminar y corregido bug en ordenación por id

This commit is contained in:
2025-09-28 14:07:05 +02:00
parent 50599cf33e
commit 22198b4f25
6 changed files with 47 additions and 13 deletions

View File

@ -103,7 +103,7 @@ public class SecurityConfig {
.loginProcessingUrl("/login") .loginProcessingUrl("/login")
.usernameParameter("username") .usernameParameter("username")
.passwordParameter("password") .passwordParameter("password")
.defaultSuccessUrl("/", true) .defaultSuccessUrl("/", false)
.failureUrl("/login?error") // útil para diagnosticar .failureUrl("/login?error") // útil para diagnosticar
) )

View File

@ -35,7 +35,7 @@ public class User {
@Column(name = "enabled") @Column(name = "enabled")
private boolean enabled; private boolean enabled;
@ManyToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL) @ManyToMany(fetch = FetchType.EAGER)
@JoinTable(name = "users_roles", joinColumns = @JoinColumn(name = "user_id"), inverseJoinColumns = @JoinColumn(name = "role_id")) @JoinTable(name = "users_roles", joinColumns = @JoinColumn(name = "user_id"), inverseJoinColumns = @JoinColumn(name = "role_id"))
private Set<Role> roles = new java.util.HashSet<>(); private Set<Role> roles = new java.util.HashSet<>();

View File

@ -1,6 +1,7 @@
package com.imprimelibros.erp.users; package com.imprimelibros.erp.users;
import com.imprimelibros.erp.datatables.DataTablesResponse; import com.imprimelibros.erp.datatables.DataTablesResponse;
import com.imprimelibros.erp.i18n.TranslationService;
import com.imprimelibros.erp.users.validation.UserForm; import com.imprimelibros.erp.users.validation.UserForm;
import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletRequest;
@ -22,7 +23,6 @@ import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.security.core.Authentication; import org.springframework.security.core.Authentication;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.security.crypto.password.PasswordEncoder;
import com.imprimelibros.erp.datatables.DataTablesRequest; import com.imprimelibros.erp.datatables.DataTablesRequest;
@ -32,7 +32,6 @@ import com.imprimelibros.erp.datatables.DataTable;
import java.util.Map; import java.util.Map;
import java.util.Optional; import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import java.util.List; import java.util.List;
import java.util.Locale; import java.util.Locale;
@ -51,19 +50,35 @@ public class UserController {
private MessageSource messageSource; private MessageSource messageSource;
private Sanitizer sanitizer; private Sanitizer sanitizer;
private PasswordEncoder passwordEncoder; private PasswordEncoder passwordEncoder;
private TranslationService translationService;
public UserController(UserDao repo, UserService userService, MessageSource messageSource, Sanitizer sanitizer, public UserController(UserDao repo, UserService userService, MessageSource messageSource, Sanitizer sanitizer,
PasswordEncoder passwordEncoder, RoleDao roleRepo) { PasswordEncoder passwordEncoder, RoleDao roleRepo, TranslationService translationService) {
this.repo = repo; this.repo = repo;
this.messageSource = messageSource; this.messageSource = messageSource;
this.sanitizer = sanitizer; this.sanitizer = sanitizer;
this.roleRepo = roleRepo; this.roleRepo = roleRepo;
this.passwordEncoder = passwordEncoder; this.passwordEncoder = passwordEncoder;
this.translationService = translationService;
} }
@GetMapping @GetMapping
public String list(Model model, Authentication authentication, Locale locale) { public String list(Model model, Authentication authentication, Locale locale) {
List<String> keys = List.of(
"usuarios.delete.title",
"usuarios.delete.text",
"usuarios.eliminar",
"usuarios.delete.button",
"app.yes",
"app.cancelar",
"usuarios.delete.ok.title",
"usuarios.delete.ok.text"
);
Map<String, String> translations = translationService.getTranslations(locale, keys);
model.addAttribute("languageBundle", translations);
return "imprimelibros/users/users-list"; return "imprimelibros/users/users-list";
} }
@ -79,7 +94,7 @@ public class UserController {
// Si 'role' es relación, sácalo de aquí: // Si 'role' es relación, sácalo de aquí:
List<String> searchable = List.of("fullName", "userName", "enabled", "rolesConcat"); // <- busca por roles de List<String> searchable = List.of("fullName", "userName", "enabled", "rolesConcat"); // <- busca por roles de
// verdad // verdad
List<String> orderable = List.of("fullName", "userName", "enabled", "roleRank"); // <- permite ordenar por estas List<String> orderable = List.of("id", "fullName", "userName", "enabled", "roleRank"); // <- permite ordenar por estas
// columnas // columnas
Specification<User> base = (root, query, cb) -> cb.conjunction(); Specification<User> base = (root, query, cb) -> cb.conjunction();

View File

@ -47,3 +47,8 @@ usuarios.error.delete-self=No se puede eliminar a sí mismo.
usuarios.exito.creado=Usuario creado con éxito. usuarios.exito.creado=Usuario creado con éxito.
usuarios.exito.actualizado=Usuario actualizado con éxito. usuarios.exito.actualizado=Usuario actualizado con éxito.
usuarios.exito.eliminado=Usuario eliminado con éxito. usuarios.exito.eliminado=Usuario eliminado con éxito.
usuarios.delete.title=Eliminar usuario
usuarios.delete.button=Si, ELIMINAR
usuarios.delete.text=¿Está seguro de que desea eliminar al usuario?<br>Esta acción no se puede deshacer.
usuarios.delete.ok.title=Usuario eliminado
usuarios.delete.ok.text=El usuario ha sido eliminado con éxito.

View File

@ -84,13 +84,17 @@ $(() => {
const id = $(this).data('id'); const id = $(this).data('id');
Swal.fire({ Swal.fire({
title: '¿Eliminar usuario?', title: window.languageBundle.get(['usuarios.delete.title']) || 'Eliminar usuario',
text: 'Esta acción no se puede deshacer.', html: window.languageBundle.get(['usuarios.delete.text']) || 'Esta acción no se puede deshacer.',
icon: 'warning', icon: 'warning',
showCancelButton: true, showCancelButton: true,
confirmButtonText: 'Sí, eliminar', buttonsStyling: false,
cancelButtonText: 'Cancelar', customClass: {
reverseButtons: true confirmButton: 'btn btn-danger w-xs mt-2',
cancelButton: 'btn btn-light w-xs mt-2'
},
confirmButtonText: window.languageBundle.get(['usuarios.delete.button']) || 'Eliminar',
cancelButtonText: window.languageBundle.get(['app.cancelar']) || 'Cancelar',
}).then((result) => { }).then((result) => {
if (!result.isConfirmed) return; if (!result.isConfirmed) return;
@ -98,7 +102,14 @@ $(() => {
url: '/users/' + id, url: '/users/' + id,
type: 'DELETE', type: 'DELETE',
success: function () { success: function () {
Swal.fire({ icon: 'success', title: 'Eliminado', timer: 1200, showConfirmButton: false }); Swal.fire({
icon: 'success', title: window.languageBundle.get(['usuarios.delete.ok.title']) || 'Eliminado',
text: window.languageBundle.get(['usuarios.delete.ok.text']) || 'El usuario ha sido eliminado con éxito.',
showConfirmButton: true,
customClass: {
confirmButton: 'btn btn-secondary w-xs mt-2',
},
});
$('#users-datatable').DataTable().ajax.reload(null, false); $('#users-datatable').DataTable().ajax.reload(null, false);
}, },
error: function (xhr) { error: function (xhr) {

View File

@ -85,6 +85,9 @@
<th:block layout:fragment="modal" /> <th:block layout:fragment="modal" />
<th:block th:replace="~{theme/partials/vendor-scripts :: scripts}" /> <th:block th:replace="~{theme/partials/vendor-scripts :: scripts}" />
<th:block layout:fragment="pagejs"> <th:block layout:fragment="pagejs">
<script th:inline="javascript">
window.languageBundle = /*[[${languageBundle}]]*/ {};
</script>
<script th:src="@{/assets/libs/datatables/datatables.min.js}"></script> <script th:src="@{/assets/libs/datatables/datatables.min.js}"></script>
<script th:src="@{/assets/libs/datatables/dataTables.bootstrap5.min.js}"></script> <script th:src="@{/assets/libs/datatables/dataTables.bootstrap5.min.js}"></script>
<script th:src="@{/assets/js/pages/imprimelibros/users/list.js}"></script> <script th:src="@{/assets/js/pages/imprimelibros/users/list.js}"></script>