Skip to content

Commit

Permalink
Merge 89805d1 into a2c1de7
Browse files Browse the repository at this point in the history
  • Loading branch information
CryceTruly committed Mar 20, 2019
2 parents a2c1de7 + 89805d1 commit 17fecc2
Show file tree
Hide file tree
Showing 15 changed files with 266 additions and 94 deletions.
5 changes: 5 additions & 0 deletions authors/apps/articles/admin.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
from .models import ReportedArticle
from django.contrib import admin


admin.site.register(ReportedArticle)
22 changes: 14 additions & 8 deletions authors/apps/articles/migrations/0001_initial.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
# Generated by Django 2.1.5 on 2019-03-20 08:46
# Generated by Django 2.1.5 on 2019-03-20 11:50

from django.conf import settings
import django.contrib.postgres.fields
from django.db import migrations, models
import django.db.models.deletion
Expand All @@ -11,7 +10,6 @@ class Migration(migrations.Migration):
initial = True

dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
('profiles', '0001_initial'),
]

Expand All @@ -33,8 +31,6 @@ class Migration(migrations.Migration):
('tagList', django.contrib.postgres.fields.ArrayField(base_field=models.CharField(max_length=200), blank=True, default=list, size=None)),
('favorited', models.BooleanField(default=False)),
('favoritesCount', models.IntegerField(default=0)),
('author', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='author_articles', to='profiles.Profile')),
('favorites', models.ManyToManyField(blank=True, related_name='favorited_articles', to='profiles.Profile')),
],
options={
'ordering': ['-created_at'],
Expand All @@ -47,8 +43,6 @@ class Migration(migrations.Migration):
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('likes', models.BooleanField(default=False, null=True)),
('created_at', models.DateTimeField(auto_now_add=True)),
('article', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='articles.Article')),
('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='profiles.Profile')),
],
),
migrations.CreateModel(
Expand All @@ -58,10 +52,22 @@ class Migration(migrations.Migration):
('rated_on', models.DateTimeField(auto_now_add=True)),
('score', models.DecimalField(decimal_places=2, max_digits=5)),
('article', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='ratings', to='articles.Article')),
('rated_by', models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, related_name='scores', to=settings.AUTH_USER_MODEL)),
],
options={
'ordering': ['-score'],
},
),
migrations.CreateModel(
name='ReportedArticle',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('reason', models.CharField(max_length=500)),
('reported_on', models.DateTimeField(auto_now_add=True)),
('article', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='articles.Article')),
('reporter', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='profiles.Profile')),
],
options={
'ordering': ['-reported_on'],
},
),
]
44 changes: 44 additions & 0 deletions authors/apps/articles/migrations/0002_auto_20190320_1150.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
# Generated by Django 2.1.5 on 2019-03-20 11:50

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


class Migration(migrations.Migration):

initial = True

dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
('profiles', '0001_initial'),
('articles', '0001_initial'),
]

operations = [
migrations.AddField(
model_name='rating',
name='rated_by',
field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, related_name='scores', to=settings.AUTH_USER_MODEL),
),
migrations.AddField(
model_name='articlelikesdislikes',
name='article',
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='articles.Article'),
),
migrations.AddField(
model_name='articlelikesdislikes',
name='user',
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='profiles.Profile'),
),
migrations.AddField(
model_name='article',
name='author',
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='author_articles', to='profiles.Profile'),
),
migrations.AddField(
model_name='article',
name='favorites',
field=models.ManyToManyField(blank=True, related_name='favorited_articles', to='profiles.Profile'),
),
]
13 changes: 13 additions & 0 deletions authors/apps/articles/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -123,3 +123,16 @@ class Rating(models.Model):

class Meta:
ordering = ["-score"]


class ReportedArticle(models.Model):
reporter=models.ForeignKey('profiles.Profile',on_delete=models.CASCADE)
article=models.ForeignKey('articles.Article',on_delete=models.CASCADE)
reason=models.CharField(max_length=500)
reported_on=models.DateTimeField(auto_now_add=True)

class Meta:
ordering=['-reported_on']

def __str__(self):
return self.reason
13 changes: 12 additions & 1 deletion authors/apps/articles/serializers.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from rest_framework import serializers
from .models import Article, ArticleLikesDislikes, Rating
from authors.apps.comments.models import Comment
from .models import Article, ArticleLikesDislikes, Rating, ReportedArticle

