Corregidos paginas de creacion

This commit is contained in:
Miguel 2025-03-04 11:46:15 +01:00
parent b48058e495
commit 9eb2bd5648
10 changed files with 439 additions and 173 deletions

View File

@ -87,74 +87,46 @@ class UserFilterForm(FlaskForm):
# Rutas # Rutas
@users_bp.route("/") @users_bp.route("/")
@login_required @login_required
@permission_required(5000) # Assuming 5000+ is admin level permission @permission_required(1000) # Minimum permission level
def list(): def list():
"""List all users.""" """List all users."""
# Import here to avoid circular imports
from services.user_service import get_all_users
users = get_all_users() users = get_all_users()
return render_template("users/list.html", users=users) return render_template("users/list.html", users=users)
@users_bp.route("/create", methods=["GET", "POST"]) @users_bp.route("/create", methods=["GET", "POST"])
@login_required @login_required
@permission_required(9000) # Solo administradores @permission_required(9000) # Admin level permission required
def create(): def create(): # Changed from create_user to create
"""Crear nuevo usuario.""" """Create a new user."""
form = UserForm() form = UserForm()
if form.validate_on_submit(): if request.method == "POST" and form.validate_on_submit():
# Validar datos try:
data = { # Extract user data from form
"nombre": form.nombre.data, user_data = {
"username": form.username.data, "username": form.username.data,
"email": form.email.data, "nombre": form.nombre.data,
"password": form.password.data, "email": form.email.data,
"nivel": form.nivel.data, "password": form.password.data,
"idioma": form.idioma.data, "nivel": form.nivel.data,
"empresa": form.empresa.data, "empresa": form.empresa.data,
"estado": form.estado.data, "idioma": form.idioma.data,
"fecha_caducidad": ( }
form.fecha_caducidad.data if form.fecha_caducidad.data else None
),
}
is_valid, errors = validate_user_data(data) # Create the user
result = create_user(user_data) # This is a function call, not a route
if not is_valid: if result["success"]:
for field, error in errors.items(): flash("Usuario creado exitosamente.", "success")
flash(f"Error en {field}: {error}", "danger") return redirect(url_for("users.list"))
return render_template("users/create.html", form=form) else:
flash(f'Error al crear usuario: {result["error"]}', "danger")
# Crear usuario except Exception as e:
success, message = create_user( flash(f"Error inesperado: {str(e)}", "danger")
username=data["username"],
nombre=data["nombre"],
email=data["email"],
password=data["password"],
nivel=data["nivel"],
idioma=data["idioma"],
fecha_caducidad=data["fecha_caducidad"],
empresa=data["empresa"],
estado=data["estado"],
)
if success:
flash(message, "success")
# Registrar actividad
log_user_management(
admin_id=current_user.id,
target_user_id=data["username"],
action="create",
)
return redirect(url_for("users.list_users"))
else:
flash(message, "danger")
# If GET request or form validation failed
return render_template("users/create.html", form=form) return render_template("users/create.html", form=form)
@ -167,7 +139,7 @@ def edit(username):
if not user: if not user:
flash(f"Usuario {username} no encontrado.", "danger") flash(f"Usuario {username} no encontrado.", "danger")
return redirect(url_for("users.list_users")) return redirect(url_for("users.list"))
form = UserForm(obj=user) form = UserForm(obj=user)
@ -207,7 +179,7 @@ def edit(username):
details={"fields_updated": list(data.keys())}, details={"fields_updated": list(data.keys())},
) )
return redirect(url_for("users.list_users")) return redirect(url_for("users.list"))
else: else:
flash(message, "danger") flash(message, "danger")
@ -221,11 +193,11 @@ def delete(username):
"""Eliminar usuario.""" """Eliminar usuario."""
if username == current_user.id: if username == current_user.id:
flash("No puede eliminar su propio usuario.", "danger") flash("No puede eliminar su propio usuario.", "danger")
return redirect(url_for("users.list_users")) return redirect(url_for("users.list"))
if username == "admin": if username == "admin":
flash("No se puede eliminar el usuario administrador.", "danger") flash("No se puede eliminar el usuario administrador.", "danger")
return redirect(url_for("users.list_users")) return redirect(url_for("users.list"))
success, message = delete_user(username) success, message = delete_user(username)
@ -239,7 +211,7 @@ def delete(username):
else: else:
flash(message, "danger") flash(message, "danger")
return redirect(url_for("users.list_users")) return redirect(url_for("users.list"))
# API para verificar disponibilidad de nombre de usuario # API para verificar disponibilidad de nombre de usuario

