Skip to content

Commit

Permalink
Merge 2adcacc into 7f5f8af
Browse files Browse the repository at this point in the history
  • Loading branch information
sanya-kenneth committed May 7, 2019
2 parents 7f5f8af + 2adcacc commit 13e5991
Show file tree
Hide file tree
Showing 18 changed files with 361 additions and 2 deletions.
Binary file modified .DS_Store
Binary file not shown.
Empty file.
3 changes: 3 additions & 0 deletions authors/apps/bookmarks/admin.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
from django.contrib import admin

# Register your models here.
5 changes: 5 additions & 0 deletions authors/apps/bookmarks/apps.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
from django.apps import AppConfig


class BookmarksConfig(AppConfig):
name = 'bookmarks'
36 changes: 36 additions & 0 deletions authors/apps/bookmarks/fixtures/articles.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
[
{
"model": "articles.article",
"pk": 1,
"fields": {
"slug" : "this-is-andela-ftub",
"title": "this is andela",
"description": "the techville",
"body": "best place to work in Uganda",
"created_at": "2019-04-29T14:13:25.526681Z",
"updated_at": "2019-04-29T14:13:25.526692Z",
"likes_count": 1,
"dislikes_count": 0,
"favorited": false,
"favorite_count": 0,
"author_id": "sanya"
}
},
{
"model": "articles.article",
"pk": 2,
"fields": {
"slug" : "python-is-good-ftuz",
"title": "python is good",
"description": "for all companies",
"body": "try out this new language",
"created_at": "2019-04-29T14:13:25.526681Z",
"updated_at": "2019-04-29T14:13:25.526692Z",
"likes_count": 1,
"dislikes_count": 0,
"favorited": false,
"favorite_count": 0,
"author_id": "sanya"
}
}
]
13 changes: 13 additions & 0 deletions authors/apps/bookmarks/fixtures/bookmark.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
[
{
"model": "bookmarks.bookmark",
"pk": 30,
"fields": {
"article_title": "python is good",
"date_created": "2019-04-29T14:13:25.526681Z",
"article_id": 2,
"user_id": 3,
"username": "admin"
}
}
]
40 changes: 40 additions & 0 deletions authors/apps/bookmarks/fixtures/users.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
[
{
"model": "authentication.user",
"pk": 1,
"fields": {
"username": "sanya",
"email": "sanyaken@gmail.com",
"password": "pbkdf2_sha256$120000$Rf2yxsEFXOI8$095XPdmnuheMIofQPVnlMftNwb/gg2BB67VIJgKljuc=",
"created_at": "2013-03-23 00:03:00",
"updated_at": "2013-03-23 01:02:00"
}
},

{
"model": "authentication.user",
"pk": 2,
"fields": {
"username": "kenned",
"email": "kenned@gmail.com",
"password": "pbkdf2_sha256$120000$FrOa2gzoWZ3m$v0T3Qk3hobNTxWrth6cHjNCREZtwWZiSDw357Hp3tbI=",
"created_at": "2013-03-23 00:03:00",
"updated_at": "2013-03-23 01:02:00"
}
},
{
"model": "authentication.user",
"pk": 3,
"fields": {
"username": "adminuser",
"email": "admin@gmail.com",
"password": "pbkdf2_sha256$120000$Xh4W8kGbUrgM$f9UVM8xwSI+pEYNdhb6L/g4IEGUJQEJ2d1SARabmhKo=",
"created_at": "2013-03-23 00:03:00",
"updated_at": "2013-03-23 01:02:00",
"is_active": true,
"is_superuser": true,
"email_verified": true
}
}

]
29 changes: 29 additions & 0 deletions authors/apps/bookmarks/migrations/0001_initial.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
# Generated by Django 2.1 on 2019-05-07 20:51

from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion


class Migration(migrations.Migration):

initial = True

dependencies = [
('articles', '0003_auto_20190505_1829'),
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
]

operations = [
migrations.CreateModel(
name='Bookmark',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('date_created', models.DateTimeField(auto_now_add=True)),
('username', models.CharField(max_length=70, null=True)),
('article_title', models.CharField(max_length=300, null=True)),
('article_id', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='articles.Article')),
('user_id', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)),
],
),
]
Empty file.
19 changes: 19 additions & 0 deletions authors/apps/bookmarks/models.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
from django.db import models
from django.utils.text import slugify
from authors.apps.articles.models import Article
from authors.apps.authentication.models import User


