Add bug report model and api
This commit is contained in:
parent
04982daff2
commit
b228ba7ed9
0
ofu_app/apps/bug_report/__init__.py
Normal file
0
ofu_app/apps/bug_report/__init__.py
Normal file
7
ofu_app/apps/bug_report/admin.py
Normal file
7
ofu_app/apps/bug_report/admin.py
Normal file
@ -0,0 +1,7 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.contrib import admin
|
||||
from apps.bug_report.models import BugMsg
|
||||
|
||||
admin.site.register(BugMsg)
|
||||
0
ofu_app/apps/bug_report/api/__init__.py
Normal file
0
ofu_app/apps/bug_report/api/__init__.py
Normal file
0
ofu_app/apps/bug_report/api/v1_2/__init__.py
Normal file
0
ofu_app/apps/bug_report/api/v1_2/__init__.py
Normal file
73
ofu_app/apps/bug_report/api/v1_2/serializers.py
Normal file
73
ofu_app/apps/bug_report/api/v1_2/serializers.py
Normal file
@ -0,0 +1,73 @@
|
||||
from apps.bug_report.models import BugMsg
|
||||
from rest_framework import serializers
|
||||
|
||||
|
||||
class BugMsgCategoriesSerializer(serializers.Serializer):
|
||||
"""Your data serializer, define your fields here."""
|
||||
|
||||
def create(self, validated_data):
|
||||
pass
|
||||
|
||||
def update(self, instance, validated_data):
|
||||
pass
|
||||
|
||||
id = serializers.CharField()
|
||||
short = serializers.CharField()
|
||||
name = serializers.CharField()
|
||||
|
||||
|
||||
class BugMsgStatesSerializer(serializers.Serializer):
|
||||
"""Your data serializer, define your fields here."""
|
||||
|
||||
def create(self, validated_data):
|
||||
pass
|
||||
|
||||
def update(self, instance, validated_data):
|
||||
pass
|
||||
|
||||
id = serializers.CharField()
|
||||
name = serializers.CharField()
|
||||
|
||||
|
||||
class BugMsgPrioritiesSerializer(serializers.Serializer):
|
||||
"""Your data serializer, define your fields here."""
|
||||
|
||||
def create(self, validated_data):
|
||||
pass
|
||||
|
||||
def update(self, instance, validated_data):
|
||||
pass
|
||||
|
||||
id = serializers.CharField()
|
||||
name = serializers.CharField()
|
||||
|
||||
|
||||
class BugMsgSerializer(serializers.HyperlinkedModelSerializer):
|
||||
category = serializers.ChoiceField(choices=BugMsg.CATEGORY_CHOICES)
|
||||
status = serializers.ChoiceField(choices=BugMsg.STATE_CHOICES)
|
||||
|
||||
# def create(self, validated_data):
|
||||
# title = validated_data.pop('title')
|
||||
# description = validated_data.pop('description')
|
||||
# category = validated_data.pop('category')
|
||||
# if 'status' in validated_data:
|
||||
# status = validated_data.pop('status')
|
||||
# else:
|
||||
# status = BugMsg.REGISTERED
|
||||
# bugMsg, _ = BugMsg.objects.get_or_create(title=title, description=description, category=category, status=status)
|
||||
# return bugMsg
|
||||
|
||||
class Meta:
|
||||
model = BugMsg
|
||||
fields = ('id', 'title', 'status', 'description', 'category')
|
||||
|
||||
|
||||
class BugMsgDetailSerializer(serializers.HyperlinkedModelSerializer):
|
||||
category = serializers.ChoiceField(choices=BugMsg.CATEGORY_CHOICES)
|
||||
priority = serializers.ChoiceField(choices=BugMsg.PRIORITY_CHOICES)
|
||||
status = serializers.ChoiceField(choices=BugMsg.STATE_CHOICES)
|
||||
registration_date = serializers.DateField(format='iso-8601')
|
||||
|
||||
class Meta:
|
||||
model = BugMsg
|
||||
fields = ('id', 'registration_date', 'title', 'description', 'category', 'priority', 'status')
|
||||
26
ofu_app/apps/bug_report/api/v1_2/urls.py
Normal file
26
ofu_app/apps/bug_report/api/v1_2/urls.py
Normal file
@ -0,0 +1,26 @@
|
||||
"""ofu_app URL Configuration
|
||||
|
||||
The `urlpatterns` list routes URLs to views. For more information please see:
|
||||
https://docs.djangoproject.com/en/1.11/topics/http/urls/
|
||||
Examples:
|
||||
Function views
|
||||
1. Add an import: from my_app import views
|
||||
2. Add a URL to urlpatterns: url(r'^$', views.home, name='home')
|
||||
Class-based views
|
||||
1. Add an import: from other_app.views import Home
|
||||
2. Add a URL to urlpatterns: url(r'^$', Home.as_view(), name='home')
|
||||
Including another URLconf
|
||||
1. Import the include() function: from django.conf.urls import url, include
|
||||
2. Add a URL to urlpatterns: url(r'^blog/', include('blog.urls'))
|
||||
"""
|
||||
from django.urls import path
|
||||
from apps.bug_report.api.v1_2 import views as api_views
|
||||
|
||||
urlpatterns = [
|
||||
# API Version 1.2
|
||||
path('bug-report/reports/', api_views.ApiBugMsgs.as_view(), name='bug-reports'),
|
||||
path('bug-report/reports/<int:pk>/', api_views.ApiBugMsgUpdate.as_view(), name='bug-report'),
|
||||
path('bug-report/priorities/', api_views.ApiBugPriorities.as_view(), name='bug-priorities'),
|
||||
path('bug-report/categories/', api_views.ApiBugCategories.as_view(), name='bug-categories'),
|
||||
path('bug-report/states/', api_views.ApiBugStates.as_view(), name='bug-states'),
|
||||
]
|
||||
49
ofu_app/apps/bug_report/api/v1_2/views.py
Normal file
49
ofu_app/apps/bug_report/api/v1_2/views.py
Normal file
@ -0,0 +1,49 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from apps.bug_report.api.v1_2.serializers import BugMsgSerializer, BugMsgCategoriesSerializer, \
|
||||
BugMsgPrioritiesSerializer, BugMsgStatesSerializer, BugMsgDetailSerializer
|
||||
from apps.bug_report.models import BugMsg
|
||||
from rest_framework import generics, views, status
|
||||
from rest_framework.decorators import permission_classes
|
||||
from rest_framework.permissions import AllowAny
|
||||
from rest_framework.response import Response
|
||||
|
||||
|
||||
@permission_classes((AllowAny,))
|
||||
class ApiBugMsgs(generics.ListCreateAPIView):
|
||||
serializer_class = BugMsgSerializer
|
||||
queryset = BugMsg.objects.order_by('-registration_date')
|
||||
|
||||
|
||||
@permission_classes((AllowAny,))
|
||||
class ApiBugMsgUpdate(generics.RetrieveUpdateAPIView):
|
||||
serializer_class = BugMsgDetailSerializer
|
||||
queryset = BugMsg.objects.all()
|
||||
|
||||
|
||||
@permission_classes((AllowAny,))
|
||||
class ApiBugPriorities(views.APIView):
|
||||
|
||||
def get(self, request):
|
||||
data = BugMsg.API_Priorities
|
||||
results = BugMsgPrioritiesSerializer(data, many=True).data
|
||||
return Response(results, status=status.HTTP_200_OK)
|
||||
|
||||
|
||||
@permission_classes((AllowAny,))
|
||||
class ApiBugCategories(views.APIView):
|
||||
|
||||
def get(self, request):
|
||||
data = BugMsg.API_CATEGORIES
|
||||
results = BugMsgCategoriesSerializer(data, many=True).data
|
||||
return Response(results, status=status.HTTP_200_OK)
|
||||
|
||||
|
||||
@permission_classes((AllowAny,))
|
||||
class ApiBugStates(views.APIView):
|
||||
|
||||
def get(self, request):
|
||||
data = BugMsg.API_STATES
|
||||
results = BugMsgStatesSerializer(data, many=True).data
|
||||
return Response(results, status=status.HTTP_200_OK)
|
||||
8
ofu_app/apps/bug_report/apps.py
Normal file
8
ofu_app/apps/bug_report/apps.py
Normal file
@ -0,0 +1,8 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.apps import AppConfig
|
||||
|
||||
|
||||
class FoodConfig(AppConfig):
|
||||
name = 'apps.food'
|
||||
83
ofu_app/apps/bug_report/models.py
Normal file
83
ofu_app/apps/bug_report/models.py
Normal file
@ -0,0 +1,83 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import os
|
||||
from io import BytesIO
|
||||
import uuid
|
||||
from _datetime import datetime
|
||||
|
||||
from PIL import Image
|
||||
from django.conf import settings
|
||||
from django.contrib.auth.models import User
|
||||
from django.core.files.uploadedfile import SimpleUploadedFile
|
||||
from django.db import models
|
||||
from django.utils import timezone
|
||||
from django.core.validators import MaxValueValidator, MinValueValidator
|
||||
|
||||
MAX_LENGTH = 256
|
||||
MAX_TITLE_LENGTH = 128
|
||||
MAX_DESCRIPTION_LENGTH = 1024
|
||||
MAX_PRIORITY_LENGTH = 32
|
||||
MAX_CATEGORY_LENGTH = 32
|
||||
MAX_STATE_LENGTH = 64
|
||||
|
||||
|
||||
# Create your models here.
|
||||
class BugMsg(models.Model):
|
||||
# Priorities
|
||||
HIGH = 'HIGH'
|
||||
LOW = 'LOW'
|
||||
|
||||
# Categories
|
||||
FOOD = 'FOOD'
|
||||
EVENTS = 'Events'
|
||||
DONAR = 'DONAR'
|
||||
OTHER = 'Other'
|
||||
|
||||
# State
|
||||
REGISTERED = 'REGISTERED'
|
||||
TODO = 'TODO'
|
||||
IN_PROGRESS = 'IN_PROGRESS'
|
||||
DONE = 'DONE'
|
||||
REJECTED = 'REJECTED'
|
||||
|
||||
PRIORITY_CHOICES = (
|
||||
(HIGH, 'High'), (LOW, 'Low')
|
||||
)
|
||||
|
||||
CATEGORY_CHOICES = (
|
||||
(FOOD, 'Food App'), (EVENTS, 'Event App'), (DONAR, 'Donar App'), (OTHER, 'Other')
|
||||
)
|
||||
|
||||
STATE_CHOICES = (
|
||||
(REGISTERED, 'registered'), (TODO, 'todo'), (IN_PROGRESS, 'in progress'), (DONE, 'done'), (REJECTED, 'rejected')
|
||||
)
|
||||
|
||||
# Api priorities data
|
||||
API_Priorities = [{'id': HIGH, 'name': 'High'},
|
||||
{'id': LOW, 'name': 'Low'}, ]
|
||||
|
||||
# Api categories data
|
||||
API_CATEGORIES = [{'id': FOOD, 'name': 'Food App', 'short': 'Food'},
|
||||
{'id': EVENTS, 'name': 'Event App', 'short': 'Events'},
|
||||
{'id': DONAR, 'name': 'Donar App', 'short': 'Donar'},
|
||||
{'id': OTHER, 'name': 'Other', 'short': 'Other'}, ]
|
||||
|
||||
# Api state data
|
||||
API_STATES = [{'id': REGISTERED, 'name': 'Registered'},
|
||||
{'id': TODO, 'name': 'todo'},
|
||||
{'id': IN_PROGRESS, 'name': 'in progress'},
|
||||
{'id': DONE, 'name': 'done'},
|
||||
{'id': REJECTED, 'name': 'rejected'},
|
||||
]
|
||||
|
||||
id = models.AutoField(primary_key=True)
|
||||
title = models.CharField(max_length=MAX_TITLE_LENGTH, unique=True)
|
||||
description = models.CharField(max_length=MAX_DESCRIPTION_LENGTH)
|
||||
priority = models.CharField(max_length=MAX_PRIORITY_LENGTH, choices=PRIORITY_CHOICES)
|
||||
category = models.CharField(max_length=MAX_CATEGORY_LENGTH, choices=CATEGORY_CHOICES)
|
||||
status = models.CharField(max_length=MAX_STATE_LENGTH, choices=STATE_CHOICES)
|
||||
registration_date = models.DateField(default=timezone.now)
|
||||
|
||||
def __str__(self):
|
||||
return "%s - %s - %s - %s" % (self.registration_date.strftime("%d.%m.%Y"), self.title, self.priority, self.status)
|
||||
0
ofu_app/apps/bug_report/tests/__init__.py
Normal file
0
ofu_app/apps/bug_report/tests/__init__.py
Normal file
133
ofu_app/apps/bug_report/tests/tests_api.py
Normal file
133
ofu_app/apps/bug_report/tests/tests_api.py
Normal file
@ -0,0 +1,133 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.test import TestCase
|
||||
from django.urls import reverse
|
||||
from apps.food.models import SingleFood, Menu
|
||||
from apps.food.api.v1_1.serializers import MenuSerializer
|
||||
from rest_framework import status
|
||||
|
||||
from datetime import datetime
|
||||
|
||||
|
||||
# Create your tests here.
|
||||
|
||||
class SingleFood_Scope(TestCase):
|
||||
def setUp(self):
|
||||
self.singlefood_1 = SingleFood.objects.create(name="testfood1")
|
||||
self.singlefood_2 = SingleFood.objects.create(name="testfood2")
|
||||
self.singlefood_3 = SingleFood.objects.create(name="testfood3")
|
||||
self.singlefood_4 = SingleFood.objects.create(name="testfood4")
|
||||
self.singlefood_5 = SingleFood.objects.create(name="testfood5")
|
||||
self.singlefood_6 = SingleFood.objects.create(name="testfood6")
|
||||
self.today_menu = Menu.objects.create(date='2017-01-15', location=Menu.ERBA)
|
||||
self.today_menu.menu.add(self.singlefood_1)
|
||||
self.today_menu.menu.add(self.singlefood_2)
|
||||
self.today_menu.menu.add(self.singlefood_3)
|
||||
self.menu_2 = Menu.objects.create(date='2017-01-10', location=Menu.FEKI)
|
||||
self.menu_2.menu.add(self.singlefood_4)
|
||||
self.menu_2.menu.add(self.singlefood_5)
|
||||
self.menu_2.menu.add(self.singlefood_6)
|
||||
|
||||
def test_get_food_root(self):
|
||||
"""
|
||||
All menus in response
|
||||
"""
|
||||
menus = Menu.objects.all()
|
||||
serializer = MenuSerializer(menus, many=True)
|
||||
response = self.client.get(reverse('api-v1_1-food-all'))
|
||||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||
self.assertEqual(response.data, serializer.data)
|
||||
|
||||
def test_get_food_date_param(self):
|
||||
"""
|
||||
Menu for a given date is in the response
|
||||
"""
|
||||
serializer = MenuSerializer(self.menu_2, many=False)
|
||||
response_1 = self.client.get(reverse('api-v1_1-food-date', kwargs={'year': '2017', 'month': '01', 'day': '10'}))
|
||||
self.assertEqual(response_1.status_code, 200)
|
||||
self.assertEqual(response_1.data, [serializer.data])
|
||||
|
||||
serializer_2 = MenuSerializer(self.today_menu, many=False)
|
||||
response_2 = self.client.get(reverse('api-v1_1-food-date', kwargs={'year': '2017', 'month': '01', 'day': '15'}))
|
||||
self.assertEqual(response_2.status_code, 200)
|
||||
self.assertEqual(response_2.data, [serializer_2.data])
|
||||
|
||||
def test_get_food_date_param_not_in_set(self):
|
||||
"""
|
||||
Empty response if no object with request date in set
|
||||
"""
|
||||
response_1 = self.client.get(reverse('api-v1_1-food-date', kwargs={'year': '2017', 'month': '01', 'day': '11'}))
|
||||
self.assertEqual(response_1.status_code, 200)
|
||||
self.assertEqual(response_1.data, [])
|
||||
|
||||
def test_get_food_location_param(self):
|
||||
"""
|
||||
Menu for a given location is in the response
|
||||
"""
|
||||
serializer_1 = MenuSerializer(self.today_menu, many=False)
|
||||
response_1 = self.client.get(reverse('api-v1_1-food-location', kwargs={'location': Menu.ERBA}))
|
||||
self.assertEqual(response_1.status_code, 200)
|
||||
self.assertEqual(response_1.data, [serializer_1.data])
|
||||
|
||||
serializer_2 = MenuSerializer(self.menu_2, many=False)
|
||||
response_2 = self.client.get(reverse('api-v1_1-food-location', kwargs={'location': Menu.FEKI}))
|
||||
self.assertEqual(response_2.status_code, 200)
|
||||
self.assertEqual(response_2.data, [serializer_2.data])
|
||||
|
||||
def test_get_food_location_param_not_in_set(self):
|
||||
"""
|
||||
Empty response if no object with request location in set
|
||||
"""
|
||||
response_1 = self.client.get(reverse('api-v1_1-food-location', kwargs={'location': Menu.AUSTRASSE}))
|
||||
self.assertEqual(response_1.status_code, 200)
|
||||
self.assertEqual(response_1.data, [])
|
||||
|
||||
def test_get_food_location_date_param(self):
|
||||
"""
|
||||
Menu for request location and date is in the response
|
||||
"""
|
||||
|
||||
serializer = MenuSerializer(self.menu_2, many=False)
|
||||
response = self.client.get(reverse('api-v1_1-food-location-date',
|
||||
kwargs={'year': '2017', 'month': '01', 'day': '10',
|
||||
'location': Menu.FEKI}))
|
||||
self.assertEqual(response.status_code, 200)
|
||||
self.assertEqual(response.data, [serializer.data])
|
||||
|
||||
def test_get_food_location_date_param_not_in_set(self):
|
||||
"""
|
||||
Empty response if no object with request date and location in set
|
||||
"""
|
||||
response_1 = self.client.get(reverse('api-v1_1-food-location-date',
|
||||
kwargs={'year': '2017', 'month': '01', 'day': '11',
|
||||
'location': Menu.FEKI}))
|
||||
self.assertEqual(response_1.status_code, 200)
|
||||
self.assertEqual(response_1.data, [])
|
||||
|
||||
response_1 = self.client.get(reverse('api-v1_1-food-location-date',
|
||||
kwargs={'year': '2017', 'month': '01', 'day': '10',
|
||||
'location': Menu.AUSTRASSE}))
|
||||
self.assertEqual(response_1.status_code, 200)
|
||||
self.assertEqual(response_1.data, [])
|
||||
|
||||
def test_get_food_today_param(self):
|
||||
"""
|
||||
Menu for request today is in the response
|
||||
"""
|
||||
self.singlefood = SingleFood.objects.create(name="testfood")
|
||||
self.today_menu = Menu.objects.create(date=datetime.today().strftime('%Y-%m-%d'), location=Menu.ERBA)
|
||||
self.today_menu.menu.add(self.singlefood)
|
||||
|
||||
serializer = MenuSerializer(self.today_menu, many=False)
|
||||
response = self.client.get(reverse('api-v1_1-food-today'))
|
||||
self.assertEqual(response.status_code, 200)
|
||||
self.assertEqual(response.data, [serializer.data])
|
||||
|
||||
def test_get_food_today_param_not_in_set(self):
|
||||
"""
|
||||
Empty response if no object with date 'today' is in set
|
||||
"""
|
||||
response = self.client.get(reverse('api-v1_1-food-today'))
|
||||
self.assertEqual(response.status_code, 200)
|
||||
self.assertEqual(response.data, [])
|
||||
24
ofu_app/apps/bug_report/tests/tests_model.py
Normal file
24
ofu_app/apps/bug_report/tests/tests_model.py
Normal file
@ -0,0 +1,24 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.test import TestCase
|
||||
|
||||
from apps.food.models import SingleFood
|
||||
|
||||
|
||||
# Create your tests here.
|
||||
|
||||
class SingleFood_Scope(TestCase):
|
||||
def setUp(self):
|
||||
SingleFood.objects.create(name="testfood")
|
||||
|
||||
def test_food_created_just_with_name(self):
|
||||
"""Animals that can speak are correctly identified"""
|
||||
food = SingleFood.objects.get(name="testfood")
|
||||
self.assertEqual(food.name, 'testfood')
|
||||
self.assertIsNone(food.allergens.all().first(), [])
|
||||
self.assertIsNone(food.price_employee)
|
||||
self.assertIsNone(food.price_guest)
|
||||
self.assertIsNone(food.price_student)
|
||||
self.assertIsNone(food.image)
|
||||
self.assertEqual(food.rating, 0.0)
|
||||
@ -4,6 +4,9 @@ from django.contrib.auth.models import User
|
||||
from rest_framework import validators
|
||||
from rest_framework import serializers
|
||||
from django.db.utils import IntegrityError
|
||||
import logging
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class UserFoodImageSerializer(serializers.HyperlinkedModelSerializer):
|
||||
@ -90,6 +93,8 @@ class UserFoodImageSerializer(serializers.ModelSerializer):
|
||||
image = validated_data.pop('image')
|
||||
food_image = FoodImage.objects.create(image=image)
|
||||
food_image.save()
|
||||
logger.info('New Image: {}\nFood: {}'.format(food_image.image.url, food.name))
|
||||
logger.error('New Image: {}\nFood: {}'.format(food_image.image.url, food.name))
|
||||
try:
|
||||
user_food_image = UserFoodImage.objects.create(user=user, food=food, image=food_image)
|
||||
user_food_image.save()
|
||||
|
||||
@ -56,7 +56,7 @@ class ApiMenus(generics.ListAPIView):
|
||||
except ValueError as e:
|
||||
# TODO: return Exception
|
||||
return []
|
||||
|
||||
queryset.order_by('date')
|
||||
return queryset
|
||||
|
||||
|
||||
|
||||
@ -101,6 +101,7 @@ INSTALLED_APPS = [
|
||||
'apps.events',
|
||||
'apps.donar',
|
||||
'apps.registration',
|
||||
'apps.bug_report',
|
||||
'rest_framework',
|
||||
'rest_framework.authtoken',
|
||||
'djoser',
|
||||
@ -235,6 +236,10 @@ LOGGING = {
|
||||
'level': 'ERROR',
|
||||
'class': 'django.utils.log.AdminEmailHandler',
|
||||
},
|
||||
'mail_admins_image_upload': {
|
||||
'level': 'INFO',
|
||||
'class': 'django.utils.log.AdminEmailHandler',
|
||||
},
|
||||
},
|
||||
'loggers': {
|
||||
'apps.food.utils': {
|
||||
@ -245,5 +250,9 @@ LOGGING = {
|
||||
'handlers': ['console', 'file', 'mail_admins'],
|
||||
'level': os.getenv('DJANGO_LOG_LEVEL', 'DEBUG'),
|
||||
},
|
||||
'apps.food.api.v1_2.serializers.user_serializers': {
|
||||
'handlers': ['mail_admins_image_upload', 'console'],
|
||||
'level': 'INFO',
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
@ -57,6 +57,7 @@ urlpatterns = [
|
||||
# -- Version 1.2
|
||||
url(r'^api/v1.2/', include('apps.food.api.v1_2.urls')),
|
||||
url(r'^api/v1.2/', include('apps.registration.api.urls')),
|
||||
url(r'^api/v1.2/', include('apps.bug_report.api.v1_2.urls')),
|
||||
|
||||
# -- Third Party APIs
|
||||
url(r'^api/auth/', include('rest_framework.urls', namespace='rest_framework')),
|
||||
|
||||
Reference in New Issue
Block a user