From ea8ffb9a7a0ca670c62022d9e1d72f4dbbdb0ea9 Mon Sep 17 00:00:00 2001 From: ankur12-1610 <76884959+ankur12-1610@users.noreply.github.com> Date: Mon, 19 Jul 2021 16:56:51 +0530 Subject: [PATCH 1/6] Auth --- authentication/templates/login.html | 12 +++++++ authentication/templates/register.html | 12 +++++++ authentication/urls.py | 8 +++++ authentication/views.py | 46 +++++++++++++++++++++++--- library/forms.py | 17 ++++++++++ library/urls.py | 2 ++ store/templates/store/base.html | 5 +-- store/views.py | 28 ++++++++++++++-- 8 files changed, 120 insertions(+), 10 deletions(-) create mode 100644 authentication/templates/login.html create mode 100644 authentication/templates/register.html create mode 100644 library/forms.py diff --git a/authentication/templates/login.html b/authentication/templates/login.html new file mode 100644 index 0000000..f1006cc --- /dev/null +++ b/authentication/templates/login.html @@ -0,0 +1,12 @@ +{% extends "store/base.html" %} + +{% block content %} +
+
+
+ {% csrf_token %} + {{form.as_p}} + +
+
+{% endblock %} \ No newline at end of file diff --git a/authentication/templates/register.html b/authentication/templates/register.html new file mode 100644 index 0000000..673e7a6 --- /dev/null +++ b/authentication/templates/register.html @@ -0,0 +1,12 @@ +{% extends "store/base.html" %} + +{% block content %} +
+
+
+ {% csrf_token %} + {{form.as_p}} + +
+
+{% endblock %} \ No newline at end of file diff --git a/authentication/urls.py b/authentication/urls.py index e69de29..9460265 100644 --- a/authentication/urls.py +++ b/authentication/urls.py @@ -0,0 +1,8 @@ +from django.urls import path +from authentication.views import * + +urlpatterns = [ + path("login/", loginView, name="loginView"), + path("register/", registerView, name="register"), + path("logout/", logoutView, name="logout"), +] \ No newline at end of file diff --git a/authentication/views.py b/authentication/views.py index 14dd530..d597b8c 100644 --- a/authentication/views.py +++ b/authentication/views.py @@ -1,13 +1,49 @@ -from django.shortcuts import render -from django.contrib.auth import login,logout,authenticate +from django.shortcuts import render, redirect +from django.http import HttpResponse +from django.contrib.auth.forms import AuthenticationForm, UserCreationForm +from django.contrib.auth import login,logout,authenticate +from django.contrib import messages +from library.forms import NewUserForm # Create your views here. def loginView(request): - pass + if request.method == "POST": + form = AuthenticationForm(request, data=request.POST) + if form.is_valid(): + username = form.cleaned_data.get('username') + password = form.cleaned_data.get('password') + user = authenticate(username=username, password=password) + if user is not None: + login(request, user) + messages.info(request, f"You are now logged in as {username}") + return redirect("index") + else: + messages.error(request, "Invalid username or password.") + else: + messages.error(request, "Invalid username or password.") + form = AuthenticationForm() + return render(request, 'login.html', {'form': form}) def logoutView(request): - pass + logout(request) + messages.info(request, "Logged out successfully!") + return redirect("index") def registerView(request): - pass \ No newline at end of file + if request.method == "POST": + form = NewUserForm(request.POST) + if form.is_valid(): + user = form.save() + username = form.cleaned_data.get('username') + messages.success(request, f"New Account Created: {username}") + login(request, user) + messages.info(request, f"You are now logged in as {username}") + return redirect("index") + + else: + for msg in form.error_messages: + messages.error(request, f"{msg}: {form.error_messages[msg]}") + + form = NewUserForm + return render(request, 'register.html', {'form': form}) \ No newline at end of file diff --git a/library/forms.py b/library/forms.py new file mode 100644 index 0000000..1b3cbb8 --- /dev/null +++ b/library/forms.py @@ -0,0 +1,17 @@ +from django import forms +from django.contrib.auth.forms import UserCreationForm +from django.contrib.auth.models import User + +class NewUserForm(UserCreationForm): + email = forms.EmailField(required=True) + + class Meta: + model = User + fields = ("username", "email", "password1", "password2") + + def save(self, commit=True): + user = super(NewUserForm, self).save(commit=False) + user.email = self.cleaned_data['email'] + if commit: + user.save() + return user diff --git a/library/urls.py b/library/urls.py index 60b7957..b078f8f 100644 --- a/library/urls.py +++ b/library/urls.py @@ -20,6 +20,8 @@ urlpatterns = [ path('',include('store.urls')), + path('', include('authentication.urls')), path('admin/', admin.site.urls), + path('authentication/',include('django.contrib.auth.urls')), path('accounts/',include('django.contrib.auth.urls')), ]+static(settings.STATIC_URL, document_root=settings.STATIC_ROOT) diff --git a/store/templates/store/base.html b/store/templates/store/base.html index 64b7a6e..f0b2238 100644 --- a/store/templates/store/base.html +++ b/store/templates/store/base.html @@ -26,10 +26,11 @@ diff --git a/store/views.py b/store/views.py index dc411b9..3343a4a 100644 --- a/store/views.py +++ b/store/views.py @@ -17,7 +17,15 @@ def bookDetailView(request, bid): 'num_available': None, # set this to the number of copies of the book available, or 0 if the book isn't available } # START YOUR CODE HERE - + book = get_object_or_404(Book, id=bid) + bookcopy = get_object_or_404(BookCopy, book=book) + + context['book'] = book + + if book.is_available: + context['num_available'] = len(bookcopy) + else: + context['num_available'] = 0 return render(request, template_name, context=context) @@ -31,7 +39,9 @@ def bookListView(request): } get_data = request.GET # START YOUR CODE HERE - + var = Book.objects.filter(title__icontains=get_data.get('title',''), author__icontains=get_data.get('author',''), genre__icontains=get_data.get('genre','')) + + context['books'] = var return render(request, template_name, context=context) @@ -46,8 +56,10 @@ def viewLoanedBooks(request): BookCopy model. Only those book copies should be included which have been loaned by the user. ''' # START YOUR CODE HERE - + user = request.user + loanedBookCopy = BookCopy.objects.filter(borrower=user) + context['books'] = loanedBookCopy return render(request, template_name, context=context) @@ -62,6 +74,16 @@ def loanBookView(request): If yes, then set the message to 'success', otherwise 'failure' ''' # START YOUR CODE HERE + book = get_object_or_404(Book, id=request.POST.get('book_id')) + if book.is_available: + user = request.user + bookCopy = BookCopy.objects.get(book=book, borrower=None) + bookCopy.borrower = user + bookCopy.save() + response_data['message'] = 'success' + else: + response_data['message'] = 'failure' + book_id = None # get the book id from post data From 63e8694c9b30c74001c0cb2413a46c44a8e8b580 Mon Sep 17 00:00:00 2001 From: ankur12-1610 <76884959+ankur12-1610@users.noreply.github.com> Date: Wed, 21 Jul 2021 14:15:15 +0530 Subject: [PATCH 2/6] Return --- store/migrations/0003_auto_20210720_1844.py | 35 +++++ store/models.py | 8 ++ store/templates/store/book_detail.html | 60 +++++++++ store/templates/store/loaned_books.html | 25 +++- store/urls.py | 1 + store/views.py | 135 ++++++++++++-------- 6 files changed, 207 insertions(+), 57 deletions(-) create mode 100644 store/migrations/0003_auto_20210720_1844.py diff --git a/store/migrations/0003_auto_20210720_1844.py b/store/migrations/0003_auto_20210720_1844.py new file mode 100644 index 0000000..a3d52a6 --- /dev/null +++ b/store/migrations/0003_auto_20210720_1844.py @@ -0,0 +1,35 @@ +# Generated by Django 2.2.1 on 2021-07-20 13:14 + +from django.conf import settings +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ('store', '0002_auto_20190607_1302'), + ] + + operations = [ + migrations.AlterField( + model_name='bookcopy', + name='borrow_date', + field=models.DateField(blank=True, null=True), + ), + migrations.AlterField( + model_name='bookcopy', + name='borrower', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='borrower', to=settings.AUTH_USER_MODEL), + ), + migrations.CreateModel( + name='UserRating', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('rating', models.FloatField(default=0)), + ('book', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='store.Book')), + ('user', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='user', to=settings.AUTH_USER_MODEL)), + ], + ), + ] diff --git a/store/models.py b/store/models.py index 17c63a3..c806825 100644 --- a/store/models.py +++ b/store/models.py @@ -30,3 +30,11 @@ def __str__(self): else: return f'{self.book.title} - Available' +class BookRating(models.Model): + user=models.ForeignKey(User, related_name='user', null=True, blank=True, on_delete=models.SET_NULL) + book = models.ForeignKey(Book, on_delete=models.CASCADE) + rating = models.FloatField(default=0.0) + + def __str__(self): + return f'{self.book.title}' + diff --git a/store/templates/store/book_detail.html b/store/templates/store/book_detail.html index 2e4b9e8..f4f77ce 100644 --- a/store/templates/store/book_detail.html +++ b/store/templates/store/book_detail.html @@ -20,6 +20,37 @@

