diff --git a/docker-compose.yml b/docker-compose.yml index fcc60e80e5c0bd2a98bacdc370e5361e1068d15a..7f874ca4d82b909c478ff1bf74e401563b2f3d4e 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -4,7 +4,7 @@ services: web: container_name: web build: ./uwe-flix - command: python /uwe-flix/manage.py runserver 0.0.0.0:8000 + command: bash -c "python /uwe-flix/manage.py makemigrations && python /uwe-flix/manage.py migrate && python /uwe-flix/manage.py runserver 0.0.0.0:8000" volumes: - .:/code ports: diff --git a/stripe-service/stripePayments/views.py b/stripe-service/stripePayments/views.py index b0a254ee22685b08283a347920ac2f54cc64fccb..bd0a6956800b3499048650b3923aebbd97811785 100644 --- a/stripe-service/stripePayments/views.py +++ b/stripe-service/stripePayments/views.py @@ -38,7 +38,7 @@ class StripePaymentView(APIView): class GuestCheckoutSessionView(APIView): def post(self, request): - domain_url = 'http://localhost:8000/' + domain_url = 'http://127.0.0.1:8000/' stripe.api_key = settings.STRIPE_SECRET_KEY data=request.data @@ -103,7 +103,7 @@ class GuestCheckoutSessionView(APIView): class TopUpCheckoutSessionView(APIView): def post(self, request): - domain_url = 'http://localhost:8000/' + domain_url = 'http://127.0.0.1:8000/' stripe.api_key = settings.STRIPE_SECRET_KEY serializer = StripeInformationSerializer(data=request.data) diff --git a/stripe-service/stripe_service/settings.py b/stripe-service/stripe_service/settings.py index da67d41919c0ae124a2d464ff3bed900e4907d35..81196c7b503cb9d2a7d041f836beadf91c01c191 100644 --- a/stripe-service/stripe_service/settings.py +++ b/stripe-service/stripe_service/settings.py @@ -28,7 +28,7 @@ STRIPE_SECRET_KEY = 'sk_test_51MqyS8EUPKHguLdpt2tkjzZxHV7g1y6I9nODUEMtcaUx36AO4k # SECURITY WARNING: don't run with debug turned on in production! DEBUG = True -ALLOWED_HOSTS = [] +ALLOWED_HOSTS = ['127.0.0.1', 'web', 'stripe'] # Application definition diff --git a/uwe-flix/Dockerfile b/uwe-flix/Dockerfile index ea13c7617aca464c93d21eb3f42081dc512ab157..00aa9ab9cbc7ca86590b097566d7f24513c703de 100644 --- a/uwe-flix/Dockerfile +++ b/uwe-flix/Dockerfile @@ -23,4 +23,4 @@ ENV PGDATABASE=uweflix_db EXPOSE 8000 # Start the Django development server -CMD ["python", "manage.py", "runserver", "0.0.0.0:8000"] \ No newline at end of file +#CMD ["python", manage.py", "runserver", "0.0.0.0:8000"] \ No newline at end of file diff --git a/uwe-flix/accounts/views.py b/uwe-flix/accounts/views.py index 964e0aeb257b0aa3ffb7f080619ad23b854412d5..9ff7f34d44514cb5978ffd52f63360653bea63c8 100644 --- a/uwe-flix/accounts/views.py +++ b/uwe-flix/accounts/views.py @@ -204,7 +204,7 @@ def debit_history(request, pk, config): else: response = requests.post( - "http://localhost:8001/api/top_up_history/", + "http://stripe:8001/api/top_up_history/", data={"config": config, "customer_id": customer_id}, ) response_dict = response.json() @@ -262,7 +262,7 @@ def top_up_request(request, pk, account, amount): serializer = TopUpStripeInformationSerializer(topup_item) response = requests.post( - "http://localhost:8001/api/top_up_create_checkout_session/", + "http://stripe:8001/api/top_up_create_checkout_session/", json=serializer.data, ) response_dict = response.json() diff --git a/uwe-flix/authentication/views.py b/uwe-flix/authentication/views.py index b72dfa07fb0a24a164c4f53f5a261c8ca12bda9b..795997769021910b1372cdd5fd6f56685be6583f 100644 --- a/uwe-flix/authentication/views.py +++ b/uwe-flix/authentication/views.py @@ -45,23 +45,28 @@ def login_view(request): user_acc = UserAccount.objects.create( discount_rate=5, balance=0, - name=f"{user.first_name}_{user.last_name}_account", + name=f"{user.username}_account", ) user.account = user_acc user.save() # Check if the user is a member of cinema_manager_temp and their expiry date has passed - cinema_manager_temp_group = Group.objects.get(name="cinema_manager_temp") - if cinema_manager_temp_group in user.groups.all(): - today = date.today() - expiry_date_str = ( - user.groups.filter(name="cinema_manager_temp") - .first() - .temporarygroup.expiry_date + try: + cinema_manager_temp_group = Group.objects.get( + name="cinema_manager_temp" ) - expiry_date = datetime.strptime(expiry_date_str, "%Y-%m-%d").date() - if today > expiry_date: - user.groups.remove(cinema_manager_temp_group) + if cinema_manager_temp_group in user.groups.all(): + today = date.today() + expiry_date_str = ( + user.groups.filter(name="cinema_manager_temp") + .first() + .temporarygroup.expiry_date + ) + expiry_date = datetime.strptime(expiry_date_str, "%Y-%m-%d").date() + if today > expiry_date: + user.groups.remove(cinema_manager_temp_group) + except Group.DoesNotExist: + pass login(request, user) return redirect("/index") @@ -102,7 +107,7 @@ def club_rep_login(request): def logout_view(request): perms = get_user_permissions(request) - + if perms == "-1": return redirect("login") @@ -127,9 +132,9 @@ def register_view(request): A redirect to the index page. """ perms = get_user_permissions(request) - print (perms) + print(perms) if not perms == "-1": - print ("ERROR") + print("ERROR") return redirect("no_access") if request.method == "POST": @@ -146,7 +151,10 @@ def register_view(request): name=f"{user.first_name}_{user.last_name}_account", ) user.account = user_account - user.is_active = False + if User.objects.all().count() <= 1: + user.is_active = True + else: + user.is_active = False user.save() messages.success(request, "Registration Successful") return redirect("/index") @@ -165,8 +173,8 @@ def register_view(request): def no_access_redirect(request): perms = get_user_permissions(request) user = request.user - context = {'perms': perms, 'user': user} - return render(request, 'authentication/no_access.html', context) + context = {"perms": perms, "user": user} + return render(request, "authentication/no_access.html", context) def elevate_user_view(request): diff --git a/uwe-flix/booking/views.py b/uwe-flix/booking/views.py index eeeae8d93785417387b1b99a1641b0481cdeccfd..3da0309db4f5ba5432e33ed8851ebd93a748962c 100644 --- a/uwe-flix/booking/views.py +++ b/uwe-flix/booking/views.py @@ -4,8 +4,8 @@ from django.urls import reverse from django.utils import timezone from clubs.models import ClubRepresentative, Club from accounts.models import Account -from.models import Reservation,Showing,Cancelation,Ticket,Film, StripeInformation -from.forms import ReservationForm, ReservationSearch +from .models import Reservation, Showing, Cancelation, Ticket, Film, StripeInformation +from .forms import ReservationForm, ReservationSearch from .serializers import GuestStripeInformationSerializer from utils.custom_decorators import get_user_permissions, is_in_group import requests @@ -17,29 +17,27 @@ from rest_framework import status def payment_confirm(request): perms = get_user_permissions(request) - session_id = request.GET.get('session_id') + session_id = request.GET.get("session_id") + + context = {"perms": perms, "session_id": session_id} + return render(request, "paymentConfirm.html", context) - context = { - 'perms': perms, - 'session_id':session_id - } - return render(request, 'paymentConfirm.html', context) -#View to create a booking +# View to create a booking def make_booking(request, pk): user = request.user - showing = Showing.objects.get(id = pk) + showing = Showing.objects.get(id=pk) perms = get_user_permissions(request) form = ReservationForm(user=request.user) - form.fields['showing'].initial = Showing.objects.get(id = pk) - + form.fields["showing"].initial = Showing.objects.get(id=pk) + # If the submit button is pressed - if request.method == 'POST': + if request.method == "POST": user = request.user # Create a temp form to get the selected showing form = ReservationForm(request.POST, user=user) - form.fields['showing'].initial = Showing.objects.get(id = pk) + form.fields["showing"].initial = Showing.objects.get(id=pk) print("here1") if form.is_valid(): print("here2") @@ -58,111 +56,140 @@ def make_booking(request, pk): adult_cost = reservation.adult_quantity * Decimal(adultTicket.price) total_cost = student_cost + child_cost + adult_cost - + # Check if the user is logged in, if so, get the user/club discount rate if request.user.is_authenticated: discount = Decimal(1 - request.user.discount_rate) - total_cost * discount + total_cost * discount # Create the final form with the reservee and cost added if request.user.is_authenticated: reservation.reservee = request.user else: - reservation.reservee=None + reservation.reservee = None reservation.booking_cost = total_cost # If the form is all correct, save the booking, update the amount of tickets and redirect to checkout current_time = timezone.now().replace(second=0, microsecond=0) if showing.start_time >= current_time: - total_seats = reservation.student_quantity + reservation.adult_quantity + reservation.child_quantity + total_seats = ( + reservation.student_quantity + + reservation.adult_quantity + + reservation.child_quantity + ) # If not a logged in user, need to redirect to payment page for card details and order confirmation if not request.user.is_authenticated: if int(showing.available_seats) >= total_seats: - order_items = [] # Creates the product data to be passed to the Stripe Payments app for checkout - if (int(reservation.child_quantity) > 0): + if int(reservation.child_quantity) > 0: order_items.append( StripeInformation( - 'Child Ticket', - ('Child ticket for the showing of ' + film.title + ' at ' + str(showing.start_time)), - (int(childTicket.price * 100)), - (int(reservation.child_quantity)) + "Child Ticket", + ( + "Child ticket for the showing of " + + film.title + + " at " + + str(showing.start_time) + ), + (int(childTicket.price * 100)), + (int(reservation.child_quantity)), ) ) - if (int(reservation.student_quantity) > 0): + if int(reservation.student_quantity) > 0: order_items.append( StripeInformation( - 'Student Ticket', - ('Student ticket for the showing of ' + film.title + ' at ' + str(showing.start_time)), - (int(studentTicket.price * 100)), - (int(reservation.student_quantity)) + "Student Ticket", + ( + "Student ticket for the showing of " + + film.title + + " at " + + str(showing.start_time) + ), + (int(studentTicket.price * 100)), + (int(reservation.student_quantity)), ) ) - if (int(reservation.adult_quantity) > 0): + if int(reservation.adult_quantity) > 0: order_items.append( StripeInformation( - 'Adult Ticket', - ('Adult ticket for the showing of ' + film.title + ' at ' + str(showing.start_time)), - (int(adultTicket.price * 100)), - (int(reservation.adult_quantity)) + "Adult Ticket", + ( + "Adult ticket for the showing of " + + film.title + + " at " + + str(showing.start_time) + ), + (int(adultTicket.price * 100)), + (int(reservation.adult_quantity)), ) ) - + if len(order_items) == 1: - serializer = GuestStripeInformationSerializer(order_items[0]) - data = {'is_many': False, 'serializer_data': serializer.data} + serializer = GuestStripeInformationSerializer( + order_items[0] + ) + data = { + "is_many": False, + "serializer_data": serializer.data, + } elif len(order_items) > 1: - serializer = GuestStripeInformationSerializer(order_items, many=True) - data = {'is_many': True, 'serializer_data': serializer.data} + serializer = GuestStripeInformationSerializer( + order_items, many=True + ) + data = {"is_many": True, "serializer_data": serializer.data} elif len(order_items) < 1: context = { - 'form': form, - 'perms': perms, - 'error': True, - 'error_message': "Please select a number of tickets." + "form": form, + "perms": perms, + "error": True, + "error_message": "Please select a number of tickets.", } return render(request, 'make_booking.html', context) - response = requests.post('http://localhost:8001/api/guest_create_checkout_session/', json=data) + response = requests.post('http://stripe:8001/api/guest_create_checkout_session/', json=data) response_dict = response.json() if response.status_code == status.HTTP_201_CREATED: - #### Redirects to checkout above, then need to place booking upon success # Save the booking reservation.showing = showing - reservation.guest_reservee = response_dict['session_id'] + reservation.guest_reservee = response_dict["session_id"] reservation.save() # Update the available seats - showing.available_seats = int(showing.available_seats) - total_seats + showing.available_seats = ( + int(showing.available_seats) - total_seats + ) showing.save() - return redirect(response_dict['url']) + return redirect(response_dict["url"]) else: context = { - 'form': form, + "form": form, } - return render(request, 'make_booking.html', context) + return render(request, "make_booking.html", context) if user.is_rep == True: - club_representative = get_object_or_404(ClubRepresentative, linked_user=user) - club = get_object_or_404(Club, representative=club_representative.id) + club_representative = get_object_or_404( + ClubRepresentative, linked_user=user + ) + club = get_object_or_404( + Club, representative=club_representative.id + ) account = club.account else: account = get_object_or_404(Account, pk=user.account_id) - if account.balance >= total_cost: if int(showing.available_seats) >= total_seats: # Save the booking @@ -170,59 +197,62 @@ def make_booking(request, pk): reservation.save() # Update the available seats - showing.available_seats = int(showing.available_seats) - total_seats + showing.available_seats = ( + int(showing.available_seats) - total_seats + ) showing.save() # Update account balance account.balance = account.balance - total_cost account.save() - return redirect('view_bookings') - + return redirect("view_bookings") + else: context = { - 'form': form, - 'perms': perms, - 'showing':showing, - 'user':user, - 'error': True, - 'error_message': "Invalid seats in showing for booking. Please select a different showing." + "form": form, + "perms": perms, + "showing": showing, + "user": user, + "error": True, + "error_message": "Invalid seats in showing for booking. Please select a different showing.", } - return render(request, 'make_booking.html', context) + return render(request, "make_booking.html", context) else: context = { - 'form': form, - 'perms': perms, - 'showing':showing, - 'user':user, - 'error': True, - 'error_message': "Invalid funds for booking. Please top-up account." + "form": form, + "perms": perms, + "showing": showing, + "user": user, + "error": True, + "error_message": "Invalid funds for booking. Please top-up account.", } - return render(request, 'make_booking.html', context) - + return render(request, "make_booking.html", context) + else: context = { - 'form': form, - 'perms': perms, - 'showing':showing, - 'user':user, - 'error': True, - 'error_message': "The start time for that showing has elapsed. Please select a different showing." + "form": form, + "perms": perms, + "showing": showing, + "user": user, + "error": True, + "error_message": "The start time for that showing has elapsed. Please select a different showing.", } - return render(request, 'make_booking.html', context) + return render(request, "make_booking.html", context) context = { - 'form': form, - 'perms': perms, - 'showing':showing, - 'user':user, + "form": form, + "perms": perms, + "showing": showing, + "user": user, } - return render(request, 'make_booking.html', context) + return render(request, "make_booking.html", context) + -#View to request a cancellation +# View to request a cancellation def request_cancelation(request, pk): - #Upon request, get relevent reservation and make a cancellation object assigned to the reservation + # Upon request, get relevent reservation and make a cancellation object assigned to the reservation reservation = Reservation.objects.get(id=pk) reservation.cancellation_requested = True @@ -232,57 +262,67 @@ def request_cancelation(request, pk): cancelation.save() - return redirect('view_bookings') + return redirect("view_bookings") -#View for viewing all of the bookings relating to the account + +# View for viewing all of the bookings relating to the account def view_bookings(request): perms = get_user_permissions(request) try: - #Get all bookings for the current user - upcoming_bookings = Reservation.objects.filter(reservee = request.user,showing__start_time__gte =datetime.now()).order_by('-showing__start_time') - past_bookings = Reservation.objects.filter(reservee = request.user,showing__start_time__lte =datetime.now()).order_by('-showing__start_time') + # Get all bookings for the current user + upcoming_bookings = Reservation.objects.filter( + reservee=request.user, showing__start_time__gte=datetime.now() + ).order_by("-showing__start_time") + past_bookings = Reservation.objects.filter( + reservee=request.user, showing__start_time__lte=datetime.now() + ).order_by("-showing__start_time") cancelations = Cancelation.objects.all() context = { - 'upcoming_bookings':upcoming_bookings, - 'past_bookings':past_bookings, - 'cancelations':cancelations, - 'perms': perms, + "upcoming_bookings": upcoming_bookings, + "past_bookings": past_bookings, + "cancelations": cancelations, + "perms": perms, } - return render(request, 'view_bookings.html',context) - #If an error occurs or if user isn't logged in, redirect to no access page + return render(request, "view_bookings.html", context) + # If an error occurs or if user isn't logged in, redirect to no access page except: - return redirect('/no_access') - + return redirect("/no_access") + + def search_booking(request): perms = get_user_permissions(request) - if request.method == 'POST': + if request.method == "POST": form = ReservationSearch(request.POST) if form.is_valid(): try: - upcoming_booking = Reservation.objects.get(guest_reservee = request.POST.get('guest_reservee'),showing__start_time__gte =datetime.now()) - context = {'config': 1,'up_book': upcoming_booking, 'perms': perms} - return render(request, 'view_guest_booking.html', context) - + upcoming_booking = Reservation.objects.get( + guest_reservee=request.POST.get("guest_reservee"), + showing__start_time__gte=datetime.now(), + ) + context = {"config": 1, "up_book": upcoming_booking, "perms": perms} + return render(request, "view_guest_booking.html", context) + except: pass try: - past_booking = Reservation.objects.get(guest_reservee = request.POST.get('guest_reservee'),showing__start_time__lte =datetime.now()) - context = {'config': 2, 'past_book':past_booking, 'perms': perms} - return render(request, 'view_guest_booking.html', context) - + past_booking = Reservation.objects.get( + guest_reservee=request.POST.get("guest_reservee"), + showing__start_time__lte=datetime.now(), + ) + context = {"config": 2, "past_book": past_booking, "perms": perms} + return render(request, "view_guest_booking.html", context) + except: pass - context = {'config': 0, 'perms': perms} - return render(request, 'view_guest_booking.html', context) + context = {"config": 0, "perms": perms} + return render(request, "view_guest_booking.html", context) else: print(form.errors) - - form = ReservationSearch() - context = {'form': form, 'perms': perms} + context = {"form": form, "perms": perms} - return render(request, 'search_booking.html', context) \ No newline at end of file + return render(request, "search_booking.html", context) \ No newline at end of file diff --git a/uwe-flix/cinema/migrations/0001_initial.py b/uwe-flix/cinema/migrations/0001_initial.py index f026b7142e9237a702e9a695322ec3651ad141c5..5f13d31c307391a0bc1902dd099fc45ac9b54f35 100644 --- a/uwe-flix/cinema/migrations/0001_initial.py +++ b/uwe-flix/cinema/migrations/0001_initial.py @@ -26,7 +26,7 @@ class Migration(migrations.Migration): fields=[ ("id", models.AutoField(primary_key=True, serialize=False)), ("title", models.CharField(max_length=255)), - ("length", models.PositiveIntegerField()), + ("length", models.DurationField()), ("rating", models.PositiveSmallIntegerField()), ("genre", models.CharField(max_length=50)), ], diff --git a/uwe-flix/cinema/migrations/0023_film_archived_showing_archived_alter_film_length.py b/uwe-flix/cinema/migrations/0023_film_archived_showing_archived_alter_film_length.py new file mode 100644 index 0000000000000000000000000000000000000000..11a7ac74860fc06b986568c75bc4734eb2e47ff9 --- /dev/null +++ b/uwe-flix/cinema/migrations/0023_film_archived_showing_archived_alter_film_length.py @@ -0,0 +1,27 @@ +# Generated by Django 4.1.5 on 2023-05-06 13:54 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + dependencies = [ + ("cinema", "0022_alter_screen_screen_number_and_more"), + ] + + operations = [ + migrations.AddField( + model_name="film", + name="archived", + field=models.BooleanField(default=False), + ), + migrations.AddField( + model_name="showing", + name="archived", + field=models.BooleanField(default=False), + ), + migrations.AlterField( + model_name="film", + name="length", + field=models.DurationField(), + ), + ] diff --git a/uwe-flix/cinema/models.py b/uwe-flix/cinema/models.py index a39ce3c948548ed19450140ee7ae307239d3bd26..1f4d20b8b055060cf015c9a2dd3b1437e1bd9f21 100644 --- a/uwe-flix/cinema/models.py +++ b/uwe-flix/cinema/models.py @@ -1,18 +1,21 @@ from django.db import models from django.core.validators import MaxValueValidator, MinValueValidator from datetime import timedelta + # Create your models here. + class Cinema(models.Model): id = models.AutoField(primary_key=True) name = models.CharField(max_length=255) location = models.CharField(max_length=255) - + def __str__(self): return self.name - + + class Film(models.Model): - ageRatings =[ + ageRatings = [ ("U", "U"), ("PG", "PG"), ("12", "12"), @@ -24,46 +27,72 @@ class Film(models.Model): title = models.CharField(max_length=255) length = models.DurationField() rating = models.CharField(max_length=3, choices=ageRatings, default="U") - description = models.CharField(max_length=255, default='') - poster_url = models.CharField(max_length=255, default='') + description = models.CharField(max_length=255, default="") + poster_url = models.CharField(max_length=255, default="") + archived = models.BooleanField(default=False) def __str__(self): return self.title - - + + def archive(self): + self.archived = True + self.save() + return self + + def unarchive(self): + self.archived = False + self.save() + return self + + class Screen(models.Model): id = models.AutoField(primary_key=True) - cinema = models.ForeignKey(Cinema, on_delete=models.CASCADE, related_name='screens') + cinema = models.ForeignKey(Cinema, on_delete=models.CASCADE, related_name="screens") screen_number = models.PositiveSmallIntegerField(unique=True) - seating_capacity = models.PositiveIntegerField(validators=[MinValueValidator(1), MaxValueValidator(300)]) + seating_capacity = models.PositiveIntegerField( + validators=[MinValueValidator(1), MaxValueValidator(300)] + ) def __str__(self): return str(self.screen_number) - + class Showing(models.Model): id = models.AutoField(primary_key=True) - film = models.ForeignKey(Film, on_delete=models.CASCADE, related_name='showings') - screen = models.ForeignKey(Screen, on_delete=models.CASCADE, related_name='showings') + film = models.ForeignKey(Film, on_delete=models.CASCADE, related_name="showings") + screen = models.ForeignKey( + Screen, on_delete=models.CASCADE, related_name="showings" + ) start_time = models.DateTimeField() end_time = models.DateTimeField(null=True) available_seats = models.IntegerField() social_distancing = models.BooleanField(default=False) last_seat_number_assigned = models.IntegerField(default=0) covid_capacity = models.IntegerField(default=0) - + archived = models.BooleanField(default=False) + def __str__(self): out = self.start_time.strftime("%d %B %Y %I:%M%p") out = out + " - " + self.film.title print(out) return out - + def save(self, *args, **kwargs): self.end_time = self.start_time + self.film.length super().save(*args, **kwargs) - - + + def archive(self): + self.archived = True + self.save() + return self + + def unarchive(self): + self.archived = False + self.save() + return self + + class Ticket(models.Model): ID = models.AutoField(primary_key=True) ticket_type = models.CharField(max_length=255) - price = models.DecimalField(max_digits=10,decimal_places=2) \ No newline at end of file + price = models.DecimalField(max_digits=10, decimal_places=2) diff --git a/uwe-flix/cinema/templates/cinema/films_management.html b/uwe-flix/cinema/templates/cinema/films_management.html index f76dfcc7b1b6d88437ee6097849cc77d6b8ea062..fbf37df72b755c28e6df366d52ced6841deaf523 100644 --- a/uwe-flix/cinema/templates/cinema/films_management.html +++ b/uwe-flix/cinema/templates/cinema/films_management.html @@ -2,38 +2,126 @@ <div class="container mt-4"> <h1>Manage Films</h1> - <table class="table table-striped mt-3"> - <thead> - <tr> - <th>Film</th> - <th>Length</th> - <th>Rating</th> - <th>Description</th> - </tr> - </thead> - <tbody> - {% for film in films %} - <tr> - <td>{{ film.title }}</td> - <td>{{ film.length }}</td> - <td>{{ film.rating }}</td> - <td>{{ film.description }}</td> - <td> - <a href="{% url 'update_film' pk=film.id %}" class="btn btn-primary" - >Edit</a - > - <a - href="{% url 'delete_film' pk=film.id %}" - class="btn btn-danger" - onclick="return confirm('Are you sure you want to delete this film? \n {{ film.title }} \n Length: {{ film.length }} \n Rating: {{ film.rating }}')" - >Delete</a - > - </td> - </tr> - {% endfor %} - </tbody> - </table> - <a href="{% url 'create_film' %}" class="btn btn-success mt-3">Create Film</a> + <ul class="nav nav-tabs" id="myTab" role="tablist"> + <li class="nav-item"> + <a + class="nav-link active" + id="films-tab" + data-toggle="tab" + href="#films" + role="tab" + aria-controls="films" + aria-selected="true" + >Films</a + > + </li> + <li class="nav-item"> + <a + class="nav-link" + id="archived-films-tab" + data-toggle="tab" + href="#archived-films" + role="tab" + aria-controls="archived-films" + aria-selected="false" + >Archived Films</a + > + </li> + </ul> + + <div class="tab-content" id="myTabContent"> + <div + class="tab-pane fade show active" + id="films" + role="tabpanel" + aria-labelledby="films-tab" + > + <table class="table table-striped mt-3"> + <thead> + <tr> + <th>Film</th> + <th>Length</th> + <th>Rating</th> + <th>Description</th> + <th>Action</th> + </tr> + </thead> + <tbody> + {% for film in films %} + <tr> + <td>{{ film.title }}</td> + <td>{{ film.length }}</td> + <td>{{ film.rating }}</td> + <td>{{ film.description }}</td> + <td> + <a + href="{% url 'update_film' pk=film.id %}" + class="btn btn-primary" + >Edit</a + > + <a + href="{% url 'delete_film' pk=film.id %}" + class="btn btn-danger" + onclick="return confirm('Are you sure you want to delete this film? \n {{ film.title }} \n Length: {{ film.length }} \n Rating: {{ film.rating }}')" + >Delete</a + > + </td> + </tr> + + {% endfor %} + </tbody> + </table> + <a href="{% url 'create_film' %}" class="btn btn-success mt-3" + >Create Film</a + > + </div> + + <div + class="tab-pane fade" + id="archived-films" + role="tabpanel" + aria-labelledby="archived-films-tab" + > + <table class="table table-striped mt-3"> + <thead> + <tr> + <th>Film</th> + <th>Length</th> + <th>Rating</th> + <th>Description</th> + <th>Action</th> + </tr> + </thead> + <tbody> + {% for film in archived_films %} + <tr> + <td>{{ film.title }}</td> + <td>{{ film.length }}</td> + <td>{{ film.rating }}</td> + <td>{{ film.description }}</td> + <td> + <a + href="{% url 'update_film' pk=film.id %}" + class="btn btn-primary" + >Edit</a + > + <a + href="{% url 'delete_film' pk=film.id %}" + class="btn btn-danger" + onclick="return confirm('Are you sure you want to delete this film? \n {{ film.title }} \n Length: {{ film.length }} \n Rating: {{ film.rating }}')" + >Delete</a + > + </td> + </tr> + + {% endfor %} + </tbody> + </table> + <a href="{% url 'create_film' %}" class="btn btn-success mt-3" + >Create Film</a + > + </div> + {% endblock %} + </div> </div> -{% endblock %} diff --git a/uwe-flix/cinema/views.py b/uwe-flix/cinema/views.py index 676a4651c63b146e52c03ef97784c1c9ce6b081e..eacbdc92d76a1a62b21ecb8bcb9fdd2c8fdf8499 100644 --- a/uwe-flix/cinema/views.py +++ b/uwe-flix/cinema/views.py @@ -3,7 +3,7 @@ from django.contrib import messages from .forms import ScreenForm, ShowingForm, FilmForm, CinemaForm, TicketForm from .models import Screen, Cinema, Film, Showing, Ticket from accounts.models import StudentDiscountRequest -from booking.models import Cancelation,Reservation +from booking.models import Cancelation, Reservation from authentication.models import User from utils.custom_decorators import get_user_permissions, is_in_group from datetime import datetime @@ -58,11 +58,11 @@ def screen_list(request): """ perms = get_user_permissions(request) print(perms) - if not perms == '3' and not perms == '4': - return redirect('no_access') - + if not perms == "3" and not perms == "4": + return redirect("no_access") + screens = Screen.objects.all() - showings = Showing.objects.all().order_by("start_time") + showings = Showing.objects.filter(archived=False).order_by("start_time") cinemas = Cinema.objects.all() context = { "user": request.user, @@ -91,19 +91,25 @@ def screen_create(request): A redirect to the screen management page. """ perms = get_user_permissions(request) - if not perms == '3' and not perms == '4': - return redirect('no_access') - - if request.method == 'POST': + if not perms == "3" and not perms == "4": + return redirect("no_access") + + if request.method == "POST": form = ScreenForm(request.POST) if form.is_valid(): screen = form.save() - return redirect('manage_screens') - + return redirect("manage_screens") + elif not form.is_valid(): - context = {'form': form, 'user': request.user, 'screen': screen, 'perms': perms, 'form_errors': form.errors} - return render(request, 'cinema/update_screen.html', context) - + context = { + "form": form, + "user": request.user, + "screen": screen, + "perms": perms, + "form_errors": form.errors, + } + return render(request, "cinema/update_screen.html", context) + form = ScreenForm() context = { "form": form, @@ -125,20 +131,26 @@ def screen_update(request, pk): redirect to screen management """ perms = get_user_permissions(request) - if not perms == '3' and not perms == '4': - return redirect('no_access') - + if not perms == "3" and not perms == "4": + return redirect("no_access") + screen = get_object_or_404(Screen, pk=pk) if request.method == "POST": form = ScreenForm(request.POST, instance=screen) if form.is_valid(): screen = form.save() - return redirect('manage_screens') - + return redirect("manage_screens") + elif not form.is_valid(): - context = {'form': form, 'user': request.user, 'screen': screen, 'perms': perms, 'form_errors': form.errors} - return render(request, 'cinema/update_screen.html', context) - + context = { + "form": form, + "user": request.user, + "screen": screen, + "perms": perms, + "form_errors": form.errors, + } + return render(request, "cinema/update_screen.html", context) + form = ScreenForm(instance=screen) context = {"form": form, "user": request.user, "screen": screen, "perms": perms} return render(request, "cinema/update_screen.html", context) @@ -146,12 +158,13 @@ def screen_update(request, pk): def screen_delete(request, pk): perms = get_user_permissions(request) - if not perms == '3' and not perms == '4': - return redirect('no_access') - + if not perms == "3" and not perms == "4": + return redirect("no_access") + screen = get_object_or_404(Screen, pk=pk) screen.delete() - return redirect('manage_screens') + return redirect("manage_screens") + def showings_list(request): """ @@ -164,19 +177,25 @@ def showings_list(request): """ perms = get_user_permissions(request) print(perms) - if not perms == '3' and not perms == '4': - return redirect('no_access') - - showings = Showing.objects.all().order_by('start_time') - context = {'showings': showings, 'perms': perms} - return render(request, 'cinema/showings_management.html', context) + if not perms == "3" and not perms == "4": + return redirect("no_access") + + showings = Showing.objects.filter(archived=False).order_by("start_time") + archived_showings = Showing.objects.filter(archived=True).order_by("start_time") + context = { + "showings": showings, + "perms": perms, + "archived_showings": archived_showings, + } + return render(request, "cinema/showings_management.html", context) + def showing_create(request): perms = get_user_permissions(request) - if not perms == '3' and not perms == '4': - return redirect('no_access') - - films = Film.objects.all() + if not perms == "3" and not perms == "4": + return redirect("no_access") + + films = Film.objects.filter(archived=False) screens = Screen.objects.all() if request.method == "POST": @@ -209,6 +228,7 @@ def showing_create(request): } return render(request, "cinema/create_showing.html", context) + def films_list(request): """ Handle a screen management page request. @@ -220,19 +240,21 @@ def films_list(request): """ perms = get_user_permissions(request) print(perms) - if not perms == '3' and not perms == '4': - return redirect('no_access') - - films = Film.objects.all().order_by('title') - context = {'films': films, 'perms': perms} - return render(request, 'cinema/films_management.html', context) + if not perms == "3" and not perms == "4": + return redirect("no_access") + + films = Film.objects.filter(archived=False).order_by("title") + archived_films = Film.objects.filter(archived=True).order_by("title") + context = {"films": films, "perms": perms, "archived_films": archived_films} + return render(request, "cinema/films_management.html", context) + def film_create(request, pk=None): perms = get_user_permissions(request) - if not perms == '3' and not perms == '4': - return redirect('no_access') - - if request.method == 'POST': + if not perms == "3" and not perms == "4": + return redirect("no_access") + + if request.method == "POST": form = FilmForm(request.POST) if form.is_valid(): f = form.save() @@ -247,11 +269,11 @@ def film_create(request, pk=None): def film_delete(request, pk): perms = get_user_permissions(request) - if not perms == '3' and not perms == '4': - return redirect('no_access') - + if not perms == "3" and not perms == "4": + return redirect("no_access") + film = get_object_or_404(Film, pk=pk) - showings = Showing.objects.filter(film=film) + showings = Showing.objects.filter(film=film, archived=False) print(f"showings {showings}") if showings.exists(): messages.error( @@ -260,9 +282,10 @@ def film_delete(request, pk): ) return redirect("film_management") else: - film.delete() + film.arhive() return redirect("film_management") + def users_list(request): """ Handle a user management page request. @@ -287,11 +310,15 @@ def users_list(request): } return render(request, "cinema/user_management.html", context) - if not perms == '3' and not perms == '4': - return redirect('no_access') - - context = {'users' : User.objects.filter(is_rep=False), 'user': request.user, 'perms': perms} - return render(request, 'cinema/user_management.html', context) + if not perms == "3" and not perms == "4": + return redirect("no_access") + + context = { + "users": User.objects.filter(is_rep=False), + "user": request.user, + "perms": perms, + } + return render(request, "cinema/user_management.html", context) def enable_user(request, pk): @@ -303,9 +330,9 @@ def enable_user(request, pk): """ perms = get_user_permissions(request) - if not perms == '3' and not perms == '4': - return redirect('no_access') - + if not perms == "3" and not perms == "4": + return redirect("no_access") + user = get_object_or_404(User, pk=pk) user.is_active = True user.save() @@ -320,9 +347,9 @@ def disable_user(request, pk): A redirect to the user management page. """ perms = get_user_permissions(request) - if not perms == '3' and not perms == '4': - return redirect('no_access') - + if not perms == "3" and not perms == "4": + return redirect("no_access") + user = get_object_or_404(User, pk=pk) user.is_active = False user.save() @@ -340,23 +367,24 @@ def bookings_list(request): """ perms = get_user_permissions(request) print(perms) - if not perms == '3' and not perms == '4': - return redirect('no_access') - - context = {'cancellations' : Cancelation.objects.all(), 'perms': perms} - return render(request, 'cinema/manage_cancellations.html', context) + if not perms == "3" and not perms == "4": + return redirect("no_access") + + context = {"cancellations": Cancelation.objects.all(), "perms": perms} + return render(request, "cinema/manage_cancellations.html", context) + def approve_cancellation(request, pk): """ Handle a cinema manager approving a user cancellation via the cancellation management page. - + Returns: A redirect to the cancellation management page. """ perms = get_user_permissions(request) - if not perms == '3' and not perms == '4': - return redirect('no_access') - + if not perms == "3" and not perms == "4": + return redirect("no_access") + cancellation = get_object_or_404(Cancelation, pk=pk) cancellation.approved = True cancellation.save() @@ -365,23 +393,25 @@ def approve_cancellation(request, pk): booking.cancelled = True booking.save() - booking.reservee.account.balance = float(booking.reservee.account.balance) + booking.booking_cost + booking.reservee.account.balance = ( + float(booking.reservee.account.balance) + booking.booking_cost + ) booking.reservee.account.save() - - return redirect('cancellation_management') + return redirect("cancellation_management") + def disapprove_cancellation(request, pk): """ Handle a cinema manager disapproving a user cancellation via the cancellation management page. - + Returns: A redirect to the cancellation management page. """ perms = get_user_permissions(request) - if not perms == '3' and not perms == '4': - return redirect('no_access') - + if not perms == "3" and not perms == "4": + return redirect("no_access") + cancellation = get_object_or_404(Cancelation, pk=pk) cancellation.approved = False cancellation.save() @@ -390,27 +420,28 @@ def disapprove_cancellation(request, pk): booking.cancelled = False booking.save() - return redirect('cancellation_management') + return redirect("cancellation_management") + def delete_showing(request, pk): perms = get_user_permissions(request) - if not perms == '3' and not perms == '4': - return redirect('no_access') - + if not perms == "3" and not perms == "4": + return redirect("no_access") + showing = get_object_or_404(Showing, pk=pk) # Need to check for related bookings, and decide what to do here. Maybe stripe has a refund? - showing.delete() + showing.archive() return redirect("showings_management") def update_showing(request, pk): perms = get_user_permissions(request) - if not perms == '3' and not perms == '4': - return redirect('no_access') - - if request.method == 'POST': + if not perms == "3" and not perms == "4": + return redirect("no_access") + + if request.method == "POST": form = ShowingForm(request.POST) if form.is_valid(): # If the screen has changed, need to check if there are enough seats in the new screen. @@ -428,12 +459,12 @@ def update_showing(request, pk): def update_film(request, pk): perms = get_user_permissions(request) - if not perms == '3' and not perms == '4': - return redirect('no_access') - + if not perms == "3" and not perms == "4": + return redirect("no_access") + film = get_object_or_404(Film, pk=pk) - if request.method == 'POST': + if request.method == "POST": form = FilmForm(request.POST) if form.is_valid(): film.title = form.cleaned_data["title"] @@ -443,7 +474,6 @@ def update_film(request, pk): film.save() return redirect("manage_screens") - form = FilmForm(instance=film) # Need to see how to default fill length and rating @@ -454,18 +484,18 @@ def update_film(request, pk): def tickets_list(request): perms = get_user_permissions(request) - if not perms == '3' and not perms == '4': - return redirect('no_access') - - context = {'tickets' : Ticket.objects.all(), 'user': request.user, 'perms': perms} - return render(request, 'cinema/tickets_management.html', context) + if not perms == "3" and not perms == "4": + return redirect("no_access") + + context = {"tickets": Ticket.objects.all(), "user": request.user, "perms": perms} + return render(request, "cinema/tickets_management.html", context) def update_ticket(request, pk): perms = get_user_permissions(request) - if not perms == '3' and not perms == '4': - return redirect('no_access') - + if not perms == "3" and not perms == "4": + return redirect("no_access") + ticket = get_object_or_404(Ticket, pk=pk) if request.method == "POST": diff --git a/uwe-flix/initial_data.json b/uwe-flix/initial_data.json index 9722010338ecb5591e9225fbd3c46b066b8d699b..3bc3e53d840b057d9eb020aa966e738d1ecfd408 100644 --- a/uwe-flix/initial_data.json +++ b/uwe-flix/initial_data.json @@ -1,86 +1,88 @@ [ { - "model": "auth.group", + "model": "cinema.Cinema", + "pk": 1, "fields": { - "id": "1", - "name": "admin" + "name": "UWEFlix", + "location" : "UWE" } }, { "model": "auth.group", + "pk": 1, "fields": { - "id": "2", - "name": "account_manager" + "name": "admin" } }, { "model": "auth.group", + "pk": 2, "fields": { - "id": "3", - "name": "cinema_manager" + "name": "account_manager" } }, { "model": "auth.group", + "pk": 3, "fields": { - "id": "4", - "name": "account_manager_temp" + "name": "cinema_manager" } }, { "model": "authentication.User", "fields": { "username": "admin", - "password": "group5desd", + "password": "pbkdf2_sha256$390000$HlaKNRkiMvNmva2t4DDGDI$YRgFar+meTQx4OfEY0vIVvgJQaip8hSTUTYVJIOTojI=", "is_superuser": true, "is_staff": true, - "is_active": true + "is_active": true, + "groups": [1] } }, { "model": "authentication.User", "fields": { - "username": "cinema-manager", - "password": "group5desd", + "username": "account_manager", + "password": "pbkdf2_sha256$390000$HlaKNRkiMvNmva2t4DDGDI$YRgFar+meTQx4OfEY0vIVvgJQaip8hSTUTYVJIOTojI=", "is_superuser": false, "is_staff": true, "is_active": true, - "groups": ["cinema_manager"] + "groups": [2] } }, { "model": "authentication.User", "fields": { - "username": "account-manager", - "password": "group5desd", + "username": "cinema_manager", + "password": "pbkdf2_sha256$390000$HlaKNRkiMvNmva2t4DDGDI$YRgFar+meTQx4OfEY0vIVvgJQaip8hSTUTYVJIOTojI=", "is_superuser": false, "is_staff": true, "is_active": true, - "groups": ["account_manager"] + "groups": [3] } }, { "model": "cinema.Ticket", "fields": { - "ID": 1, - "ticket_type": "AdultTicket", - "price": 10.0 + "ID": 1, + "ticket_type": "AdultTicket", + "price": 10.0 } }, { "model": "cinema.Ticket", "fields": { - "ID": 2, - "ticket_type": "StudentTicket", - "price": 7.50 + "ID": 2, + "ticket_type": "StudentTicket", + "price": 7.5 } }, { "model": "cinema.Ticket", - "fields":{ - "ID": 3, - "ticket_type": "ChildTicket", - "price": 5.0 + "fields": { + "ID": 3, + "ticket_type": "ChildTicket", + "price": 5.0 } } ] diff --git a/uwe-flix/templates/base.html b/uwe-flix/templates/base.html index 54a7d80bcbe11c26200d7c6e6f4ed8eac82f73b1..fccd90d1f6729e93dc9ccce4bd8d93e43f2ca37f 100644 --- a/uwe-flix/templates/base.html +++ b/uwe-flix/templates/base.html @@ -55,7 +55,7 @@ </a> <div class="dropdown-menu" aria-labelledby="navbarDropdown"> {% if perms == '-1' %} - <a class="dropdown-item" href="{% url 'search_booking' %}" + <a class="dropdown-item" href="{% url 'search_booking' %}" >View Tickets</a > {% elif not perms == '1' %} @@ -146,21 +146,22 @@ aria-expanded="false" > <i class="fa fa-user"></i> - {{user.username}} - {% if not user.is_rep %} (£{{ user.account.balance }}) {% endif %} - {% if user.is_rep %} (£{{ club_account_balance }}) {% endif %} + {{user.username}} {% if not user.is_rep %} + (£{{user.account.balance }}) + {% endif %} {% if user.is_rep %} + (£{{club_account_balance }}) {% endif %} </a> <div class="dropdown-menu dropdown-menu-right" aria-labelledby="userDropdown" > - {% if not user.is_rep %} + {% if not user.is_rep %} {% if user.account %} <a class="dropdown-item" href="{% url 'top_up_balance' pk=user.account.pk %}" >Top Up Balance</a > - {% endif %} {% if user.is_rep %} + {% endif %} {% endif %} {% if user.is_rep %} <a class="dropdown-item" href="{% url 'top_up_club_balance' pk=user.pk %}" diff --git a/uwe-flix/utils/views.py b/uwe-flix/utils/views.py index 5d95f697ccc89ad8c0192aa164f52d987fea6e12..d6ff0d50774b2fe7f0c7b708e15960e230ab8e16 100644 --- a/uwe-flix/utils/views.py +++ b/uwe-flix/utils/views.py @@ -12,7 +12,7 @@ import requests def index_view(request): perms = get_user_permissions(request) - films = Film.objects.all() + films = Film.objects.filter(archived=False) # get the date input from the form or use None as default date = None @@ -23,11 +23,11 @@ def index_view(request): # get all showings that start after the current time current_time = timezone.now() - showings = Showing.objects.filter(start_time__gte=current_time) + showings = Showing.objects.filter(start_time__gte=current_time, archived=False) # filter showings by date if provided if date is not None: - showings = showings.filter(start_time__date=date) + showings = showings.filter(start_time__date=date, archived=False) # group showings by film showings_by_film = {} @@ -56,7 +56,13 @@ def index_view(request): return render( request, "utils/index.html", - {"user": request.user, "perms": perms, "films": films, "showings": showings, "showings_by_film": showings_by_film}, + { + "user": request.user, + "perms": perms, + "films": films, + "showings": showings, + "showings_by_film": showings_by_film, + }, ) @@ -69,8 +75,8 @@ def view_my_details(request): """ perms = get_user_permissions(request) - if perms == '-1': - return redirect('login') + if perms == "-1": + return redirect("login") if request.method == "GET": # Get the current logged-in user diff --git a/uwe-flix/uweflix/settings.py b/uwe-flix/uweflix/settings.py index a19c014bf0f6acb7d94018e3f507438983a03d9e..adabfa30000b380254805d84249fa8811ffb5c7b 100644 --- a/uwe-flix/uweflix/settings.py +++ b/uwe-flix/uweflix/settings.py @@ -16,7 +16,7 @@ import os # Build paths inside the project like this: BASE_DIR / 'subdir'. BASE_DIR = Path(__file__).resolve().parent.parent -BASE_URL = 'http://localhost:8000/' +BASE_URL = 'http://web:8000/' # Quick-start development settings - unsuitable for production # See https://docs.djangoproject.com/en/4.1/howto/deployment/checklist/ @@ -27,7 +27,7 @@ SECRET_KEY = "django-insecure-@w&0@of43$$x&wqft2)fa_n5-+7j_ao)5z2ceb#%n$wn)(0oxh # SECURITY WARNING: don't run with debug turned on in production! DEBUG = True -ALLOWED_HOSTS = [] +ALLOWED_HOSTS = ['127.0.0.1', 'web', 'stripe'] # Application definition @@ -39,13 +39,13 @@ INSTALLED_APPS = [ "django.contrib.sessions", "django.contrib.messages", "django.contrib.staticfiles", - 'accounts', - 'authentication', - 'booking', - 'cinema', - 'clubs', - 'payments', - 'utils', + "accounts", + "authentication", + "booking", + "cinema", + "clubs", + "payments", + "utils", ] MIDDLEWARE = [ @@ -71,7 +71,7 @@ TEMPLATES = [ "django.template.context_processors.request", "django.contrib.auth.context_processors.auth", "django.contrib.messages.context_processors.messages", - 'utils.context_processors.club_account_balance', + "utils.context_processors.club_account_balance", ], }, }, @@ -136,6 +136,6 @@ STATIC_URL = "static/" DEFAULT_AUTO_FIELD = "django.db.models.BigAutoField" -AUTH_USER_MODEL = 'authentication.User' +AUTH_USER_MODEL = "authentication.User" -OMDB_API_KEY = '326851bc' \ No newline at end of file +OMDB_API_KEY = "326851bc" \ No newline at end of file