Skip to content
This repository has been archived by the owner on Dec 26, 2023. It is now read-only.

Fix #8: allow users to favorite articles #24

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 43 additions & 3 deletions articles/views.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
from django.shortcuts import get_object_or_404
from django.http.response import Http404
from django.shortcuts import get_object_or_404, redirect
from django.conf import settings
from django.urls import reverse_lazy
from django.shortcuts import render
from django.http import HttpResponseRedirect
from django.http import HttpResponseRedirect, JsonResponse
from django.contrib.auth.decorators import login_required
from django.contrib.auth.mixins import LoginRequiredMixin
from django.views.generic.edit import CreateView, UpdateView
Expand All @@ -12,7 +14,8 @@


def view(req, slug):
return render(req, "articles/detail.html")
article = get_object_or_404(Article, slug=slug)
return render(req, "articles/detail.html", {"article": article})


class ListArticle(ListView):
Expand Down Expand Up @@ -178,3 +181,40 @@ def form_valid(self, form):
"""
self.object = form.save(self.request.user)
return HttpResponseRedirect(self.get_success_url(), status=303)


def favorite_article(request, slug):
template = "articles/favorite.html"
if request.GET.get("mini", None):
template = "articles/favorite_mini.html"

query = Article.objects.annotate(favorited_by__count=Count("favorited_by"))
article = get_object_or_404(query, slug=slug)

favorited = False
if request.user.is_authenticated:
favorited = request.user.profile.has_favorited(article)

if request.method == "POST" and request.user.is_authenticated:
if favorited:
request.user.profile.unfavorite(article)
else:
request.user.profile.favorite(article)
favorited = not favorited

active_class = "btn-outline-primary"
if favorited:
active_class = "btn-primary"

# refresh counts
article = get_object_or_404(query, slug=slug)

return render(
request,
template,
context={
"article": article,
"active_class": active_class,
"favorited": favorited,
},
)
3 changes: 1 addition & 2 deletions realworld/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -117,12 +117,11 @@

USE_TZ = True


# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/3.1/howto/static-files/

STATIC_URL = "/static/"
STATICFILES_DIRS = []
# STATICFILES_DIRS = ["assets"]

STATIC_ROOT = BASE_DIR / "assets"

Expand Down
5 changes: 5 additions & 0 deletions realworld/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,11 @@
path("", home_views.index, name="index"),
path("article/<slug:slug>/", articles_views.view, name="article_view"),
path("article/", articles_views.ListArticle.as_view(), name="article_list"),
path(
"article/<slug:slug>/favorite/",
articles_views.favorite_article,
name="article_favorite",
),
path(
"editor/<slug:slug>/", articles_views.EditArticle.as_view(), name="article_edit"
),
Expand Down
14 changes: 6 additions & 8 deletions templates/articles/detail.html
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,9 @@ <h1>How to build webapps that scale</h1>
&nbsp; Follow Eric Simons <span class="counter">(10)</span>
</button>
&nbsp;&nbsp;
<button class="btn btn-sm btn-outline-primary">
<i class="ion-heart"></i>
&nbsp; Favorite Post <span class="counter">(29)</span>
</button>
<turbo-frame
id="favorite-{{ article.slug }}"
src="{% url 'article_favorite' slug=article.slug %}">
</div>
</div>
</div>
Expand Down Expand Up @@ -50,10 +49,9 @@ <h2 id="introducing-ionic">Introducing RealWorld.</h2>
&nbsp; Follow Eric Simons <span class="counter">(10)</span>
</button>
&nbsp;
<button class="btn btn-sm btn-outline-primary">
<i class="ion-heart"></i>
&nbsp; Favorite Post <span class="counter">(29)</span>
</button>
<turbo-frame
id="favorite-{{ article.slug }}"
src="{% url 'article_favorite' slug=article.slug %}">
</div>
</div>

Expand Down
34 changes: 34 additions & 0 deletions templates/articles/favorite.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
<turbo-frame id="favorite-{{ article.slug }}">
{% if request.method == 'POST' %}
<script>
document
.querySelectorAll("#favorite-{{article.slug}}")
.forEach((e) => e.attributeChangedCallback("src"));
</script>
Comment on lines +3 to +7
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sneaky... sneaky... 😉


{% else %} {% if request.user.is_authenticated %}
<form
method="POST"
action="{% url 'article_favorite' article.slug %}"
class="list-inline-item"
>
{% csrf_token %}
<button class="btn btn-sm {{ active_class }}">
<i class="ion-heart"></i>
{% if favorited %} &nbsp; Unfavorite Post {% else %} &nbsp; Favorite Post
{% endif %}
<span class="counter">({{ article.favorited_by__count }})</span>
</button>
</form>
{% else %}
<a
href="{% url 'login' %}"
class="btn btn-sm btn-outline-primary"
target="_top"
>
<i class="ion-heart"></i>
&nbsp; Favorite Post
<span class="counter">({{ article.favorited_by__count }})</span>
</a>
{% endif %} {% endif %}
</turbo-frame>
22 changes: 22 additions & 0 deletions templates/articles/favorite_mini.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<turbo-frame id="favorite-{{ article.slug }}">
{% if request.user.is_authenticated %}
<form
method="POST"
action="{% url 'article_favorite' article.slug %}?mini=true"
class="list-inline-item pull-xs-right"
>
{% csrf_token %}
<button class="btn {{ active_class }} btn-sm pull-xs-right">
<i class="ion-heart"></i> {{ article.favorited_by__count }}
</button>
</form>
{% else %}
<a
href="{% url 'login' %}"
class="btn btn-sm btn-outline-primary pull-xs-right"
target="_top"
>
<i class="ion-heart"></i> {{ article.favorited_by__count }}
</a>
{% endif %}
</turbo-frame>
13 changes: 5 additions & 8 deletions templates/articles/list.html
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,11 @@
</a>
<span class="date">{{ article.created_at }}</span>
</div>
<button class="btn btn-outline-primary btn-sm pull-xs-right">
<i class="ion-heart"></i> {{ article.favorited_by__count }}
</button>
<turbo-frame
id="favorite-{{ article.slug }}"
src="{% url 'article_favorite' slug=article.slug %}?mini=true"
>
</turbo-frame>
</div>
<a
href="{% url 'article_view' article.slug %}"
Expand Down Expand Up @@ -81,10 +83,5 @@ <h1>{{ article.title }}</h1>
>
{% endif %}
</span>
<script>
function toTop() {
window.scrollTo(0, 0);
}
</script>
</div>
</turbo-frame>
7 changes: 6 additions & 1 deletion templates/base.html
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,15 @@
<!-- Import the custom Bootstrap 4 theme from our hosted CDN -->
<link rel="stylesheet" href="https://demo.productionready.io/main.css" />
<script
src="https://unpkg.com/@hotwired/[email protected].2/dist/turbo.es2017-umd.js"
src="https://unpkg.com/@hotwired/[email protected].3/dist/turbo.es2017-umd.js"
defer
data-turbo-track="reload"
></script>
<script>
function toTop() {
window.scrollTo(0, 0);
}
</script>
</head>
<body>
<nav class="navbar navbar-light">
Expand Down