View File

@ -0,0 +1,79 @@
{% extends "base.html" %}
{% block title %}Crear Proyecto - ARCH{% endblock %}
{% block content %}
<div class="container mt-4">
<h1>Crear Nuevo Proyecto</h1>
<div class="card">
<div class="card-header bg-primary text-white">
<h5 class="mb-0">Información del Proyecto</h5>
</div>
<div class="card-body">
<form method="POST" action="{{ url_for('projects.create') }}">
{{ form.csrf_token if form.csrf_token }}
<div class="mb-3">
<label for="codigo" class="form-label">Código del Proyecto</label>
<input type="text" class="form-control" id="codigo" name="codigo" required>
</div>
<div class="mb-3">
<label for="descripcion" class="form-label">Descripción</label>
<textarea class="form-control" id="descripcion" name="descripcion" rows="3" required></textarea>
</div>
<div class="mb-3">
<label for="esquema" class="form-label">Esquema</label>
<select class="form-select" id="esquema" name="esquema" required>
{% if schemas %}
{% for codigo, schema in schemas.items() %}
<option value="{{ codigo }}">{{ codigo }} - {{ schema.descripcion }}</option>
{% endfor %}
{% else %}
<option value="">No hay esquemas disponibles</option>
{% endif %}
</select>
</div>
<div class="mb-3">
<label for="cliente" class="form-label">Cliente</label>
<input type="text" class="form-control" id="cliente" name="cliente">
</div>
<div class="mb-3">
<label for="destinacion" class="form-label">Destinación</label>
<input type="text" class="form-control" id="destinacion" name="destinacion">
</div>
<div class="mb-3">
<label for="proyecto_padre" class="form-label">Proyecto Padre (opcional)</label>
<select class="form-select" id="proyecto_padre" name="proyecto_padre">
<option value="">Ninguno</option>
{% if projects %}
{% for project in projects %}
<option value="{{ project.id }}">{{ project.codigo }} - {{ project.descripcion }}</option>
{% endfor %}
{% endif %}
</select>
</div>
<div class="mb-3">
<label for="estado" class="form-label">Estado</label>
<select class="form-select" id="estado" name="estado">
<option value="activo" selected>Activo</option>
<option value="archivado">Archivado</option>
<option value="suspendido">Suspendido</option>
</select>
</div>
<div class="d-flex justify-content-between">
<button type="submit" class="btn btn-primary">Crear Proyecto</button>
<a href="{{ url_for('projects.list') }}" class="btn btn-secondary">Cancelar</a>
</div>
</form>
</div>
</div>
</div>
{% endblock %}

View File

