-
Notifications
You must be signed in to change notification settings - Fork 6
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Add create bookmark functionality - Add get bookmark list functionality - Add get one bookmark - Add delete a bookmark [#165273491]
- Loading branch information
1 parent
7f5f8af
commit 2adcacc
Showing
18 changed files
with
361 additions
and
2 deletions.
There are no files selected for viewing
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
from django.contrib import admin | ||
|
||
# Register your models here. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
from django.apps import AppConfig | ||
|
||
|
||
class BookmarksConfig(AppConfig): | ||
name = 'bookmarks' |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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" | ||
} | ||
} | ||
] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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" | ||
} | ||
} | ||
] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 | ||
} | ||
} | ||
|
||
] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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)) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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" ) | ||
] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters