From c7b87328e400ae2f31ca9932c6735a0b8cc24c0f Mon Sep 17 00:00:00 2001 From: ryaningham2001 <ryaningham2001@gmail.com> Date: Wed, 4 Jan 2023 00:38:09 +0000 Subject: [PATCH] TODO create film --- UWEFlix/__pycache__/forms.cpython-310.pyc | Bin 2434 -> 3876 bytes UWEFlix/__pycache__/models.cpython-310.pyc | Bin 3572 -> 3883 bytes UWEFlix/__pycache__/urls.cpython-310.pyc | Bin 679 -> 1249 bytes UWEFlix/__pycache__/views.cpython-310.pyc | Bin 2850 -> 4510 bytes UWEFlix/forms.py | 32 +++++- UWEFlix/migrations/0004_seat.py | 21 ++++ ..._alter_film_id_alter_screen_id_and_more.py | 33 ++++++ .../__pycache__/0004_seat.cpython-310.pyc | Bin 0 -> 841 bytes ...d_alter_screen_id_and_more.cpython-310.pyc | Bin 0 -> 767 bytes UWEFlix/models.py | 13 ++- UWEFlix/templates/base.html | 11 +- UWEFlix/templates/create_screen.html | 29 ++++++ UWEFlix/templates/create_showing.html | 30 ++++++ UWEFlix/templates/index.html | 38 ++----- UWEFlix/templates/manage_screens.html | 37 +++++++ UWEFlix/templates/update_screen.html | 19 ++++ UWEFlix/templates/view_details.html | 13 +++ UWEFlix/urls.py | 8 ++ UWEFlix/views.py | 95 ++++++++++++++++-- db.sqlite3 | Bin 258048 -> 270336 bytes 20 files changed, 332 insertions(+), 47 deletions(-) create mode 100644 UWEFlix/migrations/0004_seat.py create mode 100644 UWEFlix/migrations/0005_alter_cinema_id_alter_film_id_alter_screen_id_and_more.py create mode 100644 UWEFlix/migrations/__pycache__/0004_seat.cpython-310.pyc create mode 100644 UWEFlix/migrations/__pycache__/0005_alter_cinema_id_alter_film_id_alter_screen_id_and_more.cpython-310.pyc create mode 100644 UWEFlix/templates/create_screen.html create mode 100644 UWEFlix/templates/create_showing.html create mode 100644 UWEFlix/templates/manage_screens.html create mode 100644 UWEFlix/templates/update_screen.html create mode 100644 UWEFlix/templates/view_details.html diff --git a/UWEFlix/__pycache__/forms.cpython-310.pyc b/UWEFlix/__pycache__/forms.cpython-310.pyc index 7d2b8dd23d19dede122396aa0092323147eb2923..275baa96faeb71ab99df915e7e209e5d3e4c682e 100644 GIT binary patch literal 3876 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 W{-It$Qmxokr<$o!pRHyVv;PBz+xjm6 delta 1017 zcmah|yKWOv5Zzht`(Zn4<2b<v3P;Knk}*Muf=7d5BpzFUkdQ@Ve3#&8?S*R_DU~JQ z2f}SBC}@!A@&)Pm0*d_sM9mK{vn<3IOR==0xo75{Id^9K>D-%2G4Xvz!C&j(XfW3f ziw*dAc=75S6s~YRwnt9S8M!?dlsgJHxcN@uW(51*+d|Jr#Nsw0cI4u@h-Zhpcy{xQ z5+WY=5%F`Rj7X7}5Gm!z8ZSRm*xC=$z#!G1Ct@^V@)}e@llNi!NWx7p)-fv9<u~=| z?G1Fp&zcAbs*tIYAz1uQ`|H)o^UxUh{nXG{N&v!>$97Y`FMORdW0|HvSI&^Bky%AZ zl}h+ch}BXwupp}*GIN<t#f;S19rcHCcNoQ7oJZh9>ed2(rnQM-(wkFz5U8SwY8$F> zWkYA+%dY-#y!3RFNKe<CWo-Tt5Q?+pu6ke#16fZSl+nWaRk>+=Xi+XxQ+3G2R_?Yt zDGU}!>M}LHTrXlY{J*yr(Ve1G9-Ea)He%*1c2j;g*%jhF>E2>l3NSQuGjCo4aMX-O z4ISCHF70p?7p;(%cH`)Ee;PfWM52q!hD&F?nnmJZ5=}$q{!{dcec@h*xG$qgwHaO! zv_`4ECz9FA1qE3jvl;GSoW`8X2%rXnu#g3EyLfk=Zt(s7crR%WlJQgwpSAn5>5F!@ z_QJ+IL4U{8evt4eCVklg3)&1pgUOzm5w5D9S~o@spT*HFz}yKfil>yJ4rN@WvJqH8 IL9ZFV0GgSt=l}o! diff --git a/UWEFlix/__pycache__/models.cpython-310.pyc b/UWEFlix/__pycache__/models.cpython-310.pyc index 324fde43e74156df9fe7ae18e0509858eeaad2fd..a41f30d68ea2a1f14da1ee576341ac60c928efea 100644 GIT binary patch delta 604 zcmZ9JOG{fp6vyY}zUIEdbs9B^Hl_H0U>Bv@g>I}+Oba0dQfND+i;@{M!3WH3=?AD= z7h%4DUF$~iL%4Gv3YPA=*L8a)*I<%?`Old%GymTi&h6Z3C4U&l0l{&1b=f9yFFy}| zdMnq(8WFRictk`|LO1wf@hMSik!tw@ZYVt0zy0#6D=c9j1NWrW9mZ5Rc*|8!(D9vm ziu(5-idsZzRDIp_3Z8mlGOPMo@RCvtDTzSu1PiccY`uFc-3uR824;PGyR)~Sxv9+u zw`k1mSI~*y<6&xkGq7xiOR$kuDou@aP_M;(X`KW=2@i3NaE-H?`);ePq&&z#`aGP4 z{1~Aheu_Vj5ne@0@Y)cX?j)h>%3y>!$?{sehu=E~I~k1AG~1@ChJZ$O9DE&poNkYT z88C=Iz0n`S$Lke5k%WUFJcmSEI)i?I$Q@hU6BhQv?%OT-<tukm)FFeK&rPWkK3CgD z%0}MmGrL%-W4MPiwNWUU0cA3cD$`r>H>m52c)4P(N2CCWlN1s^v6#;aEYBR~GIz%R E4{&UI?EnA( delta 424 zcmZ22_eGj7pO=@50SJE9ZcaYSJ&{j_@xnyy^K2>N!3>%bn}rzfb1<q*-pwT?&62{H z!qm$c#g@Vhlwv882WooxA4n9bOx9zSo*c(z$ioKYaxm~P3NRMQPcC2);bH~~H~?|6 z2G9&i^#yDT8KT%znHO*XX-<eiw^-aVb8?I9fvSpBfP|kW*W~vcqLX#FQ@O)HS~-9O z2gBrf+^RNuKxQgK6k`fQ6jLg57E3BCkYocpj2U4r(0neS`P@+R*@BacQd9FL3-X9F z@_>yt;A5Ta%M-*Mjb!{99@R(-0>%R^<Uq2J6U`#_;Eeq8%)Im{j$#O-xX2x7qMs(h w)&$-F$pnP0LX1L;Jd8yiU{!*X3;9YXyYLB5{>R79C^4CjUyPMSh*gXg091EfYybcN diff --git a/UWEFlix/__pycache__/urls.cpython-310.pyc b/UWEFlix/__pycache__/urls.cpython-310.pyc index 6cfc9aa41ddd2770aa51101ac76cb8f8304f3360..831c5e6fe67abe40bd2bf1cdd9b0b1ed1b36f08c 100644 GIT binary patch literal 1249 zcmaKr&2G~`5P<C_PSeD8nx;^oElokH)JqNGR#jCcQY0=Ms8EGv$#Okg*Tr5(yLNy4 z4m=2V9)f4^l~a!#xNtzs+M8mRA6p*pw==V|J2RUYMo+=#`<KuDlBOtM1=ODr!U2B# zCkjwNjg(lmRaJpGXhm~z%WmOVfp*l6HCs~^qJl<R=N;(4{Kpnjw?PX?^U#yJK2jHS zNe0pan34uaJy?`9MC!wmq!E%1BT36h2HcZ$AIXFjNe_?)@KDktq(xYjw1zZ<bxDs) zzYR%aq$SuC6b$SUJULRfpWa{&lx?+WPrdZ)My)`*2+1YK*%h98Y3QGZ5#eseA~Z?~ zqr6ZGEu=uMgeUc4l6Ok9@=lZlA+-vv{O1Fo5icdK=le-UQ>!qW6ZrxoLCA4YtLV;# zxh{?TC_Ax=evR@qMy8B#LdC`|h+FwEgao6m{zq%;BqA4LGZ`l=H^doTAgLEd+_LpL z=7ZRyUO-%qp$SE`*__DNn{3G~R`!-{G&tY7W1USw>_b}bg*4rre%MF1hT;!5zyti% zt)a+Q??kJ@xDloqlUbwu*<H)C<T9iIzdcUH*6$t8%Ev3so9*SI59b~Yk{xUh&gQUz zSVxF93VTE9{Dh_~JlUzWQ)Q3$Q?Ywx@3^7@cCYN4a?HdvwvAa=RCBsm+YpLjy_}Wv zpe$m1Ju53S%N692tD4w`#46XfSmn?*<;mR2y6D%s{*%InBD@ek4ko+K+iQ=GU(?{s zi=9d0XEC-Vcit0^jbAvE!=s7w^7y%vU6Ru%ymH<hAHEWQk*J;Nb<y366UZX6FK!** QLZPeTHCv|o@3;Hy7r|?cjQ{`u delta 128 zcmaFJxtvuypO=@50SJN`HYcYsF)%y^agYHwkmCTv#eEaCJGs)?qj*w;gBdhMChIZ2 zV)oPIot)2HA$E(qv?!+_v7{umD6e=WLy-VbLy^GbWR?&qF(8wN5d`^|`4|z9<0k+_ CFc>QU diff --git a/UWEFlix/__pycache__/views.cpython-310.pyc b/UWEFlix/__pycache__/views.cpython-310.pyc index b17f35df47ad4f5f5950f2189e2484c0a0b557a7..22f97ee8ed23183ed1148c30672854e1470f049d 100644 GIT binary patch literal 4510 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 delta 1207 zcmah|y>1gh5Wc;C+h_Z1pMT;wgpdF^q!3UNMTjU8Ek!_rh7}|@-op@XZM1hmB#LAZ zbX2ev4Fv^d1j;M$3N$BPfH$CI=4^;j5ZLlJv$ON_&FuL7?1x&RpU-C%_}qSe)cKr$ zQ)mr7!HFr1gbF8=aFwcDqZ&b*8tUAj1~;k6Eo!AUEwp)tW<b}O5oURg=D0&0o~L<U zpaou}#q`b$U0$LkUZ!PUp%v~?FO9dtDzDKR=r+r|Qs{b}WmyiC26I>*<OD0QBFH9l zSqbDME3*p77V}sY<P@vjQvCXN?84XN5}B7hvPum3k!-5IE~iyrcGbJ2D!-_kq<%E3 zHOWQ;oD;1Z#KHhgm<Sqz3gDZ<Lwy3F36SW!Q6NMMRjbqQ#lf>!RPi>2ntZKaCNpmx zPabA6GSN3lLtZgfa#QGn;}s3LXPmC4S<n8C8wDR43&fY-jCU5Yx-HJg1G6!>fNoe^ z%mM7@MbLc|#eul^Fy^7aBz{(;1#;+wq2e6Ed4R;}gh9I(ur1b(+kfrR81|U5Ij%L0 z8IYIttF@-JOcvx#+mjvZ&S1n4y;53kM+EIS*y@D4+hfeEAu|X4{$w^bW$l<jqGN*b zkwRpW8%ur-43R6Z+8$X1Hhaz(6H|V*=kH@DiGg_{m`oW@R)2dZ=)_T?wZm{oDG&Dl zQo4jrC*J8^W{oV39=UKGTn>~S_@6vh#jM=7S~gK)gXu4cY#EJ!DX^5*Mp_D<6ceTc zD+OWj6eorob#h{bf6){3csss#H?os07mQhwB{p&3XKF6de~4u;ZuqC<iaVnw75T!g zIAdF2$pd$8V1rL$Jm?D^4VN@sr1Z_wDIu4{<b4)|kto7JU@1{TNXMIFJMCV#4_(Ah zL<P-tgc$@MVF6(gVF>|A9n)VOZ5S96dkxC$hQT_4Q-oXZDIWCGA`R@yuyxzBi|}<E F=O>gz;otxO diff --git a/UWEFlix/forms.py b/UWEFlix/forms.py index f819381d..9098fc90 100644 --- a/UWEFlix/forms.py +++ b/UWEFlix/forms.py @@ -1,6 +1,6 @@ from django import forms from django.contrib.auth.models import User, Group -from .models import Account, User, Club, ClubRepresentative +from .models import Account, User, Club, ClubRepresentative, Screen, Cinema, Showing, Film from django.contrib.auth.forms import AuthenticationForm, UserCreationForm class AccountForm(forms.ModelForm): @@ -30,4 +30,32 @@ class RepresentativeRegistrationForm(forms.ModelForm): class ElevateUserForm(forms.ModelForm): user = forms.ModelChoiceField(queryset=User.objects.all()) - group = forms.ModelChoiceField(queryset=Group.objects.all()) \ No newline at end of file + group = forms.ModelChoiceField(queryset=Group.objects.all()) + + class Meta: + model = User + fields = ['user', 'group'] + +class ScreenForm(forms.ModelForm): + cinema = forms.ModelChoiceField(queryset=Cinema.objects.all()) + + class Meta: + model = Screen + fields = ['cinema', 'screen_number', 'seating_capacity'] + +class CinemaForm(forms.ModelForm): + class Meta: + model = Cinema + fields = ['name', 'location'] + +class ShowingForm(forms.ModelForm): + screen = forms.ModelChoiceField(queryset=Screen.objects.all()) + film = forms.ModelChoiceField(queryset=Film.objects.all()) + class Meta: + model = Showing + fields = ['screen', 'film', 'start_time'] + +class FilmForm(forms.ModelForm): + class Meta: + model = Film + fields = ['title', 'length', 'rating'] \ No newline at end of file diff --git a/UWEFlix/migrations/0004_seat.py b/UWEFlix/migrations/0004_seat.py new file mode 100644 index 00000000..e748ff2d --- /dev/null +++ b/UWEFlix/migrations/0004_seat.py @@ -0,0 +1,21 @@ +# Generated by Django 4.1.4 on 2023-01-03 16:06 + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('UWEFlix', '0003_cinema_film_screen_showing_cinemamanager_cinema'), + ] + + operations = [ + migrations.CreateModel( + name='Seat', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('screen', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='seats', to='UWEFlix.screen')), + ], + ), + ] diff --git a/UWEFlix/migrations/0005_alter_cinema_id_alter_film_id_alter_screen_id_and_more.py b/UWEFlix/migrations/0005_alter_cinema_id_alter_film_id_alter_screen_id_and_more.py new file mode 100644 index 00000000..0f240068 --- /dev/null +++ b/UWEFlix/migrations/0005_alter_cinema_id_alter_film_id_alter_screen_id_and_more.py @@ -0,0 +1,33 @@ +# Generated by Django 4.1.4 on 2023-01-03 23:55 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('UWEFlix', '0004_seat'), + ] + + operations = [ + migrations.AlterField( + model_name='cinema', + name='id', + field=models.AutoField(primary_key=True, serialize=False), + ), + migrations.AlterField( + model_name='film', + name='id', + field=models.AutoField(primary_key=True, serialize=False), + ), + migrations.AlterField( + model_name='screen', + name='id', + field=models.AutoField(primary_key=True, serialize=False), + ), + migrations.AlterField( + model_name='showing', + name='id', + field=models.AutoField(primary_key=True, serialize=False), + ), + ] diff --git a/UWEFlix/migrations/__pycache__/0004_seat.cpython-310.pyc b/UWEFlix/migrations/__pycache__/0004_seat.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..cc840dbb21de65aca0bf9ca5d4b74e0f82e81c1b GIT binary patch literal 841 zcmYjP!EVz)5M8ew$99s6Lxlw5P`Kq16}2aXP(#w73bm>lP(@^Ewarf4HTF8}I+XMZ z*M0-y$epj*D<^(|L(4c$Y1i7(zL}lzdox>fIuXJ3{p8p52PNcp1@12o!5(hYLnDZA zGLkzJC#MtYRG4P&#Ct=8E4*(+c;KXsukNHF=$LdHe=vu1sf}`(XkN-f8SCeTfXp0C ztJwV&BG|)ij?n;_ID$;5a1v+Yf|p`N;ewwwg@<25_@a5`&8P^_7eJUssh_sewg^Qe zT37CjCRDVqC}wv=2f1w6@bH!dGHSj*-5+K0i{0Jc-riwTsUYWUCbOKGsRmHYoEH~T zCF@Ym6;D8~k@d#FOG~AAH?s6#*!66iFUo>pDlb9U)?CY+>m~aLOB)){l4tS~Z2L3l zv%&yVJO}I7zp@R3S>|$M&8b(ryRHoj#jsgWVy1?yDqUyNvOp1DU1cUA6Xpmd25c2( z%tnl1pBEY6xy{(81<$I>6%sH9B|uFj7>y$*wl!GMKCA|#-OAH`Et5V98darjG%7U6 zM7>2ZzDT)B3QNVA4OZN6s<t`kj|ctXzKx1GtS9}G=%-j~W&R!yU&JR%uC@+Ta?bO3 zSWFi=sM5qAfa|TDc(^|v#)H%6@!|qzIGA|djQH;9#5k&5R`sekU+U^%HgTIxGy$Qm zcjGmvvq>L2^xC@)ZdNzCz71=}J#n^DTMK;j-`T6*WA9dreo~RHs^8JCPtVY2gO_z* PUpa`3kLCdloQLi|V-@zH literal 0 HcmV?d00001 diff --git a/UWEFlix/migrations/__pycache__/0005_alter_cinema_id_alter_film_id_alter_screen_id_and_more.cpython-310.pyc b/UWEFlix/migrations/__pycache__/0005_alter_cinema_id_alter_film_id_alter_screen_id_and_more.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..6fdc9d2d215e541b6340a34e32456f7ac871b8f3 GIT binary patch literal 767 zcmaJ<v2GMG5VgI&z1>YBQH3@Y(lyZ`pg{;F;&O<B6a*BpT49;>+{VYQ_pt8>M+vm~ z25NdffbVciMMsT<V7zzeBB3zSjONXZJu}a4cXl#@^5W~4@>4{}w*W2+M{t1ZZlF;_ z(V8?grwz*)B@c;WD*8xN1aumGi1JAB6Ef(1$67LAK5KMk<y^PM`M7Bn)UFJv%M#ij zpt?6`faFw>oGDt-JOV!Lg$58$`--cciZ7VzU##NE74h_nc=m6+;(4OBaNup9KK?r? zj@^HDdNi)}+dLf(hqr|TIrnj?4K&g-t)7mtW@~13BkfYWf~8L#SS@S)4h9h}9TpWv zHsE<@dlL<{@_eG}#>cL-04DFdv-Vt@>Ufa)M0Djs_)G{qzNi8HZ6RJSWF4*uNWlz@ z0#j;mmLXX_JFMqm$Ki5|Z%2H3xR|#c_E|fFHT9o~-NkHYe!d^wEuJi;*?VNFGuafQ zwp=t|=B{`S((c_VMn@;3;=$?7VsQ==B%xT7QEc9_Kw9ny8Jdd~Ekdg`4m)npYS#`M zg_~K}pDk_pQ!%O=qDcsg_;220l+kU<fBoM}esrgg2i&J>DoxeytCt-c9Rpo*v+c^e Uj$M3mZ^i3<8XAWQuCd+d532gjzW@LL literal 0 HcmV?d00001 diff --git a/UWEFlix/models.py b/UWEFlix/models.py index 8efe4a78..02682500 100644 --- a/UWEFlix/models.py +++ b/UWEFlix/models.py @@ -80,20 +80,31 @@ class Account(models.Model): end_of_month_statements = models.TextField() class Cinema(models.Model): + id = models.AutoField(primary_key=True) name = models.CharField(max_length=255) location = models.CharField(max_length=255) class Film(models.Model): + id = models.AutoField(primary_key=True) title = models.CharField(max_length=255) length = models.PositiveIntegerField() rating = models.PositiveSmallIntegerField() class Screen(models.Model): + id = models.AutoField(primary_key=True) cinema = models.ForeignKey(Cinema, on_delete=models.CASCADE, related_name='screens') screen_number = models.PositiveSmallIntegerField() seating_capacity = models.PositiveIntegerField() 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') - start_time = models.DateTimeField() \ No newline at end of file + start_time = models.DateTimeField() + + + + +class Seat(models.Model): + screen = models.ForeignKey(Screen, on_delete=models.CASCADE, related_name="seats") + diff --git a/UWEFlix/templates/base.html b/UWEFlix/templates/base.html index 95190c26..bf31cc42 100644 --- a/UWEFlix/templates/base.html +++ b/UWEFlix/templates/base.html @@ -22,14 +22,19 @@ <div class="collapse navbar-collapse" id="navbarNav"> <ul class="navbar-nav"> <li class="nav-item active"> - <a class="nav-link" href="#">Home</a> + <a class="nav-link" href="{% url 'index' %}">Home</a> </li> <li class="nav-item"> - <a class="nav-link" href="#">About</a> + <a class="nav-link" href="#">Buy Ticket</a> </li> <li class="nav-item"> - <a class="nav-link" href="#">Contact</a> + <a class="nav-link" href="#">View Tickets</a> </li> + {% if request.user.is_authenticated %} + <li class="nav-item"> + <a class = "nav-link" href="{% url 'view_details' %}">View My Details</a> + </li> + {% endif %} </ul> </div> </nav> diff --git a/UWEFlix/templates/create_screen.html b/UWEFlix/templates/create_screen.html new file mode 100644 index 00000000..5b1097ce --- /dev/null +++ b/UWEFlix/templates/create_screen.html @@ -0,0 +1,29 @@ +{% extends 'base.html' %} + +{% block content %} + +<div class="container mt-4"> + <h1>Create Screen</h1> + <form method="post" action="{% url 'create_screen' %}"> + {% csrf_token %} + <div class="form-group"> + <label for="screen_number">Screen Number</label> + <input type="number" class="form-control" id="screen_number" name="screen_number" required> + </div> + <div class="form-group"> + <label for="seating_capacity">Seating Capacity</label> + <input type="number" class="form-control" id="seating_capacity" name="seating_capacity" required> + </div> + <div class="form-group"> + <label for="cinema">Cinema</label> + <select class="form-control" id="cinema" name="cinema"> + {% for cinema in cinemas %} + <option value="{{ cinema.id }}">{{ cinema.name }}</option> + {% endfor %} + </select> + </div> + <button type="submit" class="btn btn-primary">Create Screen</button> + </form> +</div> + +{% endblock %} \ No newline at end of file diff --git a/UWEFlix/templates/create_showing.html b/UWEFlix/templates/create_showing.html new file mode 100644 index 00000000..afea2eab --- /dev/null +++ b/UWEFlix/templates/create_showing.html @@ -0,0 +1,30 @@ +{% extends 'base.html' %} + +{% block content %} + +<div class="container mt-4"> + <h1>Create Showing</h1> + <form method="post" action="{% url 'create_showing' screen.pk %}"> + {% csrf_token %} + <div class="form-group"> + <label for="film">Film</label> + <select class="form-control" id="film" name="film"> + {% for film in films %} + <option value="{{ film.id }}">{{ film.title }}</option> + {% endfor %} + </select> + </div> + <div class="form-group"> + <label for="screen">Screen</label> + <select class="form-control" id="screen" name="screen"> + <option value="{{ screen.id }}">{{ screen.cinema.name }} - Screen {{ screen.screen_number }}</option> + </select> + </div> + <div class="form-group"> + <label for="start_time">Start Time</label> + <input type="datetime-local" class="form-control" id="start_time" name="start_time" required> + </div> + <button type="submit" class="btn btn-primary">Create Showing</button> + </form> +</div> +{% endblock %} \ No newline at end of file diff --git a/UWEFlix/templates/index.html b/UWEFlix/templates/index.html index 35837f0f..198e1ce1 100644 --- a/UWEFlix/templates/index.html +++ b/UWEFlix/templates/index.html @@ -5,40 +5,16 @@ <div class="container mt-4"> <h1>Index</h1> {% if request.user.is_authenticated %} - {% if request.user.is_staff or request.user.is_superuser %} - <p>Welcome, {{ request.user.first_name }}! As an administrator, you have access to the following pages:</p> - <ul> - <li><a href="{% url 'create_account' %}">Create Account</a></li> - <li><a href="{% url 'representative_registration' %}">Representative Registration</a></li> - <li><a href="{% url 'create_club' %}">Club Registration</a></li> - <li><a href="{% url 'elevate_user' %}" class="btn btn-secondary mt-2">Elevate User</a></li> - </ul> - {% elif request.user.groups.filter(name='Cinema Manager').exists %} - <p>Welcome, {{ request.user.first_name }}! As a Cinema Manager, you have access to the following pages:</p> - <ul> - <li><a href="{% url 'create_account' %}">Create Account</a></li> - <li><a href="{% url 'representative_registration' %}">Representative Registration</a></li> - <li><a href="{% url 'create_club' %}">Club Registration</a></li> - </ul> - {% elif request.user.user_type == 'CR' %} - <p>Welcome, {{ request.user.first_name }}! As a club representative, you have access to the following pages:</p> - <ul> - <li><a href="{% url 'create_club' %}">Create Club</a></li> - </ul> - {% else %} - <p>Welcome, {{ request.user.first_name }}! You have access to the following pages:</p> - <ul> - <li><a href="{% url 'login' %}">Login</a></li> - <li><a href="{% url 'register' %}">Register</a></li> - </ul> - {% endif %} + <p>Welcome, {{ request.user.first_name }}! You have access to the following pages:</p> {% else %} <p>Welcome! You have access to the following pages:</p> - <ul> - <li><a href="{% url 'login' %}">Login</a></li> - <li><a href="{% url 'register' %}">Register</a></li> - </ul> {% endif %} + <ul> + <li><a href="{% url 'create_account' %}">Create Account</a></li> + <li><a href="{% url 'representative_registration' %}">Representative Registration</a></li> + <li><a href="{% url 'create_club' %}">Club Registration</a></li> + <li><a href="{% url 'elevate_user' %}" class="btn btn-secondary mt-2">Elevate User</a></li> + </ul> </div> {% endblock %} \ No newline at end of file diff --git a/UWEFlix/templates/manage_screens.html b/UWEFlix/templates/manage_screens.html new file mode 100644 index 00000000..b7e3032e --- /dev/null +++ b/UWEFlix/templates/manage_screens.html @@ -0,0 +1,37 @@ +{% extends 'base.html' %} + +{% block content %} + +<div class="container mt-4"> + <h1>Manage Screens</h1> + {% if screens %} + {% for screen in screens %} + <div class="card mb-3"> + <div class="card-body"> + <h5 class="card-title">Screen {{ screen.screen_number }}</h5> + <p class="card-text">Cinema: {{ screen.cinema.name }}</p> + <p class="card-text">Seating Capacity: {{ screen.seating_capacity }}</p> + <a href="{% url 'update_screen' pk=screen.pk %}" class="btn btn-primary">Update</a> + <a href="{% url 'delete_screen' pk=screen.pk %}" class="btn btn-danger">Delete</a> + <a href="{% url 'create_showing' pk=screen.pk %}" class="btn btn-success mt-2">Create Showing</a> + {% if screen.showings %} + <h6 class="mt-3">Showings:</h6> + <ul> + {% for showing in showings %} + {% if showing.screen.pk == screen.pk %} + <li>{{ showing.film.title }} - {{ showing.start_time|date:'g:i A' }}</li> + {% endif %} + {% endfor %} + </ul> + {% else %} + <p class="mt-3">No showings for this screen.</p> + {% endif %} + </div> + </div> + {% endfor %} + {% else %} + <p>No screens to display.</p> + {% endif %} + <a href="{% url 'create_screen' %}" class="btn btn-success mt-2">Create Screen</a> +</div> +{% endblock %} \ No newline at end of file diff --git a/UWEFlix/templates/update_screen.html b/UWEFlix/templates/update_screen.html new file mode 100644 index 00000000..3813f885 --- /dev/null +++ b/UWEFlix/templates/update_screen.html @@ -0,0 +1,19 @@ +{% extends 'base.html' %} + +{% block content %} + +<div class="container mt-4"> + <h1>Update Screen</h1> + <form method="post" action="{% url 'update_screen' screen.id %}"> + {% csrf_token %} + {% for field in form %} + <div class="form-group"> + {{ field.label_tag }} + {{ field }} + </div> + {% endfor %} + <button type="submit" class="btn btn-primary">Update Screen</button> + </form> +</div> + +{% endblock %} \ No newline at end of file diff --git a/UWEFlix/templates/view_details.html b/UWEFlix/templates/view_details.html new file mode 100644 index 00000000..a33b810e --- /dev/null +++ b/UWEFlix/templates/view_details.html @@ -0,0 +1,13 @@ +{% extends 'base.html' %} + +{% block content %} + +<div class="container mt-4"> + <h1>My Details</h1> + <p>Username: {{ user.username }}</p> + <p>First Name: {{ user.first_name }}</p> + <p>Last Name: {{ user.last_name }}</p> + <p>Email: {{ user.email }}</p> +</div> + +{% endblock %} \ No newline at end of file diff --git a/UWEFlix/urls.py b/UWEFlix/urls.py index c72a35eb..e3389e0c 100644 --- a/UWEFlix/urls.py +++ b/UWEFlix/urls.py @@ -11,4 +11,12 @@ urlpatterns = [ path('register/', views.register_view, name='register'), path('create_club/', views.create_club, name='create_club'), path('representative_registration/', views.representative_registration, name='representative_registration'), + path('elevate_user', views.elevate_user_view, name='elevate_user'), + path('view_details/', views.view_my_details, name='view_details'), + path('manage_screens/', views.screen_list, name='manage_screens'), + path('manage_screens/create_screen/', views.screen_create, name='create_screen'), + path('manage_screens/update_screen/<int:pk>/', views.screen_update, name='update_screen'), + path('manage_screens/delete_screen/<int:pk>/', views.screen_delete, name='delete_screen'), + path('manage_screens/screen_list/', views.screen_list, name='screen_list'), + path('manage_screens/showings/create_showing/<int:pk>/', views.showing_create, name='create_showing') ] diff --git a/UWEFlix/views.py b/UWEFlix/views.py index c60d8a23..bbda8a29 100644 --- a/UWEFlix/views.py +++ b/UWEFlix/views.py @@ -1,8 +1,8 @@ -from django.shortcuts import render, redirect, HttpResponseRedirect +from django.shortcuts import render, redirect, HttpResponseRedirect, get_object_or_404 from django.contrib.auth import authenticate, login, logout from django.contrib.auth.decorators import login_required -from .forms import AccountForm, UserRegistrationForm, ClubForm, RepresentativeRegistrationForm, ElevateUserForm -from .models import Account, User, ClubRepresentative, Club +from .forms import AccountForm, UserRegistrationForm, ClubForm, RepresentativeRegistrationForm, ElevateUserForm, ScreenForm, ShowingForm +from .models import Account, User, ClubRepresentative, Club, Screen, Cinema, Film, Showing from django.http import JsonResponse @@ -87,12 +87,87 @@ def representative_registration(request): def elevate_user_view(request): - if request.method== 'POST': + if request.method == 'POST': form = ElevateUserForm(request.POST) if form.is_valid(): - form.save(commit=True) - return redirect('/index/') - - else: - form = ElevateUserForm() - return render(request, 'elevate_user.html', {'form': form}) \ No newline at end of file + # Form is valid, process the data and return a response + # ... + return redirect('index') + else: + form = ElevateUserForm() + return render(request, 'elevate_user.html', {'form': form}) + + +def view_my_details(request): + if request.method == 'GET': + # Get the current logged-in user + user = request.user + # Render the template with the user's details + return render(request, 'view_details.html', {'user': user}) + + +### SCREEN MANAGEMENT ### +def screen_list(request): + screens = Screen.objects.all() + showings = Showing.objects.all() + return render(request, 'manage_screens.html', {'screens': screens, 'showings': showings}) + +def screen_create(request): + # if request.method == 'POST': + # form = ScreenForm(request.POST) + # if form.is_valid(): + # # Check if the user is a cinema manager + # if request.user.groups.filter(name='Cinema Manager').exists(): + # # Check if the cinema the user manages matches the cinema associated with the screen + # if request.user.cinema == form.cleaned_data['cinema']: + # form.save() + # return redirect('manage_screens') + # else: + # # Return an error message or redirect the user to a different page + # pass + # else: + # # Return an error message or redirect the user to a different page + # pass + # else: + # form = ScreenForm() + # return render(request, 'create_screen.html', {'form': form}) + + if request.method == 'POST': + form = ScreenForm(request.POST) + if form.is_valid(): + # Check if the user is a cinema manager + #if request.user.groups.filter(name='Cinema Manager').exists(): + # Check if the cinema the user manages matches the cinema associated with the screen + #if request.user.cinema == form.cleaned_data['cinema']: + form.save() + return redirect('manage_screens') + else: + form = ScreenForm() + return render(request, 'create_screen.html', {'form': form, 'cinemas': Cinema.objects.all()}) + +def screen_update(request, pk): + screen = get_object_or_404(Screen, pk=pk) + if request.method == 'POST': + form = ScreenForm(request.POST, instance=screen) + if form.is_valid(): + form.save() + return redirect('screen_list') + else: + form = ScreenForm(instance=screen) + return render(request, 'update_screen.html', {'form': form, 'screen': screen}) + +def screen_delete(request, pk): + screen = get_object_or_404(Screen, pk=pk) + screen.delete() + return redirect('screen_list') + +def showing_create(request, pk): + screen = get_object_or_404(Screen, pk=pk) + if request.method == 'POST': + form = ShowingForm(request.POST) + if form.is_valid(): + form.save() + return redirect('manage_screens') + else: + form = ShowingForm() + return render(request, 'create_showing.html', {'form': form, 'films': Film.objects.all(), 'screen': screen}) \ No newline at end of file diff --git a/db.sqlite3 b/db.sqlite3 index 26aff06e47ad63b3887aa7f7559f41d03c5cbb93..c98ac66b7484603760582aaa93f735be51a04626 100644 GIT binary patch delta 1461 zcmZuwU2Gdg5Wc-V`+V2<)|Zl88Yj)!sYOq2<BNat<B%whoeC&wQ&3VGD6SJ<TT8Kn z^4r2gVyh7k5s1X97F88WqLfNdXu&kjUq!<M5-)`Z5CQ?BF9C!oyyS&eg7rCZjMRr6 z&Fp-$GxN>t<S%IQuH|j37^EnwgPb;U06Akbhddzo@tH*gC2k|lTAU2;;5IS=%QQF9 zCmAVg5(c_Yb{-jsT~Jlk7mf^!XhY%tSVD_O!m;SKeKs}_-?fJOhcqpr+lgp6J~*Vg zRk!D`T7Ove$Zn6{=kwQl>)Z|QMqi_=+(21tic)yP!&+n{7f`+(QQzQK8~v(U*W~r6 z%?+8J%8v~D&BAX6^gHsRH8h5vMOV;ws29DDY{DZ%Tp63ZA)G+d)IL*bIdqz~I|vV- z9~_S*&Y>ruqi~n2y|fG}pa9a#r^UTc;dbuw4X3@X9uP`TyPgJO`Wu(iD)EFvQMg8- zaRh`VRE5r>2H{KLfp9HTp-u~;g|U|HJe=!G%q+DX12AN?r`h(T$#}`wXKXjx3E#7Z ziK>u+0yR&HV=--9XCW9#$T>sKg~~zVt#yh~Z9p5*3jVyAM|9*7{pTZzbGwMVsUs=_ z1X1k}BhhH#0ix%lGxJCKIT+$+(`;AL#DBqm$}jM<q%@ijA_mle-NHg518TwlO3B|8 zrS1?IPz?&H0-0}nU8680#MA88Ns}-kToi_dIGNN><_ZG@Kn&?JsLKvr1~OAWPuz#1 zu!z~az(xy;1pb;JB9Wo2W!tmKar4IQdmwxJ9{s`$gElE!Mtt=Lbf5w-l+89euF3i7 zHM{F&GVGDTggLkUXp2Hy8S&O1sEnfx0CH3(HT8LJpa4Cj&_mr-LR=Jp4CDaKXTUAq z0-A~AFQn*KX46-c8O~9t)BKP5lre6&Vh~H--E$evncDbP_9k1&*AW8aaG$9SOiDz& zE_pm)N=hYOVkJc(8g{Kh8)(8OR-ud+R^b93U4>$L(pZAetU)h*NKV(ATu&)U<BP0x z)B%!8ED_Z%>?~%k`|$3Ei)sx~uP4%1><-`uStx}c546k2kID98xLrPIFFa^hl3gcR z$>9L0{*g%EfL4qw*4uLpNRT8+2TFYS^anJHpP8q-aeN8h1YumAg{}C{EUdv7v#<%g zf<MW^7W`-#n($T@9tAJsz%pzB&3di4XBk%D8_TekA=5}?pPQqf2X-<UPUkEYJ<Up~ zFcCf<xD-is6V2%)8vdSyfEK+J{N^0Z<Krt(*(LPv6_W1i3T(o^_JL|l%pHCiC1vcz z@2tTCpb_7{PM71iZqO!NvJPjqC%`Dlrc-!+9UcT7IfR6-en@jL5s72VI;_I}J8(bV z`x*3Pd+)&aN@u$E7+OiietlcA|GEHexejC?bNYg9QfQNG>5r(AY^lvgJ#I_?1D?OE APXGV_ delta 393 zcmZoTAkgrDe}c52IRgWOJrKh{>O>u5M)QpcOZb^Zxxyy13utdPR8ZmC9457nRg9D0 zgq8m#zX|_t{xW_q{#pFj`J?z(Z5B+B;-74yAI9h~xm(|ZQDE{FeQilmE})SDeA^iK z%lR4kw(-mGr}3Ndo#cDBS<0ZBZ*qWu@aAoHevHfxYzro{J2Y-~6p&!syudAmli7jm z>SXqSMxedET$`^(>6bD)@U>26zW@^X%e%StUj0L60lux%*$*%(0)=|{+P9u#+`jc3 zQ}9F<pq+}_1rIQP;a_w>0EjjnU=di%vOz$Kn=O}t-<9_lZzRt=?x|d=9OpUg*w?d5 zvE>47_Gg=(yN!80W9W3*?aa1}cGKT&XO^2@xt-a9F=YCt?abEGqqZ~4Pd~SvSzx-% z4rUd`;OUM#n5`MDK?=pEhwWgNn7(EQvocFla1i@;p9M@oj4VyLf$ZC#tYUh=G`&BY cQDJ&?9wYB`*1gP1+avZeuMk>hz$gI10E>BfDgXcg -- GitLab