Skip to content

Commit

Permalink
Merge a60d021 into cb7d263
Browse files Browse the repository at this point in the history
  • Loading branch information
Eyansky committed Nov 10, 2018
2 parents cb7d263 + a60d021 commit 51b86bf
Show file tree
Hide file tree
Showing 26 changed files with 457 additions and 106 deletions.
4 changes: 2 additions & 2 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@ install:
script:
- python3 manage.py makemigrations authentication
- python3 manage.py migrate authentication
- python3 manage.py makemigrations articles
- python3 manage.py migrate articles
- python3 manage.py makemigrations article
- python3 manage.py migrate article
- python3 manage.py makemigrations
- python3 manage.py migrate
- coverage run manage.py test
Expand Down
Binary file added article/pexels-photo-46710.jpeg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added article/pexels-photo-46710_0Xj3j4y.jpeg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added article/pexels-photo-46710_d9gLnYe.jpeg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added article/pexels-photo-46710_fIxGucm.jpeg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added article/pexels-photo-46710_n1GDsDu.jpeg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
File renamed without changes.
File renamed without changes.
104 changes: 104 additions & 0 deletions authors/apps/article/models.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
# this is how the db will be structured.

from django.db import models
from django.utils.translation import pgettext_lazy as _
from django.contrib.auth import get_user_model
from django.core.validators import MaxValueValidator, MinValueValidator

'''Django-autoslug is a reusable Django library
that provides an improved slug field which can automatically:
populate itself from another field and preserve
uniqueness of the value'''
from autoslug import AutoSlugField
from versatileimagefield.fields import VersatileImageField


class Article(models.Model):
user = models.ForeignKey(
get_user_model(),
related_name='author',
on_delete=models.CASCADE,
null=True,
blank=True,
default=None
)
# creates a random identifier for a particular article from the title
# field.
slug = AutoSlugField(
populate_from='title',
blank=True,
null=True,
unique=True)
title = models.CharField(
_('Article field', 'title'),
unique=True,
max_length=128
)
description = models.TextField(
_('Article Field', 'description'),
blank=True,
null=True
)
body = models.TextField(
_('Article Field', 'body'),
blank=True,
null=True
)
image = VersatileImageField(
'Image',
upload_to='article/',
width_field='width',
height_field='height',
blank=True,
null=True
)
height = models.PositiveIntegerField(
'Image Height',
blank=True,
null=True
)
width = models.PositiveIntegerField(
'Image Width',
blank=True,
null=True
)
created_at = models.DateTimeField(
_('Article field', 'created at'),
auto_now_add=True,
editable=False
)
updated_at = models.DateTimeField(
_('Article field', 'updated at'),
auto_now=True
)

class Meta:
app_label = "article"

def __str__(self):
return self.title


class RateArticle(models.Model):
"""
This is the article class. It holds data for the article.
"""
rater = models.ForeignKey(
"authentication.User",
related_name="ratearticle",
on_delete=models.CASCADE) # link with the user who rated
article = models.ForeignKey(
"article.Article",
related_name="ratearticle",
on_delete=models.CASCADE) # link with the article being rated
rate = models.IntegerField(null=False, blank=False,
validators=[
MaxValueValidator(5),
MinValueValidator(1)
]) # rate value column

def __str__(self):
"""
Return a human readable format
"""
return self.rate
84 changes: 84 additions & 0 deletions authors/apps/article/serializers.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
'''Serializers allow complex data
such as querysets and model instances
to be converted to
native Python datatypes that can then
be easily rendered into JSON, XML or other content types.'''

from rest_framework import serializers
from django.apps import apps
from .models import RateArticle
from authors.apps.profiles.serializers import ProfileListSerializer


TABLE = apps.get_model('article', 'Article')
Profile = apps.get_model('profiles', 'UserProfile')

NAMESPACE = 'article'
fields = ('id', 'slug', 'image', 'title', 'description', 'body', 'user',)


class ArticleSerializer(serializers.ModelSerializer):
update_url = serializers.HyperlinkedIdentityField(
view_name=NAMESPACE + ':update', lookup_field='slug')
delete_url = serializers.HyperlinkedIdentityField(
view_name=NAMESPACE + ':delete', lookup_field='slug')
author = serializers.SerializerMethodField(read_only=True)

class Meta:
model = TABLE

fields = fields + ('author', 'update_url', 'delete_url')

def get_author(self, obj):
try:
serializer = ProfileListSerializer(
instance=Profile.objects.get(user=obj.user)
)
return serializer.data
except BaseException:
return {}

def update(self, instance, validated_data):
instance.title = validated_data.get('title', instance.title)
instance.description = validated_data.get(
'description', instance.description)
instance.body = validated_data.get('body', instance.body)
if validated_data.get('image'):
instance.image = validated_data.get('image', instance.image)

instance.save()

return instance


class ArticleCreateSerializer(serializers.ModelSerializer):
class Meta:
model = TABLE

fields = fields

def create(self, validated_data):
instance = TABLE.objects.create(**validated_data)
validated_data['slug'] = instance.slug

