- {%for msg in messages%} -
diff --git a/newsaggregator/core/__pycache__/forms.cpython-312.pyc b/newsaggregator/core/__pycache__/forms.cpython-312.pyc new file mode 100644 index 0000000..291412b Binary files /dev/null and b/newsaggregator/core/__pycache__/forms.cpython-312.pyc differ diff --git a/newsaggregator/core/__pycache__/urls.cpython-312.pyc b/newsaggregator/core/__pycache__/urls.cpython-312.pyc index c433b9f..8999bbd 100644 Binary files a/newsaggregator/core/__pycache__/urls.cpython-312.pyc and b/newsaggregator/core/__pycache__/urls.cpython-312.pyc differ diff --git a/newsaggregator/core/__pycache__/views.cpython-312.pyc b/newsaggregator/core/__pycache__/views.cpython-312.pyc index 7fe64d1..9c12d80 100644 Binary files a/newsaggregator/core/__pycache__/views.cpython-312.pyc and b/newsaggregator/core/__pycache__/views.cpython-312.pyc differ diff --git a/newsaggregator/core/forms.py b/newsaggregator/core/forms.py new file mode 100644 index 0000000..df709f6 --- /dev/null +++ b/newsaggregator/core/forms.py @@ -0,0 +1,8 @@ +from django import forms + + +class ContactForm(forms.Form): + name = forms.CharField(max_length=255, widget=forms.TextInput(attrs={'placeholder': 'Your Name'})) + email = forms.EmailField(widget=forms.EmailInput(attrs={'placeholder': 'Your Email'})) + phone = forms.IntegerField(widget=forms.NumberInput(attrs={'placeholder': 'Your Phone Number'})) + content = forms.CharField(widget=forms.Textarea(attrs={'placeholder': 'Your Message'})) \ No newline at end of file diff --git a/newsaggregator/core/urls.py b/newsaggregator/core/urls.py index d6dd3d2..24fc00b 100644 --- a/newsaggregator/core/urls.py +++ b/newsaggregator/core/urls.py @@ -1,6 +1,5 @@ from django.urls import path from core import views -from .views import submit_contact # from .views import base_view from .views import news_list @@ -12,7 +11,7 @@ # path('base/', base_view, name='base'), path('',views.news_list,name='index'), path('about/', views.about, name='about'), - path('contact.html/',views.submit_contact,name='contact'), + path('contact/',views.contact,name='contact'), path('advertise/',views.advertise,name='advertise'), path('privacy/',views.privacy,name='privacy'), diff --git a/newsaggregator/core/views.py b/newsaggregator/core/views.py index e021ac0..0e38f88 100644 --- a/newsaggregator/core/views.py +++ b/newsaggregator/core/views.py @@ -1,90 +1,95 @@ -# your_app/views.py - -from django.shortcuts import render, redirect, get_object_or_404 -from django.http import JsonResponse -from django.core.paginator import Paginator, PageNotAnInteger, EmptyPage -from .models import Headline, Bookmark, Rating, Contact from django.contrib import messages -from .decorators import custom_login_required # Import the custom decorator +from django.contrib.auth.decorators import login_required +from django.http import HttpResponse, JsonResponse +from django.shortcuts import render + +from django.shortcuts import render import requests +from django.shortcuts import render, redirect from bs4 import BeautifulSoup as BSoup +from core.models import Headline + +from datetime import datetime +from core.forms import ContactForm +from django.template.loader import render_to_string +from django.core.mail import send_mail + + +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 django.contrib import messages from django.views.decorators.csrf import csrf_exempt -import json -# def base_view(request): -# return render(request, 'core/base.html') -@custom_login_required +from django.core.paginator import Paginator,PageNotAnInteger,EmptyPage +#view for scraping new + def scrape(request, name): - Headline.objects.all().delete() + Headline.objects.all().delete() #remove all existing records from table session = requests.Session() + #useragent helps server to identify origin of request + #we are imitating request as google bot session.headers = {"User-Agent": "Googlebot/2.1 (+http://www.google.com/bot.html)"} + #google bot is crawler program + #session.headers = {"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36"} url = f"https://www.theonion.com/{name}" content = session.get(url).content + #print(content)#raw content soup = BSoup(content, "html.parser") + #print(soup) + # finding all new div using common class News = soup.find_all("div", {"class": "sc-cw4lnv-13 hHSpAQ"}) + print(News) for article in News: + #extracting news link,img url,title for each news main = article.find_all("a", href=True) linkx = article.find("a", {"class": "sc-1out364-0 dPMosf js_link"}) link = linkx["href"] titlex = article.find("h2", {"class": "sc-759qgu-0 cvZkKd sc-cw4lnv-6 TLSoz"}) title = titlex.text imgx = article.find("img")["data-src"] + #storing extracted data to model new_headline = Headline() new_headline.title = title new_headline.url = link new_headline.image = imgx new_headline.save() + #saving details to table return redirect("../") -# @custom_login_required -# def news_list(request): -# headlines = Headline.objects.all().order_by('-id') -# swiper = Headline.objects.all()[:4] -# user_bookmarked_headline_ids = [] -# if request.user.is_authenticated: -# user_bookmarked_headline_ids = request.user.bookmark_set.values_list('headline_id', flat=True) -# page = request.GET.get('page', 1) -# num_of_items = 9 -# paginator = Paginator(headlines, num_of_items) -# try: -# headlines_obj = paginator.page(page) -# except PageNotAnInteger: -# headlines_obj = paginator.page(1) -# except EmptyPage: -# headlines_obj = paginator.page(paginator.num_pages) -# context = { -# "object_list": headlines_obj, -# "paginator": paginator, -# 'swiper': swiper, -# 'user_bookmarked_headline_ids': user_bookmarked_headline_ids, -# } -# return render(request, "core/index.html", context) -from django.shortcuts import render -from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger -from .models import Headline - +@login_required(login_url='userauths:sign-in') def news_list(request): + # Fetch all headlines in reverse order headlines = Headline.objects.all().order_by('-id') swiper = Headline.objects.all()[:4] + + # Get the list of bookmarked headline IDs for the current user + user_bookmarked_headline_ids = [] + if request.user.is_authenticated: + user_bookmarked_headline_ids = request.user.bookmark_set.values_list('headline_id', flat=True) + + # Pagination logic page = request.GET.get('page', 1) num_of_items = 9 paginator = Paginator(headlines, num_of_items) + try: headlines_obj = paginator.page(page) except PageNotAnInteger: headlines_obj = paginator.page(1) except EmptyPage: headlines_obj = paginator.page(paginator.num_pages) + context = { "object_list": headlines_obj, "paginator": paginator, 'swiper': swiper, + 'user_bookmarked_headline_ids': user_bookmarked_headline_ids, } return render(request, "core/index.html", context) - -@custom_login_required +@login_required(login_url='userauths:sign-in') def index(request): Headline.objects.all().delete() session = requests.Session() @@ -92,71 +97,101 @@ def index(request): url = f"https://www.theonion.com/latest" content = session.get(url).content soup = BSoup(content, "html.parser") + News = soup.find_all("div", {"class": "sc-cw4lnv-13 hHSpAQ"}) - count = 0 + count=0 for article in News: - count += 1 - if count <= 8: + count=count+1 + + if count<=8: main = article.find_all("a", href=True) + linkx = article.find("a", {"class": "sc-1out364-0 dPMosf js_link"}) link = linkx["href"] + titlex = article.find("h2", {"class": "sc-759qgu-0 cvZkKd sc-cw4lnv-6 TLSoz"}) title = titlex.text + imgx = article.find("img")["data-src"] + new_headline = Headline() new_headline.title = title new_headline.url = link new_headline.image = imgx - new_headline.save() + new_headline.save() ##saving each record to news_headline + headlines = Headline.objects.all()[::-1] context = { "object_list": headlines, } return render(request, "core/index.html", context) -# @custom_login_required + def about(request): - context = {} + context={ + + } return render(request, "core/about.html", context) -# @custom_login_required -def submit_contact(request): - if request.method == 'POST': - name = request.POST.get('name') - email = request.POST.get('email') - phone = request.POST.get('phone') - message = request.POST.get('message') - contact = Contact() - contact.name = name - contact.email = email - contact.phone = phone - contact.message = message - contact.save() - messages.success(request, "Thanks for contacting us") - return redirect("/contact.html") - return render(request, "core/contact.html") -# @custom_login_required +def contact(request): + today_date = datetime.now().strftime('%Y-%m-%d') + if request.method == "POST": + form = ContactForm(request.POST) + + if form.is_valid(): + name = form.cleaned_data['name'] + email = form.cleaned_data['email'] + phone = form.cleaned_data['phone'] + content = form.cleaned_data['content'] + + html = render_to_string('components/email.html', { + 'name': name, + 'email': email, + 'phone': phone, + 'content': content, + }) + + send_mail("The contact form subject", 'this is the message', email, ['email@gmail.com'], html_message=html) + messages.success(request, 'Form submitted successfully!') + return redirect("core:index") + else: + form = ContactForm() + + context={ + 'today_date': today_date, + 'form': form, + } + return render(request,"core/contact.html",context) + +@login_required(login_url='userauths:sign-in') def advertise(request): - context = {} + context={ + + } return render(request, "core/advertise.html", context) -# @custom_login_required +@login_required(login_url='userauths:sign-in') def privacy(request): - context = {} + context={ + + } return render(request, "core/privacy.html", context) -# @custom_login_required + +@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') - if bookmarks.exists(): - context = {'bookmarks': bookmarks} - else: - context = {'message': 'You have no bookmarks yet.'} + context = { + 'bookmarks': bookmarks, + 'user_bookmarked_headline_ids': user_bookmarked_headline_ids, + } return render(request, 'core/bookmarks.html', context) @csrf_exempt -# @custom_login_required +@login_required(login_url='userauths:sign-in') def bookmark_article(request, headline_id): if request.method == 'POST': headline = get_object_or_404(Headline, id=headline_id) @@ -165,15 +200,14 @@ def bookmark_article(request, headline_id): return JsonResponse({'status': 'error', 'message': 'Invalid request'}, status=400) @csrf_exempt -# @custom_login_required +@login_required(login_url='userauths:sign-in') 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) -import json -# @custom_login_required + @csrf_exempt def rate_headline(request, headline_id): if request.method == 'POST': @@ -205,3 +239,5 @@ def top_rated_articles(request): top_rated_articles = Headline.objects.filter(average_rating__gte=3.5).order_by('-average_rating') paginator = Paginator(top_rated_articles, 9) page = request + + diff --git a/newsaggregator/static/assets/css/style.css b/newsaggregator/static/assets/css/style.css index 63cac60..5dbb5ac 100644 --- a/newsaggregator/static/assets/css/style.css +++ b/newsaggregator/static/assets/css/style.css @@ -29,7 +29,6 @@ --foreground-tertiary: hsl(214, 20%, 69%); --accent: hsl(229, 76%, 66%); - } @@ -236,28 +235,7 @@ header { header .flex-wrapper { display: none; } -/* The navigation bar */ -.navbar { - overflow: hidden; - background-color: #333; - position: fixed; /* Set the navbar to fixed position */ - top: 0; /* Position the navbar at the top of the page */ - width: 100%; /* Full width */ - z-index:1000; -} - -/* Links inside the navbar */ -.navbar a { - float: left; - display: block; - color: #f2f2f2; - text-align: center; - /* padding: 14px 16px; */ - text-decoration: none; -} - - -/* .navbar-section { +.navbar-section { padding-left: 3rem; padding-right: 3rem; border-bottom: 1px solid var(--action-primary); @@ -270,12 +248,12 @@ header .flex-wrapper { display: none; } align-items: center; gap: 15px; padding: 15px 0; -} */ +} .dropdown { - padding-top: 7rem; + padding-top: 2rem; padding-right: 1rem; - padding-bottom: 1rem; + padding-bottom: 1rem;; } .logo-container { @@ -370,9 +348,6 @@ header .btn-group { } - - - /*-----------------------------------*\ #HERO SECTION \*-----------------------------------*/ @@ -538,7 +513,7 @@ footer { } footer .footer-section { - padding-top: 10px; + padding-top: 1rem; display: flex; justify-content: space-evenly; grid-template-columns: 1fr; @@ -580,7 +555,6 @@ footer .wrapper { text-align: center; } font-size: var(--fs-4); text-align: center; padding-bottom: 1rem; - background-color: blue; /* border-top: 1px solid var(--action-primary); */ } @@ -594,7 +568,6 @@ footer .wrapper { text-align: center; } - /*-----------------------------------*\ #MEDIA QUERIES \*-----------------------------------*/ @@ -1102,42 +1075,39 @@ footer .wrapper { text-align: center; } - /** + /** * FOOTER */ - .footer-title { font-size: 1.125rem; } + .footer-title { font-size: 1.125rem; } - .footer-link { margin-bottom: 0.3rem; } - -} -/* custom css */ -.dark-theme .bio-content h2, -.dark-theme .ck-content h1, -.dark-theme .ck-content h2, -.dark-theme .ck-content h3, -.dark-theme .ck-content h4, -.dark-theme .ck-content h5, -.dark-theme .ck-content h6{ - color: var(--foreground-secondary); -} -.dark-theme .bio-content p, -.dark-theme .ck-content p{ - color: var(--foreground-tertiary); -} -.light-theme .bio-content h2, -.light-theme .ck-content h1, -.light-theme .ck-content h2, -.light-theme .ck-content h3, -.light-theme .ck-content h4, -.light-theme .ck-content h5, -.light-theme .ck-content h6{ - color: var(--foreground-secondary); -} -.light-theme .bio-content p, -.light-theme .ck-content p{ - color: var(--foreground-secondary); -} -.hr-container{ - background-color: blue; -} + .footer-link { margin-bottom: 0.3rem; } + + } + /* custom css */ + .dark-theme .bio-content h2, + .dark-theme .ck-content h1, + .dark-theme .ck-content h2, + .dark-theme .ck-content h3, + .dark-theme .ck-content h4, + .dark-theme .ck-content h5, + .dark-theme .ck-content h6{ + color: var(--foreground-secondary); + } + .dark-theme .bio-content p, + .dark-theme .ck-content p{ + color: var(--foreground-tertiary); + } + .light-theme .bio-content h2, + .light-theme .ck-content h1, + .light-theme .ck-content h2, + .light-theme .ck-content h3, + .light-theme .ck-content h4, + .light-theme .ck-content h5, + .light-theme .ck-content h6{ + color: var(--foreground-secondary); + } + .light-theme .bio-content p, + .light-theme .ck-content p{ + color: var(--foreground-secondary); + } \ No newline at end of file diff --git a/newsaggregator/static/assets/js/preloader.js b/newsaggregator/static/assets/js/preloader.js index 839c57f..c2a6093 100644 --- a/newsaggregator/static/assets/js/preloader.js +++ b/newsaggregator/static/assets/js/preloader.js @@ -2,9 +2,8 @@ window.addEventListener('load', function() { const preloader = document.getElementById('preloader'); const mainContent = document.querySelector('.outer-align'); - // Add a delay before hiding the preloader setTimeout(() => { preloader.style.display = 'none'; mainContent.style.display = 'flex'; - }, 100); // Adjust the delay time (in milliseconds) as needed + }, 100); }); diff --git a/newsaggregator/templates/components/footer.html b/newsaggregator/templates/components/footer.html index 7e5f083..9b79382 100644 --- a/newsaggregator/templates/components/footer.html +++ b/newsaggregator/templates/components/footer.html @@ -15,6 +15,7 @@ © 2024 Onion News Aggregator. All rights reserved.
+© Copyright 2024 Onion News
-© Copyright 2024 Onion News
\ No newline at end of file diff --git a/newsaggregator/templates/core/about.html b/newsaggregator/templates/core/about.html index cb5bedd..d11fae6 100644 --- a/newsaggregator/templates/core/about.html +++ b/newsaggregator/templates/core/about.html @@ -1,4 +1,4 @@ -{% extends 'core/base.html' %} +{% extends 'partials/base.html' %} {% load static %} {% block index %} diff --git a/newsaggregator/templates/core/contact.html b/newsaggregator/templates/core/contact.html index 9fab885..07fe277 100644 --- a/newsaggregator/templates/core/contact.html +++ b/newsaggregator/templates/core/contact.html @@ -1,4 +1,4 @@ -{% extends 'core/base.html' %} +{% extends 'partials/base.html' %} {% load static %} {% block index %} @@ -6,16 +6,10 @@