Fakultas Ilmu Komputer UI

Commit b2e5b663 authored by Muzaki Azami's avatar Muzaki Azami
Browse files

Pbi 13 progress diet client

parent c0f82ea7
......@@ -11,7 +11,7 @@ pylint:
- pip install -r requirements.txt
when: on_success
script:
- pylint --load-plugins pylint_django --rcfile=./.pylintrc dietela_backend dietela_program dietela_quiz nutritionists authentication payment profile_dietku diet_questionnaire
- pylint --load-plugins pylint_django --rcfile=./.pylintrc dietela_backend dietela_program dietela_quiz nutritionists authentication payment profile_dietku diet_questionnaire diet_progress
UnitTest:
image: python:3.6.5
......@@ -29,7 +29,7 @@ UnitTest:
- coverage erase
- SSLCONF="?sslmode=require"
- echo "$TEST_DATABASE_URL$SSLCONF"
- DATABASE_URL="$TEST_DATABASE_URL$SSLCONF" coverage run --branch --source=dietela_quiz,nutritionists,dietela_program,authentication,payment,profile_dietku,diet_questionnaire manage.py test --keepdb
- DATABASE_URL="$TEST_DATABASE_URL$SSLCONF" coverage run --branch --source=dietela_quiz,nutritionists,dietela_program,authentication,payment,profile_dietku,diet_questionnaire,diet_progress manage.py test --keepdb
- coverage xml -i
- coverage report -m
artifacts:
......
......@@ -16,6 +16,7 @@ class UserAdmin(BaseUserAdmin):
'groups',
'diet_profile',
'nutritionist',
'deadline',
'date_joined',
'is_staff',
'is_active',
......
# Generated by Django 3.1 on 2021-05-29 13:24
from django.db import migrations, models
import django.utils.timezone
class Migration(migrations.Migration):
dependencies = [
('authentication', '0004_auto_20210508_0920'),
]
operations = [
migrations.AddField(
model_name='customuser',
name='first_deadline',
field=models.DateField(default=django.utils.timezone.now),
),
]
# Generated by Django 3.1 on 2021-05-29 15:40
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('authentication', '0005_customuser_first_deadline'),
]
operations = [
migrations.RenameField(
model_name='customuser',
old_name='first_deadline',
new_name='deadline',
),
]
......@@ -14,6 +14,7 @@ class CustomUser(AbstractBaseUser, PermissionsMixin):
is_staff = models.BooleanField(default=False)
is_active = models.BooleanField(default=True)
date_joined = models.DateTimeField(default=timezone.now)
deadline = models.DateField(default=timezone.now)
diet_profile = models.OneToOneField(
DietProfile,
on_delete=models.CASCADE,
......
import datetime
def get_first_deadline(current_date):
time_table = {
'Sunday': 0,
'Saturday': 1,
'Friday': 2,
'Thursday': 3,
'Wednesday': 4,
'Tuesday' : 5,
'Monday' : 6
}
# Hari Senin berikutnya sebagai deadline, jika submit sebelum hari tsb, masuk
# laporan minggu pertama, lebih dari itu, minggu berikut-berikutnya (ditentukan
# dengan get_appropriate_week_num dibawah)
day_difference = time_table[current_date.strftime("%A")] + 8
return current_date + datetime.timedelta(days=day_difference)
def get_appropriate_week_num(user_deadline):
current_date = datetime.date.today()
date_diff = current_date - user_deadline
int_diff = int(date_diff.days)
if int_diff < 0:
return 1
## Mereturn floor dari delta perbedaan hari + 2 sebagai week number
## EX : Jika +2 delta dari deadline pertama berarti dia week kedua
## EX : Jika +16 delta dari deadline pertama berarti dia week keempat
return (int_diff//7) + 2
import datetime
from rest_framework import viewsets, status
from rest_framework.response import Response
from rest_framework.views import APIView
......@@ -12,6 +13,7 @@ from payment.serializers import CartSerializer
from .models import CustomUser
from .serializers import CustomUserDetailsSerializer, CustomLoginSerializer
from .google_utils import validate_google_token
from .utilities import get_first_deadline
class CustomLoginView(LoginView):
serializer_class = CustomLoginSerializer
......@@ -43,6 +45,8 @@ class LinkDataViewSet(viewsets.ViewSet):
user.diet_profile = diet_profile
user.nutritionist = cart.nutritionist
user.deadline = get_first_deadline(datetime.date.today())
user.save()
cart.user = user
......
......@@ -218,3 +218,60 @@ class Complaint(models.IntegerChoices):
COMPLAINT_4 = 4, 'Susah buang air besar dalam 3 hari terakhir'
COMPLAINT_5 = 5, 'Kesulitan mengunyah'
COMPLAINT_6 = 6, 'Kesulitan menelan'
class Changes(models.IntegerChoices):
CHANGES_1 = 1, '1'
CHANGES_2 = 2, '2'
CHANGES_3 = 3, '3'
CHANGES_4 = 4, '4'
CHANGES_5 = 5, '5'
class Hunger(models.IntegerChoices):
CHANGES_1 = 1, '1'
CHANGES_2 = 2, '2'
CHANGES_3 = 3, '3'
CHANGES_4 = 4, '4'
CHANGES_5 = 5, '5'
CHANGES_6 = 6, '6'
CHANGES_7 = 7, '7'
CHANGES_8 = 8, '8'
CHANGES_9 = 9, '9'
CHANGES_10 = 10, '10'
class ConsumptionInOneDay(models.IntegerChoices):
NO_GLASS = 1, '0 gelas'
ONE_GLASS = 2, '1 gelas'
TWO_GLASSES = 3, '2 gelas'
THREE_GLASSES = 4, '3 gelas'
FOUR_GLASSES = 5, '4 gelas'
MORE_GLASSES = 6, 'Lebih dari 4 gelas'
class PhysicalActivity(models.IntegerChoices):
ACTIVITY_1 = 1, 'Hampir tidak pernah olahraga dan/atau duduk lebih dari 9 jam perhari'
ACTIVITY_2 = 2, 'Jalan kaki santai'
ACTIVITY_3 = 3, 'Jalan kaki cepat'
ACTIVITY_4 = 4, 'Pemanasan'
ACTIVITY_5 = 5, 'Naik turun tangga'
ACTIVITY_6 = 6, 'Jogging'
ACTIVITY_7 = 7, 'Treadmill'
ACTIVITY_8 = 8, 'Senam Aerobic/cardio, Recovery/Scratching, Dance dll'
ACTIVITY_9 = 9, 'Latihan penguatan otot (strength workout, weight workout)'
ACTIVITY_10 = 10, 'Other'
class TimeForActivity(models.IntegerChoices):
TIME_1 = 1, '0 - 60 menit'
TIME_2 = 2, '60 - 100 menit'
TIME_3 = 3, '100 - 120 menit'
TIME_4 = 4, '100 - 120 menit'
TIME_5 = 5, '120 - 150 menit'
TIME_6 = 6, '150 - 175 menit'
TIME_7 = 7, '175 - 200 menit'
TIME_8 = 8, '200 - 250 menit'
TIME_9 = 9, 'Lebih dari 250 menit'
class Rating(models.IntegerChoices):
RATING_1 = 1, 'Rasanya mau menyerah saja'
RATING_2 = 2, 'Capek, susah, bosen, males, repot, sibuk'
RATING_3 = 3, 'Biasa aja, meski ada kendala tapi semua bisa diatur'
RATING_4 = 4, 'Lancar terus, semangat cukup stabil, gak ada masalah'
RATING_5 = 5, 'Super seneng, semangat banget, worry-free lah'
from django.contrib import admin
from .models import WeeklyReport
admin.site.register(WeeklyReport)
from django.apps import AppConfig
class DietProgressConfig(AppConfig):
name = 'diet_progress'
# Generated by Django 3.1 on 2021-05-29 13:24
from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
initial = True
dependencies = [
('nutritionists', '0002_nutritionist_profile_picture'),
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
]
operations = [
migrations.CreateModel(
name='WeeklyReport',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('weight', models.PositiveIntegerField()),
('height', models.PositiveIntegerField()),
('waist_size', models.PositiveIntegerField()),
('changes_felt', models.IntegerField(choices=[(1, '1'), (2, '2'), (3, '3'), (4, '4'), (5, '5')])),
('hunger_level', models.IntegerField(choices=[(1, '1'), (2, '2'), (3, '3'), (4, '4'), (5, '5'), (6, '6'), (7, '7'), (8, '8'), (9, '9'), (10, '10')])),
('fullness_level', models.IntegerField(choices=[(1, '1'), (2, '2'), (3, '3'), (4, '4'), (5, '5'), (6, '6'), (7, '7'), (8, '8'), (9, '9'), (10, '10')])),
('heavy_meal', models.IntegerField(choices=[(1, '1 kali'), (2, '2 kali'), (3, '3 kali'), (4, 'Lebih dari 3 kali')])),
('snacks', models.IntegerField(choices=[(1, 'Tidak pernah'), (2, '1 kali'), (3, '2 kali'), (4, '3 kali'), (5, 'Lebih dari 3 kali')])),
('sweet_beverages', models.IntegerField(choices=[(1, '0 gelas'), (2, '1 gelas'), (3, '2 gelas'), (4, '3 gelas'), (5, '4 gelas'), (6, 'Lebih dari 4 gelas')])),
('nutritional_advice', models.TextField(blank=True, null=True)),
('lifestyle_advice', models.TextField(blank=True, null=True)),
('client', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, related_name='weekly_report', to=settings.AUTH_USER_MODEL)),
('nutritionist', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='weekly_report', to='nutritionists.nutritionist')),
],
),
]
# Generated by Django 3.1 on 2021-05-29 15:40
from django.db import migrations, models
import multiselectfield.db.fields
class Migration(migrations.Migration):
dependencies = [
('diet_progress', '0001_initial'),
]
operations = [
migrations.AddField(
model_name='weeklyreport',
name='feeling_rating',
field=models.IntegerField(choices=[(1, 'Rasanya mau menyerah saja'), (2, 'Capek, susah, bosen, males, repot, sibuk'), (3, 'Biasa aja, meski ada kendala tapi semua bisa diatur'), (4, 'Lancar terus, semangat cukup stabil, gak ada masalah'), (5, 'Super seneng, semangat banget, worry-free lah')], default=1),
preserve_default=False,
),
migrations.AddField(
model_name='weeklyreport',
name='fried_snacks',
field=models.IntegerField(choices=[(1, '0 gelas'), (2, '1 gelas'), (3, '2 gelas'), (4, '3 gelas'), (5, '4 gelas'), (6, 'Lebih dari 4 gelas')], default=1),
preserve_default=False,
),
migrations.AddField(
model_name='weeklyreport',
name='fruits_portion',
field=models.IntegerField(choices=[(1, '0 gelas'), (2, '1 gelas'), (3, '2 gelas'), (4, '3 gelas'), (5, '4 gelas'), (6, 'Lebih dari 4 gelas')], default=1),
preserve_default=False,
),
migrations.AddField(
model_name='weeklyreport',
name='lesson_learned',
field=models.TextField(default=1),
preserve_default=False,
),
migrations.AddField(
model_name='weeklyreport',
name='physical_activity',
field=multiselectfield.db.fields.MultiSelectField(choices=[(1, 'Tidak ada'), (2, 'Mual'), (3, 'Muntah'), (4, 'Susah buang air besar dalam 3 hari terakhir'), (5, 'Kesulitan mengunyah'), (6, 'Kesulitan menelan')], default=1, max_length=11),
preserve_default=False,
),
migrations.AddField(
model_name='weeklyreport',
name='physical_activity_other',
field=models.TextField(default=1),
preserve_default=False,
),
migrations.AddField(
model_name='weeklyreport',
name='problem_faced_and_feedbacks',
field=models.TextField(default=1),
preserve_default=False,
),
migrations.AddField(
model_name='weeklyreport',
name='sweet_snacks',
field=models.IntegerField(choices=[(1, '0 gelas'), (2, '1 gelas'), (3, '2 gelas'), (4, '3 gelas'), (5, '4 gelas'), (6, 'Lebih dari 4 gelas')], default=1),
preserve_default=False,
),
migrations.AddField(
model_name='weeklyreport',
name='time_for_activity',
field=models.IntegerField(choices=[(1, '0 - 60 menit'), (2, '60 - 100 menit'), (3, '100 - 120 menit'), (4, '100 - 120 menit'), (5, '120 - 150 menit'), (6, '150 - 175 menit'), (7, '175 - 200 menit'), (8, '200 - 250 menit'), (9, 'Lebih dari 250 menit')], default=1),
preserve_default=False,
),
migrations.AddField(
model_name='weeklyreport',
name='umami_snacks',
field=models.IntegerField(choices=[(1, '0 gelas'), (2, '1 gelas'), (3, '2 gelas'), (4, '3 gelas'), (5, '4 gelas'), (6, 'Lebih dari 4 gelas')], default=1),
preserve_default=False,
),
migrations.AddField(
model_name='weeklyreport',
name='vegetables_portion',
field=models.IntegerField(choices=[(1, '0 gelas'), (2, '1 gelas'), (3, '2 gelas'), (4, '3 gelas'), (5, '4 gelas'), (6, 'Lebih dari 4 gelas')], default=1),
preserve_default=False,
),
migrations.AddField(
model_name='weeklyreport',
name='water_consumption',
field=models.TextField(default=1),
preserve_default=False,
),
migrations.AddField(
model_name='weeklyreport',
name='week_num',
field=models.PositiveIntegerField(default=1),
preserve_default=False,
),
]
# Generated by Django 3.1 on 2021-05-29 16:08
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('diet_progress', '0002_auto_20210529_2240'),
]
operations = [
migrations.RemoveField(
model_name='weeklyreport',
name='lifestyle_advice',
),
migrations.RemoveField(
model_name='weeklyreport',
name='nutritional_advice',
),
]
from django.db import models
from multiselectfield import MultiSelectField
from nutritionists.models import Nutritionist
from authentication.models import CustomUser
from constants.model_choices import(
LargeMealInOneDay,
SnacksInOneDay,
ConsumptionInOneDay,
Changes,
Hunger,
PhysicalActivity,
TimeForActivity,
Rating
)
class WeeklyReport(models.Model):
nutritionist = models.ForeignKey(
Nutritionist,
on_delete=models.CASCADE,
related_name='weekly_report'
)
client = models.OneToOneField(
CustomUser,
on_delete=models.CASCADE,
related_name='weekly_report'
)
week_num = models.PositiveIntegerField()
weight = models.PositiveIntegerField()
height = models.PositiveIntegerField()
waist_size = models.PositiveIntegerField()
# This belongs to ONE field on gform
changes_felt = models.IntegerField(
choices=Changes.choices)
hunger_level = models.IntegerField(
choices=Hunger.choices)
fullness_level = models.IntegerField(
choices=Hunger.choices)
heavy_meal = models.IntegerField(
choices=LargeMealInOneDay.choices)
snacks = models.IntegerField(
choices=SnacksInOneDay.choices)
sweet_beverages = models.IntegerField(
choices=ConsumptionInOneDay.choices)
fried_snacks = models.IntegerField(
choices=ConsumptionInOneDay.choices)
umami_snacks = models.IntegerField(
choices=ConsumptionInOneDay.choices)
sweet_snacks = models.IntegerField(
choices=ConsumptionInOneDay.choices)
fruits_portion = models.IntegerField(
choices=ConsumptionInOneDay.choices)
vegetables_portion = models.IntegerField(
choices=ConsumptionInOneDay.choices)
#########################################
water_consumption = models.TextField()
physical_activity = MultiSelectField(
choices = PhysicalActivity.choices)
physical_activity_other = models.TextField()
time_for_activity = models.IntegerField(
choices=TimeForActivity.choices)
feeling_rating = models.IntegerField(
choices = Rating.choices)
lesson_learned = models.TextField()
problem_faced_and_feedbacks = models.TextField()
from rest_framework import serializers, fields
from constants.model_choices import PhysicalActivity
from .models import WeeklyReport
class WeeklyReportSerializer(serializers.ModelSerializer):
physical_activity = fields.MultipleChoiceField(
choices=PhysicalActivity.choices)
class Meta:
model = WeeklyReport
fields = "__all__"
import json
import datetime
from unittest.mock import patch
from rest_framework.test import APITestCase
from django.test import TestCase
from rest_framework import status
from rest_framework.response import Response
from nutritionists.models import Nutritionist
from authentication.models import CustomUser
from .models import WeeklyReport
from .serializers import WeeklyReportSerializer
from .views import WeeklyReportViewSet
class WeeklyReportTest(APITestCase):
@classmethod
def setUpTestData(cls):
cls.BASE_URL = "/progress/user_report/"
cls.nutritionist_1 = Nutritionist.objects.create(
id=1,
full_name_and_degree="Test, S.Gz",
registration_certificate_no="1234567890",
university="Universitas Indonesia",
mastered_nutritional_problems="Manajemen berat badan, hipertensi",
handled_age_group="12-17 tahun (Remaja)",
another_practice_place="RSCM",
languages="Bahasa Indonesia, Bahasa Inggris",
)
cls.custom_user_1 = CustomUser.objects.create_user(
name='tes1',
email='email@email.com',
password='abc',
nutritionist=cls.nutritionist_1,
deadline = datetime.date.today(),
)
cls.custom_user_2 = CustomUser.objects.create_user(
name='tes2',
email='email2@email.com',
password='abc',
nutritionist=cls.nutritionist_1,
deadline = (datetime.date.today() + datetime.timedelta(days=3)),
)
def test_post_reports_api_success(self):
url = f"{self.BASE_URL}"
login_data = {
'email': 'email@email.com',
'password': 'abc',
'role': 'client',
}
response = self.client.post('/auth/user-login/', login_data, format='json')
json_response = json.loads(response.content)
self.client.credentials(HTTP_AUTHORIZATION='Bearer ' + json_response['access_token'])
data = {
"weight": 155,
"height": 188,
"waist_size": 100,
"changes_felt": 1,
"hunger_level" : 1,
"fullness_level": 1,
"heavy_meal": 1,
"snacks": 1,
"sweet_beverages":1,
"fried_snacks":1,
"umami_snacks":1,
"sweet_snacks":1,
"fruits_portion":1,
"vegetables_portion":1,
"water_consumption" : "aw",
"physical_activity": [1,2],
"physical_activity_other" : "n",
"time_for_activity":1,
"feeling_rating":2,
"lesson_learned":"a",
"problem_faced_and_feedbacks":"x"
}
response = self.client.post(
url, data, format='json')
self.assertEqual(response.status_code, status.HTTP_201_CREATED)
def test_post_reports_api_fail(self):
url = f"{self.BASE_URL}"
login_data = {
'email': 'email2@email.com',
'password': 'abc',
'role': 'client',
}
response = self.client.post('/auth/user-login/', login_data, format='json')
json_response = json.loads(response.content)
self.client.credentials(HTTP_AUTHORIZATION='Bearer ' + json_response['access_token'])
data = {
"weight": "155",
"height": 188,
"waist_size": 100,
"changes_felt": 1,
"hunger_level" : 1,
"fullness_level": 1,
"heavy_meal": 1,
"snacks": 1,
}
response = self.client.post(
url, data, format='json')
self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
def test_get_all_reports(self):
response = self.client.get(self.BASE_URL)
reports = WeeklyReport.objects.all()
serializer = WeeklyReportSerializer(reports, many=True)
self.assertEqual(response.data, serializer.data)
self.assertEqual(response.status_code, status.HTTP_200_OK)
\ No newline at end of file
from rest_framework import routers
from .views import WeeklyReportViewSet
router = routers.SimpleRouter()
router.register('progress/user_report', WeeklyReportViewSet)
urlpatterns = []
urlpatterns += router.urls
from rest_framework import viewsets, status
from rest_framework.response import Response
from authentication.utilities import get_appropriate_week_num
from .models import WeeklyReport
from .serializers import WeeklyReportSerializer
class WeeklyReportViewSet(viewsets.ModelViewSet):
serializer_class = WeeklyReportSerializer
queryset = WeeklyReport.objects.all()
def create(self, request, *args, **kwargs):