up
This commit is contained in:
@@ -20,6 +20,8 @@ server:
|
||||
name: "iSend.to"
|
||||
host: localhost
|
||||
port: 8080
|
||||
# URL pública para enlaces en correos, Telegram y webhooks (producción)
|
||||
public_url: https://admin.u-site.app
|
||||
|
||||
redis:
|
||||
instances:
|
||||
|
||||
@@ -30,6 +30,7 @@ server: &server
|
||||
name: "USITE "
|
||||
host: 0.0.0.0
|
||||
port: 8080
|
||||
public_url: https://admin.u-site.app
|
||||
|
||||
profiler:
|
||||
enabled: false
|
||||
|
||||
@@ -28,6 +28,7 @@ type ServerConfig struct {
|
||||
Env string `mapstructure:"APP_ENV" yaml:"env" env:"APP_ENV" env-default:"dev"`
|
||||
Key string `mapstructure:"APP_KEY" yaml:"key" env:"APP_KEY" env-default:"1894cde6c936a294a478cff0a9227fd276d86df6573b51af5dc59c9064edf426"`
|
||||
Url string `mapstructure:"APP_URL" yaml:"url" env:"APP_URL" env-default:"http://localhost"`
|
||||
PublicUrl string `mapstructure:"APP_PUBLIC_URL" yaml:"public_url" env:"APP_PUBLIC_URL"`
|
||||
Host string `mapstructure:"APP_HOST" yaml:"host" env:"APP_HOST" env-default:"localhost"`
|
||||
Port string `mapstructure:"APP_PORT" yaml:"port" env:"APP_PORT" env-default:"8080"`
|
||||
Path string `mapstructure:"APP_PATH" yaml:"path" env:"APP_PATH"`
|
||||
|
||||
+29
-5
@@ -10,8 +10,21 @@ import (
|
||||
"github.com/sujit-baniya/fiber-boilerplate/app"
|
||||
)
|
||||
|
||||
// getAppURL devuelve la URL base absoluta (sin slash final).
|
||||
// Si APP_URL es http://localhost sin puerto, añade APP_PORT para enlaces en desarrollo.
|
||||
// GetPublicURL devuelve la URL pública para enlaces en correos, Telegram y webhooks.
|
||||
func GetPublicURL() string {
|
||||
return getPublicURL()
|
||||
}
|
||||
|
||||
// getPublicURL usa APP_PUBLIC_URL si está configurada; si no, APP_URL (con puerto en localhost).
|
||||
func getPublicURL() string {
|
||||
if u := normalizeBaseURL(app.Http.Server.PublicUrl); u != "" {
|
||||
return u
|
||||
}
|
||||
return getAppURL()
|
||||
}
|
||||
|
||||
// getAppURL devuelve la URL base de la app (sin slash final).
|
||||
// Si APP_URL es http://localhost sin puerto, añade APP_PORT para desarrollo local.
|
||||
func getAppURL() string {
|
||||
u := strings.TrimRight(app.Http.Server.Url, "/")
|
||||
if u == "" {
|
||||
@@ -33,10 +46,21 @@ func getAppURL() string {
|
||||
return u
|
||||
}
|
||||
|
||||
// absAppURL convierte una ruta relativa en URL absoluta para correo/Telegram.
|
||||
func normalizeBaseURL(raw string) string {
|
||||
u := strings.TrimSpace(strings.TrimRight(raw, "/"))
|
||||
if u == "" {
|
||||
return ""
|
||||
}
|
||||
if !strings.Contains(u, "://") {
|
||||
u = "https://" + u
|
||||
}
|
||||
return strings.TrimRight(u, "/")
|
||||
}
|
||||
|
||||
// absAppURL convierte una ruta relativa en URL absoluta pública (correo/Telegram).
|
||||
func absAppURL(path string) string {
|
||||
if path == "" {
|
||||
return getAppURL()
|
||||
return getPublicURL()
|
||||
}
|
||||
if strings.HasPrefix(path, "http://") || strings.HasPrefix(path, "https://") {
|
||||
return path
|
||||
@@ -44,7 +68,7 @@ func absAppURL(path string) string {
|
||||
if !strings.HasPrefix(path, "/") {
|
||||
path = "/" + path
|
||||
}
|
||||
return getAppURL() + path
|
||||
return getPublicURL() + path
|
||||
}
|
||||
|
||||
func adminTicketPath(ticketID uint) string {
|
||||
|
||||
@@ -19,7 +19,35 @@ func TestGetAppURLLocalhostAddsPort(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestAbsAppURLRelativePath(t *testing.T) {
|
||||
func TestGetPublicURLPrefersPublicURL(t *testing.T) {
|
||||
app.Http = &config.AppConfig{
|
||||
Server: config.ServerConfig{
|
||||
Url: "http://localhost:8080",
|
||||
PublicUrl: "admin.u-site.app",
|
||||
Port: "8080",
|
||||
},
|
||||
}
|
||||
if got := getPublicURL(); got != "https://admin.u-site.app" {
|
||||
t.Fatalf("getPublicURL() = %q, want https://admin.u-site.app", got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestAbsAppURLUsesPublicURL(t *testing.T) {
|
||||
app.Http = &config.AppConfig{
|
||||
Server: config.ServerConfig{
|
||||
Url: "http://localhost:8080",
|
||||
PublicUrl: "https://admin.u-site.app",
|
||||
Port: "8080",
|
||||
},
|
||||
}
|
||||
got := absAppURL("/portal/proyecto/bot?tab=Tickets&ticket=1")
|
||||
want := "https://admin.u-site.app/portal/proyecto/bot?tab=Tickets&ticket=1"
|
||||
if got != want {
|
||||
t.Fatalf("absAppURL() = %q, want %q", got, want)
|
||||
}
|
||||
}
|
||||
|
||||
func TestAbsAppURLFallsBackToAppURL(t *testing.T) {
|
||||
app.Http = &config.AppConfig{
|
||||
Server: config.ServerConfig{
|
||||
Url: "http://localhost",
|
||||
@@ -34,8 +62,8 @@ func TestAbsAppURLRelativePath(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestTelegramHTMLLinkEscapesAmpersand(t *testing.T) {
|
||||
link := telegramHTMLLink("http://localhost:8084/portal/p?tab=Tickets&ticket=1", "Ver portal")
|
||||
if link != `<a href="http://localhost:8084/portal/p?tab=Tickets&ticket=1">Ver portal</a>` {
|
||||
link := telegramHTMLLink("https://admin.u-site.app/portal/p?tab=Tickets&ticket=1", "Ver portal")
|
||||
if link != `<a href="https://admin.u-site.app/portal/p?tab=Tickets&ticket=1">Ver portal</a>` {
|
||||
t.Fatalf("telegramHTMLLink() = %q", link)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -80,7 +80,7 @@ func GeneratePasswordResetURL(email string, baseURL string) string {
|
||||
|
||||
// SendPortalCredentialsEmail envía al usuario del portal su URL de acceso y contraseña inicial.
|
||||
func SendPortalCredentialsEmail(email, nombre, password string) {
|
||||
loginURL := fmt.Sprintf("%s/portal/login", app.Http.Server.Url)
|
||||
loginURL := absAppURL("/portal/login")
|
||||
htmlBody := fmt.Sprintf(`<!DOCTYPE html>
|
||||
<html><body style="font-family:Inter,sans-serif;background:#f1f5f9;padding:32px">
|
||||
<div style="max-width:480px;margin:0 auto;background:#fff;border-radius:16px;padding:32px;border:1px solid #e2e8f0">
|
||||
|
||||
@@ -84,7 +84,7 @@ func ApiRegisterPost(c *fiber.Ctx) error {
|
||||
store.Set("user_id", user.ID) // save to storage
|
||||
_ = store.Save()
|
||||
|
||||
go services.SendConfirmationEmail(user.Email, c.BaseURL(), user.NombreUsuario)
|
||||
go services.SendConfirmationEmail(user.Email, services.GetPublicURL(), user.NombreUsuario)
|
||||
return c.JSON(fiber.Map{
|
||||
"success": true,
|
||||
"message": "Registered successfully! Please confirm your email",
|
||||
|
||||
@@ -42,7 +42,7 @@ func RegisterPost(c *fiber.Ctx) error {
|
||||
store.Set("user_id", user.ID) // guardar en el almacenamiento
|
||||
_ = store.Save()
|
||||
|
||||
go services.SendConfirmationEmail(user.Email, app.Http.Server.Url, user.NombreUsuario)
|
||||
go services.SendConfirmationEmail(user.Email, services.GetPublicURL(), user.NombreUsuario)
|
||||
return c.Redirect("/")
|
||||
}
|
||||
|
||||
@@ -55,7 +55,7 @@ func VerifyRegisteredEmail(c *fiber.Ctx) error {
|
||||
// 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)
|
||||
go services.SendConfirmationEmail(user.Email, services.GetPublicURL(), user.NombreUsuario)
|
||||
return c.Redirect("/")
|
||||
}
|
||||
|
||||
@@ -70,7 +70,7 @@ func ReenvioEmail(c *fiber.Ctx) error {
|
||||
}
|
||||
|
||||
// Reenvío del correo electrónico de forma asíncrona
|
||||
go services.SendConfirmationEmail(user.Email, app.Http.Server.Url, user.NombreUsuario)
|
||||
go services.SendConfirmationEmail(user.Email, services.GetPublicURL(), user.NombreUsuario)
|
||||
|
||||
return c.Status(fiber.StatusOK).JSON(fiber.Map{
|
||||
"success": true,
|
||||
@@ -94,7 +94,7 @@ func RequestPasswordResetPost(c *fiber.Ctx) error {
|
||||
usuario_email := user.Email
|
||||
log.Println("Sending password reset email to:", usuario_email)
|
||||
|
||||
go services.SendPasswordResetEmail(usuario_email, app.Http.Server.Url)
|
||||
go services.SendPasswordResetEmail(usuario_email, services.GetPublicURL())
|
||||
|
||||
return c.JSON(fiber.Map{
|
||||
"success": true,
|
||||
|
||||
@@ -12,8 +12,8 @@ import (
|
||||
"strings"
|
||||
|
||||
"github.com/gofiber/fiber/v2"
|
||||
"github.com/sujit-baniya/fiber-boilerplate/app"
|
||||
"github.com/sujit-baniya/fiber-boilerplate/pkg/models"
|
||||
"github.com/sujit-baniya/fiber-boilerplate/pkg/services"
|
||||
)
|
||||
|
||||
// TelegramIndex renderiza la vista de configuración de Telegram.
|
||||
@@ -222,12 +222,7 @@ func SetPortalWebhook(c *fiber.Ctx) error {
|
||||
return c.Status(404).JSON(fiber.Map{"error": "Configuración no encontrada"})
|
||||
}
|
||||
|
||||
// Construir URL base desde la configuración de la app
|
||||
baseURL := app.Http.Server.Url
|
||||
if len(baseURL) > 0 && baseURL[len(baseURL)-1] == '/' {
|
||||
baseURL = baseURL[:len(baseURL)-1]
|
||||
}
|
||||
webhookURL := baseURL + "/webhooks/telegram-portal"
|
||||
webhookURL := services.GetPublicURL() + "/webhooks/telegram-portal"
|
||||
|
||||
apiURL := fmt.Sprintf("https://api.telegram.org/bot%s/setWebhook", cfg.BotToken)
|
||||
payload, _ := json.Marshal(map[string]string{"url": webhookURL})
|
||||
|
||||
@@ -486,7 +486,7 @@ func CreateUserGas(c *fiber.Ctx) error {
|
||||
}
|
||||
|
||||
// Envía un correo de confirmación
|
||||
go services.SendConfirmationEmail(m.Email, app.Http.Server.Url, m.NombreUsuario)
|
||||
go services.SendConfirmationEmail(m.Email, services.GetPublicURL(), m.NombreUsuario)
|
||||
|
||||
return c.Status(fiber.StatusCreated).JSON(fiber.Map{
|
||||
"message": "Usuario creado con éxito",
|
||||
|
||||
Reference in New Issue
Block a user