From 6b2f287f0bd846539df6382ca616954cf9e78ca2 Mon Sep 17 00:00:00 2001 From: tamaraiselvan Date: Wed, 25 Jan 2023 22:29:13 +0530 Subject: [PATCH] Major update on User Profile. User profile update feature with URL encryption and User authorization. --- .../__pycache__/settings.cpython-311.pyc | Bin 4453 -> 4522 bytes Base_Master/__pycache__/urls.cpython-311.pyc | Bin 1037 -> 1127 bytes Base_Master/settings.py | 2 +- Base_Master/urls.py | 1 + .../encryption_util.cpython-311.pyc | Bin 0 -> 2155 bytes firstapp/__pycache__/forms.cpython-311.pyc | Bin 3091 -> 3674 bytes firstapp/__pycache__/views.cpython-311.pyc | Bin 1944 -> 3844 bytes firstapp/encryption_util.py | 38 +++ firstapp/forms.py | 6 +- firstapp/views.py | 48 ++- requirements.txt | 9 +- static/login_styling/assets/css/style.css | 307 +++++++++++++++++- templates/base.html | 11 - templates/edit_profile.html | 79 +++++ templates/profile.html | 13 +- 15 files changed, 476 insertions(+), 38 deletions(-) create mode 100644 firstapp/__pycache__/encryption_util.cpython-311.pyc create mode 100644 firstapp/encryption_util.py create mode 100644 templates/edit_profile.html diff --git a/Base_Master/__pycache__/settings.cpython-311.pyc b/Base_Master/__pycache__/settings.cpython-311.pyc index 1cf6a33ab37fa02572a0c1f3195e7c8fbaa46be6..0f90d63e8b4fdf88181c4b1c7c6d045ced902933 100644 GIT binary patch delta 591 zcmY+9%}*0i6vf}0DQ)d^1}IP{UxgMZg%(>>1hgVlDpka)v4OiVew=X}unQ#yWm9*o zNw-}P5+Tuq&8++99eOu%ze7}2N69PT;s$xs(Mi{+(EsQ>w5tse8v^>;<0SaS~df}x$ z?g)mcp96*)0USDjC=Ehl;l;jbnFiq1)QOXubW2Po?85w34v&<{F%De`ZIp^{^=2JOisshw#LeA?68*YY!F)oQF zUicsW3FFj9dTD{-0$BJdcVHFPuN2OQ_JekM~X*627{f-)MoKTG4`5 zu5Y_=3xPmgF(g&n5JZT}f@rtcVKHn--A(~SD2OP9pi(<$2RbRt4Z6$*+%$q1MIjMC z?mX$Dm=xt$#rZo1671rCF3B$O=ThvFrmLDjnr+HdW}w?pDUBZLMlbasL%ryu46@Y6 zBV>`I9Qvu>5XhrYlNi7ta|pxC5sWg&U}KJ3oWLaODN9ddhV?AwnDba*7Ev@y7ojqj zEH3MU^@_z+lvvw%m9U0&Y+$plV5_b^NXo;uE3(^-edS6v0`@nDEY#lJJB@kIuHri6 aZ%EElwRYp(Q$L%8Q)_&AUlscSpMC>&X>pVQ diff --git a/Base_Master/__pycache__/urls.cpython-311.pyc b/Base_Master/__pycache__/urls.cpython-311.pyc index 2ae8c495a1ca49511de5b23a44881711c028416d..2ca292da08d670b2e9a67201464727c2f330bf92 100644 GIT binary patch delta 196 zcmeC>c+R1|oR^o20SFksT}W17Vqka-;=lkml<_%Yqq;t$9uq?ng9R* delta 108 zcmaFP(aWK}oR^o20SG>A-ktn}k%8echyw#)86fAg$wqa3My_$l0b0)@jMr3 diff --git a/Base_Master/settings.py b/Base_Master/settings.py index 555c49f..bed2d45 100644 --- a/Base_Master/settings.py +++ b/Base_Master/settings.py @@ -21,7 +21,7 @@ # SECURITY WARNING: keep the secret key used in production secret! SECRET_KEY = 'django-insecure-k6k-x^q$jjp*@bs#_7yw-!&cyn4g^byvr*lseiok=h=t#!)bw4' - +ENCRYPT_KEY = b'Py6zhVP-eFxkfq0kHUN0ZmIePwwaOeQ12ZmrFAVLbI8=' # SECURITY WARNING: don't run with debug turned on in production! DEBUG = True diff --git a/Base_Master/urls.py b/Base_Master/urls.py index 30ceda4..58192b4 100644 --- a/Base_Master/urls.py +++ b/Base_Master/urls.py @@ -9,4 +9,5 @@ path('home', views.home, name="home"), path('register/', views.signup_view, name="sign_up"), path('profile/', views.profile, name="profile"), + path('update//', views.update, name="update"), ] diff --git a/firstapp/__pycache__/encryption_util.cpython-311.pyc b/firstapp/__pycache__/encryption_util.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..fad7009ab4fee0d433f3971bddd890644d83680d GIT binary patch literal 2155 zcmbVNO=ufO6rR=UXC>>$f6aE|I(2Yj5XOqzgd{YjL{@DFT1;cN1q*??-W~l#){5B? zwm~Xx=s|%TdP^?_(?gmxhxX7yu1RCW z-n@PDzNa5Tp#Y%m?|&PL-vhv3Y+yH6M>zR{3XgyaRIUg%xg^Ii*;RBUT~^O0d8>CP z-L&V6o=tDk%K;aFT)}4>drXCA_5dUW)%`U{`c)6bfa+QUQSU!&HOdk15=144SEwlH z5aWC)t1Dc0D*)6_z|-H!FLd@1@B`elS_O~k=vjBB1~Aj@H0-t|01DmtfgN0x+w0MD zc2vP0JNr~qxqb`%qnZncoGng7s;+*$J;Bj(q(R#?SCvL<8sJe!=Mq4xH6Fj=%vAY) z+Z@26vswt+vO4HPkEgZ{0C>`o3lUrHztO?-)@hE^_%CT@taYRtKs}%C8WQ ztSk9E2||Q4lrC!7EJV>^!s{3zb}@+E02x|bNvy7a@@e{`#dYF?B?ax2G4WDCQz7wg z$U3}!jf_-KQI|6?y>b1Ty`(}*#lN_%z%tHjCE_WgdHaT;zbQ8(f7HYPzOU(P|4)+>1oNx0(-RMQyJRSxRR<0;x+eV%wP z^_dQlp2G5`j8e;aoU3e1Az0S*Jl4=oYJoaFrxxT=R+}p$tpF7~w+3;goXX^pj^%PW z)v-@KPgiih7%T6fAr=<~jI;Xh6m~(&750oDhey7devo^ZtMkX=g7j_75Td3KJru4S2v>gfoAVzU z^GoLZk|8Xc!g51cZbruH*nVEp*78%6wAUs2A@}1qD zX8!6K%rA5~e?|@H;Vt&k^E$1-?#yca`CDT(pl6S*1;C)~y&h|h*8j3L?C4O|CMau1 zoSA~(mQV50s?zqV-Ji|r*XJc--x3WWRs{M;)h3g}OT^qEK03|#h*(KL!wgtaLSqcZ z8L*0k&QXZE5vxDwO$sE~HrFN&I!~v%)Ik$W>w*n$v9<3husrv(JRdj1Gkdxbo;Aa> zb^d4|*_-0@p*VXW&OS*P;=C!&ABr~)#2e3jhIrc)Z`Xs($V5Y!XeTt!65592*Un-e zHNmo&ecJu_xwr)OrNF`rzdwC*;UfRyqKC@SAu?u#O3Na-oZE?ItiQN+Kv}fgfn(t! zL+!EuG}UuJts*aKnC^V5-sow!FZ1em7%!CBr*mdM9@ImOH}H7|nB1&pmy7EhdGOHpZiuJ5Pg^SI|BD^acZ(=>Am%INQ&vuJD= zcQYGtVbzE34ae_=;Cu1ZQZE!>J$4}ot)AT#TbW38JUa-YeBZMj@!I#efGrlOb{Imi zf_`n?Ce~KV|FMEOrKS zayL6Ns;D*?RON5=9jnTlT7}hRTl-k1m`>vyT&36AzUU$jW9>JMYu*t3fFgReVx}JC?xEq3jUYI1%?!iQ?K#A1zgfd|oA-_&O-N+`LLo!1; z6M8yug@TUtO25evP1ML4&_dpi&v0sbQyrEb?j_%*MkgJUvN{d(_yW-a6NKB!GV%_o z+i%m!2$UMke-CxmJji6!)`4;whh#fC!;v<*Acr||J$do}DzUNH k_4&XPEofmGMy0+ljA6uxt8Cu-xQO=z2nG^7JkJwU~PV5sO&wGjv+B$$FwW%;gP;l$ycts*aF zU|<5ItJHtc4os+mq5KI}Jg^}#wrVFP?wuhDQv1&L>G^x_-S^#PP1&d%IL-u7Vg3B- zFWR3fN5)QC-in}q&5s5#L}5C$K8QKAHv$lGd*JoCYh;!mdO~EA!_f2j^C)B-T$)*4 z9D{hQ>h^ZPp7A&<0e_hUz*$<&Pf=s}A!$7)*85%%wmrsx3z1e7dDtm*D6Po%=2g3? zoIy(-nWv?iN?i&y`Pq6!Yx26?pbN5NzpGZUIh~O8-ynH%2zjOav6~DJOuKWhr(RI!7w;2tN-4nUxf6!2g*ii6#w2lqK zdO(lK`FNuFv(^RW+{v&J@5?XFi?sqp&GYfY&E3@# LT|2v=L(BdFwBn`F diff --git a/firstapp/__pycache__/views.cpython-311.pyc b/firstapp/__pycache__/views.cpython-311.pyc index 71155eeb044dfdf1231709696369332ccef7ab2d..121891417dd34af05bcf62937abb3dccff090701 100644 GIT binary patch literal 3844 zcmb7G-EZ606~B}yk&iuY z7gtA@_n!N8?(cWb`CCs<96|Z#4|Z-4TK^^=%@S%fUi}#wUn2!6jE)LSnkj_RA%=X1 z^l*Vqv$P%7BZX)>THw+g{bqH(5KG5sJEF%6iF5+m(Or}l6i(swo`RSb3sPEw-Wc>I zl{m;=STzB=zz%e$GwCyQ1wrro6sZZNXBRz&(>!gS5vBVTaS5fQ?@3Q8(C#^`U8*~)rG1&2G)0SunS={M(o~%g=XoiBC46+i< zQG}H6W7y+qYah5XySNowHwxe9$U%soWSyPqoVq-&7R2i-(=imzDl3Cr9Ekj-) zS0{~4qm1QjE@zaB)-;a7E~%);mcayGQZqB{wox#-GA4KOA}YoP#^lUkDvlUQH7%2z zNq)WX(bZ*QM04577P5GGUbEKAD>7C~hN)Qw-dw%`$D2~}+2WcpRl-Id9%pJvwaTUC zRSla~wp3c)(A4|pbZOIL$;EIltjxpD{1C(rs&V3O#pOoph>eUKOJ@((4j(wuq$^F@ z{NxFr+!qh-+j83B@45Uvo4ZAnlI%*d&C9P~4fH)ZEWjYXq^%V{E6o|W;0bV; zRZUkjfEX+A;>0ra#phsJ@WmD83;L#b!y+1u0+?vMbnv~lnF@2%rrDfpq5+o*t@@4`gH5+uiH>4uV+npMOBLgvp`8j9+6>O&SF(A8u#VwiVl!AWT2<4 z6)9x5ZgfFBfCw8UtickU==T>6Vt?x*R@XGs!dXi*if^}nP*!>DDj*~k_o4;WS~nEj z4|l|Gfbe)A%0^b#6puBt8>-I`&MfD0;A|*Iut=22-BTe@vCH10~{RrX&A>Cp!dKiIpzf4z<( zu{=`~l8P5(R(m%4_te(`mOTfw@zZgO)S{#0zLx=>rRl39}%R@ zB|fy;0G)4vp*zgm-Rd(YNTQ=Q*9u2z6mXod`>AW(X4cSlsKVStzqz^{wtAX+0L!ov zI^X&X&VsS<42%VJ$QSJm9ksdb))Jr{T!lgV*DT_;8imkEiBv*ACPF)1@-zsODWD(i zq@6|Z)+h=W+z$xFFOm>PoOdx>P`wZ!GNBf8c(Y_>zEC%}n(oa9bXW(plepr$eE|!k zO>Be-_dU*7A&%MfqTmuO2nbOCIk&-@37cF!IM&n}+X*S`}-UWy}6-hVb@izAMB*%dE;CtiOkUjLSL z#9OX-s~WDwg(_3)?XRP7>>L%<+2f(nqfd^kzkcovO}Rr;)!Ayn5e94hXAhLG=HW}( zo39Byk3N3*@xdoPS%5Ayl6?6*@;v)w(~+*Y(iNM(@;~DVWkV|LQ=Nd?>s?c=jBme; zfiv&D^B%kmGm&eB1W+OfCd#k=LK$O$Y?ev~+P4`EaNO>4+j&%BfE}>%X=$jV>=@VV=AG}Fca95K%5rP<^I1tDZ8)?vkA$xBBUwB zoVqo1*H0Pba!H}ls^Rxn%euZfLeWi~{Z=o@DKZVzQwDC0lDL-37K?^OaxjP%vH{5& zmI;OBhH9$E;}n&W7*E3Pl$<_SiH&Fo!WT$ufC%!Yc#sIfH=mj$`lKR0A!TTLT+S$3 z>hCQt3>fue5t&EW*`R0CzYcyEy5EMMX@l57C!AQte|WI_VCP1iM`Chk{)Z?^4F2in z5w_zKPJF_RPwad|v$F&9C3nH*E`UOE@NoW{1$*$FCpTX#+0v{d&AQTTm4ziBShb>8 zI5z$h!RwYI%(=pxEzFVNb=&D1bNj|@VXPiS1H)DBAi5`=5bD~)?>?V*q#0M5vH6)M zZ-;L={G7|r+58;I17nVK$(1hI{3XiU#nf3Z>F1);=DLBcT-h>xyAca|Vq=V$3~MWX zbngpxPLn*Dx=~DGgLk3J@N~gYRNeG_>&0#g@X7|H9|krt;Relly$DG=Oh4P8?@e+8 zA65hn-nnMRJl*ihkiBHemZsCE`#Yj{q%QY0KLbZ7>*_D?HJC}Jr?LsNFQ zT0?Kz!CFHC{Ha<)V|KIF7^xl_VBV}F5dR6IP;&R;X$S44X8JEb8)-KH delta 388 zcmZpXo59bwoR^o20SI(H?oL)=naC%>7&1}aNS&pHA&Mh~HH9sQGnXrhE0;Tpn~@=f z9Vp6^!T}_CQ#gYeG`S|8vYD*FxQelA@@d9A#+8$;m{M8!fu^x;Uc%JN#3lq}7Ku(a zXH_@h1~Hj|geFrFFNiG$B#N1Ugn~j5ACS7mU7VSoS6UEXmYG^!Bn=edoji$kE{gz= z1++tqLkY;3&QQWQIgC**Qj^KAil?9`KP@vSRWG9?H%F5ZYx%nxjIjMF<%0NXRtBYqdO#Z>^$@GC`ayp;23?rlV2L?<6 GYy<$^9aIMZ diff --git a/firstapp/encryption_util.py b/firstapp/encryption_util.py new file mode 100644 index 0000000..b767c80 --- /dev/null +++ b/firstapp/encryption_util.py @@ -0,0 +1,38 @@ +from cryptography.fernet import Fernet +import base64 +import logging +import traceback +from django.conf import settings + +#this is your "password/ENCRYPT_KEY". keep it in settings.py file +key = Fernet.generate_key() + +def encrypt(txt): + try: + # convert integer etc to string first + txt = str(txt) + # get the key from settings + cipher_suite = Fernet(settings.ENCRYPT_KEY) # key should be byte + # #input should be byte, so convert the text to byte + encrypted_text = cipher_suite.encrypt(txt.encode('ascii')) + # encode to urlsafe base64 format + encrypted_text = base64.urlsafe_b64encode(encrypted_text).decode("ascii") + return encrypted_text + except Exception as e: + # log the error if any + print(e) + logging.getLogger("error_logger").error(traceback.format_exc()) + return None + + +def decrypt(txt): + try: + # base64 decode + txt = base64.urlsafe_b64decode(txt) + cipher_suite = Fernet(settings.ENCRYPT_KEY) + decoded_text = cipher_suite.decrypt(txt).decode("ascii") + return decoded_text + except Exception as e: + # log the error + logging.getLogger("error_logger").error(traceback.format_exc()) + return None \ No newline at end of file diff --git a/firstapp/forms.py b/firstapp/forms.py index 54c9ec4..c78e357 100644 --- a/firstapp/forms.py +++ b/firstapp/forms.py @@ -22,6 +22,10 @@ def clean_email(self): return email class profile_edit(forms.ModelForm): + first_name = forms.CharField(widget=forms.TextInput(attrs={'class':'form-control', 'placeholder': 'Enter First name'}), required=True) + last_name = forms.CharField(widget=forms.TextInput(attrs={'class':'form-control', 'placeholder': 'Enter last name'}), required=True) + email = forms.EmailField(widget=forms.EmailInput(attrs={'class':'form-control', 'placeholder': 'Enter Email address'}), required=True) + username = forms.CharField(widget=forms.TextInput(attrs={'class':'form-control', 'placeholder': 'Enter username'}), required=True) class Meta: model = User - fields=['username','email','first_name','last_name', "is_superuser"] \ No newline at end of file + fields=['username','email','first_name','last_name',] \ No newline at end of file diff --git a/firstapp/views.py b/firstapp/views.py index 63f611b..e6f2442 100644 --- a/firstapp/views.py +++ b/firstapp/views.py @@ -1,7 +1,10 @@ from django.shortcuts import render, redirect from django.contrib import messages from django.contrib.auth import login, authenticate +from django.contrib.auth.models import User +from django.contrib.auth.decorators import login_required # Create your views here. + def home(request): if request.user.is_authenticated: return render(request, 'home.html') @@ -26,4 +29,47 @@ def signup_view(request): def profile(request): - return render(request, 'profile.html') \ No newline at end of file + if request.user.is_authenticated: + lst = User.objects.filter(username=request.user).values('id') + l=[] + for i in lst: + i['encrypt_key']=encrypt(i['id']) + i['id']=i['id'] + l.append(i) + return render(request, 'profile.html', {'lst':l}) + else: + messages.error(request, 'Please Provide the credentials to Login to your account.') + return redirect("login") + + +from django.shortcuts import redirect, render, get_object_or_404 +from firstapp.encryption_util import * +@login_required +def update(request,id): + id=decrypt(id) + + # dictionary for initial data with + # field names as keys + context ={} + + # fetch the object related to passed id + obj = get_object_or_404(User, id = id) + if request.user == obj: + + # pass the object as instance in form + form = profile_edit(request.POST or None, instance = obj) + + # save the data from the form and + # redirect to detail_view + if form.is_valid(): + form.save() + messages.success(request, 'Profile updated successfully!') + return redirect('profile') + + # add form dictionary to context + context["form"] = form + + return render(request, "edit_profile.html", context) + else: + messages.error(request,"You cannot access other user profile") + return redirect("profile") \ No newline at end of file diff --git a/requirements.txt b/requirements.txt index 044d355..0eb476e 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,12 +1,9 @@ asgiref==3.5.2 +cffi==1.15.1 +cryptography==39.0.0 Django==4.0.4 django-crispy-forms==1.14.0 django-jazzmin==2.5.0 -sqlparse==0.4.2 -tzdata==2022.1 -asgiref==3.5.2 -Django==4.0.4 -django-crispy-forms==1.14.0 -django-jazzmin==2.5.0 +pycparser==2.21 sqlparse==0.4.2 tzdata==2022.1 diff --git a/static/login_styling/assets/css/style.css b/static/login_styling/assets/css/style.css index 6da1e13..12f0d3f 100644 --- a/static/login_styling/assets/css/style.css +++ b/static/login_styling/assets/css/style.css @@ -1,19 +1,3 @@ -/*-----------------------------------*\ - #style.css -\*-----------------------------------*/ - -/** - * copyright 2022 codewithsadee - */ - - - - - -/*-----------------------------------*\ - #CUSTOM PROPERTY -\*-----------------------------------*/ - :root { /** @@ -1048,3 +1032,294 @@ body { } + + +.form-control { + display: block; + width: 100%; + padding: 0.375rem 0.75rem; + font-size: 1rem; + font-weight: 400; + line-height: 1.5; + color: var(--bs-body-color); + background-color: transparent; + background-clip: padding-box; + border: 1px solid #dee2e6; + -webkit-appearance: none; + -moz-appearance: none; + appearance: none; + border-radius: 0.375rem; + transition: border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out; +} +@media (prefers-reduced-motion: reduce) { + .form-control { + transition: none; + } +} +.form-control[type="file"] { + overflow: hidden; +} +.form-control[type="file"]:not(:disabled):not([readonly]) { + cursor: pointer; +} +.form-control:focus { + color: #212529; + background-color: #fff; + border-color: #86b7fe; + outline: 0; + box-shadow: 0 0 0 0.25rem rgba(13, 110, 253, 0.25); +} +.form-control::-webkit-date-and-time-value { + height: 1.5em; +} +.form-control::-webkit-datetime-edit { + display: block; + padding: 0; +} +.form-control::-moz-placeholder { + color: rgba(173, 181, 189, 0.75); + opacity: 1; +} +.form-control::placeholder { + color: rgba(173, 181, 189, 0.75); + opacity: 1; +} +.form-control:hover:not(:disabled):not([readonly])::-webkit-file-upload-button { + background-color: var(--bs-secondary-bg); +} +.form-control:hover:not(:disabled):not([readonly])::file-selector-button { + background-color: var(--bs-secondary-bg); +} + +.row { + --bs-gutter-x: 1.5rem; + --bs-gutter-y: 0; + display: flex; + flex-wrap: wrap; + margin-top: calc(-1 * var(--bs-gutter-y)); + margin-right: calc(-0.5 * var(--bs-gutter-x)); + margin-left: calc(-0.5 * var(--bs-gutter-x)); +} +.row > * { + flex-shrink: 0; + width: 100%; + max-width: 100%; + padding-right: calc(var(--bs-gutter-x) * 0.5); + padding-left: calc(var(--bs-gutter-x) * 0.5); + margin-top: var(--bs-gutter-y); +} +.col { + flex: 1 0 0%; +} + +.form-label { + margin-bottom: 0.5rem; +} +.col-form-label { + padding-top: calc(0.375rem + 1px); + padding-bottom: calc(0.375rem + 1px); + margin-bottom: 0; + font-size: inherit; + line-height: 1.5; +} +/* The alert message box */ +.alert-success { + padding: 20px; + background-color: #0abb04c9; /* green */ + color: white; + margin-bottom: 15px; + opacity: 1; + transition: opacity 0.6s; +} + +.alert-danger { + padding: 20px; + background-color: #ff0000; /* green */ + color: white; + margin-bottom: 15px; + opacity: 1; + transition: opacity 0.6s; +} + +/* The close button */ +.closebtn { + margin-left: 15px; + color: white; + font-weight: bold; + float: right; + font-size: 22px; + line-height: 20px; + cursor: pointer; + transition: 0.3s; +} + +/* When moving the mouse over the close button */ +.closebtn:hover { + color: black; +} + +.btn { + --bs-btn-padding-x: 0.75rem; + --bs-btn-padding-y: 0.375rem; + --bs-btn-font-family: ; + --bs-btn-font-size: 1rem; + --bs-btn-font-weight: 400; + --bs-btn-line-height: 1.5; + --bs-btn-color: #212529; + --bs-btn-bg: transparent; + --bs-btn-border-width: var(--bs-border-width); + --bs-btn-border-color: transparent; + --bs-btn-border-radius: 0.375rem; + --bs-btn-hover-border-color: transparent; + --bs-btn-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.15), + 0 1px 1px rgba(0, 0, 0, 0.075); + --bs-btn-disabled-opacity: 0.65; + --bs-btn-focus-box-shadow: 0 0 0 0.25rem + rgba(var(--bs-btn-focus-shadow-rgb), 0.5); + display: inline-block; + padding: var(--bs-btn-padding-y) var(--bs-btn-padding-x); + font-family: var(--bs-btn-font-family); + font-size: var(--bs-btn-font-size); + font-weight: var(--bs-btn-font-weight); + line-height: var(--bs-btn-line-height); + color: var(--bs-btn-color); + text-align: center; + text-decoration: none; + vertical-align: middle; + cursor: pointer; + -webkit-user-select: none; + -moz-user-select: none; + user-select: none; + border: var(--bs-btn-border-width) solid var(--bs-btn-border-color); + border-radius: var(--bs-btn-border-radius); + background-color: var(--bs-btn-bg); + transition: color 0.15s ease-in-out, background-color 0.15s ease-in-out, + border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out; +} +@media (prefers-reduced-motion: reduce) { + .btn { + transition: none; + } +} +.btn:hover { + color: var(--bs-btn-hover-color); + background-color: var(--bs-btn-hover-bg); + border-color: var(--bs-btn-hover-border-color); +} +.btn-check + .btn:hover { + color: var(--bs-btn-color); + background-color: var(--bs-btn-bg); + border-color: var(--bs-btn-border-color); +} +.btn:focus-visible { + color: var(--bs-btn-hover-color); + background-color: var(--bs-btn-hover-bg); + border-color: var(--bs-btn-hover-border-color); + outline: 0; + box-shadow: var(--bs-btn-focus-box-shadow); +} +.btn-check:focus-visible + .btn { + border-color: var(--bs-btn-hover-border-color); + outline: 0; + box-shadow: var(--bs-btn-focus-box-shadow); +} +.btn-check:checked + .btn, +.btn.active, +.btn.show, +.btn:first-child:active, +:not(.btn-check) + .btn:active { + color: var(--bs-btn-active-color); + background-color: var(--bs-btn-active-bg); + border-color: var(--bs-btn-active-border-color); +} +.btn-check:checked + .btn:focus-visible, +.btn.active:focus-visible, +.btn.show:focus-visible, +.btn:first-child:active:focus-visible, +:not(.btn-check) + .btn:active:focus-visible { + box-shadow: var(--bs-btn-focus-box-shadow); +} +.btn.disabled, +.btn:disabled, +fieldset:disabled .btn { + color: var(--bs-btn-disabled-color); + pointer-events: none; + background-color: var(--bs-btn-disabled-bg); + border-color: var(--bs-btn-disabled-border-color); + opacity: var(--bs-btn-disabled-opacity); +} +.btn-outline-primary { + --bs-btn-color: #0d6efd; + --bs-btn-border-color: #0d6efd; + --bs-btn-hover-color: #fff; + --bs-btn-hover-bg: #0d6efd; + --bs-btn-hover-border-color: #0d6efd; + --bs-btn-focus-shadow-rgb: 13, 110, 253; + --bs-btn-active-color: #fff; + --bs-btn-active-bg: #0d6efd; + --bs-btn-active-border-color: #0d6efd; + --bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125); + --bs-btn-disabled-color: #0d6efd; + --bs-btn-disabled-bg: transparent; + --bs-btn-disabled-border-color: #0d6efd; + --bs-gradient: none; +} +.btn-outline-danger { + --bs-btn-color: #dc3545; + --bs-btn-border-color: #dc3545; + --bs-btn-hover-color: #fff; + --bs-btn-hover-bg: #dc3545; + --bs-btn-hover-border-color: #dc3545; + --bs-btn-focus-shadow-rgb: 220, 53, 69; + --bs-btn-active-color: #fff; + --bs-btn-active-bg: #dc3545; + --bs-btn-active-border-color: #dc3545; + --bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125); + --bs-btn-disabled-color: #dc3545; + --bs-btn-disabled-bg: transparent; + --bs-btn-disabled-border-color: #dc3545; + --bs-gradient: none; +} +.btn-outline-success { + --bs-btn-color: #038045; + --bs-btn-border-color: #198754; + --bs-btn-hover-color: #fff; + --bs-btn-hover-bg: #198754; + --bs-btn-hover-border-color: #198754; + --bs-btn-focus-shadow-rgb: 25, 135, 84; + --bs-btn-active-color: #fff; + --bs-btn-active-bg: #198754; + --bs-btn-active-border-color: #198754; + --bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125); + --bs-btn-disabled-color: #198754; + --bs-btn-disabled-bg: transparent; + --bs-btn-disabled-border-color: #198754; + --bs-gradient: none; +} +.btn-outline-info { + --bs-btn-color: #0dcaf0; + --bs-btn-border-color: #0dcaf0; + --bs-btn-hover-color: #000; + --bs-btn-hover-bg: #0dcaf0; + --bs-btn-hover-border-color: #0dcaf0; + --bs-btn-focus-shadow-rgb: 13, 202, 240; + --bs-btn-active-color: #000; + --bs-btn-active-bg: #0dcaf0; + --bs-btn-active-border-color: #0dcaf0; + --bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125); + --bs-btn-disabled-color: #0dcaf0; + --bs-btn-disabled-bg: transparent; + --bs-btn-disabled-border-color: #0dcaf0; + --bs-gradient: none; +} +.d-grid { + display: grid !important; +} +.gap-3 { + gap: 1rem !important; +} +@media (min-width: 576px) { + .d-md-block { + display: block !important; + } +} \ No newline at end of file diff --git a/templates/base.html b/templates/base.html index 1ac670d..b126e1c 100644 --- a/templates/base.html +++ b/templates/base.html @@ -34,7 +34,6 @@ -
diff --git a/templates/edit_profile.html b/templates/edit_profile.html new file mode 100644 index 0000000..6a47826 --- /dev/null +++ b/templates/edit_profile.html @@ -0,0 +1,79 @@ +{% extends 'base.html' %} +{% block pagetitle %}Profile{% endblock %} +{% load static %} +{% block content %} +
+
+

Update Profile

+
+
+
+ {% csrf_token %} +
+ +
+ {{user.get_full_name}} +
+ +
+
+
+ + {{form.first_name}} +
+
+ + {{form.last_name}} +
+
+

+ +

+ {% if user.is_superuser %} +

+ + {% elif user.is_staff %} + + {% else %} + + {% endif %} +

+
+ +
+ +
    + + +
+ +
+
+ + + +
+
+
+
+
+
+{% endblock %} \ No newline at end of file diff --git a/templates/profile.html b/templates/profile.html index f630c2b..c94138e 100644 --- a/templates/profile.html +++ b/templates/profile.html @@ -5,6 +5,14 @@

Profile Section

+ {% if messages %} + {% for message in messages %} +
+ × + {{message}} +
+ {% endfor %} + {% endif %}
@@ -17,8 +25,9 @@

Profile Section