class Bookmark(models.Model):
"""
Model class for bookmarks
"""
date_created = models.DateTimeField(auto_now_add=True)
user_id = models.ForeignKey(User, on_delete=models.CASCADE)
username = models.CharField(max_length=70, null=True)
article_id = models.ForeignKey(Article, on_delete=models.CASCADE)
article_title = models.CharField(max_length=300, null=True)


def __str__(self):
return self.article_title
12 changes: 12 additions & 0 deletions authors/apps/bookmarks/serializers.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
from rest_framework import serializers
from authors.apps.bookmarks.models import Bookmark


class BookmarkSerializer(serializers.ModelSerializer):
"""
Srializer class for bookmarks
"""
class Meta:
model = Bookmark
fields = ('id', 'user_id', 'article_id', 'username',
'article_title', 'date_created')
Empty file.
27 changes: 27 additions & 0 deletions authors/apps/bookmarks/tests/base.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
from rest_framework.test import APIClient, APITestCase
from django.urls import reverse


class BaseTestCase(APITestCase):
"""
Class to setup our tests
"""
fixtures = ['authors/apps/bookmarks/fixtures/users.json',
'authors/apps/bookmarks/fixtures/articles.json',
'authors/apps/bookmarks/fixtures/bookmark.json'
]

login_data = {
"user": {
"email": "admin@gmail.com",
"password": "admin123456"
}
}

def setUp(self):
self.client = APIClient()
self.login_url = reverse('user_login')
self.login_response = self.client.post(
self.login_url, self.login_data, format='json')
test_token = self.login_response.data['token']
self.auth_header = 'Bearer {}'.format(test_token)
57 changes: 57 additions & 0 deletions authors/apps/bookmarks/tests/test_bookmarks.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
from django.urls import reverse
from .base import BaseTestCase


class BookmarkTestCase(BaseTestCase):
"""
Class Test Case for bookmarks
"""
def test_creates_bookmark(self):
url = '/api/articles/1/bookmarks/'
response = self.client.post(url, HTTP_AUTHORIZATION=self.auth_header, format="json")
self.assertEqual(response.status_code, 201)
self.assertEqual(response.data['bookmark']['article_title'], 'this is andela')
self.assertEqual(response.data['bookmark']['id'], 31)
self.assertEqual(response.data['bookmark']['article_id'], 1)
self.assertEqual(response.data['bookmark']['username'], 'adminuser')

def test_returns_error_if_user_attempts_to_bookmark_twice(self):
url = '/api/articles/1/bookmarks/'
self.client.post(url, HTTP_AUTHORIZATION=self.auth_header, format="json")
response = self.client.post(url, HTTP_AUTHORIZATION=self.auth_header, format="json")
self.assertEqual(response.status_code, 400)
self.assertIn(response.data['error'], "You already bookmarked this Article")

def test_gets_bootmarks(self):
url = reverse("list_bookmarks")
url_create = '/api/articles/1/bookmarks/'
self.client.post(url_create, HTTP_AUTHORIZATION=self.auth_header, format="json")
response = self.client.get(url, HTTP_AUTHORIZATION=self.auth_header, format="json")
self.assertEqual(response.status_code, 200)
self.assertIsInstance(response.data['bookmarks'], list)

def test_gets_one_bookmark(self):
url_create = '/api/articles/1/bookmarks/'
url = '/api/bookmarks/30/'
self.client.post(url_create, HTTP_AUTHORIZATION=self.auth_header, format="json")
response = self.client.get(url, HTTP_AUTHORIZATION=self.auth_header, format="json")
self.assertEqual(response.status_code, 200)

def test_deletes_bookmark(self):
url = '/api/bookmarks/30/delete/'
response = self.client.delete(url, HTTP_AUTHORIZATION=self.auth_header, format="json")
self.assertEqual(response.status_code, 204)

def test_returns_error_if_article_doesnot_exist_on_bookmarking(self):
url = '/api/articles/1000/bookmarks/'
response = self.client.post(url, HTTP_AUTHORIZATION=self.auth_header, format="json")
self.assertEqual(response.status_code, 404)
self.assertIn("Article does not exist", str(response.data))

def test_returns_error_if_no_bookmark_is_found(self):
url = reverse('list_bookmarks')
url_d = '/api/bookmarks/30/delete/'
self.client.delete(url_d, HTTP_AUTHORIZATION=self.auth_header, format="json")
response = self.client.get(url, HTTP_AUTHORIZATION=self.auth_header, format="json")
self.assertEqual(response.status_code, 404)
self.assertIn("No bookmarks found", str(response.data))
11 changes: 11 additions & 0 deletions authors/apps/bookmarks/urls.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
from django.urls import path
from .views import CreateBookmark, ListBookmarks, RetrieveBookmark, DeleteBookmark


