Commit 6987371b authored by Elias Larsen's avatar Elias Larsen
Browse files

Merge branch 'master' into elias/fix/facilities

parents c2805be2 728f8a56
from django.contrib import admin
from comments.models import Comment
# Register your models here.
from .models import Comment
admin.site.register(Comment)
from django.db import models
from django.conf import settings
from django.contrib.contenttypes.fields import GenericForeignKey
from django.contrib.contenttypes.models import ContentType
from django.urls import reverse
from django.db import models
from django.contrib.auth import get_user_model
from workouts.models import Workout
......
from django.urls import path, include
from comments.models import Comment, Like
from django.urls import path
from comments.views import CommentList, CommentDetail, LikeList, LikeDetail
from rest_framework.urlpatterns import format_suffix_patterns
urlpatterns = [
path("api/comments/", CommentList.as_view(), name="comment-list"),
......
from django.shortcuts import render
from rest_framework import generics, mixins
from comments.models import Comment, Like
from rest_framework import permissions
from rest_framework.filters import OrderingFilter
from comments.models import Comment, Like
from comments.permissions import IsCommentVisibleToUser
from comments.serializers import CommentSerializer
from comments.serializers import LikeSerializer
from workouts.permissions import IsOwner, IsReadOnly
from comments.serializers import CommentSerializer, LikeSerializer
from django.db.models import Q
from rest_framework.filters import OrderingFilter
# Create your views here.
class CommentList(
mixins.ListModelMixin, mixins.CreateModelMixin, generics.GenericAPIView
mixins.ListModelMixin,
mixins.CreateModelMixin,
generics.GenericAPIView
):
# queryset = Comment.objects.all()
serializer_class = CommentSerializer
......@@ -28,40 +29,30 @@ class CommentList(
serializer.save(owner=self.request.user)
def get_queryset(self):
"""A comment should be visible to the requesting user if any of the following hold:
- The comment is on a public visibility workout
- The comment was written by the user
- The comment is on a coach visibility workout and the user is the workout owner's coach
- The comment is on a workout owned by the user
"""
workout_pk = self.kwargs.get("pk")
qs = Comment.objects.none()
queryset = Comment.objects.none()
if workout_pk:
qs = Comment.objects.filter(workout=workout_pk)
queryset = Comment.objects.filter(workout=workout_pk)
elif self.request.user:
"""A comment should be visible to the requesting user if any of the following hold:
- The comment is on a public visibility workout
- The comment was written by the user
- The comment is on a coach visibility workout and the user is the workout owner's coach
- The comment is on a workout owned by the user
"""
# The code below is kind of duplicate of the one in ./permissions.py
# We should replace it with a better solution.
# Or maybe not.
qs = Comment.objects.filter(
Q(workout__visibility="PU")
| Q(owner=self.request.user)
| (
Q(workout__visibility="CO")
& Q(workout__owner__coach=self.request.user)
)
| Q(workout__owner=self.request.user)
).distinct()
return qs
queryset = Comment.objects.filter(
IsCommentVisibleToUser.has_object_permission
).distinct()
return queryset
# Details of comment
class CommentDetail(
mixins.RetrieveModelMixin,
mixins.UpdateModelMixin,
mixins.DestroyModelMixin,
generics.GenericAPIView,
mixins.RetrieveModelMixin,
mixins.UpdateModelMixin,
mixins.DestroyModelMixin,
generics.GenericAPIView,
):
queryset = Comment.objects.all()
serializer_class = CommentSerializer
......@@ -80,7 +71,11 @@ class CommentDetail(
# List of likes
class LikeList(mixins.ListModelMixin, mixins.CreateModelMixin, generics.GenericAPIView):
class LikeList(
mixins.ListModelMixin,
mixins.CreateModelMixin,
generics.GenericAPIView
):
serializer_class = LikeSerializer
permission_classes = [permissions.IsAuthenticated]
......@@ -99,10 +94,10 @@ class LikeList(mixins.ListModelMixin, mixins.CreateModelMixin, generics.GenericA
# Details of like
class LikeDetail(
mixins.RetrieveModelMixin,
mixins.UpdateModelMixin,
mixins.DestroyModelMixin,
generics.GenericAPIView,
mixins.RetrieveModelMixin,
mixins.UpdateModelMixin,
mixins.DestroyModelMixin,
generics.GenericAPIView,
):
queryset = Like.objects.all()
serializer_class = LikeSerializer
......
# Generated by Django 3.1 on 2021-04-07 17:51
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('facilities', '0003_auto_20210308_1733'),
]
operations = [
migrations.AlterField(
model_name='facility',
name='image2',
field=models.CharField(blank=True, max_length=2048),
),
migrations.AlterField(
model_name='facility',
name='image3',
field=models.CharField(blank=True, max_length=2048),
),
migrations.AlterField(
model_name='facility',
name='image4',
field=models.CharField(blank=True, max_length=2048),
),
migrations.AlterField(
model_name='facility',
name='image5',
field=models.CharField(blank=True, max_length=2048),
),
]
......@@ -12,21 +12,24 @@ https://docs.djangoproject.com/en/3.1/ref/settings/
from pathlib import Path
import os
from typing import Dict
import dj_database_url
import dotenv
# Get the GROUPID variable to accept connections from the application server and NGINX
groupid = os.environ.get("GROUPID", "0")
group_id = os.environ.get("GROUPID", "0")
# Email configuration
# The host must be running within NTNU's VPN (vpn.ntnu.no) to allow this config
# Usage: https://docs.djangoproject.com/en/3.1/topics/email/#obtaining-an-instance-of-an-email-backend
# Usage:
# https://docs.djangoproject.com/en/3.1/topics/email/#obtaining-an-instance-of-an-email-backend
EMAIL_BACKEND = "django.core.mail.backends.smtp.EmailBackend"
EMAIL_HOST = "mx.ntnu.no"
EMAIL_USE_TLS = False
EMAIL_PORT = 25
# Build paths inside the project like this: BASE_DIR / 'subdir'.
BASE_DIR = Path(__file__).resolve(strict=True).parent.parent
dotenv_file = os.path.join(BASE_DIR, ".env")
......@@ -42,8 +45,8 @@ ALLOWED_HOSTS = [
"127.0.0.1",
"localhost",
"0.0.0.0",
"10." + groupid + ".0.6",
"10." + groupid + ".0.4",
"10." + group_id + ".0.6",
"10." + group_id + ".0.4",
"molde.idi.ntnu.no",
"10.0.2.2",
"tdt4242-t11.herokuapp.com",
......@@ -96,12 +99,11 @@ TEMPLATES = [
WSGI_APPLICATION = "secfit.wsgi.application"
# Database
# https://docs.djangoproject.com/en/3.1/ref/settings/#databases
if 'DATABASE_URL' in os.environ:
DATABASES = {
DATABASES: Dict[str, Dict] = {
"default": {}
}
db_from_env = dj_database_url.config(conn_max_age=500)
......@@ -114,8 +116,6 @@ else:
}
}
# CORS Policy
CORS_ORIGIN_ALLOW_ALL = (
True
......@@ -134,7 +134,6 @@ USE_L10N = True
USE_TZ = True
# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/3.1/howto/static-files/
......@@ -146,7 +145,6 @@ STATIC_URL = "/static/"
MEDIA_ROOT = os.path.join(BASE_DIR, "media")
MEDIA_URL = "/media/"
REST_FRAMEWORK = {
"DEFAULT_PAGINATION_CLASS": "rest_framework.pagination.PageNumberPagination",
"PAGE_SIZE": 10,
......
from django.contrib import admin
from django.contrib.auth.admin import UserAdmin
from .models import Offer, AthleteFile
from django.contrib.auth import get_user_model
from .models import Offer, AthleteFile
from .forms import CustomUserChangeForm, CustomUserCreationForm
# Register your models here.
class CustomUserAdmin(UserAdmin):
add_form = CustomUserCreationForm
form = CustomUserChangeForm
model = get_user_model()
# list_display = UserAdmin.list_display + ('coach',)
fieldsets = UserAdmin.fieldsets + ((None, {"fields": ("coach",)}),)
add_fieldsets = UserAdmin.add_fieldsets + ((None, {"fields": ("coach",)}),)
......
......@@ -4,13 +4,11 @@ from django.contrib.auth import get_user_model
class CustomUserCreationForm(UserCreationForm):
phone_number = forms.CharField(max_length=50)
country = forms.CharField(max_length=50)
city = forms.CharField(max_length=50)
street_address = forms.CharField(max_length=50)
class Meta(UserCreationForm):
model = get_user_model()
fields = ("username", "coach", "phone_number", "country", "city", "street_address")
......
......@@ -3,9 +3,6 @@ from django.contrib.auth.models import AbstractUser
from django.contrib.auth import get_user_model
# Create your models here.
class User(AbstractUser):
"""
Standard Django User model with an added field for a user's coach.
......@@ -18,7 +15,7 @@ class User(AbstractUser):
country = models.TextField(max_length=50, blank=True)
city = models.TextField(max_length=50, blank=True)
street_address = models.TextField(max_length=50, blank=True)
def athlete_directory_path(instance, filename):
"""
......
from rest_framework import serializers
from django.contrib.auth import get_user_model, password_validation
from users.models import Offer, AthleteFile
from django import forms
from users.models import Offer, AthleteFile
class UserSerializer(serializers.HyperlinkedModelSerializer):
......@@ -30,9 +30,7 @@ class UserSerializer(serializers.HyperlinkedModelSerializer):
def validate_password(self, value):
data = self.get_initial()
password = data.get("password")
password1 = data.get("password1")
try:
password_validation.validate_password(password)
......@@ -49,7 +47,14 @@ class UserSerializer(serializers.HyperlinkedModelSerializer):
country = validated_data["country"]
city = validated_data["city"]
street_address = validated_data["street_address"]
user_obj = get_user_model()(username=username, email=email, phone_number=phone_number, country=country, city=city, street_address=street_address)
user_obj = get_user_model()(
username=username,
email=email,
phone_number=phone_number,
country=country,
city=city,
street_address=street_address
)
user_obj.set_password(password)
user_obj.save()
......
from django.test import TestCase, Client
import uuid
variables = [
'username',
'email',
'password',
'password1',
'phone_number',
'country',
'city',
'street_address'
]
variable_values = {
'valid':
{
'username': 'Testuser',
'email': 'test@test.te',
'password': 'password',
'password1': 'password',
'phone_number': '1234567890',
'country': 'Testonia',
'city': 'Testheim',
'street_address': 'Test',
},
'invalid': {
'username': 'Test user',
'email': 'test',
'password': None,
'password1': None,
'phone_number': 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX',
'country': 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX',
'city': 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX',
'street_address': 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX',
},
'blank': {
'username': '',
'email': '',
'password': '',
'password1': '',
'phone_number': '',
'country': '',
'city': '',
'street_address': '',
}
}
# Test cases generated by https://pairwise.teremokgames.com
test_cases = [
{
"username": "invalid", "password": "blank", "password1": "valid", "email": "invalid", "phone_number": "valid", "country": "blank", "city": "blank", "street_address": "invalid"},{
"username": "invalid", "password": "valid", "password1": "blank", "email": "valid", "phone_number": "blank", "country": "blank", "city": "invalid", "street_address": "valid"},{
"username": "invalid", "password": "valid", "password1": "blank", "email": "blank", "phone_number": "invalid", "country": "valid", "city": "blank", "street_address": "invalid"},{
"username": "invalid", "password": "blank", "password1": "blank", "email": "invalid", "phone_number": "valid", "country": "blank", "city": "invalid", "street_address": "valid"},{
"username": "invalid", "password": "blank", "password1": "valid", "email": "valid", "phone_number": "blank", "country": "invalid", "city": "valid", "street_address": "blank"},{
"username": "valid", "password": "blank", "password1": "blank", "email": "blank", "phone_number": "invalid", "country": "blank", "city": "valid", "street_address": "blank"},{
"username": "valid", "password": "blank", "password1": "blank", "email": "invalid", "phone_number": "blank", "country": "valid", "city": "blank", "street_address": "valid"},{
"username": "valid", "password": "valid", "password1": "valid", "email": "valid", "phone_number": "blank", "country": "valid", "city": "invalid", "street_address": "blank"},{
"username": "blank", "password": "valid", "password1": "blank", "email": "valid", "phone_number": "valid", "country": "invalid", "city": "invalid", "street_address": "blank"},{
"username": "blank", "password": "blank", "password1": "blank", "email": "blank", "phone_number": "blank", "country": "valid", "city": "valid", "street_address": "invalid"},{
"username": "blank", "password": "blank", "password1": "blank", "email": "valid", "phone_number": "invalid", "country": "invalid", "city": "blank", "street_address": "blank"},{
"username": "blank", "password": "blank", "password1": "valid", "email": "blank", "phone_number": "valid", "country": "valid", "city": "invalid", "street_address": "invalid"},{
"username": "blank", "password": "valid", "password1": "blank", "email": "blank", "phone_number": "blank", "country": "blank", "city": "valid", "street_address": "valid"},{
"username": "blank", "password": "blank", "password1": "valid", "email": "invalid", "phone_number": "invalid", "country": "blank", "city": "blank", "street_address": "blank"},{
"username": "invalid", "password": "blank", "password1": "valid", "email": "blank", "phone_number": "invalid", "country": "invalid", "city": "valid", "street_address": "valid"},{
"username": "invalid", "password": "valid", "password1": "valid", "email": "valid", "phone_number": "blank", "country": "blank", "city": "blank", "street_address": "invalid"},{
"username": "invalid", "password": "blank", "password1": "blank", "email": "blank", "phone_number": "blank", "country": "invalid", "city": "invalid", "street_address": "valid"},{
"username": "invalid", "password": "valid", "password1": "blank", "email": "invalid", "phone_number": "invalid", "country": "valid", "city": "valid", "street_address": "blank"},{
"username": "valid", "password": "valid", "password1": "valid", "email": "invalid", "phone_number": "blank", "country": "invalid", "city": "valid", "street_address": "blank"},{
"username": "valid", "password": "blank", "password1": "blank", "email": "valid", "phone_number": "blank", "country": "valid", "city": "blank", "street_address": "invalid"},{
"username": "valid", "password": "blank", "password1": "valid", "email": "blank", "phone_number": "invalid", "country": "blank", "city": "invalid", "street_address": "valid"},{
"username": "valid", "password": "valid", "password1": "blank", "email": "invalid", "phone_number": "valid", "country": "blank", "city": "valid", "street_address": "blank"},{
"username": "valid", "password": "blank", "password1": "blank", "email": "valid", "phone_number": "blank", "country": "invalid", "city": "blank", "street_address": "invalid"},{
"username": "valid", "password": "valid", "password1": "valid", "email": "blank", "phone_number": "invalid", "country": "valid", "city": "blank", "street_address": "valid"},{
"username": "valid", "password": "blank", "password1": "blank", "email": "blank", "phone_number": "valid", "country": "blank", "city": "invalid", "street_address": "blank"},{
"username": "blank", "password": "blank", "password1": "valid", "email": "invalid", "phone_number": "blank", "country": "valid", "city": "invalid", "street_address": "blank"},{
"username": "blank", "password": "blank", "password1": "blank", "email": "valid", "phone_number": "invalid", "country": "blank", "city": "valid", "street_address": "invalid"},{
"username": "blank", "password": "valid", "password1": "blank", "email": "blank", "phone_number": "valid", "country": "invalid", "city": "blank", "street_address": "valid"},{
"username": "blank", "password": "blank", "password1": "valid", "email": "blank", "phone_number": "blank", "country": "valid", "city": "invalid", "street_address": "blank"},{
"username": "blank", "password": "valid", "password1": "blank", "email": "invalid", "phone_number": "blank", "country": "blank", "city": "valid", "street_address": "invalid"},{
"username": "blank", "password": "blank", "password1": "valid", "email": "valid", "phone_number": "invalid", "country": "blank", "city": "blank", "street_address": "valid"},{
"username": "blank", "password": "valid", "password1": "blank", "email": "blank", "phone_number": "valid", "country": "invalid", "city": "blank", "street_address": "blank"}
]
class UserRegistration2WayTestCase(TestCase):
def setUp(self):
print("Running two way user registration")
self.client = Client()
def test_two_way(self):
for testcase in test_cases:
request = {}
invalid_request = False
for key, value in testcase.items():
request[key] = variable_values[value][key]
if key == 'username' and value == 'valid':
# Add a uid to username to avoid "user already exists error"
request['username'] = request['username'] + str(uuid.uuid4())
if (
value == 'invalid'
or (key == 'username' and value == 'blank')
or (key == 'password' and value == 'blank')
or (key == 'password1' and value == 'blank')
):
invalid_request = True
response_code = 400 if invalid_request else 201
response = self.client.post('/api/users/', request)
self.assertEqual(response.status_code, response_code)
from users.tests.UserRegistration import *
from users.tests.UserSerializer import *
\ No newline at end of file
from users.tests.offers import OfferTestCase
from users.tests.user_registration import UserRegistration2WayTestCase
from users.tests.user_serializer import UserSerializerTestCase
from django.test import TestCase
from django.contrib.auth import get_user_model
from rest_framework.test import APIClient
from users.models import Offer
class OfferTestCase(TestCase):
def setUp(self):
self.client = APIClient()
self.user_model = get_user_model()
self.password = "password"
self.user1 = self.user_model(
username="testOffer1",
email="test@test.com",
phone_number="12345678",
country="Norway",
city="Oslo",
street_address="address 10"
)
self.user1.set_password(self.password)
self.user1.save()
self.user2 = self.user_model(
username="testOffer2",
email="test@test.com",
phone_number="12345678",
country="Norway",
city="Oslo",
street_address="address 10"
)
self.user2.set_password(self.password)
self.user2.save()
def _send_offer(self, user_id, status):
request = {"status": status, "recipient": "http://127.0.0.1:8000/api/users/{0}/".format(user_id)}
response = self.client.post('/api/offers/', request)
return response.status_code
def _login(self, user):
request = {"username": user.username, "password": self.password}
response = self.client.post('/api/token/', request)
access_token = response.data['access']
self.client.credentials(HTTP_AUTHORIZATION='Bearer ' + access_token)
def test_create_offer(self):
recipient = self.user2.id
self._login(self.user1)
status_code = self._send_offer(recipient, Offer.PENDING)
self.assertEqual(status_code, 201)
def test_get_offers(self):
self._login(self.user1)
self._send_offer(self.user2.id, Offer.PENDING)
self._login(self.user2)
response = self.client.get('/api/offers/')
number_of_offers = response.data["count"]
self.assertEqual(1, number_of_offers)
def test_get_offer_detail(self):
self._login(self.user1)
self._send_offer(self.user2.id, Offer.PENDING)
self._login(self.user2)
response = self.client.get('/api/offers/1/')
self.assertEqual(200, response.status_code)
def test_decline_offer(self):
self._login(self.user1)
self._send_offer(self.user2.id, Offer.PENDING)
self._login(self.user2)
response = self.client.patch('/api/offers/1/', {"status": Offer.DECLINED})
self.assertEqual(200, response.status_code)
def test_accept_offer(self):
self._login(self.user1)
self._send_offer(self.user2.id, Offer.PENDING)
self._login(self.user2)
offer_response = self.client.patch('/api/offers/1/', {"status": Offer.ACCEPTED})
self.assertEqual(200, offer_response.status_code)
coach_response = self.client.patch(
'/api/users/{0}/'.format(self.user2.id),
{"coach": "http://127.0.0.1:8000/api/users/{0}/".format(self.user1.id)}
)
self.assertEqual(200, coach_response.status_code)
athlete = self.user_model.objects.get(username=self.user2.username)
self.assertEqual(athlete.coach.id, self.user1.id)
test_data = {
"username": "testCreate",
"email": "test@test.com",
"password": "1",
"password1": "1",
"phone_number": "12345678",
"country": "Norway",
"city": "Oslo",
"street_address": "address 10"
}
test_data1 = {
"username": "testCreate",
"email": "test@test.com",
"password": "",
"password1": "",
"phone_number": "12345678",
"country": "Norway",
"city": "Oslo",
"street_address": "address 10"
}
variables = [
'username',
'email',
'password',
'password1',
'phone_number',
'country',
'city',
'street_address'
]
variable_values = {
'valid':
{
'username': 'Testuser',
'email': 'test@test.te',