#1 Autenticacion

Stängd
cettipao wants to merge 10 commits from wilitp/auth-to-clima into wilitp/main

+ 2 - 2
app/api/admin.py

@@ -1,5 +1,5 @@
 from django.contrib import admin
-from .models import Preport
+from .models import ProgrammedReport
 
 # Register your models here.
-admin.site.register(Preport)
+admin.site.register(ProgrammedReport)

+ 14 - 0
app/api/client.py

@@ -0,0 +1,14 @@
+import requests
+from preports.settings import CLIMA_URL
+
+
+def get_user_id(token: str) -> requests.Response:
+    try:
+        response = requests.get(
+            f"{CLIMA_URL}/api/get_user_id/",
+            # Authorization debe tener el prefijo 'Token '
+            headers={"Authorization": "Token " + token},
+        )
+        return response
+    except:
+        return None

+ 2 - 2
app/api/migrations/0001_initial.py

@@ -1,4 +1,4 @@
-# Generated by Django 4.0.4 on 2022-05-13 22:53
+# Generated by Django 4.0.4 on 2022-09-20 19:13
 
 import api.validators
 from django.db import migrations, models
@@ -13,7 +13,7 @@ class Migration(migrations.Migration):
 
     operations = [
         migrations.CreateModel(
-            name='Preport',
+            name='ProgrammedReport',
             fields=[
                 ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
                 ('user_id', models.CharField(max_length=2048)),

+ 1 - 1
app/api/models.py

@@ -2,7 +2,7 @@ from django.db import models
 from .validators import json_email_array, json_not_empty_string_array
 
 
-class Preport(models.Model):
+class ProgrammedReport(models.Model):
     user_id = models.CharField(max_length=2048)
     report_type = models.CharField(max_length=50)
     modules = models.JSONField(

+ 17 - 0
app/api/permissions.py

@@ -0,0 +1,17 @@
+from rest_framework import permissions
+from .client import get_user_id
+
+
+class IsOmixomUser(permissions.BasePermission):
+    message = 'El token no pertenece a un usuario de Omixom'
+
+    # Determina el usuario al que pertenece el Token de Autorizacion.
+    # Solo da permisos si el token es valido y en ese caso setea el user_id asociado a ese token.
+    def has_permission(self, request, view):
+        token = request.META.get('HTTP_AUTHORIZATION')
+        response = get_user_id(token)
+        if response:
+            request.data["user_id"] = response.json()["user_id"]
+            return response.status_code == 200
+        else:
+            return False

+ 3 - 3
app/api/serializers.py

@@ -1,9 +1,9 @@
 from rest_framework import serializers
-from .models import Preport
+from .models import ProgrammedReport
 
 
-class PreportSerializer(serializers.ModelSerializer):
+class ProgrammedReportSerializer(serializers.ModelSerializer):
     class Meta:
-        model = Preport
+        model = ProgrammedReport
         fields = ["id", "user_id", "report_type", "modules",
                   "notified_emails", "last_report_date"]

+ 0 - 3
app/api/tests.py

@@ -1,3 +0,0 @@
-from django.test import TestCase
-
-# Create your tests here.

+ 2 - 2
app/api/urls.py

@@ -1,8 +1,8 @@
 from rest_framework.routers import SimpleRouter
-from .views import PreportViewSet
+from .views import ProgrammedReportViewSet
 
 
 router = SimpleRouter()
-router.register(r'preports', PreportViewSet, "preport")
+router.register(r'preports', ProgrammedReportViewSet, "preport")
 
 urlpatterns = router.urls

+ 1 - 5
app/api/validators.py

@@ -1,11 +1,7 @@
-import json
-import re
 from typing import List
 from django.core.exceptions import ValidationError
 from django.core.validators import validate_email
 
-from django.db.models.lookups import Regex
-
 
 def json_email_array(val: List):
     '''
@@ -32,7 +28,7 @@ def json_not_empty_string_array(val):
     valid = True
 
     # Ser una lista no vacia
-    if(not (isinstance(val, list) and len(val) > 0)):
+    if (not (isinstance(val, list) and len(val) > 0)):
         valid = False
 
     # Ser una lista de strings

+ 24 - 11
app/api/views.py

@@ -1,16 +1,29 @@
 from rest_framework import viewsets
-from rest_framework.permissions import AllowAny
-from .models import Preport
-from .serializers import PreportSerializer
+from .models import ProgrammedReport
+from .serializers import ProgrammedReportSerializer
+from .permissions import IsOmixomUser
 
 
-class PreportViewSet(viewsets.ModelViewSet):
-    # TODO: Mostrar solo los reportes del usuario
-    def get_queryset(self):
-        qs = Preport.objects.all()
-        return qs
+# API de Programmed Reports:
+# Requisitos:
+#   - Especificar el TOKEN del usuario en el HTTP Header "AUTHORIZATION".
+#   - Las requests deben ser JSON.
+#   - No es necesario enviar el field user_id, esto es seteado automaticamente al recibir el TOKEN.
+# Endpoints: (BASE_URL: /api/preports)
+#   - (List) GET /                   -> Obtener la lista de todos los Programmed Report
+#   - (Create) POST /                -> Crear un nuevo Programmed Report
+#   - (Retrieve) GET /{id}/          -> Obtener la informacion de un Programmed Report
+#   - (Update) PUT /{id}/            -> Actualizar un Programmed Report (requiere todos los fields)
+#   - (Partial_Update) PATCH /{id}/  -> Actualizar algunos fields de un Programmed Repor
+#   - (Delete) DELETE /{id}/         -> Elimina un Programmed Report
 
-    serializer_class = PreportSerializer
+class ProgrammedReportViewSet(viewsets.ModelViewSet):
+    # El ViewSet solo es valido si el Token enviado es de un usuario de Omixom.
+    permission_classes = [IsOmixomUser]
+    serializer_class = ProgrammedReportSerializer
 
-    # TODO: Implementar la permission class para checkear el token del usuario y vea que clases
-    permission_classes = [AllowAny]
+    # Solo se devuelven los modelos para el user_id asociado al token. (Ver IsOmixomUser)
+    def get_queryset(self):
+        user_id = self.request.data["user_id"]
+        qs = ProgrammedReport.objects.filter(user_id=user_id)
+        return qs

+ 5 - 4
app/preports/settings.py

@@ -76,17 +76,16 @@ WSGI_APPLICATION = 'preports.wsgi.application'
 # Database
 # https://docs.djangoproject.com/en/4.0/ref/settings/#databases
 
-DATABASES = {
+DATABASES =  {
     'default': {
-        'NAME': 'p-reports',
+        'NAME': os.getenv("DB_NAME"),
         'ENGINE': 'django.db.backends.postgresql',
-        'USER': 'p-reports',
+        'USER': os.getenv("DB_USER"),
         'PASSWORD': os.getenv("DB_PASSWORD"),
         'HOST': 'db'
     },
 }
 
-
 # Password validation
 # https://docs.djangoproject.com/en/4.0/ref/settings/#auth-password-validators
 
@@ -127,3 +126,5 @@ STATIC_URL = 'static/'
 # https://docs.djangoproject.com/en/4.0/ref/settings/#default-auto-field
 
 DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'
+
+CLIMA_URL = os.getenv("CLIMA_URL")

+ 5 - 0
app/requirements.txt

@@ -1,10 +1,15 @@
 asgiref==3.5.1
+certifi==2022.5.18.1
+charset-normalizer==2.0.12
 Django==4.0.4
 django-filter==21.1
 djangorestframework==3.13.1
+idna==3.3
 importlib-metadata==4.11.3
 Markdown==3.3.7
 psycopg2-binary==2.9.3
 pytz==2022.1
+requests==2.27.1
 sqlparse==0.4.2
+urllib3==1.26.9
 zipp==3.8.0

+ 15 - 6
docker-compose.yml

@@ -1,4 +1,4 @@
-version: '3'
+version: "3"
 
 services:
   app:
@@ -7,13 +7,22 @@ services:
       dockerfile: ./Dockerfile
     ports:
       - "8080:8000"
-    env_file:
-      - app.env
-    volumes: 
+    environment:
+      - DB_NAME=programmed-reports
+      - DB_USER=user-preports
+      - DB_PASSWORD=pass-preports
+        # En local se deben conectar los containers a la misma red,
+        # Idealmente en una red dedicada solo para microservicios
+        # Reemplazar con la URL real en produccion
+      - CLIMA_URL=http://172.29.0.3:8080
+    volumes:
       - ./app:/app
   db:
     image: postgres
-    env_file:
-      - postgres.env
+    environment:
+      - TZ=GMT+3
+      - POSTGRES_DB=programmed-reports
+      - POSTGRES_USER=user-preports
+      - POSTGRES_PASSWORD=pass-preports
     volumes:
       - ./data/postgres_data:/var/lib/postgresql/data/