From 692ca1a3bcb321a43cecb1eb6235e08a813d541c Mon Sep 17 00:00:00 2001 From: lanan Date: Thu, 13 Jun 2024 11:10:45 +0200 Subject: [PATCH 01/21] neue Models erstellt --- app/core/admin.py | 8 ++++++-- app/core/models.py | 18 ++++++++++++++++-- 2 files changed, 22 insertions(+), 4 deletions(-) diff --git a/app/core/admin.py b/app/core/admin.py index 9ecfbf3..955d83d 100644 --- a/app/core/admin.py +++ b/app/core/admin.py @@ -1,6 +1,10 @@ from django.contrib import admin -from core.models import Sample +from core.models import UserIDList +from core.models import Answers + + +admin.site.register(UserIDList) +admin.site.register(Answers) -admin.site.register(Sample) diff --git a/app/core/models.py b/app/core/models.py index 890c13e..f3fa86a 100644 --- a/app/core/models.py +++ b/app/core/models.py @@ -1,5 +1,19 @@ from django.db import models -class Sample(models.Model): - attachment = models.FileField() + + +class UserIDList(models.Model): + created_at = models.DateTimeField(auto_now_add=True) + updated_at = models.DateTimeField(auto_now=True) + userid = models.CharField(max_length=200) +def __str__(self): + return self.userid + + +class Answers(models.Model): + userid = models.ForeignKey(UserIDList, on_delete=models.CASCADE) + question_type_id = models.PositiveIntegerField(default=1) + data = models.JSONField(default=list,null=True,blank=True) + def __str__(self): + return self.userid.userid From 19f3256331043e9e089bf4b00016735b01123e2a Mon Sep 17 00:00:00 2001 From: lanan Date: Mon, 17 Jun 2024 14:30:11 +0200 Subject: [PATCH 02/21] =?UTF-8?q?HTTP=20requests=20funktionieren,=20Objekt?= =?UTF-8?q?e=20sind=20aufrufbar=20und=20=C3=A4nderbar?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/app/settings.py | 4 +- app/app/urls.py | 3 +- app/core/admin.py | 7 ++- app/core/migrations/0001_initial.py | 18 ++++++-- app/core/models.py | 17 ++++++- app/core/serializers.py | 15 +++++++ app/core/urls.py | 12 +++++ app/core/views.py | 70 ++++++++++++++++++++++++++++- 8 files changed, 135 insertions(+), 11 deletions(-) create mode 100644 app/core/serializers.py create mode 100644 app/core/urls.py diff --git a/app/app/settings.py b/app/app/settings.py index 371a0ba..0d27540 100644 --- a/app/app/settings.py +++ b/app/app/settings.py @@ -82,9 +82,9 @@ DATABASES = { 'default': { - 'ENGINE': 'django.db.backends.postgresql', + 'ENGINE': 'django.db.backends.sqlite3', 'HOST': os.environ.get('DB_HOST'), - 'NAME': os.environ.get('DB_NAME'), + 'NAME': BASE_DIR /'data'/ 'db.sqlite3', 'USER': os.environ.get('DB_USER'), 'PASSWORD': os.environ.get('DB_PASS'), } diff --git a/app/app/urls.py b/app/app/urls.py index ce406a7..e1e1579 100644 --- a/app/app/urls.py +++ b/app/app/urls.py @@ -14,12 +14,13 @@ 2. Add a URL to urlpatterns: path('blog/', include('blog.urls')) """ from django.contrib import admin -from django.urls import path +from django.urls import path, include from django.conf.urls.static import static from django.conf import settings urlpatterns = [ path('admin/', admin.site.urls), + path('', include('core.urls')) ] if settings.DEBUG: diff --git a/app/core/admin.py b/app/core/admin.py index 9ecfbf3..252216a 100644 --- a/app/core/admin.py +++ b/app/core/admin.py @@ -1,6 +1,9 @@ from django.contrib import admin -from core.models import Sample +from core.models import UserIDList +from core.models import Answers + +admin.site.register(UserIDList) +admin.site.register(Answers) -admin.site.register(Sample) diff --git a/app/core/migrations/0001_initial.py b/app/core/migrations/0001_initial.py index 1b38125..6fea403 100644 --- a/app/core/migrations/0001_initial.py +++ b/app/core/migrations/0001_initial.py @@ -1,5 +1,6 @@ -# Generated by Django 3.2.3 on 2021-05-17 20:01 +# Generated by Django 5.0.6 on 2024-06-17 09:01 +import django.db.models.deletion from django.db import migrations, models @@ -12,10 +13,21 @@ class Migration(migrations.Migration): operations = [ migrations.CreateModel( - name='Sample', + name='UserIDList', fields=[ ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('attachment', models.FileField(upload_to='')), + ('created_at', models.DateTimeField(auto_now_add=True)), + ('updated_at', models.DateTimeField(auto_now=True)), + ('userid', models.CharField(max_length=200)), + ], + ), + migrations.CreateModel( + name='Answers', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('question_type_id', models.PositiveIntegerField(default=1)), + ('data', models.JSONField(blank=True, default=list, null=True)), + ('userid', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='core.useridlist')), ], ), ] diff --git a/app/core/models.py b/app/core/models.py index 890c13e..3f07ce1 100644 --- a/app/core/models.py +++ b/app/core/models.py @@ -1,5 +1,18 @@ from django.db import models -class Sample(models.Model): - attachment = models.FileField() +class UserIDList(models.Model): + created_at = models.DateTimeField(auto_now_add=True) + updated_at = models.DateTimeField(auto_now=True) + userid = models.CharField(max_length=200) +def __str__(self): + return self.userid + + +class Answers(models.Model): + userid = models.ForeignKey(UserIDList, on_delete=models.CASCADE) + question_type_id = models.PositiveIntegerField(default=1) + data = models.JSONField(default=list,null=True,blank=True) + def __str__(self): + return self.userid.userid + diff --git a/app/core/serializers.py b/app/core/serializers.py new file mode 100644 index 0000000..a1f4863 --- /dev/null +++ b/app/core/serializers.py @@ -0,0 +1,15 @@ +from rest_framework import serializers +from core.models import UserIDList +from core.models import Answers + +class UserIDListSerializer(serializers.ModelSerializer): + class Meta: + model=UserIDList + fields= ["created_at", "updated_at", "userid"] + + +class AnswersSerializer(serializers.ModelSerializer): + + class Meta: + model=Answers + fields= ["userid", "question_type_id","data"] \ No newline at end of file diff --git a/app/core/urls.py b/app/core/urls.py new file mode 100644 index 0000000..e9d0f93 --- /dev/null +++ b/app/core/urls.py @@ -0,0 +1,12 @@ + +from django.urls import path +from core.views import useridlist +from core.views import useridlist_detail +from core.views import answers +urlpatterns = [ + path('userid/', useridlist), + path('useriddetail/', useridlist_detail), + path('answers/', answers), + + +] \ No newline at end of file diff --git a/app/core/views.py b/app/core/views.py index 91ea44a..4786cd9 100644 --- a/app/core/views.py +++ b/app/core/views.py @@ -1,3 +1,71 @@ from django.shortcuts import render - +from django.http import HttpResponse, JsonResponse +from rest_framework.parsers import JSONParser +from core.models import UserIDList +from core.models import Answers +from core.serializers import UserIDListSerializer +from core.serializers import AnswersSerializer +from django.views.decorators.csrf import csrf_exempt # Create your views here. +@csrf_exempt +def useridlist(request): + + if request.method=='GET': + users=UserIDList.objects.all() + print(users) # Debug-Ausgabe der QuerySet-Objekte + serializer=UserIDListSerializer(users, many=True) + print(serializer.data) # Debug-Ausgabe der serialisierten Daten + return JsonResponse(serializer.data, safe=False) + + elif request.method=='POST': + data=JSONParser().parse(request) + serializer=UserIDListSerializer(data=data) + + if serializer.is_valid(): + serializer.save() + return JsonResponse(serializer.data, status=201) + return JsonResponse(serializer.errors, status=404) + + +@csrf_exempt +def answers(request): + + if request.method=='GET': + answers=Answers.objects.all() + print(answers) # Debug-Ausgabe der QuerySet-Objekte + serializer=AnswersSerializer(answers, many=True) + print(serializer.data) # Debug-Ausgabe der serialisierten Daten + return JsonResponse(serializer.data, safe=False) + + elif request.method=='POST': + data=JSONParser().parse(request) + serializer=AnswersSerializer(data=data) + + if serializer.is_valid(): + serializer.save() + return JsonResponse(serializer.data, status=201) + return JsonResponse(serializer.errors, status=404) + + +@csrf_exempt +def useridlist_detail(request, pk): + try: + id=UserIDList.objects.get(pk=pk) + except UserIDList.DoesNotExist: + return HttpResponse(status=404) + + if request.method=='GET': + serializer=UserIDListSerializer(id) + return JsonResponse(serializer.data) + + elif request.method=='PUT': + data=JSONParser().parse(request) + serializer=UserIDListSerializer(id,dat=data) + if serializer.is_valid(): + serializer.save() + return JsonResponse(serializer.data) + return JsonResponse(serializer.errors, status=400) + + elif request.method=='DELETE': + id.delete() + return HttpResponse(status=204) \ No newline at end of file From f237526f5e673b01553de338dae9e8b1d219c6de Mon Sep 17 00:00:00 2001 From: lanan Date: Mon, 17 Jun 2024 15:50:41 +0200 Subject: [PATCH 03/21] =?UTF-8?q?API=20views=20erstellt=20f=C3=BCr=20useri?= =?UTF-8?q?d=20und=20answers?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/app/settings.py | 1 + app/core/urls.py | 16 ++++- app/core/views.py | 153 ++++++++++++++++++++++++++++++++++++++------ 3 files changed, 147 insertions(+), 23 deletions(-) diff --git a/app/app/settings.py b/app/app/settings.py index 0d27540..6b4712c 100644 --- a/app/app/settings.py +++ b/app/app/settings.py @@ -44,6 +44,7 @@ 'django.contrib.messages', 'django.contrib.staticfiles', 'core', + 'rest_framework' ] MIDDLEWARE = [ diff --git a/app/core/urls.py b/app/core/urls.py index e9d0f93..559883e 100644 --- a/app/core/urls.py +++ b/app/core/urls.py @@ -3,10 +3,20 @@ from core.views import useridlist from core.views import useridlist_detail from core.views import answers +from core.views import answers_detail +from core.views import UserIDListAPIView +from core.views import UserIDListDetailsAPIView +from core.views import AnswersAPIView +from core.views import AnswersDetailsAPIView urlpatterns = [ - path('userid/', useridlist), - path('useriddetail/', useridlist_detail), - path('answers/', answers), + # path('userid/', useridlist), + path('userid/', UserIDListAPIView.as_view()), + #path('useriddetail/', useridlist_detail), + path('useriddetail/', UserIDListDetailsAPIView.as_view()), + #path('answers/', answers), + path('answers/', AnswersAPIView.as_view()), + # path('answersdetail/', answers_detail), + path('answersdetail/', AnswersDetailsAPIView.as_view()), ] \ No newline at end of file diff --git a/app/core/views.py b/app/core/views.py index 4786cd9..8074b0d 100644 --- a/app/core/views.py +++ b/app/core/views.py @@ -6,8 +6,98 @@ from core.serializers import UserIDListSerializer from core.serializers import AnswersSerializer from django.views.decorators.csrf import csrf_exempt +from rest_framework.decorators import api_view +from rest_framework.response import Response +from rest_framework import status +from rest_framework.views import APIView # Create your views here. -@csrf_exempt + + +class UserIDListAPIView(APIView): + + def get(self, request): + users=UserIDList.objects.all() + serializer=UserIDListSerializer(users, many=True) + return Response(serializer.data) + + def post(self, request): + serializer=UserIDListSerializer(data=request.data) + + if serializer.is_valid(): + serializer.save() + return Response(serializer.data, status=status.HTTP_201_CREATED) + return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) + + + +class UserIDListDetailsAPIView(APIView): + def get_object(self,id): + try: + return UserIDList.objects.get(id=id) + except UserIDList.DoesNotExist: + return HttpResponse(status=status.HTTP_404_NOT_FOUND) + + def get(self, request, id): + id=self.get_object(id) + serializer=UserIDListSerializer(id) + return Response(serializer.data) + + def put(self, request, id): + id=self.get_object(id) + serializer=UserIDListSerializer(id,data=request.data) + + if serializer.is_valid(): + serializer.save() + return Response(serializer.data) + return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) + + def delete(self, request, id): + id=self.get_object(id) + id.delete() + return Response(status=status.HTTP_204_NO_CONTENT) + +class AnswersAPIView(APIView): + + def get(self, request): + answers=Answers.objects.all() + serializer=AnswersSerializer(answers, many=True) + return Response(serializer.data) + + def post(self, request): + serializer=AnswersSerializer(data=request.data) + + if serializer.is_valid(): + serializer.save() + return Response(serializer.data, status=status.HTTP_201_CREATED) + return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) + +class AnswersDetailsAPIView(APIView): + def get_object(self, id): + try: + return Answers.objects.get(id=id) + except Answers.DoesNotExist: + raise Http404 + + def get(self, request, id): + answer = self.get_object(id) + serializer = AnswersSerializer(answer) + return Response(serializer.data) + + def put(self, request, id): + answer = self.get_object(id) + serializer = AnswersSerializer(answer, data=request.data) + + if serializer.is_valid(): + serializer.save() + return Response(serializer.data) + return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) + + def delete(self, request, id): + answer = self.get_object(id) + answer.delete() + return Response(status=status.HTTP_204_NO_CONTENT) + +@api_view(['GET', 'POST']) def useridlist(request): if request.method=='GET': @@ -15,19 +105,19 @@ def useridlist(request): print(users) # Debug-Ausgabe der QuerySet-Objekte serializer=UserIDListSerializer(users, many=True) print(serializer.data) # Debug-Ausgabe der serialisierten Daten - return JsonResponse(serializer.data, safe=False) + return Response(serializer.data) elif request.method=='POST': - data=JSONParser().parse(request) - serializer=UserIDListSerializer(data=data) + + serializer=UserIDListSerializer(data=request.data) if serializer.is_valid(): serializer.save() - return JsonResponse(serializer.data, status=201) - return JsonResponse(serializer.errors, status=404) + return Response(serializer.data, status=status.HTTP_201_CREATED) + return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) -@csrf_exempt +@api_view(['GET', 'POST']) def answers(request): if request.method=='GET': @@ -35,37 +125,60 @@ def answers(request): print(answers) # Debug-Ausgabe der QuerySet-Objekte serializer=AnswersSerializer(answers, many=True) print(serializer.data) # Debug-Ausgabe der serialisierten Daten - return JsonResponse(serializer.data, safe=False) + return Response(serializer.data) elif request.method=='POST': - data=JSONParser().parse(request) - serializer=AnswersSerializer(data=data) + + serializer=AnswersSerializer(data=request.data) if serializer.is_valid(): serializer.save() - return JsonResponse(serializer.data, status=201) - return JsonResponse(serializer.errors, status=404) + return Response(serializer.data, status=status.HTTP_201_CREATED) + return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) -@csrf_exempt +@api_view(['GET', 'POST', 'DELETE']) def useridlist_detail(request, pk): try: id=UserIDList.objects.get(pk=pk) except UserIDList.DoesNotExist: - return HttpResponse(status=404) + return HttpResponse(status=status.HTTP_404_NOT_FOUND) if request.method=='GET': serializer=UserIDListSerializer(id) - return JsonResponse(serializer.data) + return Response(serializer.data) elif request.method=='PUT': - data=JSONParser().parse(request) - serializer=UserIDListSerializer(id,dat=data) + + serializer=UserIDListSerializer(id,data=request.data) if serializer.is_valid(): serializer.save() - return JsonResponse(serializer.data) - return JsonResponse(serializer.errors, status=400) + return Response(serializer.data) + return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) elif request.method=='DELETE': id.delete() - return HttpResponse(status=204) \ No newline at end of file + return Response(status=status.HTTP_204_NO_CONTENT) + +@api_view(['GET', 'POST', 'DELETE']) +def answers_detail(request, pk): + try: + answer=Answers.objects.get(pk=pk) + except Answers.DoesNotExist: + return HttpResponse(status=status.HTTP_404_NOT_FOUND) + + if request.method=='GET': + serializer=AnswersSerializer(answer) + return Response(serializer.data) + + elif request.method=='PUT': + + serializer=AnswersSerializer(answer,data=request.data) + if serializer.is_valid(): + serializer.save() + return Response(serializer.data) + return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) + + elif request.method=='DELETE': + answer.delete() + return Response(status=status.HTTP_204_NO_CONTENT) From e016417fc8b5d8629f541ddf514782fd2601d78e Mon Sep 17 00:00:00 2001 From: lanan Date: Tue, 18 Jun 2024 11:47:51 +0200 Subject: [PATCH 04/21] =?UTF-8?q?user=5Fid=20Funktion=20mit=20uuid=20hinzu?= =?UTF-8?q?gef=C3=BCgt,=20um=20zu=20testen=20siehe=20Kommentare=20dadr?= =?UTF-8?q?=C3=BCber?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/core/urls.py | 17 +++++++++-------- app/core/views.py | 34 ++++++++++++++++++++++++++++++---- 2 files changed, 39 insertions(+), 12 deletions(-) diff --git a/app/core/urls.py b/app/core/urls.py index 559883e..226ee99 100644 --- a/app/core/urls.py +++ b/app/core/urls.py @@ -8,15 +8,16 @@ from core.views import UserIDListDetailsAPIView from core.views import AnswersAPIView from core.views import AnswersDetailsAPIView + urlpatterns = [ - # path('userid/', useridlist), - path('userid/', UserIDListAPIView.as_view()), - #path('useriddetail/', useridlist_detail), - path('useriddetail/', UserIDListDetailsAPIView.as_view()), - #path('answers/', answers), - path('answers/', AnswersAPIView.as_view()), - # path('answersdetail/', answers_detail), - path('answersdetail/', AnswersDetailsAPIView.as_view()), + path('userid/', useridlist), + # path('userid/', UserIDListAPIView.as_view()), + #path('useriddetail/', useridlist_detail), + path('useriddetail/', UserIDListDetailsAPIView.as_view()), + #path('answers/', answers), + path('answers/', AnswersAPIView.as_view()), + #path('answersdetail/', answers_detail), + path('answersdetail/', AnswersDetailsAPIView.as_view()), ] \ No newline at end of file diff --git a/app/core/views.py b/app/core/views.py index 8074b0d..d2c7844 100644 --- a/app/core/views.py +++ b/app/core/views.py @@ -1,17 +1,43 @@ from django.shortcuts import render -from django.http import HttpResponse, JsonResponse -from rest_framework.parsers import JSONParser +from django.http import HttpResponse from core.models import UserIDList from core.models import Answers from core.serializers import UserIDListSerializer from core.serializers import AnswersSerializer -from django.views.decorators.csrf import csrf_exempt from rest_framework.decorators import api_view from rest_framework.response import Response from rest_framework import status from rest_framework.views import APIView +import uuid # Create your views here. +#Funktion zum Abrufen oder Erstellen einer UserID +#zum testen: +#$python manage.py shell +#from core.models import UserIDList +#from core.views import user_id +# Teste das Abrufen einer bestehenden UserID +#user = user_id(action="getDBObject", userID="efd69e9c-3945-4885-9a06-c9216efec82b") +#print(user) # Sollte None zurückgeben, wenn die UserID nicht existiert +# Erstelle eine neue UserID +#new_user_id = user_id(action="create") +#print(new_user_id) # Sollte eine neue UUID zurückgeben +# Teste das Abrufen der gerade erstellten UserID +#user = user_id(action="getDBObject", userID=new_user_id) +#print(user) # Sollte das UserIDList Objekt mit der neuen UUID zurückgeben + + +def user_id(action, userID="efd69e9c-3945-4885-9a06-c9216efec82b"): + if action == "getDBObject": + if UserIDList.objects.filter(userid=userID).exists(): + return UserIDList.objects.get(userid=userID) + else: + return None + elif action == "create": + userIDValue = str(uuid.uuid4()) + UserIDList.objects.create(userid=userIDValue) + return userIDValue + return None class UserIDListAPIView(APIView): @@ -76,7 +102,7 @@ def get_object(self, id): try: return Answers.objects.get(id=id) except Answers.DoesNotExist: - raise Http404 + return HttpResponse(status=status.HTTP_404_NOT_FOUND) def get(self, request, id): answer = self.get_object(id) From 90730c6317ebb11e312247318cacf04a8ba4d607 Mon Sep 17 00:00:00 2001 From: lanan Date: Wed, 19 Jun 2024 11:33:34 +0200 Subject: [PATCH 05/21] =?UTF-8?q?in=20settings.py=20zur=C3=BCck=20auf=20po?= =?UTF-8?q?stgresql=20gesetzt=20bei=20DATABASES?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/app/settings.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/app/settings.py b/app/app/settings.py index 6b4712c..e1788a2 100644 --- a/app/app/settings.py +++ b/app/app/settings.py @@ -83,9 +83,9 @@ DATABASES = { 'default': { - 'ENGINE': 'django.db.backends.sqlite3', + 'ENGINE': 'django.db.backends.postgresql', 'HOST': os.environ.get('DB_HOST'), - 'NAME': BASE_DIR /'data'/ 'db.sqlite3', + 'NAME': os.environ.get('DB_NAME'), 'USER': os.environ.get('DB_USER'), 'PASSWORD': os.environ.get('DB_PASS'), } From cc387381c5489b55ba8cfdfe2678d7be755130a4 Mon Sep 17 00:00:00 2001 From: GeorgiosK78 Date: Wed, 19 Jun 2024 11:59:20 +0200 Subject: [PATCH 06/21] =?UTF-8?q?peters=20datei=20hinzugef=C3=BCgt?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/core/x_data_utils.py | 414 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 414 insertions(+) create mode 100644 app/core/x_data_utils.py diff --git a/app/core/x_data_utils.py b/app/core/x_data_utils.py new file mode 100644 index 0000000..b5616b0 --- /dev/null +++ b/app/core/x_data_utils.py @@ -0,0 +1,414 @@ +# pip install +## Django>=3.2.3,<3.3 +## Markdown==3.6 + +from django.db import models +from core.models import UserIDList, Answers #core.models could change e.g. api.models +#from markdown import markdown # type: ignore +import uuid + +# copy to models.py the following lines and uncomment those lines +################ models.py #################### +# class UserIDList(models.Model): +# created_at = models.DateTimeField(auto_now_add=True) +# updated_at = models.DateTimeField(auto_now=True) +# userid = models.CharField(max_length=200) +# def __str__(self): +# return self.userid + +# class Answers(models.Model): +# userid = models.ForeignKey(UserIDList, on_delete=models.CASCADE) +# question_type_id = models.PositiveIntegerField(default=1) +# data = models.JSONField(default=list,null=True,blank=True) +# def __str__(self): +# return self.userid.userid +################## models.py end ##################### + +markdown_flag = True + +### main function to set DB-data ###################### +# http://127.0.0.1:8000/api/question/1/8/ +def answer_post_view(question_type_id, question_id, action='getDBObject', userID="efd69e9c-3945-4885-9a06-c9216efec82b", answer=""): + obj, config = get_interview_config_db({}, question_type_id, question_id, action=action, userID=userID) + set_answer(obj, config, answer) + return obj, config + +def set_answer(object, config, answer): + object.data[config['answer_label']] = answer + object.save() + +### main function to get DB-data ###################### +# http://127.0.0.1:8000/api/question/1/8/ +def get_interview_config_db(request, question_type_id, question_id, action='getDBObject', userID="efd69e9c-3945-4885-9a06-c9216efec82b"): + # API-Access: use action='getDBObject' and the specific userID + # otherwise use standard + userid = user_id(action, request, userID=userID) + if not userid: + return None, None + answer = Answers.objects.filter(userid=userid, question_type_id=question_type_id) + if not answer.exists(): + interview_config = get_all_interview_data_db(question_type_id) + Answers.objects.create(userid=userid, question_type_id=question_type_id, data={'interview_config': interview_config}) + object = Answers.objects.get(userid=userid, question_type_id=question_type_id) + config = get_interview_config(question_type_id, question_id, object=object) + return object, config + +def user_id(action, request=[], userID="efd69e9c-3945-4885-9a06-c9216efec82b"): + if action =="getDBObject": + if UserIDList.objects.filter(userid = userID).exists(): + return UserIDList.objects.get(userid=userID) + else: + return None + elif action == "create": + userIDValue = str(uuid.uuid4()) + UserIDList.objects.create(userid=userIDValue) + return userIDValue + return None + +def get_interview_config(question_type_id, question_id, object=None): + if not question_type_id: + question_type_id = 1 + if not question_id: + question_id = 1 + + if object: + interview_config = object.data['interview_config'] + else: + interview_config = get_all_interview_data_db(question_type_id) + + start_page = interview_config['start_page'] + end_page = interview_config['end_page'] + order = interview_config['order'] + + real_num_of_questions = interview_config['real_num_of_questions'] + number_of_questions = interview_config['number_of_questions'] + institution = interview_config['institution'] + type = interview_config['type'] + + real_question_nr = interview_config['real_question_nrs'][question_id-1] # starts with zero + answer_label = order[question_id-1] # starts with zero + io_type = interview_config[answer_label]['io_type'] + question_title = interview_config[answer_label]['question_title'] + question_title_description = interview_config[answer_label]['question_title_description'] + answer_template = interview_config[answer_label]['answer_template'] + if io_type == "selectable" and real_question_nr: #sort only questions analysis are ordered by fitting + all_elements = sorted(interview_config[answer_label]['all_elements']) + else: + all_elements = interview_config[answer_label]['all_elements'] + + # set properties which are not existent + props_string = ["summary", "prompt_type", "prompt_type_ext", "add_detail", "source"] + props_dict = ["branches", "generate"] + props_list = [] + interview_config = set_missing_props(interview_config, answer_label, + props_string=props_string, + props_dict=props_dict, props_list=props_list) + + summary = interview_config[answer_label]['summary'] + prompt_type = interview_config[answer_label]['prompt_type'] + prompt_type_ext = interview_config[answer_label]['prompt_type_ext'] + add_detail = interview_config[answer_label]['add_detail'] + branches = interview_config[answer_label]['branches'] + source = interview_config[answer_label]['source'] + generate = get_generate_context_prop(interview_config[answer_label]) + menue_pages = interview_config['menue_pages'] + #print(f"{generate=}") + + selected_elements = [] + if io_type in ['numerical', 'editable','generated']: + selected_elements = "" + if object: + if answer_label in object.data.keys(): + selected_elements = object.data[answer_label] + + question_id_prev, question_id_next = get_next_prev_id(question_id, order, source, branches, + selected_elements) + + io_type_target="generated" + # io_type_target and question not yet generated filters all ids + ids = get_question_id_of_io_type(interview_config, io_type=io_type_target) + next_io_type = "" + prev_io_type = "" + + if question_id_next in ids: + next_io_type = io_type_target + + if question_id_prev in ids: + prev_io_type = io_type_target + + # set language + #if interview_config['lang'] != get_language(): + # activate(interview_config['lang']) + + config = {'institution':institution, 'type': type, 'question_type_id': question_type_id, 'question_id': question_id, + 'question_id_prev': question_id_prev, 'question_id_next': question_id_next, 'prompt_type': prompt_type, + 'answer_label': answer_label, 'all_elements': all_elements, 'answer_template': answer_template ,'number_of_questions': number_of_questions, + 'io_type': io_type, 'question_title': question_title, 'question_title_description': question_title_description, + 'start_page': start_page, 'end_page':end_page, 'next_io_type': next_io_type, 'prev_io_type': prev_io_type, "summary": summary, + "real_question_nr": real_question_nr, "real_num_of_questions": real_num_of_questions, + 'question_title_exists': (question_title != ""), 'prompt_type_ext': prompt_type_ext, 'branches': branches, + 'add_detail': add_detail, 'order_length': len(order), 'selected_elements': selected_elements, 'generate': generate, 'menue_pages': menue_pages + } + # 'generate' is a dictionary + # 'generate': {'title':'.....', 'title_description':'........', 'qa':[{'question':'......', 'answer',''}, {'question':'......', 'answer',''} ], + # 'body':'......','add_detail':'.....'} + return config + +def set_missing_props(config, answer_label, props_string=[], props_dict=[], props_list=[]): + for prop in props_dict: + if prop not in config[answer_label].keys(): + config[answer_label][prop] = {} + for prop in props_string: + if prop not in config[answer_label].keys(): + config[answer_label][prop] = "" + for prop in props_list: + if prop not in config[answer_label].keys(): + config[answer_label][prop] = [] + return config + +def get_next_prev_id(question_id, order, source, branches, selected_elements): + question_id_prev = question_id-1 + question_id_next = question_id+1 + + for dest in branches.keys(): + if branches[dest] == len(selected_elements): #we distiguish only the number of selected_elements + question_id_next = index_in_list(order, dest)+1 + if source != "": + question_id_prev = index_in_list(order, source)+1 + return question_id_prev, question_id_next + +def index_in_list(myList, element): + if element in myList: + return myList.index(element) + else: + return None + +def get_question_id_of_io_type(interview_config, io_type=""): + question_ids=[] + order = interview_config['order'] + for question_id in range(1, len(order)+1): + answer_label = order[question_id-1] + io_type_this = interview_config[answer_label]['io_type'] + if io_type == io_type_this and interview_config[answer_label]['question_title'] == "": #not yet generated + question_ids.append(question_id) + return question_ids + +def set_initial_generate_prop(config, answer_label, llm_answer=""): + # prepare data + if config[answer_label]['io_type'] != "selectable": + programs, fits = get_programs(config[answer_label]['all_elements']) + else: + programs = ["",""] + fits = ["",""] + ncs = get_ncs(config, answer_label, programs) + data_keys = {"": programs[0], "": programs[1], "": fits[0], "":fits[1], "":ncs[0], "":ncs[1]} + title = replace_key_words(config[answer_label]['question_title'], data_keys, c="") + title_description = replace_key_words(config[answer_label]['question_title_description'], data_keys, c="") + add_detail = replace_key_words(config[answer_label]['add_detail'], data_keys, c="") + if not isinstance(llm_answer, dict): + if markdown_flag: + body = llm_answer + else: + body = markdown(llm_answer, extensions=['tables']) + #body = body.replace("",'
') + else: + body = "" + + prop = get_prop(programs) + if prop not in config[answer_label]['generate']: + config[answer_label]['generate'][prop]={} + config[answer_label]['generate'][prop] = {"title": title, "title_description": title_description, + "add_detail": add_detail, 'llm_answer':llm_answer, + "body": body, "query": "", "qa": []} + return config + +def replace_key_words(mystring, data_keys, c = '"'): + for key in data_keys.keys(): + mystring = mystring.replace(key, c+data_keys[key]+c) + return mystring + +def get_ncs(config, answer_label, programs): + ncs=["",""] + source = config[answer_label]['source'] + if source != "": + source_answer = config[source]['generate']['all']['llm_answer'] + for idx, key in zip(range(len(programs)), programs): + if key != "": + if 'NC' in source_answer[key]: + ncs[idx] = source_answer[key]['NC'] + + return ncs + +def get_generate_context_prop(context): + if context['io_type'] == "text_edit": + programs, fits = get_programs(context['all_elements']) + prop = get_prop(programs) + else: + prop = 'all' + if prop not in context['generate']: + context['generate'][prop] = {} + return context['generate'][prop] + +def get_prop(programs): + prop = "" + for program in programs: + if prop != "": + if program != "": + prop += f"_{program}" + else: + if program != "": + prop += program + if prop == "": + prop = "all" + return prop + +def get_programs(my_list=['Management, Economics and Social Science: Gut','Volkswirtschaft: Gut']): + # return always two programs and the resp. fits + programs = ["", ""] + fits = ["", ""] + my_list = sorted(my_list) + for idx, item in zip(range(len(my_list)),my_list): + pos = item.rfind(':') + if pos > -1: + program = item[0:pos].strip() + fit = item[pos+1::].strip() + else: + program = item + fit = "" + programs[idx] = program + fits[idx] = fit + return programs, fits + +def get_all_interview_data_db(question_type_id): + data={"A1": ["Biologie", "Chemie"], + "A2": ["KI ausprobieren", "Mathematische Modelle entwickeln", "Mathe anwenden", "Schwere Matheprobleme lösen", "Programmieren"], + "A3": [], + "A4": "1.0", + "A5": "Manager short-term and ceo long-term", + "A6": "Ich bin ein Problemlöser", + "A7": ["Algorithmen", "Datenanalyse", "IT Projektmanagement", "Start-Up Gründung"], + "A8": ["Auf Englisch und Deutsch studieren"], + "A9": "Ja gerne", + "P1": [], + "S1": [], + "ANALYSIS1": [], + "interview_config": { + "lang": "de", + "type": "bachelor", + "order": ["S1", "A1", "A2", "A3", "A4", "A5", "A6", "P1", "A7", "A8", "A9", "ANALYSIS1", "ANALYSIS2", "ANALYSIS3"], + "end_page": "home", + "start_page": "start", + "institution": "WiSo Fakultät an der Universität zu Köln", + "menue_pages": [{"id": 2, "no": 1, "title": "Welche Fächer haben dich in der Schule interessiert?"}, {"id": 3, "no": 2, "title": "Was macht dir Spaß?"}, {"id": 4, "no": 3, "title": "Was magst du nicht?"}, {"id": 5, "no": 4, "title": "Wo liegt dein (voraussichtlicher) Abiturnotendurchschnitt?"}, {"id": 6, "no": 5, "title": "Wie siehst du deine berufliche Zukunft?"}, {"id": 7, "no": 6, "title": "Gibt es noch etwas, das ich über dich wissen sollte?"}, {"id": 9, "no": 7, "title": "Über welche Themenfelder möchtest du in deinem Studium mehr erfahren?"}, {"id": 10, "no": 8, "title": "Was ist dir im Studium wichtig?"}, {"id": 11, "no": 9, "title": "'Individual Generated Question'"}, {"id": 12, "no": None, "title": "Deine passenden Studiengänge"}], + "question_items": ["A1", "A2", "A3", "A4", "A5", "A6", "A7", "A8", "A9"], + "real_question_nrs": [None, 1, 2, 3, 4, 5, 6, None, 7, 8, 9, None, None, None], + "number_of_questions": 11, + "real_num_of_questions": 9, + "A1": {"source": "", "io_type": "selectable", "summary": "", "branches": {}, + "generate": {"all": {}}, "add_detail": "", "prompt_type": "", + "all_elements": ["Mathe", "Kunst", "Physik", "Sport", "Philosophie", "Englisch", "Religion", "Technologie", "Musik", "Biologie", "Wirtschaft", "Chemie", "Soziales", "Geschichte", "Geographie", "Sprachen", "Deutsch", "Pädagogik", "Recht", "Psychologie", "Ernährung", "Informatik"], + "question_title": "Welche Fächer haben dich in der Schule interessiert?", "answer_template": "Die folgenden Fächer haben mich in der Schule interessiert: ", "prompt_type_ext": "", "question_title_description": ""}, + "A2": {"source": "", "io_type": "selectable", "summary": "", "branches": {}, + "generate": {"all": {}}, "add_detail": "", "prompt_type": "", + "all_elements": ["Mathe anwenden", "Schwere Matheprobleme lösen", "Kurse geben", "Ethische Fragen diskutieren", "Anderen etwas beibringen", "Projekte leiten", "Präsentieren", "Umweltthemen diskutieren", "Unternehmen verstehen", "Theorien verstehen", "Soziale Probleme diskutieren", "Programmieren", "Events organisieren", "Aktienmärkte verstehen", "Wirtschaftspolitik verstehen", "Musik komponieren", "Literatur interpretieren", "Fremdsprachen sprechen", "Instrumente spielen", "Kulturen erforschen", "Soziale Interaktionen verstehen", "Geschichtliche Entwicklungen analysieren", "Philosophische Theorien verstehen", "KI ausprobieren", "Menschen unterstützen", "Gesetzgebung verstehen", "Chemische Experimente durchführen", "Mathematische Modelle entwickeln", "Biologische Prozesse erforschen", "Verhaltensmuster analysieren", "Anatomie verstehen", "Argumentationsstrategien entwickeln", "Zusammenhänge im Körper untersuchen", "Naturwissenschaftliche Zusammenhänge analysieren"], + "question_title": "Was macht dir Spaß?", "answer_template": "Ich mag die folgenden Aktivitäten: ", + "prompt_type_ext": "", + "question_title_description": ""}, + "A3": {"source": "", "io_type": "selectable", "summary": "", "branches": {}, + "generate": {"all": {}}, "add_detail": "", "prompt_type": "", + "all_elements": ["Mathe anwenden", "Schwere Matheprobleme lösen", "Kurse geben", "Ethische Fragen diskutieren", "Anderen etwas beibringen", "Projekte leiten", "Präsentieren", "Umweltthemen diskutieren", "Unternehmen verstehen", "Theorien verstehen", "Soziale Probleme diskutieren", "Programmieren", "Events organisieren", "Aktienmärkte verstehen", "Wirtschaftspolitik verstehen", "Musik komponieren", "Literatur interpretieren", "Fremdsprachen sprechen", "Instrumente spielen", "Kulturen erforschen", "Soziale Interaktionen verstehen", "Geschichtliche Entwicklungen analysieren", "Philosophische Theorien verstehen", "KI ausprobieren", "Menschen unterstützen", "Gesetzgebung verstehen", "Chemische Experimente durchführen", "Mathematische Modelle entwickeln", "Biologische Prozesse erforschen", "Verhaltensmuster analysieren", "Anatomie verstehen", "Argumentationsstrategien entwickeln", "Zusammenhänge im Körper untersuchen", "Naturwissenschaftliche Zusammenhänge analysieren"], + "question_title": "Was magst du nicht?", "answer_template": "Folgende Aktivitäten lehne ich ab: ", "prompt_type_ext": "", "question_title_description": ""}, + "A4": {"source": "", "io_type": "numerical", "summary": "", "branches": {}, + "generate": {"all": {}}, "add_detail": "", "prompt_type": "", + "all_elements": ["0", "1.0", "1.1", "1.2", "1.3", "1.4", "1.5", "1.6", "1.7", "1.8", "1.9", "2.0", "2.1", "2.2", "2.3", "2.4", "2.5", "2.6", "2.7", "2.8", "2.9", "3.0", "3.1", "3.2", "3.3", "3.4", "3.5", "3.6", "3.7", "3.8", "3.9", "4.0"], + "question_title": "Wo liegt dein (voraussichtlicher) Abiturnotendurchschnitt?", "answer_template": "Mein Abiturnotendurchschnitt = ", "prompt_type_ext": "", + "question_title_description": "Bereich zwischen 1.0 und 4.0?"}, + "A5": {"source": "", "io_type": "editable", "summary": "", "branches": {}, + "generate": {"all": {}}, "add_detail": "", "prompt_type": "", + "all_elements": [], + "question_title": "Wie siehst du deine berufliche Zukunft?", "answer_template": "", "prompt_type_ext": "", + "question_title_description": "Sag mir bitte, ob du einen konkreten Berufswunsch hast, ob dich gewisse Branchen interessieren und ob du konkrete Arbeitgeber im Blick hast. Oder möchtest du ein Startup gründen? Je mehr ich über deine Berufsziele weiß, desto besser kann ich dich beraten!"}, + "A6": {"source": "", "io_type": "editable", "summary": "", "branches": {}, + "generate": {"all": {}}, "add_detail": "", "prompt_type": "", + "all_elements": [], + "question_title": "Gibt es noch etwas, das ich über dich wissen sollte?", "answer_template": "", "prompt_type_ext": "", + "question_title_description": "Gibt es weitere Dinge, die mir helfen, den passenden Studiengang für dich zu finden. Das könnte z.B. deine Stärken und Schwächen oder Interessen außerhalb der Schule sein."}, + "A7": {"source": "", "io_type": "selectable", "summary": "", "branches": {}, + "generate": {"all": {}}, "add_detail": "", "prompt_type": "", + "all_elements": ["Datenanalyse", "Finanzmanagement", "Zivilrecht", "Marketingstrategien", "Verhaltensökonomie", "Internationale Wirtschaft", "Nachhaltigkeit & Umwelt", "Start-Up Gründung", "Sozialpsychologie", "Genetik", "IT Projektmanagement", "Algorithmen", "Strafrecht", "Gesundheitsmanagement", "Soziale Themen", "Unternehmensführung", "Literatur", "Geschichtsepochen", "Fremdsprachen", "Pädagogische Methodik", "Musikalische Strukturen", "Entwicklungspsychologie", "Medientheorie", "Spracherwerb", "Soziale Strukturen", "Umweltsysteme & Klima", "Materie und Energie", "Chemische Strukturen", "Medizinische Diagnostik", "Patientenversorgung", "Neurobiologie", "Molekularbiologie", "Internationales Recht und Handelsrecht", "Verhaltenspsychologie", "Soziale Interaktionen"], + "question_title": "Über welche Themenfelder möchtest du in deinem Studium mehr erfahren?", "answer_template": "Ich bin an folgenden Themenfeldern interessiert: ", "prompt_type_ext": "", + "question_title_description": ""}, + "A8": {"source": "", "io_type": "selectable", "summary": "", "branches": {}, + "generate": {"all": {}}, "add_detail": "", "prompt_type": "", + "all_elements": ["Auf Englisch studieren", "Auf Deutsch studieren", "Auf Englisch und Deutsch studieren", "Auslandssemester einlegen", "Kontakte zu Unternehmen knüpfen", "Projekte mit Unternehmen durchführen", "In Studierendenteams arbeiten", "in Schulen arbeiten", "Laborexperimente durchführen", "Forschungsprojekte", "Exkursionen", "Praktika", "Praxiserfahrung sammeln"], + "question_title": "Was ist dir im Studium wichtig?", "answer_template": "Mir ist folgendes wichtig: ", "prompt_type_ext": "", + "question_title_description": ""}, + "A9": {"source": "", "io_type": "generated", + "summary": "Du hast einen Abiturnotendurchschnitt von 1.0, interessierst dich für Biologie, Chemie, Algorithmen, Datenanalyse, IT Projektmanagement und Start-Up Gründung. Du magst KI ausprobieren, mathematische Modelle entwickeln, Mathe anwenden, schwere Matheprobleme lösen und programmieren. Du möchtest Manager und langfristig CEO werden und legst Wert auf ein Studium in Englisch und Deutsch.", "branches": {}, + "generate": {"all": {}}, "add_detail": "", "prompt_type": "generate_question", "all_elements": [], + "question_title": "Möchtest du in deinem Studium auch wirtschaftliche und betriebswirtschaftliche Aspekte vertiefen?", "answer_template": "", "prompt_type_ext": "", + "question_title_description": ""}, + "P1": {"source": "", "io_type": "pause", "summary": "", "branches": {}, + "generate": {"all": {}}, "add_detail": "", "prompt_type": "", + "all_elements": [], + "question_title": "Super, das war's schon mit dem ersten Teil!", "answer_template": "", "prompt_type_ext": "", + "question_title_description": "Jetzt kommen noch drei Fragen zu deinen Studienwünschen."}, + "S1": {"source": "", "io_type": "start", "summary": "", "branches": {}, + "generate": {"all": {}}, "add_detail": "", "prompt_type": "", + "all_elements": [], "question_title": "Ich stelle dir 9 Fragen \nüber dich und deine Studienwünsche.", "answer_template": "", "prompt_type_ext": "", + "question_title_description": "Los geht's mit sechs Fragen zu dir!"}, + "ANALYSIS1": { + "source": "", "io_type": "selectable", "summary": "", "branches": {"ANALYSIS2": 1, "ANALYSIS3": 2}, + "generate": {"all": { + "qa": [], "body": "", "query": "", + "title": "Deine passenden Studiengänge", "add_detail": "", + "llm_answer": {"Volkswirtschaft": {"NC": "2.5", "Fit": "Okay"}, + "Betriebswirtschaft": {"NC": "1.6", "Fit": "Gut"}, + "Gesundheitsökonomie": {"NC": "2.4", "Fit": "Eher nicht"}, + "Sozialwissenschaften": {"NC": "2.0", "Fit": "Eher nicht"}, + "Wirtschaftsinformatik": {"NC": "1.8", "Fit": "Sehr gut"}, + "Wirtschaftspädagogik": {"NC": "2.2", "Fit": "Eher nicht"}, + "Management, Economics and Social Sciences": {"NC": "1.0", "Fit": "Gut"} + }, + "title_description": "Wähle einen Studiengang und klicke auf 'Details', um mehr über den Fit zu erfahren. \nOder wähle 2 Studiengänge zum 'Vergleich' für dich wichtiger Kriterien aus." + } + }, + "add_detail": "", + "prompt_type": "institution_fitting", + "all_elements": ["Wirtschaftsinformatik: Sehr gut", "Management, Economics and Social Sciences: Gut", "Betriebswirtschaft: Gut", "Volkswirtschaft: Okay", "Gesundheitsökonomie: Eher nicht", "Sozialwissenschaften: Eher nicht", "Wirtschaftspädagogik: Eher nicht"], + "question_title": "Deine passenden Studiengänge", "answer_template": "", "prompt_type_ext": "", + "question_title_description": "Wähle einen Studiengang und klicke auf 'Details', um mehr über den Fit zu erfahren. \nOder wähle 2 Studiengänge zum 'Vergleich' für dich wichtiger Kriterien aus." + }, + "ANALYSIS2": { + "source": "ANALYSIS1", "io_type": "text_edit", "summary": "", "branches": {}, + "generate": {"Wirtschaftsinformatik": { + "qa": [], "body": "

Einschätzung: Sehr gut

\n

Deine Interessen an \"Algorithmen\", \"Datenanalyse\", \"IT Projektmanagement\" und \"Start-Up Gründung\" passen perfekt. \"Programmieren\" und \"Mathe anwenden\" sind zentrale Bestandteile. \"Auf Englisch und Deutsch studieren\" ist gegeben. Eventuell könnten technische Details herausfordernd sein.

", + "query": "", + "title": "Erläuterungen zum Studiengang: Wirtschaftsinformatik - Fit: Sehr gut", + "add_detail": "Der Studiengang Wirtschaftsinformatik hatte im letzten Jahr einen NC von 1.8. Der NC ist eines der Auswahlkriterien für dieses Programm und kann sich von Jahr zu Jahr ändern. Beachte: Wenn der Abiturnotendurchschnitt kleiner oder gleich dem NC-Wert ist, kannst du das Programm vermutlich studieren, wenn anders gegebenenfalls nicht. Ich habe mein Bestes gegeben, um deinen Fit gut einzuschätzen. Editiere gerne dein Profil über das Hauptmenü, wenn du mir mehr oder andere Informationen über dich geben möchtest, als ich habe. Du kannst mehr Details über Wirtschaftsinformatik erfahren. Dann gebe deine Fragen in die Eingabemaske ein. Um Wirtschaftsinformatik mit einem anderen Studiengang zu vergleichen, gehe zurück (' hatte im letzten Jahr einen NC von . Der NC ist eines der Auswahlkriterien für dieses Programm und kann sich von Jahr zu Jahr ändern. Beachte: Wenn der Abiturnotendurchschnitt kleiner oder gleich dem NC-Wert ist, kannst du das Programm vermutlich studieren, wenn anders gegebenenfalls nicht. Ich habe mein Bestes gegeben, um deinen Fit gut einzuschätzen. Editiere gerne dein Profil über das Hauptmenü, wenn du mir mehr oder andere Informationen über dich geben möchtest, als ich habe. Du kannst mehr Details über erfahren. Dann gebe deine Fragen in die Eingabemaske ein. Um mit einem anderen Studiengang zu vergleichen, gehe zurück (' - Fit: ", "answer_template": "", + "prompt_type_ext": "program_chat", + "question_title_description": "Du kannst diese Erläuterungen jederzeit erneut erzeugen - klicke 'generate again'. Oder stelle deine Fragen." + }, + "ANALYSIS3": { + "source": "ANALYSIS1", "io_type": "text_edit", "summary": "", "branches": {}, + "generate": {"Management, Economics and Social Sciences_Wirtschaftsinformatik": { + "qa": [], "body": "Hier ein Vergleich der beiden Programme anhand von Kriterien, die für dich relevant sein müssten.\n\n| Kriterium | Management, Economics and Social Sciences | Wirtschaftsinformatik |\n|------------------------------------|-------------------------------------------|--------------------------------------|\n| Manager short-term and CEO long-term | Gut für Management- und Führungspositionen | Gut für IT-Management und Führung |\n| KI ausprobieren | Nicht spezifisch abgedeckt | Gut abgedeckt durch IT und Algorithmen|\n| Mathematische Modelle entwickeln | Teilweise abgedeckt | Gut abgedeckt durch Datenanalyse |\n| Mathe anwenden | Gut abgedeckt | Sehr gut abgedeckt |\n| Schwere Matheprobleme lösen | Teilweise abgedeckt | Sehr gut abgedeckt |\n| Programmieren | Nicht spezifisch abgedeckt | Sehr gut abgedeckt |\n| Abiturnotendurchschnitt = 1.0 | NC = 1.0 | NC = 1.8 |\n\nBeide Programme könnten für dich passen, aber \"Wirtschaftsinformatik\" scheint besser geeignet zu sein. Deine Interessen an \"KI ausprobieren\", \"Mathematische Modelle entwickeln\", \"Mathe anwenden\", \"Schwere Matheprobleme lösen\" und \"Programmieren\" werden in der \"Wirtschaftsinformatik\" sehr gut abgedeckt. Zudem bietet dieses Programm eine solide Grundlage für eine Karriere im IT-Management und als CEO eines Technologieunternehmens. \"Management, Economics and Social Sciences\" ist ebenfalls eine gute Wahl, besonders wenn du dich stärker auf Management und wirtschaftliche Aspekte konzentrieren möchtest.", + "query": "", + "title": "Paco's Vergleich der Studiengänge Management, Economics and Social Sciences (Fit=Sehr gut) und Wirtschaftsinformatik (Fit=Sehr gut)", + "add_detail": "Die oben angegebenen NCs sind vom letzten Jahr. Der NC ist eines der Auswahlkriterien für die Programme und kann sich von Jahr zu Jahr ändern. Beachte: Wenn der Abiturnotendurchschnitt kleiner oder gleich dem NC-Wert ist, kannst du das Programm vermutlich studieren, wenn anders gegebenenfalls nicht. Gibt es andere Kriterien, anhand derer ich die Programme für dich vergleichen soll? Dann gebe deine Kriterien in der Eingabemaske ein.", + "llm_answer": "Hier ein Vergleich der beiden Programme anhand von Kriterien, die für dich relevant sein müssten.\n\n| Kriterium | Management, Economics and Social Sciences | Wirtschaftsinformatik |\n|------------------------------------|-------------------------------------------|--------------------------------------|\n| Manager short-term and CEO long-term | Gut für Management- und Führungspositionen | Gut für IT-Management und Führung |\n| KI ausprobieren | Nicht spezifisch abgedeckt | Gut abgedeckt durch IT und Algorithmen|\n| Mathematische Modelle entwickeln | Teilweise abgedeckt | Gut abgedeckt durch Datenanalyse |\n| Mathe anwenden | Gut abgedeckt | Sehr gut abgedeckt |\n| Schwere Matheprobleme lösen | Teilweise abgedeckt | Sehr gut abgedeckt |\n| Programmieren | Nicht spezifisch abgedeckt | Sehr gut abgedeckt |\n| Abiturnotendurchschnitt = 1.0 | NC = 1.0 | NC = 1.8 |\n\nBeide Programme könnten für dich passen, aber \"Wirtschaftsinformatik\" scheint besser geeignet zu sein. Deine Interessen an \"KI ausprobieren\", \"Mathematische Modelle entwickeln\", \"Mathe anwenden\", \"Schwere Matheprobleme lösen\" und \"Programmieren\" werden in der \"Wirtschaftsinformatik\" sehr gut abgedeckt. Zudem bietet dieses Programm eine solide Grundlage für eine Karriere im IT-Management und als CEO eines Technologieunternehmens. \"Management, Economics and Social Sciences\" ist ebenfalls eine gute Wahl, besonders wenn du dich stärker auf Management und wirtschaftliche Aspekte konzentrieren möchtest.", + "title_description": "Du kannst Pacos's Kriterien Vergleich immer wiederholen - klicke 'generate again'. Du kannst weitere Kriterien zum Vergleich nennen." + } + }, + "add_detail": "Die oben angegebenen NCs sind vom letzten Jahr. Der NC ist eines der Auswahlkriterien für die Programme und kann sich von Jahr zu Jahr ändern. Beachte: Wenn der Abiturnotendurchschnitt kleiner oder gleich dem NC-Wert ist, kannst du das Programm vermutlich studieren, wenn anders gegebenenfalls nicht. Gibt es andere Kriterien, anhand derer ich die Programme für dich vergleichen soll? Dann gebe deine Kriterien in der Eingabemaske ein.", "prompt_type": "program_compare", "all_elements": ["Wirtschaftsinformatik: Sehr gut", "Management, Economics and Social Sciences: Sehr gut"], "question_title": "Paco's Vergleich der Studiengänge (Fit=) und (Fit=)", "answer_template": "", + "prompt_type_ext": "program_compare_my_criteria", + "question_title_description": "Du kannst Pacos's Kriterien Vergleich immer wiederholen - klicke 'generate again'. Du kannst weitere Kriterien zum Vergleich nennen." + } + } + } + return data \ No newline at end of file From 8a86fc00db1eaa5c5bfe0d7e2254f5258fd6c030 Mon Sep 17 00:00:00 2001 From: lanan Date: Wed, 19 Jun 2024 12:46:53 +0200 Subject: [PATCH 07/21] user_id automatisch und manuell generierbar bei Klick auf POST --- app/core/urls.py | 19 +++++++++++-------- app/core/views.py | 47 +++++++++++++++++------------------------------ 2 files changed, 28 insertions(+), 38 deletions(-) diff --git a/app/core/urls.py b/app/core/urls.py index 226ee99..2b9f1d6 100644 --- a/app/core/urls.py +++ b/app/core/urls.py @@ -10,14 +10,17 @@ from core.views import AnswersDetailsAPIView urlpatterns = [ - path('userid/', useridlist), - # path('userid/', UserIDListAPIView.as_view()), - #path('useriddetail/', useridlist_detail), - path('useriddetail/', UserIDListDetailsAPIView.as_view()), - #path('answers/', answers), - path('answers/', AnswersAPIView.as_view()), - #path('answersdetail/', answers_detail), - path('answersdetail/', AnswersDetailsAPIView.as_view()), + #path('userid/', useridlist), + #path('userid/', UserIDListAPIView.as_view()), + #path('useriddetail/', useridlist_detail), + #path('answersdetail/', answers_detail), + #path('answers/', answers), + #path('useriddetail/', UserIDListDetailsAPIView.as_view()), + #path('answersdetail/', answers_detail), + path('api/answers/', AnswersAPIView.as_view()), + path('api/answerslist/', AnswersDetailsAPIView.as_view()), + path('api/useridlist/', UserIDListAPIView.as_view(), name='useridlist-list'), + path('api/useridlist//', UserIDListDetailsAPIView.as_view(), name='useridlist-details'), ] \ No newline at end of file diff --git a/app/core/views.py b/app/core/views.py index d2c7844..315c840 100644 --- a/app/core/views.py +++ b/app/core/views.py @@ -11,33 +11,10 @@ import uuid # Create your views here. -#Funktion zum Abrufen oder Erstellen einer UserID -#zum testen: -#$python manage.py shell -#from core.models import UserIDList -#from core.views import user_id -# Teste das Abrufen einer bestehenden UserID -#user = user_id(action="getDBObject", userID="efd69e9c-3945-4885-9a06-c9216efec82b") -#print(user) # Sollte None zurückgeben, wenn die UserID nicht existiert -# Erstelle eine neue UserID -#new_user_id = user_id(action="create") -#print(new_user_id) # Sollte eine neue UUID zurückgeben -# Teste das Abrufen der gerade erstellten UserID -#user = user_id(action="getDBObject", userID=new_user_id) -#print(user) # Sollte das UserIDList Objekt mit der neuen UUID zurückgeben - - -def user_id(action, userID="efd69e9c-3945-4885-9a06-c9216efec82b"): - if action == "getDBObject": - if UserIDList.objects.filter(userid=userID).exists(): - return UserIDList.objects.get(userid=userID) - else: - return None - elif action == "create": - userIDValue = str(uuid.uuid4()) - UserIDList.objects.create(userid=userIDValue) - return userIDValue - return None + +# Funktion zur Generierung einer neuen UserID +def generate_user_id(): + return str(uuid.uuid4()) class UserIDListAPIView(APIView): @@ -46,14 +23,24 @@ def get(self, request): serializer=UserIDListSerializer(users, many=True) return Response(serializer.data) + def post(self, request): - serializer=UserIDListSerializer(data=request.data) + # Überprüfen, ob eine UserID in der Anfrage übergeben wurde + if 'userid' in request.data and request.data['userid']: + user_id = request.data['userid'] + if UserIDList.objects.filter(userid=user_id).exists(): + return Response({"error": "UserID already exists."}, status=status.HTTP_400_BAD_REQUEST) + else: + # Wenn keine UserID übergeben wurde, generiere automatisch eine neue + user_id = generate_user_id() + + # Füge die generierte oder übergebene UserID zur Anfrage hinzu + request.data['userid'] = user_id + serializer = UserIDListSerializer(data=request.data) if serializer.is_valid(): serializer.save() return Response(serializer.data, status=status.HTTP_201_CREATED) - return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) - class UserIDListDetailsAPIView(APIView): From 71ce96e3f94eb66280384c20ca3b188d63991ab5 Mon Sep 17 00:00:00 2001 From: lanan Date: Wed, 19 Jun 2024 15:25:44 +0200 Subject: [PATCH 08/21] user_id methode aus x_data_utils.py erfolgreich eingebunden --- app/app/settings.py | 2 +- app/core/views.py | 27 ++++++++++++++------------- app/core/x_data_utils.py | 15 +++++++++------ requirements.txt | 2 ++ 4 files changed, 26 insertions(+), 20 deletions(-) diff --git a/app/app/settings.py b/app/app/settings.py index e1788a2..3cdef94 100644 --- a/app/app/settings.py +++ b/app/app/settings.py @@ -84,7 +84,7 @@ DATABASES = { 'default': { 'ENGINE': 'django.db.backends.postgresql', - 'HOST': os.environ.get('DB_HOST'), + 'HOST': os.environ.get('DB_HOST', 'localhost'), 'NAME': os.environ.get('DB_NAME'), 'USER': os.environ.get('DB_USER'), 'PASSWORD': os.environ.get('DB_PASS'), diff --git a/app/core/views.py b/app/core/views.py index 315c840..c6401d2 100644 --- a/app/core/views.py +++ b/app/core/views.py @@ -8,39 +8,40 @@ from rest_framework.response import Response from rest_framework import status from rest_framework.views import APIView +from core.x_data_utils import user_id import uuid # Create your views here. -# Funktion zur Generierung einer neuen UserID -def generate_user_id(): - return str(uuid.uuid4()) + class UserIDListAPIView(APIView): - def get(self, request): - users=UserIDList.objects.all() - serializer=UserIDListSerializer(users, many=True) + def get(self, request): + users = UserIDList.objects.all() + serializer = UserIDListSerializer(users, many=True) return Response(serializer.data) - - - def post(self, request): + + def post(self, request): # Überprüfen, ob eine UserID in der Anfrage übergeben wurde if 'userid' in request.data and request.data['userid']: - user_id = request.data['userid'] - if UserIDList.objects.filter(userid=user_id).exists(): + user_id_value = request.data['userid'] + if UserIDList.objects.filter(userid=user_id_value).exists(): return Response({"error": "UserID already exists."}, status=status.HTTP_400_BAD_REQUEST) else: # Wenn keine UserID übergeben wurde, generiere automatisch eine neue - user_id = generate_user_id() + user_id_value = user_id(action="create") # Füge die generierte oder übergebene UserID zur Anfrage hinzu - request.data['userid'] = user_id + request.data['userid'] = user_id_value serializer = UserIDListSerializer(data=request.data) if serializer.is_valid(): serializer.save() return Response(serializer.data, status=status.HTTP_201_CREATED) + else: + return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) + class UserIDListDetailsAPIView(APIView): diff --git a/app/core/x_data_utils.py b/app/core/x_data_utils.py index b5616b0..8dad053 100644 --- a/app/core/x_data_utils.py +++ b/app/core/x_data_utils.py @@ -6,6 +6,7 @@ from core.models import UserIDList, Answers #core.models could change e.g. api.models #from markdown import markdown # type: ignore import uuid +import markdown # copy to models.py the following lines and uncomment those lines ################ models.py #################### @@ -54,16 +55,18 @@ def get_interview_config_db(request, question_type_id, question_id, action='getD return object, config def user_id(action, request=[], userID="efd69e9c-3945-4885-9a06-c9216efec82b"): - if action =="getDBObject": - if UserIDList.objects.filter(userid = userID).exists(): + if action == "getDBObject": + # Überprüfe, ob eine UserID mit der gegebenen userID existiert + if UserIDList.objects.filter(userid=userID).exists(): return UserIDList.objects.get(userid=userID) else: return None elif action == "create": - userIDValue = str(uuid.uuid4()) - UserIDList.objects.create(userid=userIDValue) - return userIDValue - return None + # Erzeuge eine neue UserID + userIDValue = str(uuid.uuid4()) # Generiere eine UUID + UserIDList.objects.create(userid=userIDValue) # Speichere die neue UserID in der Datenbank + return userIDValue # Gib die neu generierte UserID zurück + return None # Falls ein ungültiger action-Wert übergeben wurde, gib None zurück def get_interview_config(question_type_id, question_id, object=None): if not question_type_id: diff --git a/requirements.txt b/requirements.txt index 2244900..36c3a18 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,3 +1,5 @@ Django>=3.2.3,<3.3 psycopg2>=2.8.6,<2.9 uWSGI>=2.0.19.1,<2.1 +markdown +djangorestframework \ No newline at end of file From 7c878d2ea98ad7bdd0b0055d33ae4c660093ce8e Mon Sep 17 00:00:00 2001 From: GeorgiosK78 Date: Wed, 19 Jun 2024 16:18:13 +0200 Subject: [PATCH 09/21] /interviewdetails/{token} returns all data for token --- app/core/models.py | 1 + app/core/serializers.py | 3 ++- app/core/urls.py | 2 ++ app/core/views.py | 21 +++++++++++++++++---- 4 files changed, 22 insertions(+), 5 deletions(-) diff --git a/app/core/models.py b/app/core/models.py index 3f07ce1..0212796 100644 --- a/app/core/models.py +++ b/app/core/models.py @@ -16,3 +16,4 @@ class Answers(models.Model): def __str__(self): return self.userid.userid + diff --git a/app/core/serializers.py b/app/core/serializers.py index a1f4863..d09772e 100644 --- a/app/core/serializers.py +++ b/app/core/serializers.py @@ -12,4 +12,5 @@ class AnswersSerializer(serializers.ModelSerializer): class Meta: model=Answers - fields= ["userid", "question_type_id","data"] \ No newline at end of file + fields= ["userid", "question_type_id","data"] + diff --git a/app/core/urls.py b/app/core/urls.py index 226ee99..9a457b9 100644 --- a/app/core/urls.py +++ b/app/core/urls.py @@ -18,6 +18,8 @@ path('answers/', AnswersAPIView.as_view()), #path('answersdetail/', answers_detail), path('answersdetail/', AnswersDetailsAPIView.as_view()), + path('interviewdetails//', AnswersAPIView.as_view(), name='interview-details'), + ] \ No newline at end of file diff --git a/app/core/views.py b/app/core/views.py index d2c7844..dc38427 100644 --- a/app/core/views.py +++ b/app/core/views.py @@ -9,6 +9,7 @@ from rest_framework import status from rest_framework.views import APIView import uuid +from .x_data_utils import get_all_interview_data_db, get_interview_config # Create your views here. #Funktion zum Abrufen oder Erstellen einer UserID @@ -82,12 +83,24 @@ def delete(self, request, id): id.delete() return Response(status=status.HTTP_204_NO_CONTENT) + class AnswersAPIView(APIView): - def get(self, request): - answers=Answers.objects.all() - serializer=AnswersSerializer(answers, many=True) - return Response(serializer.data) + def get(self, request, userid): + try: + # Versuche, die Interviewdaten für den Benutzer abzurufen + answers = Answers.objects.get(userid__userid=userid) # Hier wird nach der UserID in der UserIDList gesucht + serializer = AnswersSerializer(answers) + return Response(serializer.data) + + except Answers.DoesNotExist: + # Wenn keine Interviewdaten für den Benutzer vorhanden sind, rufe die Standarddaten ab + interview_data = get_all_interview_data_db(1) # Annahme: Funktion zum Abrufen von Standarddaten + # Erstelle eine neue Instanz von Answers für den Benutzer mit den Standarddaten + user = UserIDList.objects.get(userid=userid) + answers = Answers.objects.create(userid=user, data=interview_data) + serializer = AnswersSerializer(answers) + return Response(serializer.data) def post(self, request): serializer=AnswersSerializer(data=request.data) From 7ca7e78dc13f44e42f683be140cbf3a5547f9058 Mon Sep 17 00:00:00 2001 From: GeorgiosK78 Date: Wed, 19 Jun 2024 17:54:51 +0200 Subject: [PATCH 10/21] /interviwedetais/{userid}/{questionNR} "POST" speichert eine json mit antworten zur frage --- app/core/serializers.py | 2 +- app/core/urls.py | 10 +++-- app/core/views.py | 91 +++++++++++++++++++++++------------------ 3 files changed, 59 insertions(+), 44 deletions(-) diff --git a/app/core/serializers.py b/app/core/serializers.py index d09772e..d3d1391 100644 --- a/app/core/serializers.py +++ b/app/core/serializers.py @@ -9,7 +9,7 @@ class Meta: class AnswersSerializer(serializers.ModelSerializer): - + class Meta: model=Answers fields= ["userid", "question_type_id","data"] diff --git a/app/core/urls.py b/app/core/urls.py index 9a457b9..e7fe8a1 100644 --- a/app/core/urls.py +++ b/app/core/urls.py @@ -1,13 +1,13 @@ from django.urls import path -from core.views import useridlist +from core.views import useridlist from core.views import useridlist_detail from core.views import answers from core.views import answers_detail from core.views import UserIDListAPIView from core.views import UserIDListDetailsAPIView -from core.views import AnswersAPIView -from core.views import AnswersDetailsAPIView +from core.views import AnswersAPIView, AnswersDetailAPIView + urlpatterns = [ path('userid/', useridlist), @@ -17,8 +17,10 @@ #path('answers/', answers), path('answers/', AnswersAPIView.as_view()), #path('answersdetail/', answers_detail), - path('answersdetail/', AnswersDetailsAPIView.as_view()), + # path('answersdetail/', AnswersDetailAPIView.as_view()), path('interviewdetails//', AnswersAPIView.as_view(), name='interview-details'), + path('interviewdetails///', AnswersDetailAPIView.as_view(), name='interview-details-detail'), + diff --git a/app/core/views.py b/app/core/views.py index dc38427..317d8bc 100644 --- a/app/core/views.py +++ b/app/core/views.py @@ -12,20 +12,6 @@ from .x_data_utils import get_all_interview_data_db, get_interview_config # Create your views here. -#Funktion zum Abrufen oder Erstellen einer UserID -#zum testen: -#$python manage.py shell -#from core.models import UserIDList -#from core.views import user_id -# Teste das Abrufen einer bestehenden UserID -#user = user_id(action="getDBObject", userID="efd69e9c-3945-4885-9a06-c9216efec82b") -#print(user) # Sollte None zurückgeben, wenn die UserID nicht existiert -# Erstelle eine neue UserID -#new_user_id = user_id(action="create") -#print(new_user_id) # Sollte eine neue UUID zurückgeben -# Teste das Abrufen der gerade erstellten UserID -#user = user_id(action="getDBObject", userID=new_user_id) -#print(user) # Sollte das UserIDList Objekt mit der neuen UUID zurückgeben def user_id(action, userID="efd69e9c-3945-4885-9a06-c9216efec82b"): @@ -40,6 +26,7 @@ def user_id(action, userID="efd69e9c-3945-4885-9a06-c9216efec82b"): return userIDValue return None + class UserIDListAPIView(APIView): def get(self, request): @@ -56,7 +43,6 @@ def post(self, request): return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) - class UserIDListDetailsAPIView(APIView): def get_object(self,id): try: @@ -84,6 +70,8 @@ def delete(self, request, id): return Response(status=status.HTTP_204_NO_CONTENT) +# /interviwedetais/{userid} +# gibt Alle Daten zum thema interview zurück (fragen, antworten, alles) class AnswersAPIView(APIView): def get(self, request, userid): @@ -94,8 +82,7 @@ def get(self, request, userid): return Response(serializer.data) except Answers.DoesNotExist: - # Wenn keine Interviewdaten für den Benutzer vorhanden sind, rufe die Standarddaten ab - interview_data = get_all_interview_data_db(1) # Annahme: Funktion zum Abrufen von Standarddaten + interview_data = get_all_interview_data_db() # Annahme: Funktion zum Abrufen von Standarddaten # Erstelle eine neue Instanz von Answers für den Benutzer mit den Standarddaten user = UserIDList.objects.get(userid=userid) answers = Answers.objects.create(userid=user, data=interview_data) @@ -110,31 +97,57 @@ def post(self, request): return Response(serializer.data, status=status.HTTP_201_CREATED) return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) -class AnswersDetailsAPIView(APIView): - def get_object(self, id): - try: - return Answers.objects.get(id=id) - except Answers.DoesNotExist: - return HttpResponse(status=status.HTTP_404_NOT_FOUND) - def get(self, request, id): - answer = self.get_object(id) - serializer = AnswersSerializer(answer) - return Response(serializer.data) - - def put(self, request, id): - answer = self.get_object(id) - serializer = AnswersSerializer(answer, data=request.data) +# /interviwedetais/{userid}/{questionNR} +# gibt die jeweiligen daten zur question mit questionNR zurück +# Post: /interviwedetais/{userid}/{questionNR} speichert die Antworten in data +# Beispielpost : { "new_data": ["Mathe", "Biologie", "Chemie"] } +class AnswersDetailAPIView(APIView): - if serializer.is_valid(): - serializer.save() - return Response(serializer.data) - return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) + def get(self, request, userid, question_number): + try: + + # Versuche, die Interviewdaten für den Benutzer und die Frage zu finden + answers = Answers.objects.get(userid__userid=userid) + + # Annahme: data ist ein JSONField, das `interview_config` enthält + interview_config = answers.data.get('interview_config', {}) + + # Zugriff auf das entsprechende Element wie A1, A2, usw. + data = interview_config.get(f'A{question_number}', None) + + if data is None: + return Response({'error': f'Keine Daten gefunden für Frage A{question_number}.'}, status=status.HTTP_404_NOT_FOUND) + + return Response(data) + + except Answers.DoesNotExist: + return Response({'error': 'Interviewantworten für diesen Benutzer nicht gefunden.'}, status=status.HTTP_404_NOT_FOUND) + + except Exception as e: + return Response({'error': str(e)}, status=status.HTTP_500_INTERNAL_SERVER_ERROR) - def delete(self, request, id): - answer = self.get_object(id) - answer.delete() - return Response(status=status.HTTP_204_NO_CONTENT) + def post(self, request, userid, question_number): + try: + # Versuche, die Interviewdaten für den Benutzer und die Frage zu aktualisieren + answers = Answers.objects.get(userid__userid=userid) + + # Neuer JSON-Wert aus dem Request + new_data = request.data.get('new_data', {}) + + # Update des entsprechenden Elements wie A1, A2, usw. direkt in data + answers.data[f'A{question_number}'] = new_data + + # Speichern der aktualisierten Daten zurück in der Datenbank + answers.save() + + return Response({'success': f'Daten für Frage A{question_number} erfolgreich aktualisiert.'}, status=status.HTTP_200_OK) + + except Answers.DoesNotExist: + return Response({'error': 'Interviewantworten für diesen Benutzer nicht gefunden.'}, status=status.HTTP_404_NOT_FOUND) + + except Exception as e: + return Response({'error': str(e)}, status=status.HTTP_500_INTERNAL_SERVER_ERROR) @api_view(['GET', 'POST']) def useridlist(request): From a56b6fb078068b02fe6789cfa5b1f5b6a4a3eaff Mon Sep 17 00:00:00 2001 From: lanan Date: Thu, 20 Jun 2024 10:27:57 +0200 Subject: [PATCH 11/21] markdown in requirements.txt dazu getan --- app/core/x_data_utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/core/x_data_utils.py b/app/core/x_data_utils.py index b5616b0..5b5bd9d 100644 --- a/app/core/x_data_utils.py +++ b/app/core/x_data_utils.py @@ -6,7 +6,7 @@ from core.models import UserIDList, Answers #core.models could change e.g. api.models #from markdown import markdown # type: ignore import uuid - +import markdown # copy to models.py the following lines and uncomment those lines ################ models.py #################### # class UserIDList(models.Model): From a3065f08a7ec0ff9b677d5dff9b5bdcc90bac163 Mon Sep 17 00:00:00 2001 From: lanan Date: Thu, 20 Jun 2024 10:29:38 +0200 Subject: [PATCH 12/21] requirements.txt --- requirements.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/requirements.txt b/requirements.txt index 2244900..c579ea4 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,3 +1,4 @@ Django>=3.2.3,<3.3 psycopg2>=2.8.6,<2.9 uWSGI>=2.0.19.1,<2.1 +markdown \ No newline at end of file From de7545984eec2d925fe041de44a3b44ac181002f Mon Sep 17 00:00:00 2001 From: Sabaawi7 Date: Thu, 20 Jun 2024 11:49:43 +0300 Subject: [PATCH 13/21] added tokenAuth --- app/app/settings.py | 9 +++- app/app/urls.py | 2 +- app/core/migrations/0002_user.py | 43 +++++++++++++++++ app/core/models.py | 28 +++++++++++ app/core/serializers.py | 15 ++++++ app/core/urls.py | 18 +++----- app/core/views.py | 79 +++++++++++++++++++++++++------- requirements.txt | 3 ++ 8 files changed, 165 insertions(+), 32 deletions(-) create mode 100644 app/core/migrations/0002_user.py diff --git a/app/app/settings.py b/app/app/settings.py index 6b4712c..1cbad47 100644 --- a/app/app/settings.py +++ b/app/app/settings.py @@ -43,6 +43,7 @@ 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', + 'corsheaders', 'core', 'rest_framework' ] @@ -83,12 +84,13 @@ DATABASES = { 'default': { - 'ENGINE': 'django.db.backends.sqlite3', + 'ENGINE': 'django.db.backends.postgresql', 'HOST': os.environ.get('DB_HOST'), - 'NAME': BASE_DIR /'data'/ 'db.sqlite3', + 'NAME': os.environ.get('DB_NAME'), 'USER': os.environ.get('DB_USER'), 'PASSWORD': os.environ.get('DB_PASS'), } + } @@ -138,3 +140,6 @@ # https://docs.djangoproject.com/en/3.2/ref/settings/#default-auto-field DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField' + +CORS_ORIGIN_ALLOW_ALL = True +CORS_ALLOW_CREDENTIALS = True \ No newline at end of file diff --git a/app/app/urls.py b/app/app/urls.py index e1e1579..b860ffc 100644 --- a/app/app/urls.py +++ b/app/app/urls.py @@ -20,7 +20,7 @@ urlpatterns = [ path('admin/', admin.site.urls), - path('', include('core.urls')) + path('api/', include('core.urls')) ] if settings.DEBUG: diff --git a/app/core/migrations/0002_user.py b/app/core/migrations/0002_user.py new file mode 100644 index 0000000..efc1daa --- /dev/null +++ b/app/core/migrations/0002_user.py @@ -0,0 +1,43 @@ +# Generated by Django 3.2.25 on 2024-06-20 06:17 + +import django.contrib.auth.models +from django.db import migrations, models +import django.utils.timezone + + +class Migration(migrations.Migration): + + dependencies = [ + ('auth', '0012_alter_user_first_name_max_length'), + ('core', '0001_initial'), + ] + + operations = [ + migrations.CreateModel( + name='User', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('last_login', models.DateTimeField(blank=True, null=True, verbose_name='last login')), + ('is_superuser', models.BooleanField(default=False, help_text='Designates that this user has all permissions without explicitly assigning them.', verbose_name='superuser status')), + ('first_name', models.CharField(blank=True, max_length=150, verbose_name='first name')), + ('last_name', models.CharField(blank=True, max_length=150, verbose_name='last name')), + ('is_staff', models.BooleanField(default=False, help_text='Designates whether the user can log into this admin site.', verbose_name='staff status')), + ('is_active', models.BooleanField(default=True, help_text='Designates whether this user should be treated as active. Unselect this instead of deleting accounts.', verbose_name='active')), + ('date_joined', models.DateTimeField(default=django.utils.timezone.now, verbose_name='date joined')), + ('name', models.CharField(max_length=255)), + ('email', models.EmailField(max_length=254, unique=True)), + ('password', models.CharField(max_length=255)), + ('username', models.CharField(blank=True, max_length=255, null=True)), + ('groups', models.ManyToManyField(blank=True, help_text='The groups this user belongs to. A user will get all permissions granted to each of their groups.', related_name='core_user_set', related_query_name='core_user', to='auth.Group')), + ('user_permissions', models.ManyToManyField(blank=True, help_text='Specific permissions for this user.', related_name='core_user_set', related_query_name='core_user', to='auth.Permission')), + ], + options={ + 'verbose_name': 'user', + 'verbose_name_plural': 'users', + 'abstract': False, + }, + managers=[ + ('objects', django.contrib.auth.models.UserManager()), + ], + ), + ] diff --git a/app/core/models.py b/app/core/models.py index 3f07ce1..1d648ca 100644 --- a/app/core/models.py +++ b/app/core/models.py @@ -1,4 +1,32 @@ from django.db import models +from django.contrib.auth.models import AbstractUser + + + +class User(AbstractUser): + name = models.CharField(max_length=255) + email = models.EmailField(unique=True) + password = models.CharField(max_length=255) + username = models.CharField(max_length=255, blank=True, null=True) # to avoid potential issues + + USERNAME_FIELD = 'email' + REQUIRED_FIELDS = [] + + # Add related_name attributes to avoid conflicts + groups = models.ManyToManyField( + 'auth.Group', + related_name='core_user_set', # Avoid conflict with auth.User.groups + blank=True, + help_text='The groups this user belongs to. A user will get all permissions granted to each of their groups.', + related_query_name='core_user', + ) + user_permissions = models.ManyToManyField( + 'auth.Permission', + related_name='core_user_set', # Avoid conflict with auth.User.user_permissions + blank=True, + help_text='Specific permissions for this user.', + related_query_name='core_user', + ) class UserIDList(models.Model): diff --git a/app/core/serializers.py b/app/core/serializers.py index a1f4863..1dc595b 100644 --- a/app/core/serializers.py +++ b/app/core/serializers.py @@ -1,7 +1,22 @@ from rest_framework import serializers from core.models import UserIDList from core.models import Answers +from core.models import * +class UserSerializer(serializers.ModelSerializer): + class Meta: + model=User + fields = ["id", "name", "email", "password"] + extra_kwargs = { + "password": {"write_only":True} + } + def create(self, validated_data): + password = validated_data.pop("password", None) + instance = self.Meta.model(**validated_data) + if password is not None: + instance.set_password(password) + instance.save() + return instance class UserIDListSerializer(serializers.ModelSerializer): class Meta: model=UserIDList diff --git a/app/core/urls.py b/app/core/urls.py index 226ee99..10b27ef 100644 --- a/app/core/urls.py +++ b/app/core/urls.py @@ -1,23 +1,17 @@ from django.urls import path -from core.views import useridlist -from core.views import useridlist_detail -from core.views import answers -from core.views import answers_detail -from core.views import UserIDListAPIView -from core.views import UserIDListDetailsAPIView -from core.views import AnswersAPIView -from core.views import AnswersDetailsAPIView - +from core.views import * urlpatterns = [ - path('userid/', useridlist), - # path('userid/', UserIDListAPIView.as_view()), + # path('userid/', useridlist), + path('userid/', UserIDListAPIView.as_view()), #path('useriddetail/', useridlist_detail), path('useriddetail/', UserIDListDetailsAPIView.as_view()), #path('answers/', answers), path('answers/', AnswersAPIView.as_view()), #path('answersdetail/', answers_detail), path('answersdetail/', AnswersDetailsAPIView.as_view()), + path('login', LoginUserView.as_view()), + path('register', RegisterUserView.as_view()), + path('user', UserView.as_view()) - ] \ No newline at end of file diff --git a/app/core/views.py b/app/core/views.py index d2c7844..cbbefab 100644 --- a/app/core/views.py +++ b/app/core/views.py @@ -2,12 +2,14 @@ from django.http import HttpResponse from core.models import UserIDList from core.models import Answers -from core.serializers import UserIDListSerializer -from core.serializers import AnswersSerializer +from core.models import User +from core.serializers import * from rest_framework.decorators import api_view from rest_framework.response import Response +from rest_framework.exceptions import AuthenticationFailed from rest_framework import status from rest_framework.views import APIView +import jwt, datetime import uuid # Create your views here. @@ -27,17 +29,57 @@ #print(user) # Sollte das UserIDList Objekt mit der neuen UUID zurückgeben -def user_id(action, userID="efd69e9c-3945-4885-9a06-c9216efec82b"): - if action == "getDBObject": - if UserIDList.objects.filter(userid=userID).exists(): - return UserIDList.objects.get(userid=userID) - else: - return None - elif action == "create": - userIDValue = str(uuid.uuid4()) - UserIDList.objects.create(userid=userIDValue) - return userIDValue - return None +class RegisterUserView(APIView): + def post(self, request): + serializer = UserSerializer(data=request.data) + serializer.is_valid(raise_exception=True) + serializer.save() + + return Response(serializer.data) + +class LoginUserView(APIView): + def post(self, request): + email = request.data["email"] + password = request.data["password"] + + user = User.objects.filter(email=email).first() + + if user is None: + raise AuthenticationFailed("User not found!") + + if not user.check_password(password): + raise AuthenticationFailed("Incorrect Password!") + + payload = { + "id":user.id, + "exp":datetime.datetime.now() + datetime.timedelta(minutes=60), + "iat":datetime.datetime.now() + } + encoded_token = jwt.encode(payload, "secret", algorithm="HS256") + decoded_token = jwt.decode(encoded_token, "secret", algorithms=["HS256"]) + + response = Response() + response.set_cookie(key="jwt",value=encoded_token,httponly=True) + response.data = { + "jwt":encoded_token + } + return response + +class UserView(APIView): + def get(self, request): + token = request.COOKIES.get("jwt") + + if not token: + raise AuthenticationFailed("Unauthenticated") + try: + payload = jwt.decode(token, "secret", algorithms=["HS256"]) + except jwt.ExpiredSignatureError: + raise AuthenticationFailed("Unauthenticated") + + user = User.objects.filter(id=payload["id"]) + serializer = UserSerializer(user) + return Response(serializer.data) + class UserIDListAPIView(APIView): @@ -47,13 +89,13 @@ def get(self, request): return Response(serializer.data) def post(self, request): + userIDValue = str(uuid.uuid4()) + request.data["userid"] = userIDValue serializer=UserIDListSerializer(data=request.data) - if serializer.is_valid(): + if serializer.is_valid(raise_exception=True): serializer.save() - return Response(serializer.data, status=status.HTTP_201_CREATED) - return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) - + return Response(serializer.data, status=status.HTTP_201_CREATED) class UserIDListDetailsAPIView(APIView): @@ -208,3 +250,6 @@ def answers_detail(request, pk): elif request.method=='DELETE': answer.delete() return Response(status=status.HTTP_204_NO_CONTENT) + + + \ No newline at end of file diff --git a/requirements.txt b/requirements.txt index 2244900..1422ec7 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,3 +1,6 @@ Django>=3.2.3,<3.3 psycopg2>=2.8.6,<2.9 uWSGI>=2.0.19.1,<2.1 +djangorestframework >= 3.15.1,<3.16 +pyjwt >=2.8.0, <2.8.1 +django-cors-headers \ No newline at end of file From 062cc91b59e7ddeee63ea0dde2ce02787dc4234d Mon Sep 17 00:00:00 2001 From: lanan Date: Thu, 20 Jun 2024 11:12:42 +0200 Subject: [PATCH 14/21] requirements.txt --- requirements.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/requirements.txt b/requirements.txt index c579ea4..55de2f6 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,4 +1,5 @@ Django>=3.2.3,<3.3 psycopg2>=2.8.6,<2.9 uWSGI>=2.0.19.1,<2.1 +djangorestframework markdown \ No newline at end of file From 1701d2c9d9eee8275d773a586e712de3ec5ab066 Mon Sep 17 00:00:00 2001 From: GeorgiosK78 Date: Thu, 20 Jun 2024 16:48:47 +0200 Subject: [PATCH 15/21] get question data and set selected answers works --- app/core/urls.py | 4 +-- app/core/views.py | 87 ++++++++++++++++++++++++++++++++++++----------- 2 files changed, 70 insertions(+), 21 deletions(-) diff --git a/app/core/urls.py b/app/core/urls.py index e7fe8a1..3b8f46f 100644 --- a/app/core/urls.py +++ b/app/core/urls.py @@ -18,8 +18,8 @@ path('answers/', AnswersAPIView.as_view()), #path('answersdetail/', answers_detail), # path('answersdetail/', AnswersDetailAPIView.as_view()), - path('interviewdetails//', AnswersAPIView.as_view(), name='interview-details'), - path('interviewdetails///', AnswersDetailAPIView.as_view(), name='interview-details-detail'), + # path('interviewdetails//', AnswersAPIView.as_view(), name='interview-details'), + #path('interviewdetails///', AnswersDetailAPIView.as_view(), name='interview-details-detail'), diff --git a/app/core/views.py b/app/core/views.py index 317d8bc..38f07cf 100644 --- a/app/core/views.py +++ b/app/core/views.py @@ -72,36 +72,85 @@ def delete(self, request, id): # /interviwedetais/{userid} # gibt Alle Daten zum thema interview zurück (fragen, antworten, alles) + class AnswersAPIView(APIView): - def get(self, request, userid): + def post(self, request): try: - # Versuche, die Interviewdaten für den Benutzer abzurufen - answers = Answers.objects.get(userid__userid=userid) # Hier wird nach der UserID in der UserIDList gesucht - serializer = AnswersSerializer(answers) - return Response(serializer.data) + # Überprüfe, ob der Body der Anfrage leer ist + if not request.data: + return Response({'error': 'Der Anfrage-Body darf nicht leer sein.'}, status=status.HTTP_400_BAD_REQUEST) + + # Extrahiere die erforderlichen Parameter aus der Anfrage + request_data = request.data + userid = request_data.get('userid') + question_type_id = request_data.get('question_type_id') + question_nr = request_data.get('question_nr') + request_type = request_data.get('request_type') + data_to_post = request_data.get('dataToPost', None) + + if not userid or not question_type_id or not question_nr or not request_type: + return Response({'error': 'Erforderliche Parameter fehlen.'}, status=status.HTTP_400_BAD_REQUEST) + + # Verarbeite die Anfrage basierend auf dem request_type + if request_type == 'get': + # Versuche, die Interviewdaten für den Benutzer abzurufen + try: + #answers = Answers.objects.get(userid__userid=userid) + #serializer = AnswersSerializer(answers) + #return Response(serializer.data) + answers = Answers.objects.get(userid__userid=userid) + # Annahme: data ist ein JSONField, das `interview_config` enthält + interview_config = answers.data.get('interview_config', {}) + # Zugriff auf das entsprechende Element wie A1, A2, usw. + data = interview_config.get(f'A{question_nr}', None) + if data is None: + return Response({'error': f'Keine Daten gefunden für Frage A{question_nr}.'}, status=status.HTTP_404_NOT_FOUND) + + return Response(data) + + except Answers.DoesNotExist: + interview_data = get_all_interview_data_db(question_type_id) # Annahme: Funktion zum Abrufen von Standarddaten + # Erstelle eine neue Instanz von Answers für den Benutzer mit den Standarddaten + user = UserIDList.objects.get(userid=userid) + answers = Answers.objects.create(userid=user, data=interview_data) + serializer = AnswersSerializer(answers) + return Response(serializer.data, status=status.HTTP_201_CREATED) + + elif request_type == 'post': + if data_to_post is None: + return Response({'error': 'Keine neuen Daten bereitgestellt.'}, status=status.HTTP_400_BAD_REQUEST) + + #kann evtl raus hier drunter + if not isinstance(data_to_post, list): + return Response({'error': 'Die neuen Daten müssen eine Liste sein.'}, status=status.HTTP_400_BAD_REQUEST) + + # Versuche, die Interviewdaten für den Benutzer abzurufen + try: + answers = Answers.objects.get(userid__userid=userid) + except Answers.DoesNotExist: + return Response({'error': 'Interviewantworten für diesen Benutzer nicht gefunden.'}, status=status.HTTP_404_NOT_FOUND) + + # Aktualisiere die Daten für die entsprechende Frage + answers.data[f'A{question_nr}'] = data_to_post + answers.save() + return Response({'success': f'Daten für Frage A{question_nr} erfolgreich aktualisiert.'}, status=status.HTTP_200_OK) + + else: + return Response({'error': 'Ungültiger request_type.'}, status=status.HTTP_400_BAD_REQUEST) - except Answers.DoesNotExist: - interview_data = get_all_interview_data_db() # Annahme: Funktion zum Abrufen von Standarddaten - # Erstelle eine neue Instanz von Answers für den Benutzer mit den Standarddaten - user = UserIDList.objects.get(userid=userid) - answers = Answers.objects.create(userid=user, data=interview_data) - serializer = AnswersSerializer(answers) - return Response(serializer.data) + except Exception as e: + return Response({'error': str(e)}, status=status.HTTP_500_INTERNAL_SERVER_ERROR) - def post(self, request): - serializer=AnswersSerializer(data=request.data) - if serializer.is_valid(): - serializer.save() - return Response(serializer.data, status=status.HTTP_201_CREATED) - return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) - + + # /interviwedetais/{userid}/{questionNR} # gibt die jeweiligen daten zur question mit questionNR zurück # Post: /interviwedetais/{userid}/{questionNR} speichert die Antworten in data # Beispielpost : { "new_data": ["Mathe", "Biologie", "Chemie"] } + class AnswersDetailAPIView(APIView): def get(self, request, userid, question_number): From 610cef7f1f05b60948682795f90c34c4969f3cd6 Mon Sep 17 00:00:00 2001 From: Mohammed Sabaawi <116801010+Sabaawi7@users.noreply.github.com> Date: Thu, 20 Jun 2024 18:36:42 +0300 Subject: [PATCH 16/21] Update README.md --- README.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/README.md b/README.md index c8b1f1d..edcfd53 100644 --- a/README.md +++ b/README.md @@ -3,3 +3,10 @@ This is the finished source code for the tutorial [Deploying Django with Docker Compose](https://londonappdeveloper.com/deploying-django-with-docker-compose/). In this tutorial, we teach you how to prepare and deploying a Django project to an AWS EC2 instance using Docker Compose. + +For Software Samurais: +to use run this BackendApp you need to do the following step: +1. Start the docker desktop app on your device +2. run the command "docker-compose up" +3. After making substantial changes you would need to rebuild the image. Preferrably by deleting the old image from the docker desktop app and running the command again. +4. the backed app is reachable at "localhost:8000" From 5f8192c0c1d204b089b76fd4aae9a08ffb237b7c Mon Sep 17 00:00:00 2001 From: GeorgiosK78 Date: Thu, 20 Jun 2024 18:06:05 +0200 Subject: [PATCH 17/21] Answers api for get and post with token --- app/core/views.py | 53 +++++++++++++++++++++++++++++++++++++---------- 1 file changed, 42 insertions(+), 11 deletions(-) diff --git a/app/core/views.py b/app/core/views.py index 38f07cf..4ab2628 100644 --- a/app/core/views.py +++ b/app/core/views.py @@ -72,7 +72,6 @@ def delete(self, request, id): # /interviwedetais/{userid} # gibt Alle Daten zum thema interview zurück (fragen, antworten, alles) - class AnswersAPIView(APIView): def post(self, request): @@ -89,20 +88,51 @@ def post(self, request): request_type = request_data.get('request_type') data_to_post = request_data.get('dataToPost', None) - if not userid or not question_type_id or not question_nr or not request_type: + if not userid or not question_type_id or not request_type: return Response({'error': 'Erforderliche Parameter fehlen.'}, status=status.HTTP_400_BAD_REQUEST) - # Verarbeite die Anfrage basierend auf dem request_type + # GET CONFIG INFOS + # test with : {"userid": "{userid}","question_type_id": 1,"request_type": "get"} + if request_type == 'get' and not question_nr : + answers = Answers.objects.get(userid__userid=userid) + interview_config = answers.data.get('interview_config', {}) + return Response(interview_config) + + # GET SELECTED ANSWERS + # test with : {"userid": "{userid}","question_type_id": 1,"request_type": "getSelectedAnswers"} + if request_type == 'getSelectedAnswers' : + try: + answers = Answers.objects.get(userid__userid=userid) + data = answers.data + interview_config = data.get('interview_config', {}) + # Annahme: 'real_num_of_questions' gibt die Anzahl der Fragen an + real_num_of_questions = interview_config.get('real_num_of_questions', 0) + selected_answers = {} + + # Iteriere über die Fragen von A1 bis Ax (basierend auf real_num_of_questions) + for i in range(1, real_num_of_questions + 1): + key = f'A{i}' + + if key in interview_config: + question_title = interview_config[key].get('question_title', f'Frage A{i}') + selected_answers[question_title] = data.get(f'A{i}', []) + else: + selected_answers[f'Frage A{i}'] = [] + + return Response(selected_answers) + + except Answers.DoesNotExist: + return Response({'error': 'Interviewantworten für diesen Benutzer nicht gefunden.'}, status=status.HTTP_404_NOT_FOUND) + + except Exception as e: + return Response({'error': str(e)}, status=status.HTTP_500_INTERNAL_SERVER_ERROR) + + # GET QUESTION INFOS TO QUESTION NR + # test with : {"userid": "{userid}", "question_nr": 1, question_type_id": 1, "request_type": "get"} if request_type == 'get': - # Versuche, die Interviewdaten für den Benutzer abzurufen try: - #answers = Answers.objects.get(userid__userid=userid) - #serializer = AnswersSerializer(answers) - #return Response(serializer.data) answers = Answers.objects.get(userid__userid=userid) - # Annahme: data ist ein JSONField, das `interview_config` enthält interview_config = answers.data.get('interview_config', {}) - # Zugriff auf das entsprechende Element wie A1, A2, usw. data = interview_config.get(f'A{question_nr}', None) if data is None: return Response({'error': f'Keine Daten gefunden für Frage A{question_nr}.'}, status=status.HTTP_404_NOT_FOUND) @@ -117,7 +147,9 @@ def post(self, request): serializer = AnswersSerializer(answers) return Response(serializer.data, status=status.HTTP_201_CREATED) - elif request_type == 'post': + # POST SELECTED ANSWERS TO DATA + # test with : {"userid": "{userid}", "question_nr": 1, question_type_id": 1, "request_type": "post", "dataToPost": ["Mathe", "Biologie", "Chemie"] } + if request_type == 'post': if data_to_post is None: return Response({'error': 'Keine neuen Daten bereitgestellt.'}, status=status.HTTP_400_BAD_REQUEST) @@ -150,7 +182,6 @@ def post(self, request): # gibt die jeweiligen daten zur question mit questionNR zurück # Post: /interviwedetais/{userid}/{questionNR} speichert die Antworten in data # Beispielpost : { "new_data": ["Mathe", "Biologie", "Chemie"] } - class AnswersDetailAPIView(APIView): def get(self, request, userid, question_number): From ceaacfc6fd732693de9612d9a87ccd4747730a06 Mon Sep 17 00:00:00 2001 From: GeorgiosK78 Date: Thu, 20 Jun 2024 18:17:05 +0200 Subject: [PATCH 18/21] Answers api with instructions in comments --- app/core/views.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/core/views.py b/app/core/views.py index 4ab2628..1f789dc 100644 --- a/app/core/views.py +++ b/app/core/views.py @@ -128,7 +128,7 @@ def post(self, request): return Response({'error': str(e)}, status=status.HTTP_500_INTERNAL_SERVER_ERROR) # GET QUESTION INFOS TO QUESTION NR - # test with : {"userid": "{userid}", "question_nr": 1, question_type_id": 1, "request_type": "get"} + # test with : {"userid": "{userid}", "question_nr": 1, "question_type_id": 1, "request_type": "get"} if request_type == 'get': try: answers = Answers.objects.get(userid__userid=userid) @@ -148,7 +148,7 @@ def post(self, request): return Response(serializer.data, status=status.HTTP_201_CREATED) # POST SELECTED ANSWERS TO DATA - # test with : {"userid": "{userid}", "question_nr": 1, question_type_id": 1, "request_type": "post", "dataToPost": ["Mathe", "Biologie", "Chemie"] } + # test with : {"userid": "{userid}", "question_nr": 1, "question_type_id": 1, "request_type": "post", "dataToPost": ["Mathe", "Biologie", "Chemie"] } if request_type == 'post': if data_to_post is None: return Response({'error': 'Keine neuen Daten bereitgestellt.'}, status=status.HTTP_400_BAD_REQUEST) From 496dba78d89fa2e163f50b0d48d2a1c28310057f Mon Sep 17 00:00:00 2001 From: Sabaawi7 Date: Thu, 20 Jun 2024 19:48:37 +0300 Subject: [PATCH 19/21] added token auth logic for user register, logout, login and view. Also added UserID token as cookie --- app/core/serializers.py | 2 + app/core/urls.py | 15 ++- app/core/views.py | 210 ++++++++++++++++++++------------------- app/core/x_data_utils.py | 1 - requirements.txt | 6 +- 5 files changed, 115 insertions(+), 119 deletions(-) diff --git a/app/core/serializers.py b/app/core/serializers.py index 1dc595b..1f57669 100644 --- a/app/core/serializers.py +++ b/app/core/serializers.py @@ -17,6 +17,8 @@ def create(self, validated_data): instance.set_password(password) instance.save() return instance + + class UserIDListSerializer(serializers.ModelSerializer): class Meta: model=UserIDList diff --git a/app/core/urls.py b/app/core/urls.py index 10b27ef..c8ec1cd 100644 --- a/app/core/urls.py +++ b/app/core/urls.py @@ -2,16 +2,13 @@ from django.urls import path from core.views import * urlpatterns = [ - # path('userid/', useridlist), - path('userid/', UserIDListAPIView.as_view()), - #path('useriddetail/', useridlist_detail), + path('userid', UserIDListAPIView.as_view()), path('useriddetail/', UserIDListDetailsAPIView.as_view()), - #path('answers/', answers), - path('answers/', AnswersAPIView.as_view()), - #path('answersdetail/', answers_detail), + path('answers', AnswersAPIView.as_view()), path('answersdetail/', AnswersDetailsAPIView.as_view()), - path('login', LoginUserView.as_view()), - path('register', RegisterUserView.as_view()), - path('user', UserView.as_view()) + path('login', LoginUserAPIView.as_view()), + path('register', RegisterUserAPIView.as_view()), + path('user', UserView.as_view()), + path('logout', LogoutUserAPIView.as_view()) ] \ No newline at end of file diff --git a/app/core/views.py b/app/core/views.py index ff02a8e..d6d0979 100644 --- a/app/core/views.py +++ b/app/core/views.py @@ -1,153 +1,158 @@ +from functools import partial, update_wrapper from django.shortcuts import render from django.http import HttpResponse from core.models import UserIDList from core.models import Answers -from core.models import User from core.serializers import * from rest_framework.decorators import api_view +from django.utils.decorators import method_decorator from rest_framework.response import Response -from rest_framework.exceptions import AuthenticationFailed from rest_framework import status from rest_framework.views import APIView -<<<<<<< HEAD -import jwt, datetime -======= +from rest_framework.exceptions import AuthenticationFailed from core.x_data_utils import user_id ->>>>>>> main -import uuid +import jwt, datetime # Create your views here. - - - -<<<<<<< HEAD -class RegisterUserView(APIView): +class RegisterUserAPIView(APIView): + @method_decorator(api_view(['POST'])) def post(self, request): + serializer = UserSerializer(data=request.data) - serializer.is_valid(raise_exception=True) - serializer.save() + if serializer.is_valid(): + user = serializer.save() + return Response(serializer.data, status=status.HTTP_201_CREATED) + return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) - return Response(serializer.data) - -class LoginUserView(APIView): +class LoginUserAPIView(APIView): + @method_decorator(api_view(['POST'])) def post(self, request): - email = request.data["email"] - password = request.data["password"] + email = request.data['email'] + password = request.data['password'] user = User.objects.filter(email=email).first() if user is None: - raise AuthenticationFailed("User not found!") - + raise AuthenticationFailed('User not found!') if not user.check_password(password): - raise AuthenticationFailed("Incorrect Password!") - + raise AuthenticationFailed('Incorrect password!') payload = { - "id":user.id, - "exp":datetime.datetime.now() + datetime.timedelta(minutes=60), - "iat":datetime.datetime.now() + 'id': user.id, + 'exp': datetime.datetime.now() + datetime.timedelta(days=1), + 'iat': datetime.datetime.now() } - encoded_token = jwt.encode(payload, "secret", algorithm="HS256") - decoded_token = jwt.decode(encoded_token, "secret", algorithms=["HS256"]) + token = jwt.encode(payload, 'secret', algorithm='HS256') response = Response() - response.set_cookie(key="jwt",value=encoded_token,httponly=True) + response.set_cookie(key='jwt', value=token, httponly=True) response.data = { - "jwt":encoded_token + "message": "login successful" } return response +class LogoutUserAPIView(APIView): + @method_decorator(api_view(['POST'])) + def post(self, request): + response = Response() + response.delete_cookie('jwt') + response.data = { + "message": "logout successful" + } + return response class UserView(APIView): + @method_decorator(api_view(['GET'])) def get(self, request): - token = request.COOKIES.get("jwt") + token = request.COOKIES.get('jwt') if not token: - raise AuthenticationFailed("Unauthenticated") + raise AuthenticationFailed('Unauthenticated!') + try: - payload = jwt.decode(token, "secret", algorithms=["HS256"]) + payload = jwt.decode(token, 'secret', algorithms=['HS256']) except jwt.ExpiredSignatureError: - raise AuthenticationFailed("Unauthenticated") - - user = User.objects.filter(id=payload["id"]) + raise AuthenticationFailed('Unauthenticated!') + + user = User.objects.filter(id=payload['id']).first() serializer = UserSerializer(user) return Response(serializer.data) - -======= ->>>>>>> main class UserIDListAPIView(APIView): + @method_decorator(api_view(['GET'])) + def get(self, request): + users = UserIDList.objects.all() + serializer = UserIDListSerializer(users, many=True) + return Response(serializer.data) + - def get(self, request): - users = UserIDList.objects.all() - serializer = UserIDListSerializer(users, many=True) - return Response(serializer.data) -<<<<<<< HEAD - - def post(self, request): - userIDValue = str(uuid.uuid4()) - request.data["userid"] = userIDValue - serializer=UserIDListSerializer(data=request.data) -======= - - def post(self, request): - # Überprüfen, ob eine UserID in der Anfrage übergeben wurde - if 'userid' in request.data and request.data['userid']: - user_id_value = request.data['userid'] - if UserIDList.objects.filter(userid=user_id_value).exists(): + def post(self, request): + # Überprüfen, ob eine UserID in der Anfrage übergeben wurde + if request.COOKIES.get('UserID'): return Response({"error": "UserID already exists."}, status=status.HTTP_400_BAD_REQUEST) - else: - # Wenn keine UserID übergeben wurde, generiere automatisch eine neue - user_id_value = user_id(action="create") + if ('userid' in request.data and request.data['userid']): + user_id_value = request.data['userid'] + if UserIDList.objects.filter(userid=user_id_value).exists(): + return Response({"error": "UserID already exists."}, status=status.HTTP_400_BAD_REQUEST) + else: + # Wenn keine UserID übergeben wurde, generiere automatisch eine neue + user_id_value = user_id(action="create") + + # Füge die generierte oder übergebene UserID zur Anfrage hinzu + request.data['userid'] = user_id_value + serializer = UserIDListSerializer(data=request.data) + + if serializer.is_valid(): + serializer.save() + payload = { + 'userid': user_id_value, + 'exp': datetime.datetime.now() + datetime.timedelta(minutes=60), + 'iat': datetime.datetime.now() + } + token = jwt.encode(payload, 'secret', algorithm='HS256') + response = Response() + response.set_cookie(key='UserID', value=token, httponly=True) + response.data = { + "message": "UserID created successfully", + "userid": user_id_value + } + return response + else: + return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) - # Füge die generierte oder übergebene UserID zur Anfrage hinzu - request.data['userid'] = user_id_value - serializer = UserIDListSerializer(data=request.data) ->>>>>>> main - - if serializer.is_valid(raise_exception=True): - serializer.save() -<<<<<<< HEAD - return Response(serializer.data, status=status.HTTP_201_CREATED) -======= - return Response(serializer.data, status=status.HTTP_201_CREATED) - else: - return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) - ->>>>>>> main class UserIDListDetailsAPIView(APIView): - def get_object(self,id): - try: - return UserIDList.objects.get(id=id) - except UserIDList.DoesNotExist: - return HttpResponse(status=status.HTTP_404_NOT_FOUND) - - def get(self, request, id): - id=self.get_object(id) - serializer=UserIDListSerializer(id) - return Response(serializer.data) - - def put(self, request, id): + @method_decorator(api_view(['GET'])) + def get_object(self,id): + try: + return UserIDList.objects.get(id=id) + except UserIDList.DoesNotExist: + return HttpResponse(status=status.HTTP_404_NOT_FOUND) + @method_decorator(api_view(['GET'])) + def get(self, request, id): id=self.get_object(id) - serializer=UserIDListSerializer(id,data=request.data) - - if serializer.is_valid(): - serializer.save() - return Response(serializer.data) - return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) - - def delete(self, request, id): - id=self.get_object(id) - id.delete() - return Response(status=status.HTTP_204_NO_CONTENT) - -class AnswersAPIView(APIView): - + serializer=UserIDListSerializer(id) + return Response(serializer.data) + @method_decorator(api_view(['PUT'])) + def put(self, request, id): + id=self.get_object(id) + serializer=UserIDListSerializer(id,data=request.data) + + if serializer.is_valid(): + serializer.save() + return Response(serializer.data) + return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) + @method_decorator(api_view(['DELETE'])) + def delete(self, request, id): + id=self.get_object(id) + id.delete() + return Response(status=status.HTTP_204_NO_CONTENT) + +class AnswersAPIView(APIView): + @method_decorator(api_view(['GET'])) def get(self, request): answers=Answers.objects.all() serializer=AnswersSerializer(answers, many=True) return Response(serializer.data) - + @method_decorator(api_view(['POST'])) def post(self, request): serializer=AnswersSerializer(data=request.data) @@ -267,6 +272,3 @@ def answers_detail(request, pk): elif request.method=='DELETE': answer.delete() return Response(status=status.HTTP_204_NO_CONTENT) - - - \ No newline at end of file diff --git a/app/core/x_data_utils.py b/app/core/x_data_utils.py index 8dad053..82b7c4d 100644 --- a/app/core/x_data_utils.py +++ b/app/core/x_data_utils.py @@ -64,7 +64,6 @@ def user_id(action, request=[], userID="efd69e9c-3945-4885-9a06-c9216efec82b"): elif action == "create": # Erzeuge eine neue UserID userIDValue = str(uuid.uuid4()) # Generiere eine UUID - UserIDList.objects.create(userid=userIDValue) # Speichere die neue UserID in der Datenbank return userIDValue # Gib die neu generierte UserID zurück return None # Falls ein ungültiger action-Wert übergeben wurde, gib None zurück diff --git a/requirements.txt b/requirements.txt index 4f6e2de..58d6500 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,11 +1,7 @@ Django>=3.2.3,<3.3 psycopg2>=2.8.6,<2.9 uWSGI>=2.0.19.1,<2.1 -<<<<<<< HEAD -djangorestframework >= 3.15.1,<3.16 -pyjwt >=2.8.0, <2.8.1 django-cors-headers -======= markdown djangorestframework ->>>>>>> main +pyjwt \ No newline at end of file From 61c5a723bd47869cc408478443e145f6e918835e Mon Sep 17 00:00:00 2001 From: GeorgiosK78 Date: Thu, 20 Jun 2024 21:50:46 +0200 Subject: [PATCH 20/21] falls keine daten vorhanden werden welche erzeugt --- app/core/views.py | 32 +++++++++++++++++--------------- app/core/x_data_utils.py | 16 ++++++++-------- 2 files changed, 25 insertions(+), 23 deletions(-) diff --git a/app/core/views.py b/app/core/views.py index 1f789dc..1cff42a 100644 --- a/app/core/views.py +++ b/app/core/views.py @@ -70,8 +70,9 @@ def delete(self, request, id): return Response(status=status.HTTP_204_NO_CONTENT) -# /interviwedetais/{userid} -# gibt Alle Daten zum thema interview zurück (fragen, antworten, alles) + +# Man muss eine Post anfrage schicken und daten übergeben um Daten zu erhalten +# wie in den beispielen unten erklärt class AnswersAPIView(APIView): def post(self, request): @@ -91,14 +92,22 @@ def post(self, request): if not userid or not question_type_id or not request_type: return Response({'error': 'Erforderliche Parameter fehlen.'}, status=status.HTTP_400_BAD_REQUEST) - # GET CONFIG INFOS + try: + answers = Answers.objects.get(userid__userid=userid) + except Answers.DoesNotExist: + # Wenn keine Daten vorhanden sind, erstelle eine neue Instanz mit Standarddaten + interview_data = get_all_interview_data_db(question_type_id) + user = UserIDList.objects.get(userid=userid) + answers = Answers.objects.create(userid=user, data=interview_data) + +############ GET CONFIG INFOS ############ # test with : {"userid": "{userid}","question_type_id": 1,"request_type": "get"} if request_type == 'get' and not question_nr : answers = Answers.objects.get(userid__userid=userid) interview_config = answers.data.get('interview_config', {}) return Response(interview_config) - # GET SELECTED ANSWERS +############# GET SELECTED ANSWERS ############ # test with : {"userid": "{userid}","question_type_id": 1,"request_type": "getSelectedAnswers"} if request_type == 'getSelectedAnswers' : try: @@ -126,8 +135,8 @@ def post(self, request): except Exception as e: return Response({'error': str(e)}, status=status.HTTP_500_INTERNAL_SERVER_ERROR) - - # GET QUESTION INFOS TO QUESTION NR + +############# GET QUESTION INFOS TO QUESTION NR ############ # test with : {"userid": "{userid}", "question_nr": 1, "question_type_id": 1, "request_type": "get"} if request_type == 'get': try: @@ -147,16 +156,12 @@ def post(self, request): serializer = AnswersSerializer(answers) return Response(serializer.data, status=status.HTTP_201_CREATED) - # POST SELECTED ANSWERS TO DATA +############# POST SELECTED ANSWERS TO DATA ############ # test with : {"userid": "{userid}", "question_nr": 1, "question_type_id": 1, "request_type": "post", "dataToPost": ["Mathe", "Biologie", "Chemie"] } if request_type == 'post': if data_to_post is None: return Response({'error': 'Keine neuen Daten bereitgestellt.'}, status=status.HTTP_400_BAD_REQUEST) - #kann evtl raus hier drunter - if not isinstance(data_to_post, list): - return Response({'error': 'Die neuen Daten müssen eine Liste sein.'}, status=status.HTTP_400_BAD_REQUEST) - # Versuche, die Interviewdaten für den Benutzer abzurufen try: answers = Answers.objects.get(userid__userid=userid) @@ -178,10 +183,7 @@ def post(self, request): -# /interviwedetais/{userid}/{questionNR} -# gibt die jeweiligen daten zur question mit questionNR zurück -# Post: /interviwedetais/{userid}/{questionNR} speichert die Antworten in data -# Beispielpost : { "new_data": ["Mathe", "Biologie", "Chemie"] } + class AnswersDetailAPIView(APIView): def get(self, request, userid, question_number): diff --git a/app/core/x_data_utils.py b/app/core/x_data_utils.py index 5b5bd9d..7b442ae 100644 --- a/app/core/x_data_utils.py +++ b/app/core/x_data_utils.py @@ -280,15 +280,15 @@ def get_programs(my_list=['Management, Economics and Social Science: Gut','Volks return programs, fits def get_all_interview_data_db(question_type_id): - data={"A1": ["Biologie", "Chemie"], - "A2": ["KI ausprobieren", "Mathematische Modelle entwickeln", "Mathe anwenden", "Schwere Matheprobleme lösen", "Programmieren"], + data={"A1": [], + "A2": [], "A3": [], - "A4": "1.0", - "A5": "Manager short-term and ceo long-term", - "A6": "Ich bin ein Problemlöser", - "A7": ["Algorithmen", "Datenanalyse", "IT Projektmanagement", "Start-Up Gründung"], - "A8": ["Auf Englisch und Deutsch studieren"], - "A9": "Ja gerne", + "A4": "", + "A5": "", + "A6": "", + "A7": [], + "A8": [], + "A9": "", "P1": [], "S1": [], "ANALYSIS1": [], From 14f3daef36615dc195acba159996ca390a0bf77b Mon Sep 17 00:00:00 2001 From: Sabaawi7 Date: Fri, 21 Jun 2024 13:03:37 +0300 Subject: [PATCH 21/21] adjusted views.py to be class based --- app/core/views.py | 122 ++++++++-------------------------------------- 1 file changed, 19 insertions(+), 103 deletions(-) diff --git a/app/core/views.py b/app/core/views.py index d6d0979..367738d 100644 --- a/app/core/views.py +++ b/app/core/views.py @@ -14,7 +14,6 @@ import jwt, datetime # Create your views here. class RegisterUserAPIView(APIView): - @method_decorator(api_view(['POST'])) def post(self, request): serializer = UserSerializer(data=request.data) @@ -24,7 +23,6 @@ def post(self, request): return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) class LoginUserAPIView(APIView): - @method_decorator(api_view(['POST'])) def post(self, request): email = request.data['email'] password = request.data['password'] @@ -37,7 +35,7 @@ def post(self, request): raise AuthenticationFailed('Incorrect password!') payload = { 'id': user.id, - 'exp': datetime.datetime.now() + datetime.timedelta(days=1), + 'exp': datetime.datetime.now() + datetime.timedelta(minutes=60), 'iat': datetime.datetime.now() } @@ -50,7 +48,6 @@ def post(self, request): return response class LogoutUserAPIView(APIView): - @method_decorator(api_view(['POST'])) def post(self, request): response = Response() response.delete_cookie('jwt') @@ -59,7 +56,6 @@ def post(self, request): } return response class UserView(APIView): - @method_decorator(api_view(['GET'])) def get(self, request): token = request.COOKIES.get('jwt') @@ -76,7 +72,6 @@ def get(self, request): return Response(serializer.data) class UserIDListAPIView(APIView): - @method_decorator(api_view(['GET'])) def get(self, request): users = UserIDList.objects.all() serializer = UserIDListSerializer(users, many=True) @@ -120,18 +115,17 @@ def post(self, request): class UserIDListDetailsAPIView(APIView): - @method_decorator(api_view(['GET'])) def get_object(self,id): try: return UserIDList.objects.get(id=id) except UserIDList.DoesNotExist: return HttpResponse(status=status.HTTP_404_NOT_FOUND) - @method_decorator(api_view(['GET'])) def get(self, request, id): id=self.get_object(id) + if id.status_code==status.HTTP_404_NOT_FOUND: + return Response({"message": "UserID not found!"}, status=status.HTTP_404_NOT_FOUND) serializer=UserIDListSerializer(id) return Response(serializer.data) - @method_decorator(api_view(['PUT'])) def put(self, request, id): id=self.get_object(id) serializer=UserIDListSerializer(id,data=request.data) @@ -140,27 +134,34 @@ def put(self, request, id): serializer.save() return Response(serializer.data) return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) - @method_decorator(api_view(['DELETE'])) def delete(self, request, id): id=self.get_object(id) id.delete() return Response(status=status.HTTP_204_NO_CONTENT) -class AnswersAPIView(APIView): - @method_decorator(api_view(['GET'])) +class AnswersAPIView(APIView): def get(self, request): - answers=Answers.objects.all() - serializer=AnswersSerializer(answers, many=True) + answers = Answers.objects.all() + serializer = AnswersSerializer(answers, many=True) return Response(serializer.data) - @method_decorator(api_view(['POST'])) + def post(self, request): - serializer=AnswersSerializer(data=request.data) + token = request.COOKIES.get('UserID') + if token: + token = jwt.decode(token, "secret", algorithms=["HS256"]) + userIDint = token["userid"] + try: + user = UserIDList.objects.get(userid=userIDint) + request.data["userid"] = user.id + except UserIDList.DoesNotExist: + return Response({"error": "UserID not found"}, status=status.HTTP_400_BAD_REQUEST) + + serializer = AnswersSerializer(data=request.data) if serializer.is_valid(): serializer.save() return Response(serializer.data, status=status.HTTP_201_CREATED) - return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) - + return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) class AnswersDetailsAPIView(APIView): def get_object(self, id): try: @@ -187,88 +188,3 @@ def delete(self, request, id): answer.delete() return Response(status=status.HTTP_204_NO_CONTENT) -@api_view(['GET', 'POST']) -def useridlist(request): - - if request.method=='GET': - users=UserIDList.objects.all() - print(users) # Debug-Ausgabe der QuerySet-Objekte - serializer=UserIDListSerializer(users, many=True) - print(serializer.data) # Debug-Ausgabe der serialisierten Daten - return Response(serializer.data) - - elif request.method=='POST': - - serializer=UserIDListSerializer(data=request.data) - - if serializer.is_valid(): - serializer.save() - return Response(serializer.data, status=status.HTTP_201_CREATED) - return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) - - -@api_view(['GET', 'POST']) -def answers(request): - - if request.method=='GET': - answers=Answers.objects.all() - print(answers) # Debug-Ausgabe der QuerySet-Objekte - serializer=AnswersSerializer(answers, many=True) - print(serializer.data) # Debug-Ausgabe der serialisierten Daten - return Response(serializer.data) - - elif request.method=='POST': - - serializer=AnswersSerializer(data=request.data) - - if serializer.is_valid(): - serializer.save() - return Response(serializer.data, status=status.HTTP_201_CREATED) - return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) - - -@api_view(['GET', 'POST', 'DELETE']) -def useridlist_detail(request, pk): - try: - id=UserIDList.objects.get(pk=pk) - except UserIDList.DoesNotExist: - return HttpResponse(status=status.HTTP_404_NOT_FOUND) - - if request.method=='GET': - serializer=UserIDListSerializer(id) - return Response(serializer.data) - - elif request.method=='PUT': - - serializer=UserIDListSerializer(id,data=request.data) - if serializer.is_valid(): - serializer.save() - return Response(serializer.data) - return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) - - elif request.method=='DELETE': - id.delete() - return Response(status=status.HTTP_204_NO_CONTENT) - -@api_view(['GET', 'POST', 'DELETE']) -def answers_detail(request, pk): - try: - answer=Answers.objects.get(pk=pk) - except Answers.DoesNotExist: - return HttpResponse(status=status.HTTP_404_NOT_FOUND) - - if request.method=='GET': - serializer=AnswersSerializer(answer) - return Response(serializer.data) - - elif request.method=='PUT': - - serializer=AnswersSerializer(answer,data=request.data) - if serializer.is_valid(): - serializer.save() - return Response(serializer.data) - return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) - - elif request.method=='DELETE': - answer.delete() - return Response(status=status.HTTP_204_NO_CONTENT)