up
This commit is contained in:
@@ -20,9 +20,10 @@ type PortalUser struct {
|
|||||||
ClienteID *uint `json:"cliente_id" gorm:"column:cliente_id;index"` // nil si es partner
|
ClienteID *uint `json:"cliente_id" gorm:"column:cliente_id;index"` // nil si es partner
|
||||||
Cliente *Cliente `json:"cliente" gorm:"foreignKey:ClienteID"`
|
Cliente *Cliente `json:"cliente" gorm:"foreignKey:ClienteID"`
|
||||||
Rol string `json:"rol" gorm:"column:rol;default:'cliente'"` // cliente|partner
|
Rol string `json:"rol" gorm:"column:rol;default:'cliente'"` // cliente|partner
|
||||||
Activo bool `json:"activo" gorm:"column:activo;default:true"`
|
Activo bool `json:"activo" gorm:"column:activo;default:true"`
|
||||||
Notas string `json:"notas" gorm:"column:notas;type:text"`
|
Notas string `json:"notas" gorm:"column:notas;type:text"`
|
||||||
PortalAccesos []PortalAcceso `json:"portal_accesos" gorm:"foreignKey:PortalUserID"`
|
TelegramChatID string `json:"telegram_chat_id" gorm:"column:telegram_chat_id"`
|
||||||
|
PortalAccesos []PortalAcceso `json:"portal_accesos" gorm:"foreignKey:PortalUserID"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (PortalUser) TableName() string { return "portal_users" }
|
func (PortalUser) TableName() string { return "portal_users" }
|
||||||
@@ -71,12 +72,13 @@ func CreatePortalUser(u *PortalUser) error {
|
|||||||
|
|
||||||
func UpdatePortalUser(u *PortalUser) error {
|
func UpdatePortalUser(u *PortalUser) error {
|
||||||
return app.Http.Database.DB.Model(&PortalUser{}).Where("id = ?", u.ID).Updates(map[string]interface{}{
|
return app.Http.Database.DB.Model(&PortalUser{}).Where("id = ?", u.ID).Updates(map[string]interface{}{
|
||||||
"nombre": u.Nombre,
|
"nombre": u.Nombre,
|
||||||
"email": u.Email,
|
"email": u.Email,
|
||||||
"cliente_id": u.ClienteID,
|
"cliente_id": u.ClienteID,
|
||||||
"rol": u.Rol,
|
"rol": u.Rol,
|
||||||
"activo": u.Activo,
|
"activo": u.Activo,
|
||||||
"notas": u.Notas,
|
"notas": u.Notas,
|
||||||
|
"telegram_chat_id": u.TelegramChatID,
|
||||||
}).Error
|
}).Error
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -21,6 +21,7 @@
|
|||||||
<th class="px-4 py-3 text-left">Rol</th>
|
<th class="px-4 py-3 text-left">Rol</th>
|
||||||
<th class="px-4 py-3 text-left">Cliente / Accesos</th>
|
<th class="px-4 py-3 text-left">Cliente / Accesos</th>
|
||||||
<th class="px-4 py-3 text-left">Estado</th>
|
<th class="px-4 py-3 text-left">Estado</th>
|
||||||
|
<th class="px-4 py-3 text-left">Telegram</th>
|
||||||
<th class="px-4 py-3 text-left">Acciones</th>
|
<th class="px-4 py-3 text-left">Acciones</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
@@ -54,6 +55,10 @@
|
|||||||
<td class="px-4 py-3">
|
<td class="px-4 py-3">
|
||||||
<span :class="u.activo ? 'badge-green' : 'badge-slate'" class="badge" x-text="u.activo ? 'Activo' : 'Inactivo'"></span>
|
<span :class="u.activo ? 'badge-green' : 'badge-slate'" class="badge" x-text="u.activo ? 'Activo' : 'Inactivo'"></span>
|
||||||
</td>
|
</td>
|
||||||
|
<td class="px-4 py-3 text-slate-500 text-xs">
|
||||||
|
<span x-show="u.telegram_chat_id" x-text="u.telegram_chat_id" class="font-mono"></span>
|
||||||
|
<span x-show="!u.telegram_chat_id" class="text-slate-300">—</span>
|
||||||
|
</td>
|
||||||
<td class="px-4 py-3 flex gap-2">
|
<td class="px-4 py-3 flex gap-2">
|
||||||
<button @click="openEdit(u)" class="btn-icon text-yellow-500" title="Editar">
|
<button @click="openEdit(u)" class="btn-icon text-yellow-500" title="Editar">
|
||||||
<svg class="w-4 h-4" fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" d="M11 5H6a2 2 0 00-2 2v11a2 2 0 002 2h11a2 2 0 002-2v-5m-1.414-9.414a2 2 0 112.828 2.828L11.828 15H9v-2.828l8.586-8.586z"/></svg>
|
<svg class="w-4 h-4" fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" d="M11 5H6a2 2 0 00-2 2v11a2 2 0 002 2h11a2 2 0 002-2v-5m-1.414-9.414a2 2 0 112.828 2.828L11.828 15H9v-2.828l8.586-8.586z"/></svg>
|
||||||
@@ -101,6 +106,7 @@
|
|||||||
<input type="checkbox" x-model="form.activo" class="w-4 h-4">
|
<input type="checkbox" x-model="form.activo" class="w-4 h-4">
|
||||||
</div>
|
</div>
|
||||||
<div><label class="label">Notas</label><textarea x-model="form.notas" class="input-field w-full" rows="2"></textarea></div>
|
<div><label class="label">Notas</label><textarea x-model="form.notas" class="input-field w-full" rows="2"></textarea></div>
|
||||||
|
<div><label class="label">Chat ID de Telegram</label><input x-model="form.telegram_chat_id" class="input-field w-full font-mono" placeholder="Ej: 123456789"><p class="text-xs text-slate-400 mt-1">Se usa para enviar notificaciones al usuario vía Telegram.</p></div>
|
||||||
</div>
|
</div>
|
||||||
<p x-show="error" x-text="error" class="text-red-500 text-sm mt-3"></p>
|
<p x-show="error" x-text="error" class="text-red-500 text-sm mt-3"></p>
|
||||||
<div class="flex justify-end gap-3 mt-5">
|
<div class="flex justify-end gap-3 mt-5">
|
||||||
@@ -150,7 +156,7 @@ function portalUsuariosApp() {
|
|||||||
showModal: false, showDelete: false, showAccesoModal: false,
|
showModal: false, showDelete: false, showAccesoModal: false,
|
||||||
editId: null, deleteId: null, error: '',
|
editId: null, deleteId: null, error: '',
|
||||||
accesoUserId: null, accesoClienteId: '',
|
accesoUserId: null, accesoClienteId: '',
|
||||||
form: { nombre:'', email:'', password:'', rol:'cliente', cliente_id:'', activo:true, notas:'' },
|
form: { nombre:'', email:'', password:'', rol:'cliente', cliente_id:'', activo:true, notas:'', telegram_chat_id:'' },
|
||||||
|
|
||||||
async init() { await this.load(); },
|
async init() { await this.load(); },
|
||||||
|
|
||||||
@@ -165,12 +171,12 @@ function portalUsuariosApp() {
|
|||||||
|
|
||||||
openCreate() {
|
openCreate() {
|
||||||
this.editId=null; this.error='';
|
this.editId=null; this.error='';
|
||||||
this.form={nombre:'',email:'',password:'',rol:'cliente',cliente_id:'',activo:true,notas:''};
|
this.form={nombre:'',email:'',password:'',rol:'cliente',cliente_id:'',activo:true,notas:'',telegram_chat_id:''};
|
||||||
this.showModal=true;
|
this.showModal=true;
|
||||||
},
|
},
|
||||||
openEdit(u) {
|
openEdit(u) {
|
||||||
this.editId=u.ID; this.error='';
|
this.editId=u.ID; this.error='';
|
||||||
this.form={nombre:u.nombre,email:u.email,password:'',rol:u.rol,cliente_id:u.cliente_id||'',activo:u.activo,notas:u.notas||''};
|
this.form={nombre:u.nombre,email:u.email,password:'',rol:u.rol,cliente_id:u.cliente_id||'',activo:u.activo,notas:u.notas||'',telegram_chat_id:u.telegram_chat_id||''};
|
||||||
this.showModal=true;
|
this.showModal=true;
|
||||||
},
|
},
|
||||||
async save() {
|
async save() {
|
||||||
|
|||||||
@@ -40,12 +40,13 @@ func LoadPortalUsuarios(c *fiber.Ctx) error {
|
|||||||
|
|
||||||
func CreatePortalUsuario(c *fiber.Ctx) error {
|
func CreatePortalUsuario(c *fiber.Ctx) error {
|
||||||
type Req struct {
|
type Req struct {
|
||||||
Nombre string `json:"nombre"`
|
Nombre string `json:"nombre"`
|
||||||
Email string `json:"email"`
|
Email string `json:"email"`
|
||||||
Password string `json:"password"`
|
Password string `json:"password"`
|
||||||
ClienteID *uint `json:"cliente_id"`
|
ClienteID *uint `json:"cliente_id"`
|
||||||
Rol string `json:"rol"`
|
Rol string `json:"rol"`
|
||||||
Notas string `json:"notas"`
|
Notas string `json:"notas"`
|
||||||
|
TelegramChatID string `json:"telegram_chat_id"`
|
||||||
}
|
}
|
||||||
var req Req
|
var req Req
|
||||||
if err := c.BodyParser(&req); err != nil {
|
if err := c.BodyParser(&req); err != nil {
|
||||||
@@ -62,13 +63,14 @@ func CreatePortalUsuario(c *fiber.Ctx) error {
|
|||||||
req.Rol = "cliente"
|
req.Rol = "cliente"
|
||||||
}
|
}
|
||||||
u := &models.PortalUser{
|
u := &models.PortalUser{
|
||||||
Nombre: req.Nombre,
|
Nombre: req.Nombre,
|
||||||
Email: strings.ToLower(strings.TrimSpace(req.Email)),
|
Email: strings.ToLower(strings.TrimSpace(req.Email)),
|
||||||
Password: hashed,
|
Password: hashed,
|
||||||
ClienteID: req.ClienteID,
|
ClienteID: req.ClienteID,
|
||||||
Rol: req.Rol,
|
Rol: req.Rol,
|
||||||
Activo: true,
|
Activo: true,
|
||||||
Notas: req.Notas,
|
Notas: req.Notas,
|
||||||
|
TelegramChatID: req.TelegramChatID,
|
||||||
}
|
}
|
||||||
if err := models.CreatePortalUser(u); err != nil {
|
if err := models.CreatePortalUser(u); err != nil {
|
||||||
return c.Status(500).JSON(fiber.Map{"error": err.Error()})
|
return c.Status(500).JSON(fiber.Map{"error": err.Error()})
|
||||||
@@ -83,25 +85,27 @@ func UpdatePortalUsuario(c *fiber.Ctx) error {
|
|||||||
return c.Status(400).JSON(fiber.Map{"error": "ID inválido"})
|
return c.Status(400).JSON(fiber.Map{"error": "ID inválido"})
|
||||||
}
|
}
|
||||||
type Req struct {
|
type Req struct {
|
||||||
Nombre string `json:"nombre"`
|
Nombre string `json:"nombre"`
|
||||||
Email string `json:"email"`
|
Email string `json:"email"`
|
||||||
Password string `json:"password"`
|
Password string `json:"password"`
|
||||||
ClienteID *uint `json:"cliente_id"`
|
ClienteID *uint `json:"cliente_id"`
|
||||||
Rol string `json:"rol"`
|
Rol string `json:"rol"`
|
||||||
Activo bool `json:"activo"`
|
Activo bool `json:"activo"`
|
||||||
Notas string `json:"notas"`
|
Notas string `json:"notas"`
|
||||||
|
TelegramChatID string `json:"telegram_chat_id"`
|
||||||
}
|
}
|
||||||
var req Req
|
var req Req
|
||||||
if err := c.BodyParser(&req); err != nil {
|
if err := c.BodyParser(&req); err != nil {
|
||||||
return c.Status(400).JSON(fiber.Map{"error": err.Error()})
|
return c.Status(400).JSON(fiber.Map{"error": err.Error()})
|
||||||
}
|
}
|
||||||
u := &models.PortalUser{
|
u := &models.PortalUser{
|
||||||
Nombre: req.Nombre,
|
Nombre: req.Nombre,
|
||||||
Email: strings.ToLower(strings.TrimSpace(req.Email)),
|
Email: strings.ToLower(strings.TrimSpace(req.Email)),
|
||||||
ClienteID: req.ClienteID,
|
ClienteID: req.ClienteID,
|
||||||
Rol: req.Rol,
|
Rol: req.Rol,
|
||||||
Activo: req.Activo,
|
Activo: req.Activo,
|
||||||
Notas: req.Notas,
|
Notas: req.Notas,
|
||||||
|
TelegramChatID: req.TelegramChatID,
|
||||||
}
|
}
|
||||||
u.ID = uint(id)
|
u.ID = uint(id)
|
||||||
if err := models.UpdatePortalUser(u); err != nil {
|
if err := models.UpdatePortalUser(u); err != nil {
|
||||||
|
|||||||
Reference in New Issue
Block a user