Skip to content

Commit

Permalink
Resolved Conflicts
Browse files Browse the repository at this point in the history
  • Loading branch information
Varsha010101 committed Jun 1, 2024
2 parents d942ce1 + 098f788 commit d5e2455
Show file tree
Hide file tree
Showing 12 changed files with 290 additions and 71 deletions.
2 changes: 2 additions & 0 deletions desktop.ini
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
[.ShellClassInfo]
LocalizedResourceName=@NEWS-AGGREGATOR-PROJECT,0
1 change: 1 addition & 0 deletions newsaggregator/NEWS-AGGREGATOR-PROJECT
Submodule NEWS-AGGREGATOR-PROJECT added at d942ce
30 changes: 30 additions & 0 deletions newsaggregator/core/models.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
from django.db import models
from django.conf import settings
from django.db.models.signals import post_delete

from django.dispatch import receiver

from django.core.validators import EmailValidator

class Contact(models.Model):
Expand All @@ -13,10 +17,14 @@ def __str__(self):
return self.name + " - " + self.email




class Headline(models.Model):
title = models.CharField(max_length=200)#title char(200)
image = models.URLField(null=True, blank=True)#image
url = models.TextField()
average_rating = models.FloatField(default=0, null=True, blank=True)
rating_count = models.IntegerField(default=0)
def __str__(self):
return self.title

Expand All @@ -26,3 +34,25 @@ class Bookmark(models.Model):

def __str__(self):
return f"{self.user} - {self.headline.title}"


# stores all the rating given by all the users
class Rating(models.Model):
user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
headline = models.ForeignKey(Headline, on_delete=models.CASCADE)
rating = models.IntegerField(choices=[(i, str(i)) for i in range(1, 6)], null=True, blank=True)

def __str__(self):
return f"{self.user} rated {self.headline.title} as {self.rating}"



# trigger if any rating is deleted(for eg, if any user gets deleted with respective ratings)
@receiver(post_delete, sender=Rating)
def recalculate_average_rating(sender, instance, **kwargs):
# Calculate the new average rating for the deleted rating's headline
ratings = Rating.objects.filter(headline=instance.headline)
headline = instance.headline
headline.rating_count = ratings.count()
headline.average_rating = sum(r.rating for r in ratings) / headline.rating_count if headline.rating_count > 0 else 0
headline.save()
10 changes: 7 additions & 3 deletions newsaggregator/core/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,13 @@
path('privacy/',views.privacy,name='privacy'),
path('scrape/<str:name>', views.scrape, name="scrape"),


# bookmarking
path('bookmark/<int:headline_id>/', views.bookmark_article, name='bookmark_article'),
# bookmarking
path('bookmarks/', views.view_bookmarks, name='view_bookmarks'),

path('remove_bookmark/<int:headline_id>/', views.remove_bookmark, name='remove_bookmark'),
path('rate_headline/<int:headline_id>/', views.rate_headline, name='rate_headline'),

path('top-rated/', views.top_rated_articles, name='top_rated_articles'),


]
99 changes: 87 additions & 12 deletions newsaggregator/core/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@

from django.contrib.auth.decorators import login_required
from django.shortcuts import render, redirect, get_object_or_404
from core.models import Headline, Bookmark
from core.models import Headline, Bookmark, Rating
from django.contrib import messages
from django.views.decorators.csrf import csrf_exempt

Expand Down Expand Up @@ -167,17 +167,32 @@ def privacy(request):
return render(request, "core/privacy.html", context)


@login_required
def view_bookmarks(request):
# Get the list of bookmarked headline IDs for the current user
user_bookmarked_headline_ids = request.user.bookmark_set.values_list('headline_id', flat=True)
bookmarks = Bookmark.objects.filter(user=request.user).select_related('headline')
context = {
'bookmarks': bookmarks,
'user_bookmarked_headline_ids': user_bookmarked_headline_ids,
}
return render(request, 'core/bookmarks.html', context)
# @login_required(login_url='userauths:sign-in')
# def view_bookmarks(request):
# # Get the list of bookmarked headlines for the current user
# bookmarks = Bookmark.objects.filter(user=request.user).select_related('headline')

# if bookmarks.exists():
# context = {'bookmarks': bookmarks}
# else:
# context = {'message': 'You have no bookmarks yet.'}


# return render(request, 'core/bookmarks.html', context)
def view_bookmarks(request):
if request.user.is_authenticated:
# Get the list of bookmarked headlines for the current user
bookmarks = Bookmark.objects.filter(user=request.user).select_related('headline')