Title: {{ book.title }}

Rs. {{ book.mrp }}
Available Copies:
{{ num_available }}
+ {% if user.is_authenticated %} +
+ Rate: + + + + {% csrf_token %} + + + + + + + + +
+ + {% endif %} {% endblock %} \ No newline at end of file diff --git a/store/templates/store/loaned_books.html b/store/templates/store/loaned_books.html index d6f2044..b329b79 100644 --- a/store/templates/store/loaned_books.html +++ b/store/templates/store/loaned_books.html @@ -37,7 +37,28 @@

Loaned Books list

{% endblock %} \ No newline at end of file diff --git a/store/urls.py b/store/urls.py index 4520334..9857608 100644 --- a/store/urls.py +++ b/store/urls.py @@ -8,4 +8,5 @@ path('books/loaned/', viewLoanedBooks, name="view-loaned"), path('books/loan/', loanBookView, name="loan-book"), path('books/return/', returnBookView, name="return-book"), + path('book/bookrating/', rateBookView, name="rate-book" ) ] diff --git a/store/views.py b/store/views.py index 3343a4a..a75c844 100644 --- a/store/views.py +++ b/store/views.py @@ -1,11 +1,12 @@ -from django.shortcuts import render +from django.shortcuts import render,redirect from django.shortcuts import get_object_or_404 +from django.shortcuts import get_list_or_404 +from datetime import date from store.models import * from django.contrib.auth.decorators import login_required from django.http import JsonResponse from django.views.decorators.csrf import csrf_exempt -# Create your views here. def index(request): return render(request, 'store/index.html') @@ -13,36 +14,27 @@ def index(request): def bookDetailView(request, bid): template_name = 'store/book_detail.html' context = { - 'book': None, # set this to an instance of the required book - 'num_available': None, # set this to the number of copies of the book available, or 0 if the book isn't available - } - # START YOUR CODE HERE - book = get_object_or_404(Book, id=bid) - bookcopy = get_object_or_404(BookCopy, book=book) - + 'book': None, + 'num_available': None, + } + book = get_object_or_404(Book, pk=bid) + bookcopy = get_list_or_404(BookCopy, book=bid) context['book'] = book - - if book.is_available: - context['num_available'] = len(bookcopy) - else: - context['num_available'] = 0 - - return render(request, template_name, context=context) + context['num_available'] = len(bookcopy) + return render(request, template_name, context) @csrf_exempt def bookListView(request): template_name = 'store/book_list.html' context = { - 'books': None, # set this to the list of required books upon filtering using the GET parameters - # (i.e. the book search feature will also be implemented in this view) + 'books': None, } get_data = request.GET - # START YOUR CODE HERE - var = Book.objects.filter(title__icontains=get_data.get('title',''), author__icontains=get_data.get('author',''), genre__icontains=get_data.get('genre','')) + + var = Book.objects.filter(title__icontains=get_data.get('title',''),author__icontains=get_data.get('author',''),genre__icontains=get_data.get('genre', '')) context['books'] = var - return render(request, template_name, context=context) @login_required @@ -51,16 +43,8 @@ def viewLoanedBooks(request): context = { 'books': None, } - ''' - The above key 'books' in the context dictionary should contain a list of instances of the - BookCopy model. Only those book copies should be included which have been loaned by the user. - ''' - # START YOUR CODE HERE - user = request.user - loanedBookCopy = BookCopy.objects.filter(borrower=user) - - context['books'] = loanedBookCopy - + loanedbookcopy = BookCopy.objects.filter(borrower=request.user) + context['books'] = loanedbookcopy return render(request, template_name, context=context) @csrf_exempt @@ -69,36 +53,77 @@ def loanBookView(request): response_data = { 'message': None, } - ''' - Check if an instance of the asked book is available. - If yes, then set the message to 'success', otherwise 'failure' - ''' - # START YOUR CODE HERE - book = get_object_or_404(Book, id=request.POST.get('book_id')) - if book.is_available: - user = request.user - bookCopy = BookCopy.objects.get(book=book, borrower=None) - bookCopy.borrower = user - bookCopy.save() - response_data['message'] = 'success' - else: - response_data['message'] = 'failure' - - book_id = None # get the book id from post data + if request.method == 'POST': + bid = request.POST.get('bid', None) + bookcopy = BookCopy.objects.filter(book=bid, status=True) + if len(bookcopy) > 0: + bookcopy[0].borrower = request.user + bookcopy[0].borrower_date = date.today() + bookcopy[0].status = False + bookcopy[0].save() + response_data['message'] = 'success' + else: + response_data['message'] = 'not available' + return JsonResponse(response_data) -''' -FILL IN THE BELOW VIEW BY YOURSELF. -This view will return the issued book. -You need to accept the book id as argument from a post request. -You additionally need to complete the returnBook function in the loaned_books.html file -to make this feature complete -''' + @csrf_exempt @login_required def returnBookView(request): - pass + response_data = { + 'message': None, + } + if request.method == 'POST': + bid = request.POST.get('bid', None) + bookcopy = BookCopy.objects.filter(book=bid, status=True) + if len(bookcopy) > 0: + bookcopy[0].borrower = None + bookcopy[0].borrower_date = date.today() + bookcopy[0].status = True + bookcopy[0].save() + response_data['message'] = 'success' + else: + response_data['message'] = 'failiure' + + return JsonResponse(response_data) + +@csrf_exempt +@login_required +def rateBookView(request): + + if request.method == "POST": + data = request.POST + bid=data.get('bid','') + rate=data.get('rate',0.0) + print(bid) + print(rate) + book = Book.objects.get(pk=bid) + oldRating=BookRating.objects.filter(user=request.user,book=book) + rating=BookRating() + rating.book=book + rating.user=request.user + rating.rating=rate + oldRating.delete() + rating.save() + other=BookRating.objects.filter(book=book) + rating_sum = 0.0 + for current in other: + rating_sum += current.rating + book.rating = rating_sum/other.count() + book.rating = round(book.rating,2) + book.save() + response_data={ + 'message':'success' + } + else: + response_data={ + 'message':'failure' + } + + + return JsonResponse(response_data) From 89789da836ff32a0868ebbcfe7f1486a59eb6fc8 Mon Sep 17 00:00:00 2001 From: ankur12-1610 <76884959+ankur12-1610@users.noreply.github.com> Date: Wed, 21 Jul 2021 15:21:45 +0530 Subject: [PATCH 3/6] Minor changes --- authentication/templates/login.html | 5 +++++ authentication/templates/register.html | 5 +++++ store/templates/store/book_detail.html | 26 +++++++------------------- 3 files changed, 17 insertions(+), 19 deletions(-) diff --git a/authentication/templates/login.html b/authentication/templates/login.html index f1006cc..4cad9b8 100644 --- a/authentication/templates/login.html +++ b/authentication/templates/login.html @@ -1,6 +1,11 @@ {% extends "store/base.html" %} +{% block title %} +Login +{% endblock %} + {% block content %} +

Login


diff --git a/authentication/templates/register.html b/authentication/templates/register.html index 673e7a6..d581991 100644 --- a/authentication/templates/register.html +++ b/authentication/templates/register.html @@ -1,6 +1,11 @@ {% extends "store/base.html" %} +{% block title %} +Register +{% endblock %} + {% block content %} +

Register


diff --git a/store/templates/store/book_detail.html b/store/templates/store/book_detail.html index f4f77ce..4c5487a 100644 --- a/store/templates/store/book_detail.html +++ b/store/templates/store/book_detail.html @@ -23,36 +23,24 @@

Title: {{ book.title }}

{% if user.is_authenticated %}
Rate: - - - + {% csrf_token %} - - - - - - - + +
- - {% endif %} + +{% else %} +

Please login or register to issue the book

+{% endif %}