return validated_data


class RateArticleSerializer(serializers.ModelSerializer):
"""
validate rate article
"""
slug = serializers.SlugField()
rate = serializers.IntegerField()

def validate(self, data):
rate = data['rate']
if not rate > 0 or not rate <= 5:
raise serializers.ValidationError(
'invalid rate value should be > 0 or <=5')

return data

class Meta:
model = RateArticle
fields = ("slug", "rate")
File renamed without changes.
File renamed without changes.
100 changes: 100 additions & 0 deletions authors/apps/article/tests/test_article.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
from django.apps import apps
from django.test import TestCase
from django.urls import reverse
from rest_framework.test import APIClient
import factory
from faker import Factory
from django.contrib.auth import get_user_model

Article = apps.get_model('article', 'Article')
faker = Factory.create()


class UserFactory(factory.DjangoModelFactory):
class Meta:
model = get_user_model()

username = factory.Sequence(lambda n: 'map%d' % n)
email = factory.Sequence(lambda n: 'example_%s@map.com' % n)
password = factory.PostGenerationMethodCall('set_password', '1234abcd')


class ArticleFactory(factory.DjangoModelFactory):
class Meta:
model = Article

user = factory.SubFactory(UserFactory)
title = faker.name()
description = faker.text()
body = faker.text()
slug = factory.Sequence(lambda n: 'map-slug%d' % n)
image = factory.django.ImageField(color='blue')


class TestArticles(TestCase):
def setUp(self):
self.user = UserFactory()
self.article = ArticleFactory()
self.client = APIClient()
self.client.force_authenticate(user=self.user)
self.client.credentials(
HTTP_AUTHORIZATION='Bearer ' +
self.user.token())

self.namespace = 'article'
self.body = {
'title': faker.name(),
'description': faker.text(),
'body': faker.text(),
}
self.create_url = reverse(self.namespace + ':create')
self.list_url = reverse(self.namespace + ':list')
self.update_url = reverse(
self.namespace + ':update',
kwargs={
'slug': self.article.slug})
self.delete_url = reverse(
self.namespace + ':delete',
kwargs={
'slug': self.article.slug})
self.retrieve_url = reverse(
self.namespace + ':detail',
kwargs={
'slug': self.article.slug})

def test_create_article_api(self):
response = self.client.post(self.create_url, self.body, format='json')
self.assertEqual(201, response.status_code)

def test_retrieve_article_api(self):
response = self.client.get(self.retrieve_url)
self.assertContains(response, self.article)

def test_list_article_api_with_parameters(self):
self.client.post(self.create_url, self.body, format='json')
response = self.client.get(
self.list_url + '?q=' + self.article.slug[0])
self.assertContains(response, self.article)

def test_listing_articles_api(self):
response = self.client.get(self.list_url)
self.assertContains(response, self.article)

def test_update_article_api(self):
response = self.client.post(self.create_url, self.body, format='json')
self.update_url = reverse(
self.namespace + ':update',
kwargs={
'slug': response.data.get('slug')})
response = self.client.put(self.update_url, self.body)
self.assertEqual(200, response.status_code)

def test_delete_article_api(self):
response = self.client.post(self.create_url, self.body, format='json')
self.delete_url = reverse(
self.namespace + ':delete',
kwargs={
'slug': response.data.get('slug')})

response = self.client.delete(self.delete_url)
self.assertEqual(204, response.status_code)
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,14 @@ def setUp(self):
"""
Prepare test environment for each testcase
"""

self.article = {
"title": "How to train your dragon today",
"description": "Ever wonder how?",
"body": "You have to believe in you",
"image": "https://dummyimage.com/600x400/000/fff"
}

self.client = APIClient()
self.article = Article()
self.signup_url = reverse('authentication:register')
Expand Down Expand Up @@ -53,21 +61,25 @@ def setUp(self):
body = "this is a body"
author = self.user
article = Article(
author=author,
user=author,
slug=self.slug,
body=body,
title=title,
description=description)
description=description
)
article.save()
self.rate_details = {
"user": {
"slug": self.slug,
"rate": 3
}
}
self.rate_url = os.environ["URL"]+"api/article/"\
+ self.slug + "/rate/"
self.view_rates_url = os.environ["URL"]+"api/article/rate/"
self.rate_url = os.environ["URL"] + \
"api/article/" + self.slug + "/rate/"
self.view_rates_url = os.environ["URL"] + "api/article/rate/"

self.articles_url = os.environ["URL"] + "api/article/"
self.create_articles_url = os.environ["URL"] + "api/article/create"

def test_rate_article_without_token(self):
"""
Expand Down Expand Up @@ -152,9 +164,7 @@ def test_get_rate_article(self):
response = self.client.get(
self.view_rates_url + str(1) + "/",
format='json')
self.assertEqual(
3.5,
response.data["rates"])

self.assertEqual(response.status_code, status.HTTP_200_OK)

def test_get_rate_article_not_found(self):
Expand Down
Loading

0 comments on commit 51b86bf

Please sign in to comment.