forked from TDTP/admin_transporte_backend
Merge branch 'master' of https://gitlab.com/m3f_usm/admin_transporte/backend into develop/Ronald
Obteniendo ultima versionfrancisco/photos
commit
b1041b2a2f
|
@ -0,0 +1,19 @@
|
|||
# Conexion con base datos principal
|
||||
DBHOST=db
|
||||
DBPORT=5432
|
||||
DBNAME=transporte
|
||||
DBSCHEMA=public
|
||||
DBUSER=postgres
|
||||
DBPASS=password
|
||||
|
||||
# Conexion con base datos redis
|
||||
DB_REDIS_HOST=dbproto
|
||||
DB_REDIS_PORT=6379
|
||||
|
||||
# Datos de emisor de correos
|
||||
SMTP_HOST=smtp-mail.outlook.com
|
||||
SMTP_PORT=587
|
||||
SMTP_PROTOCOL=tls
|
||||
SMTP_USER=francisco.sandoval@outlook.cl
|
||||
SMTP_PASS=ppcsrdsvecdewnfl
|
||||
SMTP_FROM='"Sistema Transporte" <francisco.sandoval@outlook.cl>'
|
|
@ -2,11 +2,10 @@ from django.urls import resolve
|
|||
from django.http import HttpResponse
|
||||
from .models import Usuario, Persona
|
||||
from decouple import config
|
||||
from project.settings import SECRET_KEY
|
||||
import jwt
|
||||
import logging
|
||||
|
||||
private_key = config('SECRET_JWT')
|
||||
|
||||
class ApiMiddleware:
|
||||
def __init__(self, get_response):
|
||||
self.get_response = get_response
|
||||
|
@ -17,11 +16,6 @@ class ApiMiddleware:
|
|||
response = self.get_response(request)
|
||||
return response
|
||||
|
||||
# se omite esta regla en login
|
||||
if request.path == '/api/auth/' and request.method == 'POST':
|
||||
response = self.get_response(request)
|
||||
return response
|
||||
|
||||
match = resolve(request.path)
|
||||
logging.error(match)
|
||||
|
||||
|
@ -30,6 +24,22 @@ class ApiMiddleware:
|
|||
response = self.get_response(request)
|
||||
return response
|
||||
|
||||
if match.url_name == 'auth_login' and request.method == 'POST':
|
||||
response = self.get_response(request)
|
||||
return response
|
||||
|
||||
if match.url_name == 'auth_recuperar':
|
||||
response = self.get_response(request)
|
||||
return response
|
||||
|
||||
if match.url_name == 'auth_info':
|
||||
response = self.get_response(request)
|
||||
return response
|
||||
|
||||
if match.url_name == 'auth_contrasena':
|
||||
response = self.get_response(request)
|
||||
return response
|
||||
|
||||
# se omite esta regla al mostrar informacion publica de paradero
|
||||
if match.url_name == 'paradero-info-public' and request.method == 'GET':
|
||||
response = self.get_response(request)
|
||||
|
@ -42,7 +52,7 @@ class ApiMiddleware:
|
|||
token = authorization[1]
|
||||
|
||||
try:
|
||||
decoded = jwt.decode(token, private_key, algorithms=["HS256"])
|
||||
decoded = jwt.decode(token, SECRET_KEY, algorithms=["HS256"])
|
||||
except jwt.ExpiredSignatureError:
|
||||
return HttpResponse('token ya no es valido', status = 400)
|
||||
except jwt.InvalidTokenError:
|
||||
|
|
|
@ -369,24 +369,13 @@ class Usuario(models.Model):
|
|||
vigente = models.BooleanField(blank=True, null=True)
|
||||
superuser = models.BooleanField(blank=True, null=True)
|
||||
id_rol = models.ForeignKey(Rol, models.DO_NOTHING, db_column='id_rol', blank=False, null=False)
|
||||
clave = models.CharField(max_length=100, blank=True, null=True)
|
||||
|
||||
class Meta:
|
||||
managed = False
|
||||
db_table = 'usuario'
|
||||
|
||||
|
||||
class UsuarioClave(models.Model):
|
||||
login = models.OneToOneField(Usuario, models.DO_NOTHING, db_column='login', primary_key=True)
|
||||
clave = models.CharField(max_length=60, blank=True, null=True)
|
||||
clave_anterior = models.CharField(max_length=60, blank=True, null=True)
|
||||
fecha_modificacion = models.DateField(blank=True, null=True)
|
||||
codigo = models.DecimalField(max_digits=8, decimal_places=0, blank=True, null=True)
|
||||
|
||||
class Meta:
|
||||
managed = False
|
||||
db_table = 'usuario_clave'
|
||||
|
||||
|
||||
class Vehiculo(models.Model):
|
||||
ppu = models.CharField(primary_key=True, max_length=10)
|
||||
id_tipo_vehiculo = models.ForeignKey(TipoVehiculo, models.DO_NOTHING, db_column='id_tipo_vehiculo', blank=True, null=True)
|
||||
|
|
|
@ -0,0 +1,23 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Document</title>
|
||||
</head>
|
||||
<body>
|
||||
<div style="text-align: center;">
|
||||
<p><strong>Estimado/a {{ nombre }}</strong></p>
|
||||
<p>Para crear una nueva contraseña, es necesario que ingrese el siguiente código:
|
||||
<strong style="font-size: 1.5rem;">{{ codigo }}</strong>
|
||||
</p>
|
||||
|
||||
<p>Pinche el siguiente botón para crear una nueva contraseña.</p>
|
||||
<p>
|
||||
<a href="{{ vinculo }}" target="_blank" style="background: steelblue; color: #fff; padding: 1rem;">
|
||||
CREAR NUEVA CONTRASEÑA
|
||||
</a>
|
||||
</p>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
|
@ -34,7 +34,10 @@ router.register('roles-lineas', rol_linea.RolLineaViewSet, basename='rol_linea')
|
|||
|
||||
urlpatterns = [
|
||||
path('', include(router.urls)),
|
||||
path('auth/', auth.jwt_login, name='auth'),
|
||||
path('auth/', auth.jwt_login, name='auth_login'),
|
||||
path('auth/recuperar/', auth.recuperar, name='auth_recuperar'),
|
||||
path('auth/info/', auth.info_token, name='auth_info'),
|
||||
path('auth/nueva-contrasena/', auth.nueva_contrasena, name='auth_contrasena'),
|
||||
path('mapas/paraderos/', mapa.paraderos, name='mapa-paraderos'),
|
||||
path('mapas/rutas/', mapa.rutas, name='mapa-rutas'),
|
||||
path('upload/zip/', upload.upload_zip, name='upload_zip'),
|
||||
|
|
|
@ -1,18 +1,22 @@
|
|||
|
||||
from django.views.decorators.csrf import csrf_exempt
|
||||
from django.http import HttpResponse
|
||||
from django.http import JsonResponse
|
||||
from django.contrib.auth.hashers import check_password, make_password
|
||||
from django.http import HttpResponse, JsonResponse
|
||||
|
||||
from rest_framework.decorators import action, api_view, schema
|
||||
from project.settings import SECRET_KEY, EMAIL_HOST
|
||||
|
||||
from .. import models, schemas
|
||||
from api import models, schemas
|
||||
from datetime import datetime, timedelta
|
||||
from decouple import config
|
||||
import json
|
||||
import jwt
|
||||
from datetime import datetime, timedelta
|
||||
import logging
|
||||
import random
|
||||
|
||||
private_key = config('SECRET_JWT')
|
||||
from django.conf import settings
|
||||
from django.core.mail import EmailMultiAlternatives
|
||||
from django.template.loader import get_template
|
||||
|
||||
# Views jwt
|
||||
@csrf_exempt
|
||||
|
@ -21,26 +25,27 @@ private_key = config('SECRET_JWT')
|
|||
@schema(schemas.AuthSchema())
|
||||
def jwt_login(request):
|
||||
if request.method == 'POST':
|
||||
count = models.Usuario.objects.filter(vigente = True).count()
|
||||
logging.error(f'count usuario vigente = {count}')
|
||||
|
||||
# validar username y password
|
||||
# validar rut y password
|
||||
input = json.loads(request.body)
|
||||
username = input['username']
|
||||
password = input['password']
|
||||
rut = input['rut'].replace('.','').replace('-','')
|
||||
|
||||
if rut != '0':
|
||||
dv = rut[-1].upper()
|
||||
rut = rut[:-1]
|
||||
|
||||
usuario = None
|
||||
|
||||
if count > 0:
|
||||
usuario = models.Usuario.objects.filter(login = username, vigente = True).values().first()
|
||||
elif username == '0' and password == '0':
|
||||
if rut == '0' and password == '0':
|
||||
usuario = { 'login': '0', 'clave': '0' }
|
||||
|
||||
if not usuario:
|
||||
return HttpResponse('Acceso no valido', status=400)
|
||||
# solo se permite usuario 0 si no existen usuarios vigentes
|
||||
count = models.Usuario.objects.filter(vigente = True).count()
|
||||
if count > 0:
|
||||
return HttpResponse('Acceso no valido', status=400)
|
||||
else:
|
||||
usuario = models.Usuario.objects.filter(vigente=1, rut__rut=rut, rut__dv=dv).values().first()
|
||||
|
||||
if username != '0':
|
||||
clave = models.UsuarioClave.objects.filter(login = username).first()
|
||||
if not clave or clave.clave != password:
|
||||
if not check_password(input['password'], usuario['clave']):
|
||||
return HttpResponse('Acceso no valido', status=400)
|
||||
|
||||
ahora = datetime.utcnow()
|
||||
|
@ -52,7 +57,132 @@ def jwt_login(request):
|
|||
'exp': manana, # ahora + timedelta(minutes=60),
|
||||
'login': usuario['login']
|
||||
}
|
||||
token = jwt.encode(payload, private_key, algorithm="HS256")
|
||||
token = jwt.encode(payload, SECRET_KEY, algorithm="HS256")
|
||||
return JsonResponse({ 'token': token })
|
||||
|
||||
elif request.method == 'GET':
|
||||
return JsonResponse(request.jwt_info)
|
||||
|
||||
|
||||
|
||||
@csrf_exempt
|
||||
@action(detail=False, methods=['post'])
|
||||
@api_view(['POST'])
|
||||
def recuperar(request):
|
||||
input = json.loads(request.body)
|
||||
rut = input['rut'].replace('.','').replace('-','')
|
||||
|
||||
dv = rut[-1].upper()
|
||||
rut = rut[:-1]
|
||||
|
||||
persona = models.Persona.objects.filter(rut=rut, dv=dv).first()
|
||||
usuario = models.Usuario.objects.filter(rut=rut, vigente=True).first()
|
||||
|
||||
if usuario == None or persona == None:
|
||||
return HttpResponse('Acceso no valido', status=400)
|
||||
|
||||
if persona.email != input['email'].lower():
|
||||
return HttpResponse('Acceso no valido', status=400)
|
||||
|
||||
codigo_aleatorio = random.randint(100000, 999999)
|
||||
ahora = datetime.utcnow()
|
||||
expira = ahora + timedelta(minutes=5)
|
||||
payload = {
|
||||
'iat': ahora,
|
||||
'exp': expira,
|
||||
'rut': f'{persona.rut}',
|
||||
'codigo': codigo_aleatorio
|
||||
}
|
||||
token = jwt.encode(payload, SECRET_KEY, algorithm="HS256")
|
||||
vinculo = f"{http_referer(request)}/?s={token}#/new-password"
|
||||
|
||||
exito = enviar_correo(persona.email, 'Recuperar acceso', {
|
||||
'nombre': f'{persona.nombres} {persona.apellido_a} {persona.apellido_b}',
|
||||
'codigo': codigo_aleatorio,
|
||||
'vinculo': vinculo
|
||||
})
|
||||
|
||||
return JsonResponse({ 'ok': exito, 'HTTP_REFERER': request.META['HTTP_REFERER'] })
|
||||
|
||||
|
||||
|
||||
@csrf_exempt
|
||||
@action(detail=False, methods=['post'])
|
||||
@api_view(['POST'])
|
||||
def info_token(request):
|
||||
input = json.loads(request.body)
|
||||
token = input['token']
|
||||
try:
|
||||
decoded = jwt.decode(token, SECRET_KEY, algorithms=["HS256"])
|
||||
persona = models.Persona.objects.filter(rut=decoded['rut']).first()
|
||||
|
||||
return JsonResponse({
|
||||
'nombres': persona.nombres,
|
||||
'apellido_a': persona.apellido_a,
|
||||
'apellido_b': persona.apellido_b
|
||||
})
|
||||
except jwt.ExpiredSignatureError:
|
||||
return HttpResponse('token ya no es valido', status = 400)
|
||||
except jwt.InvalidTokenError:
|
||||
return HttpResponse('token es invalido', status = 400)
|
||||
|
||||
|
||||
|
||||
@csrf_exempt
|
||||
@action(detail=False, methods=['post'])
|
||||
@api_view(['POST'])
|
||||
def nueva_contrasena(request):
|
||||
input = json.loads(request.body)
|
||||
token = input['token']
|
||||
try:
|
||||
decoded = jwt.decode(token, SECRET_KEY, algorithms=["HS256"])
|
||||
|
||||
if f"{decoded['codigo']}" != input['codigo']:
|
||||
return HttpResponse('código es invalido', status = 400)
|
||||
|
||||
usuario = models.Usuario.objects.filter(rut = decoded['rut']).first()
|
||||
if usuario == None:
|
||||
return HttpResponse('Usuario no encontrado', status = 400)
|
||||
|
||||
usuario.clave = make_password(input['password'])
|
||||
usuario.save()
|
||||
|
||||
return JsonResponse({ 'ok': True })
|
||||
|
||||
except jwt.ExpiredSignatureError:
|
||||
return HttpResponse('token ya no es valido', status = 400)
|
||||
except jwt.InvalidTokenError:
|
||||
return HttpResponse('token es invalido', status = 400)
|
||||
except Exception as e:
|
||||
logging.error(e)
|
||||
return HttpResponse('error al cambiar contraseña', status = 500)
|
||||
|
||||
|
||||
|
||||
|
||||
def enviar_correo(destinatario, asunto, contenido):
|
||||
try:
|
||||
template = get_template('correo_recuperar.html') # Ruta al template del correo
|
||||
contenido_renderizado = template.render(contenido)
|
||||
|
||||
mensaje = EmailMultiAlternatives(asunto, '', settings.EMAIL_HOST_USER, [destinatario])
|
||||
mensaje.attach_alternative(contenido_renderizado, 'text/html')
|
||||
mensaje.send()
|
||||
return True
|
||||
except Exception as e:
|
||||
print(f'EMAIL_HOST: {EMAIL_HOST}', flush=True)
|
||||
print(f'ERROR: {e}', flush=True)
|
||||
return False
|
||||
|
||||
|
||||
|
||||
|
||||
def http_referer(request):
|
||||
if 'HTTP_REFERER' in request.META:
|
||||
referer = request.META['HTTP_REFERER']
|
||||
else:
|
||||
protocol = request.scheme
|
||||
host = request.META['HTTP_HOST']
|
||||
port = request.META['SERVER_PORT']
|
||||
referer = f'{protocol}://{host}'
|
||||
return referer
|
|
@ -28,7 +28,7 @@ class ParaderoViewSet(viewsets.ModelViewSet):
|
|||
|
||||
@action(detail=False, methods=['get'], url_path='info-public/(?P<pk>\S+)')
|
||||
def info_public(self, request, pk=None):
|
||||
if hasattr(request.META,'HTTP_REFERER'):
|
||||
if 'HTTP_REFERER' in request.META:
|
||||
referer = request.META['HTTP_REFERER']
|
||||
else:
|
||||
protocol = request.scheme
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
|
||||
from django.db import transaction
|
||||
from django.http import HttpResponse, JsonResponse
|
||||
from django.contrib.auth.hashers import make_password
|
||||
from rest_framework import viewsets
|
||||
from rest_framework.response import Response
|
||||
from rest_framework.decorators import action
|
||||
|
@ -60,24 +61,10 @@ class UsuarioViewSet(viewsets.ModelViewSet):
|
|||
)
|
||||
usuario.save()
|
||||
|
||||
# logging.error(f'clave = {input["clave"]}')
|
||||
if input['clave']:
|
||||
logging.error('Modificar clave de usuario')
|
||||
clave = models.UsuarioClave.objects.filter(login = usuario.login).first()
|
||||
if clave:
|
||||
logging.error('Clave Usuario ya existe')
|
||||
clave.clave_anterior = clave.clave
|
||||
clave.clave = input['clave']
|
||||
clave.fecha_modificacion = datetime.datetime.now()
|
||||
clave.save()
|
||||
else:
|
||||
logging.error('Clave Usuario se creará')
|
||||
clave = models.UsuarioClave(
|
||||
login = usuario,
|
||||
clave = input['clave'],
|
||||
fecha_modificacion = datetime.datetime.now()
|
||||
)
|
||||
clave.save()
|
||||
usuario.clave = make_password(input['clave'])
|
||||
usuario.save()
|
||||
|
||||
return Response({
|
||||
'rut': persona.rut,
|
||||
|
@ -101,13 +88,11 @@ class UsuarioViewSet(viewsets.ModelViewSet):
|
|||
|
||||
def update(self, request, *args, **kwargs):
|
||||
input = json.loads(request.body)
|
||||
logging.error(input)
|
||||
try:
|
||||
pk = input['rut']
|
||||
with transaction.atomic():
|
||||
|
||||
# validaciones se realiza a nivel del model
|
||||
|
||||
persona = models.Persona.objects.filter(rut = pk).first()
|
||||
rol = models.Rol.objects.filter(id_rol = input.get('id_rol')).first()
|
||||
|
||||
|
@ -119,23 +104,8 @@ class UsuarioViewSet(viewsets.ModelViewSet):
|
|||
|
||||
if 'clave' in input:
|
||||
logging.error('Modificar clave de usuario')
|
||||
logging.error(f'clave = {input["clave"]}')
|
||||
|
||||
clave = models.UsuarioClave.objects.filter(login = usuario.login).first()
|
||||
if clave:
|
||||
logging.error('Clave Usuario ya existe')
|
||||
clave.clave_anterior = clave.clave
|
||||
clave.clave = input['clave']
|
||||
clave.fecha_modificacion = datetime.datetime.now()
|
||||
clave.save()
|
||||
else:
|
||||
logging.error('Clave Usuario se creará')
|
||||
clave = models.UsuarioClave(
|
||||
login = usuario,
|
||||
clave = input['clave'],
|
||||
fecha_modificacion = datetime.datetime.now()
|
||||
)
|
||||
clave.save()
|
||||
usuario.clave = make_password(input['clave'])
|
||||
usuario.save()
|
||||
|
||||
return Response({
|
||||
'rut': persona.rut,
|
||||
|
|
|
@ -9,9 +9,12 @@ https://docs.djangoproject.com/en/4.2/topics/settings/
|
|||
For the full list of settings and their values, see
|
||||
https://docs.djangoproject.com/en/4.2/ref/settings/
|
||||
"""
|
||||
|
||||
from dotenv import load_dotenv
|
||||
from pathlib import Path
|
||||
from decouple import config
|
||||
import os
|
||||
|
||||
load_dotenv()
|
||||
|
||||
# Build paths inside the project like this: BASE_DIR / 'subdir'.
|
||||
BASE_DIR = Path(__file__).resolve().parent.parent
|
||||
|
@ -62,7 +65,10 @@ ROOT_URLCONF = 'project.urls'
|
|||
TEMPLATES = [
|
||||
{
|
||||
'BACKEND': 'django.template.backends.django.DjangoTemplates',
|
||||
'DIRS': [ BASE_DIR / 'dist' ],
|
||||
'DIRS': [
|
||||
os.path.join(BASE_DIR, 'dist'),
|
||||
os.path.join(BASE_DIR, 'api', 'templates')
|
||||
],
|
||||
'APP_DIRS': True,
|
||||
'OPTIONS': {
|
||||
'context_processors': [
|
||||
|
@ -170,3 +176,10 @@ LOGGING = {
|
|||
},
|
||||
}
|
||||
"""
|
||||
|
||||
|
||||
EMAIL_HOST = config('SMTP_HOST')
|
||||
EMAIL_PORT = config('SMTP_PORT', 587)
|
||||
EMAIL_HOST_USER = config('SMTP_USER', 'tu_correo@gmail.com') # Tu dirección de correo
|
||||
EMAIL_HOST_PASSWORD = config('SMTP_PASS', 'tu_contraseña') # Tu contraseña de correo
|
||||
EMAIL_USE_TLS = config('SMTP_PROTOCOL') == 'tls'
|
|
@ -4,6 +4,7 @@ djangorestframework
|
|||
django-cors-headers
|
||||
django-filter
|
||||
coreapi
|
||||
python-dotenv
|
||||
python-decouple
|
||||
PyJWT
|
||||
pymongo
|
||||
|
|
Loading…
Reference in New Issue