Initial commit
This commit is contained in:
@@ -0,0 +1,96 @@
|
||||
package controllers
|
||||
|
||||
import (
|
||||
"github.com/gofiber/fiber/v2" //nolint:goimports
|
||||
"github.com/gookit/validate"
|
||||
"github.com/sujit-baniya/fiber-boilerplate/app"
|
||||
"github.com/sujit-baniya/fiber-boilerplate/pkg/auth"
|
||||
"github.com/sujit-baniya/fiber-boilerplate/pkg/models"
|
||||
"github.com/sujit-baniya/fiber-boilerplate/pkg/services"
|
||||
)
|
||||
|
||||
func OAuthToken(c *fiber.Ctx) error { //nolint:wsl
|
||||
var login models.Login
|
||||
if err := c.BodyParser(&login); err != nil {
|
||||
return c.Status(401).JSON(fiber.Map{
|
||||
"error": true,
|
||||
"message": "Invalid Credentials",
|
||||
})
|
||||
}
|
||||
|
||||
v := validate.Struct(login)
|
||||
if !v.Validate() {
|
||||
return c.Status(401).JSON(fiber.Map{
|
||||
"error": true,
|
||||
"message": v.Errors.All(),
|
||||
})
|
||||
}
|
||||
user, err := login.CheckLogin() //nolint:wsl
|
||||
if err != nil {
|
||||
return c.Status(401).JSON(fiber.Map{
|
||||
"error": true,
|
||||
"message": err.Error(),
|
||||
})
|
||||
}
|
||||
token, err := auth.Login(c, user.ID, app.Http.Token.ApiJwtSecret) //nolint:wsl
|
||||
if err != nil {
|
||||
return c.Status(401).JSON(fiber.Map{
|
||||
"error": true,
|
||||
"message": err.Error(),
|
||||
})
|
||||
}
|
||||
return c.JSON(fiber.Map{
|
||||
"token": token.Hash,
|
||||
"expires_in": token.Expire,
|
||||
})
|
||||
}
|
||||
|
||||
func ApiLoginPost(c *fiber.Ctx) error { //nolint:wsl
|
||||
// Obtener el usuario del contexto
|
||||
user, ok := c.Locals("user").(*models.User)
|
||||
if !ok || user == nil {
|
||||
return c.JSON(fiber.Map{
|
||||
"success": false,
|
||||
"message": "Usuario no encontrado o no autenticado",
|
||||
})
|
||||
}
|
||||
|
||||
// Generar el token JWT para el usuario
|
||||
token, err := auth.Login(c, user.ID, app.Http.Token.AppJwtSecret)
|
||||
if err != nil {
|
||||
return c.JSON(fiber.Map{
|
||||
"success": false,
|
||||
"message": "Error al generar el token: " + err.Error(),
|
||||
})
|
||||
}
|
||||
|
||||
// Retornar respuesta con el usuario y el token
|
||||
return c.JSON(fiber.Map{
|
||||
"success": true,
|
||||
"message": "Inicio de sesión exitoso",
|
||||
"user": user,
|
||||
"token": token,
|
||||
})
|
||||
}
|
||||
|
||||
func ApiRegisterPost(c *fiber.Ctx) error {
|
||||
register := c.Locals("register").(models.RegisterForm)
|
||||
user, err := register.Signup()
|
||||
if err != nil {
|
||||
return c.Status(fiber.StatusNotFound).JSON(fiber.Map{"error": true, "message": "Error on register request", "data": err.Error()}) //nolint:errcheck
|
||||
|
||||
}
|
||||
store := app.Http.Session.Get(c) // get/create new session
|
||||
store.Set("user_id", user.ID) // save to storage
|
||||
_ = store.Save()
|
||||
|
||||
go services.SendConfirmationEmail(user.Email, c.BaseURL(), user.NombreUsuario)
|
||||
return c.JSON(fiber.Map{
|
||||
"success": true,
|
||||
"message": "Registered successfully! Please confirm your email",
|
||||
})
|
||||
}
|
||||
|
||||
func RefreshOauthToken(c *fiber.Ctx) error {
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
package controllers
|
||||
|
||||
import "github.com/gofiber/fiber/v2"
|
||||
|
||||
func Me(c *fiber.Ctx) error {
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,105 @@
|
||||
package controllers
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/gofiber/fiber/v2" //nolint:goimports
|
||||
"github.com/gofiber/fiber/v2/middleware/session"
|
||||
"github.com/sujit-baniya/fiber-boilerplate/app"
|
||||
"github.com/sujit-baniya/fiber-boilerplate/pkg/auth"
|
||||
"github.com/sujit-baniya/fiber-boilerplate/pkg/models"
|
||||
)
|
||||
|
||||
func LoginGet(c *fiber.Ctx) error {
|
||||
data := getFlashData(c)
|
||||
data["title"] = "Login | "
|
||||
return c.Render("auth/login", data, "layouts/landing")
|
||||
}
|
||||
|
||||
func LoginPost(c *fiber.Ctx) error {
|
||||
// Verificar si falta la contraseña
|
||||
if c.Locals("missing_password") == true {
|
||||
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{
|
||||
"status": "missing",
|
||||
"message": "no_password",
|
||||
})
|
||||
}
|
||||
|
||||
// Obtener el usuario desde el contexto
|
||||
user := c.Locals("user").(*models.Users)
|
||||
|
||||
// Intentar realizar el login
|
||||
_, err := auth.Login(c, user.ID, app.Http.Token.AppJwtSecret) //nolint:wsl
|
||||
if err != nil {
|
||||
// Si ocurre un error, devolverlo en formato JSON
|
||||
return c.JSON(fiber.Map{
|
||||
"status": "error",
|
||||
"message": err.Error(),
|
||||
})
|
||||
}
|
||||
|
||||
// Si todo está bien, devolver éxito y el token JWT
|
||||
return c.JSON(fiber.Map{
|
||||
"status": "success",
|
||||
"message": "Login exitoso",
|
||||
})
|
||||
}
|
||||
|
||||
var store = session.New()
|
||||
|
||||
func LogoutPost(c *fiber.Ctx) error {
|
||||
// Verifica si el usuario está autenticado
|
||||
if auth.IsLoggedIn(c) {
|
||||
// Cierra la sesión en el backend
|
||||
err := auth.Logout(c)
|
||||
if err != nil {
|
||||
return fiber.NewError(fiber.StatusInternalServerError, "Logout failed")
|
||||
}
|
||||
}
|
||||
|
||||
// Elimina la sesión actual
|
||||
sess, err := store.Get(c)
|
||||
if err == nil {
|
||||
_ = sess.Destroy()
|
||||
}
|
||||
|
||||
// Limpia ambas cookies de sesión
|
||||
c.ClearCookie("session_id")
|
||||
c.ClearCookie("Verify-Rest-Token")
|
||||
|
||||
// Limpia la cookie CSRF
|
||||
c.Cookie(&fiber.Cookie{
|
||||
Name: "Verify-Rest-Token", // Nombre de la cookie CSRF, ajusta si usas un nombre diferente
|
||||
Value: "",
|
||||
Expires: time.Now().Add(-1 * time.Hour), // Establece la cookie para que expire en el pasado
|
||||
HTTPOnly: true,
|
||||
Secure: true,
|
||||
SameSite: "Strict",
|
||||
})
|
||||
// Limpia la cookie CSRF
|
||||
c.Cookie(&fiber.Cookie{
|
||||
Name: "session_id", // Nombre de la cookie CSRF, ajusta si usas un nombre diferente
|
||||
Value: "",
|
||||
Expires: time.Now().Add(-1 * time.Hour), // Establece la cookie para que expire en el pasado
|
||||
HTTPOnly: true,
|
||||
Secure: true,
|
||||
SameSite: "Strict",
|
||||
})
|
||||
|
||||
// Ajusta encabezados de caché para evitar almacenamientos no deseados en caché
|
||||
c.Set("X-DNS-Prefetch-Control", "off")
|
||||
c.Set("Pragma", "no-cache")
|
||||
c.Set("Expires", "Fri, 01 Jan 1990 00:00:00 GMT")
|
||||
c.Set("Cache-Control", "no-cache, must-revalidate, no-store, max-age=0, private")
|
||||
|
||||
// Redirige al usuario a la página de inicio de sesión
|
||||
return c.Redirect("/login")
|
||||
}
|
||||
|
||||
func getFlashData(c *fiber.Ctx) fiber.Map {
|
||||
data := app.Http.Flash.Get(c)
|
||||
if data == nil {
|
||||
data = fiber.Map{}
|
||||
}
|
||||
return data
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
package controllers
|
||||
|
||||
import (
|
||||
"github.com/gofiber/fiber/v2"
|
||||
)
|
||||
|
||||
// RENDER
|
||||
func Dashboard(c *fiber.Ctx) error {
|
||||
data := fiber.Map{
|
||||
"user": c.Locals("user").(map[string]interface{}),
|
||||
"modules": c.Locals("userModules"),
|
||||
}
|
||||
|
||||
// Renderiza la vista con el layout layouts/main
|
||||
if err := c.Render("dashboard", data, "layouts/main"); err != nil {
|
||||
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
|
||||
"message": "Error rendering template",
|
||||
"error": err.Error(),
|
||||
})
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
package controllers
|
||||
|
||||
import (
|
||||
"github.com/gofiber/fiber/v2"
|
||||
"github.com/sujit-baniya/fiber-boilerplate/pkg/auth"
|
||||
)
|
||||
|
||||
func Landing(c *fiber.Ctx) error {
|
||||
user, err := auth.User(c)
|
||||
if err != nil {
|
||||
auth.Logout(c)
|
||||
}
|
||||
view := "index"
|
||||
|
||||
if err := c.Render(view, fiber.Map{
|
||||
"auth": user != nil,
|
||||
"user": user,
|
||||
}, "layouts/main"); err != nil {
|
||||
panic(err.Error())
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func Terms(c *fiber.Ctx) error {
|
||||
if err := c.Render("terms", fiber.Map{"title": "Terms | "}, "layouts/landing"); err != nil {
|
||||
panic(err.Error())
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func PrivacyPolicy(c *fiber.Ctx) error {
|
||||
if err := c.Render("privacy-policy", fiber.Map{"title": "Privacy Policy | "}, "layouts/landing"); err != nil {
|
||||
panic(err.Error())
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func Disclaimer(c *fiber.Ctx) error {
|
||||
if err := c.Render("disclaimer", fiber.Map{"title": "Disclaimer | "}, "layouts/main"); err != nil {
|
||||
panic(err.Error())
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func App(c *fiber.Ctx) error {
|
||||
user, err := auth.User(c)
|
||||
if err != nil {
|
||||
auth.Logout(c)
|
||||
}
|
||||
view := "home"
|
||||
|
||||
if err := c.Render(view, fiber.Map{
|
||||
"auth": user != nil,
|
||||
"user": user,
|
||||
}); err != nil {
|
||||
panic(err.Error())
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func Admin(c *fiber.Ctx) error {
|
||||
user, err := auth.User(c)
|
||||
if err != nil {
|
||||
auth.Logout(c)
|
||||
}
|
||||
view := "admin-home"
|
||||
|
||||
if err := c.Render(view, fiber.Map{
|
||||
"auth": user != nil,
|
||||
"user": user,
|
||||
}); err != nil {
|
||||
panic(err.Error())
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,162 @@
|
||||
package controllers
|
||||
|
||||
import (
|
||||
"math"
|
||||
"strconv"
|
||||
|
||||
"github.com/gofiber/fiber/v2" //nolint:goimports
|
||||
"github.com/sujit-baniya/fiber-boilerplate/pkg/models"
|
||||
)
|
||||
|
||||
// RENDER
|
||||
func Modules(c *fiber.Ctx) error {
|
||||
// Renderiza la vista "modules" con el layout "layouts/landing"
|
||||
// Renderizar la vista "roles" y pasar los datos al frontend
|
||||
data := fiber.Map{
|
||||
"user": c.Locals("user").(map[string]interface{}),
|
||||
"modules": c.Locals("userModules"),
|
||||
}
|
||||
|
||||
if err := c.Render("modules", data, "layouts/main"); err != nil {
|
||||
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
|
||||
"message": "Error rendering template",
|
||||
"error": err.Error(),
|
||||
})
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
//CONSULTAR TODOS LOS MODULOS
|
||||
|
||||
func GetModules(c *fiber.Ctx) error {
|
||||
// Obtener parámetros de consulta para la paginación
|
||||
pageStr := c.Query("page", "1") // Por defecto, la página es 1
|
||||
page, err := strconv.Atoi(pageStr)
|
||||
if err != nil || page < 1 {
|
||||
page = 1
|
||||
}
|
||||
|
||||
searchQuery := c.Query("search", "") // Obtener el término de búsqueda
|
||||
limit := 10 // Número de módulos por página
|
||||
offset := (page - 1) * limit
|
||||
|
||||
// Llama a AllModules con el término de búsqueda
|
||||
modules, total, err := models.AllModules(limit, offset, searchQuery)
|
||||
if err != nil {
|
||||
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
|
||||
"message": "Error retrieving modules",
|
||||
"error": err.Error(),
|
||||
})
|
||||
}
|
||||
|
||||
// Calcular el total de páginas
|
||||
totalPages := int(math.Ceil(float64(total) / float64(limit)))
|
||||
|
||||
// Envía los módulos como respuesta JSON junto con la información de paginación
|
||||
return c.JSON(fiber.Map{
|
||||
"modules": modules,
|
||||
"total": total, // Total de módulos disponibles
|
||||
"totalPages": totalPages, // Total de páginas
|
||||
"page": page, // Página actual
|
||||
"limit": limit, // Límites por página
|
||||
})
|
||||
}
|
||||
|
||||
func AllModulesSelect(c *fiber.Ctx) error {
|
||||
modules, err := models.AllModulesWithSubmodules()
|
||||
if err != nil {
|
||||
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
|
||||
"message": "Error retrieving modules",
|
||||
"error": err.Error(),
|
||||
})
|
||||
}
|
||||
|
||||
return c.JSON(fiber.Map{
|
||||
"modules": modules,
|
||||
})
|
||||
}
|
||||
|
||||
// ACTUALIZAR
|
||||
func UpdateModule(c *fiber.Ctx) error {
|
||||
var m models.Modules
|
||||
uid, err := strconv.ParseUint(c.Params("id"), 10, 32)
|
||||
if err != nil {
|
||||
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{
|
||||
"message": "ID inválido",
|
||||
"error": true,
|
||||
})
|
||||
}
|
||||
|
||||
// Analiza el cuerpo de la solicitud
|
||||
if err := c.BodyParser(&m); err != nil {
|
||||
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{
|
||||
"message": "Error al analizar el cuerpo de la solicitud",
|
||||
"error": true,
|
||||
})
|
||||
}
|
||||
|
||||
m.ID = uint(uid)
|
||||
|
||||
// Actualiza el módulo en la base de datos
|
||||
if err := models.UpdateModule(m); err != nil {
|
||||
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
|
||||
"message": err.Error(),
|
||||
"error": true,
|
||||
})
|
||||
}
|
||||
|
||||
return c.Status(fiber.StatusOK).JSON(fiber.Map{
|
||||
"message": "Módulo actualizado con éxito",
|
||||
"error": false,
|
||||
"module": m,
|
||||
})
|
||||
}
|
||||
|
||||
// CREAR
|
||||
func CreateModule(c *fiber.Ctx) error {
|
||||
var m models.Modules
|
||||
|
||||
// Analiza el cuerpo de la solicitud
|
||||
if err := c.BodyParser(&m); err != nil {
|
||||
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{
|
||||
"message": "Error al analizar el cuerpo de la solicitud",
|
||||
"error": true,
|
||||
})
|
||||
}
|
||||
|
||||
// Crea el nuevo módulo en la base de datos
|
||||
if err := models.CreateModule(m); err != nil { // Asegúrate de tener una función para crear un módulo
|
||||
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
|
||||
"message": err.Error(),
|
||||
"error": true,
|
||||
})
|
||||
}
|
||||
|
||||
return c.Status(fiber.StatusCreated).JSON(fiber.Map{
|
||||
"message": "Módulo creado con éxito",
|
||||
"error": false,
|
||||
"module": m,
|
||||
})
|
||||
}
|
||||
|
||||
// ELIMINAR
|
||||
func DeleteModule(c *fiber.Ctx) error {
|
||||
uid, err := strconv.ParseUint(c.Params("id"), 10, 32)
|
||||
if err != nil {
|
||||
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{
|
||||
"message": "Invalid ID",
|
||||
"error": true,
|
||||
})
|
||||
}
|
||||
|
||||
if err := models.DeleteModule(uint(uid)); err != nil { // Ensure you have a function for deleting a module
|
||||
return c.JSON(fiber.Map{
|
||||
"message": err.Error(),
|
||||
"error": true,
|
||||
})
|
||||
}
|
||||
return c.JSON(fiber.Map{
|
||||
"message": "Modulo eliminado correctamente",
|
||||
"error": false,
|
||||
})
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
package controllers
|
||||
|
||||
import (
|
||||
"github.com/gofiber/fiber/v2"
|
||||
)
|
||||
|
||||
func Profile(c *fiber.Ctx) error {
|
||||
// Obtiene el usuario del contexto en formato map[string]interface{}
|
||||
user, ok := c.Locals("user").(map[string]interface{})
|
||||
if !ok || user == nil {
|
||||
return c.Status(fiber.StatusUnauthorized).JSON(fiber.Map{
|
||||
"message": "Usuario no autenticado",
|
||||
})
|
||||
}
|
||||
|
||||
// Obtener el usuario del contexto
|
||||
// Renderiza la vista "profile" pasando el usuario
|
||||
if err := c.Render("profile", fiber.Map{
|
||||
"user": user,
|
||||
}, "layouts/main"); err != nil {
|
||||
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
|
||||
"message": "Error rendering template",
|
||||
"error": err.Error(),
|
||||
})
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,302 @@
|
||||
package controllers
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
"errors"
|
||||
"fmt"
|
||||
"log"
|
||||
"math/big"
|
||||
"strings"
|
||||
|
||||
"github.com/gofiber/fiber/v2"
|
||||
"github.com/sujit-baniya/fiber-boilerplate/app"
|
||||
"github.com/sujit-baniya/fiber-boilerplate/config"
|
||||
"github.com/sujit-baniya/fiber-boilerplate/pkg/auth"
|
||||
"github.com/sujit-baniya/fiber-boilerplate/pkg/models"
|
||||
"github.com/sujit-baniya/fiber-boilerplate/pkg/services"
|
||||
"golang.org/x/crypto/bcrypt"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
// Función para renderizar la página de registro
|
||||
func RegisterGet(c *fiber.Ctx) error {
|
||||
data := getFlashData(c)
|
||||
data["title"] = "Register | "
|
||||
if err := c.Render("auth/register", data, "layouts/landing"); err != nil { //nolint:wsl
|
||||
panic(err.Error())
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Función para manejar la solicitud de registro
|
||||
func RegisterPost(c *fiber.Ctx) error {
|
||||
register := c.Locals("register").(models.RegisterForm)
|
||||
user, err := register.Signup()
|
||||
if err != nil {
|
||||
return app.Http.Flash.WithError(c, fiber.Map{
|
||||
"error": true,
|
||||
"message": "Error on register request: " + err.Error(),
|
||||
}).Redirect("/register")
|
||||
}
|
||||
store := app.Http.Session.Get(c) // obtener/crear nueva sesión
|
||||
store.Set("user_id", user.ID) // guardar en el almacenamiento
|
||||
_ = store.Save()
|
||||
|
||||
go services.SendConfirmationEmail(user.Email, app.Http.Server.Url, user.NombreUsuario)
|
||||
return c.Redirect("/")
|
||||
}
|
||||
|
||||
// Función para verificar el correo electrónico registrado
|
||||
func VerifyRegisteredEmail(c *fiber.Ctx) error {
|
||||
|
||||
return c.Redirect("/app")
|
||||
}
|
||||
|
||||
// Función para reenviar el correo de confirmación
|
||||
func ResendConfirmEmail(c *fiber.Ctx) error {
|
||||
user, _ := auth.User(c)
|
||||
go services.SendConfirmationEmail(user.Email, app.Http.Server.Url, user.NombreUsuario)
|
||||
return c.Redirect("/")
|
||||
}
|
||||
|
||||
func ReenvioEmail(c *fiber.Ctx) error {
|
||||
usuarioID := c.Params("id") // Usa Params para obtener el parámetro de la ruta
|
||||
user, err := models.GetUserById(usuarioID)
|
||||
if err != nil {
|
||||
return c.Status(fiber.StatusNotFound).JSON(fiber.Map{
|
||||
"success": false,
|
||||
"message": "Usuario no encontrado: " + err.Error(),
|
||||
})
|
||||
}
|
||||
|
||||
// Reenvío del correo electrónico de forma asíncrona
|
||||
go services.SendConfirmationEmail(user.Email, app.Http.Server.Url, user.NombreUsuario)
|
||||
|
||||
return c.Status(fiber.StatusOK).JSON(fiber.Map{
|
||||
"success": true,
|
||||
"message": "Email reenviado correctamente",
|
||||
})
|
||||
}
|
||||
|
||||
// Función para manejar la solicitud de restablecimiento de contraseña
|
||||
func RequestPasswordResetPost(c *fiber.Ctx) error {
|
||||
// Crear una estructura para mapear los datos entrantes
|
||||
type Request struct {
|
||||
NombreUsuario string `json:"nombre_usuario"` // Mapeo con la clave del JSON
|
||||
}
|
||||
|
||||
var req Request
|
||||
|
||||
// Parsear el cuerpo JSON de la solicitud
|
||||
if err := c.BodyParser(&req); err != nil {
|
||||
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{
|
||||
"success": false,
|
||||
"message": "Invalid JSON format",
|
||||
})
|
||||
}
|
||||
|
||||
// Obtener el usuario del JSON parseado
|
||||
usuario := req.NombreUsuario
|
||||
fmt.Println("Usuario recibido:", usuario)
|
||||
|
||||
// Intentar obtener el usuario por nombre de usuario
|
||||
user, err := models.GetUserByUsuario(usuario)
|
||||
|
||||
if err != nil || user == nil {
|
||||
// Devolver respuesta de error en formato JSON
|
||||
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{
|
||||
"success": false,
|
||||
"message": "Usuario inactivo o no existente",
|
||||
})
|
||||
}
|
||||
|
||||
// Obtener el email del usuario
|
||||
usuario_email := user.Email
|
||||
|
||||
// Imprimir el email en la consola
|
||||
log.Println("Sending password reset email to:", usuario_email)
|
||||
|
||||
// Enviar el correo de restablecimiento de contraseña de forma asíncrona
|
||||
go services.SendPasswordResetEmail(usuario_email, app.Http.Server.Url)
|
||||
|
||||
// Devolver respuesta de éxito en formato JSON
|
||||
return c.JSON(fiber.Map{
|
||||
"success": true,
|
||||
"message": "We've sent an email to reset your password to your registered email address",
|
||||
})
|
||||
}
|
||||
|
||||
// todo: Generar contrasenas aleatorias /do/generate-password
|
||||
func generatePassword(length int) (string, error) {
|
||||
const charset = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!@#$%&"
|
||||
var password strings.Builder
|
||||
for i := 0; i < length; i++ {
|
||||
randomIndex, err := rand.Int(rand.Reader, big.NewInt(int64(len(charset))))
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
password.WriteByte(charset[randomIndex.Int64()])
|
||||
}
|
||||
return password.String(), nil
|
||||
}
|
||||
|
||||
func hashPassword(password string) (string, error) {
|
||||
hashed, err := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return string(hashed), nil
|
||||
}
|
||||
|
||||
func updatePassword(nombreUsuario, plainPassword string) error {
|
||||
var user models.RegisterForm
|
||||
|
||||
result := app.Http.Database.DB.Where("nombre_usuario = ?", nombreUsuario).First(&user)
|
||||
if errors.Is(result.Error, gorm.ErrRecordNotFound) {
|
||||
return errors.New("codigo no pertenece a ningun usuario")
|
||||
}
|
||||
|
||||
if user.Password != "" {
|
||||
return errors.New("este usuario ya cuenta con una contraseña")
|
||||
}
|
||||
|
||||
hashedPassword, err := hashPassword(plainPassword)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
user.Password = hashedPassword
|
||||
if err := app.Http.Database.DB.Save(&user).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func GeneratePasswordPost(c *fiber.Ctx) error {
|
||||
// Parsear el cuerpo de la solicitud
|
||||
var body struct {
|
||||
NombreUsuario string `json:"nombre_usuario"`
|
||||
}
|
||||
if err := c.BodyParser(&body); err != nil {
|
||||
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{
|
||||
"success": false,
|
||||
"message": "Error al analizar el cuerpo de la solicitud",
|
||||
})
|
||||
}
|
||||
|
||||
if body.NombreUsuario == "" {
|
||||
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{
|
||||
"success": false,
|
||||
"message": "El codigo de usuario es requerido",
|
||||
})
|
||||
}
|
||||
|
||||
// Generar la contraseña
|
||||
password, err := generatePassword(12)
|
||||
if err != nil {
|
||||
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
|
||||
"success": false,
|
||||
"message": "Error generando contraseña",
|
||||
})
|
||||
}
|
||||
|
||||
// Actualizar la contraseña en la base de datos
|
||||
if err := updatePassword(body.NombreUsuario, password); err != nil {
|
||||
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
|
||||
"success": false,
|
||||
"message": err.Error(),
|
||||
})
|
||||
}
|
||||
|
||||
// Responder con la contraseña generada
|
||||
return c.JSON(fiber.Map{
|
||||
"success": true,
|
||||
"message": "Contrasena generada exitosamente",
|
||||
"password": password,
|
||||
})
|
||||
}
|
||||
|
||||
// Función para renderizar la página de restablecimiento de contraseña
|
||||
func PasswordReset(c *fiber.Ctx) error {
|
||||
token := c.Query("t")
|
||||
if err := c.Render("auth/password-reset", fiber.Map{
|
||||
"Title": "Password Reset",
|
||||
"Token": token,
|
||||
}, "layouts/landing"); err != nil {
|
||||
panic(err.Error())
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func PasswordResetPost(c *fiber.Ctx) error {
|
||||
// Recuperar el nombre de usuario y la nueva contraseña del formulario
|
||||
nombreUsuario := c.FormValue("nombre_usuario")
|
||||
password := c.FormValue("password")
|
||||
|
||||
// Validar que ambos campos estén presentes
|
||||
if nombreUsuario == "" || password == "" {
|
||||
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{
|
||||
"message": "Los campos nombre_usuario y password son obligatorios.",
|
||||
"error": true,
|
||||
})
|
||||
}
|
||||
|
||||
// Imprimir los datos recibidos (opcional para depuración)
|
||||
fmt.Printf("Datos recibidos: nombre_usuario=%s, password=%s\n", nombreUsuario, password)
|
||||
|
||||
// Buscar al usuario en la base de datos por nombre de usuario
|
||||
user, err := models.GetUserByUsuario(nombreUsuario)
|
||||
if err != nil || user == nil {
|
||||
return c.Status(fiber.StatusUnauthorized).JSON(fiber.Map{
|
||||
"message": "Usuario no encontrado.",
|
||||
"error": true,
|
||||
})
|
||||
}
|
||||
|
||||
hash := config.Hash{}
|
||||
|
||||
// Encripta la nueva contraseña
|
||||
hashedPassword, err := hash.Create(password)
|
||||
if err != nil {
|
||||
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
|
||||
"message": "Error al encriptar la contraseña",
|
||||
"error": true,
|
||||
})
|
||||
}
|
||||
// Asigna la contraseña encriptada al modelo
|
||||
password = hashedPassword
|
||||
|
||||
// Actualizar la contraseña del usuario
|
||||
err = models.UpdateUserPassword(user.ID, password)
|
||||
if err != nil {
|
||||
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
|
||||
"message": "Error al actualizar la contraseña.",
|
||||
"error": true,
|
||||
})
|
||||
}
|
||||
|
||||
// Redirigir al usuario al formulario de inicio de sesión después del éxito
|
||||
return c.Redirect("/login")
|
||||
}
|
||||
|
||||
// Función para renderizar la página de solicitud de restablecimiento de contraseña
|
||||
func RequestPasswordReset(c *fiber.Ctx) error {
|
||||
data := getFlashData(c)
|
||||
data["title"] = "Password Reset | "
|
||||
if err := c.Render("auth/request-password-reset", data, "layouts/landing"); err != nil { //nolint:wsl
|
||||
panic(err.Error())
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func TokenVencido(c *fiber.Ctx) error {
|
||||
// Renderiza la vista con el layout layouts/main
|
||||
if err := c.Render("token_vencido", nil, "layouts/landing"); err != nil {
|
||||
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
|
||||
"message": "Error rendering template",
|
||||
"error": err.Error(),
|
||||
})
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,117 @@
|
||||
package controllers
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/gofiber/fiber/v2"
|
||||
"github.com/sujit-baniya/fiber-boilerplate/app"
|
||||
"github.com/sujit-baniya/fiber-boilerplate/pkg/models"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
func CreateNewRole(c *fiber.Ctx) error {
|
||||
var role models.Role
|
||||
c.BodyParser(&role)
|
||||
app.Http.Database.Create(&role)
|
||||
return c.JSON(role)
|
||||
}
|
||||
func RemoveRole(c *fiber.Ctx) error {
|
||||
var role models.Role
|
||||
c.BodyParser(&role)
|
||||
|
||||
app.Http.Database.
|
||||
Delete(&models.RoleAndPermission{})
|
||||
app.Http.Auth.Enforcer.LoadPolicy()
|
||||
return nil
|
||||
}
|
||||
|
||||
func AssignRoleToUser(c *fiber.Ctx) error {
|
||||
var roleRequest models.RoleRequest
|
||||
var role1 models.RoleAndPermission
|
||||
c.BodyParser(&roleRequest)
|
||||
role := models.RoleAndPermission{
|
||||
Ptype: "g",
|
||||
V0: fmt.Sprintf("%d", roleRequest.UserID),
|
||||
V1: roleRequest.Role,
|
||||
}
|
||||
err := app.Http.Database.Unscoped().First(&role1, models.RoleAndPermission{Ptype: role.Ptype,V0: role.V0, V1: role.V1}).Error
|
||||
if err != nil {
|
||||
app.Http.Database.Create(&role)
|
||||
app.Http.Auth.Enforcer.LoadPolicy()
|
||||
return c.JSON(role)
|
||||
}
|
||||
role1.DeletedAt = gorm.DeletedAt{Valid: false}
|
||||
app.Http.Database.Unscoped().Save(role1)
|
||||
app.Http.Auth.Enforcer.LoadPolicy()
|
||||
return c.JSON(role1)
|
||||
}
|
||||
|
||||
func RevokeRoleFromUser(c *fiber.Ctx) error {
|
||||
var roleRequest models.RoleRequest
|
||||
c.BodyParser(&roleRequest)
|
||||
app.Http.Database.
|
||||
Delete(
|
||||
&models.RoleAndPermission{},
|
||||
models.RoleAndPermission{V0: fmt.Sprintf("%d", roleRequest.UserID), V1: roleRequest.Role})
|
||||
app.Http.Auth.Enforcer.LoadPolicy()
|
||||
return c.JSON("Role Revoked from user")
|
||||
}
|
||||
|
||||
func ChangeRoleForUser(c *fiber.Ctx) error {
|
||||
var role models.RoleRequest
|
||||
var role1 models.RoleAndPermission
|
||||
c.BodyParser(&role)
|
||||
err := app.Http.Database.Unscoped().First(&role1, models.RoleAndPermission{Ptype: "g",V0: fmt.Sprintf("%d", role.UserID), V1: role.OldRole}).Error
|
||||
if err == nil {
|
||||
role1.V1 = role.Role
|
||||
role1.DeletedAt = gorm.DeletedAt{Valid: false}
|
||||
app.Http.Database.Unscoped().Save(role1)
|
||||
app.Http.Auth.Enforcer.LoadPolicy()
|
||||
return c.JSON("Role Changed for user")
|
||||
}
|
||||
return c.JSON("Role doesn't exists")
|
||||
}
|
||||
|
||||
func AddPermissionOnRole(c *fiber.Ctx) error {
|
||||
var permission models.PermissionRequest
|
||||
var role1 models.RoleAndPermission
|
||||
c.BodyParser(&permission)
|
||||
if permission.Role != "" && permission.Module != "" && permission.Action != "" {
|
||||
role := models.RoleAndPermission{
|
||||
Ptype: "p",
|
||||
V0: permission.Role,
|
||||
V1: permission.Module,
|
||||
V2: permission.Action,
|
||||
Category: "permission",
|
||||
}
|
||||
err := app.Http.Database.Unscoped().First(&role1, models.RoleAndPermission{Ptype: role.Ptype,V0: role.V0, V1: role.V1, V2: role.V2}).Error
|
||||
if err != nil {
|
||||
app.Http.Database.Create(&role)
|
||||
}
|
||||
role1.DeletedAt = gorm.DeletedAt{Valid: false}
|
||||
app.Http.Database.Unscoped().Save(role1)
|
||||
}
|
||||
if permission.Role != "" && permission.Route != "" && permission.Method != "" {
|
||||
fmt.Println(1)
|
||||
role := models.RoleAndPermission{
|
||||
Ptype: "p",
|
||||
V0: permission.Role,
|
||||
V1: permission.Route,
|
||||
V2: permission.Method,
|
||||
Category: "route",
|
||||
}
|
||||
err := app.Http.Database.Unscoped().First(&role1, models.RoleAndPermission{Ptype: role.Ptype,V0: role.V0, V1: role.V1, V2: role.V2}).Error
|
||||
if err != nil {
|
||||
app.Http.Database.Create(&role)
|
||||
}
|
||||
role1.DeletedAt = gorm.DeletedAt{Valid: false}
|
||||
app.Http.Database.Unscoped().Save(role1)
|
||||
}
|
||||
app.Http.Auth.Enforcer.LoadPolicy()
|
||||
return nil
|
||||
}
|
||||
func RemovePermissionFromRole(c *fiber.Ctx) error {
|
||||
return nil
|
||||
}
|
||||
func ChangePermissionOnRole(c *fiber.Ctx) error {
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,196 @@
|
||||
package controllers
|
||||
|
||||
import (
|
||||
"math"
|
||||
"strconv"
|
||||
|
||||
"github.com/gofiber/fiber/v2" //nolint:goimports
|
||||
"github.com/sujit-baniya/fiber-boilerplate/app"
|
||||
"github.com/sujit-baniya/fiber-boilerplate/pkg/models"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
// RENDER
|
||||
func Roles(c *fiber.Ctx) error {
|
||||
// Obtener los módulos organizados desde el contexto
|
||||
|
||||
// Renderizar la vista "roles" y pasar los datos al frontend
|
||||
data := fiber.Map{
|
||||
"user": c.Locals("user").(map[string]interface{}),
|
||||
"modules": c.Locals("userModules"),
|
||||
}
|
||||
|
||||
// Renderiza la vista "roles" con el layout "layouts/main"
|
||||
if err := c.Render("roles", data, "layouts/main"); err != nil {
|
||||
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
|
||||
"message": "Error rendering template",
|
||||
"error": err.Error(),
|
||||
})
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// CONSULTAR TODOS LOS registroa
|
||||
func GetRoles(c *fiber.Ctx) error {
|
||||
// Obtener parámetros de consulta para la paginación
|
||||
pageStr := c.Query("page", "1") // Por defecto, la página es 1
|
||||
page, err := strconv.Atoi(pageStr)
|
||||
if err != nil || page < 1 {
|
||||
page = 1
|
||||
}
|
||||
|
||||
searchQuery := c.Query("search", "") // Obtener el término de búsqueda
|
||||
limit := 10 // Número de módulos por página
|
||||
offset := (page - 1) * limit
|
||||
|
||||
// Llama a AllModules con el término de búsqueda
|
||||
roles, total, err := models.AllRoles(limit, offset, searchQuery)
|
||||
if err != nil {
|
||||
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
|
||||
"message": "Error retrieving modules",
|
||||
"error": err.Error(),
|
||||
})
|
||||
}
|
||||
|
||||
modules, err := models.AllModulesSelect()
|
||||
if err != nil {
|
||||
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
|
||||
"message": "Error retrieving modules",
|
||||
"error": err.Error(),
|
||||
})
|
||||
}
|
||||
|
||||
// Llama a AllRoles sin el término de búsqueda para obtener todos los roles
|
||||
// submodules, err := models.AllSubmodulesSelect() // Pasamos 0 para limit y offset para obtener todos los roles
|
||||
// if err != nil {
|
||||
// return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
|
||||
// "message": "Error retrieving roles",
|
||||
// "error": err.Error(),
|
||||
// })
|
||||
// }
|
||||
|
||||
// Calcular el total de páginas
|
||||
totalPages := int(math.Ceil(float64(total) / float64(limit)))
|
||||
|
||||
// Envía los módulos como respuesta JSON junto con la información de paginación
|
||||
return c.JSON(fiber.Map{
|
||||
"roles": roles,
|
||||
"modules": modules,
|
||||
"total": total, // Total de disponibles
|
||||
"totalPages": totalPages, // Total de páginas
|
||||
"page": page, // Página actual
|
||||
"limit": limit, // Límites por página
|
||||
})
|
||||
}
|
||||
func UpdateRole(c *fiber.Ctx) error {
|
||||
var m models.Roles
|
||||
uid, err := strconv.ParseUint(c.Params("id"), 10, 32)
|
||||
if err != nil {
|
||||
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{
|
||||
"message": "ID inválido",
|
||||
"error": true,
|
||||
})
|
||||
}
|
||||
|
||||
// Analiza el cuerpo de la solicitud
|
||||
if err := c.BodyParser(&m); err != nil {
|
||||
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{
|
||||
"message": "Error al analizar el cuerpo de la solicitud",
|
||||
"error": true,
|
||||
})
|
||||
}
|
||||
|
||||
// Buscar el rol actual en la base de datos
|
||||
var existingRole models.Roles
|
||||
if err := app.Http.Database.DB.Preload("Submodules").First(&existingRole, uid).Error; err != nil {
|
||||
return c.Status(fiber.StatusNotFound).JSON(fiber.Map{
|
||||
"message": "Rol no encontrado",
|
||||
"error": true,
|
||||
})
|
||||
}
|
||||
|
||||
// Eliminar todas las relaciones existentes
|
||||
if err := app.Http.Database.DB.Model(&existingRole).Association("Submodules").Clear(); err != nil {
|
||||
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
|
||||
"message": "Error al eliminar relaciones de submódulos",
|
||||
"error": true,
|
||||
})
|
||||
}
|
||||
|
||||
// Establecer el ID del rol
|
||||
m.ID = uint(uid)
|
||||
|
||||
// Agregar los nuevos submódulos
|
||||
var newSubmodules []models.Submodules
|
||||
for _, submodule := range m.Submodules {
|
||||
var newSubmodule models.Submodules
|
||||
if err := app.Http.Database.DB.First(&newSubmodule, submodule.ID).Error; err == nil {
|
||||
newSubmodules = append(newSubmodules, newSubmodule)
|
||||
}
|
||||
}
|
||||
|
||||
// Asignar los nuevos submódulos al rol
|
||||
m.Submodules = newSubmodules
|
||||
|
||||
// Actualizar el rol en la base de datos
|
||||
if err := app.Http.Database.DB.Session(&gorm.Session{FullSaveAssociations: true}).Save(&m).Error; err != nil {
|
||||
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
|
||||
"message": err.Error(),
|
||||
"error": true,
|
||||
})
|
||||
}
|
||||
|
||||
return c.Status(fiber.StatusOK).JSON(fiber.Map{
|
||||
"message": "Rol actualizado con éxito",
|
||||
"error": false,
|
||||
"role": m,
|
||||
})
|
||||
}
|
||||
|
||||
func CreateRole(c *fiber.Ctx) error {
|
||||
var m models.Roles
|
||||
|
||||
// Parse the request body
|
||||
if err := c.BodyParser(&m); err != nil {
|
||||
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{
|
||||
"message": "Error parsing request body",
|
||||
"error": true,
|
||||
})
|
||||
}
|
||||
|
||||
// Create the role in the database
|
||||
if err := models.CreateRole(m); err != nil {
|
||||
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
|
||||
"message": err.Error(),
|
||||
"error": true,
|
||||
})
|
||||
}
|
||||
|
||||
return c.Status(fiber.StatusCreated).JSON(fiber.Map{
|
||||
"message": "Role creado correctamente",
|
||||
"error": false,
|
||||
"role": m,
|
||||
})
|
||||
}
|
||||
|
||||
// ELIMINAR
|
||||
func DeleteRole(c *fiber.Ctx) error {
|
||||
uid, err := strconv.ParseUint(c.Params("id"), 10, 32)
|
||||
if err != nil {
|
||||
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{
|
||||
"message": "Invalid ID",
|
||||
"error": true,
|
||||
})
|
||||
}
|
||||
|
||||
if err := models.DeleteRole(uint(uid)); err != nil { // Ensure you have a function for deleting a module
|
||||
return c.JSON(fiber.Map{
|
||||
"message": err.Error(),
|
||||
"error": true,
|
||||
})
|
||||
}
|
||||
return c.JSON(fiber.Map{
|
||||
"message": "Modulo eliminado correctamente",
|
||||
"error": false,
|
||||
})
|
||||
}
|
||||
@@ -0,0 +1,747 @@
|
||||
package controllers
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/gofiber/fiber/v2" //nolint:goimports
|
||||
"github.com/sujit-baniya/fiber-boilerplate/pkg/models"
|
||||
)
|
||||
|
||||
// RENDER
|
||||
func Submodules(c *fiber.Ctx) error {
|
||||
data := fiber.Map{
|
||||
"user": c.Locals("user").(map[string]interface{}),
|
||||
"modules": c.Locals("userModules"),
|
||||
}
|
||||
|
||||
// Renderiza la vista "modules" con el layout "layouts/landing"
|
||||
if err := c.Render("submodules", data, "layouts/main"); err != nil {
|
||||
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
|
||||
"message": "Error rendering template",
|
||||
"error": err.Error(),
|
||||
})
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
//CONSULTAR TODOS LOS SUBMODULOS
|
||||
|
||||
func GetSubmodules(c *fiber.Ctx) error {
|
||||
// Obtener parámetros de consulta para la paginación
|
||||
pageStr := c.Query("page", "1") // Por defecto, la página es 1
|
||||
page, err := strconv.Atoi(pageStr)
|
||||
if err != nil || page < 1 {
|
||||
page = 1
|
||||
}
|
||||
|
||||
searchQuery := c.Query("search", "") // Obtener el término de búsqueda
|
||||
limit := 10 // Número de módulos por página
|
||||
offset := (page - 1) * limit
|
||||
|
||||
// Llama a AllModules con el término de búsqueda
|
||||
submodules, total, err := models.AllSubmodules(limit, offset, searchQuery)
|
||||
if err != nil {
|
||||
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
|
||||
"message": "Error retrieving modules",
|
||||
"error": err.Error(),
|
||||
})
|
||||
}
|
||||
|
||||
// Llama a AllRoles sin el término de búsqueda para obtener todos los roles
|
||||
modules, err := models.AllModulesSelect() // Pasamos 0 para limit y offset para obtener todos los roles
|
||||
if err != nil {
|
||||
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
|
||||
"message": "Error retrieving roles",
|
||||
"error": err.Error(),
|
||||
})
|
||||
}
|
||||
|
||||
// Calcular el total de páginas
|
||||
totalPages := int(math.Ceil(float64(total) / float64(limit)))
|
||||
|
||||
// Envía los módulos como respuesta JSON junto con la información de paginación
|
||||
return c.JSON(fiber.Map{
|
||||
"submodules": submodules,
|
||||
"modules": modules,
|
||||
"total": total, // Total de módulos disponibles
|
||||
"totalPages": totalPages, // Total de páginas
|
||||
"page": page, // Página actual
|
||||
"limit": limit, // Límites por página
|
||||
})
|
||||
}
|
||||
|
||||
// ACTUALIZAR
|
||||
func UpdateSubmodule(c *fiber.Ctx) error {
|
||||
var m models.Submodules
|
||||
uid, err := strconv.ParseUint(c.Params("id"), 10, 32)
|
||||
if err != nil {
|
||||
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{
|
||||
"message": "ID inválido",
|
||||
"error": true,
|
||||
})
|
||||
}
|
||||
|
||||
// Analiza el cuerpo de la solicitud
|
||||
if err := c.BodyParser(&m); err != nil {
|
||||
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{
|
||||
"message": "Error al analizar el cuerpo de la solicitud",
|
||||
"error": true,
|
||||
})
|
||||
}
|
||||
|
||||
m.ID = uint(uid)
|
||||
|
||||
// Actualiza el módulo en la base de datos
|
||||
if err := models.UpdateSubmodule(m); err != nil {
|
||||
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
|
||||
"message": err.Error(),
|
||||
"error": true,
|
||||
})
|
||||
}
|
||||
|
||||
return c.Status(fiber.StatusOK).JSON(fiber.Map{
|
||||
"message": "Registro actualizado con éxito",
|
||||
"error": false,
|
||||
"submodule": m,
|
||||
})
|
||||
}
|
||||
|
||||
// CREAR SUBMODULO
|
||||
func CreateSubmodule(c *fiber.Ctx) error {
|
||||
var m models.Submodules
|
||||
|
||||
// Analiza el cuerpo de la solicitud
|
||||
if err := c.BodyParser(&m); err != nil {
|
||||
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{
|
||||
"message": "Error al analizar el cuerpo de la solicitud",
|
||||
"error": true,
|
||||
})
|
||||
}
|
||||
|
||||
// Crea el nuevo módulo en la base de datos
|
||||
if err := models.CreateSubmodule(m); err != nil {
|
||||
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
|
||||
"message": err.Error(),
|
||||
"error": true,
|
||||
})
|
||||
}
|
||||
|
||||
// Crear el archivo del modelo basado en el nombre del submódulo (title)
|
||||
title := m.Title
|
||||
fileName := fmt.Sprintf("C:/laragon/www/gases/fiber-boilerplate/pkg/models/%s.go", strings.ToLower(title))
|
||||
controllerFileName := fmt.Sprintf("C:/laragon/www/gases/fiber-boilerplate/rest/controllers/%s_controller.go", strings.ToLower(title))
|
||||
routeFileName := "C:/laragon/www/gases/fiber-boilerplate/rest/routes/user.go"
|
||||
viewFileName := fmt.Sprintf("C:/laragon/www/gases/fiber-boilerplate/resources/views/%s.html", strings.ToLower(title)) // Ruta del archivo de vista
|
||||
|
||||
// Generar el contenido del archivo
|
||||
content := generateModelFileContent(title)
|
||||
|
||||
// Crear y escribir el archivo de modelo
|
||||
if err := os.WriteFile(fileName, []byte(content), 0644); err != nil {
|
||||
fmt.Printf("Error al crear el archivo de modelo: %s\n", err)
|
||||
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
|
||||
"message": "Error al crear el archivo de modelo",
|
||||
"error": true,
|
||||
})
|
||||
}
|
||||
fmt.Printf("Archivo de modelo creado: %s\n", fileName)
|
||||
|
||||
// Generar el contenido del archivo de controlador
|
||||
controllerContent := generateControllerFileContent(title)
|
||||
|
||||
// Crear y escribir el archivo de controlador
|
||||
if err := os.WriteFile(controllerFileName, []byte(controllerContent), 0644); err != nil {
|
||||
fmt.Printf("Error al crear el archivo de controlador: %s\n", err)
|
||||
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
|
||||
"message": "Error al crear el archivo de controlador",
|
||||
"error": true,
|
||||
})
|
||||
}
|
||||
fmt.Printf("Archivo de controlador creado: %s\n", controllerFileName)
|
||||
|
||||
// Generar el contenido del archivo de vista
|
||||
viewContent := generateViewFileContent(title)
|
||||
|
||||
// Crear y escribir el archivo de vista
|
||||
if err := os.WriteFile(viewFileName, []byte(viewContent), 0644); err != nil {
|
||||
fmt.Printf("Error al crear el archivo de vista: %s\n", err)
|
||||
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
|
||||
"message": "Error al crear el archivo de vista",
|
||||
"error": true,
|
||||
})
|
||||
}
|
||||
fmt.Printf("Archivo de vista creado: %s\n", viewFileName)
|
||||
|
||||
// Añadir las rutas al archivo user.go
|
||||
routeContent := generateRouteFileContent(title)
|
||||
|
||||
// Abrir el archivo user.go en modo append y añadir las nuevas rutas
|
||||
if err := appendToFile(routeFileName, routeContent); err != nil {
|
||||
fmt.Printf("Error al añadir las rutas al archivo user.go: %s\n", err)
|
||||
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
|
||||
"message": "Error al añadir las rutas al archivo user.go",
|
||||
"error": true,
|
||||
})
|
||||
}
|
||||
fmt.Printf("Rutas añadidas al archivo user.go: %s\n", routeFileName)
|
||||
|
||||
return c.Status(fiber.StatusCreated).JSON(fiber.Map{
|
||||
"message": "Registro creado con éxito",
|
||||
"error": false,
|
||||
"submodule": m,
|
||||
})
|
||||
}
|
||||
|
||||
// Función auxiliar para pluralizar el nombre si es necesario
|
||||
func pluralize(word string) string {
|
||||
// Simple heuristic: if the word ends in "s", don't pluralize
|
||||
if strings.HasSuffix(word, "s") {
|
||||
return word
|
||||
}
|
||||
return word + "s"
|
||||
}
|
||||
|
||||
// Función que genera el contenido del archivo del modelo
|
||||
func generateModelFileContent(title string) string {
|
||||
pluralTitle := pluralize(title)
|
||||
return fmt.Sprintf(`package models
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"gorm.io/gorm"
|
||||
"github.com/sujit-baniya/fiber-boilerplate/app"
|
||||
)
|
||||
|
||||
type %s struct {
|
||||
gorm.Model // Embedding gorm.Model to inherit fields like ID, CreatedAt, UpdatedAt, DeletedAt
|
||||
ID uint gorm:"primarykey"
|
||||
ModifiedAt time.Time json:"modified_at" gorm:"column:modified_at"
|
||||
Description string json:"description" gorm:"column:description"
|
||||
Title string json:"title" gorm:"column:title"
|
||||
}
|
||||
|
||||
// TableName overrides the table name used by %s to %s
|
||||
func (%s) TableName() string {
|
||||
return "%s"
|
||||
}
|
||||
|
||||
// All%s recupera todos los registros con búsqueda
|
||||
func All%s(limit, offset int, search string) ([]%s, int64, error) {
|
||||
var items []%s
|
||||
var total int64
|
||||
db := app.Http.Database.DB.Model(&%s{})
|
||||
|
||||
// Filtrar por término de búsqueda si se proporciona
|
||||
if search != "" {
|
||||
db = db.Where("title LIKE ? OR description LIKE ?", "%%"+search+"%%", "%%"+search+"%%")
|
||||
}
|
||||
|
||||
// Obtener el total de registros
|
||||
if err := db.Count(&total).Error; err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
// Obtener los registros con paginación
|
||||
if err := db.Order("created_at DESC").Limit(limit).Offset(offset).Find(&items).Error; err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
return items, total, nil
|
||||
}
|
||||
|
||||
// All%sSelect recupera todos los registros sin paginación
|
||||
func All%sSelect() ([]%s, error) {
|
||||
var items []%s
|
||||
|
||||
// Realizar la consulta para obtener todos los registros
|
||||
if err := app.Http.Database.DB.Model(&%s{}).Find(&items).Error; err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return items, nil
|
||||
}
|
||||
|
||||
// Create%s creates a new record
|
||||
func Create%s(item %s) error {
|
||||
if err := app.Http.Database.DB.Create(&item).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Update%s updates an existing record
|
||||
func Update%s(item %s) error {
|
||||
if err := app.Http.Database.DB.Save(&item).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Delete%s deletes a record by its ID
|
||||
func Delete%s (id uint) error {
|
||||
if err := app.Http.Database.DB.Delete(&%s{}, id).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
`,
|
||||
title, // Nombre de la estructura (singular)
|
||||
title, title, // TableName usa el nombre en singular para la estructura y la función
|
||||
title, pluralTitle, // Nombre de la tabla (en plural)
|
||||
pluralTitle, pluralTitle, title, // Función All para paginación, plural y singular
|
||||
title, title, // Modelo usado en la consulta
|
||||
pluralTitle, pluralTitle, title, // AllSelect sin paginación
|
||||
title, title, title, // Crear, actualizar, borrar registros
|
||||
title, title, title, title) // Funciones de creación, actualización y eliminación
|
||||
}
|
||||
|
||||
// Función para generar el contenido del archivo de controlador
|
||||
func generateControllerFileContent(title string) string {
|
||||
lowerTitle := strings.ToLower(title)
|
||||
|
||||
// Contenido del controlador reemplazando "Title" con el nombre del submódulo
|
||||
return fmt.Sprintf(`package controllers
|
||||
|
||||
import (
|
||||
"github.com/gofiber/fiber/v2"
|
||||
"github.com/sujit-baniya/fiber-boilerplate/pkg/models"
|
||||
"strconv"
|
||||
"math"
|
||||
)
|
||||
|
||||
|
||||
// RENDER
|
||||
func %s(c *fiber.Ctx) error {
|
||||
// Renderiza la vista con el layout layouts/main
|
||||
if err := c.Render("%s", nil, "layouts/main"); err != nil {
|
||||
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
|
||||
"message": "Error rendering template",
|
||||
"error": err.Error(),
|
||||
})
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// CONSULTAR TODOS LOS REGISTROS
|
||||
func Get%s(c *fiber.Ctx) error {
|
||||
// Obtener parámetros de consulta para la paginación
|
||||
pageStr := c.Query("page", "1") // Por defecto, la página es 1
|
||||
page, err := strconv.Atoi(pageStr)
|
||||
if err != nil || page < 1 {
|
||||
page = 1
|
||||
}
|
||||
|
||||
searchQuery := c.Query("search", "") // Obtener el término de búsqueda
|
||||
limit := 10 // Número de registros por página
|
||||
offset := (page - 1) * limit
|
||||
|
||||
// Llama a AllModules con el término de búsqueda
|
||||
records, total, err := models.All%s(limit, offset, searchQuery)
|
||||
if err != nil {
|
||||
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
|
||||
"message": "Error retrieving records",
|
||||
"error": err.Error(),
|
||||
})
|
||||
}
|
||||
|
||||
// Calcular el total de páginas
|
||||
totalPages := int(math.Ceil(float64(total) / float64(limit)))
|
||||
|
||||
// Envía los registros como respuesta JSON junto con la información de paginación
|
||||
return c.JSON(fiber.Map{
|
||||
"registros": records,
|
||||
"total": total, // Total de registros disponibles
|
||||
"totalPages": totalPages, // Total de páginas
|
||||
"page": page, // Página actual
|
||||
"limit": limit, // Límites por página
|
||||
})
|
||||
}
|
||||
|
||||
// CREAR
|
||||
func Create%s(c *fiber.Ctx) error {
|
||||
var m models.%s
|
||||
|
||||
// Analiza el cuerpo de la solicitud
|
||||
if err := c.BodyParser(&m); err != nil {
|
||||
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{
|
||||
"message": "Error al analizar el cuerpo de la solicitud",
|
||||
"error": true,
|
||||
})
|
||||
}
|
||||
|
||||
// Crea el nuevo registro en la base de datos
|
||||
if err := models.Create%s(m); err != nil {
|
||||
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
|
||||
"message": err.Error(),
|
||||
"error": true,
|
||||
})
|
||||
}
|
||||
|
||||
return c.Status(fiber.StatusCreated).JSON(fiber.Map{
|
||||
"message": "Registro creado con éxito",
|
||||
"error": false,
|
||||
"registro": m,
|
||||
})
|
||||
}
|
||||
|
||||
// ACTUALIZAR
|
||||
func Update%s(c *fiber.Ctx) error {
|
||||
var m models.%s
|
||||
uid, err := strconv.ParseUint(c.Params("id"), 10, 32)
|
||||
if err != nil {
|
||||
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{
|
||||
"message": "ID inválido",
|
||||
"error": true,
|
||||
})
|
||||
}
|
||||
|
||||
// Analiza el cuerpo de la solicitud
|
||||
if err := c.BodyParser(&m); err != nil {
|
||||
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{
|
||||
"message": "Error al analizar el cuerpo de la solicitud",
|
||||
"error": true,
|
||||
})
|
||||
}
|
||||
|
||||
m.ID = uint(uid)
|
||||
|
||||
// Actualiza el módulo en la base de datos
|
||||
if err := models.Update%s(m); err != nil {
|
||||
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
|
||||
"message": err.Error(),
|
||||
"error": true,
|
||||
})
|
||||
}
|
||||
|
||||
return c.Status(fiber.StatusOK).JSON(fiber.Map{
|
||||
"message": "Registro actualizado con éxito",
|
||||
"error": false,
|
||||
"registro": m,
|
||||
})
|
||||
}
|
||||
|
||||
// Delete%s elimina un %s por su ID
|
||||
func Delete%s(c *fiber.Ctx) error {
|
||||
uid, err := strconv.ParseUint(c.Params("id"), 10, 32)
|
||||
if err != nil {
|
||||
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{
|
||||
"message": "ID inválido",
|
||||
"error": true,
|
||||
})
|
||||
}
|
||||
|
||||
// Lógica para eliminar %s
|
||||
if err := models.Delete%s(uint(uid)); err != nil {
|
||||
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
|
||||
"message": err.Error(),
|
||||
"error": true,
|
||||
})
|
||||
}
|
||||
|
||||
return c.Status(fiber.StatusOK).JSON(fiber.Map{
|
||||
"message": "%s eliminado con éxito",
|
||||
"error": false,
|
||||
})
|
||||
}
|
||||
`, title, lowerTitle, title, title, title, title, title, title, title, lowerTitle, title, title, lowerTitle, title)
|
||||
}
|
||||
|
||||
// Función para generar el contenido de rutas para el nuevo submódulo
|
||||
func generateRouteFileContent(title string) string {
|
||||
lowerTitle := strings.ToLower(title)
|
||||
|
||||
// Bloque de rutas personalizado
|
||||
return fmt.Sprintf(`
|
||||
// Rutas para %s
|
||||
account.Get("/%s", controllers.Get%s) // Renderizar la vista de %s
|
||||
account.Get("/load%s", controllers.Get%s) // Obtener todos los %s
|
||||
account.Post("/%s", controllers.Create%s) // Crear un nuevo %s
|
||||
account.Put("/%s/:id", controllers.Update%s) // Actualizar un %s existente
|
||||
account.Delete("/%s/:id", controllers.Delete%s) // Eliminar un %s
|
||||
`, lowerTitle, lowerTitle, title, lowerTitle, lowerTitle, title, lowerTitle, lowerTitle, title, lowerTitle, lowerTitle, title, lowerTitle, lowerTitle, title)
|
||||
}
|
||||
|
||||
// Función para añadir contenido a un archivo existente
|
||||
func appendToFile(fileName, content string) error {
|
||||
f, err := os.OpenFile(fileName, os.O_APPEND|os.O_WRONLY, 0644)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
if _, err := f.WriteString(content); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// generateViewFileContent genera el contenido del archivo de vista para un submódulo
|
||||
func generateViewFileContent(title string) string {
|
||||
return fmt.Sprintf(`
|
||||
<div x-data="app" class="bg-white rounded-lg shadow">
|
||||
|
||||
<div x-show="loading" class="fixed inset-0 bg-gray-800 bg-opacity-75 flex z-50 justify-center items-center">
|
||||
<img src="../img/loading.gif" alt="Cargando..." class="w-16 h-16" />
|
||||
</div>
|
||||
|
||||
|
||||
<div class="container mx-auto p-6 w-full">
|
||||
<div class="justify-between items-center w-full md:flex">
|
||||
<div>
|
||||
<h1 class="text-2xl font-bold mb-2">Lista de actualizaciones de datos de usuario</h1>
|
||||
<p class="mb-4 text-sm">Gestión de actualizaciones de datos de usuario.</p>
|
||||
</div>
|
||||
|
||||
<div class="mb-4 md:mb-0 relative">
|
||||
<input type="text" placeholder="Buscar..." class="border border-gray-300 rounded p-2 w-full"
|
||||
x-model="search" @input.debounce.500ms="loadData()" />
|
||||
</div>
|
||||
|
||||
<div class="flex itmems-center justify-end mb-4 md:mb-0">
|
||||
<button @click="exportToExcel()" class="bg-[#8eb02f] text-white px-4 py-2 rounded text-sm">Exportar a
|
||||
Excel</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="overflow-x-auto">
|
||||
<table class="table-auto w-full">
|
||||
<thead class="text-sm text-left py-4 border-b border-gray-300">
|
||||
<tr class="text-left font-semibold border-collapse">
|
||||
<th class="py-2 px-4 border-b">Código</th>
|
||||
<th class="py-2 px-4 border-b">Nombre</th>
|
||||
<th class="py-2 px-4 border-b"></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody class="text-gray-500 select-none text-sm">
|
||||
<template x-for="data in datos" :key="data.id">
|
||||
<tr class="hover:bg-gray-100">
|
||||
|
||||
<td class="py-3 text-xs px-4 border-b" x-text="data.codigo"></td>
|
||||
<td class="py-3 text-xs px-4 border-b" x-text="data.name"></td>
|
||||
<td class="py-3 text-xs px-4 border-b">
|
||||
<div class="flex items-center">
|
||||
<div :class="data.revisado ? 'bg-green-500' : 'bg-gray-400'"
|
||||
class="w-3 h-3 rounded-full mr-2"></div>
|
||||
<span x-text="data.revisado ? 'Revisado' : 'No Revisado'"></span>
|
||||
</div>
|
||||
</td>
|
||||
<td class="py-3 text-xs px-4 border-b"
|
||||
x-text="data.created_at ? new Date(data.created_at).toLocaleDateString('es-ES', { year: 'numeric', month: 'long', day: 'numeric' }) : 'Fecha no disponible'">
|
||||
</td>
|
||||
<td class="py-3 text-xs px-4 border-b">
|
||||
<div class="flex items-center gap-2">
|
||||
<button @click="openViewModal(data)" title="Ver">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24"
|
||||
stroke-width="1.5" stroke="currentColor" class="w-5 text-[#8eb02f]">
|
||||
<path stroke-linecap="round" stroke-linejoin="round"
|
||||
d="M2.036 12.322a1.012 1.012 0 0 1 0-.639C3.423 7.51 7.36 4.5 12 4.5c4.638 0 8.573 3.007 9.963 7.178.07.207.07.431 0 .639C20.577 16.49 16.64 19.5 12 19.5c-4.638 0-8.573-3.007-9.963-7.178Z" />
|
||||
<path stroke-linecap="round" stroke-linejoin="round"
|
||||
d="M15 12a3 3 0 1 1-6 0 3 3 0 0 1 6 0Z" />
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</template>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<div class="flex justify-start items-center gap-1 p-4">
|
||||
<button @click="page = Math.max(1, page - 1); loadData()" :disabled="page === 1"
|
||||
class="px-4 py-2 bg-gray-300 rounded disabled:opacity-50">
|
||||
Anterior
|
||||
</button>
|
||||
<template x-for="pageNum in paginatedPages" :key="pageNum">
|
||||
<button @click="goToPage(pageNum)" class="px-4 py-2 bg-gray-300 rounded "
|
||||
:class="{ 'bg-blue-500 text-white': pageNum === page }" x-text="pageNum"></button>
|
||||
</template>
|
||||
<button @click="page += 1; loadData()" :disabled="datos.length < limit" :disabled="page === totalPages"
|
||||
class="px-4 py-2 bg-gray-300 rounded disabled:opacity-50">
|
||||
Siguiente
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Modal Ver -->
|
||||
<div x-show="viewModal"
|
||||
class="fixed inset-0 overflow-auto bg-gray-800 bg-opacity-75 flex justify-center items-center z-50">
|
||||
<div class="bg-white rounded-lg shadow-lg p-6 w-11/12 max-w-lg">
|
||||
<h2 class="text-lg font-bold mb-4">Ver actualizacion de datos de usuario</h2>
|
||||
|
||||
<div class="w-full mb-4">
|
||||
<label class="block mb-2">Tipo de usuario:</label>
|
||||
<input type="text" x-model="selectedItem.tipo_usuario" disabled
|
||||
class="border border-gray-300 rounded p-2 w-full" placeholder="Ingresa el tipo de usuario" />
|
||||
|
||||
</div>
|
||||
|
||||
<div class="flex flex-col sm:flex-row justify-between gap-4 mb-4">
|
||||
<div class="w-full">
|
||||
<label class="block mb-2">Tipo de persona:</label>
|
||||
<input type="text" x-model="selectedItem.tipo_persona" disabled
|
||||
class="border border-gray-300 rounded p-2 w-full" placeholder="Ingresa el tipo de persona" />
|
||||
</div>
|
||||
<div class="w-full">
|
||||
<label class="block mb-2">Nombre:</label>
|
||||
<input type="text" x-model="selectedItem.name" disabled
|
||||
class="border border-gray-300 rounded p-2 w-full" placeholder="Ingresa el nombre" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="flex justify-end gap-2">
|
||||
<button @click="viewModal = false" class="px-4 py-2 bg-gray-300 rounded">Cerrar</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
<script>
|
||||
function app() {
|
||||
return {
|
||||
datos: [],
|
||||
loading: false,
|
||||
limit: 10,
|
||||
page: 1,
|
||||
search: '',
|
||||
totalPages: 0,
|
||||
paginatedPages: [],
|
||||
|
||||
|
||||
// modales
|
||||
viewModal: false,
|
||||
|
||||
|
||||
item: {
|
||||
|
||||
},
|
||||
|
||||
selectedItem: {
|
||||
id: '',
|
||||
tipo_persona: '',
|
||||
name: '',
|
||||
|
||||
},
|
||||
|
||||
|
||||
|
||||
|
||||
loadData() {
|
||||
if (this.search !== '') {
|
||||
this.page = 1;
|
||||
this.limit = 100;
|
||||
} else {
|
||||
this.limit = 10;
|
||||
}
|
||||
this.loading = true;
|
||||
axios.get('/app/loadactualizaciondatosusuarios', {
|
||||
params: {
|
||||
page: this.page,
|
||||
limit: this.limit,
|
||||
search: this.search
|
||||
}
|
||||
}).then(response => {
|
||||
|
||||
this.datos = response.data.registros.map(data => ({
|
||||
id: data.ID,
|
||||
tipo_persona: data.tipo_persona,
|
||||
name: data.name,
|
||||
created_at: data.CreatedAt,
|
||||
}));
|
||||
this.totalPages = response.data.totalPages;
|
||||
this.calculatePaginatedPages();
|
||||
}).catch(error => {
|
||||
console.error('Error al obtener datos:', error);
|
||||
}).finally(() => {
|
||||
this.loading = false;
|
||||
});
|
||||
},
|
||||
|
||||
calculatePaginatedPages() {
|
||||
const maxVisiblePages = 5;
|
||||
const pages = [];
|
||||
const startPage = Math.max(1, this.page - Math.floor(maxVisiblePages / 2));
|
||||
const endPage = Math.min(this.totalPages, startPage + maxVisiblePages - 1);
|
||||
|
||||
for (let i = startPage; i <= endPage; i++) {
|
||||
pages.push(i);
|
||||
}
|
||||
|
||||
this.paginatedPages = pages;
|
||||
},
|
||||
|
||||
goToPage(page) {
|
||||
this.page = page;
|
||||
this.loadData();
|
||||
},
|
||||
|
||||
init() {
|
||||
this.loadData();
|
||||
},
|
||||
|
||||
openViewModal(data) {
|
||||
|
||||
this.selectedItem.id = data.id;
|
||||
this.selectedItem.tipo_persona = data.tipo_persona;
|
||||
this.selectedItem.name = data.name;
|
||||
|
||||
|
||||
this.viewModal = true;
|
||||
},
|
||||
|
||||
|
||||
|
||||
exportToExcel() {
|
||||
axios.get('/app/export/actualizacion-datos-usuarios', {
|
||||
responseType: 'blob', // Importante para manejar el archivo binario
|
||||
}).then(response => {
|
||||
const url = window.URL.createObjectURL(new Blob([response.data]));
|
||||
const link = document.createElement('a');
|
||||
link.href = url;
|
||||
link.setAttribute('download', 'actualizacion_datos_usuarios.xlsx'); // Nombre del archivo
|
||||
document.body.appendChild(link);
|
||||
link.click();
|
||||
}).catch(error => {
|
||||
console.error('Error al exportar datos:', error);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
</script>
|
||||
`)
|
||||
}
|
||||
|
||||
// ELIMINAR
|
||||
func DeleteSubmodule(c *fiber.Ctx) error {
|
||||
uid, err := strconv.ParseUint(c.Params("id"), 10, 32)
|
||||
if err != nil {
|
||||
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{
|
||||
"message": "Invalid ID",
|
||||
"error": true,
|
||||
})
|
||||
}
|
||||
|
||||
if err := models.DeleteSumodule(uint(uid)); err != nil { // Ensure you have a function for deleting a module
|
||||
return c.JSON(fiber.Map{
|
||||
"message": err.Error(),
|
||||
"error": true,
|
||||
})
|
||||
}
|
||||
return c.JSON(fiber.Map{
|
||||
"message": "Registro eliminado correctamente",
|
||||
"error": false,
|
||||
})
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
package controllers
|
||||
|
||||
import (
|
||||
"github.com/gofiber/fiber/v2" //nolint:goimports
|
||||
"github.com/sujit-baniya/fiber-boilerplate/pkg/auth"
|
||||
"github.com/sujit-baniya/fiber-boilerplate/pkg/models"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
|
||||
func UserInfo(c *fiber.Ctx) error {
|
||||
users, err := models.GetUserById(c.Params("id"))
|
||||
if err != nil {
|
||||
return c.JSON(fiber.Map{
|
||||
"message": err.Error(),
|
||||
"error": true,
|
||||
})
|
||||
}
|
||||
return c.JSON(users)
|
||||
}
|
||||
|
||||
func Me(c *fiber.Ctx) error {
|
||||
user, _ := auth.User(c)
|
||||
return c.JSON(user)
|
||||
}
|
||||
|
||||
func UserSettings(c *fiber.Ctx) error {
|
||||
uid, _ := strconv.ParseUint(c.Params("id"), 10, 32)
|
||||
user := models.User{
|
||||
ID: uint(uid),
|
||||
}
|
||||
settings, err := user.Settings()
|
||||
if err != nil {
|
||||
return c.JSON(fiber.Map{
|
||||
"message": err.Error(),
|
||||
"error": true,
|
||||
})
|
||||
}
|
||||
return c.JSON(settings)
|
||||
}
|
||||
|
||||
func StoreUserSettings(c *fiber.Ctx) error {
|
||||
var userSettings models.UserSetting
|
||||
c.BodyParser(&userSettings)
|
||||
uid, _ := strconv.ParseUint(c.Params("id"), 10, 32)
|
||||
userSettings.UserID = uint(uid)
|
||||
userSettings.UpdateOrCreate()
|
||||
return c.JSON(userSettings)
|
||||
}
|
||||
@@ -0,0 +1,556 @@
|
||||
package controllers
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math"
|
||||
"strconv"
|
||||
|
||||
"github.com/gofiber/fiber/v2" //nolint:goimports
|
||||
"github.com/sujit-baniya/fiber-boilerplate/app"
|
||||
"github.com/sujit-baniya/fiber-boilerplate/config"
|
||||
"github.com/sujit-baniya/fiber-boilerplate/pkg/models"
|
||||
"github.com/sujit-baniya/fiber-boilerplate/pkg/services"
|
||||
)
|
||||
|
||||
// RENDER
|
||||
func Users(c *fiber.Ctx) error {
|
||||
data := fiber.Map{
|
||||
"user": c.Locals("user").(map[string]interface{}),
|
||||
"modules": c.Locals("userModules"),
|
||||
}
|
||||
|
||||
// Renderiza la vista "modules" con el layout "layouts/landing"
|
||||
if err := c.Render("users", data, "layouts/main"); err != nil {
|
||||
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
|
||||
"message": "Error rendering template",
|
||||
"error": err.Error(),
|
||||
})
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// RENDER usuarios gas
|
||||
func UsersGas(c *fiber.Ctx) error {
|
||||
data := fiber.Map{
|
||||
"user": c.Locals("user").(map[string]interface{}),
|
||||
"modules": c.Locals("userModules"),
|
||||
}
|
||||
// Renderiza la vista "modules" con el layout "layouts/landing"
|
||||
if err := c.Render("users_gas", data, "layouts/main"); err != nil {
|
||||
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
|
||||
"message": "Error rendering template",
|
||||
"error": err.Error(),
|
||||
})
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// CONSULTAR TODOS LOS REGISTROS
|
||||
func GetUsers(c *fiber.Ctx) error {
|
||||
// Obtener parámetros de consulta para la paginación
|
||||
pageStr := c.Query("page", "1") // Por defecto, la página es 1
|
||||
page, err := strconv.Atoi(pageStr)
|
||||
if err != nil || page < 1 {
|
||||
page = 1
|
||||
}
|
||||
|
||||
searchQuery := c.Query("search", "") // Obtener el término de búsqueda
|
||||
limit := 10 // Número de módulos por página
|
||||
offset := (page - 1) * limit
|
||||
|
||||
// Llama a AllUsers con el término de búsqueda
|
||||
Users, totalUsers, err := models.AllUsersSistema(limit, offset, searchQuery)
|
||||
if err != nil {
|
||||
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
|
||||
"message": "Error retrieving users",
|
||||
"error": err.Error(),
|
||||
})
|
||||
}
|
||||
|
||||
// Llama a AllRoles sin el término de búsqueda para obtener todos los roles
|
||||
roles, err := models.AllRolesSelect() // Pasamos 0 para limit y offset para obtener todos los roles
|
||||
if err != nil {
|
||||
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
|
||||
"message": "Error retrieving roles",
|
||||
"error": err.Error(),
|
||||
})
|
||||
}
|
||||
|
||||
// Calcular el total de páginas para usuarios
|
||||
totalPages := int(math.Ceil(float64(totalUsers) / float64(limit)))
|
||||
|
||||
// Envía los usuarios y roles como respuesta JSON junto con la información de paginación
|
||||
return c.JSON(fiber.Map{
|
||||
"Users": Users,
|
||||
"Roles": roles,
|
||||
"total": totalUsers, // Total de usuarios disponibles
|
||||
"totalPages": totalPages, // Total de páginas
|
||||
"page": page, // Página actual
|
||||
"limit": limit, // Límites por página
|
||||
})
|
||||
}
|
||||
|
||||
// CONSULTAR TODOS LOS REGISTROS GAS
|
||||
func GetusersGas(c *fiber.Ctx) error {
|
||||
// Obtener parámetros de consulta para la paginación
|
||||
pageStr := c.Query("page", "1") // Por defecto, la página es 1
|
||||
page, err := strconv.Atoi(pageStr)
|
||||
if err != nil || page < 1 {
|
||||
page = 1
|
||||
}
|
||||
|
||||
searchQuery := c.Query("search", "") // Obtener el término de búsqueda
|
||||
limit := 10 // Número de módulos por página
|
||||
offset := (page - 1) * limit
|
||||
|
||||
// Llama a AllUsers con el término de búsqueda
|
||||
Users, totalUsers, err := models.AllUsersGas(limit, offset, searchQuery)
|
||||
if err != nil {
|
||||
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
|
||||
"message": "Error retrieving users",
|
||||
"error": err.Error(),
|
||||
})
|
||||
}
|
||||
|
||||
// Calcular el total de páginas para usuarios
|
||||
totalPages := int(math.Ceil(float64(totalUsers) / float64(limit)))
|
||||
|
||||
// Envía los usuarios y roles como respuesta JSON junto con la información de paginación
|
||||
return c.JSON(fiber.Map{
|
||||
"Users": Users,
|
||||
"total": totalUsers, // Total de usuarios disponibles
|
||||
"totalPages": totalPages, // Total de páginas
|
||||
"page": page, // Página actual
|
||||
"limit": limit, // Límites por página
|
||||
})
|
||||
}
|
||||
|
||||
// GetUser consulta un solo registro de usuario por su ID
|
||||
func GetUser(c *fiber.Ctx) error {
|
||||
// Obtiene el ID del parámetro de la URL
|
||||
idParam := c.Params("id")
|
||||
fmt.Print(idParam)
|
||||
|
||||
// Convierte el parámetro a un uint
|
||||
userID, err := strconv.ParseUint(idParam, 10, 32)
|
||||
if err != nil {
|
||||
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{
|
||||
"message": "Invalid user ID",
|
||||
"error": err.Error(),
|
||||
})
|
||||
}
|
||||
|
||||
// Canal para recibir el resultado de la consulta
|
||||
resultChan := make(chan *models.Users)
|
||||
errorChan := make(chan error)
|
||||
|
||||
// Ejecuta la consulta en una goroutine
|
||||
go func() {
|
||||
user, err := models.FindUserByID(uint(userID))
|
||||
if err != nil {
|
||||
errorChan <- err
|
||||
return
|
||||
}
|
||||
// Si no hay error, envía el resultado al canal
|
||||
resultChan <- user
|
||||
}()
|
||||
|
||||
// Espera el resultado o el error de la goroutine
|
||||
select {
|
||||
case user := <-resultChan:
|
||||
// Si el usuario no existe
|
||||
if user == nil {
|
||||
return c.Status(fiber.StatusNotFound).JSON(fiber.Map{
|
||||
"message": "User not found",
|
||||
})
|
||||
}
|
||||
// Envía el usuario como respuesta JSON
|
||||
return c.JSON(fiber.Map{
|
||||
"user": user,
|
||||
})
|
||||
case err := <-errorChan:
|
||||
// Maneja el error
|
||||
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
|
||||
"message": "Error retrieving user",
|
||||
"error": err.Error(),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func UpdateUser(c *fiber.Ctx) error {
|
||||
var m models.Users
|
||||
uid, err := strconv.ParseUint(c.Params("id"), 10, 32)
|
||||
if err != nil {
|
||||
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{
|
||||
"message": "ID inválido",
|
||||
"error": true,
|
||||
})
|
||||
}
|
||||
|
||||
// Analiza el cuerpo de la solicitud
|
||||
if err := c.BodyParser(&m); err != nil {
|
||||
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{
|
||||
"message": "Error al analizar el cuerpo de la solicitud",
|
||||
"error": true,
|
||||
})
|
||||
}
|
||||
|
||||
m.ID = uint(uid)
|
||||
|
||||
// Si el campo Estado está presente, solo se actualiza ese campo
|
||||
if m.Estado != nil {
|
||||
// Actualiza el estado del usuario
|
||||
if err := models.UpdateUserEstado(m.ID, *m.Estado); err != nil {
|
||||
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
|
||||
"message": err.Error(),
|
||||
"error": true,
|
||||
})
|
||||
}
|
||||
return c.Status(fiber.StatusOK).JSON(fiber.Map{
|
||||
"message": "Estado del usuario actualizado con éxito",
|
||||
"error": false,
|
||||
"user": m,
|
||||
})
|
||||
}
|
||||
|
||||
// Verifica que al menos dos de los campos relevantes estén llenos (Name, NombreUsuario, Email)
|
||||
if (m.Name == "" && m.NombreUsuario == "" && m.Email == "") ||
|
||||
(m.Name == "" && m.Email == "") ||
|
||||
(m.NombreUsuario == "" && m.Email == "") {
|
||||
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{
|
||||
"message": "Se deben llenar al menos dos de los siguientes campos: Name, NombreUsuario, Email",
|
||||
"error": true,
|
||||
})
|
||||
}
|
||||
|
||||
// Crea un mapa para los campos que se actualizarán
|
||||
updates := make(map[string]interface{})
|
||||
|
||||
// Agrega los campos que están presentes en la solicitud
|
||||
if m.Name != "" {
|
||||
updates["Name"] = m.Name
|
||||
}
|
||||
if m.NombreUsuario != "" {
|
||||
updates["NombreUsuario"] = m.NombreUsuario
|
||||
}
|
||||
if m.Email != "" {
|
||||
updates["email"] = m.Email
|
||||
}
|
||||
if m.RoleID != 0 {
|
||||
updates["role_id"] = m.RoleID
|
||||
}
|
||||
|
||||
// Realiza la actualización de los campos seleccionados
|
||||
if err := models.UpdateUser(m.ID, m.Name, m.NombreUsuario, m.Email, int(m.RoleID)); err != nil {
|
||||
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
|
||||
"message": err.Error(),
|
||||
"error": true,
|
||||
})
|
||||
}
|
||||
|
||||
return c.Status(fiber.StatusOK).JSON(fiber.Map{
|
||||
"message": "Usuario actualizado con éxito",
|
||||
"error": false,
|
||||
"user": m,
|
||||
})
|
||||
}
|
||||
|
||||
func UpdateUserGas(c *fiber.Ctx) error {
|
||||
var m models.Users
|
||||
uid, err := strconv.ParseUint(c.Params("id"), 10, 32)
|
||||
if err != nil {
|
||||
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{
|
||||
"message": "ID inválido",
|
||||
"error": true,
|
||||
})
|
||||
}
|
||||
|
||||
var existing models.Users
|
||||
if err := app.Http.Database.DB.First(&existing, uid).Error; err != nil {
|
||||
return c.Status(fiber.StatusNotFound).JSON(fiber.Map{
|
||||
"message": "Registro no encontrado",
|
||||
"error": true,
|
||||
})
|
||||
}
|
||||
|
||||
if err := c.BodyParser(&m); err != nil {
|
||||
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{
|
||||
"message": "Error al analizar el cuerpo de la solicitud",
|
||||
"error": true,
|
||||
})
|
||||
}
|
||||
|
||||
if m.Name != "" {
|
||||
existing.Name = m.Name
|
||||
}
|
||||
if m.NombreUsuario != "" {
|
||||
existing.NombreUsuario = m.NombreUsuario
|
||||
}
|
||||
if m.NumeroMedidor != "" {
|
||||
existing.NumeroMedidor = m.NumeroMedidor
|
||||
}
|
||||
if m.Email != "" {
|
||||
existing.Email = m.Email
|
||||
}
|
||||
if m.Celular != "" {
|
||||
existing.Celular = m.Celular
|
||||
}
|
||||
|
||||
if err := app.Http.Database.DB.Save(&existing).Error; err != nil {
|
||||
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
|
||||
"message": "Error al guardar los cambios",
|
||||
"error": true,
|
||||
})
|
||||
}
|
||||
|
||||
return c.Status(fiber.StatusOK).JSON(fiber.Map{
|
||||
"message": "Usuario actualizado con éxito",
|
||||
"error": false,
|
||||
"user": existing,
|
||||
})
|
||||
}
|
||||
|
||||
// ACTUALIZAR
|
||||
func UpdatePassword(c *fiber.Ctx) error {
|
||||
var m models.Users
|
||||
uid, err := strconv.ParseUint(c.Params("id"), 10, 32)
|
||||
if err != nil {
|
||||
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{
|
||||
"message": "ID inválido",
|
||||
"error": true,
|
||||
})
|
||||
}
|
||||
|
||||
// Analiza el cuerpo de la solicitud
|
||||
if err := c.BodyParser(&m); err != nil {
|
||||
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{
|
||||
"message": "Error al analizar el cuerpo de la solicitud",
|
||||
"error": true,
|
||||
})
|
||||
}
|
||||
|
||||
m.ID = uint(uid)
|
||||
|
||||
// Verifica si hay un nuevo password para actualizar
|
||||
if m.Password != "" {
|
||||
// Crea una instancia de Hash
|
||||
hash := config.Hash{}
|
||||
|
||||
// Encripta la nueva contraseña
|
||||
hashedPassword, err := hash.Create(m.Password)
|
||||
if err != nil {
|
||||
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
|
||||
"message": "Error al encriptar la contraseña",
|
||||
"error": true,
|
||||
})
|
||||
}
|
||||
// Asigna la contraseña encriptada al modelo
|
||||
m.Password = hashedPassword
|
||||
|
||||
// Actualiza solo el campo de contraseña en la base de datos
|
||||
if err := models.UpdateUserPassword(m.ID, m.Password); err != nil {
|
||||
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
|
||||
"message": err.Error(),
|
||||
"error": true,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
return c.Status(fiber.StatusOK).JSON(fiber.Map{
|
||||
"message": "Contraseña actualizada con éxito",
|
||||
"error": false,
|
||||
})
|
||||
}
|
||||
|
||||
// CREAR
|
||||
func CreateUser(c *fiber.Ctx) error {
|
||||
var m models.Users
|
||||
|
||||
// Analiza el cuerpo de la solicitud
|
||||
if err := c.BodyParser(&m); err != nil {
|
||||
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{
|
||||
"message": "Error al analizar el cuerpo de la solicitud",
|
||||
"error": true,
|
||||
})
|
||||
}
|
||||
|
||||
// Crea el nuevo módulo en la base de datos
|
||||
if err := models.CreateUser(m); err != nil { // Asegúrate de tener una función para crear un módulo
|
||||
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
|
||||
"message": err.Error(),
|
||||
"error": true,
|
||||
})
|
||||
}
|
||||
|
||||
return c.Status(fiber.StatusCreated).JSON(fiber.Map{
|
||||
"message": "Usuario creado con éxito",
|
||||
"error": false,
|
||||
"user": m,
|
||||
})
|
||||
}
|
||||
|
||||
// ELIMINAR
|
||||
func DeleteUser(c *fiber.Ctx) error {
|
||||
uid, err := strconv.ParseUint(c.Params("id"), 10, 32)
|
||||
if err != nil {
|
||||
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{
|
||||
"message": "Invalid ID",
|
||||
"error": true,
|
||||
})
|
||||
}
|
||||
|
||||
if err := models.DeleteUser(uint(uid)); err != nil { // Ensure you have a function for deleting a module
|
||||
return c.JSON(fiber.Map{
|
||||
"message": err.Error(),
|
||||
"error": true,
|
||||
})
|
||||
}
|
||||
return c.JSON(fiber.Map{
|
||||
"message": "Usuario eliminado correctamente",
|
||||
"error": false,
|
||||
})
|
||||
}
|
||||
|
||||
func CreateUserGas(c *fiber.Ctx) error {
|
||||
var m models.Users
|
||||
|
||||
// Analiza el cuerpo de la solicitud
|
||||
if err := c.BodyParser(&m); err != nil {
|
||||
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{
|
||||
"message": "Error al analizar el cuerpo de la solicitud",
|
||||
"error": true,
|
||||
})
|
||||
}
|
||||
|
||||
// Verifica si el nombre de usuario ya existe
|
||||
exists, err := models.CheckUsernameExists(m.NombreUsuario)
|
||||
if err != nil {
|
||||
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
|
||||
"message": "Error al verificar el nombre de usuario",
|
||||
"error": err.Error(),
|
||||
})
|
||||
}
|
||||
|
||||
if exists {
|
||||
return c.Status(fiber.StatusConflict).JSON(fiber.Map{
|
||||
"message": "El codigo ya se encuentra registrado",
|
||||
"error": true,
|
||||
})
|
||||
}
|
||||
// Debug: imprimir los datos que se pasan a GetValidarMedidor
|
||||
fmt.Println("Llamando a GetValidarMedidor con NombreUsuario:", m.NombreUsuario, "y NumeroMedidor:", m.NumeroMedidor)
|
||||
// Aquí llamamos a la función GetValidarMedidor pasándole el código y medidor directamente desde el cuerpo de la solicitud
|
||||
|
||||
|
||||
// Obtén el RoleID basado en el RoleName
|
||||
roleName := "Usuarios"
|
||||
role, err := models.FindRoleByName(roleName)
|
||||
if err != nil {
|
||||
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
|
||||
"message": "Error al obtener el rol",
|
||||
"error": err.Error(),
|
||||
})
|
||||
}
|
||||
|
||||
// Asigna el RoleID al usuario
|
||||
m.RoleID = role.ID
|
||||
m.TipoUsuario = "gas"
|
||||
estado := true
|
||||
m.Estado = &estado
|
||||
m.Password = ""
|
||||
|
||||
// Crea el nuevo usuario en la base de datos (sin asignar el ID manualmente)
|
||||
if err := models.CreateUser(m); err != nil {
|
||||
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
|
||||
"message": err.Error(),
|
||||
"error": true,
|
||||
})
|
||||
}
|
||||
|
||||
user, err := models.GetUserByUsuarioVerify(m.NombreUsuario)
|
||||
if err != nil {
|
||||
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
|
||||
"message": "Error retrieving user",
|
||||
"error": err.Error(),
|
||||
})
|
||||
}
|
||||
// Aquí el modelo `m` debe tener el ID generado por la base de datos
|
||||
fmt.Println("Nuevo usuario creado con ID:", user.ID)
|
||||
|
||||
// Llama a la función createPassword pasando el ID del nuevo usuario
|
||||
if err := createPassword(c, user.ID); err != nil {
|
||||
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
|
||||
"message": "Error al actualizar la contraseña",
|
||||
"error": true,
|
||||
})
|
||||
}
|
||||
|
||||
// Envía un correo de confirmación
|
||||
go services.SendConfirmationEmail(m.Email, app.Http.Server.Url, m.NombreUsuario)
|
||||
|
||||
return c.Status(fiber.StatusCreated).JSON(fiber.Map{
|
||||
"message": "Usuario creado con éxito",
|
||||
"error": false,
|
||||
"user": m,
|
||||
})
|
||||
}
|
||||
|
||||
func createPassword(c *fiber.Ctx, UserId uint) error {
|
||||
// Modelo para recibir los datos del cuerpo de la solicitud
|
||||
type PasswordUpdateRequest struct {
|
||||
Password string `json:"password"`
|
||||
}
|
||||
|
||||
var req PasswordUpdateRequest
|
||||
|
||||
// Analiza el cuerpo de la solicitud
|
||||
fmt.Println("Recibiendo solicitud para actualizar contraseña...")
|
||||
if err := c.BodyParser(&req); err != nil {
|
||||
fmt.Println("Error al analizar el cuerpo de la solicitud:", err)
|
||||
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{
|
||||
"message": "Error al analizar el cuerpo de la solicitud",
|
||||
"error": true,
|
||||
})
|
||||
}
|
||||
|
||||
// Verifica si el password no está vacío
|
||||
if req.Password == "" {
|
||||
fmt.Println("La contraseña no puede estar vacía")
|
||||
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{
|
||||
"message": "La contraseña no puede estar vacía",
|
||||
"error": true,
|
||||
})
|
||||
}
|
||||
|
||||
// Crea una instancia del encriptador de contraseñas
|
||||
hash := config.Hash{}
|
||||
|
||||
// Encripta la nueva contraseña
|
||||
fmt.Println("Encriptando la contraseña...")
|
||||
hashedPassword, err := hash.Create(req.Password)
|
||||
if err != nil {
|
||||
fmt.Println("Error al encriptar la contraseña:", err)
|
||||
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
|
||||
"message": "Error al encriptar la contraseña",
|
||||
"error": true,
|
||||
})
|
||||
}
|
||||
fmt.Println("Contraseña encriptada con éxito.")
|
||||
|
||||
// Actualiza solo el campo de contraseña en la base de datos
|
||||
fmt.Printf("Actualizando la contraseña del usuario con ID %d\n", UserId)
|
||||
if err := models.UpdateUserPassword(UserId, hashedPassword); err != nil {
|
||||
fmt.Println("Error al actualizar la contraseña en la base de datos:", err)
|
||||
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
|
||||
"message": "Error al actualizar la contraseña en la base de datos",
|
||||
"error": true,
|
||||
})
|
||||
}
|
||||
|
||||
// Respuesta de éxito
|
||||
fmt.Println("Contraseña actualizada con éxito.")
|
||||
return c.Status(fiber.StatusOK).JSON(fiber.Map{
|
||||
"message": "Contraseña actualizada con éxito",
|
||||
"error": false,
|
||||
})
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
package middlewares
|
||||
|
||||
import (
|
||||
"github.com/gofiber/fiber/v2"
|
||||
"github.com/gookit/validate"
|
||||
"github.com/sujit-baniya/fiber-boilerplate/pkg/models"
|
||||
)
|
||||
|
||||
func ValidateApiLoginPost(c *fiber.Ctx) error {
|
||||
var login models.Login
|
||||
if err := c.BodyParser(&login); err != nil {
|
||||
return c.Status(401).JSON(fiber.Map{
|
||||
"error": true,
|
||||
"message": "Invalid Credentials",
|
||||
})
|
||||
}
|
||||
v := validate.Struct(login)
|
||||
if !v.Validate() {
|
||||
return c.Status(401).JSON(fiber.Map{
|
||||
"error": true,
|
||||
"message": "Invalid Credentials",
|
||||
})
|
||||
}
|
||||
user, err := login.CheckLogin() //nolint:wsl
|
||||
|
||||
if err != nil {
|
||||
return c.Status(401).JSON(fiber.Map{
|
||||
"error": true,
|
||||
"message": "Invalid Credentials",
|
||||
})
|
||||
}
|
||||
c.Locals("user", user)
|
||||
return c.Next()
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
package middlewares
|
||||
|
||||
import (
|
||||
"github.com/gofiber/fiber/v2"
|
||||
"github.com/gookit/validate"
|
||||
"github.com/sujit-baniya/fiber-boilerplate/pkg/models"
|
||||
)
|
||||
|
||||
func ValidateApiRegisterPost(c *fiber.Ctx) error {
|
||||
var register models.RegisterForm
|
||||
if err := c.BodyParser(®ister); err != nil {
|
||||
return c.Status(401).JSON(fiber.Map{
|
||||
"error": true,
|
||||
"message": err.Error(),
|
||||
})
|
||||
}
|
||||
|
||||
v := validate.Struct(register)
|
||||
if !v.Validate() {
|
||||
return c.Status(401).JSON(fiber.Map{
|
||||
"error": true,
|
||||
"message": v.Errors,
|
||||
})
|
||||
}
|
||||
c.Locals("register", register)
|
||||
return c.Next()
|
||||
}
|
||||
@@ -0,0 +1,272 @@
|
||||
package middlewares
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"strings"
|
||||
|
||||
"github.com/oarkflow/log"
|
||||
|
||||
"github.com/sujit-baniya/fiber-boilerplate/app"
|
||||
config2 "github.com/sujit-baniya/fiber-boilerplate/config"
|
||||
"github.com/sujit-baniya/fiber-boilerplate/pkg/auth"
|
||||
|
||||
"github.com/form3tech-oss/jwt-go"
|
||||
"github.com/gofiber/fiber/v2"
|
||||
)
|
||||
|
||||
// Config defines the config for BasicAuth middleware
|
||||
type AuthConfig struct {
|
||||
// Filter defines a function to skip middleware.
|
||||
// Optional. Default: nil
|
||||
Filter func(*fiber.Ctx) bool
|
||||
|
||||
// SuccessHandler defines a function which is executed for a valid token.
|
||||
// Optional. Default: nil
|
||||
SuccessHandler fiber.Handler
|
||||
|
||||
// ErrorHandler defines a function which is executed for an invalid token.
|
||||
// It may be used to define a custom JWT error.
|
||||
// Optional. Default: 401 Invalid or expired JWT
|
||||
ErrorHandler fiber.ErrorHandler
|
||||
|
||||
// Signing key to validate token. Used as fallback if SigningKeys has length 0.
|
||||
// Required. This or SigningKeys.
|
||||
SigningKey interface{}
|
||||
|
||||
// Map of signing keys to validate token with kid field usage.
|
||||
// Required. This or SigningKey.
|
||||
SigningKeys map[string]interface{}
|
||||
|
||||
// Signing method, used to check token signing method.
|
||||
// Optional. Default: "HS256".
|
||||
// Possible values: "HS256", "HS384", "HS512", "ES256", "ES384", "ES512", "RS256", "RS384", "RS512"
|
||||
SigningMethod string
|
||||
|
||||
// Context key to store user information from the token into context.
|
||||
// Optional. Default: "user".
|
||||
ContextKey string
|
||||
|
||||
// Claims are extendable claims data defining token content.
|
||||
// Optional. Default value jwt.MapClaims
|
||||
Claims jwt.Claims
|
||||
|
||||
// TokenLookup is a string in the form of "<source>:<name>" that is used
|
||||
// to extract token from the request.
|
||||
// Optional. Default value "header:Authorization".
|
||||
// Possible values:
|
||||
// - "header:<name>"
|
||||
// - "query:<name>"
|
||||
// - "param:<name>"
|
||||
// - "cookie:<name>"
|
||||
TokenLookup string
|
||||
|
||||
// AuthScheme to be used in the Authorization header.
|
||||
// Optional. Default: "Bearer".
|
||||
AuthScheme string
|
||||
|
||||
keyFunc jwt.Keyfunc
|
||||
}
|
||||
|
||||
// New ...
|
||||
func Authenticate(config ...AuthConfig) fiber.Handler {
|
||||
// Init config
|
||||
var cfg AuthConfig
|
||||
if len(config) > 0 {
|
||||
cfg = config[0]
|
||||
}
|
||||
if cfg.SuccessHandler == nil {
|
||||
cfg.SuccessHandler = func(c *fiber.Ctx) error {
|
||||
return c.Next()
|
||||
}
|
||||
}
|
||||
if cfg.ErrorHandler == nil {
|
||||
cfg.ErrorHandler = func(c *fiber.Ctx, err error) error {
|
||||
var er fiber.Error
|
||||
if err.Error() == "Missing or malformed JWT" {
|
||||
er.Code = fiber.StatusBadRequest
|
||||
} else {
|
||||
er.Code = fiber.StatusUnauthorized
|
||||
}
|
||||
er.Message = err.Error()
|
||||
return config2.CustomErrorHandler(c, &er)
|
||||
}
|
||||
}
|
||||
if cfg.SigningKey == nil && len(cfg.SigningKeys) == 0 {
|
||||
log.Error().Msg("Fiber: JWT middleware requires signing key")
|
||||
}
|
||||
if cfg.SigningMethod == "" {
|
||||
cfg.SigningMethod = "HS256"
|
||||
}
|
||||
if cfg.ContextKey == "" {
|
||||
cfg.ContextKey = "user"
|
||||
}
|
||||
if cfg.Claims == nil {
|
||||
cfg.Claims = jwt.MapClaims{}
|
||||
}
|
||||
if cfg.TokenLookup == "" {
|
||||
cfg.TokenLookup = "header:" + fiber.HeaderAuthorization
|
||||
}
|
||||
if cfg.AuthScheme == "" {
|
||||
cfg.AuthScheme = "Bearer"
|
||||
}
|
||||
cfg.keyFunc = func(t *jwt.Token) (interface{}, error) {
|
||||
// Check the signing method
|
||||
if t.Method.Alg() != cfg.SigningMethod {
|
||||
return nil, fmt.Errorf("Unexpected jwt signing method=%v", t.Header["alg"])
|
||||
}
|
||||
if len(cfg.SigningKeys) > 0 {
|
||||
if kid, ok := t.Header["kid"].(string); ok {
|
||||
if key, ok := cfg.SigningKeys[kid]; ok {
|
||||
return key, nil
|
||||
}
|
||||
}
|
||||
return nil, fmt.Errorf("Unexpected jwt key id=%v", t.Header["kid"])
|
||||
}
|
||||
return cfg.SigningKey, nil
|
||||
}
|
||||
// Initialize
|
||||
extractors := make([]func(c *fiber.Ctx) (string, error), 0)
|
||||
rootParts := strings.Split(cfg.TokenLookup, ",")
|
||||
for _, rootPart := range rootParts {
|
||||
parts := strings.Split(strings.TrimSpace(rootPart), ":")
|
||||
|
||||
switch parts[0] {
|
||||
case "header":
|
||||
extractors = append(extractors, jwtFromHeader(parts[1], cfg.AuthScheme))
|
||||
case "query":
|
||||
extractors = append(extractors, jwtFromQuery(parts[1]))
|
||||
case "param":
|
||||
extractors = append(extractors, jwtFromParam(parts[1]))
|
||||
case "cookie":
|
||||
extractors = append(extractors, jwtFromCookie(parts[1]))
|
||||
}
|
||||
}
|
||||
// Return middleware handler
|
||||
return func(c *fiber.Ctx) error {
|
||||
// Filter request to skip middleware
|
||||
if cfg.Filter != nil && cfg.Filter(c) {
|
||||
return c.Next()
|
||||
}
|
||||
var auth string
|
||||
var err error
|
||||
|
||||
for _, extractor := range extractors {
|
||||
auth, err = extractor(c)
|
||||
if auth != "" && err == nil {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return cfg.ErrorHandler(c, err)
|
||||
}
|
||||
token := new(jwt.Token)
|
||||
if _, ok := cfg.Claims.(jwt.MapClaims); ok {
|
||||
token, err = jwt.Parse(auth, cfg.keyFunc)
|
||||
} else {
|
||||
t := reflect.ValueOf(cfg.Claims).Type().Elem()
|
||||
claims := reflect.New(t).Interface().(jwt.Claims)
|
||||
token, err = jwt.ParseWithClaims(auth, claims, cfg.keyFunc)
|
||||
}
|
||||
if err == nil && token.Valid {
|
||||
// Store user information from token into context.
|
||||
c.Locals(cfg.ContextKey, token)
|
||||
return cfg.SuccessHandler(c)
|
||||
}
|
||||
return cfg.ErrorHandler(c, err)
|
||||
}
|
||||
}
|
||||
|
||||
// jwtFromHeader returns a function that extracts token from the request header.
|
||||
func jwtFromHeader(header string, authScheme string) func(c *fiber.Ctx) (string, error) {
|
||||
return func(c *fiber.Ctx) (string, error) {
|
||||
auth := c.Get(header)
|
||||
l := len(authScheme)
|
||||
if len(auth) > l+1 && auth[:l] == authScheme {
|
||||
return auth[l+1:], nil
|
||||
}
|
||||
return "", errors.New("Missing or malformed JWT")
|
||||
}
|
||||
}
|
||||
|
||||
// jwtFromQuery returns a function that extracts token from the query string.
|
||||
func jwtFromQuery(param string) func(c *fiber.Ctx) (string, error) {
|
||||
return func(c *fiber.Ctx) (string, error) {
|
||||
token := c.Query(param)
|
||||
if token == "" {
|
||||
return "", errors.New("Missing or malformed JWT")
|
||||
}
|
||||
return token, nil
|
||||
}
|
||||
}
|
||||
|
||||
// jwtFromParam returns a function that extracts token from the url param string.
|
||||
func jwtFromParam(param string) func(c *fiber.Ctx) (string, error) {
|
||||
return func(c *fiber.Ctx) (string, error) {
|
||||
token := c.Params(param)
|
||||
if token == "" {
|
||||
return "", errors.New("Missing or malformed JWT")
|
||||
}
|
||||
return token, nil
|
||||
}
|
||||
}
|
||||
|
||||
// jwtFromCookie returns a function that extracts token from the named cookie.
|
||||
func jwtFromCookie(name string) func(c *fiber.Ctx) (string, error) {
|
||||
return func(c *fiber.Ctx) (string, error) {
|
||||
token := c.Cookies(name)
|
||||
if token == "" {
|
||||
return "", errors.New("Missing or malformed JWT")
|
||||
}
|
||||
return token, nil
|
||||
}
|
||||
}
|
||||
|
||||
func AuthWeb() func(*fiber.Ctx) error {
|
||||
// Definir la función que maneja la autenticación
|
||||
return func(c *fiber.Ctx) error {
|
||||
// Intentar obtener el usuario
|
||||
user, err := auth.User(c)
|
||||
|
||||
// Si no se puede obtener el usuario (es nil o hay error), hacer logout
|
||||
if err != nil || user == nil {
|
||||
// Ejecutar logout y destruir la sesión
|
||||
auth.Logout(c)
|
||||
|
||||
// Redirigir al login
|
||||
return c.Redirect("/login")
|
||||
}
|
||||
|
||||
// Si el usuario está presente, continuar con la autenticación normal
|
||||
return Authenticate(AuthConfig{
|
||||
SigningKey: []byte(app.Http.Token.AppJwtSecret),
|
||||
TokenLookup: "cookie:Verify-Rest-Token",
|
||||
ErrorHandler: func(ctx *fiber.Ctx, err error) error {
|
||||
// En caso de error de autenticación, hacer logout
|
||||
auth.Logout(ctx)
|
||||
return ctx.Redirect("/login")
|
||||
},
|
||||
})(c) // Llamar al siguiente middleware
|
||||
}
|
||||
}
|
||||
|
||||
func AuthAdmin(c *fiber.Ctx) error {
|
||||
if !auth.IsAdmin(c) {
|
||||
auth.Logout(c)
|
||||
return c.Redirect("/login")
|
||||
}
|
||||
return c.Next()
|
||||
}
|
||||
|
||||
func AuthApi() func(*fiber.Ctx) error {
|
||||
return Authenticate(AuthConfig{
|
||||
SigningKey: []byte(app.Http.Token.ApiJwtSecret),
|
||||
TokenLookup: "header:Verify-Rest-Token",
|
||||
ErrorHandler: func(ctx *fiber.Ctx, err error) error {
|
||||
auth.Logout(ctx)
|
||||
return ctx.Status(401).JSON("Invalid Attempt")
|
||||
},
|
||||
})
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
package middlewares
|
||||
|
||||
import (
|
||||
"github.com/gofiber/fiber/v2"
|
||||
"github.com/sujit-baniya/fiber-boilerplate/pkg/auth"
|
||||
)
|
||||
|
||||
func LoadUserMiddleware(c *fiber.Ctx) error {
|
||||
user, err := auth.User(c)
|
||||
if err == nil && user != nil {
|
||||
// Convertimos el usuario a un map[string]interface{} e incluimos los campos necesarios
|
||||
userData := map[string]interface{}{
|
||||
"ID": user.ID,
|
||||
"Name": user.Name,
|
||||
"Email": user.Email,
|
||||
"NombreUsuario": user.NombreUsuario,
|
||||
"IsAdmin": user.IsAdmin,
|
||||
"Role": map[string]interface{}{
|
||||
"ID": user.Role.ID,
|
||||
"Name": user.Role.Name,
|
||||
// Incluye otros campos relevantes del rol
|
||||
},
|
||||
}
|
||||
|
||||
// Guarda el map en el contexto
|
||||
c.Locals("user", userData)
|
||||
}
|
||||
// Si no está autenticado, continuamos sin agregar nada
|
||||
return c.Next()
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
package middlewares
|
||||
|
||||
import "github.com/gofiber/fiber/v2"
|
||||
|
||||
func LoadCacheHeaders(c *fiber.Ctx) error {
|
||||
c.Set("X-DNS-Prefetch-Control", "off")
|
||||
c.Set("Pragma", "no-cache")
|
||||
c.Set("Expires", "Fri, 01 Jan 1990 00:00:00 GMT")
|
||||
c.Set("Cache-Control", "no-cache, must-revalidate, no-store, max-age=0, private")
|
||||
return c.Next()
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
package middlewares
|
||||
|
||||
import (
|
||||
"github.com/gofiber/fiber/v2"
|
||||
"github.com/sujit-baniya/fiber-boilerplate/pkg/auth"
|
||||
)
|
||||
|
||||
func LimitPhoneNumbersPerRequest(c *fiber.Ctx) error {
|
||||
if auth.IsLoggedIn(c) {
|
||||
return c.Redirect("/")
|
||||
}
|
||||
return c.Next()
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
package middlewares
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/gofiber/fiber/v2"
|
||||
"github.com/oarkflow/log"
|
||||
)
|
||||
|
||||
func NewLog(logger *log.Logger, skip func(c *fiber.Ctx) bool) fiber.Handler {
|
||||
return func(c *fiber.Ctx) error {
|
||||
start := time.Now()
|
||||
next := c.Next()
|
||||
|
||||
if skip != nil && skip(c) {
|
||||
return nil
|
||||
}
|
||||
|
||||
end := time.Now()
|
||||
latency := end.Sub(start)
|
||||
|
||||
status := c.Response().StatusCode()
|
||||
msg := "Request"
|
||||
if next != nil {
|
||||
msg = next.Error()
|
||||
}
|
||||
|
||||
var e *log.Entry
|
||||
switch {
|
||||
case status >= 400 && status < 500:
|
||||
e = logger.Warn()
|
||||
case status >= 500:
|
||||
e = logger.Error()
|
||||
default:
|
||||
e = logger.Info()
|
||||
}
|
||||
e.Int("status", status).
|
||||
Str("method", c.Method()).
|
||||
Str("path", c.Path()).
|
||||
Str("ip", c.IP()).
|
||||
Dur("latency", latency).
|
||||
Str("user_agent", c.Get(fiber.HeaderUserAgent)).
|
||||
Msg(msg)
|
||||
|
||||
return nil
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
package middlewares
|
||||
|
||||
import (
|
||||
"github.com/gofiber/fiber/v2"
|
||||
"github.com/gookit/validate"
|
||||
"github.com/sujit-baniya/fiber-boilerplate/pkg/auth"
|
||||
"github.com/sujit-baniya/fiber-boilerplate/pkg/models"
|
||||
)
|
||||
|
||||
func RedirectToHomePageOnLogin(c *fiber.Ctx) error {
|
||||
if auth.IsLoggedIn(c) {
|
||||
return c.Redirect("/app/dashboard")
|
||||
}
|
||||
return c.Next()
|
||||
}
|
||||
|
||||
func ValidateLoginPost(c *fiber.Ctx) error {
|
||||
var login models.Login
|
||||
if err := c.BodyParser(&login); err != nil {
|
||||
return c.JSON(fiber.Map{
|
||||
"status": "error",
|
||||
"message": err.Error(),
|
||||
})
|
||||
}
|
||||
v := validate.Struct(login)
|
||||
if !v.Validate() {
|
||||
return c.JSON(fiber.Map{
|
||||
"status": "error",
|
||||
"message": v.Errors.One(),
|
||||
})
|
||||
}
|
||||
|
||||
user, err := login.CheckLogin()
|
||||
|
||||
if err != nil {
|
||||
return c.JSON(fiber.Map{
|
||||
"status": "error",
|
||||
"message": err.Error(),
|
||||
})
|
||||
}
|
||||
|
||||
c.Locals("user", user)
|
||||
return c.Next()
|
||||
}
|
||||
@@ -0,0 +1,115 @@
|
||||
package middlewares
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
"github.com/gofiber/fiber/v2"
|
||||
"github.com/sujit-baniya/fiber-boilerplate/pkg/auth"
|
||||
"github.com/sujit-baniya/fiber-boilerplate/pkg/models"
|
||||
)
|
||||
|
||||
func MenuMiddleware(c *fiber.Ctx) error {
|
||||
// Verificar si el usuario está logueado
|
||||
if !auth.IsLoggedIn(c) {
|
||||
return c.Status(fiber.StatusUnauthorized).JSON(fiber.Map{
|
||||
"error": true,
|
||||
"message": "Usuario no autenticado",
|
||||
})
|
||||
}
|
||||
|
||||
// Obtener los datos del usuario autenticado
|
||||
user, err := auth.User(c)
|
||||
if err != nil {
|
||||
// Si ocurre un error al obtener el usuario, finalizar la solicitud
|
||||
fmt.Printf("Error al obtener usuario: %v\n", err)
|
||||
return c.Status(fiber.StatusUnauthorized).JSON(fiber.Map{
|
||||
"error": true,
|
||||
"message": "Usuario no válido o sesión expirada",
|
||||
})
|
||||
}
|
||||
|
||||
// Buscar los módulos y submódulos del usuario
|
||||
userModules, err := models.FindUserByID(user.ID)
|
||||
if err != nil {
|
||||
fmt.Printf("Error al buscar datos del usuario: %v\n", err)
|
||||
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
|
||||
"error": true,
|
||||
"message": "Error al obtener datos del usuario",
|
||||
})
|
||||
}
|
||||
|
||||
// Organizar los módulos y submódulos
|
||||
moduleMap := make(map[string][]map[string]string)
|
||||
|
||||
for _, submodule := range userModules.Role.Submodules {
|
||||
// Recuperar el nombre del módulo
|
||||
moduleName := submodule.Module.Title
|
||||
// Crear un mapa para cada submódulo que contenga el título y la URL
|
||||
submoduleData := map[string]string{
|
||||
"title": submodule.Title,
|
||||
"url": submodule.Url, // Suponiendo que el submódulo tiene un campo `URL`
|
||||
}
|
||||
// Agregar el submódulo a la lista correspondiente del módulo
|
||||
moduleMap[moduleName] = append(moduleMap[moduleName], submoduleData)
|
||||
}
|
||||
|
||||
// Ordenar los módulos alfabéticamente
|
||||
var sortedModules []string
|
||||
for module := range moduleMap {
|
||||
sortedModules = append(sortedModules, module)
|
||||
}
|
||||
sort.Strings(sortedModules)
|
||||
|
||||
// Ordenar los submódulos de cada módulo alfabéticamente
|
||||
for _, moduleName := range sortedModules {
|
||||
// Ordenar los submódulos alfabéticamente por título
|
||||
sort.Slice(moduleMap[moduleName], func(i, j int) bool {
|
||||
return moduleMap[moduleName][i]["title"] < moduleMap[moduleName][j]["title"]
|
||||
})
|
||||
}
|
||||
c.Locals("userModules", moduleMap)
|
||||
|
||||
// Obtener un array solo con las URLs
|
||||
var urls []string
|
||||
for _, submodules := range moduleMap {
|
||||
for _, submoduleData := range submodules {
|
||||
urls = append(urls, submoduleData["url"])
|
||||
}
|
||||
}
|
||||
|
||||
// Opcional: adjuntar la lista de URLs al contexto
|
||||
c.Locals("urls", urls)
|
||||
|
||||
// Verificar si la URL de la solicitud está en la lista de URLs permitidas
|
||||
requestURL := c.Path()
|
||||
|
||||
// Obtener el índice del último '/' en la URL de la solicitud
|
||||
lastSlashIndex := strings.LastIndex(requestURL, "/")
|
||||
if lastSlashIndex != -1 {
|
||||
// Obtener solo la parte de la URL después del último '/'
|
||||
requestURL = requestURL[lastSlashIndex+1:]
|
||||
}
|
||||
|
||||
// Verificar si la URL modificada está en la lista de URLs permitidas
|
||||
urlAllowed := false
|
||||
for _, url := range urls {
|
||||
// Comparar solo la parte de la URL después del último '/'
|
||||
if requestURL == url[strings.LastIndex(url, "/")+1:] {
|
||||
urlAllowed = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
// Si la URL no está permitida, devolver un error
|
||||
if !urlAllowed {
|
||||
return c.Status(fiber.StatusForbidden).JSON(fiber.Map{
|
||||
"error": true,
|
||||
"message": "Acceso no permitido a esta ruta",
|
||||
})
|
||||
}
|
||||
|
||||
// Continuar con la siguiente función de middleware o manejador
|
||||
return c.Next()
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
package middlewares
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/sujit-baniya/fiber-boilerplate/utils"
|
||||
|
||||
"github.com/gofiber/fiber/v2"
|
||||
"github.com/sujit-baniya/fiber-boilerplate/app"
|
||||
)
|
||||
|
||||
func ValidatePasswordReset(c *fiber.Ctx) error {
|
||||
token := c.Query("t")
|
||||
err := _validatePasswordReset(c, token)
|
||||
if err != nil {
|
||||
return app.Http.Flash.WithError(c, fiber.Map{
|
||||
"message": err.Error(),
|
||||
}).Redirect("/token-vencido")
|
||||
}
|
||||
return c.Next()
|
||||
}
|
||||
|
||||
func ValidatePasswordResetPost(c *fiber.Ctx) error {
|
||||
token := c.Params("token")
|
||||
err := _validatePasswordReset(c, token)
|
||||
if err != nil {
|
||||
return app.Http.Flash.WithError(c, fiber.Map{
|
||||
"message": err.Error(),
|
||||
}).Redirect("/login")
|
||||
}
|
||||
return c.Next()
|
||||
}
|
||||
|
||||
func _validatePasswordReset(c *fiber.Ctx, t string) error {
|
||||
t = utils.Decrypt(t, app.Http.Server.Key)
|
||||
emailParts := strings.Split(t, "-reset-")
|
||||
if len(emailParts) != 2 {
|
||||
return errors.New("Invalid Password Reset Token")
|
||||
}
|
||||
|
||||
tokenTS, err := strconv.ParseInt(emailParts[1], 10, 64)
|
||||
if err != nil {
|
||||
return errors.New("Invalid Password Reset Token")
|
||||
}
|
||||
now := time.Now().Unix()
|
||||
diff := now - tokenTS
|
||||
if diff > (5 * 60) {
|
||||
return errors.New("Password Reset Token has expired!")
|
||||
} else if diff < 0 {
|
||||
return errors.New("Invalid Password Reset Token")
|
||||
}
|
||||
c.Locals("email", emailParts[0])
|
||||
c.Locals("token", t)
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
package middlewares
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/sujit-baniya/fiber-boilerplate/utils"
|
||||
|
||||
"github.com/gofiber/fiber/v2"
|
||||
"github.com/gookit/validate"
|
||||
"github.com/sujit-baniya/fiber-boilerplate/app"
|
||||
"github.com/sujit-baniya/fiber-boilerplate/pkg/auth"
|
||||
"github.com/sujit-baniya/fiber-boilerplate/pkg/models"
|
||||
)
|
||||
|
||||
func ValidateRegisterPost(c *fiber.Ctx) error {
|
||||
// Declara el modelo RegisterForm
|
||||
var register models.RegisterForm
|
||||
|
||||
// Intenta parsear el cuerpo de la solicitud
|
||||
if err := c.BodyParser(®ister); err != nil {
|
||||
return app.Http.Flash.WithError(c, fiber.Map{
|
||||
"message": "Error al procesar los datos del formulario: " + err.Error(),
|
||||
}).Redirect("/register-gas")
|
||||
}
|
||||
|
||||
// Realiza la validación del formulario
|
||||
v := validate.Struct(register)
|
||||
if v == nil {
|
||||
return app.Http.Flash.WithError(c, fiber.Map{
|
||||
"message": "Error en la validación de los datos del formulario.",
|
||||
}).Redirect("/register-gas")
|
||||
}
|
||||
|
||||
// Verifica si hay errores de validación
|
||||
if !v.Validate() {
|
||||
errorMessage := "Error desconocido en los datos del formulario."
|
||||
if len(v.Errors) > 0 {
|
||||
errorMessage = v.Errors.One() // Obtiene el primer error si existe
|
||||
}
|
||||
return app.Http.Flash.WithError(c, fiber.Map{
|
||||
"message": errorMessage,
|
||||
}).Redirect("/register-gas")
|
||||
}
|
||||
|
||||
return c.Next()
|
||||
}
|
||||
|
||||
func ValidateConfirmToken(c *fiber.Ctx) error {
|
||||
t := utils.Decrypt(c.Query("t"), app.Http.Server.Key)
|
||||
fmt.Println(t)
|
||||
user, err := models.GetUserByUsuarioVerify(t)
|
||||
if err != nil {
|
||||
return app.Http.Flash.WithError(c, fiber.Map{
|
||||
"message": err.Error(),
|
||||
}).Redirect("/login")
|
||||
}
|
||||
|
||||
if user.EmailVerified {
|
||||
return app.Http.Flash.WithError(c, fiber.Map{
|
||||
"message": "Usuario was already validated",
|
||||
}).Redirect("/login")
|
||||
}
|
||||
user.EmailVerified = true
|
||||
app.Http.Database.DB.Save(&user)
|
||||
|
||||
auth.Login(c, user.ID, app.Http.Server.Key) //nolint:wsl
|
||||
c.Locals("user", user)
|
||||
return c.Next()
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
package middlewares
|
||||
|
||||
import (
|
||||
"github.com/gofiber/fiber/v2"
|
||||
"github.com/gofiber/fiber/v2/middleware/limiter"
|
||||
"time"
|
||||
)
|
||||
|
||||
func MaxBodySize(sizeInMB int) fiber.Handler {
|
||||
sizeInMB = sizeInMB * 1024 * 1024
|
||||
return func(c *fiber.Ctx) error {
|
||||
if len(c.Body()) >= sizeInMB {
|
||||
// custom response here
|
||||
return fiber.ErrRequestEntityTooLarge
|
||||
}
|
||||
return c.Next()
|
||||
}
|
||||
}
|
||||
|
||||
func Limit(maxRequest int, duration time.Duration) func(*fiber.Ctx) error {
|
||||
return limiter.New(limiter.Config{
|
||||
Max: maxRequest,
|
||||
Expiration: duration * time.Minute,
|
||||
LimitReached: func(c *fiber.Ctx) error {
|
||||
return c.Status(429).JSON(fiber.Map{
|
||||
"error": true,
|
||||
"message": "Too many requests",
|
||||
})
|
||||
},
|
||||
})
|
||||
}
|
||||
@@ -0,0 +1,86 @@
|
||||
// scrypt.go
|
||||
package middlewares
|
||||
|
||||
import (
|
||||
"crypto/aes"
|
||||
"crypto/cipher"
|
||||
"crypto/rand"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"log"
|
||||
"time"
|
||||
|
||||
"golang.org/x/crypto/scrypt"
|
||||
)
|
||||
|
||||
func Encrypt(key, data []byte) ([]byte, error) {
|
||||
key, salt, err := DeriveKey(key, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
blockCipher, err := aes.NewCipher(key)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
gcm, err := cipher.NewGCM(blockCipher)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
nonce := make([]byte, gcm.NonceSize())
|
||||
if _, err = rand.Read(nonce); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ciphertext := gcm.Seal(nonce, nonce, data, nil)
|
||||
ciphertext = append(ciphertext, salt...)
|
||||
return ciphertext, nil
|
||||
}
|
||||
func Decrypt(key, data []byte) ([]byte, error) {
|
||||
salt, data := data[len(data)-32:], data[:len(data)-32]
|
||||
key, _, err := DeriveKey(key, salt)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
blockCipher, err := aes.NewCipher(key)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
gcm, err := cipher.NewGCM(blockCipher)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
nonce, ciphertext := data[:gcm.NonceSize()], data[gcm.NonceSize():]
|
||||
plaintext, err := gcm.Open(nil, nonce, ciphertext, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return plaintext, nil
|
||||
}
|
||||
func DeriveKey(password, salt []byte) ([]byte, []byte, error) {
|
||||
if salt == nil {
|
||||
salt = make([]byte, 32)
|
||||
if _, err := rand.Read(salt); err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
}
|
||||
key, err := scrypt.Key(password, salt, 1048576, 8, 1, 32)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
return key, salt, nil
|
||||
}
|
||||
func main() {
|
||||
var (
|
||||
password = []byte("mysecretpassword")
|
||||
data = []byte(fmt.Sprintf("%v", time.Now().Unix()))
|
||||
)
|
||||
ciphertext, err := Encrypt(password, data)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
fmt.Printf("ciphertext: %s\n", hex.EncodeToString(ciphertext))
|
||||
plaintext, err := Decrypt(password, ciphertext)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
fmt.Printf("plaintext: %s\n", plaintext)
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
package routes
|
||||
|
||||
import (
|
||||
"github.com/gofiber/fiber/v2"
|
||||
"github.com/sujit-baniya/fiber-boilerplate/rest/controllers"
|
||||
)
|
||||
|
||||
func AdminRoutes(web fiber.Router) {
|
||||
admin := web.Group("admin")
|
||||
admin.Get("/", controllers.Admin)
|
||||
admin.Get("/users", controllers.GetUsers)
|
||||
AdminUserRoutes(admin)
|
||||
RolesRoutes(admin)
|
||||
PermissionRoutes(admin)
|
||||
}
|
||||
|
||||
func AdminUserRoutes(a fiber.Router) {
|
||||
services := a.Group("users")
|
||||
services.Get("/", controllers.GetUsers)
|
||||
services.Get("/:id", controllers.UserInfo)
|
||||
services.Put("/:id", controllers.UpdateUser)
|
||||
services.Get("/:id/settings", controllers.UserSettings)
|
||||
services.Post("/:id/settings", controllers.StoreUserSettings)
|
||||
}
|
||||
|
||||
func RolesRoutes(r fiber.Router) {
|
||||
roles := r.Group("roles")
|
||||
roles.Post("/create", controllers.CreateNewRole)
|
||||
roles.Post("/remove", controllers.RemoveRole)
|
||||
roles.Post("/assign", controllers.AssignRoleToUser)
|
||||
roles.Post("/revoke", controllers.RevokeRoleFromUser)
|
||||
roles.Post("/change", controllers.ChangeRoleForUser)
|
||||
}
|
||||
|
||||
func PermissionRoutes(r fiber.Router) {
|
||||
roles := r.Group("permissions")
|
||||
roles.Post("/add", controllers.AddPermissionOnRole)
|
||||
roles.Post("/remove", controllers.RemovePermissionFromRole)
|
||||
roles.Post("/change", controllers.ChangePermissionOnRole)
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
package routes
|
||||
|
||||
import (
|
||||
"github.com/gofiber/fiber/v2"
|
||||
apiControllers "github.com/sujit-baniya/fiber-boilerplate/rest/controllers/api"
|
||||
)
|
||||
|
||||
func ApiRoutes(api fiber.Router) {
|
||||
v1Routes(api)
|
||||
}
|
||||
|
||||
func v1AuthRoutes(api fiber.Router) {
|
||||
api.Post("/oauth/token", apiControllers.OAuthToken)
|
||||
}
|
||||
|
||||
func v1Routes(api fiber.Router) {
|
||||
v1 := api.Group("v1")
|
||||
v1AuthRoutes(v1)
|
||||
}
|
||||
@@ -0,0 +1,96 @@
|
||||
package routes
|
||||
|
||||
import (
|
||||
"github.com/gofiber/fiber/v2"
|
||||
"github.com/sujit-baniya/fiber-boilerplate/rest/controllers"
|
||||
apiControllers "github.com/sujit-baniya/fiber-boilerplate/rest/controllers/api"
|
||||
"github.com/sujit-baniya/fiber-boilerplate/rest/middlewares"
|
||||
)
|
||||
|
||||
func WebAuthRoutes(App fiber.Router) {
|
||||
//App.Get("/login",
|
||||
// middlewares.RedirectToHomePageOnLogin,
|
||||
// controllers.LoginGet,
|
||||
//)
|
||||
App.Post("/do/login",
|
||||
middlewares.ValidateLoginPost,
|
||||
controllers.LoginPost,
|
||||
)
|
||||
App.Post("/do/logout",
|
||||
controllers.LogoutPost,
|
||||
)
|
||||
|
||||
App.Get("/register", middlewares.RedirectToHomePageOnLogin, controllers.RegisterGet)
|
||||
App.Post("/do/register",
|
||||
middlewares.RedirectToHomePageOnLogin,
|
||||
middlewares.ValidateRegisterPost,
|
||||
controllers.RegisterPost,
|
||||
)
|
||||
|
||||
App.Get("/reset-password",
|
||||
middlewares.ValidatePasswordReset,
|
||||
controllers.PasswordReset,
|
||||
)
|
||||
App.Get("/token-vencido",
|
||||
controllers.TokenVencido,
|
||||
)
|
||||
App.Post("/do/reset-password",
|
||||
controllers.RequestPasswordResetPost,
|
||||
)
|
||||
// Generar contraseñas aleatorias /do/generate-password
|
||||
App.Post("/do/generate-password",
|
||||
controllers.GeneratePasswordPost,
|
||||
)
|
||||
|
||||
//App.Get("/request-password-reset", middlewares.RedirectToHomePageOnLogin, controllers.RequestPasswordReset)
|
||||
App.Post("/do/password-reset/:token",
|
||||
middlewares.RedirectToHomePageOnLogin,
|
||||
middlewares.ValidatePasswordResetPost,
|
||||
middlewares.ValidateRegisterPost,
|
||||
controllers.PasswordResetPost)
|
||||
App.Get("/resend/confirm", controllers.ResendConfirmEmail)
|
||||
App.Get("/do/verify-email",
|
||||
middlewares.ValidateConfirmToken,
|
||||
controllers.VerifyRegisteredEmail,
|
||||
)
|
||||
}
|
||||
|
||||
func AuthRoutes(App fiber.Router) {
|
||||
App.Post("/do/login",
|
||||
middlewares.ValidateApiLoginPost,
|
||||
apiControllers.ApiLoginPost,
|
||||
)
|
||||
App.Post("/me", controllers.Me)
|
||||
App.Post("/do/logout", controllers.LogoutPost)
|
||||
|
||||
App.Get("/register", middlewares.RedirectToHomePageOnLogin, controllers.RegisterGet)
|
||||
//App.Post("/do/register",
|
||||
// middlewares.ValidateApiRegisterPost,
|
||||
// apiControllers.ApiRegisterPost,
|
||||
//)
|
||||
|
||||
App.Get("/reset-password",
|
||||
middlewares.ValidatePasswordReset,
|
||||
controllers.PasswordReset,
|
||||
)
|
||||
App.Post("/do/reset-password",
|
||||
controllers.RequestPasswordResetPost,
|
||||
)
|
||||
// Generar contraseñas aleatorias /do/generate-password
|
||||
App.Post("/do/generate-password",
|
||||
controllers.GeneratePasswordPost,
|
||||
)
|
||||
|
||||
App.Get("/request-password-reset", middlewares.RedirectToHomePageOnLogin, controllers.RequestPasswordReset)
|
||||
App.Post("/do/password-reset/:token",
|
||||
middlewares.RedirectToHomePageOnLogin,
|
||||
middlewares.ValidatePasswordResetPost,
|
||||
middlewares.ValidateRegisterPost,
|
||||
controllers.PasswordResetPost)
|
||||
App.Get("/resend/confirm", controllers.ResendConfirmEmail)
|
||||
App.Get("/do/verify-email",
|
||||
middlewares.ValidateConfirmToken,
|
||||
controllers.VerifyRegisteredEmail,
|
||||
)
|
||||
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
package routes
|
||||
|
||||
import "github.com/gofiber/fiber/v2"
|
||||
|
||||
func LoadCharts(app fiber.Router) {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
package routes
|
||||
|
||||
import (
|
||||
"github.com/gofiber/fiber/v2"
|
||||
"github.com/sujit-baniya/fiber-boilerplate/app"
|
||||
"github.com/sujit-baniya/fiber-boilerplate/rest/controllers"
|
||||
"github.com/sujit-baniya/fiber-boilerplate/rest/middlewares"
|
||||
)
|
||||
|
||||
func LandingRoutes(web fiber.Router) {
|
||||
//web.Get("/", controllers.Landing)
|
||||
web.Get("/ping", Pong)
|
||||
web.Get("/all-routes", AllRoutes)
|
||||
web.Get("/do/verify-email", middlewares.ValidateConfirmToken, controllers.VerifyRegisteredEmail)
|
||||
|
||||
|
||||
}
|
||||
|
||||
func Pong(c *fiber.Ctx) error {
|
||||
return c.SendString("Pong")
|
||||
}
|
||||
|
||||
func AllRoutes(c *fiber.Ctx) error {
|
||||
return c.JSON(app.Http.Server.Stack())
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
package routes
|
||||
|
||||
import (
|
||||
"github.com/gofiber/fiber/v2"
|
||||
)
|
||||
|
||||
func LoadRoutes(app *fiber.App) {
|
||||
// Grupo de rutas de la API con autenticación
|
||||
//api := app.Group("/api").Use(middlewares.AuthApi())
|
||||
//ApiRoutes(api)
|
||||
|
||||
// Grupo de rutas web (sin autenticación)
|
||||
web := app.Group("")
|
||||
|
||||
// Rutas del backend (web)
|
||||
WebRoutes(web)
|
||||
|
||||
vue := app.Group("")
|
||||
// Sirve archivos estáticos de Vue.js desde la carpeta 'dist'
|
||||
vue.Static("/", "./dist") // Sirve archivos estáticos de Vue.js
|
||||
|
||||
// Ruta para acceder a los archivos subidos
|
||||
vue.Get("/uploads/:filename", func(c *fiber.Ctx) error {
|
||||
filename := c.Params("filename")
|
||||
// Devuelve el archivo solicitado desde 'uploads'
|
||||
return c.SendFile("./uploads/" + filename)
|
||||
})
|
||||
|
||||
// Ruta wildcard para manejar las rutas del frontend (SPA)
|
||||
vue.Get("/*", func(c *fiber.Ctx) error {
|
||||
return c.SendFile("./dist/index.html")
|
||||
})
|
||||
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
package routes
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/gofiber/fiber/v2"
|
||||
"github.com/sujit-baniya/fiber-boilerplate/rest/controllers"
|
||||
"github.com/sujit-baniya/fiber-boilerplate/rest/middlewares"
|
||||
)
|
||||
|
||||
func UserRoutes(app fiber.Router) {
|
||||
protected := app.Group("/app").
|
||||
Use(
|
||||
middlewares.AuthWeb(), // Middleware de autenticación
|
||||
middlewares.LoadUserMiddleware, // Middleware para cargar el usuario
|
||||
)
|
||||
|
||||
// Rutas de la aplicación
|
||||
|
||||
// web me redireccione a /
|
||||
protected.Get("/web", func(c *fiber.Ctx) error { return c.Redirect("/", http.StatusSeeOther) })
|
||||
app.Get("/web", func(c *fiber.Ctx) error { return c.Redirect("/", http.StatusSeeOther) })
|
||||
protected.Get("/", controllers.App)
|
||||
protected.Get("/me", controllers.Me)
|
||||
|
||||
// Rutas de módulos
|
||||
protected.Get("/modules", middlewares.MenuMiddleware, controllers.Modules) // Renderizar la vista
|
||||
protected.Get("/loadmodules", controllers.GetModules) // Obtener todos los módulos
|
||||
protected.Post("/modules", controllers.CreateModule) // Crear un nuevo módulo
|
||||
protected.Put("/modules/:id", controllers.UpdateModule) // Actualizar un módulo existente
|
||||
protected.Delete("/modules/:id", controllers.DeleteModule) // Eliminar un módulo
|
||||
|
||||
// Rutas de roles
|
||||
protected.Get("/roles", middlewares.MenuMiddleware, controllers.Roles) // Renderizar la vista
|
||||
protected.Get("/loadroles", controllers.GetRoles) // Obtener todos
|
||||
protected.Post("/roles", controllers.CreateRole) // Crear
|
||||
protected.Put("/roles/:id", controllers.UpdateRole) // Actualizar
|
||||
protected.Delete("/roles/:id", controllers.DeleteRole) // Eliminar
|
||||
|
||||
// Rutas de usuarios
|
||||
protected.Get("/users", middlewares.MenuMiddleware, controllers.Users) // Renderizar la vista
|
||||
protected.Get("/loadusers", controllers.GetUsers) // Obtener
|
||||
protected.Post("/users", controllers.CreateUser) // Crear
|
||||
protected.Put("/users/:id", controllers.UpdateUser) // Actualizar
|
||||
protected.Put("/password/:id", controllers.UpdatePassword) // Actualizar
|
||||
protected.Delete("/users/:id", controllers.DeleteUser) // Eliminar
|
||||
protected.Get("/user/:id", controllers.GetUser) // Buscar un usuario
|
||||
|
||||
// Rutas de módulos
|
||||
protected.Get("/submodules", middlewares.MenuMiddleware, controllers.Submodules) // Renderizar la vista
|
||||
protected.Get("/loadsubmodules", controllers.GetSubmodules) // Obtener todos los módulos
|
||||
protected.Post("/submodules", controllers.CreateSubmodule) // Crear un nuevo módulo
|
||||
protected.Put("/submodules/:id", controllers.UpdateSubmodule) // Actualizar un módulo existente
|
||||
protected.Delete("/submodules/:id", controllers.DeleteSubmodule) // Eliminar un módulo
|
||||
// Eliminar un colaborador por ID
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
package routes
|
||||
|
||||
import (
|
||||
"github.com/gofiber/fiber/v2"
|
||||
"github.com/sujit-baniya/fiber-boilerplate/rest/middlewares"
|
||||
)
|
||||
|
||||
// Configuración de rutas web
|
||||
func WebRoutes(web fiber.Router) {
|
||||
// Aplicar el middleware para desactivar el caché
|
||||
web.Use(middlewares.LoadCacheHeaders)
|
||||
// Rutas específicas del backend
|
||||
LandingRoutes(web)
|
||||
WebAuthRoutes(web)
|
||||
UserRoutes(web)
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user