Skip to content

Commit

Permalink
Merge pull request #88 from Anas-mhameed/view-article
Browse files Browse the repository at this point in the history
Adding read article feature, adding a new view, new template, new route
  • Loading branch information
Yarboa authored Jan 18, 2023
2 parents db3ab2d + 9ccb289 commit fbbe167
Show file tree
Hide file tree
Showing 8 changed files with 285 additions and 22 deletions.
5 changes: 3 additions & 2 deletions finalProject_g4/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,12 @@
urlpatterns = [
path('admin/', admin.site.urls),
path('', views.home_page, name='homepage'),
path('search/', views.search, name='search'),
path('search/<str:user_nickname>/', views.search, name='search'),
path('create_article/', views.create_article, name='create_article'),
path('about/', views.about_page, name='aboutpage'),
path('my_articles/<str:nickname>/', views.my_articles, name="my_articles"),
path('signup/', views.sign_up, name='signup')
path('signup/', views.sign_up, name='signup'),
path('article/<str:user_nickname>/<str:article_pk>/', views.show_article, name='show_article'),
]

handler404 = views.error_404
36 changes: 36 additions & 0 deletions projboard/static/css/read_article.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@

article{
max-width: 70%;
margin: 0 auto;

}
header{
min-height: 40vh;
}
.footer {

display: flex;
justify-content: flex-end;
align-items: flex-end;
gap: 1rem;
}
.footer > *{
margin : 0px 0px 0px;
}
hr {
border: 0;
height: 3px;
background-image: -webkit-linear-gradient(left, #5b5b5b, #3c3326, #f0f0f0);
background-image: -moz-linear-gradient(left, #5b5b5b, #3c3326, #f0f0f0);
background-image: -ms-linear-gradient(left, #5b5b5b, #3c3326, #f0f0f0);
background-image: -o-linear-gradient(left, #5b5b5b, #3c3326, #f0f0f0);
}
.nickname{
justify-self: flex-start;
}
.Green{
background-color: rgb(54, 169, 38);
}
.Red{
background-color: rgb(186, 80, 80);
}
2 changes: 1 addition & 1 deletion projboard/templates/base.html
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@
<a class="nav-link" href="/create_article">Create Article</a>
</li>
<li class="nav-item">
<a class="nav-link" href="/search">Search Article</a>
<a class="nav-link" href="/search/''">Search Article</a>
</li>
<li class="nav-item">
<a class="nav-link" href="/about">About</a>
Expand Down
2 changes: 1 addition & 1 deletion projboard/templates/searchArticle/search_article.html
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ <h2>{{article.title | truncatechars:30}}</h2>
<p>{{article.content | truncatechars:70}}</p>
<footer>
<div class="footer">
<button role="submit">View Blog</button>
<a href="{% url 'show_article' user_nickname=user.nickname article_pk=article.id %}"><button>View Blog</button></a>
<p>
<strong>Category</strong>:
{% if article.subject_id == null %}
Expand Down
59 changes: 59 additions & 0 deletions projboard/templates/show/read_article.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
{% extends "base.html" %}
{% load static %}
{% block content %}
<head>
<link rel="stylesheet" type="text/css" href="{% static 'css/read_article.css' %}">
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:opsz,wght,FILL,[email protected],100..700,0..1,-50..200" />
<link rel="preconnect" href="https://fonts.googleapis.com"><link rel="preconnect" href="https://fonts.gstatic.com" crossorigin><link href="https://fonts.googleapis.com/css2?family=Anton&family=Zilla+Slab:wght@400;700&display=swap" rel="stylesheet">

</head>
<main>
<article>
<header>
<h2>{{article.title}}</h2>
<div class="footer">
<p class="nickname"> &#128100; {{article.user_id.nickname}} | &#8987; {{article.date}} </p>
<p id="category">
<strong>Category</strong>:
{% if article.subject_id == null %}
Other
{% else %}
{{article.subject_id}}
{% endif %}
</p>
<span class="material-symbols-outlined">
reviews
</span>
<p><strong>
Views: {{ article.num_of_views }}
</strong></p>
</div>
<hr>
<p>{{article.content}}</p>
</header>
<footer>
<hr>
<form method="POST">
<div class="footer">
{% csrf_token %}

{% if liked == False %}
<button class="Green" type="submit" >
Like
</button>
<input name='like_method' value='Add' hidden>
{% else %}
<button class="Red" type="submit" >
Unlike
</button>
<input name='like_method' value='Remove' hidden>
{% endif %}
<p><strong>
Likes: {{ article.num_of_likes }}
</strong></p>
</div>
</form>
</footer>
</article>
</main>
{% endblock %}
12 changes: 12 additions & 0 deletions projboard/tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -103,3 +103,15 @@ def articles_num():
def user_articles(user):
user_articles = Article.search_by_user(user)
return user_articles


@pytest.fixture
@pytest.mark.django_db
def world_cup_article():
return Article.search_by_title('world cup')[0]


@pytest.fixture
@pytest.mark.django_db
def math_article():
return Article.search_by_title('1+1')[0]
147 changes: 131 additions & 16 deletions projboard/tests/test_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,16 +38,36 @@ def test_homepage(client, articles_num):
assert 'landing/homepage.html' in template_names


def test_get_searchpage(client):
response = client.get("/search/")
@pytest.fixture
@pytest.mark.django_db
def User2():
return User.get_user_by_nickname("User2")


@pytest.mark.django_db
def test_get_searchpage(client, User2):
response = client.get(f"/search/{User2.nickname}/")
assert response.status_code == 200
assert response.context['user'] == User2
assert [] == response.context[ARTICLES]
assert '' == response.context[SEARCHINPUT]
assert 'title' == response.context[SEARCHMETHOD]
assert 0 == response.context[COUNT]
assert '' == response.context[MESSAGE]


@pytest.mark.django_db
def test_get_empty_searchpage(client):
response = client.get("/search/")
assert response.status_code == 404


@pytest.mark.django_db
def test_get_invalid_nickname_searchpage(client):
response = client.get("/search/fakeUser2/")
assert response.status_code == 404


@pytest.fixture
@pytest.mark.django_db
def articles_by_title():
Expand Down Expand Up @@ -79,8 +99,8 @@ def articles_by_user():


@pytest.mark.django_db
def test_valid_title_searchpage_results(client, articles_by_title):
response = client.post('/search/', {'searchInput': VALIDTITLE, 'searchOptions': 'title'})
def test_valid_title_searchpage_results(client, articles_by_title, User2):
response = client.post(f'/search/{User2.nickname}/', {'searchInput': VALIDTITLE, 'searchOptions': 'title'})
assert response.status_code == 200
assert response.context[SEARCHINPUT] == VALIDTITLE
for i in response.context[ARTICLES]:
Expand All @@ -90,8 +110,8 @@ def test_valid_title_searchpage_results(client, articles_by_title):


@pytest.mark.django_db
def test_invalid_title_searchpage_results(client, invalid_articles_by_title):
response = client.post('/search/', {'searchInput': INVALIDINPUT, 'searchOptions': 'title'})
def test_invalid_title_searchpage_results(client, invalid_articles_by_title, User2):
response = client.post(f'/search/{User2.nickname}/', {'searchInput': INVALIDINPUT, 'searchOptions': 'title'})
assert response.status_code == 200
assert response.context[SEARCHINPUT] == INVALIDINPUT
for i in response.context[ARTICLES]:
Expand All @@ -101,8 +121,8 @@ def test_invalid_title_searchpage_results(client, invalid_articles_by_title):


@pytest.mark.django_db
def test_valid_subject_searchpage_results(client, articles_by_subject):
response = client.post('/search/', {'searchInput': VALIDSUBJECT, 'searchOptions': 'subject'})
def test_valid_subject_searchpage_results(client, articles_by_subject, User2):
response = client.post(f'/search/{User2.nickname}/', {'searchInput': VALIDSUBJECT, 'searchOptions': 'subject'})
assert response.status_code == 200
assert response.context[SEARCHINPUT] == VALIDSUBJECT
for i in response.context[ARTICLES]:
Expand All @@ -112,17 +132,17 @@ def test_valid_subject_searchpage_results(client, articles_by_subject):


@pytest.mark.django_db
def test_invalid_subject_searchpage_result(client):
response = client.post('/search/', {'searchInput': INVALIDSUBJECT, 'searchOptions': 'subject'})
def test_invalid_subject_searchpage_result(client, User2):
response = client.post(f'/search/{User2.nickname}/', {'searchInput': INVALIDSUBJECT, 'searchOptions': 'subject'})
assert response.status_code == 200
assert response.context[SEARCHINPUT] == INVALIDSUBJECT
assert response.context[COUNT] == 0
assert response.context[MESSAGE] == WRONG_SUBJECT_MESSAGE


@pytest.mark.django_db
def test_valid_user_searchpage_results(client, articles_by_user):
response = client.post('/search/', {'searchInput': VALIDUSER, 'searchOptions': 'user'})
def test_valid_user_searchpage_results(client, articles_by_user, User2):
response = client.post(f'/search/{User2.nickname}/', {'searchInput': VALIDUSER, 'searchOptions': 'user'})
assert response.status_code == 200
assert response.context[SEARCHINPUT] == VALIDUSER
for i in response.context[ARTICLES]:
Expand All @@ -132,17 +152,17 @@ def test_valid_user_searchpage_results(client, articles_by_user):


@pytest.mark.django_db
def test_invalid_user_searchpage_result(client):
response = client.post('/search/', {'searchInput': INVALIDUSER, 'searchOptions': 'user'})
def test_invalid_user_searchpage_result(client, User2):
response = client.post(f'/search/{User2.nickname}/', {'searchInput': INVALIDUSER, 'searchOptions': 'user'})
assert response.status_code == 200
assert response.context[SEARCHINPUT] == INVALIDUSER
assert response.context[COUNT] == 0
assert response.context[MESSAGE] == WRONG_USER_MESSAGE


@pytest.mark.django_db
def test_empty_searchpage_results(client):
response = client.post('/search/', {'searchInput': '', 'searchOptions': 'title'})
def test_empty_searchpage_results(client, User2):
response = client.post(f'/search/{User2.nickname}/', {'searchInput': '', 'searchOptions': 'title'})
assert response.context[MESSAGE] == EMPTY_TITLE_MESSAGE


Expand Down Expand Up @@ -238,3 +258,98 @@ def test_signup_page(client):
assert response.status_code == 200
template_names = set(tmpl.origin.template_name for tmpl in response.templates)
assert 'signup/signup.html' in template_names


@pytest.mark.django_db
def test_read_view_new_article(client, world_cup_article, User2):
"""
Testing the number of views in a new article (not viewed yet)
=> num of views should increase by 1
"""
# recieving world cup article that User 2 didn't view yet, plus getting num views of it
num_views1 = world_cup_article.num_of_views

# preparing the page route
route = '/article/{0}/{1}/'.format(User2.nickname, world_cup_article.id)

# Send a GET request to the page
response = client.get(route)

assert response.status_code == 200
assert response.context['user'] == User2
# Create a set of template names from the templates used in the response
template_names = set(tmpl.origin.template_name for tmpl in response.templates)
# And check if that show/read_article.html is in the set.
assert 'show/read_article.html' in template_names
# checking the result of the view return
assert response.context['article'] == world_cup_article
# getting num of views after viewing the article
num_views2 = response.context['article'].num_of_views
# checking that num views has been increased
assert num_views2 == num_views1 + 1


@pytest.mark.django_db
def test_like_article(client, world_cup_article, User2):
# recieving world cup article that User 2 didn't like yet, plus getting num likes of it
num_likes1 = world_cup_article.num_of_likes

# preparing the page route
route = '/article/{0}/{1}/'.format(User2.nickname, world_cup_article.id)
# Send a POST request to the page
response = client.post(route, {'like_method': 'Add'})

assert response.status_code == 200
assert response.context['article'] == world_cup_article
# getting num of likes after liking the article
num_likes2 = response.context['article'].num_of_likes
# checking that num likes has been increased
assert num_likes2 == num_likes1 + 1


@pytest.mark.django_db
def test_unlike_article(client, math_article, User2):
# recieving world cup article that User 2 didn't like yet, plus getting num likes of it
num_likes1 = math_article.num_of_likes

# preparing the page route
route = '/article/{0}/{1}/'.format(User2.nickname, math_article.id)
# Send a POST request to the page
response = client.post(route, {'like_method': 'Remove'})

assert response.status_code == 200
assert response.context['article'] == math_article
# getting num of likes after liking the article
num_likes2 = response.context['article'].num_of_likes
# checking that num likes has been dicreased
assert num_likes2 == num_likes1 - 1


@pytest.mark.django_db
def test_read_already_viewed_article(client, math_article, User2):
"""
Testing the number of views in an already viewed article (got viewed in the past)
=> num of views should't increase
"""
# recieving world cup article that User 2 didn't view yet, plus getting num views of it
num_views1 = math_article.num_of_views

# preparing the page route
route = '/article/{0}/{1}/'.format(User2.nickname, math_article.id)

# Send a GET request to the page
response = client.get(route)

assert response.status_code == 200
assert response.context['user'] == User2
# Create a set of template names from the templates used in the response
template_names = set(tmpl.origin.template_name for tmpl in response.templates)
# And check if that show/read_article.html is in the set.
assert 'show/read_article.html' in template_names

# checking the result of the view return
assert response.context['article'] == math_article
# getting num of views after viewing the article
num_views2 = response.context['article'].num_of_views
# checking that num views didn't increased
assert num_views2 == num_views1
Loading

0 comments on commit fbbe167

Please sign in to comment.