if bookmarks.exists():
context = {'bookmarks': bookmarks}
else:
context = {'message': 'You have no bookmarks yet.'}

return render(request, 'core/bookmarks.html', context)
else:
message = 'Sign in to view bookmarks.'
return render(request, 'core/index.html', {'message': message})
@csrf_exempt
@login_required(login_url='userauths:sign-in')
def bookmark_article(request, headline_id):
Expand All @@ -193,4 +208,64 @@ def remove_bookmark(request, headline_id):
if request.method == 'POST':
Bookmark.objects.filter(user=request.user, headline_id=headline_id).delete()
return JsonResponse({'status': 'success'})
return JsonResponse({'status': 'error', 'message': 'Invalid request'}, status=400)
return JsonResponse({'status': 'error', 'message': 'Invalid request'}, status=400)
import json
@login_required
@csrf_exempt
def rate_headline(request, headline_id):
if request.method == 'POST':
headline = get_object_or_404(Headline, id=headline_id)

try:
data = json.loads(request.body)
print("Received data:", data) # Print the entire JSON payload for debugging
rating_value_str = data.get('rating')
# print("rating_value_str:", rating_value_str) # Add this line for debugging
except json.JSONDecodeError:
return JsonResponse({'status': 'fail', 'message': 'Invalid JSON'}, status=400)

if rating_value_str is not None:
try:
rating_value = int(rating_value_str)
except ValueError:
return JsonResponse({'status': 'fail', 'message': 'Invalid rating value'}, status=400)
else:
return JsonResponse({'status': 'fail', 'message': 'Rating value is missing'}, status=400)

# Check if the user has already rated this headline
rating, created = Rating.objects.get_or_create(user=request.user, headline=headline)
rating.rating = rating_value
rating.save()

# Update headline average rating and rating count
ratings = Rating.objects.filter(headline=headline).exclude(rating__isnull=True)
headline.rating_count = ratings.count()
headline.average_rating = sum(r.rating for r in ratings) / headline.rating_count if headline.rating_count > 0 else 0
headline.save()

return JsonResponse({'status': 'success', 'average_rating': headline.average_rating, 'rating_count': headline.rating_count})
return JsonResponse({'status': 'fail'}, status=400)
from django.shortcuts import render
from .models import Headline

def top_rated_articles(request):
if request.user.is_authenticated:
top_rated_articles = Headline.objects.filter(average_rating__gte=3.5).order_by('-average_rating')
else:
top_rated_articles = Headline.objects.none()

paginator = Paginator(top_rated_articles, 9) # 9 items per page

page = request.GET.get('page')
try:
top_rated_articles_obj = paginator.page(page)
except PageNotAnInteger:
top_rated_articles_obj = paginator.page(1)
except EmptyPage:
top_rated_articles_obj = paginator.page(paginator.num_pages)

context = {
'object_list': top_rated_articles_obj,
'paginator': paginator
}
return render(request, 'core/index.html', context)
2 changes: 1 addition & 1 deletion newsaggregator/newsaggregator/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -146,4 +146,4 @@

DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'

AUTH_USER_MODEL='userauths.User'
AUTH_USER_MODEL='userauths.User'
72 changes: 71 additions & 1 deletion newsaggregator/static/assets/css/index.css
Original file line number Diff line number Diff line change
@@ -1,3 +1,73 @@
.dropdown-item:hover{
background-color: #edf2f7;
}
}



.d-flex {
display: flex;
justify-content: space-between;
align-items: center;
width: 100%;
}

.rating-container {
display: flex;
align-items: center;
gap: 10px; /* Adjust the gap as needed */
width: 100%; /* Make the rating container full width */
}

.rate {
display: flex;
align-items: center;
gap: 5px; /* Adjust the gap as needed */
flex-direction: row-reverse; /* Reverse the order of the stars */
}

.rate input[type="radio"] {
display: none; /* Hide the radio buttons */
}

.rate label {
cursor: pointer;
display: inline-block;
}

.rate label:before {
content: '☆';
font-size: 1.5em; /* Adjust the size as needed */
margin-right: 2px;
}

/* Ensure all previous stars are filled when hovering or checked */
.rate input[type="radio"]:checked ~ label:before,
.rate input[type="radio"]:checked + label:before,
.rate input[type="radio"]:checked + label ~ label:before {
content: '★';
color: gold; /* Adjust the color as needed */
}

