From d702332e9127b28e5d0f155c42d074f504105ec7 Mon Sep 17 00:00:00 2001 From: Flatlogic Bot Date: Sat, 28 Feb 2026 04:54:16 +0000 Subject: [PATCH] v1 --- config/__pycache__/settings.cpython-311.pyc | Bin 5552 -> 5618 bytes config/__pycache__/urls.cpython-311.pyc | Bin 1557 -> 996 bytes config/settings.py | 4 + config/urls.py | 17 +- core/__pycache__/models.cpython-311.pyc | Bin 209 -> 3904 bytes core/__pycache__/urls.cpython-311.pyc | Bin 347 -> 802 bytes core/__pycache__/views.cpython-311.pyc | Bin 1364 -> 7418 bytes core/migrations/0001_initial.py | 41 +++ .../__pycache__/0001_initial.cpython-311.pyc | Bin 0 -> 2891 bytes core/models.py | 61 ++++- core/templates/base.html | 144 +++++++++-- core/templates/core/dashboard.html | 211 ++++++++++++++++ core/templates/core/index.html | 239 ++++++++---------- core/templates/core/login.html | 79 ++++++ core/templates/core/profile_edit.html | 108 ++++++++ core/templates/core/register.html | 82 ++++++ core/urls.py | 12 +- core/views.py | 117 +++++++-- 18 files changed, 931 insertions(+), 184 deletions(-) create mode 100644 core/migrations/0001_initial.py create mode 100644 core/migrations/__pycache__/0001_initial.cpython-311.pyc create mode 100644 core/templates/core/dashboard.html create mode 100644 core/templates/core/login.html create mode 100644 core/templates/core/profile_edit.html create mode 100644 core/templates/core/register.html diff --git a/config/__pycache__/settings.cpython-311.pyc b/config/__pycache__/settings.cpython-311.pyc index 881731c8d6a538112a17daaf3e733deb4d833646..449589760d0875811287ab26805857d9073961c4 100644 GIT binary patch delta 165 zcmdm>{Yjg5IWI340}vc7T$EWekyn!O(MI(vEW$2P`l*~Lu2tL&3{eIt%)tzrZkt%A zatT$j>*uDXWG3q0Vg=KhhMTAJ^D|lB;`DWO@pOz24f46g1z`sH`-c?q0F5pZ1QGl| x;unWaZhlH>PO4o|CXmYr#Ko^SpAx*yEb)Lxw1M*mujmZ+i@fp;Tp$S62LNa}E-L^4 delta 78 zcmeyQy+NCIIWI340}x2uotEh`kyn!O%0~4oEUe7I44N*R`BiXU<{GWs711vsrT3b2*|o7#WxtQdv@1QyH^3K_-Gg7T3fDVmx4RHXzBI!ai}9 zd_8w6TNV#Q0RuykUn)0HiX(*sD9Q^HP2sHKW?)#uwTy{@VKop#Kow9viW{OHsG1KZ z4rKGg*aY+lFfbTFlmayg;@6bI9n1j2nmm(tFy}K0O*UkiFLaC3*VV<-F+McN=N1>3 zIr%h;yQnnKC}6-b6a&MD;R7=xBjXJQg~`UOoy^RPfs^;MI-1;I;h$hO!EA=c6)Bw^ k9#?GqF9-)*6b`roBv}F)yg~2-J5Vv>2L=#XBndPP09H&+6aWAK literal 1557 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 GZ|y(NsF830 literal 209 zcmZ3^%ge<81QK_rWm*F1#~=<2FhLogg@BCd3@HpLj5!Rsj8Tk?3@J>(44TX@K?*b( zZ?Wa(r=;c-`)M-W;!Md(%uCPLOGzqX21>4E_zY6>OHV%|KQ~psG^sSNq*On(A~m_R zB)>?%JijQrxF9h(RX;huC{-U~j9x+IFAf_ZyEG@&u80Guoe_wOWr4&8W=2NF8w@fR Ku%RM0pb7wG3pAVn diff --git a/core/__pycache__/urls.cpython-311.pyc b/core/__pycache__/urls.cpython-311.pyc index ebb8c6ea5957e01e2e132c7f2744cb84e6f77cdc..5ed621c2a397788bf153138bb166a5258fe31cdf 100644 GIT binary patch literal 802 zcmZvYzi-n(6vyx4=lpU^p#g~>l^9TjB2~2%DUpIuhX^Dl7Q_;U%FSI97yn4lF$FJl z?9d@Y1)Uin2nPNE{s&v~5P4Rge zu}#uZ-&y?FPe}>`&*3uanhp<3g7+`)&H@4<!I_10<)6DJ-IsMO)!3ow_Pw1z*uIdx7P56h_E^XU30YlQ zUL@U<&rP)~;ldFWiRcp1@DErUzS{M_lPi?SeA|$98Nq(wjskV~Q^#Y0&3DBeyewPf|Hf^mP)es{E4n_Xq#9kHvpi8tC(lkdPhX#P zFAgH8#ZXJ2HiaUp561l5oji%46+RtbF*FirWb(c7^W=7I@*;v} y49x_ZnY=X)&Oc7xM9_|*oj^NNA70dw``f>EBk07?NuV>+3mdr;O@5+^75oKOC(uIx delta 251 zcmZ3)cAH6kIWI340}x2uotBveq#uJgFu)3Be72dWu3DeMx`u5TGXukFAclZ+#weB) z_Fx80j+Y<-O~zX+1&JjYFBzenjQrfxTMR`YV?c6wiMgqMnyk0DQ?e5C()0C7i*kyK zK!)97Ez3+TF9s{T#SIh&no^Qllvlix;WJR0;g^nnM*d`ZCKE0`AP;1EvDf5SCMk;t s4B{71(FZmLR?Y^O4xx^a8Eh9=xX?n`v01JHI~q7TwRC8X`i_9yzYdlP$EnWzn9_a*kRw509N4kiXU z!jlU`>3TqvZngU>4SD^ZJ zO`Rl0A-At1_n@)|Y8+DfL5?ZhRTA6#J=U3zagMmCn#nsVH8OfG=5c&f%_%B%0#sEp zR85;s4=U&j%aBg$G_I%TSk4>I+<8RMPsbwj1+shTpO z)j6GJo!*}}G^=^gc{gh&N!3sC(3t``fvjp6sYTU*wD%U&G`@$uCD5k-3e|6AG}ZB5 zS<+1%b4SVs7D zL&B>Fuv9+9S0uMM#rq(b@E6HlE)jsG^E-QQr08lUef!tyV#Y9OeUjJK#%FV;N~8Dm zJdIATx?1s6I-b8BRkNv#7ELJ%g$crRV1eC9JHaJYTS=PgT{DeStpx-J{=Oby;4YBm zS_#=|)~n|#+*gqQb-nC9SKzklbE>OBLg8CAjXu-gC~sODPpjT#oOA}Z(w$?8@_qR%a(SnyLG|We)f@`k7o0R8O)ak^kPH!74skAzg)~PyiC!?+!@s)dy$i|d( zm*mhJfEsU7>Va;Ie*&>i%HcjcJo;_;@XPSwt;JF}ZinMVZ&~j9{L@FDTEp>@JYmZd z6~YA-Zl`yz-8*g_St#|U?cTH{rFTU6@!4<1;g{m@)^$r9E{Vr%@z}TGPhW~ZEs3XW z@f6m)Sg(1Z)cc;@`<^Ae2R#&}*DwT9;^Q0sx6R!DKS6r3@pPG|(zVqtSJG5Ot1#SQ~oN9%8#Ve&ald|63CUDHcj{%$8$Cp}c3Gz2~j1ReR4wQFt6Gi#@mv17#`v`Nc;UA6|NV zsd%X@M~WgHgLY!vH2`)XnariKYBK4BlF6*Db;bl;)PW_zumYRh!GGn!;vB z4?!Dj+)h_@R%un!l1VsIM{%sUgVXNp_Mj>XJSm0(0wz)WDN94eSz8*~Qmns8TGGcQ z>0?{^czw1a_`G{6q%Oij4)Y!)sjgW>*0on**=Rw>b!p;=z4) zDeRWc^}xt2z2w(_;p(x?iAWD%PE9hdNeFY+zdt*62(9!1#XpSRgMrd79{icj%p zxWB4S5Z3|&j3|KgX4BK&pTcc=6Cp)}WsrXCYg>l+2dbHhdGSc(si8W;Jv9ZKLeqgK zfGu=HP1kQ{a*Iju@Q!C8qpwNm>rbThoJnnoFx-AHD3P zIO2*1rf*5tfT|!-NSP)z=xG@6n#dXgGYWj=dk^Lux&{!8>OfQ|Sn=pW#*C&GfTu7w zjrKMkkHsJpt4!JM8J1DgStwZ zc~POm3;^~$^G;An8A}U#iYjX|bH*89(0AiYW>$mch(WtfIAbK6sj@<`SBgXYBj@;$ z3aUT=a9B~cM2>)7pI(9t#Gerd0l@HgKPcG#F|gp?!#ncc4Y4GT+47hb7~2tho{U?A z$4lY~TRdS2C)ldAEC|vywjgJrpVkFYxZBJt(oam(sD@@=*-E|`wQSO?)oAz2^gW=U zILnUE>PPSMrr1y^fLCp`w;VCM8s!ax*|{a4+0)Qe+6e4blIw1sVcRG;6Zu&+K-+@i zEpQpG^%e%34y04Ka{21DwbM6L4ZOaJ{ITk%!D{7lV0%WRSAZP?^MvvhO*K{bRRi_3&A^#O6fJo#xrF6D+m{ApKkQO^p9BnksTQb z#P5MpoU-LpKq*A|^T|h(56?Y5S0O_1csa87%hSI-{l%H5XNogB5&&`IR7r~3Qq+>7 zJ5nF`@r@hSTd9(?U`q>@w6GHy+?X##j@gl8mUOHVgf{*pk??p)K4Qy9ib5646WedS z7~2LSIc?Z&MK?k#Qb1KP-MHQ5R1wHjIh zM1KZ)c+5INs~&(^ zIK{WgcYxYI&%g!lG?2*|W(pkc+JUNHkLFk47NaWBD!y*zHSOLgy#Vd5^)u);quDim zJj0yhua*TxcJ&!fJ`{4Qow3tmW9^P2pENm}Y@>EHlvgN5ZEPH~n7GB)I?rce#v!yvpnnUbf zDn*Xikt3FLq~eD2xdE{xerSsyTEd5&AjX+8 z5GP>kKJ&so2Qq4*0ps1T@&N6+9e&>V0MJz00Qhnp%EqN;yIN?k&o{#qY;p^<6#h1| z>~yTz;x5;zV}WmH&5yiAFFdDs9s~;fOxq3az9$zf@Q=KU1X4nQb5jq!1yAz~cbfwc zX3u@01Li^pzQo_q7Rj(?OhKYn zjJP+(K)^-F8outvtzW(Pi8XW0I)icJ6ZbDjh9fu|H$mT#p|RWW5K$X}(*+*F$S)Xa znpselwFo<-jm{Z25gDPS!`Ogdy_?qZ$fn`TJ)<9EzJP;sJerz=m%&s{(X)=vNTEYx zC|5)atofi3=}c+e6L?u;DXy#MUxi(iyR&e`vFG8yMCIWYLeAQ2~CCWh|E|W0`0^Xd2Q1Ng7`SOFy>z8-L$dkE}IB1K5mN4jA zr^61f8&m;R$EPf(a*H~}@i^V?NA2GZPT2j98%sJh;eFF!#>E{D9vCN5RbcM}nT0ss zrQE$m?!*S~?At{rjuhIU_z*)8BhK({N{R~RF$J%x21UslL@T$-$ z@L}Z@=Ks(r9Pn`Q3aN`wi2FH*b?b6~@Zky{;yz;8A91fdknv!+n&p=Eac3$7M7<0% Wjt99Zc-yFnex4hukWRr)&;J9s(VSWU literal 1364 zcmZ`(&1)M+6ra_{dS%J>I!c! z|D2kdL_iDu-_09gg#HmqK%t><`ZWm8kbw-zLiw{@%1fY!tdJefM7AQl zBhn19Sa6Ea_&F0f52+#t(zs7E+?3c%aE4Gt31lN`$VZUXaWDY%0l$fN{S4($*^jWf zAQFOZ8L?*M2p%0Y9=dd7Ae9|G&s?)vuje~ z*w|s3fmzYCyi6leblsZSXw)-0vAJ@~b$=8ZkKMM4%pxUIZ^X86P1|903-h@L+xPEo zRqQc33p$+=>?7eip%aJUJ?4psnxMCzWy{3I+3KUJ!>U=lhxIBWG+QI|iRTt| zob~hDHF3?$xOE;8-gF7B3n+Sj0BfPw>ijEJJ5jZcy3$owUa6}m>S{+#chz)jv!|tA z{CuKaZ)?{N(g*36i>>ealjojZ{Vnq})5;BG^zo;?`IUZhwUbPDlj(kPrJMYslf2eV zUh6F^_AXrPFJC&Ww^QpcL!ISZcRANzT0Z=#edVjazv(R9>@M9L%*JNq0Rq;#^X5EC zoIAMEUcCCE)QPWk<7@56+9@On0Hh1B(RpB8KAS2P06puedS=OZWkMOW!1G(l6GL;A z0R;Uy__hCq=tXh$6JT$Z8#Xbj7G9^9K^1=i?=i4JSdye3inaW&hh|#-_ZofP9$!6l Xxjnvm=u&%p4P;gNa)91vejfh;ew7%Q6y6_u{Szm(+q8C^AG;xxxKVyuTGRsqTsuF7va@3^z; zv?&tm0VIyx$Ppn?K;+P44jg*qxR&-1%?XK9Z?2kCF7Rg8cAGRHy7s=E_vYL8-n=*O z&Hmiq9~I#G=H8FG9TtSYIMcm?oxzJ$7qk7wQ>@R*7YjYY@L`E zQ|bg^!>V-N^B#!~^CArTz8A3PPf0>zNtOg0*zEc&VC5D2BG`x9zp7#>>|rBa36cq-C@-i6sHe9rREGJyc-#?BgTx0uRr5m{UEBxSM(|` zURz1l!~Azd&U=_wBQpM)o*@r&u50TJBJviRI3W(f<8i1;r6hVAYUu)t-0arPIt#5* zvY{K8Njh3!(v4y+z+zg{CTfLZ&BloJHK<Ju z9t&VY9{9=>P5PQ+tHiRQ>`@cEqbU$RyUb@~%FCUFDm9{4utoWXVqt?+yavJTGNquI z2HvJ494{RXEMu(>t;8l~cCDe&QC}QcF{cY!z0tJjm?vT30@=c*O}A;r7X(-A8m2T0 z9P2X(xeHp<4MKA=SP3mq9h=Ca;~w}hx>h69o(5;@^etZ$Ste%HmrQUSa#<((0TdGJ z*Dcj*maPia%NRkw3n9FrH4Pi=XqK%K)6h-K`=FO2liX*4Cgg;L8h##gGK&yXgPeyxx%&a>zZ9#bD0U4TgFRr3?5p(ttK&aw5Y@B$nY z4nLf&kvg7jmYb&CoW&1t1>B^w_X)jgHM9zz<$;`idECv;&COj>JAs;MY*T)GdIZj8 z!TJeKmq)$dp97~KEw&XQGWl)P4ZrhC*q!{S70$cid|Q?Vl}F3%s1V8Uxv~93`p?8! zCwcL^EjM{_FYw2NQ&Jt1I!UXQwA`fS#O?jWkTX2B^PW3A^yyyjEng?TgPx(FKUR!dned=Djn_lIf0Ohe* z^*s4hYM+S?4zz>)k?3;)$N?wqk(X&o{f{)Iob=Sr1vfqAytnA2ms;s1H@)P7qg z_2@ib2T)iCP#)0*sokgWbwv0&fE;kr&J3Ma9(~Mz^j3G@=E7{qFQ*w)p7B5CX1X;+ z7XZfkI`b7`ZulJ_(tE>e7G9P6rErt$^^~u`=rH`g-)ughYryiaJIe;rmPJv7$`H>x mLe~H9cL%RXCLQ5~e_J^(DsAC)@?F%8Pdw)n2Pe#WUi||YzWECP literal 0 HcmV?d00001 diff --git a/core/models.py b/core/models.py index 71a8362..035bc75 100644 --- a/core/models.py +++ b/core/models.py @@ -1,3 +1,62 @@ from django.db import models +from django.contrib.auth.models import User +from django.db.models.signals import post_save +from django.dispatch import receiver -# Create your models here. +class Profile(models.Model): + LOCATION_CHOICES = [ + ('Canley', 'Canley'), + ('Leamington Spa', 'Leamington Spa'), + ('On-Campus', 'On-Campus'), + ('Coventry', 'Coventry'), + ('Other', 'Other'), + ] + LOOKING_FOR_CHOICES = [ + ('Friends', 'Friends'), + ('Short-term', 'Short-term'), + ('Long-term', 'Long-term'), + ] + YEAR_CHOICES = [ + ('Year 1', 'Year 1'), + ('Year 2', 'Year 2'), + ('Year 3', 'Year 3'), + ('Year 4+', 'Year 4+'), + ('Postgraduate', 'Postgraduate'), + ] + + user = models.OneToOneField(User, on_delete=models.CASCADE, related_name='profile') + course = models.CharField(max_length=255, blank=True) + year = models.CharField(max_length=50, choices=YEAR_CHOICES, blank=True) + location = models.CharField(max_length=50, choices=LOCATION_CHOICES, blank=True) + looking_for = models.CharField(max_length=50, choices=LOOKING_FOR_CHOICES, blank=True) + bio = models.TextField(max_length=500, blank=True) + is_subscribed = models.BooleanField(default=False) + last_online = models.DateTimeField(auto_now=True) + + def __str__(self): + return f"{self.user.username}'s profile" + + @property + def primary_photo(self): + primary = self.photos.filter(is_primary=True).first() + if primary: + return primary + return self.photos.first() + +class Photo(models.Model): + profile = models.ForeignKey(Profile, on_delete=models.CASCADE, related_name='photos') + image = models.ImageField(upload_to='profile_photos/') + is_primary = models.BooleanField(default=False) + uploaded_at = models.DateTimeField(auto_now_add=True) + + def __str__(self): + return f"Photo for {self.profile.user.username}" + +@receiver(post_save, sender=User) +def create_user_profile(sender, instance, created, **kwargs): + if created: + Profile.objects.create(user=instance) + +@receiver(post_save, sender=User) +def save_user_profile(sender, instance, **kwargs): + instance.profile.save() \ No newline at end of file diff --git a/core/templates/base.html b/core/templates/base.html index 1e7e5fb..140d13b 100644 --- a/core/templates/base.html +++ b/core/templates/base.html @@ -1,25 +1,131 @@ - - - {% block title %}Knowledge Base{% endblock %} - {% if project_description %} - - - - {% endif %} - {% if project_image_url %} - - - {% endif %} - {% load static %} - - {% block head %}{% endblock %} + + + {% block title %}Warwick Connect{% endblock %} + + + + + + + + + + {% load static %} + + {% block head %}{% endblock %} - - {% block content %}{% endblock %} - + - +
+ {% if messages %} + {% for message in messages %} + + {% endfor %} + {% endif %} + + {% block content %}{% endblock %} +
+ + + {% block extra_js %}{% endblock %} + + \ No newline at end of file diff --git a/core/templates/core/dashboard.html b/core/templates/core/dashboard.html new file mode 100644 index 0000000..24f833b --- /dev/null +++ b/core/templates/core/dashboard.html @@ -0,0 +1,211 @@ +{% extends "base.html" %} + +{% block title %}Discover Students | Warwick Connect{% endblock %} + +{% block extra_css %} + +{% endblock %} + +{% block content %} +
+

Who's Online

+

Find fellow students at Warwick university.

+
+ +
+ {% for profile in visible_profiles %} +
+
+ {% if profile.primary_photo %} + {{ profile.user.username }} + {% else %} +
{{ profile.user.username|slice:":1"|upper }}
+ {% endif %} +
+
+
+
{{ profile.user.first_name|default:profile.user.username }}
+
{{ profile.course|default:"Student" }} · {{ profile.year }}
+
+ {{ profile.location }} + Looking for: {{ profile.looking_for }} +
+
+
+ {% empty %} +
+

No students found yet. Be the first to join!

+
+ {% endfor %} + + {% for profile in locked_profiles %} +
+
+
{{ profile.user.username|slice:":1"|upper }}
+
+
+
+
Unlock Full Grid
+
£3.99/mo
+ +

See all students online

+
+
+
+
Student Name
+
Course · Year
+
+
+ {% endfor %} +
+ +{% if not is_subscribed and locked_profiles %} +
+

Ready to see everyone?

+

Join other subscribers and unlock the full discovery grid, messaging, and more.

+ +
+{% endif %} +{% endblock %} diff --git a/core/templates/core/index.html b/core/templates/core/index.html index faec813..a7bc3d4 100644 --- a/core/templates/core/index.html +++ b/core/templates/core/index.html @@ -1,145 +1,128 @@ {% extends "base.html" %} -{% block title %}{{ project_name }}{% endblock %} +{% block title %}Connect with Warwick Students | Warwick Connect{% endblock %} -{% block head %} - - - +{% block extra_css %} {% endblock %} {% block content %} -
-
-

Analyzing your requirements and generating your app…

-
- Loading… +
+
+
+
+ Exclusive for @warwick.ac.uk students +

Discover your next connection at Warwick.

+

The only dating and networking platform dedicated exclusively to University of Warwick students. Find friends, study buddies, or something more.

+ +
+
+ +
+
+
+
+
+
+
-

AppWizzy AI is collecting your requirements and applying the first changes.

-

This page will refresh automatically as the plan is implemented.

-

- Runtime: Django {{ django_version }} · Python {{ python_version }} - — UTC {{ current_time|date:"Y-m-d H:i:s" }} -

-
-
-
- Page updated: {{ current_time|date:"Y-m-d H:i:s" }} (UTC) -
-{% endblock %} \ No newline at end of file + + +
+
+
+
+
🎓
+

Verified Students Only

+

Every user is verified with a Warwick email address, ensuring a safe and authentic community.

+
+
+
+
+
📍
+

Nearby Connections

+

Whether you're in Leamington, Canley, or On-Campus, find students exactly where you are.

+
+
+
+
+
+

Meaningful Matches

+

Search by course, year, and what you're looking for to find the perfect match.

+
+
+
+
+{% endblock %} diff --git a/core/templates/core/login.html b/core/templates/core/login.html new file mode 100644 index 0000000..ad19391 --- /dev/null +++ b/core/templates/core/login.html @@ -0,0 +1,79 @@ +{% extends "base.html" %} + +{% block title %}Log In | Warwick Connect{% endblock %} + +{% block extra_css %} + +{% endblock %} + +{% block content %} +
+

Log In

+

Welcome back, student.

+ +
+ {% csrf_token %} + + {% for field in form %} +
+ + {{ field }} + {% if field.errors %} +
+ {{ field.errors.0 }} +
+ {% endif %} +
+ {% endfor %} + + +
+ +

+ New to Warwick Connect? Join Now +

+
+{% endblock %} diff --git a/core/templates/core/profile_edit.html b/core/templates/core/profile_edit.html new file mode 100644 index 0000000..4db566a --- /dev/null +++ b/core/templates/core/profile_edit.html @@ -0,0 +1,108 @@ +{% extends "base.html" %} + +{% block title %}Complete Your Profile | Warwick Connect{% endblock %} + +{% block extra_css %} + +{% endblock %} + +{% block content %} +
+

Complete Your Profile

+

Tell other students about yourself to find better connections.

+ +
+ {% csrf_token %} + +
+
+

Academic & Location

+
+ +
+ + {{ form.course }} +
+ +
+ + {{ form.year }} +
+ +
+ + {{ form.location }} +
+ +
+ + {{ form.looking_for }} +
+ +
+

About You

+
+ +
+ + {{ form.bio }} +
+
+ + +
+
+{% endblock %} diff --git a/core/templates/core/register.html b/core/templates/core/register.html new file mode 100644 index 0000000..5a2ce29 --- /dev/null +++ b/core/templates/core/register.html @@ -0,0 +1,82 @@ +{% extends "base.html" %} + +{% block title %}Join Warwick Connect{% endblock %} + +{% block extra_css %} + +{% endblock %} + +{% block content %} +
+

Create Account

+

Join the exclusive Warwick student network.

+ +
+ {% csrf_token %} + + {% for field in form %} +
+ + {{ field }} + {% if field.help_text %} +
{{ field.help_text }}
+ {% endif %} + {% if field.errors %} +
+ {{ field.errors.0 }} +
+ {% endif %} +
+ {% endfor %} + + +
+ +

+ Already have an account? Log In +

+
+{% endblock %} diff --git a/core/urls.py b/core/urls.py index 6299e3d..4f9e9c6 100644 --- a/core/urls.py +++ b/core/urls.py @@ -1,7 +1,11 @@ from django.urls import path - -from .views import home +from . import views urlpatterns = [ - path("", home, name="home"), -] + path('', views.home, name='home'), + path('register/', views.register, name='register'), + path('login/', views.login_view, name='login'), + path('logout/', views.logout_view, name='logout'), + path('dashboard/', views.dashboard, name='dashboard'), + path('profile/edit/', views.profile_edit, name='profile_edit'), +] \ No newline at end of file diff --git a/core/views.py b/core/views.py index c9aed12..e1e6277 100644 --- a/core/views.py +++ b/core/views.py @@ -1,25 +1,110 @@ import os -import platform - +import random from django import get_version as django_version -from django.shortcuts import render +from django.shortcuts import render, redirect, get_object_or_404 +from django.contrib.auth import login, authenticate, logout +from django.contrib.auth.forms import UserCreationForm, AuthenticationForm +from django.contrib.auth.decorators import login_required +from django.contrib import messages +from django import forms +from .models import Profile, Photo from django.utils import timezone +from django.contrib.auth.models import User +class WarwickRegistrationForm(UserCreationForm): + email = forms.EmailField(required=True, help_text="Enter your @warwick.ac.uk email address") + + def clean_email(self): + email = self.cleaned_data.get('email') + if not email.endswith("@warwick.ac.uk"): + raise forms.ValidationError("You must use a @warwick.ac.uk email address to register.") + if User.objects.filter(email=email).exists(): + raise forms.ValidationError("This email is already in use.") + return email + + def save(self, commit=True): + user = super().save(commit=False) + user.email = self.cleaned_data['email'] + if commit: + user.save() + return user + +class ProfileEditForm(forms.ModelForm): + class Meta: + model = Profile + fields = ['course', 'year', 'location', 'looking_for', 'bio'] + widgets = { + 'course': forms.TextInput(attrs={'class': 'form-control', 'placeholder': 'e.g. Computer Science'}), + 'year': forms.Select(attrs={'class': 'form-select'}), + 'location': forms.Select(attrs={'class': 'form-select'}), + 'looking_for': forms.Select(attrs={'class': 'form-select'}), + 'bio': forms.Textarea(attrs={'class': 'form-control', 'rows': 3, 'placeholder': 'Tell others a bit about yourself...'}), + } def home(request): - """Render the landing screen with loader and environment details.""" - host_name = request.get_host().lower() - agent_brand = "AppWizzy" if host_name == "appwizzy.com" else "Flatlogic" - now = timezone.now() + if request.user.is_authenticated: + return redirect('dashboard') + return render(request, "core/index.html") + +def register(request): + if request.method == 'POST': + form = WarwickRegistrationForm(request.POST) + if form.is_valid(): + user = form.save() + login(request, user) + messages.success(request, "Welcome to Warwick Connect! Please complete your profile.") + return redirect('profile_edit') + else: + form = WarwickRegistrationForm() + return render(request, 'core/register.html', {'form': form}) + +@login_required +def profile_edit(request): + profile = request.user.profile + if request.method == 'POST': + form = ProfileEditForm(request.POST, instance=profile) + if form.is_valid(): + form.save() + messages.success(request, "Profile updated successfully!") + return redirect('dashboard') + else: + form = ProfileEditForm(instance=profile) + return render(request, 'core/profile_edit.html', {'form': form, 'profile': profile}) + +@login_required +def dashboard(request): + all_profiles = Profile.objects.exclude(user=request.user) + + if not request.user.profile.is_subscribed: + profiles_list = list(all_profiles) + if len(profiles_list) > 12: + visible_profiles = random.sample(profiles_list, 12) + locked_profiles = [p for p in profiles_list if p not in visible_profiles] + else: + visible_profiles = profiles_list + locked_profiles = [] + else: + visible_profiles = all_profiles + locked_profiles = [] context = { - "project_name": "New Style", - "agent_brand": agent_brand, - "django_version": django_version(), - "python_version": platform.python_version(), - "current_time": now, - "host_name": host_name, - "project_description": os.getenv("PROJECT_DESCRIPTION", ""), - "project_image_url": os.getenv("PROJECT_IMAGE_URL", ""), + 'visible_profiles': visible_profiles, + 'locked_profiles': locked_profiles, + 'is_subscribed': request.user.profile.is_subscribed, } - return render(request, "core/index.html", context) + return render(request, 'core/dashboard.html', context) + +def login_view(request): + if request.method == 'POST': + form = AuthenticationForm(request, data=request.POST) + if form.is_valid(): + user = form.get_user() + login(request, user) + return redirect('dashboard') + else: + form = AuthenticationForm() + return render(request, 'core/login.html', {'form': form}) + +def logout_view(request): + logout(request) + return redirect('home')