@ -0,0 +1,140 @@
{% extends "base.html" %}
{% block title %}Crear Esquema - ARCH{% endblock %}
{% block content %}
<div class="container mt-4">
<h1>Crear Nuevo Esquema</h1>
<div class="card">
<div class="card-header bg-primary text-white">
<h5 class="mb-0">Información del Esquema</h5>
</div>
<div class="card-body">
<form method="POST" action="{{ url_for('schemas.create') }}" id="schema-form">
{{ form.csrf_token if form.csrf_token }}
<div class="mb-3">
<label for="codigo" class="form-label">Código del Esquema</label>
<input type="text" class="form-control" id="codigo" name="codigo" required>
</div>
<div class="mb-3">
<label for="descripcion" class="form-label">Descripción</label>
<textarea class="form-control" id="descripcion" name="descripcion" rows="3" required></textarea>
</div>
<hr>
<h4>Documentos del Esquema</h4>
<div id="documents-container">
<!-- Initial document template -->
<div class="document-item card mb-3 p-3">
<div class="row">
<div class="col-md-3 mb-3">
<label class="form-label">Tipo de Documento</label>
<select class="form-select" name="doc_tipo[]" required>
{% if filetypes %}
{% for extension, filetype in filetypes.items() %}
<option value="{{ extension }}">{{ filetype.descripcion }}</option>
{% endfor %}
{% else %}
<option value="">No hay tipos disponibles</option>
{% endif %}
</select>
</div>
<div class="col-md-4 mb-3">
<label class="form-label">Nombre</label>
<input type="text" class="form-control" name="doc_nombre[]" required>
</div>
<div class="col-md-2 mb-3">
<label class="form-label">Nivel Ver</label>
<input type="number" class="form-control" name="doc_nivel_ver[]" value="0" min="0" max="9999">
</div>
<div class="col-md-2 mb-3">
<label class="form-label">Nivel Editar</label>
<input type="number" class="form-control" name="doc_nivel_editar[]" value="1000" min="0" max="9999">
</div>
<div class="col-md-1 mb-3 d-flex align-items-end">
<button type="button" class="btn btn-danger remove-document" style="display:none;">
<i class="fas fa-trash"></i>
</button>
</div>
</div>
</div>
</div>
<div class="mb-4">
<button type="button" class="btn btn-secondary" id="add-document">
<i class="fas fa-plus"></i> Agregar Documento
</button>
</div>
<div class="d-flex justify-content-between">
<button type="submit" class="btn btn-primary">Crear Esquema</button>
<a href="{{ url_for('schemas.list') }}" class="btn btn-secondary">Cancelar</a>
</div>
</form>
</div>
</div>
</div>
{% endblock %}
{% block scripts %}
<script>
document.addEventListener('DOMContentLoaded', function() {
const container = document.getElementById('documents-container');
const addButton = document.getElementById('add-document');
// Initially enable the remove button if more than one document exists
updateRemoveButtons();
addButton.addEventListener('click', function() {
const documentTemplate = container.querySelector('.document-item').cloneNode(true);
// Reset values
const inputs = documentTemplate.querySelectorAll('input[type="text"], input[type="number"]');
inputs.forEach(input => {
if (input.name.includes('nivel_ver')) {
input.value = '0';
} else if (input.name.includes('nivel_editar')) {
input.value = '1000';
} else {
input.value = '';
}
});
container.appendChild(documentTemplate);
updateRemoveButtons();
// Add event listener to the new remove button
documentTemplate.querySelector('.remove-document').addEventListener('click', function() {
this.closest('.document-item').remove();
updateRemoveButtons();
});
});
// Function to update the visibility of remove buttons
function updateRemoveButtons() {
const items = container.querySelectorAll('.document-item');
items.forEach((item, index) => {
const removeBtn = item.querySelector('.remove-document');
if (items.length > 1) {
removeBtn.style.display = 'block';
} else {
removeBtn.style.display = 'none';
}
});
}
// Add event listeners to initial remove buttons
document.querySelectorAll('.remove-document').forEach(button => {
button.addEventListener('click', function() {
this.closest('.document-item').remove();
updateRemoveButtons();
});
});
});
</script>
{% endblock %}

View File

@ -0,0 +1,73 @@
{% extends "base.html" %}
{% block title %}Crear Usuario - ARCH{% endblock %}
{% block content %}
<div class="container mt-4">
<h1>Crear Usuario</h1>
<div class="card">
<div class="card-header bg-primary text-white">
<h5 class="mb-0">Información del Usuario</h5>
</div>
<div class="card-body">
<form method="POST" action="{{ url_for('users.create') }}">
{{ form.csrf_token if form.csrf_token }}
<div class="mb-3">
<label for="username" class="form-label">Nombre de Usuario</label>
<input type="text" class="form-control" id="username" name="username" required>
</div>
<div class="mb-3">
<label for="nombre" class="form-label">Nombre Completo</label>
<input type="text" class="form-control" id="nombre" name="nombre" required>
</div>
<div class="mb-3">
<label for="email" class="form-label">Correo Electrónico</label>
<input type="email" class="form-control" id="email" name="email" required>
</div>
<div class="mb-3">
<label for="password" class="form-label">Contraseña</label>
<input type="password" class="form-control" id="password" name="password" required>
</div>
<div class="mb-3">
<label for="password_confirm" class="form-label">Confirmar Contraseña</label>
<input type="password" class="form-control" id="password_confirm" name="password_confirm" required>
</div>
<div class="mb-3">
<label for="nivel" class="form-label">Nivel de Acceso</label>
<select class="form-select" id="nivel" name="nivel" required>
<option value="1000">Usuario (1000)</option>
<option value="5000">Supervisor (5000)</option>
<option value="9000">Administrador (9000)</option>
<option value="9999">Super Administrador (9999)</option>
</select>
</div>
<div class="mb-3">
<label for="empresa" class="form-label">Empresa</label>
<input type="text" class="form-control" id="empresa" name="empresa" value="ARCH">
</div>
<div class="mb-3">
<label for="idioma" class="form-label">Idioma</label>
<select class="form-select" id="idioma" name="idioma">
<option value="es" selected>Español</option>
<option value="en">Inglés</option>
</select>
</div>
<div class="d-flex justify-content-between">
<button type="submit" class="btn btn-primary">Crear Usuario</button>
<a href="{{ url_for('users.list') }}" class="btn btn-secondary">Cancelar</a>
</div>
</form>
</div>
</div>
</div>
{% endblock %}

