added functionality to Serializer validate method
This commit is contained in:
@@ -174,7 +174,7 @@ AUTH_PASSWORD_VALIDATORS = [
|
|||||||
|
|
||||||
LANGUAGE_CODE = 'es-MX'
|
LANGUAGE_CODE = 'es-MX'
|
||||||
|
|
||||||
TIME_ZONE = 'CST6CDT'
|
TIME_ZONE = 'America/Chihuahua'
|
||||||
|
|
||||||
USE_I18N = True
|
USE_I18N = True
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,9 @@
|
|||||||
from django.contrib import admin
|
from django.contrib import admin
|
||||||
from .models import Sistema, sistemas_por_cliente
|
from .models import Sistema, sistemas_por_cliente, Device,DeviceHistory
|
||||||
# Register your models here.
|
# Register your models here.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class Sistema_Admin(admin.ModelAdmin):
|
class Sistema_Admin(admin.ModelAdmin):
|
||||||
def NSistema(self,obj):
|
def NSistema(self,obj):
|
||||||
return obj.nombre_sistema
|
return obj.nombre_sistema
|
||||||
@@ -13,5 +15,14 @@ class SPC(admin.ModelAdmin):
|
|||||||
return obj
|
return obj
|
||||||
list_display = ['id_sistema','Cliente','num_licencias']
|
list_display = ['id_sistema','Cliente','num_licencias']
|
||||||
|
|
||||||
|
class DeviceHistoryAdmin(admin.ModelAdmin):
|
||||||
|
list_display = ['device','first_authentication', 'last_authentication']
|
||||||
|
|
||||||
|
class DeviceAdmin(admin.ModelAdmin):
|
||||||
|
list_display = ['client', 'device_name', 'ip_address', 'sistema']
|
||||||
|
|
||||||
|
|
||||||
admin.site.register(Sistema,Sistema_Admin)
|
admin.site.register(Sistema,Sistema_Admin)
|
||||||
admin.site.register(sistemas_por_cliente,SPC)
|
admin.site.register(sistemas_por_cliente,SPC)
|
||||||
|
admin.site.register(Device,DeviceAdmin)
|
||||||
|
admin.site.register(DeviceHistory,DeviceHistoryAdmin)
|
||||||
@@ -0,0 +1,44 @@
|
|||||||
|
# Generated by Django 4.1.3 on 2023-01-23 15:37
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
import django.db.models.deletion
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('Clientes', '0014_alter_clientes_options'),
|
||||||
|
('Sistemas', '0001_initial'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='Device',
|
||||||
|
fields=[
|
||||||
|
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
|
('password', models.CharField(max_length=128, verbose_name='password')),
|
||||||
|
('last_login', models.DateTimeField(blank=True, null=True, verbose_name='last login')),
|
||||||
|
('device_name', models.CharField(max_length=255)),
|
||||||
|
('device_os', models.CharField(max_length=255)),
|
||||||
|
('ip_address', models.GenericIPAddressField()),
|
||||||
|
('client', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='Clientes.clientes')),
|
||||||
|
],
|
||||||
|
options={
|
||||||
|
'abstract': False,
|
||||||
|
},
|
||||||
|
),
|
||||||
|
migrations.AlterModelOptions(
|
||||||
|
name='sistemas_por_cliente',
|
||||||
|
options={'ordering': ('-cliente', 'id_sistema')},
|
||||||
|
),
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='DeviceHistory',
|
||||||
|
fields=[
|
||||||
|
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
|
('first_authentication', models.DateTimeField(auto_now_add=True)),
|
||||||
|
('last_authentication', models.DateTimeField(auto_now=True)),
|
||||||
|
('ip_address', models.GenericIPAddressField()),
|
||||||
|
('device', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='Sistemas.device')),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
]
|
||||||
26
Sistemas/migrations/0003_device_token_device_username.py
Normal file
26
Sistemas/migrations/0003_device_token_device_username.py
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
# Generated by Django 4.1.3 on 2023-01-23 17:18
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
import django.db.models.deletion
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('authtoken', '0003_tokenproxy'),
|
||||||
|
('Sistemas', '0002_device_alter_sistemas_por_cliente_options_and_more'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='device',
|
||||||
|
name='token',
|
||||||
|
field=models.OneToOneField(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='authtoken.token'),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='device',
|
||||||
|
name='username',
|
||||||
|
field=models.CharField(default=1, max_length=150, unique=True),
|
||||||
|
preserve_default=False,
|
||||||
|
),
|
||||||
|
]
|
||||||
21
Sistemas/migrations/0004_alter_device_username.py
Normal file
21
Sistemas/migrations/0004_alter_device_username.py
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
# Generated by Django 4.1.3 on 2023-01-23 17:22
|
||||||
|
|
||||||
|
from django.conf import settings
|
||||||
|
from django.db import migrations, models
|
||||||
|
import django.db.models.deletion
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
||||||
|
('Sistemas', '0003_device_token_device_username'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='device',
|
||||||
|
name='username',
|
||||||
|
field=models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL),
|
||||||
|
),
|
||||||
|
]
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
# Generated by Django 4.1.3 on 2023-01-23 17:39
|
||||||
|
|
||||||
|
from django.db import migrations
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('Sistemas', '0004_alter_device_username'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.RemoveField(
|
||||||
|
model_name='device',
|
||||||
|
name='last_login',
|
||||||
|
),
|
||||||
|
migrations.RemoveField(
|
||||||
|
model_name='device',
|
||||||
|
name='password',
|
||||||
|
),
|
||||||
|
]
|
||||||
19
Sistemas/migrations/0006_device_sistema.py
Normal file
19
Sistemas/migrations/0006_device_sistema.py
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
# Generated by Django 4.1.3 on 2023-01-25 13:59
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
import django.db.models.deletion
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('Sistemas', '0005_remove_device_last_login_remove_device_password'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='device',
|
||||||
|
name='sistema',
|
||||||
|
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='Sistemas.sistemas_por_cliente'),
|
||||||
|
),
|
||||||
|
]
|
||||||
19
Sistemas/migrations/0007_alter_device_sistema.py
Normal file
19
Sistemas/migrations/0007_alter_device_sistema.py
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
# Generated by Django 4.1.3 on 2023-01-25 14:33
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
import django.db.models.deletion
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('Sistemas', '0006_device_sistema'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='device',
|
||||||
|
name='sistema',
|
||||||
|
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='Sistemas.sistema'),
|
||||||
|
),
|
||||||
|
]
|
||||||
@@ -1,9 +1,11 @@
|
|||||||
from django.db import models
|
from django.db import models
|
||||||
|
from django.core.exceptions import ValidationError
|
||||||
from Clientes.models import Clientes
|
from Clientes.models import Clientes
|
||||||
|
from django.contrib.auth.models import User
|
||||||
|
from rest_framework.authtoken.models import Token
|
||||||
|
from django.contrib.auth.models import BaseUserManager
|
||||||
|
|
||||||
|
import re
|
||||||
|
|
||||||
|
|
||||||
class Sistema(models.Model):
|
class Sistema(models.Model):
|
||||||
nombre_sistema= models.CharField(max_length=100, blank=False,null=False,unique=True)
|
nombre_sistema= models.CharField(max_length=100, blank=False,null=False,unique=True)
|
||||||
@@ -18,10 +20,79 @@ class sistemas_por_cliente(models.Model):
|
|||||||
num_licencias= models.IntegerField(default=1)
|
num_licencias= models.IntegerField(default=1)
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
|
#{self.cliente.Nombre}-
|
||||||
return self.cliente.Nombre
|
return f'{self.id_sistema.nombre_sistema}'
|
||||||
class Meta:
|
class Meta:
|
||||||
ordering= ('-cliente','id_sistema')
|
ordering= ('-cliente','id_sistema')
|
||||||
|
|
||||||
|
|
||||||
|
class DeviceManager(BaseUserManager):
|
||||||
|
def generate_unique_username(self,client, device_name, ip_address):
|
||||||
|
username = f"Device_{client.RFC}_{device_name}_{ip_address}"
|
||||||
|
username_ = re.sub(r'\W+', '', username)
|
||||||
|
if User.objects.filter(username=username_).exists():
|
||||||
|
raise ValidationError(f"El Usuario ya existe {username_}")
|
||||||
|
return username_
|
||||||
|
|
||||||
|
def create_user(self,client, device_name, device_os, ip_address ):
|
||||||
|
user_= User.objects.create_user(
|
||||||
|
username=self.generate_unique_username(client,device_name,ip_address)
|
||||||
|
)
|
||||||
|
device =self.model(
|
||||||
|
client=client,
|
||||||
|
device_name= device_name,
|
||||||
|
device_os=device_os,
|
||||||
|
ip_address=ip_address,
|
||||||
|
username=user_
|
||||||
|
)
|
||||||
|
device.save()
|
||||||
|
|
||||||
|
Token.objects.create(user=user_)
|
||||||
|
DeviceHistory.objects.create(device=device)
|
||||||
|
return device
|
||||||
|
|
||||||
|
class Device(models.Model):
|
||||||
|
client = models.ForeignKey(Clientes,on_delete=models.CASCADE)
|
||||||
|
device_name = models.CharField(max_length=255)
|
||||||
|
device_os = models.CharField(max_length=255)
|
||||||
|
ip_address= models.GenericIPAddressField()
|
||||||
|
token = models.OneToOneField(Token, on_delete=models.CASCADE, blank=True,null=True)
|
||||||
|
username = models.OneToOneField(User, on_delete=models.CASCADE)
|
||||||
|
sistema = models.ForeignKey(Sistema,on_delete=models.CASCADE, blank=True, null=True)
|
||||||
|
#objects = DeviceManager()
|
||||||
|
def generate_unique_username(self,client, device_name,ip_address):
|
||||||
|
username = f"Device_{client.RFC}_{device_name}_{ip_address}"
|
||||||
|
username_ = re.sub(r'\W+', '', username)
|
||||||
|
|
||||||
|
if User.objects.filter(username=username_).exists():
|
||||||
|
raise ValidationError(f"El Usuario ya existe {username_}")
|
||||||
|
obj= User.objects.create_user(
|
||||||
|
username=username_
|
||||||
|
)
|
||||||
|
return obj
|
||||||
|
|
||||||
|
def save(self, *args, **kwargs):
|
||||||
|
if not self.pk:
|
||||||
|
obj = self.generate_unique_username(self.client,self.device_name, self.ip_address)
|
||||||
|
self.username= obj
|
||||||
|
token= Token.objects.create(user=obj)
|
||||||
|
self.token=token
|
||||||
|
super().save(*args, **kwargs)
|
||||||
|
DeviceHistory.objects.create(device=self,ip_address=self.ip_address)
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return f'{self.username}'
|
||||||
|
|
||||||
|
class DeviceHistory(models.Model):
|
||||||
|
device = models.ForeignKey(Device, on_delete=models.CASCADE)
|
||||||
|
first_authentication = models.DateTimeField(auto_now_add=True)
|
||||||
|
last_authentication = models.DateTimeField(auto_now=True)
|
||||||
|
ip_address = models.GenericIPAddressField()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class Maquinas_Conectadas(models.Model):
|
class Maquinas_Conectadas(models.Model):
|
||||||
|
|||||||
4
Sistemas/permissions.py
Normal file
4
Sistemas/permissions.py
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
from rest_framework.permissions import BasePermission
|
||||||
|
class HasAuthorizationHeader(BasePermission):
|
||||||
|
def has_permission(self, request, view):
|
||||||
|
return 'Authorization' in request.headers
|
||||||
40
Sistemas/serializers.py
Normal file
40
Sistemas/serializers.py
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
|
||||||
|
from rest_framework import serializers
|
||||||
|
from .models import Device, Sistema, sistemas_por_cliente
|
||||||
|
from Clientes.models import Clientes
|
||||||
|
|
||||||
|
class SistemaPrimaryKeyRelatedField(serializers.PrimaryKeyRelatedField):
|
||||||
|
def to_internal_value(self,data):
|
||||||
|
try:
|
||||||
|
print(Sistema.objects.get(nombre_sistema=data))
|
||||||
|
return Sistema.objects.get(nombre_sistema=data)
|
||||||
|
except Sistema.DoesNotExist:
|
||||||
|
raise serializers.ValidationError("Sistema no existe")
|
||||||
|
|
||||||
|
class ClientPrimaryKeyRelatedField(serializers.PrimaryKeyRelatedField):
|
||||||
|
def to_internal_value(self,data):
|
||||||
|
try:
|
||||||
|
return Clientes.objects.get(RFC=data)
|
||||||
|
except Clientes.DoesNotExist:
|
||||||
|
raise serializers.ValidationError("No existe Cliente")
|
||||||
|
|
||||||
|
class DeviceSerializer(serializers.ModelSerializer):
|
||||||
|
client = ClientPrimaryKeyRelatedField(queryset=Clientes.objects.all())
|
||||||
|
sistema = SistemaPrimaryKeyRelatedField(queryset=Sistema.objects.all())
|
||||||
|
token = serializers.CharField(read_only=True)
|
||||||
|
class Meta:
|
||||||
|
model =Device
|
||||||
|
fields = ('client','sistema','device_name','device_os', 'ip_address','token')
|
||||||
|
|
||||||
|
|
||||||
|
def validate(self, data):
|
||||||
|
sistema = data.get('sistema', None)
|
||||||
|
client = data.get('client', None)
|
||||||
|
try:
|
||||||
|
sistemaxCli = sistemas_por_cliente.objects.get(id_sistema=sistema,cliente=client)
|
||||||
|
print('validate spc', sistemaxCli)
|
||||||
|
except sistemas_por_cliente.DoesNotExist:
|
||||||
|
raise serializers.ValidationError('No existe licencia para este sistmea y/o cliente')
|
||||||
|
if sistemaxCli.num_licencias <= Device.objects.filter(sistema=sistemaxCli.id_sistema).count():
|
||||||
|
raise serializers.ValidationError(f"No hay licencias disponibles para este sistema:{sistema} y cliente:{client}")
|
||||||
|
return data
|
||||||
@@ -7,10 +7,14 @@ from .views import (
|
|||||||
SistemasXCliente_DetailView,
|
SistemasXCliente_DetailView,
|
||||||
|
|
||||||
#DRF APIViews
|
#DRF APIViews
|
||||||
Registrar_PC,
|
RegisterDeviceView,
|
||||||
|
AuthenticateDeviceView,
|
||||||
|
LogoutView,
|
||||||
)
|
)
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
path('',SistemasXCliente_ListView.as_view(),name='lista_sistmas'),
|
path('',SistemasXCliente_ListView.as_view(),name='lista_sistmas'),
|
||||||
path('detail/<str:pk>/',SistemasXCliente_DetailView.as_view(),name='detail_sistemas'),
|
path('detail/<str:pk>/',SistemasXCliente_DetailView.as_view(),name='detail_sistemas'),
|
||||||
path('registerPC/',Registrar_PC.as_view(),name='register_PC'),
|
path('registerPC/',RegisterDeviceView.as_view(),name='register_PC'),
|
||||||
|
path('authenticatePC/',AuthenticateDeviceView.as_view(), name="authenticateDevice"),
|
||||||
|
path('logout/', LogoutView.as_view(), name='logout_sistemas'),
|
||||||
]
|
]
|
||||||
@@ -1,14 +1,18 @@
|
|||||||
from django.shortcuts import render
|
from django.shortcuts import render
|
||||||
|
from django.contrib.auth import logout
|
||||||
from django.views.generic.list import ListView
|
from django.views.generic.list import ListView
|
||||||
from django.views.generic.detail import DetailView
|
from django.views.generic.detail import DetailView
|
||||||
|
from rest_framework.authentication import TokenAuthentication
|
||||||
from rest_framework.views import APIView
|
from rest_framework.views import APIView
|
||||||
from rest_framework.response import Response
|
from rest_framework.response import Response
|
||||||
from rest_framework.permissions import IsAuthenticated
|
from rest_framework.permissions import IsAuthenticated
|
||||||
from rest_framework import status, permissions
|
from rest_framework import status, permissions
|
||||||
|
from django.contrib.auth.models import User
|
||||||
from .models import sistemas_por_cliente
|
from .models import sistemas_por_cliente, DeviceHistory,Device
|
||||||
|
from .serializers import DeviceSerializer
|
||||||
|
from .permissions import HasAuthorizationHeader
|
||||||
|
from django.utils import timezone
|
||||||
|
import re
|
||||||
|
|
||||||
class SistemasXCliente_ListView(ListView):
|
class SistemasXCliente_ListView(ListView):
|
||||||
model = sistemas_por_cliente
|
model = sistemas_por_cliente
|
||||||
@@ -19,13 +23,76 @@ class SistemasXCliente_DetailView(DetailView):
|
|||||||
model = sistemas_por_cliente
|
model = sistemas_por_cliente
|
||||||
template_name= 'Sistemas/Xclientes/detail.html'
|
template_name= 'Sistemas/Xclientes/detail.html'
|
||||||
|
|
||||||
#registrar Equipo
|
from .verificacion_licencias import NumLicencias
|
||||||
class Registrar_PC(APIView):
|
class RegisterDeviceView(APIView):
|
||||||
permissions_classes = (permissions.AllowAny,)
|
permissions_classes = (permissions.AllowAny,)
|
||||||
|
|
||||||
def post(self,request, format=None):
|
def post(self,request):
|
||||||
data = request.data
|
try:
|
||||||
return Response(data)
|
# client = request.data.get('client')
|
||||||
|
# device_name = request.data.get('device_name')
|
||||||
|
# ip_address = request.data.get('ip_address')
|
||||||
|
# print('-----Not Token, so its register User ',request.data.get('token'))
|
||||||
|
# if self.Check_unique_username(client,device_name,ip_address):
|
||||||
|
# #or Device.objects.filter(username=username_check).exists():
|
||||||
|
# return Response({'Error':'El Dispositivo ya se encuentra registrado','isError':True}, status=status.HTTP_200_OK)
|
||||||
|
|
||||||
def get(self,request):
|
serializer = DeviceSerializer(data=request.data,context={'request':request})
|
||||||
pass
|
if serializer.is_valid():
|
||||||
|
serializer.save()
|
||||||
|
return Response(serializer.data, status=status.HTTP_200_OK)
|
||||||
|
else:
|
||||||
|
print('serializer.errors',serializer.errors)
|
||||||
|
return Response({'Error':f'{serializer.errors}','isError':True}, status=status.HTTP_200_OK)
|
||||||
|
except Exception as e:
|
||||||
|
return Response(
|
||||||
|
{'1)Error':f'{e}','isError':True}
|
||||||
|
, status=status.HTTP_200_OK
|
||||||
|
)
|
||||||
|
|
||||||
|
def Check_unique_username(self,client, device_name, ip_address):
|
||||||
|
username_ = f"Device_{client}_{device_name}_{ip_address}"
|
||||||
|
username_ = re.sub(r'\W+', '', username_)
|
||||||
|
if User.objects.filter(username=username_).exists():
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class AuthenticateDeviceView(APIView):
|
||||||
|
authentication_classes= [TokenAuthentication]
|
||||||
|
permissions_classes=[IsAuthenticated]
|
||||||
|
|
||||||
|
def get(self, request):
|
||||||
|
try:
|
||||||
|
obj, created = DeviceHistory.objects.get_or_create(
|
||||||
|
device=request.user.device,
|
||||||
|
ip_address=request.META.get('REMOTE_ADDR'),
|
||||||
|
)
|
||||||
|
obj.last_authentication=timezone.now()
|
||||||
|
obj.save()
|
||||||
|
|
||||||
|
device_data=DeviceSerializer(request.user.device).data
|
||||||
|
|
||||||
|
if device_data.serializer.is_valid:
|
||||||
|
print('ACCEPT',device_data.serializer.data)
|
||||||
|
return Response(device_data.serializer.data, status=status.HTTP_200_OK)
|
||||||
|
else:
|
||||||
|
print('ERROR',device_data.serializer.errors)
|
||||||
|
return Response(
|
||||||
|
{'Error':f'{device_data.serializer.errors}','isError':True}
|
||||||
|
, status=status.HTTP_200_OK
|
||||||
|
)
|
||||||
|
except Exception as e:
|
||||||
|
return Response(
|
||||||
|
{'Error':f'{e}','isError':True}
|
||||||
|
, status=status.HTTP_200_OK
|
||||||
|
)
|
||||||
|
|
||||||
|
class LogoutView(APIView):
|
||||||
|
authentication_classes = (TokenAuthentication,)
|
||||||
|
permission_classes = (IsAuthenticated,HasAuthorizationHeader,)
|
||||||
|
|
||||||
|
def post(self, request):
|
||||||
|
logout(request)
|
||||||
|
return Response({'OK':'Dispositivo desautenticado'},status=200)
|
||||||
Reference in New Issue
Block a user