.rate label:hover ~ label:before,
.rate label:hover:before {
content: '★';
color: gold;
}

.submit-btn {
padding: 3px 6px; /* Make the button smaller */
background-color: #007bff;
color: white;
border: none;
border-radius: 4px;
cursor: pointer;
margin-left: auto; /* Push the button to the rightmost end */
}

.submit-btn:hover {
background-color: #0056b3;
}

.average-rating {
margin-left: 10px; /* Adjust the margin as needed */
}
3 changes: 2 additions & 1 deletion newsaggregator/static/assets/css/style.css
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
--foreground-tertiary: hsl(214, 20%, 69%);

--accent: hsl(229, 76%, 66%);


}

Expand Down Expand Up @@ -1114,4 +1115,4 @@ footer .wrapper { text-align: center; }
.light-theme .bio-content p,
.light-theme .ck-content p{
color: var(--foreground-secondary);
}
}
34 changes: 34 additions & 0 deletions newsaggregator/static/assets/js/script.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,37 @@ navMenuBtn.addEventListener('click', navToggleFunc);
navCloseBtn.addEventListener('click', navToggleFunc);


// for star rating
let selectedRating = {};

function setRating(headlineId, rating) {
selectedRating[headlineId] = rating;
}

function submitRating(headlineId) {

const rating = selectedRating[headlineId];
if (typeof rating !== 'undefined') {
console.log(typeof(rating));
fetch(`/rate_headline/${headlineId}/`, {
method: 'POST',
headers: {
'X-CSRFToken': '{{ csrf_token }}',
'Content-Type': 'application/json'
},
body: JSON.stringify({ rating: rating })
})
.then(response => response.json())
.then(data => {
if (data.status === 'success') {
const averageRatingElement = document.querySelector(`#average-rating-${headlineId}`);
averageRatingElement.innerHTML = `(${data.average_rating}:${data.rating_count} ratings)`;
} else {
console.error('Error:', data);
}
})
.catch(error => console.error('Error:', error));
} else {
alert('Please select a rating before submitting.');
}
}
32 changes: 17 additions & 15 deletions newsaggregator/templates/components/category-btn.html
Original file line number Diff line number Diff line change
@@ -1,15 +1,17 @@
<div style="display: flex; align-items: center; justify-content: flex-end;">
<div class="dropdown">
<button class="btn btn-secondary dropdown-toggle" type="button" id="dropdownMenuButton" data-bs-toggle="dropdown" aria-expanded="false">
Category
</button>
<ul class="dropdown-menu" aria-labelledby="dropdownMenuButton">
<li><a class="dropdown-item" href="{% url 'core:scrape' name='latest' %}">Latest</a></li>
<li><a class="dropdown-item" href="{% url 'core:scrape' name='entertainment' %}">Entertainment</a></li>
<li><a class="dropdown-item" href="{% url 'core:scrape' name='sports' %}">Sports</a></li>
<li><a class="dropdown-item" href="{% url 'core:scrape' name='politics' %}">Politics</a></li>
<li><a class="dropdown-item" href="{% url 'core:scrape' name='opinion' %}">Opinion</a></li>
<li><a class="dropdown-item" href="{% url 'core:scrape' name='breaking-news' %}">Breaking News</a></li>
</ul>
</div>
</div>
<div style="display: flex; align-items: center; justify-content: flex-end;">
<div class="dropdown">
<button class="btn btn-secondary dropdown-toggle" type="button" id="dropdownMenuButton" data-bs-toggle="dropdown" aria-expanded="false">
Category
</button>
<ul class="dropdown-menu" aria-labelledby="dropdownMenuButton">
<li><a class="dropdown-item" href="{% url 'core:scrape' name='latest' %}">Latest</a></li>
<li><a class="dropdown-item" href="{% url 'core:scrape' name='entertainment' %}">Entertainment</a></li>
<li><a class="dropdown-item" href="{% url 'core:scrape' name='sports' %}">Sports</a></li>
<li><a class="dropdown-item" href="{% url 'core:scrape' name='politics' %}">Politics</a></li>
<li><a class="dropdown-item" href="{% url 'core:scrape' name='opinion' %}">Opinion</a></li>
<li><a class="dropdown-item" href="{% url 'core:scrape' name='breaking-news' %}">Breaking News</a></li>
<li><a class="dropdown-item" href="{% url 'core:top_rated_articles' %}">Top Rated</a></li>

</ul>
</div>
</div>
Loading

0 comments on commit d5e2455

Please sign in to comment.