from ..profiles.serializers import ProfileSerializer

Expand Down Expand Up @@ -83,6 +83,8 @@ class RatingSerializer(serializers.ModelSerializer):
score = serializers.DecimalField(
required=True, max_digits=5, decimal_places=2)

score = serializers.DecimalField(required=True, max_digits=5,
decimal_places=2)
class Meta:
model = Rating
fields = ('score', 'rated_by', 'article', 'author')
Expand All @@ -95,3 +97,12 @@ def get_author(self, obj):

def get_rated_by(self, obj):
return obj.rated_by.username


class ReportedArticleSerializer(serializers.ModelSerializer):
reporter = ProfileSerializer(read_only=True)
article = ArticleSerializer(read_only=True)

class Meta:
model = ReportedArticle
fields = ('id', 'reporter', 'article', 'reason',)
4 changes: 4 additions & 0 deletions authors/apps/articles/tests/test_data.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,7 @@
"tagList": ["test", "apps"]
}
}

valid_reported_article={
"reason":"The post is copied from test.com"
}
52 changes: 52 additions & 0 deletions authors/apps/articles/tests/test_report_article.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
from rest_framework import status
from authors.apps.articles.tests.base_class import ArticlesBaseTest
from .test_data import valid_reported_article
from authors.apps.articles.models import Article
from django.urls import reverse


class TestReportArticle(ArticlesBaseTest):
def test_can_not_report_own_article(self):
"""
Tests method tests a user who is authenticated can report his/her own article
"""

self.add_article()

article = Article.objects.all().first()
response = self.client.post(
reverse('articles:report-article',
kwargs={'slug': article.slug}),
data=valid_reported_article, format='json')
self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN)
self.assertEqual(response.data['message'],
'You cannot report your own article')

def test_can_report_some_article(self):
"""
Tests if a user who is authenticated can report some article
"""

self.add_article()
self.register_and_login_new_user()

article = Article.objects.all().first()
response = self.client.post(
reverse('articles:report-article',
kwargs={'slug': article.slug}),
data=valid_reported_article, format='json')
self.assertEqual(response.status_code, status.HTTP_201_CREATED)

def test_can_report_some_article_not_logged_in(self):
"""
Tests if a user who is authenticated can report some article
"""
self.add_article()
article = Article.objects.all().first()
self.client.credentials(HTTP_AUTHORIZATION='')
response = self.client.post(
reverse('articles:report-article',
kwargs={'slug': article.slug}),
data=valid_reported_article, format='json')
self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN)
self.assertEqual(response.data['detail'], 'Authentication credentials were not provided.')
11 changes: 9 additions & 2 deletions authors/apps/articles/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,10 @@
from .views import (
ArticlesApiView, ArticleDetailApiView,
ArticleLikeApiView, RateArticleView,
FavoriteHandlerView, ArticleTagsApiView
FavoriteHandlerView, ArticleTagsApiView, ReportArticleView
)


urlpatterns = [
path('articles/', ArticlesApiView.as_view(), name='articles'),
path(
Expand All @@ -18,10 +20,15 @@
name='article-like'
),
path("articles/<slug>/rate/", RateArticleView.as_view(), name="rating"),

path("articles/<slug>/report/", ReportArticleView.as_view(),
name="report-article"),

path(
'tags/',
ArticleTagsApiView.as_view(),
name='article-tags'
),
path('articles/<slug>/favorite', FavoriteHandlerView.as_view(), name='article-favorite'),
path('articles/<slug>/favorite', FavoriteHandlerView.as_view(),
name='article-favorite'),
]
34 changes: 31 additions & 3 deletions authors/apps/articles/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
from .utils import Utils
from authors.apps.articles.models import Article, ArticleLikesDislikes, Rating
from ..profiles.models import Profile
from authors.apps.core.utils import Utilities


class ArticlesApiView (generics.ListCreateAPIView):
Expand Down Expand Up @@ -260,11 +261,38 @@ def post(self, request, slug):
user_obj=user, slug=article.slug)

def delete(self, request, slug):
user = request.user
article = get_object_or_404(Article, slug=slug)
if article in user.profile.favorited_articles.all():
if article in request.user.profile.favorited_articles.all():
return Article.objects.unfavorite_an_article(
request_user=user, slug=article.slug)
request_user=request.user, slug=article.slug)
else:
return Response({"error": "Article does not exist in your favorites"},
status=status.HTTP_400_BAD_REQUEST)