View File

@ -28,39 +28,41 @@
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
{% for user_id, user in users.items() %} {% if users and users|length > 0 %}
<tr> {% for user in users %}
<td>{{ user.username }}</td> <tr>
<td>{{ user.nombre }}</td> <td>{{ user.username }}</td>
<td>{{ user.email }}</td> <td>{{ user.nombre }}</td>
<td>{{ user.nivel }}</td> <td>{{ user.email }}</td>
<td> <td>{{ user.nivel }}</td>
{% if user.estado == 'activo' %} <td>
<span class="badge bg-success">Activo</span> {% if user.estado == 'activo' %}
{% else %} <span class="badge bg-success">Activo</span>
<span class="badge bg-danger">Inactivo</span> {% else %}
{% endif %} <span class="badge bg-danger">Inactivo</span>
</td> {% endif %}
<td> </td>
<div class="btn-group btn-group-sm" role="group"> <td>
<a href="{{ url_for('users.edit', username=user.username) }}" <div class="btn-group btn-group-sm" role="group">
class="btn btn-outline-primary" title="Editar"> <a href="{{ url_for('users.edit', username=user.username) }}"
<i class="fas fa-edit"></i> class="btn btn-outline-primary" title="Editar">
</a> <i class="fas fa-edit"></i>
{% if user_id != current_user.get_id() and current_user.has_permission(9000) %} </a>
<button type="button" class="btn btn-outline-danger" {% if user_id != current_user.get_id() and current_user.has_permission(9000) %}
onclick="confirmDelete('{{ user.username }}', '{{ user.username }}')" title="Eliminar"> <button type="button" class="btn btn-outline-danger"
<i class="fas fa-trash"></i> onclick="confirmDelete('{{ user.username }}', '{{ user.username }}')" title="Eliminar">
</button> <i class="fas fa-trash"></i>
{% endif %} </button>
</div> {% endif %}
</td> </div>
</tr> </td>
</tr>
{% endfor %}
{% else %} {% else %}
<tr> <tr>
<td colspan="6" class="text-center">No hay usuarios registrados.</td> <td colspan="6" class="text-center">No hay usuarios registrados.</td>
</tr> </tr>
{% endfor %} {% endif %}
</tbody> </tbody>
</table> </table>
</div> </div>

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -2,7 +2,7 @@
"ESQ001": { "ESQ001": {
"codigo": "ESQ001", "codigo": "ESQ001",
"descripcion": "Proyecto estándar", "descripcion": "Proyecto estándar",
"fecha_creacion": "2025-03-04T10:17:09.979764+00:00", "fecha_creacion": "2025-03-04T10:25:03.799581+00:00",
"creado_por": "admin", "creado_por": "admin",
"documentos": [ "documentos": [
{ {

View File

@ -3,12 +3,12 @@
"nombre": "Administrador", "nombre": "Administrador",
"username": "admin", "username": "admin",
"email": "admin@example.com", "email": "admin@example.com",
"password_hash": "$2b$04$MDmmt/Wr5K0vEpL0I2gfVOQb6af8xHtympw8lbDUjuTA8mY4wEJ7K", "password_hash": "$2b$04$UGmPF4BBNejhS7ZKA58/hu3A8DtXkx7/Fyw.8igRby6eDw/RwkvAq",
"nivel": 9999, "nivel": 9999,
"idioma": "es", "idioma": "es",
"fecha_caducidad": null, "fecha_caducidad": null,
"empresa": "", "empresa": "",
"estado": "activo", "estado": "activo",
"ultimo_acceso": "2025-03-04T10:17:09.978287+00:00" "ultimo_acceso": "2025-03-04T10:25:03.799581+00:00"
} }
} }