diff --git a/authentication/templates/authentication/register.html b/authentication/templates/authentication/register.html new file mode 100644 index 0000000..07dac5b --- /dev/null +++ b/authentication/templates/authentication/register.html @@ -0,0 +1,97 @@ + + + + + + + Document + + +
+ + +
+
{% csrf_token %} + +
+ +
+ +
+ +
+
+ + + + +
+
+ + + + + + + + diff --git a/authentication/urls.py b/authentication/urls.py index e69de29..cd061c7 100644 --- a/authentication/urls.py +++ b/authentication/urls.py @@ -0,0 +1,9 @@ +from django.urls import path +from . import views + +app_name = "main" + + +urlpatterns = [ + path("register", views.registerView, name="register") +] \ No newline at end of file diff --git a/authentication/views.py b/authentication/views.py index 14dd530..108d931 100644 --- a/authentication/views.py +++ b/authentication/views.py @@ -1,7 +1,17 @@ -from django.shortcuts import render +import json + +from django.shortcuts import render, redirect from django.contrib.auth import login,logout,authenticate +from django.contrib.auth.models import User, auth # Create your views here. +dataDictionary = {'cas': 0} +dataJSON = json.dumps(dataDictionary) +dataDictionary1 = {'cas': 1} +dataJSON1 = json.dumps(dataDictionary1) +dataDictionary2 = {'cas': 2} +dataJSON2 = json.dumps(dataDictionary2) + def loginView(request): pass @@ -10,4 +20,19 @@ def logoutView(request): pass def registerView(request): - pass \ No newline at end of file + template_name = 'authentication/register.html' + if request.method == 'POST': + f_name = request.POST['first_name'] + l_name = request.POST['last_name'] + username = request.POST['username'] + password = request.POST['password'] + print(type(f_name), type(l_name), type(username), type(password)) + if len(f_name) == 0 or len(l_name) == 0 or len(username) == 0 or len(password) == 0: + return render(request, template_name, {'data': dataJSON1}) + if User.objects.filter(username=username): + return render(request, template_name, {'data': dataJSON2}) + user = User.objects.create_user(username=username, password=password, first_name=f_name, last_name=l_name) + user.save() + return redirect('accounts/login') + else: + return render(request, template_name, {'data': dataJSON}) diff --git a/library/settings.py b/library/settings.py index 9009d3b..ff4f62f 100644 --- a/library/settings.py +++ b/library/settings.py @@ -9,12 +9,13 @@ For the full list of settings and their values, see https://docs.djangoproject.com/en/2.1/ref/settings/ """ +from pathlib import Path import django_heroku import os # Build paths inside the project like this: os.path.join(BASE_DIR, ...) -BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) +BASE_DIR = Path(__file__).resolve().parent.parent # Quick-start development settings - unsuitable for production @@ -57,7 +58,7 @@ TEMPLATES = [ { 'BACKEND': 'django.template.backends.django.DjangoTemplates', - 'DIRS': [], + 'DIRS': [BASE_DIR / 'templates'], 'APP_DIRS': True, 'OPTIONS': { 'context_processors': [ diff --git a/library/urls.py b/library/urls.py index 60b7957..e2a0300 100644 --- a/library/urls.py +++ b/library/urls.py @@ -20,6 +20,7 @@ urlpatterns = [ path('',include('store.urls')), + path('',include('authentication.urls')), path('admin/', admin.site.urls), path('accounts/',include('django.contrib.auth.urls')), ]+static(settings.STATIC_URL, document_root=settings.STATIC_ROOT) diff --git a/store/admin.py b/store/admin.py index 144f0f1..3d31a26 100644 --- a/store/admin.py +++ b/store/admin.py @@ -4,3 +4,4 @@ admin.site.register(Book) admin.site.register(BookCopy) +admin.site.register(BookRating) diff --git a/store/migrations/0003_auto_20210714_0609.py b/store/migrations/0003_auto_20210714_0609.py new file mode 100644 index 0000000..f7ab24e --- /dev/null +++ b/store/migrations/0003_auto_20210714_0609.py @@ -0,0 +1,30 @@ +# Generated by Django 2.2.1 on 2021-07-14 06:09 + +from django.conf import settings +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('store', '0002_auto_20190607_1302'), + ] + + operations = [ + migrations.AddField( + model_name='book', + name='number', + field=models.PositiveIntegerField(default=0), + ), + 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), + ), + ] diff --git a/store/migrations/0004_auto_20210715_0628.py b/store/migrations/0004_auto_20210715_0628.py new file mode 100644 index 0000000..f8d4532 --- /dev/null +++ b/store/migrations/0004_auto_20210715_0628.py @@ -0,0 +1,19 @@ +# Generated by Django 2.2.1 on 2021-07-15 06:28 + +from django.db import migrations, models +import django.utils.timezone + + +class Migration(migrations.Migration): + + dependencies = [ + ('store', '0003_auto_20210714_0609'), + ] + + operations = [ + migrations.AlterField( + model_name='bookcopy', + name='borrow_date', + field=models.DateField(blank=True, default=django.utils.timezone.now, null=True), + ), + ] diff --git a/store/migrations/0005_bookrating.py b/store/migrations/0005_bookrating.py new file mode 100644 index 0000000..9eeb104 --- /dev/null +++ b/store/migrations/0005_bookrating.py @@ -0,0 +1,23 @@ +# Generated by Django 2.2.1 on 2021-07-15 06:39 + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('store', '0004_auto_20210715_0628'), + ] + + operations = [ + migrations.CreateModel( + name='BookRating', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('ratedBy', models.CharField(max_length=50)), + ('rating', models.SmallIntegerField()), + ('book', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='store.Book')), + ], + ), + ] diff --git a/store/migrations/0006_auto_20210715_1250.py b/store/migrations/0006_auto_20210715_1250.py new file mode 100644 index 0000000..c75ae1d --- /dev/null +++ b/store/migrations/0006_auto_20210715_1250.py @@ -0,0 +1,18 @@ +# Generated by Django 2.2.1 on 2021-07-15 12:50 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('store', '0005_bookrating'), + ] + + operations = [ + migrations.AlterField( + model_name='book', + name='rating', + field=models.FloatField(default=-1), + ), + ] diff --git a/store/models.py b/store/models.py index 17c63a3..04c0d25 100644 --- a/store/models.py +++ b/store/models.py @@ -1,3 +1,5 @@ +from django.utils import timezone + from django.db import models from django.contrib.auth.models import User # Create your models here. @@ -8,7 +10,8 @@ class Book(models.Model): genre = models.CharField(max_length=50) description = models.TextField(null=True) mrp = models.PositiveIntegerField() - rating = models.FloatField(default=0.0) + rating = models.FloatField(default=-1) + number = models.PositiveIntegerField(default=0) class Meta: ordering = ('title',) @@ -19,7 +22,7 @@ def __str__(self): class BookCopy(models.Model): book = models.ForeignKey(Book, on_delete=models.CASCADE) - borrow_date = models.DateField(null=True, blank=True) + borrow_date = models.DateField(null=True, blank=True, default=timezone.now) # True status means that the copy is available for issue, False means unavailable status = models.BooleanField(default=False) borrower = models.ForeignKey(User, related_name='borrower', null=True, blank=True, on_delete=models.SET_NULL) @@ -30,3 +33,10 @@ def __str__(self): else: return f'{self.book.title} - Available' + +class BookRating(models.Model): + book = models.ForeignKey(Book, on_delete=models.CASCADE) + ratedBy = models.CharField(max_length=50) + rating = models.SmallIntegerField() + + diff --git a/store/templates/store/base.html b/store/templates/store/base.html index 64b7a6e..3b99111 100644 --- a/store/templates/store/base.html +++ b/store/templates/store/base.html @@ -29,7 +29,7 @@
  • My Borrowed
  • Logout
  • {% else %} - +
  • Login
  • {% endif %} diff --git a/store/templates/store/book_detail.html b/store/templates/store/book_detail.html index 2e4b9e8..ab80cc2 100644 --- a/store/templates/store/book_detail.html +++ b/store/templates/store/book_detail.html @@ -15,14 +15,27 @@

    Title: {{ book.title }}

    Description:
    {{ book.description }}
    Rating:
    -
    {{ book.rating }}
    + {% if book.rating == -1 %} +
    Unrated
    + {% else %} +
    {{ book.rating }}
    + {% endif %}
    MRP:
    Rs. {{ book.mrp }}
    Available Copies:
    {{ num_available }}
    + {% endblock %} \ No newline at end of file diff --git a/store/templates/store/book_list.html b/store/templates/store/book_list.html index f83eb5b..ad1cb20 100644 --- a/store/templates/store/book_list.html +++ b/store/templates/store/book_list.html @@ -41,7 +41,11 @@

    Books list

    {{ book.title }} {{ book.author }} {{ book.genre }} + {% if book.rating == -1 %} + Unrated + {% else %} {{ book.rating }} + {% endif %} {{ book.mrp }} {% endfor %} diff --git a/store/templates/store/loaned_books.html b/store/templates/store/loaned_books.html index d6f2044..1c927fc 100644 --- a/store/templates/store/loaned_books.html +++ b/store/templates/store/loaned_books.html @@ -29,7 +29,7 @@

    Loaned Books list

    {{ copy.book.author }} {{ copy.book.genre }} {{ copy.borrow_date }} - + {% endfor %} @@ -37,7 +37,16 @@

    Loaned Books list

    {% endblock %} \ No newline at end of file diff --git a/store/urls.py b/store/urls.py index 4520334..1e98006 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('books/rate/', rateBook, name="rate-book"), ] diff --git a/store/views.py b/store/views.py index dc411b9..840806f 100644 --- a/store/views.py +++ b/store/views.py @@ -1,24 +1,34 @@ +import json + from django.shortcuts import render from django.shortcuts import get_object_or_404 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 +from django.http import Http404 -# Create your views here. +# Create your views here. def index(request): return render(request, 'store/index.html') + 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 + '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 } + try: + context['book'] = Book.objects.get(pk=bid) + context['num_available'] = Book.objects.get(pk=bid).number + except Book.DoesNotExist: + context['num_available'] = 0 + # START YOUR CODE HERE - - + return render(request, template_name, context=context) @@ -26,57 +36,145 @@ def bookDetailView(request, bid): 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, # 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) } get_data = request.GET + q = Book.objects.all() + if 'title' in get_data: + if len(get_data['title']) != 0: + q = q.filter(title=get_data['title']) + if 'author' in get_data: + if len(get_data['author']) != 0: + q = q.filter(author=get_data['author']) + if 'genre' in get_data: + if len(get_data['genre']) != 0: + q = q.filter(genre=get_data['genre']) + # START YOUR CODE HERE - - + context['books'] = q return render(request, template_name, context=context) + @login_required def viewLoanedBooks(request): template_name = 'store/loaned_books.html' context = { 'books': None, } + username = request.user.username + q = BookCopy.objects.all() + v = [] + for i in q: + if str(i.borrower) == str(username): + v.append(i) + context['books'] = v ''' 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 - - return render(request, template_name, context=context) + @csrf_exempt @login_required def loanBookView(request): + bid = request.POST['bid'] response_data = { 'message': None, } + q = Book.objects.get(pk=bid) + + username = request.user.username + r = BookCopy.objects.all() + v = [] + for i in r: + if str(i.borrower) == str(username): + v.append(i) + for i in v: + if q == i.book: + response_data['message'] = 'failure' + break + else: + if q.number > 0: + response_data['message'] = 'success' + q.number -= 1 + q.save() + s = BookCopy(book=q, borrower=request.user) + s.save() + else: + response_data['message'] = 'failure' + ''' 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_id = None # get the book id from post data - + # get the book id from post data 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 + Data = json.loads(request.body.decode('UTF-8')) + bid = Data['detail'] + q = Book.objects.get(pk=bid) + username = request.user.username + + r = BookCopy.objects.all() + for i in r: + if str(i.borrower) == str(username) and i.book == q: + i.delete() + q.number += 1 + q.save() + break + response_data = { + 'message': 'Successful', + } + return JsonResponse(response_data) +@csrf_exempt +@login_required +def rateBook(request): + Data = request.POST + response_data = { + 'message': 'success', + } + rate = Data['rate'] + q = Book.objects.get(pk=Data['bid']) + username = request.user.username + r = BookRating.objects.all() + r = r.filter(book=q) + for i in r: + if i.ratedBy == str(username): + i.rating = rate + i.save() + break + else: + x = BookRating(book=q, ratedBy=str(username), rating=rate) + x.save() + a = 0 + b = 0 + r = BookRating.objects.all() + r = r.filter(book=q) + for i in r: + a += 1 + b += i.rating + r = b / a + q.rating = r + q.save() + return JsonResponse(response_data) \ No newline at end of file diff --git a/templates/registration/login.html b/templates/registration/login.html new file mode 100644 index 0000000..c7c8011 --- /dev/null +++ b/templates/registration/login.html @@ -0,0 +1,79 @@ + + + + + + + + Document + + +
    + + + + +
    + {% csrf_token %} + {{ form.as_p }} + + +
    + + +
    + + + +