diff --git a/requirements.txt b/requirements.txt index 4599539..6d61030 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,12 +1,22 @@ asgiref==3.4.1 certifi==2021.10.8 +cffi==1.15.0 charset-normalizer==2.0.7 +cryptography==35.0.0 +defusedxml==0.7.1 Django==3.2.9 +django-allauth==0.46.0 django-rest-auth==0.9.5 djangorestframework==3.12.4 idna==3.3 +oauthlib==3.1.1 +pycparser==2.21 +PyJWT==2.3.0 +python-dateutil==2.8.2 +python3-openid==3.2.0 pytz==2021.3 requests==2.26.0 +requests-oauthlib==1.3.0 six==1.16.0 sqlparse==0.4.2 urllib3==1.26.7 diff --git a/teeting_backend/assignment/admin.py b/teeting_backend/assignment/admin.py index 8c38f3f..cd03b46 100644 --- a/teeting_backend/assignment/admin.py +++ b/teeting_backend/assignment/admin.py @@ -1,3 +1,5 @@ from django.contrib import admin - +from .models import Mission, Achievement # Register your models here. +admin.site.register(Mission) +admin.site.register(Achievement) \ No newline at end of file diff --git a/teeting_backend/assignment/apps.py b/teeting_backend/assignment/apps.py index d80b629..488efae 100644 --- a/teeting_backend/assignment/apps.py +++ b/teeting_backend/assignment/apps.py @@ -4,3 +4,6 @@ class AssignmentConfig(AppConfig): default_auto_field = 'django.db.models.BigAutoField' name = 'assignment' + def ready(self) -> None: + import assignment.signals + return super().ready() diff --git a/teeting_backend/assignment/migrations/0001_initial.py b/teeting_backend/assignment/migrations/0001_initial.py new file mode 100644 index 0000000..c2dcceb --- /dev/null +++ b/teeting_backend/assignment/migrations/0001_initial.py @@ -0,0 +1,32 @@ +import datetime +from django.db import migrations, models + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + ] + + operations = [ + migrations.CreateModel( + name='Achievement', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('level', models.IntegerField(choices=[(1, 'level1'), (2, 'level2'), (3, 'level3'), (4, 'level4'), (5, 'level5'), (6, 'level6'), (7, 'level7'), (8, 'level8'), (9, 'level9')])), + ('score', models.IntegerField(default=0)), + ], + ), + migrations.CreateModel( + name='Mission', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('begDate', models.DateTimeField(default=datetime.datetime.now)), + ('expDate', models.DateTimeField(default=datetime.datetime.now)), + ('status', models.IntegerField(choices=[(0, 'fail'), (1, 'success'), (2, 'doing'), (3, 'finished')], default=2)), + ('content', models.CharField(max_length=200)), + ('reward', models.IntegerField()), + ], + ), + ] diff --git a/teeting_backend/finance/migrations/0002_initial.py b/teeting_backend/assignment/migrations/0002_initial.py similarity index 53% rename from teeting_backend/finance/migrations/0002_initial.py rename to teeting_backend/assignment/migrations/0002_initial.py index 949af71..900d96a 100644 --- a/teeting_backend/finance/migrations/0002_initial.py +++ b/teeting_backend/assignment/migrations/0002_initial.py @@ -1,4 +1,4 @@ -# Generated by Django 3.2.9 on 2021-11-16 11:53 +# Generated by Django 3.2.9 on 2021-11-22 05:37 from django.conf import settings from django.db import migrations, models @@ -10,24 +10,25 @@ class Migration(migrations.Migration): initial = True dependencies = [ - ('finance', '0001_initial'), + ('ttAccount', '0001_initial'), + ('assignment', '0001_initial'), migrations.swappable_dependency(settings.AUTH_USER_MODEL), ] operations = [ migrations.AddField( - model_name='transaction', - name='user', - field=models.ForeignKey(default=1, on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL), + model_name='mission', + name='child', + field=models.ForeignKey(default=1, on_delete=django.db.models.deletion.CASCADE, related_name='mission', to='ttAccount.child'), ), migrations.AddField( - model_name='balance', - name='currentUser', - field=models.OneToOneField(default=1, on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL), + model_name='mission', + name='parent', + field=models.ForeignKey(default=1, on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL), ), migrations.AddField( - model_name='analysis', - name='transaction', - field=models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, to='finance.transaction'), + model_name='achievement', + name='child', + field=models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, related_name='achievement_child', to='ttAccount.child'), ), ] diff --git a/teeting_backend/assignment/migrations/0003_alter_achievement_level.py b/teeting_backend/assignment/migrations/0003_alter_achievement_level.py new file mode 100644 index 0000000..f9b2327 --- /dev/null +++ b/teeting_backend/assignment/migrations/0003_alter_achievement_level.py @@ -0,0 +1,18 @@ +# Generated by Django 3.2.9 on 2021-11-22 07:26 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('assignment', '0002_initial'), + ] + + operations = [ + migrations.AlterField( + model_name='achievement', + name='level', + field=models.IntegerField(choices=[(1, 'level1'), (2, 'level2'), (3, 'level3'), (4, 'level4'), (5, 'level5'), (6, 'level6'), (7, 'level7'), (8, 'level8'), (9, 'level9')], default=1), + ), + ] diff --git a/teeting_backend/assignment/models.py b/teeting_backend/assignment/models.py index 71a8362..9e06360 100644 --- a/teeting_backend/assignment/models.py +++ b/teeting_backend/assignment/models.py @@ -1,3 +1,43 @@ from django.db import models - +from django.db.models.deletion import CASCADE +from django.urls.resolvers import _PATH_PARAMETER_COMPONENT_RE +from ttAccount.models import User, Child +from datetime import datetime # Create your models here. + +class Mission(models.Model): + STATUS = ( + (0, 'fail'), # 기한이 지나서 실패 + (1, 'success'), # 미션 성공, 송금하지 않은 상태 + (2, 'doing'), # 미션 진행중 + (3, 'finished') # 성공 후 송금 완료 + ) + parent = models.ForeignKey(User, on_delete=CASCADE, default=1) + child = models.ForeignKey(Child, on_delete=CASCADE, related_name='mission', default=1) + begDate = models.DateTimeField(default=datetime.now) + expDate = models.DateTimeField(default=datetime.now) + status = models.IntegerField(default=2, choices=STATUS) + content = models.CharField(max_length=200) + reward = models.IntegerField() + + def __str__(self): + return self.content + +class Achievement(models.Model): + LEVEL_CHOICES = ( + (1, 'level1'), + (2, 'level2'), + (3, 'level3'), + (4, 'level4'), + (5, 'level5'), + (6, 'level6'), + (7, 'level7'), + (8, 'level8'), + (9, 'level9') + ) + child = models.OneToOneField(Child, on_delete=CASCADE, related_name='achievement_child') + level = models.IntegerField(choices=LEVEL_CHOICES, default=1) + score = models.IntegerField(default=0) + + def __str__(self): + return self.child.firstname + ' score' diff --git a/teeting_backend/assignment/serializers.py b/teeting_backend/assignment/serializers.py new file mode 100644 index 0000000..049fe79 --- /dev/null +++ b/teeting_backend/assignment/serializers.py @@ -0,0 +1,13 @@ +from django.db import models +from django.db.models import fields +from rest_framework import serializers +from .models import Mission, Achievement + +class MissionSerializer(serializers.ModelSerializer): + class Meta: + model = Mission + fields = '__all__' +class AchievementSerializer(serializers.ModelSerializer): + class Meta: + model = Achievement + fields = '__all__' \ No newline at end of file diff --git a/teeting_backend/assignment/signals.py b/teeting_backend/assignment/signals.py new file mode 100644 index 0000000..8855acd --- /dev/null +++ b/teeting_backend/assignment/signals.py @@ -0,0 +1,55 @@ +from django.db.models.signals import post_save +from django.core.signals import request_started +from django.db.models import F +from django.dispatch import receiver +from .models import Mission, Achievement +from datetime import datetime +# mission이 finished (& transferred..?) 되면 achievement의 score가 update +# achievement의 score가 update되면 achievement의 level이 update +@receiver(post_save, sender=Mission) +def update_achievement_score(sender, **kwargs): + childid = kwargs['instance'].child_id + status = kwargs['instance'].status + reward = kwargs['instance'].reward + try: + if status == 3: + Achievement.objects.filter(child_id=childid).update(score=F('score') + (reward * 0.01)) + except: + pass +@receiver(post_save, sender=Achievement) +def update_achievement_level(sender, **kwargs): + childid = kwargs['instance'].child_id + score = kwargs['instance'].score + try: + if score < 500: + Achievement.objects.filter(child_id=childid).update(level=1) + elif score < 1000: + Achievement.objects.filter(child_id=childid).update(level=2) + elif score < 1500: + Achievement.objects.filter(child_id=childid).update(level=3) + elif score < 2000: + Achievement.objects.filter(child_id=childid).update(level=4) + elif score < 2500: + Achievement.objects.filter(child_id=childid).update(level=5) + elif score < 3000: + Achievement.objects.filter(child_id=childid).update(level=6) + elif score < 3500: + Achievement.objects.filter(child_id=childid).update(level=7) + elif score < 4000: + Achievement.objects.filter(child_id=childid).update(level=8) + else: + Achievement.objects.filter(child_id=childid).update(level=9) + except: + pass + +# 현재 접근 시간보다 mission의 expDate가 이전이면 status를 fail로 +@receiver(request_started) +def date_expire(sender, **kwargs): + current = datetime.now().date() + try: + for mission in list(Mission.objects.all()): + if mission.status == 2 and mission.expDate.date() < current: + mission.status = 0 #fail + mission.save() + except: + print('error') \ No newline at end of file diff --git a/teeting_backend/assignment/urls.py b/teeting_backend/assignment/urls.py new file mode 100644 index 0000000..e502492 --- /dev/null +++ b/teeting_backend/assignment/urls.py @@ -0,0 +1,12 @@ +from rest_framework import routers, urlpatterns +from rest_framework.routers import DefaultRouter +from django.urls import path, include +from assignment import views + +router = DefaultRouter() +router.register(r'mission', views.MissionViewSet, basename='mission') +router.register(r'achievement', views.AchievementViewSet, basename='achievement') + +urlpatterns = [ + path('', include(router.urls)) +] \ No newline at end of file diff --git a/teeting_backend/assignment/views.py b/teeting_backend/assignment/views.py index 91ea44a..c1bbf25 100644 --- a/teeting_backend/assignment/views.py +++ b/teeting_backend/assignment/views.py @@ -1,3 +1,56 @@ +from django.http import request from django.shortcuts import render +from rest_framework.permissions import IsAuthenticated +from rest_framework.authentication import TokenAuthentication +from rest_framework import viewsets + +from ttAccount.models import Child +from .models import Mission, Achievement +from .serializers import MissionSerializer, AchievementSerializer # Create your views here. + +class MissionViewSet(viewsets.ModelViewSet): + permission_classes = [IsAuthenticated] + authentication_classes = [TokenAuthentication] + queryset = Mission.objects.all() + serializer_class = MissionSerializer + #해당 child에 대해서만 나오게 하려면 + + def get_queryset(self): + qs = super().get_queryset() + if self.request.method == "GET": + if self.request.user.is_authenticated : # 로그인 유무 + childid = self.request.query_params.get("childId", None) + # childid가 존재하고 현재 로그인 된 유저의 자식일때만 반영 + if childid is not None and Child.objects.filter(id=childid).first().parent == self.request.user: + qs = Mission.objects.filter(child_id=childid) + else: + qs = qs.none() + else: + qs = qs.none() + return qs + + def update(self, request, *args, **kwargs): + kwargs['partial'] = True + return super().update(request, *args, **kwargs) + + +class AchievementViewSet(viewsets.ModelViewSet): + permission_classes = [IsAuthenticated] + authentication_classes = [TokenAuthentication] + queryset = Achievement.objects.all() + serializer_class = AchievementSerializer + + def get_queryset(self): + qs = super().get_queryset() + if self.request.user.is_authenticated : # 로그인 유무 + childid = self.request.query_params.get("childId", None) + # childid가 존재하고 현재 로그인 된 유저의 자식일때만 반영 + if childid is not None and Child.objects.filter(id=childid).first().parent == self.request.user: + qs = Achievement.objects.filter(child_id=childid) + else: + qs = qs.none() + else: + qs = qs.none() + return qs diff --git a/teeting_backend/finance/migrations/0001_initial.py b/teeting_backend/finance/migrations/0001_initial.py index dbd72c4..2cffadc 100644 --- a/teeting_backend/finance/migrations/0001_initial.py +++ b/teeting_backend/finance/migrations/0001_initial.py @@ -1,4 +1,5 @@ -# Generated by Django 3.2.9 on 2021-11-16 11:53 +# Generated by Django 3.2.9 on 2021-11-22 05:37 + import django.core.validators from django.db import migrations, models @@ -16,27 +17,11 @@ class Migration(migrations.Migration): name='Analysis', fields=[ ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('category', models.CharField(max_length=200)), - ], - ), - migrations.CreateModel( - name='Balance', - fields=[ - ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('balance', models.IntegerField(default=0)), - ], - ), - migrations.CreateModel( - name='Transaction', - fields=[ - ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('trdd', models.CharField(max_length=8)), - ('txtm', models.CharField(max_length=6)), - ('mnrcDrotDsnc', models.IntegerField(validators=[django.core.validators.MinValueValidator(1), django.core.validators.MaxValueValidator(4)])), + ('date', models.DateField()), ('tram', models.IntegerField(validators=[django.core.validators.MinValueValidator(0)])), - ('aftrBlnc', models.IntegerField()), ('bnprCntn', models.TextField()), ('tuno', models.IntegerField()), + ('category', models.IntegerField(choices=[(0, '식비'), (1, '교통비'), (2, '문화생활비'), (3, '기타')], default=0)), ], ), ] diff --git a/teeting_backend/finance/migrations/0002_analysis_child.py b/teeting_backend/finance/migrations/0002_analysis_child.py new file mode 100644 index 0000000..0863b62 --- /dev/null +++ b/teeting_backend/finance/migrations/0002_analysis_child.py @@ -0,0 +1,22 @@ +# Generated by Django 3.2.9 on 2021-11-22 05:37 + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + ('ttAccount', '0001_initial'), + ('finance', '0001_initial'), + ] + + operations = [ + migrations.AddField( + model_name='analysis', + name='child', + field=models.ForeignKey(default=1, on_delete=django.db.models.deletion.CASCADE, to='ttAccount.child'), + ), + ] diff --git a/teeting_backend/finance/migrations/0003_auto_20211117_1339.py b/teeting_backend/finance/migrations/0003_auto_20211117_1339.py deleted file mode 100644 index 296635f..0000000 --- a/teeting_backend/finance/migrations/0003_auto_20211117_1339.py +++ /dev/null @@ -1,83 +0,0 @@ -# Generated by Django 3.2.9 on 2021-11-17 04:39 - -from django.conf import settings -import django.core.validators -from django.db import migrations, models -import django.db.models.deletion - - -class Migration(migrations.Migration): - - dependencies = [ - migrations.swappable_dependency(settings.AUTH_USER_MODEL), - ('finance', '0002_initial'), - ] - - operations = [ - migrations.RemoveField( - model_name='transaction', - name='user', - ), - migrations.RemoveField( - model_name='analysis', - name='transaction', - ), - migrations.AddField( - model_name='analysis', - name='aftrBlnc', - field=models.IntegerField(default=1), - preserve_default=False, - ), - migrations.AddField( - model_name='analysis', - name='bnprCntn', - field=models.TextField(default=1), - preserve_default=False, - ), - migrations.AddField( - model_name='analysis', - name='child', - field=models.ForeignKey(default=1, on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL), - ), - migrations.AddField( - model_name='analysis', - name='mnrcDrotDsnc', - field=models.IntegerField(default=1, validators=[django.core.validators.MinValueValidator(1), django.core.validators.MaxValueValidator(4)]), - preserve_default=False, - ), - migrations.AddField( - model_name='analysis', - name='tram', - field=models.IntegerField(default=1, validators=[django.core.validators.MinValueValidator(0)]), - preserve_default=False, - ), - migrations.AddField( - model_name='analysis', - name='trdd', - field=models.CharField(default=1, max_length=8), - preserve_default=False, - ), - migrations.AddField( - model_name='analysis', - name='tuno', - field=models.IntegerField(default=1), - preserve_default=False, - ), - migrations.AddField( - model_name='analysis', - name='txtm', - field=models.CharField(default=1, max_length=6), - preserve_default=False, - ), - migrations.AlterField( - model_name='analysis', - name='category', - field=models.IntegerField(choices=[(0, '식비'), (1, '교통비'), (2, '문화생활비'), (3, '기타')], default=0), - ), - migrations.DeleteModel( - name='Balance', - ), - migrations.DeleteModel( - name='Transaction', - ), - ] diff --git a/teeting_backend/finance/models.py b/teeting_backend/finance/models.py index 141d793..dcc8361 100644 --- a/teeting_backend/finance/models.py +++ b/teeting_backend/finance/models.py @@ -1,21 +1,18 @@ from django.core import validators from django.db import models from django.db.models.deletion import CASCADE -from django.utils import translation from ttAccount.models import * from django.core import validators - # Create your models here. # 분석 모델 class Analysis(models.Model) : - # family = models.ForeignKey(Family, on_delete=CASCADE, default=1) - child = models.ForeignKey(User, on_delete=CASCADE, default=1) - trdd = models.CharField(max_length=8) # 거래날짜 - txtm = models.CharField(max_length=6) # 거래시간 - mnrcDrotDsnc = models.IntegerField(validators=[validators.MinValueValidator(1), validators.MaxValueValidator(4)]) # 1,2는 입금 / 3,4는 출금 + child = models.ForeignKey(Child, on_delete=CASCADE, default=1) + date = models.DateField(auto_now=False) # 거래날짜 + # txtm = models.CharField(max_length=6) # 거래시간 + # mnrcDrotDsnc = models.IntegerField(validators=[validators.MinValueValidator(1), validators.MaxValueValidator(4)]) # 1,2는 입금 / 3,4는 출금 tram = models.IntegerField(validators = [validators.MinValueValidator(0)]) # 거래금액 - aftrBlnc = models.IntegerField() # 거래후잔액 + # aftrBlnc = models.IntegerField() # 거래후잔액 bnprCntn = models.TextField() # 통장인자내용 tuno = models.IntegerField() # 거래고유번호 CATEGORIIES = ( @@ -24,4 +21,7 @@ class Analysis(models.Model) : (2, "문화생활비"), (3, "기타") ) - category = models.IntegerField(default=0, choices=CATEGORIIES) \ No newline at end of file + category = models.IntegerField(default=0, choices=CATEGORIIES) + + def __str__(self): + return self.bnprCntn \ No newline at end of file diff --git a/teeting_backend/finance/serializers.py b/teeting_backend/finance/serializers.py index 24448fd..617a3e7 100644 --- a/teeting_backend/finance/serializers.py +++ b/teeting_backend/finance/serializers.py @@ -1,3 +1,4 @@ +from django.core.serializers import serialize from django.db.models import fields from rest_framework import serializers from .models import * @@ -5,4 +6,4 @@ class AnalysisSerializer(serializers.ModelSerializer) : class Meta : model = Analysis - fields = '__all__' \ No newline at end of file + fields = '__all__' diff --git a/teeting_backend/finance/urls.py b/teeting_backend/finance/urls.py index fd9af7e..e406f0a 100644 --- a/teeting_backend/finance/urls.py +++ b/teeting_backend/finance/urls.py @@ -2,21 +2,28 @@ from .views import * -analysis_list = AnalysisViewSet.as_view({ - 'get' : 'list', - 'post' : 'create' -}) +# analysis_list = AnalysisViewSet.as_view({ +# 'get' : 'list', +# 'post' : 'create' +# }) -analysis_detail = AnalysisViewSet.as_view({ - 'get' : 'retrieve', - 'put' : 'update', - 'patch' : 'partial_update', - 'delete' : 'destroy', -}) +# analysis_detail = AnalysisViewSet.as_view({ +# 'get' : 'retrieve', +# 'put' : 'update', +# 'patch' : 'partial_update', +# 'delete' : 'destroy', +# }) urlpatterns = [ - path('analysis/', analysis_list), - path('analysis/', analysis_detail), - path('balance', InquireBalanceView.as_view()), # 잔액조회 + # path('analysis/', analysis_list), + # path('analysis/', analysis_detail), + + + path('analysis', ChildAnalysisView.as_view()), # 자녀분석 조회 ?childId= + path('balance/', ParentBalanceView.as_view()), # 잔액조회 부모 + path('balance/child', ChildBalanceView.as_view()), # 잔액조회 자녀 + # path('transaction', ChildTransactionView.as_view()), # 거래내역조회 자녀 부모 포함?childId=&period= + path('transaction', TransactionView.as_view()), + path('remittance', RemittanceView.as_view()), #송금하기, ?childId= ] \ No newline at end of file diff --git a/teeting_backend/finance/views.py b/teeting_backend/finance/views.py index 2530e3d..6ce1ff0 100644 --- a/teeting_backend/finance/views.py +++ b/teeting_backend/finance/views.py @@ -1,57 +1,340 @@ +from django.utils import datastructures from rest_framework import serializers, viewsets, authentication, status +from rest_framework.exceptions import bad_request from rest_framework.permissions import IsAuthenticated from rest_framework.authentication import TokenAuthentication from rest_framework.views import APIView from .models import * from .serializers import * -from ttAccount.models import User +from ttAccount.models import User, Child import requests import json from datetime import datetime +from dateutil.relativedelta import relativedelta + import random from django.http import HttpResponse # Create your views here. -# 분석작업 기본적인 CRUD 구현 변경 많이많이 필요함 -class AnalysisViewSet(viewsets.ModelViewSet) : +# 잔액조회 (부모) +class ParentBalanceView(APIView) : permission_classes = [IsAuthenticated] authentication_classes = [TokenAuthentication] - queryset = Analysis.objects.all() - serializer_class = AnalysisSerializer + def get(self, request): - def perform_create(self, serializer): - serializer.save(child = self.request.user) + user = User.objects.filter(username = self.request.user).first() + + url = "https://developers.nonghyup.com/InquireBalance.nh" # 잔액 조회 url - def get_queryset(self): - qs = super().get_queryset() + apiNm = url[url.find(".com/")+5 : url.find(".nh")] + tsymd = datetime.today().strftime("%Y%m%d") + trtm = "112428" + iscd = user.iscd + fintechApsno = "001" + apiSvcCd = "ReceivedTransferA" + # isTuno = 임의번호로 채번 + accessToken = user.accessToken + finAcno = user.finAcno + + headers = { + "Content-Type": "application/json; chearset=utf-8", + } - if self.request.user.is_authenticated : - qs = qs.filter(child = self.request.user) + body = { + "Header": { + "ApiNm": apiNm, + "Tsymd": tsymd, + "Trtm": trtm, + "Iscd": iscd, + "FintechApsno": fintechApsno, + "ApiSvcCd": apiSvcCd, + "IsTuno": "0007773" + str(random.randint(0,10000)), # isTuno + "AccessToken": accessToken + }, + "FinAcno": finAcno + } + + res = requests.post(url, data=json.dumps(body), headers=headers) + data = {} + if res.status_code == 200 : + data["id"] = self.request.user.id + data["username"] = self.request.user.username + data["acno"] = self.request.user.acno + data["balance"] = int(res.json()["Ldbl"]) + return HttpResponse(json.dumps(data), content_type="text/json-comment-filtered", status = status.HTTP_200_OK) else : - qs = qs.none() - return qs + return HttpResponse("No User", res.status_code) + +# 잔액조회 (자녀) +class ChildBalanceView(APIView) : + + permission_classes = [IsAuthenticated] + authentication_classes = [TokenAuthentication] + + def get(self, request): + currentUser = User.objects.filter(username = self.request.user).first() + children = Child.objects.filter(parent = currentUser) + + # 프론트에 response로 줄 json data + data = [] + + # 자녀 수만큼 api 반복 호출 + for i in range(len(children)) : + url = "https://developers.nonghyup.com/InquireBalance.nh" # 잔액 조회 url + apiNm = url[url.find(".com/")+5 : url.find(".nh")] + tsymd = datetime.today().strftime("%Y%m%d") + trtm = "112428" + iscd = children[i].iscd + fintechApsno = "001" + apiSvcCd = "ReceivedTransferA" + # isTuno = 임의번호로 채번 + accessToken = children[i].accessToken + finAcno = children[i].finAcno + + headers = { + "Content-Type": "application/json; chearset=utf-8", + } -# 잔액 조회 GET 버전 -class InquireBalanceView(APIView) : + body = { + "Header": { + "ApiNm": apiNm, + "Tsymd": tsymd, + "Trtm": trtm, + "Iscd": iscd, + "FintechApsno": fintechApsno, + "ApiSvcCd": apiSvcCd, + "IsTuno": "0007773" + str(random.randint(0,10000)), # isTuno + "AccessToken": accessToken + }, + "FinAcno": finAcno + } + + res = requests.post(url, data=json.dumps(body), headers=headers) + children_data = {} + if res.status_code == 200 : + children_data["id"] = children[i].id + children_data["firstname"] = children[i].firstname + children_data["parent"] = children[i].parent.username + children_data["balance"] = int(res.json()["Ldbl"]) + data.append(children_data) + else : + return HttpResponse("No child", res.status_code) + return HttpResponse(json.dumps(data), content_type="text/json-comment-filtered", status = status.HTTP_200_OK) + + +# 거래내역 조회 -> params가 있다면 자녀거래내역 조회 / 없다면 유저(부모)의 거래내역 조회 +class TransactionView(APIView) : permission_classes = [IsAuthenticated] authentication_classes = [TokenAuthentication] - # 부모는 get으로 조회 def get(self, request): + url = 'https://developers.nonghyup.com/InquireTransactionHistory.nh' # 거래내역 조회 url user = User.objects.filter(username = self.request.user).first() + childId = self.request.query_params.get('childId') - url = "https://developers.nonghyup.com/InquireBalance.nh" # 잔액 조회 url + # params로 받은 childId값이 없다면 유저거래내역 조회 + if not childId : + apiNm = url[url.find(".com/")+5:url.find(".nh")] + tsymd = datetime.today().strftime("%Y%m%d") + trtm = "112428" + iscd = user.iscd + fintechApsno = "001" + apiSvcCd = "ReceivedTransferA" + # isTuno = 임의번호로 채번 + accessToken = user.accessToken + bncd = "011" # 농협은행코드 고정값 + acno = user.acno + insymd = (datetime.today() + relativedelta(days=-90)).strftime("%Y%m%d") + ineymd = datetime.today().strftime("%Y%m%d") + trnsDsnc = "A" + lnsq = "DESC" + pageNo = "1" + dmcnt = "100" + + headers = { + "Content-Type": "application/json; chearset=utf-8", + } - apiNm = url[url.find(".com/")+5 : url.find(".nh")] + body = { + "Header": { + "ApiNm": apiNm, + "Tsymd": tsymd, + "Trtm": trtm, + "Iscd": iscd, + "FintechApsno": fintechApsno, + "ApiSvcCd": apiSvcCd, + "IsTuno": "0007773" + str(random.randint(0,10000)), # isTuno + "AccessToken": accessToken + }, + "Bncd": bncd, + "Acno": acno, + "Insymd": insymd, + "Ineymd": ineymd, + "TrnsDsnc": trnsDsnc, + "Lnsq": lnsq, + "PageNo": pageNo, + "Dmcnt": dmcnt + } + + # params로 받은 childId값이 있다면 유저거래내역 조회 + else : + child = Child.objects.filter(parent = user).filter(pk = childId).first() + + apiNm = url[url.find(".com/")+5:url.find(".nh")] + tsymd = datetime.today().strftime("%Y%m%d") + trtm = "112428" + iscd = child.iscd + fintechApsno = "001" + apiSvcCd = "ReceivedTransferA" + # isTuno = 임의번호로 채번 + accessToken = child.accessToken + bncd = "011" # 농협은행코드 고정값 + acno = child.acno + insymd = (datetime.today() + relativedelta(days=-90)).strftime("%Y%m%d") + ineymd = datetime.today().strftime("%Y%m%d") + trnsDsnc = "A" + lnsq = "DESC" + pageNo = "1" + dmcnt = "100" + + headers = { + "Content-Type": "application/json; chearset=utf-8", + } + + body = { + "Header": { + "ApiNm": apiNm, + "Tsymd": tsymd, + "Trtm": trtm, + "Iscd": iscd, + "FintechApsno": fintechApsno, + "ApiSvcCd": apiSvcCd, + "IsTuno": "0007773" + str(random.randint(0,10000)), # isTuno + "AccessToken": accessToken + }, + "Bncd": bncd, + "Acno": acno, + "Insymd": insymd, + "Ineymd": ineymd, + "TrnsDsnc": trnsDsnc, + "Lnsq": lnsq, + "PageNo": pageNo, + "Dmcnt": dmcnt + } + + # 프론트에 response로 줄 json data + data = [] + + res = requests.post(url, data=json.dumps(body), headers=headers) + if res.status_code == 200 : + rec = res.json()["REC"] + + for i in range(len(rec)) : + transactions = {} + transactions["trdd"] = rec[i]["Trdd"] + transactions["txtm"] = rec[i]["Txtm"] + transactions["mnrcDrotDsnc"] = int(rec[i]["MnrcDrotDsnc"]) + transactions["tram"] = int(rec[i]["Tram"]) + transactions["aftrBlnc"] = int(rec[i]["AftrBlnc"]) + transactions["bnprCntn"] = rec[i]["BnprCntn"] + transactions["tuno"] = int(rec[i]["Tuno"]) + data.append(transactions) + return HttpResponse(json.dumps(data), content_type="text/json-comment-filtered", status = status.HTTP_200_OK) + + else : + return HttpResponse("No User or No Child", res.status_code) + + +# 자녀 분석결과 조회 +class ChildAnalysisView(APIView) : + + permission_classes = [IsAuthenticated] + authentication_classes = [TokenAuthentication] + + + def get(self, request): + + # 프론트에 response로 줄 json data + data = {} + childId = self.request.query_params.get('childId') + child = Child.objects.filter(pk = childId).first() + period = self.request.query_params.get('period') + + if not child : + return HttpResponse("You don't have such child", status=status.HTTP_400_BAD_REQUEST) + + # 필터링할 날짜 범위 지정 + if period == "week" : + start_date = datetime.now().date() + relativedelta(days=-7) + elif period == "month" : + start_date = datetime.now().date() + relativedelta(months=-1) + elif period == "semiannual" : + start_date = datetime.now().date() + relativedelta(months=-6) + elif period == "annual" : + start_date = datetime.now().date() + relativedelta(years=-1) + else : + return HttpResponse("Period is uncorrect", status=status.HTTP_400_BAD_REQUEST) + + spending = Analysis.objects.filter(child = child).filter(date__range = [start_date, datetime.now().date()]) + + + # initializing + food = 0 # 0번 카테고리 + transportation = 0 # 1번 카테고리 + hobby = 0 # 2번 카테고리 + etc = 0 # 3번 카테고리 + + for i in range(len(spending)) : + if spending[i].category == 0 : + food += spending[i].tram + + elif spending[i].category == 1 : + transportation += spending[i].tram + + elif spending[i].category == 2 : + hobby += spending[i].tram + + elif spending[i].category == 3 : + etc += spending[i].tram + + data["food"] = food + data["transportation"] = transportation + data["hobby"] = hobby + data["etc"] = etc + data["total"] = food + transportation + hobby + etc + + if self.request.user.is_authenticated : + return HttpResponse(json.dumps(data), content_type="text/json-comment-filtered", status=status.HTTP_200_OK) + else : + return HttpResponse(status=status.HTTP_400_BAD_REQUEST) + + + +class RemittanceView(APIView): + permission_classes = [IsAuthenticated] + authentication_classes = [TokenAuthentication] + + def post(self, request): + + user = User.objects.filter(username = self.request.user).first() + childid = self.request.query_params.get("childId", None) + if childid is not None: + child = Child.objects.filter(id=childid).first() + else: + return HttpResponse(status=status.HTTP_400_BAD_REQUEST) + + url_drawing = "https://developers.nonghyup.com/DrawingTransfer.nh" # 출금 이체 url + + apiNm = url_drawing[url_drawing.find(".com/")+5 : url_drawing.find(".nh")] tsymd = datetime.today().strftime("%Y%m%d") trtm = "112428" iscd = user.iscd @@ -60,7 +343,9 @@ def get(self, request): # isTuno = 임의번호로 채번 accessToken = user.accessToken finAcno = user.finAcno - + tram = self.request.POST['tram'] + dractOtlt = child.lastname + child.firstname #출금인자내용 + headers = { "Content-Type": "application/json; chearset=utf-8", } @@ -73,20 +358,58 @@ def get(self, request): "Iscd": iscd, "FintechApsno": fintechApsno, "ApiSvcCd": apiSvcCd, - "IsTuno": "0007770", # isTuno + "IsTuno": "0007773" + str(random.randint(0,10000)), # isTuno "AccessToken": accessToken }, - "FinAcno": finAcno + "FinAcno": finAcno, + "Tram" : tram, + "DractOtlt" : dractOtlt } - - res = requests.post(url, data=json.dumps(body), headers=headers) + res = requests.post(url_drawing, data=json.dumps(body), headers=headers) if res.status_code == 200 : - print(res.json()["Ldbl"]) - return HttpResponse(res.json()["Ldbl"], status = status.HTTP_200_OK) - else : - return HttpResponse(res.status_code) - - + #출금성공, 입금 + url_receive = "https://developers.nonghyup.com/ReceivedTransferAccountNumber.nh" # 출금 이체 url + apiNm = url_receive[url_receive.find(".com/")+5 : url_receive.find(".nh")] + tsymd = datetime.today().strftime("%Y%m%d") + trtm = "112428" + iscd = child.iscd + fintechApsno = "001" + apiSvcCd = "ReceivedTransferA" + # isTuno = 임의번호로 채번 + accessToken = child.accessToken + bncd = "011" + acno = child.acno + tram = self.request.POST['tram'] + dractOtlt = child.lastname + child.firstname #출금인자내용 + mractOtlt = user.username + headers = { + "Content-Type": "application/json; chearset=utf-8", + } + body = { + "Header": { + "ApiNm": apiNm, + "Tsymd": tsymd, + "Trtm": trtm, + "Iscd": iscd, + "FintechApsno": fintechApsno, + "ApiSvcCd": apiSvcCd, + "IsTuno": "0007773" + str(random.randint(0,10000)), # isTuno + "AccessToken": accessToken + }, + "Bncd" : bncd, + "Acno" : acno, + "Tram" : tram, + "DractOtlt" : dractOtlt, + "MractOtlt" : mractOtlt + } + res = requests.post(url_receive, data=json.dumps(body), headers=headers) + if res.status_code == 200 : + return HttpResponse("remittance successed", status = status.HTTP_200_OK) + else: + return HttpResponse("drawed but not transferred error", res.status_code) #출금은 되었는데 입금이 안됨.... 나중에 핸들링 필요 + else : + #출금실패 + return HttpResponse("not drawed",res.status_code) diff --git a/teeting_backend/my_settings.py b/teeting_backend/my_settings.py new file mode 100644 index 0000000..3993876 --- /dev/null +++ b/teeting_backend/my_settings.py @@ -0,0 +1,11 @@ +DATABASES = { + 'default' : { + 'ENGINE' : 'django.db.backends.mysql', + 'NAME' : 'teenting_db', + 'USER' : 'root', + 'PASSWORD' : 'password', + 'HOST' : 'localhost', + 'PORT' : '3306', + } +} +SECRET_KEY = 'django-insecure-ekox3y18$=_o!eeh&qx47dxy&t8+(f_avmzj=too-3mt^+=ng*' \ No newline at end of file diff --git a/teeting_backend/teeting_backend/settings.py b/teeting_backend/teeting_backend/settings.py index 3a25546..10e5d04 100644 --- a/teeting_backend/teeting_backend/settings.py +++ b/teeting_backend/teeting_backend/settings.py @@ -11,6 +11,7 @@ """ from pathlib import Path +import my_settings # Build paths inside the project like this: BASE_DIR / 'subdir'. BASE_DIR = Path(__file__).resolve().parent.parent @@ -20,12 +21,14 @@ # See https://docs.djangoproject.com/en/3.2/howto/deployment/checklist/ # SECURITY WARNING: keep the secret key used in production secret! -SECRET_KEY = 'django-insecure-ekox3y18$=_o!eeh&qx47dxy&t8+(f_avmzj=too-3mt^+=ng*' - +# SECRET_KEY = 'django-insecure-ekox3y18$=_o!eeh&qx47dxy&t8+(f_avmzj=too-3mt^+=ng*' +SECRET_KEY = my_settings.SECRET_KEY # SECURITY WARNING: don't run with debug turned on in production! DEBUG = True -ALLOWED_HOSTS = [] +ALLOWED_HOSTS = [ + '3.37.71.54' +] # Application definition @@ -37,6 +40,7 @@ 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', + #'django.contrib.sites' # app 추가 'ttAccount', @@ -46,6 +50,13 @@ 'rest_framework', 'rest_auth', 'rest_framework.authtoken', + + 'django.contrib.sites', #회원가입 + 'allauth', + 'allauth.account', + 'allauth.socialaccount', + 'rest_auth.registration', + ] MIDDLEWARE = [ @@ -81,13 +92,15 @@ # Database # https://docs.djangoproject.com/en/3.2/ref/settings/#databases - +''' DATABASES = { 'default': { 'ENGINE': 'django.db.backends.sqlite3', 'NAME': BASE_DIR / 'db.sqlite3', } } +''' +DATABASES = my_settings.DATABASES # Password validation @@ -133,4 +146,16 @@ DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField' -AUTH_USER_MODEL = 'ttAccount.User' \ No newline at end of file +AUTH_USER_MODEL = 'ttAccount.User' + +REST_FRAMEWORK = { + 'DEFAULT_PERMISSION_CLASSES': ( + 'rest_framework.permissions.IsAuthenticated', + ), + 'DEFAULT_AUTHENTICATION_CLASSES': ( + 'rest_framework.authentication.TokenAuthentication', + #'rest_framework.authentication.SessionAuthentication', + ) +} + +SITE_ID = 1 \ No newline at end of file diff --git a/teeting_backend/teeting_backend/urls.py b/teeting_backend/teeting_backend/urls.py index 9a1cb94..ef4aa23 100644 --- a/teeting_backend/teeting_backend/urls.py +++ b/teeting_backend/teeting_backend/urls.py @@ -15,7 +15,17 @@ """ from django.contrib import admin from django.urls import path, include +from rest_framework import urls +from rest_auth import urls +from django.conf import settings +from assignment import urls urlpatterns = [ path('admin/', admin.site.urls), + path('api-auth/', include("rest_framework.urls")), + # path('api/rest-auth/', include('rest_auth.urls')), + path('api/assignment/', include('assignment.urls')), + path('api/ttAccount/', include('ttAccount.urls')), + path('api/finance/', include('finance.urls')), + ] diff --git a/teeting_backend/ttAccount/admin.py b/teeting_backend/ttAccount/admin.py index 28a1201..3344b47 100644 --- a/teeting_backend/ttAccount/admin.py +++ b/teeting_backend/ttAccount/admin.py @@ -1,6 +1,6 @@ from django.contrib import admin -from .models import User, Family +from .models import User, Child # Register your models here. admin.site.register(User) -admin.site.register(Family) +admin.site.register(Child) \ No newline at end of file diff --git a/teeting_backend/ttAccount/migrations/0001_initial.py b/teeting_backend/ttAccount/migrations/0001_initial.py index f624b14..da92037 100644 --- a/teeting_backend/ttAccount/migrations/0001_initial.py +++ b/teeting_backend/ttAccount/migrations/0001_initial.py @@ -1,11 +1,11 @@ -# Generated by Django 3.2.9 on 2021-11-16 11:53 +# Generated by Django 3.2.9 on 2021-11-22 05:37 + from django.conf import settings -import django.contrib.auth.models -import django.contrib.auth.validators from django.db import migrations, models import django.db.models.deletion import django.utils.timezone +import ttAccount.models class Migration(migrations.Migration): @@ -24,38 +24,40 @@ class Migration(migrations.Migration): ('password', models.CharField(max_length=128, verbose_name='password')), ('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')), - ('username', models.CharField(error_messages={'unique': 'A user with that username already exists.'}, help_text='Required. 150 characters or fewer. Letters, digits and @/./+/-/_ only.', max_length=150, unique=True, validators=[django.contrib.auth.validators.UnicodeUsernameValidator()], verbose_name='username')), - ('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')), - ('email', models.EmailField(blank=True, max_length=254, verbose_name='email address')), - ('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')), - ('birthday', models.CharField(max_length=8)), - ('isParent', models.BooleanField(default=False)), - ('finAcno', models.CharField(max_length=200)), - ('finCard', models.CharField(max_length=200)), - ('acno', models.CharField(max_length=100)), - ('iscd', models.CharField(max_length=20)), - ('accessToken', models.CharField(max_length=200)), + ('username', models.CharField(max_length=30, unique=True)), + ('firstname', models.CharField(max_length=30)), + ('lastname', models.CharField(max_length=30)), + ('is_staff', models.BooleanField(default=False)), + ('is_active', models.BooleanField(default=True)), + ('date_joined', models.DateTimeField(default=django.utils.timezone.now)), + ('finAcno', models.CharField(blank=True, max_length=200, null=True)), + ('acno', models.CharField(blank=True, max_length=100, null=True)), + ('iscd', models.CharField(blank=True, max_length=20, null=True)), + ('accessToken', models.CharField(blank=True, max_length=200, 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='user_set', related_query_name='user', to='auth.Group', verbose_name='groups')), ('user_permissions', models.ManyToManyField(blank=True, help_text='Specific permissions for this user.', related_name='user_set', related_query_name='user', to='auth.Permission', verbose_name='user permissions')), ], options={ 'verbose_name': 'user', 'verbose_name_plural': 'users', - 'abstract': False, + 'swappable': 'AUTH_USER_MODEL', }, managers=[ - ('objects', django.contrib.auth.models.UserManager()), + ('objects', ttAccount.models.UserManager()), ], ), migrations.CreateModel( - name='Family', + name='Child', fields=[ ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('child', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='family_child', to=settings.AUTH_USER_MODEL)), - ('parent', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='family_parent', to=settings.AUTH_USER_MODEL)), + ('firstname', models.CharField(max_length=20)), + ('lastname', models.CharField(max_length=20)), + ('birthday', models.CharField(max_length=8)), + ('finAcno', models.CharField(max_length=200)), + ('acno', models.CharField(max_length=100)), + ('iscd', models.CharField(max_length=20)), + ('accessToken', models.CharField(max_length=200)), + ('parent', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)), ], ), ] diff --git a/teeting_backend/ttAccount/migrations/0002_user_birthda.py b/teeting_backend/ttAccount/migrations/0002_user_birthda.py new file mode 100644 index 0000000..39abdf8 --- /dev/null +++ b/teeting_backend/ttAccount/migrations/0002_user_birthda.py @@ -0,0 +1,19 @@ +# Generated by Django 3.2.9 on 2021-11-22 10:32 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('ttAccount', '0001_initial'), + ] + + operations = [ + migrations.AddField( + model_name='user', + name='birthda', + field=models.CharField(default=19990221, max_length=8), + preserve_default=False, + ), + ] diff --git a/teeting_backend/ttAccount/migrations/0003_rename_birthda_user_birthday.py b/teeting_backend/ttAccount/migrations/0003_rename_birthda_user_birthday.py new file mode 100644 index 0000000..363bff2 --- /dev/null +++ b/teeting_backend/ttAccount/migrations/0003_rename_birthda_user_birthday.py @@ -0,0 +1,18 @@ +# Generated by Django 3.2.9 on 2021-11-22 10:32 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('ttAccount', '0002_user_birthda'), + ] + + operations = [ + migrations.RenameField( + model_name='user', + old_name='birthda', + new_name='birthday', + ), + ] diff --git a/teeting_backend/ttAccount/models.py b/teeting_backend/ttAccount/models.py index d01f0b9..6b5b83f 100644 --- a/teeting_backend/ttAccount/models.py +++ b/teeting_backend/ttAccount/models.py @@ -1,17 +1,85 @@ from django.db import models from django.contrib.auth.models import AbstractUser +from django.db.models.deletion import CASCADE +from django.db.models.fields import related +from django.contrib.auth.base_user import AbstractBaseUser, BaseUserManager +from django.contrib.auth.models import PermissionsMixin +from django.utils import timezone + # Create your models here. -class User(AbstractUser): +# class User(AbstractUser): +# birthday = models.CharField(max_length=8) +# finAcno = models.CharField(max_length=200) #핀어카운트 +# acno = models.CharField(max_length=100) #계좌 +# iscd =models.CharField(max_length=20) #기관번호 +# accessToken = models.CharField(max_length=200) #토큰 + + +class UserManager(BaseUserManager): + use_in_migrations = True + + def _create_user(self, username, password, **extra_fields): + if not username : + raise ValueError('Username must be set') + user = self.model(username = username, **extra_fields) + user.set_password(password) + user.save(using=self._db) + return user + + def create_user(self, username=None, password=None, **extra_fields): + extra_fields.setdefault('is_staff', False) + extra_fields.setdefault('is_superuser', False) + return self._create_user(username, password, **extra_fields) + + def create_superuser(self, username, password, **extra_fields): + extra_fields.setdefault('is_staff', True) + extra_fields.setdefault('is_superuser', True) + + if extra_fields.get('is_staff') is not True: + raise ValueError('Superuser must have is_staff=True.') + if extra_fields.get('is_superuser') is not True: + raise ValueError('Superuser must have is_superuser=True.') + + return self._create_user(username, password, **extra_fields) + +class User(AbstractBaseUser, PermissionsMixin) : + + username = models.CharField(max_length=30, unique=True) + firstname = models.CharField(max_length=30) + lastname = models.CharField(max_length=30) + birthday = models.CharField(max_length=8) + + is_staff = models.BooleanField(default=False) + is_active = models.BooleanField(default=True) + date_joined = models.DateTimeField(default=timezone.now) + + finAcno = models.CharField(max_length=200, null=True, blank=True) #핀어카운트 + acno = models.CharField(max_length=100, null=True, blank=True) #계좌 + iscd =models.CharField(max_length=20, null=True, blank=True) #기관번호 + accessToken = models.CharField(max_length=200, null=True, blank=True) #토큰 + + objects = UserManager() + + USERNAME_FIELD = 'username' + REQUIRED_FIELD = ['username'] + + class Meta: + verbose_name = 'user' + verbose_name_plural = 'users' + swappable = 'AUTH_USER_MODEL' + + + +class Child(models.Model): + firstname = models.CharField(max_length=20) + lastname = models.CharField(max_length=20) + parent = models.ForeignKey(User, on_delete=CASCADE) birthday = models.CharField(max_length=8) - isParent = models.BooleanField(default=False) finAcno = models.CharField(max_length=200) - finCard = models.CharField(max_length=200) acno = models.CharField(max_length=100) iscd =models.CharField(max_length=20) accessToken = models.CharField(max_length=200) - -class Family(models.Model): - parent = models.ForeignKey(User, on_delete=models.CASCADE, related_name='family_parent') - child = models.ForeignKey(User, on_delete=models.CASCADE, related_name='family_child') \ No newline at end of file + def __str__(self): + return self.firstname \ No newline at end of file diff --git a/teeting_backend/ttAccount/serializers.py b/teeting_backend/ttAccount/serializers.py new file mode 100644 index 0000000..f506c65 --- /dev/null +++ b/teeting_backend/ttAccount/serializers.py @@ -0,0 +1,19 @@ +from re import L + +from django.db import models +from .models import User, Child +from rest_framework import serializers + +class UserSerializer(serializers.ModelSerializer): + class Meta: + model = User + fields = '__all__' + + +class ChildSerializer(serializers.ModelSerializer) : + class Meta : + model = Child + fields = '__all__' + + + \ No newline at end of file diff --git a/teeting_backend/ttAccount/urls.py b/teeting_backend/ttAccount/urls.py new file mode 100644 index 0000000..ec2efa5 --- /dev/null +++ b/teeting_backend/ttAccount/urls.py @@ -0,0 +1,29 @@ +from django.urls import path +from .views import * +from rest_auth.views import (LoginView, LogoutView) +from rest_auth.registration.views import RegisterView + +user_info = UserInfoViewSet.as_view({ + 'get' : 'list', +}) + +child_list = ChildInfoViewSet.as_view({ + 'get': 'list', +}) + +child_detail = ChildInfoViewSet.as_view({ + 'get': 'retrieve', + 'put': 'update', + 'patch': 'partial_update', + 'delete': 'destroy', +}) + +urlpatterns = [ + + path('user', user_info), + path('child', child_list), + path('child/', child_detail), + path('login', LoginView.as_view()), + path('logout', LogoutView.as_view()), + path('register', RegisterView.as_view()), +] \ No newline at end of file diff --git a/teeting_backend/ttAccount/views.py b/teeting_backend/ttAccount/views.py index 91ea44a..1639cc7 100644 --- a/teeting_backend/ttAccount/views.py +++ b/teeting_backend/ttAccount/views.py @@ -1,3 +1,41 @@ -from django.shortcuts import render +from rest_framework import generics, viewsets +from rest_framework import authentication +from rest_framework.permissions import IsAuthenticated +from rest_framework.authentication import TokenAuthentication -# Create your views here. +from .models import * +from .serializers import * + +class UserInfoViewSet(viewsets.ModelViewSet) : + + permission_classes = [IsAuthenticated] + authentication_classes = [TokenAuthentication] + + queryset = User.objects.all() + serializer_class = UserSerializer + + def get_queryset(self): + qs = super().get_queryset() + + if self.request.user.is_authenticated : + qs = qs.filter(username = self.request.user) + else : + qs = qs.none() + return qs + +class ChildInfoViewSet(viewsets.ModelViewSet) : + + permission_classes = [IsAuthenticated] + authentication_classes = [TokenAuthentication] + + queryset = Child.objects.all() + serializer_class = ChildSerializer + + def get_queryset(self): + qs = super().get_queryset() + + if self.request.user.is_authenticated : + qs = qs.filter(parent = self.request.user) + else : + qs = qs.none() + return qs