class ReportArticleView(generics.GenericAPIView):
serializer_class = serializers.ReportedArticleSerializer
permission_classes = (permissions.IsAuthenticated,)

def post(self, request, slug):
reporter = Profile.objects.get(user=request.user)
article = Article.objects.filter(slug=slug).first()
data = {
"reporter": reporter,
"article": article,
"reason": request.data['reason'] if 'reason' in request.data
else ''
}
if reporter == article.author:
return Response({"message": "You cannot report your own article"},
status=status.HTTP_403_FORBIDDEN)

serializer = self.serializer_class(data=data)
serializer.is_valid(raise_exception=True)
serializer.save(reporter=reporter, article=article)
data = {"subject": "[Article Reported]", "to":
serializer.data['article']['author']['email'],
"body": f"Your article was reported,These are the details:\n{data['reason']}"}
Utilities.send_email(data, 'article_reports')

return Response(serializer.data, status=status.HTTP_201_CREATED)
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.5 on 2019-03-19 08:16
# Generated by Django 2.1.5 on 2019-03-20 11:50

from django.db import migrations, models

Expand Down
8 changes: 4 additions & 4 deletions authors/apps/authentication/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ def post(self, request):
"created an account on Authors heaven.",
user_data['email']
]
Utilities.email_renderer(message)
Utilities.send_email(message,'auth')

return Response(user_data, status=status.HTTP_201_CREATED)

Expand Down Expand Up @@ -106,7 +106,7 @@ def get(self, request):
user.is_verified = True
user.save()
return self.sendResponse(
"Your Email has been verified,you can now login",
"Your Email has been verified,you can now login",
status.HTTP_200_OK
)

Expand All @@ -125,14 +125,14 @@ def post(self, request):
message = [
request,
"reset-password/change/",
str((jwt.encode({"email": request.data['email']},
str((jwt.encode({"email": request.data['email']},
settings.SECRET_KEY)).decode('utf-8')
),
"Reset Password",
"requested for password reset.",
request.data['email']
]
Utilities.email_renderer(message)
Utilities.send_email(message,'auth')
return Response(
{
"message": "Please check your email for the reset password link."
Expand Down
4 changes: 2 additions & 2 deletions authors/apps/comments/migrations/0001_initial.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Generated by Django 2.1.5 on 2019-03-20 08:46
# Generated by Django 2.1.5 on 2019-03-20 11:50

from django.db import migrations, models
import django.db.models.deletion
Expand All @@ -9,8 +9,8 @@ class Migration(migrations.Migration):
initial = True

dependencies = [
('articles', '0001_initial'),
('profiles', '0001_initial'),
('articles', '0002_auto_20190320_1150'),
]

operations = [
Expand Down
18 changes: 10 additions & 8 deletions authors/apps/core/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,15 @@ class Utilities:
"""Utility class that contains helper function"""

@staticmethod
def email_renderer(data):
def send_email(data,intent=None):
"""This function sends email to users."""

url = f"http://{get_current_site(data[0]).domain}/api/users/{data[1]}?token={data[2]}"
subject = f"[Authors Heaven] {data[3]}"
body = f"Hello, \
\nYou are receiving this e-mail because you have {data[4]}' \
'\nClick the click below to verify your account.\n{url}"
EmailMessage(subject, body, to=[data[5]]).send(fail_silently=False)
if intent == 'article_reports':
EmailMessage(data['subject'],body=data['body'],to=[data['to']]).send(fail_silently=False)
else:
url = f"http://{get_current_site(data[0]).domain}/api/users/{data[1]}?token={data[2]}"
subject = f"[Authors Heaven] {data[3]}"
body = f"Hello, \
\nYou are receiving this e-mail because you have {data[4]}' \
'\nClick the click below to verify your account.\n{url}"
EmailMessage(subject, body, to=[data[5]]).send(fail_silently=False)
return
2 changes: 1 addition & 1 deletion authors/apps/profiles/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ class Profile(models.Model):
updated_at = models.DateTimeField(auto_now=True)

def __str__(self):
return f"{self.user.username}"
return self.user.username

@property
def owner(self):
Expand Down
Loading

0 comments on commit 17fecc2

Please sign in to comment.