Skip to content

Commit

Permalink
Merge 3e2be7a into 6d02828
Browse files Browse the repository at this point in the history
  • Loading branch information
zaabu committed Oct 16, 2018
2 parents 6d02828 + 3e2be7a commit 4c3dc44
Show file tree
Hide file tree
Showing 12 changed files with 110 additions and 19 deletions.
3 changes: 2 additions & 1 deletion authors/apps/articles/admin.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
from django.contrib import admin
from authors.apps.articles.models import Article, RateArticle, LikeArticle
from authors.apps.articles.models import Article, RateArticle, LikeArticle, Category
admin.site.register(Article)
admin.site.register(RateArticle)
admin.site.register(LikeArticle)
admin.site.register(Category)
6 changes: 5 additions & 1 deletion authors/apps/articles/exceptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,8 @@

class TagHasNoArticles(APIException):
status_code = 400
default_detail = "This tag currently has no articles"
default_detail = "This tag currently has no articles"

class CatHasNoArticles(APIException):
status_code = 400
default_detail = "This category currently has no articles"
17 changes: 17 additions & 0 deletions authors/apps/articles/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,20 @@
from taggit.managers import TaggableManager


class Category(models.Model):
title = models.CharField(max_length=100)
slug = models.SlugField(max_length=100, unique=True)

class Meta:
verbose_name_plural = "Categories"

def __str__(self):
return self.title

def save(self, *args, **kwargs):
if not self.slug:
self.slug = get_unique_slug(self, 'title', 'slug')
return super().save(*args, **kwargs)

class Article(models.Model):
"""
Expand Down Expand Up @@ -43,6 +57,9 @@ class Article(models.Model):

tags = TaggableManager()

category = models.ForeignKey(Category,
on_delete=models.CASCADE)

def __str__(self):
"""
Returns a string representation of this `Article`.
Expand Down
6 changes: 6 additions & 0 deletions authors/apps/articles/renderers.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,3 +21,9 @@ class LikeUserJSONRenderer(AhJSONRenderer):
class RateUserJSONRenderer(AhJSONRenderer):
charset = 'utf-8'
object_label = 'rate'

class CategoryJSONRenderer(AhJSONRenderer):
charset = 'utf-8'
object_label = 'category'


14 changes: 11 additions & 3 deletions authors/apps/articles/serializers.py
Original file line number Diff line number Diff line change
@@ -1,31 +1,39 @@
from authors.apps.articles.models import Article, RateArticle, LikeArticle
from authors.apps.articles.models import Article, RateArticle, LikeArticle, Category
from authors.apps.authentication.models import User
from django.core.exceptions import ObjectDoesNotExist
from rest_framework import serializers
from taggit_serializer.serializers import (TagListSerializerField,
TaggitSerializer)

from taggit.models import Tag


class ArticleSerializer(TaggitSerializer, serializers.ModelSerializer):
"""Serializer for articles."""
author = serializers.ReadOnlyField(source='author.username')
read_time = serializers.ReadOnlyField(source='read')
tags = TagListSerializerField()

class Meta:
model = Article
""" List all of the fields that could possibly be included in a request
or response, including fields specified explicitly above."""

fields = ('author', 'title', 'slug', 'description',
'body', 'created_at', 'updated_at', 'read_time', 'average_rating', 'likes', 'dislikes','tags',)
'body', 'created_at', 'updated_at', 'read_time', 'average_rating', 'likes', 'dislikes','tags','category')
read_only_fields = ('slug', 'author_id',)

class TagSerializer(serializers.ModelSerializer):

class Meta:
model = Tag
fields = ('name',)

class CategorySerializer(serializers.ModelSerializer):

class Meta:
model = Category
fields = ('title',)

class RateArticleSerializer(serializers.ModelSerializer):
rated_by = serializers.ReadOnlyField(source='rated_by.username')
Expand Down
6 changes: 5 additions & 1 deletion authors/apps/articles/urls.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
from django.urls import path

from .views import (ArticleAPIView, ArticleAPIDetailsView,
RateArticleView, LikeArticleView, LikeAPIDetailsView, TagListAPIView, TagRetrieveAPIView)
RateArticleView, LikeArticleView, LikeAPIDetailsView,
TagListAPIView, TagRetrieveAPIView, CategoryListCreateAPIView, CategoryRetrieveAPIView)

app_name = "articles"

Expand All @@ -16,4 +17,7 @@
LikeAPIDetailsView.as_view(), name='dislike'),
path("tags/", TagListAPIView.as_view()),
path("tags/<str:tag_name>/", TagRetrieveAPIView.as_view()),
path("categories/", CategoryListCreateAPIView.as_view()),
path("categories/<str:cat_name>/", CategoryRetrieveAPIView.as_view()),

]
46 changes: 40 additions & 6 deletions authors/apps/articles/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,30 +7,32 @@
from django.http import JsonResponse
from django.shortcuts import get_object_or_404, render
from rest_framework import generics, serializers, status
from rest_framework.exceptions import PermissionDenied
from rest_framework.exceptions import PermissionDenied, ValidationError
from rest_framework.generics import ListCreateAPIView
from rest_framework.permissions import (AllowAny, IsAuthenticated,
IsAuthenticatedOrReadOnly)
from rest_framework.response import Response
from django.http import JsonResponse
from taggit.models import Tag

from .exceptions import TagHasNoArticles
from .models import Article, LikeArticle, RateArticle
from .exceptions import TagHasNoArticles, CatHasNoArticles
from .models import Article, LikeArticle, RateArticle, Category
from .renderers import (ArticleJSONRenderer, LikeUserJSONRenderer,
RateUserJSONRenderer,TagJSONRenderer)
RateUserJSONRenderer,TagJSONRenderer, CategoryJSONRenderer)
from .serializers import (ArticleSerializer, LikeArticleSerializer,
RateArticleSerializer)
RateArticleSerializer, CategorySerializer)


class TagListAPIView(generics.ListAPIView):
""" List all tags """
queryset = Tag.objects.all()
permission_classes = (AllowAny,)
renderer_classes = (TagJSONRenderer,)
serializer_class = TagSerializer


class TagRetrieveAPIView(generics.RetrieveAPIView):

""" Get articles under a specific tag """
permission_classes = (AllowAny,)
renderer_classes = (ArticleJSONRenderer,)

Expand All @@ -42,6 +44,38 @@ def retrieve(self, request, *args, **kwargs):
else:
raise TagHasNoArticles("This tag currently has no articles")

class CategoryListCreateAPIView(generics.ListCreateAPIView):
""" List / Create categories """

queryset = Category.objects.all()
permission_classes = (AllowAny,)
serializer_class = CategorySerializer
renderer_classes = (CategoryJSONRenderer,)

def create(self, request):
category = Category.objects.filter(
title=request.data.get('title'),
)
if category:
raise ValidationError("Category with this title already exists")
return super().create(request)


class CategoryRetrieveAPIView(generics.RetrieveAPIView):
""" Get articles under a specific category """
permission_classes = (AllowAny,)
serializer_class = ArticleSerializer

def retrieve(self, request, *args, **kwargs):
try:
cat_name = self.kwargs["cat_name"]
category = Category.objects.get(title=cat_name)
articles = Article.objects.filter(category=category).values()
return Response({'articles': articles}, status=status.HTTP_200_OK)
except ObjectDoesNotExist:
raise CatHasNoArticles("The category currently has no articles")


class ArticleAPIView(generics.ListCreateAPIView):
"""create an article, list all articles paginated to 5 per page"""
queryset = Article.objects.all()
Expand Down
2 changes: 1 addition & 1 deletion authors/apps/authentication/migrations/0001_initial.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Generated by Django 2.1.1 on 2018-10-15 11:05
# Generated by Django 2.1 on 2018-10-15 19:51

from django.db import migrations, models

Expand Down
1 change: 1 addition & 0 deletions authors/apps/core/exceptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ def core_exception_handler(exc, context):
handlers = {
'ProfileDoesNotExist': _handle_generic_error,
'TagHasNoArticles': _handle_generic_error,
'CatHasNoArticles': _handle_generic_error,
'ValidationError': _handle_generic_error
}
# This is how we identify the type of the current exception. We will use
Expand Down
File renamed without changes.
3 changes: 2 additions & 1 deletion tests/test_articles/test_articles.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,15 @@
from rest_framework import status
# from tests.test_authentication.test_base import BaseTest
from ..test_authentication.test_base import BaseTest
from authors.apps.articles.models import Article
from authors.apps.articles.models import Article, Category
from authors.apps.authentication.models import User

class ArticlesTest(APITestCase,BaseTest):
def setUp(self):
BaseTest.__init__(self)
self.client = APIClient()


def create_login_user(self):
user=User.objects.create_user(self.username,self.email,self.password)
User.is_verified=True
Expand Down
25 changes: 20 additions & 5 deletions tests/test_authentication/test_base.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
from authors.apps.articles.models import Category

class BaseTest:
"""
Class contains data to be used for testing
Expand All @@ -12,6 +14,12 @@ def __init__(self):
self.title = "How to tnnrain your flywwwwwwwwwwf"
self.description = "Ever wondner how toddddd ddddwwwwd?"
self.body = "You have to benlieve becausedddddddddcf"

self.category = Category.objects.create(
title='test category',
)


self.reg_data = {
"user": {
"username": self.username,
Expand Down Expand Up @@ -66,7 +74,9 @@ def __init__(self):
"description": self.description,
"body": self.body,
"tags": ["reactjs"],
"category_name": "Money"

"category": self.category.id

}
}

Expand All @@ -76,7 +86,8 @@ def __init__(self):
"description": self.description,
"body": self.body,
"tags": ["reactjs", "angularjs", "dragons"],
"category_name": "Money"
"category": self.category.id

}
}

Expand All @@ -87,7 +98,8 @@ def __init__(self):
"description": "",
"body": "",
"tags": ["reactjs", "angularjs", "dragons"],
"category_name": "Money"
"category": self.category.id

}
}
self.wrong_article_update = {
Expand All @@ -96,7 +108,8 @@ def __init__(self):
"description": "",
"body": "You cc",
"tags": ["reactjs", "angularjs", "dragons"],
"category_name": "Money"
"category": self.category.id

}
}

Expand All @@ -106,7 +119,7 @@ def __init__(self):
"description": "How to manage carrying",
"body": "You cc",
"tags": ["reactjs", "angularjs", "dragons"],
"category_name": "Money"
"category": self.category.id
}
}

Expand All @@ -133,3 +146,5 @@ def __init__(self):
"likes": True,
}
}


0 comments on commit 4c3dc44

Please sign in to comment.