urlpatterns = [
path('articles/<int:pk>/bookmarks/',
CreateBookmark.as_view(), name="create_bookmarks"),
path('bookmarks/', ListBookmarks.as_view(), name="list_bookmarks" ),
path('bookmarks/<int:pk>/', RetrieveBookmark.as_view(), name="retrieve_bookmark" ),
path('bookmarks/<int:pk>/delete/', DeleteBookmark.as_view(), name="delete_bookmark" )
]
105 changes: 105 additions & 0 deletions authors/apps/bookmarks/views.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
from rest_framework.generics import CreateAPIView, ListAPIView, RetrieveAPIView, DestroyAPIView
from rest_framework.response import Response
from rest_framework import status
from rest_framework.exceptions import NotFound
from authors.apps.articles.models import Article
from .serializers import BookmarkSerializer
from .models import Bookmark


class GetBookMarks:

@staticmethod
def get_bookmarks(req):
try:
bookmarklist = Bookmark.objects.all()
return bookmarklist
except Bookmark.DoesNotExist:
return None


class CreateBookmark(CreateAPIView):
"""
View class for creating a bookmark
"""
serializer_class = BookmarkSerializer

def create(self, request, pk):
"""
Method creates a new bookmark
"""
try:
user = request.user
bookmarks = GetBookMarks.get_bookmarks(request)
article = Article.objects.get(pk=pk)
for bookmark in bookmarks:
if bookmark.user_id.id == user.id and\
bookmark.article_id.id == int(article.id):
return Response({'error': 'You already bookmarked this Article'},
status=status.HTTP_400_BAD_REQUEST)
data = {'user_id': user.id, 'username': user.username,
'article_title': article.title, 'article_id': article.id}
serializer = BookmarkSerializer(data=data)
serializer.is_valid(raise_exception=True)
serializer.save()
response_data = serializer.data
response_data.pop('user_id')
return Response({'bookmark': response_data},
status=status.HTTP_201_CREATED)
except:
error = {'error': 'Article does not exist'}
raise NotFound(detail=error)


class ListBookmarks(ListAPIView):
"""
View class for fetching all user bookmarks
"""
serializer_class = BookmarkSerializer

def get(self, request):
"""
Method gets a list of bookmarks of the current user
"""
user = request.user
bookmarks = Bookmark.objects.filter(user_id=user.id)
if bookmarks:
serializer = BookmarkSerializer(bookmarks, many=True)
return Response({'bookmarks': serializer.data},
status=status.HTTP_200_OK)
return Response({'message': 'No bookmarks found'},
status=status.HTTP_404_NOT_FOUND)


class RetrieveBookmark(RetrieveAPIView):
"""
View class for getting one bookmark
"""
serializer_class = BookmarkSerializer
queryset = Bookmark.objects.all()

def retrieve(self, request, *args, **kwargs):
"""
Method gets one bookmark
"""
instance = self.get_object()
serializer = self.get_serializer(instance)
return Response({'bookmark': serializer.data},
status=status.HTTP_200_OK)


class DeleteBookmark(DestroyAPIView):
"""
View class for deleting a bookmark
"""
serializer_class = BookmarkSerializer
queryset = Bookmark.objects.all()

def destroy(self, request, *args, **kwargs):
"""
Method deletes a bookmark
"""
instance = self.get_object()
self.perform_destroy(instance)
return Response({"message": "Bookmark deleted"},
status=status.HTTP_204_NO_CONTENT)
3 changes: 2 additions & 1 deletion authors/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,8 @@
'authors.apps.comments',
'authors.apps.favorites',
'authors.apps.rate_article',
'authors.apps.article_tags'
'authors.apps.article_tags',
'authors.apps.bookmarks'
]

MIDDLEWARE = [
Expand Down
3 changes: 2 additions & 1 deletion authors/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,5 +24,6 @@
path('api/', include('authors.apps.comments.urls')),
path('api/articles/', include('authors.apps.favorites.urls')),
path('api/', include('authors.apps.rate_article.urls')),
path('api/', include('authors.apps.article_tags.urls'))
path('api/', include('authors.apps.article_tags.urls')),
path('api/', include('authors.apps.bookmarks.urls'))
]

0 comments on commit 13e5991

Please sign in to comment.