From 1386b414c2cf363ea7c2620da729b9e6c3be8f36 Mon Sep 17 00:00:00 2001 From: RohanSaeed Date: Mon, 30 Oct 2023 11:59:16 +0500 Subject: [PATCH 1/3] library management system created --- .gitignore | 9 +- db.sqlite3 | Bin 0 -> 184320 bytes file.csv | 6 + library/__pycache__/settings.cpython-311.pyc | Bin 0 -> 3478 bytes library/__pycache__/urls.cpython-311.pyc | Bin 0 -> 1261 bytes library/__pycache__/wsgi.cpython-311.pyc | Bin 0 -> 695 bytes library/settings.py | 37 +++- library/urls.py | 4 +- .../__pycache__/admin.cpython-311.pyc | Bin 0 -> 794 bytes .../__pycache__/apps.cpython-311.pyc | Bin 0 -> 578 bytes .../__pycache__/models.cpython-311.pyc | Bin 0 -> 4145 bytes .../__pycache__/serializers.cpython-311.pyc | Bin 0 -> 2152 bytes .../__pycache__/urls.cpython-311.pyc | Bin 0 -> 1883 bytes .../__pycache__/views.cpython-311.pyc | Bin 0 -> 10281 bytes library_management/admin.py | 10 ++ library_management/apps.py | 6 + library_management/cron.py | 18 ++ library_management/forms.py | 22 +++ .../commands/import_books_from_csv.py | 41 +++++ library_management/migrations/0001_initial.py | 69 ++++++++ .../migrations}/__init__.py | 0 .../__pycache__/0001_initial.cpython-311.pyc | Bin 0 -> 4084 bytes .../__pycache__/__init__.cpython-311.pyc | Bin 0 -> 195 bytes library_management/models.py | 60 +++++++ library_management/permissions.py | 26 +++ library_management/serializers.py | 26 +++ library_management/tests.py | 3 + library_management/urls.py | 17 ++ library_management/views.py | 164 ++++++++++++++++++ templates/base.html | 43 +++++ templates/book_request.html | 14 ++ templates/book_return.html | 18 ++ templates/book_search_results.html | 20 +++ templates/data.html | 5 + templates/librarian_dashboard.html | 14 ++ templates/login.html | 16 ++ templates/max_requests.html | 1 + templates/my_books.html | 33 ++++ templates/new_ticket.html | 7 + templates/profile.html | 7 + templates/signup.html | 38 ++++ users/__pycache__/admin.cpython-311.pyc | Bin 0 -> 374 bytes users/__pycache__/apps.cpython-311.pyc | Bin 0 -> 540 bytes users/__pycache__/forms.cpython-311.pyc | Bin 0 -> 2393 bytes users/__pycache__/models.cpython-311.pyc | Bin 0 -> 1173 bytes users/__pycache__/urls.cpython-311.pyc | Bin 0 -> 981 bytes users/__pycache__/views.cpython-311.pyc | Bin 0 -> 4116 bytes users/admin.py | 5 + users/apps.py | 6 + users/forms.py | 32 ++++ users/migrations/0001_initial.py | 48 +++++ users/migrations/__init__.py | 0 .../__pycache__/0001_initial.cpython-311.pyc | Bin 0 -> 4112 bytes .../__pycache__/__init__.cpython-311.pyc | Bin 0 -> 182 bytes users/models.py | 13 ++ users/tests.py | 3 + users/urls.py | 9 + users/views.py | 58 +++++++ 58 files changed, 904 insertions(+), 4 deletions(-) create mode 100644 db.sqlite3 create mode 100644 file.csv create mode 100644 library/__pycache__/settings.cpython-311.pyc create mode 100644 library/__pycache__/urls.cpython-311.pyc create mode 100644 library/__pycache__/wsgi.cpython-311.pyc create mode 100644 library_management/__pycache__/admin.cpython-311.pyc create mode 100644 library_management/__pycache__/apps.cpython-311.pyc create mode 100644 library_management/__pycache__/models.cpython-311.pyc create mode 100644 library_management/__pycache__/serializers.cpython-311.pyc create mode 100644 library_management/__pycache__/urls.cpython-311.pyc create mode 100644 library_management/__pycache__/views.cpython-311.pyc create mode 100644 library_management/admin.py create mode 100644 library_management/apps.py create mode 100644 library_management/cron.py create mode 100644 library_management/forms.py create mode 100644 library_management/managment/commands/import_books_from_csv.py create mode 100644 library_management/migrations/0001_initial.py rename {library => library_management/migrations}/__init__.py (100%) create mode 100644 library_management/migrations/__pycache__/0001_initial.cpython-311.pyc create mode 100644 library_management/migrations/__pycache__/__init__.cpython-311.pyc create mode 100644 library_management/models.py create mode 100644 library_management/permissions.py create mode 100644 library_management/serializers.py create mode 100644 library_management/tests.py create mode 100644 library_management/urls.py create mode 100644 library_management/views.py create mode 100644 templates/base.html create mode 100644 templates/book_request.html create mode 100644 templates/book_return.html create mode 100644 templates/book_search_results.html create mode 100644 templates/data.html create mode 100644 templates/librarian_dashboard.html create mode 100644 templates/login.html create mode 100644 templates/max_requests.html create mode 100644 templates/my_books.html create mode 100644 templates/new_ticket.html create mode 100644 templates/profile.html create mode 100644 templates/signup.html create mode 100644 users/__pycache__/admin.cpython-311.pyc create mode 100644 users/__pycache__/apps.cpython-311.pyc create mode 100644 users/__pycache__/forms.cpython-311.pyc create mode 100644 users/__pycache__/models.cpython-311.pyc create mode 100644 users/__pycache__/urls.cpython-311.pyc create mode 100644 users/__pycache__/views.cpython-311.pyc create mode 100644 users/admin.py create mode 100644 users/apps.py create mode 100644 users/forms.py create mode 100644 users/migrations/0001_initial.py create mode 100644 users/migrations/__init__.py create mode 100644 users/migrations/__pycache__/0001_initial.cpython-311.pyc create mode 100644 users/migrations/__pycache__/__init__.cpython-311.pyc create mode 100644 users/models.py create mode 100644 users/tests.py create mode 100644 users/urls.py create mode 100644 users/views.py diff --git a/.gitignore b/.gitignore index a979ee7..49f1a84 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,8 @@ -/venv \ No newline at end of file +*.log +*.pot +*.pyc +__pycache__ +db.sqlite3 +media +venv/ +.env diff --git a/db.sqlite3 b/db.sqlite3 new file mode 100644 index 0000000000000000000000000000000000000000..708bb54cc954912a15e20a4e5ccc4d9a97901f5f GIT binary patch literal 184320 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 V1V8`;K;XqDaMm&B>AnB|{{gB{Mppm; literal 0 HcmV?d00001 diff --git a/file.csv b/file.csv new file mode 100644 index 0000000..a7f1128 --- /dev/null +++ b/file.csv @@ -0,0 +1,6 @@ +title,author,publisher,available_quantity +Book 1,Author 1,Publisher A,10 +Book 2,Author 2,Publisher B,15 +Book 3,Author 3,Publisher A,8 +Book 4,Author 4,Publisher C,20 +Book 5,Author 5,Publisher B,12 diff --git a/library/__pycache__/settings.cpython-311.pyc b/library/__pycache__/settings.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..0ea90e8d9452ab2c15dfcd36b206508733ddf4c4 GIT binary patch literal 3478 zcmb6b&2QV*{ZZedMOl^=MR5{GuJd7MG3B;N+YPA~S)v^+vgAo}yb%QmTJKq=Es_dJ zIWtchkVCf>Sb!eZLk~d@8HWBdc443fPX>0{O+a_*W&1r!vSm5IGJZV1_xt{QkALSl z7QyxPf0oE!#u54_T@0>3fAZ768HE0ZFcJ}Fu&2q041B#!kLne@Ob_N0eI7)7yZ!<5 zTbO)5SRgSljC&J2LkvwWa)4Z)7y_9A?0*aTzlXPXiD4WNSsWC{Tx@6r8*!oG5hw>x zFNt1+z5$OfUl;AzjSVQyXW|5A#W+|n*+62Vf$-ROjCcjU5%?xCCtk%-Jln(WGI4#cL8Sw-B0Z5&tvBI9DbFAkHD~-BB5hQKiZeL`SkG3go8?O0UhcIRr2Z_Nkog}z`_ z!MI6Y%8&y$LW*_3S81qVvUY~EACB75x11m1ul8U=T=SQeKqacW#^>D6{~$GuZ9WIX zbA`MdBK>s478&9`Y)2N>5Co;}Hp&p=s1t)I4>PazB0t3S$vd2AD)qfxC{1Wq{&y=h z%;gsCN^^)W($5RuHkziL=}WPQ+G@g1a9-?vMBd#LYJIfnga?$6VYi6>U`f!kPbg z9!m2?Q?ba$HVeT1eBR>(gwkrEBsjiOc1ib9%r-eZRs z(~If*^tKl+??yb`bzpbVuw)RcZD{a;lMmC)3)#VpO0Xhl9KZXWpL2qe1V@-8IUe0~ zf-N{Js7x>9%?T21Ujb>3SJ3tyFRYx9L1Zk^8P_`i`o(4VC`13;ST9#<13VlSQmt4u z=jphO`_qB|;R48p#tH}{DXXu*yM8);}c3*=Co4qFv+6`>|Q6Mpab^TP7Rs>5ZA z#qy?*caNp26D^dgH2?tsD!S^hYlVEiC~Rgcf)lBf%Qb1EQp}Z0D^9p3tgRQbHKFRn zHmj=zN?$DGvb6Y}a6VhhQnghlmEEX4l?I2I^gLTE0J01{Gwx#OxhJia^Fq<#irLcY zMs`(@aTu!1&q_|fbzKBkYM?4d&2i#+VI{j!tVtlSEUgrTV%`bm zD&^8|%F9(Jye8xeS(ng96XE!FbwvZuTrlCQr;g z_}j?zD`MgNd>Vkxeh&E7!Ox+`P+aXMSu&PDApNB^SvcvtUWQ@19+vTS5gk&9VLM@Z zpP)k>@_P0#dG9DbcO0MVjGrX0y{;clWsZ`I$H~P*G}#TINbJjp zuS0)Y`fBONv6&ynW{$>YkLh#&c< z@9s33yww@+vS=dJ;Z7qHo$%?{cqeoUUIw}m6uk;wuqgTH5XHfFe~tn6hz9}^>W6&% sVxSW=x{%39pyra0R&M;O&A)!}=P$mQd$W4PJvinbbXa;DkD(_13+#$ef&c&j literal 0 HcmV?d00001 diff --git a/library/__pycache__/urls.cpython-311.pyc b/library/__pycache__/urls.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..a78759719665940d1e23b8fa7bdfacf91a6ce432 GIT binary patch literal 1261 zcmb7Dzi-n(6h1qbA9Yo#b|A1Fs*qzTwMAQ&sDKcqq7v!=bjgxl?Mvcd`>Z<$Xa>}g z31z4Re*h{%{4OIT zw@T(*egfwM@=z0bnx_X^s5f;@`Guem;wBD@&7y{M#IT2%-YewjlI=?Hy=duA!J z2y4+RooTQG_so8SE2p^1-*BBmv*Im0N0vd~LK5TP*;C^3sO@+9f+jwXNSg~1_(y_@ zV-gGAV{T#_#)~c^hkX&mG)b6<;gr|1tWe0Y~hSI z4j7e;NX8ll0qZ77EE|sFaaY=2k47Dyr*nDeu*li6H=KmWzAGICb|AfUjK^aX6{rH{Duh>|*lx`< z>sei09CdB&ik{MHim!{I39&%HH);fRyJnsnjMF&8lH>Hu=TVl|E%^X z;2j4Vm}fFoAmueJ%lNJ)+0rIO>VCg*2ia7P2TwxA(1uNx9X6(Q36O*RpD$35kHghHn>57UxP77$Tym!dUtVn_yM= zWN~g7zMxCkMpxU;fzsdz-ldVGjCsxulP_UPolMI5PbqmQ9b7v;zN&18-0KJIzE}n_ z^(D*quuKb@rcL!_4Ns9;2-0qyBQk$opxfuayQU>nTsYZzcVl?>v~l`igxAJ+?E+UI zR2`Z_^J9IqYK~XU5w4AKZMJcJSRGc+Z*GiMHpeTQBfK@nThlUL)=w7IPb`6?9}p9E Aga7~l literal 0 HcmV?d00001 diff --git a/library/__pycache__/wsgi.cpython-311.pyc b/library/__pycache__/wsgi.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..1e5f647cf586504491f3eaf3d668ecac3a88cec9 GIT binary patch literal 695 zcmY*XOG_L<5U!q4HyPt1A$kim;zh{LB$88*K%z!A4?V1su$S3(x^{LpJ>A1}tI?B( zKz>55IT?a~W(|Tcr-htyTkz&7J^O%7^|PwGzVEB1e=aO|VD0g{8h#@He@bU!Gvm!| z$8Np@hbC~s9YLDJuC8!Wx9Ji<(w*FdAG4F>>6Op$*$W5Y(vFc4Z~)y4>s(Gk(46B= z1J>rwZoH3;ojQ$_Y$q{otDK7DFlYHG&2rVn$oQUDHx$2QN~5NxgLIU@gkXmPDbtkE zRPiH$HG#({=rPNa;gMu1a@uOKEE7q@Orm6~W%1rvmQ>|P6KM(4;Q>|Bf+w1`6M;{t zM)W$yWco!Aa208vcbSaUL{p^F0A=vpUk^I!#HfH{Ce&$)(gY_uP6F?5S?cZ@DIUdW z!ZH?4$tae$-oD!1*$W%n`}_6XoksX!Z|mUw_SxdNdS9b4iH!AHrKp6Vl@Nx7qja%2 z65>ZzzhA=Ut|cleD36m|$-=XV9NX+jm|}j4@fX~ditaXo1C6;3a@Ao{GejP2q5f=C z7L2KDDU&S5VJ+j(uqHn{y}P$Ddg+&W)q>eS1p1Sm1}-6F;8e)W0Ltkh5bykc+4}IT v_kZt$^VPe7rQfjBTlRZTUthuIHEi}^vtM25RadU6tJl@l^ZByn4=ngUcM{BC literal 0 HcmV?d00001 diff --git a/library/settings.py b/library/settings.py index 51069ea..bf9b89b 100644 --- a/library/settings.py +++ b/library/settings.py @@ -10,7 +10,21 @@ https://docs.djangoproject.com/en/4.2/ref/settings/ """ +import os from pathlib import Path +import environ + +env = environ.Env() +environ.Env.read_env() + +# Previous settings ... +EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend' +EMAIL_HOST = env('EMAIL_HOST') +EMAIL_PORT = 587 +EMAIL_USE_TLS = True +EMAIL_HOST_USER = env('EMAIL_HOST_USER') +EMAIL_HOST_PASSWORD = env('EMAIL_HOST_PASSWORD') + # Build paths inside the project like this: BASE_DIR / 'subdir'. BASE_DIR = Path(__file__).resolve().parent.parent @@ -37,6 +51,10 @@ 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', + 'users', + 'library_management', + 'rest_framework', + 'django_crontab', ] MIDDLEWARE = [ @@ -54,7 +72,7 @@ TEMPLATES = [ { 'BACKEND': 'django.template.backends.django.DjangoTemplates', - 'DIRS': [], + 'DIRS': ['templates'], 'APP_DIRS': True, 'OPTIONS': { 'context_processors': [ @@ -80,7 +98,6 @@ } } - # Password validation # https://docs.djangoproject.com/en/4.2/ref/settings/#auth-password-validators @@ -99,6 +116,7 @@ }, ] +AUTH_USER_MODEL = 'users.User' # Internationalization # https://docs.djangoproject.com/en/4.2/topics/i18n/ @@ -121,3 +139,18 @@ # https://docs.djangoproject.com/en/4.2/ref/settings/#default-auto-field DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField' + +CRONJOBS = [ + ('0 0 * * *', 'library_management.cron.send_return_reminders') +] + +EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend' +EMAIL_HOST = '' +EMAIL_PORT = 587 +EMAIL_USE_TLS = True +EMAIL_HOST_USER = '' +EMAIL_HOST_PASSWORD = '' + + +MEDIA_URL = '/media/' +MEDIA_ROOT = os.path.join(BASE_DIR, 'media') diff --git a/library/urls.py b/library/urls.py index 89c46af..a19fbd7 100644 --- a/library/urls.py +++ b/library/urls.py @@ -15,8 +15,10 @@ 2. Add a URL to urlpatterns: path('blog/', include('blog.urls')) """ from django.contrib import admin -from django.urls import path +from django.urls import path, include urlpatterns = [ path('admin/', admin.site.urls), + path('user/', include('users.urls')), + path('lib/', include('library_management.urls')) ] diff --git a/library_management/__pycache__/admin.cpython-311.pyc b/library_management/__pycache__/admin.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..95405e2abd7c90881ede1ff31711f2bb7f545297 GIT binary patch literal 794 zcmbVJJ5R$f5I&PfOHo0HsY_e2Wq?Y|2qe^jhhX5bWPyNBB{WXJPKDU{0c@;HAjA*g zZzL!Z$P*G%w@PfCuz{e!gnBxk@B6Ip?DO4Ks})doFu9Bl0eI6OH{&~bUr;C4K!K6~ z7;y;!I!29Pj2W)MOxI+VYcbokS;;LCKyp&fOWcg-S#d|>R#kjZ>&yP7F-Oo?BWUaq zG^M{9YVLqz^>up=k(Ni9ANF;>jwQ{NDC){_9oK~Dp`6g^HlFoR#Io`Q;vNrWbqmim z-1U#T7;iZhIZ02vuoKN6MPbbSL#{_8Z5B}s1h*96whkp7^bolIe`yLoMp@?A@kNaM z9^MrT!`0TFKrUK5I`%^0A<|YGMK_L4TY;+W@rya;gTN4|gJxqZvL$|KSX<;J|u!3Y=_hyu?=hD;?x zp)%)ClC5*A7m#4kAuchQ!`vvNy5FWZ#5FyQ_B6+%%nr3<%RGuB@6=*8O=@VbDn z+>kIv^%e_nBhT0Ks?G1J%cmb7(TVSenm-7{cvGct5H`3PuGX}%KT+z_^3Jd&R#08W zc2zkk=gkYEKny;kstA+@Zg8|H9%LOJ2AkXz^A69rn#l;EDeO&t@7bD!c4zQcJy{>( K_46NBTI>r@+L%iK literal 0 HcmV?d00001 diff --git a/library_management/__pycache__/models.cpython-311.pyc b/library_management/__pycache__/models.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..b30d9689fbe705ed257d074348f2a1cb44a01e51 GIT binary patch literal 4145 zcmcha&2JmW6~K4N<;QYKks%oiuq8)T+z5=UueMTZS9PPvVx&5zQ;W`lhb&f_iA0)Q zDzi%`atoA)9)zMOco5(ML4h0sSAuoWAq8^iA%DUW*aNZXAwW(JdY~Yka%tb2B}I{@ zWv2x?Kd;4}~=l9+W{}zda1Sns4entNk5QJ~B(JsDL<@ldac_a{lh()0!=0p+e zo}#DZ&3Q$^BfKjR?;ivrQL!MkZ+`3*geP#hCFkQ-KCtqiW98>o0k8_5V-?_5GFXMq zu?li41+2p7Sji-^Dx?OU;xJR9<1dv7EgDdh?irM=w}#JuPG84Ap!rCkLQW(?&f^iN zw=-=b9(W#$Fm<@xf>VEi1x)(|7BFS72)2C^FOi6J;OlwGGPmLjik8HG5a=0;LV_?| z*^%BUm+wC%V6-nfp_2BgTBQ1hx%tq)1`1;;oANqxWvf`$h-#J{Nv{-(j&H4~>Gzq( zy(>WIM_Q$5W>R4%sH(bFqN?hIR25!frHJ*gs(xJ2imrws3y!?Fsj+mP776%-I~>1O zF*nQ1k+&*q#k{denG;$mX&clv^5wDaB;PL^c{BfjuIMJ+pe+wU@UEMAb9-Mn2Is=} zD^s{=#uO`WYPz9ON~Ug7FP=&JiL>(!^3;QL-XsOS>fe+c-amwSC<;mH+LS`(Kiogtmte#I%`K~ ztIPOdm)fK00)2;2e0NMU+T@ug{SY-xb5CP{3C%>na2-HEEim`%EgvqVUUN zC|*Iq*$bu1jOI7=TXdV@gq^_R!s_C}%_T>w05*KJ9SQk&i#PzjfJ0cj+!i=gzCZu;Zik_!T>TrFyH;+m4PRQlopbR&=Hwow1`c)#XNV ztd_QuV~0K~Iag24*~z);ZTz^y#1VFJcAEIU0ZoT9BIdlXVp5^47pNavu#30_5@9!M zkdeEr<#Vk=+*)aSBi;k4hZiJDDs+ef(s{~*)jqTHAXQQUf#3yFr}rS(GqMBkjnnET$8#|gYob&}UN*d(}sc5q>9i09qcs_ zS=d9uklf0uUj9VY2zi=B6?)kBG8ulH!1`u6zfKJ{0IigVh0y>fynecQKm*yu>-gs& z9tpn_3h?We!l~V7us4I|G_DJH2QQxqfAzwwJeh}~5$4Xx7)eR&bGn1`ObY$R+t3o4wVK)UFTG6-RdnkP=e>vdR zt>D`nu1qT46PwP3yGy^hx3rp7SF;P*d#mc=@|~5%rBxoY>__022P+%J8a~TS%{X2s zf?=A?ms+73Zq1K}CyS$n-!L_^VmNY^ermdb8e@E|@{lzc)r_*vuA$eSFujU>C@#Qd z{2fFmOq(9*vfq*}HbVlW@*fzmiLu(8oftdJT8ZoR#C1Dyz4~5z?`R}mwO*V3YP;zb z2YxLc2`Epvtfs#i9IHLB2gmlvS4nH|Mt$&xJ$S>Cl1)kUEr?B_zjPxS=dljgX^~pB z<3B^C6VVVUXO1%e&z*yKApXJxNtK+COBrTb9!mYg0SV|1hgJ}r2?|7iAJF%XOpHK) zaeVMT_7;dUgmVNQ#yih#!;NpwKr~u#ThVd&elC3>yEQ8~-r_pa!}Uw>%YKYQ8AH(z z!39*HKnsI{=pgv~4dG>X3gqT0V$&;JWbnCN$h4Du4>JGdCV=^mmp*CTP5d2;{%IXf zvK$#1kO?`F4E+RGFPmS#Pfa!fzBxKi|BW>~H?yCh!1T+03gUlbiYE*K~rbD)j;+H7; z0k?z-6u5~QzX#C)4szZo;Ta;%dJrUxQ4|}(kk$Qd2*XzQx9RtZb4}q{u`~Cl`6KK<=_q4<@vWxttf={S z!$;VE(ox0-M9k^^W$lgKt4CaSa@JzhFG46kD{2>ZhtU63^xv|GhedeT&x%@l_q`+R KKk1|7tMMPPyMaRh literal 0 HcmV?d00001 diff --git a/library_management/__pycache__/serializers.cpython-311.pyc b/library_management/__pycache__/serializers.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..d918d977461d1e640fa6de2b50bedabcb24530ad GIT binary patch literal 2152 zcmb_d%}*0S6rb5INHrhSP?ZRU%zJ+Ri;&>~MW3at z7o}1`4I;h{!-`M|G~bH#iU`Xpl@lBI{w}{#5apFw@b&bn zjZAFWwbAsJgO{9uNr}79?OJjOUxpDznr=CcmS#<&g{N2p?x(Q;&-U-tanEkU38g(OrhYNLZQrZ6k!aZLo!rX&H`XXx~ehV zyBhL(k4S0sAtcbix<&$`>q-Qi#GRjfiM5wVN?L&RG^L4~_SoVkFAH*p;V zU9gsj=(-XSCvfjk1G|)l)4k&Kl`w`|>wgaK0tNTnCE<+=NO&99LC}Y^B_Xg}M<+{l(~tW6o-L5&L3Gt*FiDHt_7{*EIWQ(FHJGMf7)M-!{ieMxbEf|9B#Bkxtf#Ft-fu!l+Ap#v9Y{e4g z-cdEoDL@ww9lX_JC$~j97aH>?@Q4E_a4OI#TY_}T)H~8llvIOtBB^_xd+&Gez5Mu1 zQBneHcQ(I-Kg9*%A1Pf}E*SR(JHr-m#u;ZUa<0Tl4&_LUGd>FEBF1uIXV`*VQjC#| zoGaxb56xwQaiozr%1}<4ae}+WSy#$uawuntapaNmxi*wD%{UVyab|{cGK`~)#JN6{ zqcTo>g12>xWUWkr@8egsMGgcr?}pPmfmdn3h!_8QUr4*xqKKF;(takIeWTCB_`aWz!(~7LdfW_-kK00}qTx)lXZVRrXFBq3UO875! zeH|A?u`kRzA0K^T#`*a88zi4^o=%@W{`rZg%(==OQHoS4{{D>vRtQ+3V5QF^9I4co z(p0+PNkvyG5~)O`l2fj+brSc*Hv+%@8(c%+XJ?SAw>-7%s%4@sQgxAl3I&w_cA7uC zPctPiqq!N4WGXaM=_MVoLBIwD8(~NQxb3M+uDV3jDpjk!uN|;Oz!n8tVaUz%A}wfM zVc9J#lfo)3tiDV;V26Mm3USKdMO9g2&hp|3qx+4CupwX_A)}L!nv{O1SwCPB6(0X51$^{YuTK2Oxl%_q~nd?e)(fW>TFxQ>vre!I+FSkFj zpV9=NpX!`y^Y+M{*-$Q=2veFaHdb{Vv@V#9reF4zPqynxxvIB zE$_9-1i35}>3{(-I8m-nhP>oTl9-!*| zp1#H@RUc6G1J%SHeN9rT0iYUG+8f4+Qrr;WhMRCx6gL9615LPTiW>#om=b8{Ge&Xa zfSXYEH{fO{ZW3_O@0oF2p8A4I%*xXMUy@@056Uy=xM=)a9@ZG;P2cfC;mU`~&sG#w zgU|K_<=Xj7`ii2RERbAOFxwD+T2)sRf}A(Kj9yzIc}k3*tO2y{s3B={o}kWGhZ7dow;(^8i%osctH zft*!HE~BcMLLR97M7gRERY_)3t2f}=`z}#Zno?=+VeQ35C9jZ7T8%nM2UO8%()GcL z=_1YnI+e|=!rX#556S^s%bbnzsC*qAnNms*;A$ ztp`j4eRk*J&sUtnC3u-jI27lSP{DAURYOv(pnvZId|=fi+=?e5Ds78=!YlKz*$z|0 zc_AMcqCQhhCiAJBl1!T3WHMKfSF%|4CzC&0No5&^a>eu%E-t~IsHQWO&6*(l zp3P=1k`%cylS}1Oi%L$(Yt^cxt?DWWh8kbKL3*J(3c^rO4*^)S{*|TRt>U&cxFrpi zq+vrEUOQC|jp;&nx#yrBIiw5w*-OT%owVMAQ-J<+_dwKAb>5f&m0n5C^d|gkTr}a+;w1GyPfE!IkCYrHqo52^u@LfN?BMRsnXT#sIts zKZ2pPGx(2ngnhK;#2jG$d`?g~Y`1iY31eF$6HvTK0~7XP9WtSD*|<=G0NJ5V0kAJS zY)C`f(&&~nT9U>MX&mKX3gm#jY|+^GM_;tv`0cT5C(NU9+554s)w1J=KoEsr)3SRE zX=Ga(-;%~l(xf3x;<956%f`la%SLB_&n_xdZLdLoow5U*h9Em(|18^>BI(O$QNIgc z1gT7_3RWbEqON2$HGWykWz$t#hP|TImEgDg1%R)(BDVy8*(39jYLUAsXtq{MR(TV- z)ASUDhmN~2?+4Ynb2nXDTaB#9%g&;!D9FMcN4@KWmADqnHac}QcVLqxX7)1aLLM|U zuabk%5!g)^5~<{6{BoJ@E7wwFQLSmJ>AsZ7Y6@X~$!!X%lD%Yl2y>^VK&fAY#WFpuKCBfN)~asvTS$t6u*U6310`t) ztk$|fck{Mp3?6)R^6}iGBPHp$AsyGntNYKw(9zA-80OCYv~?rUzz&hJZe@^PzAT#(!YVVbj)Am8xmK zT&U1j=r|;x1#5Jm?5_I$&T)Ipjpk^zmaJr-ThaN@UEdeaX`xyR*;CI;7^!Y1AVvNv zwJf%jqBf8sl;LlYwWjAR1i_j7BG?;Y1tKKVt!gQ4MP2R8rLKcjrBO38t5F9z0Zqtp zYzILzLs5B)wo{2Tg|i==J8y~^HF*^RSlRTavq~zj$VoY+rD%-H9L?+44|Zm{(uI}0 zMn&0lr)juMa0N`R-3@Zh#`fE%X13$Bt(i8NIAOVwowzHON!}IY$w!z zdr_Zws}wqHgbwS0!#n9@m4_N|%k&f-MW^g+;roS!llPe#p$6e<6#2fx^yBi>BqWk6 zip(_1!}3BJj#}zM&`{azzF^ajPY`tsfGPk$CvUU<)W?5F2doL72m{>;5NFe@PlNq(Qrb`1*{VxS+qBgtsJpW=Nmu z;%CiX!rGpH`!T#kVQ(+7hZVNA2^McXV0jxuItVkwFBCv;+4!Qc zX%moI+xiw@-)m7QCksvX-R7HYUaq~?U#$ef+)@3KU5%auLR6Hd%0mS3=Kc)T; zz@q&Ji+m?rlBNx5y21YY+Qz@>8#4N4?iGx_BkS+)L`ICr)OIAk6^TEZ(IfFv8{fj#TdE6w!}1Dy_3+SHud3h=tkCOEYA>MIpgAMvyRHSMT2Y<`N^pwf zXYPS9%#ZK`RJp8BH80k&Lwpf=d8YY=d5e zxe?P3X(1fau~WF!ux%GHVYDy>Y^nl)%n=X6SVmzJ@<->tKB0$ZOQCrqG{5fO=@~P6 zX104?+3I=a@u=SON~!0l(Q|ZN+KC)6BGcQELtBwUj|Dh9D@EQhBJZqsKqS>4Ef2=a z1F@$bA>ak+rJ&7ArE?+LG5|7zm|iQ_wIn-NWLf7TOtevHQdo!J3j9<|J=d&%`HNsS(%GmY|sMzL?TE^))z;BS`z_(#6}T%@K| z;83h2DQW4XX1T=1Bxx^Qsn-;kKaVE@G+jl}gNz{$X-7V-m@ah%4slH{=D941s3y0^ zkgzSu4tA5tN{YM2f*cgP)qxf)iPt*%9BAl?)&GHP_7C6r)aZ||3%A-0v1do>{^hk> z*S4kMEopcY&g>=(X+jq#=w3$sjS)4j-*mz0wUQ+Qmf3XKNi-(p1VaVWr>>;aimE18 zNS5FX&GyRl(@Hj*OoD1JL#>L8J;v6t1Vw_NhzRtmFxl$AvOltRqTD&KHec=@13By( z*ofUOmbzj_S8VM)jMFDEOn(u;gcJv=6VmEt@6G|HX2}1vOMuGpKMm#CwFKJyg=o{c zE3%VC2t!yJMi4?Uf?yQE7=m#GSF7L`P-r@U>@%d%ZE12#nk-3EhBSo-kkbtZkk~_= zgF#D3mEkfJ{ZslEfD1LeV&|zKdWJO4UtLZAr?|E zUo51E%yc-g%u;kK$Bhb&sWiq&ke*Y8x&dVsH?nHEgDrX{t3YrIDPIGC8Ni4Un%WK> z+zK6h9MMAuOQCm-(7V979bf0hgx>qA{>Hq1=2QLkzb^SM7`_X-aDi@0Ype1#bo$3J zvdBN=>#f91I3}ujVcBto3MUzZ!y^H@Z+hslPTf{OXl)C?;gF^d3r8omAX;`eVxyh~ z*qbPfV|pq(V2UYF=w%IZwChk$nfRS_I!_NfhAIvj94`u!E#$@hB^MCT&^7`kFlxA2 zrnk}v0&A88TAPf0SkAYDjax;M&jI=O@Kdo@*uCI@5ggwRPHhFJ?k(xTsZ#JwBlzap znX)HnczSMUwmcKMXQC{2Z;O#FF|ygCi;vA;)WF0#rP8+d`3&Y zDZ>Xh7E|A|%YNYJkF?A0LF(m5A`j>TF`u>Pt@HTC#ObCJVkt)wgBaF>qxHeyUBEu5 z&~O|`jAVUqEhNU40=ASGf_9tS1c3QHUSKM+8DJ&2BZdu3sf9ch9P&3n1;((Iu+S9h z=h#()*a%F=*AVr$2#}~g;m1G_2eyRe?||f=k!%gXiwn!ZDu{UFfA%>PuO^=!U5h z>K8;TVYY1s`H7DEa_uN(hQbgQNXUe4Aa*A0ht)SWtCN{dbVnr%s;d z%iN$||CYHSz5Xq8C-fhB%iOSD|CYIaz5Xq8BYOQ?=4SL(Z>zRpovVAxTvV@r%iICI z{w;Ga>Gf}!8`bOIRy56PY39ifk7Xaa%w_Z+dRy_Zakfw0PX1-MCu;)h*9|H93=z+3 zSih4GBXJ|x2pgT0IE=&HclDc@n?v5Uc-7F{0tH|f{p7&Xc~!Ukhp^N zx_P|ZYYjKfKckrEc6?Vik0;fw;fDN-VxHUa@g5$}KUzZ^12NC-__sQENc)<>#^f`s zeO^P2h&+Vi&EWRbGpv1HL+y9)F=R_4*!U}BA21vc$d(Egc$kDK+o0Ej+_yk?8-6we H>dF5fI6so_ literal 0 HcmV?d00001 diff --git a/library_management/admin.py b/library_management/admin.py new file mode 100644 index 0000000..7f115cd --- /dev/null +++ b/library_management/admin.py @@ -0,0 +1,10 @@ +from django.contrib import admin + +from .models import Book, BookIssue, BookRequest, BookReturn, NewBookTicket +# Register your models here. + +admin.site.register(Book) +admin.site.register(BookIssue) +admin.site.register(BookRequest) +admin.site.register(BookReturn) +admin.site.register(NewBookTicket) diff --git a/library_management/apps.py b/library_management/apps.py new file mode 100644 index 0000000..9591f7f --- /dev/null +++ b/library_management/apps.py @@ -0,0 +1,6 @@ +from django.apps import AppConfig + + +class LibraryManagementConfig(AppConfig): + default_auto_field = 'django.db.models.BigAutoField' + name = 'library_management' diff --git a/library_management/cron.py b/library_management/cron.py new file mode 100644 index 0000000..853179e --- /dev/null +++ b/library_management/cron.py @@ -0,0 +1,18 @@ +from django.core.mail import send_mail +from django.utils import timezone +from .models import BookIssue, Book + + +def send_return_reminders(): + actual_return_date = timezone.now() - timezone.timedelta(days=15) + overdue_books = BookIssue.objects.filter( + return_date__lt=actual_return_date, is_returned=False) + + for book in overdue_books: + user = book.user + subject = 'Return Reminder' + message = f"Dear {user.username}, please remember to return the book '{book.book.name}' as soon as possible." + from_email = 'rohan.saeed@arbisoft.com' + recipient_list = [user.email] + + send_mail(subject, message, from_email, recipient_list) diff --git a/library_management/forms.py b/library_management/forms.py new file mode 100644 index 0000000..4cd578f --- /dev/null +++ b/library_management/forms.py @@ -0,0 +1,22 @@ +from .models import Book, BookIssue, NewBookTicket +from django import forms + + +class BookSearchForm(forms.Form): + q = forms.CharField(label='Search for books', required=False) + + +class BookReturnForm(forms.Form): + book_issue = forms.ModelChoiceField(queryset=BookIssue.objects.filter( + returned=False), label='Select a Book to Return', empty_label='-- Select a Book to Return --') + + +class BookRequestForm(forms.Form): + book = forms.ModelChoiceField(queryset=Book.objects.all( + ), label='Select a Book', empty_label='-- Select a Book --') + + +class NewTicketForm(forms.ModelForm): + class Meta: + model = NewBookTicket + fields = ['user', 'book_name'] diff --git a/library_management/managment/commands/import_books_from_csv.py b/library_management/managment/commands/import_books_from_csv.py new file mode 100644 index 0000000..b2082f0 --- /dev/null +++ b/library_management/managment/commands/import_books_from_csv.py @@ -0,0 +1,41 @@ +# myapp/management/commands/import_books_from_csv.py +import csv +from django.core.management.base import BaseCommand + +from library_management.models import Book + + +class Command(BaseCommand): + help = 'Import books from a CSV file' + + def add_arguments(self, parser): + parser.add_argument('file_path', type=str, help='Path to the CSV file') + + def handle(self, *args, **kwargs): + file_path = kwargs['file_path'] + try: + with open(file_path, 'r') as csvfile: + reader = csv.DictReader(csvfile) + for row in reader: + title = row['title'] + author = row['author'] + publisher = row['publisher'] + available_quantity = int(row['available_quantity']) + + book, created = Book.objects.get_or_create( + title=title, + author=author, + publisher=publisher, + defaults={'available_quantity': available_quantity} + ) + + if not created: + book.available_quantity = available_quantity + book.save() + + self.stdout.write(self.style.SUCCESS( + f'Successfully imported book: {title}')) + + except FileNotFoundError: + self.stdout.write(self.style.ERROR( + 'File not found. Please check the file path.')) diff --git a/library_management/migrations/0001_initial.py b/library_management/migrations/0001_initial.py new file mode 100644 index 0000000..359f5ee --- /dev/null +++ b/library_management/migrations/0001_initial.py @@ -0,0 +1,69 @@ +# Generated by Django 4.2.6 on 2023-10-30 02:01 + +from django.conf import settings +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ] + + operations = [ + migrations.CreateModel( + name='Book', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('name', models.CharField(max_length=100)), + ('author', models.CharField(max_length=100)), + ('publisher', models.CharField(max_length=100)), + ('image', models.ImageField(blank=True, null=True, upload_to='books/')), + ('quantity', models.PositiveIntegerField(default=0)), + ], + ), + migrations.CreateModel( + name='NewBookTicket', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('book_name', models.CharField(max_length=255)), + ('status', models.CharField(choices=[('Pending', 'Pending'), ('Approved', 'Approved'), ('Rejected', 'Rejected')], default='Pending', max_length=20)), + ('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)), + ], + ), + migrations.CreateModel( + name='BookReturn', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('return_date', models.DateField()), + ('book', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='library_management.book')), + ('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)), + ], + ), + migrations.CreateModel( + name='BookRequest', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('request_date', models.DateTimeField(auto_now_add=True)), + ('status', models.CharField(choices=[('Pending', 'Pending'), ('Approved', 'Approved'), ('Rejected', 'Rejected')], default='Pending', max_length=20)), + ('rejection_reason', models.TextField(blank=True, null=True)), + ('book', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='library_management.book')), + ('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)), + ], + ), + migrations.CreateModel( + name='BookIssue', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('issued_date', models.DateField()), + ('return_date', models.DateField()), + ('returned', models.BooleanField(default=False)), + ('reminder_sent', models.BooleanField(default=False)), + ('book', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='library_management.book')), + ('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)), + ], + ), + ] diff --git a/library/__init__.py b/library_management/migrations/__init__.py similarity index 100% rename from library/__init__.py rename to library_management/migrations/__init__.py diff --git a/library_management/migrations/__pycache__/0001_initial.cpython-311.pyc b/library_management/migrations/__pycache__/0001_initial.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..18b931a43414bfe8fa232edcd5af90757dd076ec GIT binary patch literal 4084 zcmdT{O;8(07M>aXjefuq!N>wj7T7ozRDfhxTk$$;LJ$rln79lkyUJm9P&Z=4Xh!K7 z;o!rT4|~{SZp+cN2X?o@fx{j+`j}&@Y7SJNQne@F>gjY|jfJ^QSSX7~C`(8z2P6RpYrf3_4j?PkaoUEmMzUJm9@74U+3$=Ir+2c{(x%#?)t5P+1hR@jx z_?&ZX?Dcov2If1zBR~wU{ahbV{!Po#{|k}93m`J&dVJXj0f{@;Pi7suNEY01_4OU; z1C7HcWBMz>`K({t%?sfC?irbPR%YIE*QXD04Zc|&P~jXhzm5!#oczsKL**-I1Wue$ z7QOEuFH0==iD|AgNkjLTG*>DFSwd~vrcxnTwJ~Dx2GQy&*;Ll?CW~5_XsWI~!7Q*1v!0z09rW6Vs-T!MaM?fUSnZUwq_C*Z8TSO&052Rg+N~wKMAkEzSejl zz(Om!YOI5frmnMSv!R6Sl0r6 z%)MCBD(l#0QLfpw>&5?EG0Rr%rd0^Q!5Vph4FrcQxyDsWOrB~qh`E6g$#(`G;u@}i z=VTBDT(K9t*nypq%9^QFuthR_hF4}5Yyu*nCTbcA9MagvOajYe+?t2jZW4pViThR% zz{!H#v?pm@TOl0Nx@rIvb!^yUe1gTjbze8JWwQjqF5|8Q@4dJf=3_-gh$V?@C)^Me zh?Hd-017Wbgx3ug<%;GktBF}$<1ggxFMGy7T)POaYX-tZv0(d!LWaqTiB*c?w6kMDh8TCo2H zo-=G*#lFNnlVGiCd=42JMm5!_noL3~Om-sz2(ifY)Z+A1X@*5h5CuDw@^@g9$w_`%|8lTJUr_w*9F4OeLw;N7+WH0#r4O&*HL1@})r7b6I(WDJB zG*j5>b25e9MVh(Y%G`D`w`ubC`>6~a7~T4vGcdYq(SbXyfjiE?9h&@TKXsMn#xKub%pkiZrybHM|W@REq(t-+P~cDUv~PJY4Xec)Bw$XxV7wL zKYX5|+38kx+R0ASWU1X1>FsWZV$s-30muO-?Y<)y^5<~jtp**s&=!Q^lyriAE-mpP zRjTmURV2N1>48gOB!wjxo)Heu$nNrg{^S&AoZ^C0T&7=DoUbgJv0EA2$=Ed6Y)3=f z51IP`?`H5#?CqL23f8gXlpvm97eSe!~nypOJ$uwzlH8Xb( zGq2IX;wO^4@O!}HGY zJWbwzyNf>;i8B)K>N$`&EnugOLGDlR+@ILHOtX`%?4*;Oq{)x>Q+Ya6e0I|rD(+!A zRB8>CoS_m;&iwMuUXpos#(8!EIpCzdC>DFdPe0=yGUu0^g3RJx{T!>9#;RAzqn#17 z;ud|cT4xRi$Gm^1V}7kAlfE`G%Q;v1XTbd^f8-r1cgX^D`QK2>2GS0Qq6kGz9Hc`2 k_;+8pMNj+g9}{bb{~(6j!kgsVn3KHml206*GV5CP6Q*VXF8}}l literal 0 HcmV?d00001 diff --git a/library_management/migrations/__pycache__/__init__.cpython-311.pyc b/library_management/migrations/__pycache__/__init__.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..3ef11548fc1e8d89db71da5bf26df2b755a5d255 GIT binary patch literal 195 zcmZ3^%ge<81a*A&sUZ3>h=2h`DC095kTIPhg&~+hlhJP_LlF~@{~09tD@;GMIJKx) zzbHQ=F|Rl=H8n-wCAB!aB)>pECo`!iv8YlvH!&|UJvBEquLLF(k0g|vnO>Awl9``Z ytREkrnU`4-AFo$X`HRCQH$SB`C)KWq6=)5}A;tVa;sY}yBjX1K7*WIw6axU-oifh= literal 0 HcmV?d00001 diff --git a/library_management/models.py b/library_management/models.py new file mode 100644 index 0000000..600ac1d --- /dev/null +++ b/library_management/models.py @@ -0,0 +1,60 @@ +from django.db import models +from users.models import User + + +class Book(models.Model): + name = models.CharField(max_length=100) + author = models.CharField(max_length=100) + publisher = models.CharField(max_length=100) + image = models.ImageField(upload_to='books/', null=True, blank=True) + quantity = models.PositiveIntegerField(default=0) + + +class BookIssue(models.Model): + user = models.ForeignKey(User, on_delete=models.CASCADE) + book = models.ForeignKey(Book, on_delete=models.CASCADE) + issued_date = models.DateField() + return_date = models.DateField() + returned = models.BooleanField(default=False) + reminder_sent = models.BooleanField(default=False) + + +class BookRequest(models.Model): + REQUEST_STATUS_CHOICES = ( + ('Pending', 'Pending'), + ('Approved', 'Approved'), + ('Rejected', 'Rejected'), + ) + user = models.ForeignKey(User, on_delete=models.CASCADE) + book = models.ForeignKey(Book, on_delete=models.CASCADE) + request_date = models.DateTimeField(auto_now_add=True) + status = models.CharField( + max_length=20, choices=REQUEST_STATUS_CHOICES, default='Pending') + rejection_reason = models.TextField(blank=True, null=True) + + def __str__(self): + return f'{self.user.username} requests {self.book.name}' + + +class BookReturn(models.Model): + user = models.ForeignKey(User, on_delete=models.CASCADE) + book = models.ForeignKey(Book, on_delete=models.CASCADE) + return_date = models.DateField() + + def __str__(self): + return f'{self.user} - {self.book}' + + +class NewBookTicket(models.Model): + BOOK_TICKET_STATUS_CHOICES = ( + ('Pending', 'Pending'), + ('Approved', 'Approved'), + ('Rejected', 'Rejected'), + ) + user = models.ForeignKey(User, on_delete=models.CASCADE) + book_name = models.CharField(max_length=255) + status = models.CharField( + max_length=20, choices=BOOK_TICKET_STATUS_CHOICES, default='Pending') + + def __str__(self): + return f'{self.user} - {self.book_name}' diff --git a/library_management/permissions.py b/library_management/permissions.py new file mode 100644 index 0000000..9c84cd7 --- /dev/null +++ b/library_management/permissions.py @@ -0,0 +1,26 @@ +from rest_framework import permissions + + +class IsStaffEditorPermission(permissions.DjangoModelPermissions): + def has_permission(self, request, view): + user = request.user + if user.is_librarian: + if user.has_perm("library_management.add_book"): + return True + if user.has_perm("library_management.view_book"): + return True + if user.has_perm("library_management.delete_book"): + return True + if user.has_perm("library_management.change_book"): + return True + + if user.is_librarian == False: + if user.has_perm("library_management.add_book"): + return True + if user.has_perm("library_management.view_book"): + return True + if user.has_perm("library_management.delete_book"): + return False + if user.has_perm("library_management.change_book"): + return False + return False diff --git a/library_management/serializers.py b/library_management/serializers.py new file mode 100644 index 0000000..4047451 --- /dev/null +++ b/library_management/serializers.py @@ -0,0 +1,26 @@ +from rest_framework import serializers +from .models import Book, BookIssue, BookRequest, NewBookTicket + + +class BookSerializer(serializers.ModelSerializer): + class Meta: + model = Book + fields = '__all__' + + +class BookIssueSerializer(serializers.ModelSerializer): + class Meta: + model = BookIssue + fields = '__all__' + + +class BookRequestSerializer(serializers.ModelSerializer): + class Meta: + model = BookRequest + fields = '__all__' + + +class BookTicketSerializer(serializers.ModelSerializer): + class Meta: + model = NewBookTicket + fields = '__all__' diff --git a/library_management/tests.py b/library_management/tests.py new file mode 100644 index 0000000..7ce503c --- /dev/null +++ b/library_management/tests.py @@ -0,0 +1,3 @@ +from django.test import TestCase + +# Create your tests here. diff --git a/library_management/urls.py b/library_management/urls.py new file mode 100644 index 0000000..140bfef --- /dev/null +++ b/library_management/urls.py @@ -0,0 +1,17 @@ +from django.urls import path +from . import views +urlpatterns = [ + path('', views.BookList.as_view(), name='book-list'), + path('book_search//', + views.BookSearchView.as_view(), name='book_search_results'), + path('/', views.BookDetail.as_view()), + path('issues/', views.BookIssueList.as_view(), name='issues'), + path('requests/', views.BookRequestList.as_view(), name='requests'), + path('book_request/', views.BookRequestView.as_view(), name='book_request'), + path('book_return/', views.BookReturnView.as_view(), name='book_return'), + path('my_books/', views.MyBooksView.as_view(), name='my_books'), + path('new_ticket/', views.NewTicketCreateView.as_view(), name='new_ticket'), + path('my_tickets', views.BookTicketView.as_view(), name='my_tickets'), + path('dashboard/', views.librarian_dashboard, + name='librarian_dashboard'), +] diff --git a/library_management/views.py b/library_management/views.py new file mode 100644 index 0000000..3edeca8 --- /dev/null +++ b/library_management/views.py @@ -0,0 +1,164 @@ +from .models import BookRequest +from .forms import NewTicketForm +from .models import BookIssue, BookRequest, BookReturn, NewBookTicket +from .forms import BookReturnForm +from .models import BookIssue +from .forms import BookRequestForm +from django.shortcuts import render, redirect +from django.views import View +from .models import Book +from django.views.generic import ListView +from django.shortcuts import render +from .permissions import IsStaffEditorPermission +from django.urls import reverse_lazy +from django.views.generic.edit import CreateView +from .models import NewBookTicket +from .forms import NewTicketForm +from rest_framework import generics +from .models import Book, BookIssue, BookRequest +from .serializers import BookSerializer, BookIssueSerializer, BookRequestSerializer, BookTicketSerializer +from django.utils import timezone +from django.http import HttpResponse + + +class BookList(generics.ListCreateAPIView): + queryset = Book.objects.all() + serializer_class = BookSerializer + permission_classes = [IsStaffEditorPermission] + + +class BookDetail(generics.RetrieveAPIView): + queryset = Book.objects.all() + serializer_class = BookSerializer + lookup_field = 'pk' + + +class BookIssueList(generics.ListCreateAPIView): + queryset = BookIssue.objects.all() + serializer_class = BookIssueSerializer + + +class BookRequestList (generics.ListAPIView): + queryset = BookRequest.objects.all() + serializer_class = BookRequestSerializer + + +class BookSearchView(View): + template_name = 'book_search_results.html' + + def get(self, request, *args, **kwargs): + book_name = self.kwargs['book_name'] + books = Book.objects.filter(name__icontains=book_name) + return render(request, 'book_search_results.html', {'books': books, 'book_name': book_name}) + + +class BookRequestView(View): + template_name = 'book_request.html' + + def get(self, request): + form = BookRequestForm() + return render(request, self.template_name, {'form': form}) + + def post(self, request): + form = BookRequestForm(request.POST) + if form.is_valid(): + book = form.cleaned_data['book'] + max_requests = 3 + user_requests = BookRequest.objects.filter( + user=request.user, status='Pending').count() + + if user_requests >= max_requests: + return render(request, 'max_requests.html') + BookRequest.objects.create(user=request.user, book=book) + return redirect('requests') + + return render(request, self.template_name, {'form': form}) + + +class BookReturnView(View): + template_name = 'book_return.html' + + def get(self, request): + books_issued = BookIssue.objects.filter( + user=request.user, returned=False) + form = BookReturnForm() + return render(request, self.template_name, {'books_issued': books_issued, 'form': form}) + + def post(self, request): + form = BookReturnForm(request.POST) + if form.is_valid(): + + book_issue_id = form.cleaned_data['book_issue_id'] + book_issue = BookIssue.objects.get(id=book_issue_id) + + book_issue.returned = True + + book_issue.return_date = timezone.now() + + book_issue.save() + + return redirect('issues') + + books_issued = BookIssue.objects.filter( + user=request.user, returned=False) + return render(request, self.template_name, {'books_issued': books_issued, 'form': form}) + + +class MyBooksView(ListView): + template_name = 'my_books.html' + context_object_name = 'my_books' + + def get_queryset(self): + user = self.request.user + issued_books = BookIssue.objects.filter(user=user, returned=False) + requested_books = BookRequest.objects.filter(user=user) + returned_books = BookReturn.objects.filter(user=user) + + return { + 'issued_books': issued_books, + 'requested_books': requested_books, + 'returned_books': returned_books, + } + + +class NewTicketCreateView(CreateView): + model = NewBookTicket + form_class = NewTicketForm + template_name = 'new_ticket.html' + success_url = reverse_lazy('my_tickets') + + def form_valid(self, form): + form.instance.user = self.request.user + return super().form_valid(form) + + +class BookTicketView(generics.ListAPIView): + queryset = NewBookTicket.objects.all() + serializer_class = BookTicketSerializer + + +def librarian_dashboard(request): + pending_requests = BookRequest.objects.filter(status='Pending') + return render(request, 'librarian_dashboard.html', {'pending_requests': pending_requests}) + + +def accept_request(request, request_id): + book_request = BookRequest.objects.get(pk=request_id) + if book_request.status == 'pending': + book_request.save(status='accepted') + + return redirect('librarian_dashboard') + + return HttpResponse('Invalid request') + + +def reject_request(request, request_id): + book_request = BookRequest.objects.get(pk=request_id) + if book_request.status == 'pending': + book_request.status = 'rejected' + rejection_reason = request.POST.get('rejection_reason') + book_request.rejection_reason = rejection_reason + book_request.save() + return redirect('librarian_dashboard') + + return HttpResponse('Invalid request') diff --git a/templates/base.html b/templates/base.html new file mode 100644 index 0000000..fac08aa --- /dev/null +++ b/templates/base.html @@ -0,0 +1,43 @@ + + + + + + {% block title %}Authentication App{% endblock %} + + + + + +
{% block content %} {% endblock %}
+ + diff --git a/templates/book_request.html b/templates/book_request.html new file mode 100644 index 0000000..3da207e --- /dev/null +++ b/templates/book_request.html @@ -0,0 +1,14 @@ + + + + Book Request + + +

Request a Book

+ +
+ {% csrf_token %} {{ form.as_p }} + +
+ + diff --git a/templates/book_return.html b/templates/book_return.html new file mode 100644 index 0000000..96b8af2 --- /dev/null +++ b/templates/book_return.html @@ -0,0 +1,18 @@ + + + + Return a Book + + +

Return a Book

+ + {% if books_issued %} +
+ {% csrf_token %} {{ form.as_table }} + +
+ {% else %} +

No books issued.

+ {% endif %} + + diff --git a/templates/book_search_results.html b/templates/book_search_results.html new file mode 100644 index 0000000..9571cf1 --- /dev/null +++ b/templates/book_search_results.html @@ -0,0 +1,20 @@ + + + + Search Results + + +

Search Results

+
    + {% for book in books %} +
  • + Name: {{ book.name }}, Author:{{book.author}}, Available Quantity: + {{book.quantity}} +
  • + + {% empty %} +
  • No books found.
  • + {% endfor %} +
+ + diff --git a/templates/data.html b/templates/data.html new file mode 100644 index 0000000..4847987 --- /dev/null +++ b/templates/data.html @@ -0,0 +1,5 @@ +{% extends 'base.html' %} {% block content %} +
+

{{user}}

+
+{% endblock %} diff --git a/templates/librarian_dashboard.html b/templates/librarian_dashboard.html new file mode 100644 index 0000000..e1855a3 --- /dev/null +++ b/templates/librarian_dashboard.html @@ -0,0 +1,14 @@ +{% extends 'base.html' %} {% block content %} +

Librarian Dashboard

+

Pending Book Requests

+
    + {% for request in pending_requests %} +
  • + {{ request.user }} requested {{ request.book_title }} + Accept + Reject +
  • + {% endfor %} +
+ +{% endblock %} diff --git a/templates/login.html b/templates/login.html new file mode 100644 index 0000000..1a22669 --- /dev/null +++ b/templates/login.html @@ -0,0 +1,16 @@ +{% extends 'base.html' %} {% block content %} +

Login

+
+ {% csrf_token %} +
+ + {{ form.username }} +
+ +
+ + {{form.password}} +
+ +
+{% endblock %} diff --git a/templates/max_requests.html b/templates/max_requests.html new file mode 100644 index 0000000..8379d46 --- /dev/null +++ b/templates/max_requests.html @@ -0,0 +1 @@ +

You have reached maximum limit of requests.

diff --git a/templates/my_books.html b/templates/my_books.html new file mode 100644 index 0000000..11587ef --- /dev/null +++ b/templates/my_books.html @@ -0,0 +1,33 @@ + + + + My Books + + +

My Books

+

Issued Books

+
    + {% for book_issue in my_books.issued_books %} +
  • + {{ book_issue.book.name }} (Return by: {{ book_issue.return_date }}) +
  • + {% endfor %} +
+ +

Requested Books

+
    + {% for book_request in my_books.requested_books %} +
  • {{ book_request.book.name }} (Status: {{ book_request.status }})
  • + {% endfor %} +
+ +

Returned Books

+
    + {% for book_return in my_books.returned_books %} +
  • + {{ book_return.book.name }} (Return Date: {{ book_return.return_date }}) +
  • + {% endfor %} +
+ + diff --git a/templates/new_ticket.html b/templates/new_ticket.html new file mode 100644 index 0000000..89fa056 --- /dev/null +++ b/templates/new_ticket.html @@ -0,0 +1,7 @@ +{% extends "base.html" %} {% block content %} +

Create a New Ticket

+
+ {% csrf_token %} {{ form.as_p }} + +
+{% endblock %} diff --git a/templates/profile.html b/templates/profile.html new file mode 100644 index 0000000..5841c6e --- /dev/null +++ b/templates/profile.html @@ -0,0 +1,7 @@ +{% extends 'base.html' %} {% block content %} +

User Profile

+
+ {% csrf_token %} {{ form.as_p }} + +
+{% endblock %} diff --git a/templates/signup.html b/templates/signup.html new file mode 100644 index 0000000..cc501c8 --- /dev/null +++ b/templates/signup.html @@ -0,0 +1,38 @@ +{% extends 'base.html' %} {% block content %} +

Sign Up

+
+ {% csrf_token %} +
+ + {{ form.username }} +
+ +
+ + {{ form.email }} +
+ +
+ + {{form.password1}} +
+ +
+ + {{form.password2}} +
+
+ + {{form.date_of_birth}} +
+
+ + {{form.phone}} +
+
+ + {{form.gender}} +
+ +
+{% endblock %} diff --git a/users/__pycache__/admin.cpython-311.pyc b/users/__pycache__/admin.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..99929f088ef2bf0fcaec7ffc7a3be409cafbd889 GIT binary patch literal 374 zcmY*Tu};G<5WTCDs45Ce7rL=#X!8LerbbbXozX)JZY8D|Bhn zTjTbrgS=3bS>p!Po=r=t+lG?VmSo;w!&TUx#LmLTrnr~dN+J~x$v%|DB+l4Jnpr=W zS|*f}F5~I$?{0;`WVUUe@`PzdXC`DXx05~RYb_9Q3CGobEa9lyk97bTJa!h){eo4GgO%weSeOD#fC5Dx_{c^G z6gUB@+yhk^dR776#45~IsCEv9{vksHW$WE2ItqiK>s*$Md_!fhXbCU@1~#G~?jl>I zimg#qXlPmOB4#`;uHS9bYZ5r2Ne8AMQs%|xq3d+hBs_MRM>9Q@+`ge_6^sMoGmNt; z#)6u964x=lO^H`#nv@Mm>Lr*60X)nVG?{yag?!p_&&q3CJiH=7Oc z;DnDlJ_(4!d=?~DUfUv36r0hA%f{tS6CiF2H~ty3_U=?`&1%hYPY&K#ar=gv)ygkQ zAud~5NYy3Ei5mhfEBnQ#4)~@BWhdiP;pQqrXa+me-*djEpshLlb&tlUJpKA7l^6R4 D$oz;8 literal 0 HcmV?d00001 diff --git a/users/__pycache__/forms.cpython-311.pyc b/users/__pycache__/forms.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..fa42cf8ebe27269168b617a1db259f5b9e94da45 GIT binary patch literal 2393 zcmbVN&2Jk;6yMn|f5e-{Q5#BA650U52yCdJmsCh7vD+ZxAVMy_Sewk)-eB*#vul-H zXbv25;J~3$bLfdfAZiXhBJoeSQV!M}P$f>iIdV=p@!o7~*Xt-kj6FZi%zN|Z&F{T= z`@3Z&6=<_7i)>$0lz(v2Z^rqc_XGw{6{=8DR~n>52#(dd+R#c`Loewt*Qj1M8fM8P zN>!o8Z=@7cmHP@ce^zLWX$N5YIrOlV;!+j|S%T>iSwhN^Ae&%hTY87PB3ctPwXS5W z*C@&mVN^Wc@H48I+VB});>->l&n>{BnEt92)R-GMTZ6UNB;2K=az=w~`l?-LJdVq% zFbk}K(?mEm)?h#9=*brJL5rP_dL0-%RhUvDR4J*d!nAF@uSJQR_o)QhsOFF({Qz8e zj&8_yWE`k4haR?)DR=cx0OI8w{gVx>nE$~FPzk;aD5Qi<9K|9hrG}x1NGzHJiYG*J z-Kn}8O(e4*^kApSgih^%A?5xJMQplhxc%YqK8G4XiWr3ZEiFgY_=h_V>5>4CpA9ul{Fv( zbLg|5lc}0*?m*JPUHCPylZNiU2e3Q%b*8TF8C{i3-|Z@W*fa6RQIUTDP|Qs7Ih@QR zyo-QuOeB`!)&+Dl9Im*{R=|;FkyxtP{9N=sL?{%^qG)1C1}PLy-p?18^WT-19;~e_ z<=6R5G>&KT1qA8B`#4JV0n^O?3*e1ATwVAz|75L`p4orA-+K1=Mdi;*`-^;gzVLFs za6Dh=YUJ7ja-txfO59z2m73kl|8nUbOYQ-LJ%GFUSJvF##<4Z`hw!R zvPR7I3vLg&83qzd4kguL!I>E|6Y`Hw=n~fNf*9YUkMC)W^;_-q?J>^z9Z-#i@N-;4 z!025-@d8pD1*CWZDUJ$4iqTv#lM*J~w%w{17K*pSNp{O~1MX~QZTM7XWqslp0gj(7 zVam$q%QDD6#%1~DF=isMid7MLmi|UAau&ZAmeeo#B4{J~{@(!b?g{BA*W082j`DT; zqW`#NS68Q1AmJQ#C%efcfu}wW?ewh^Ts|GjZfFE@bR61Kx1lf)NYjBVr4e9r9QKW8 NS5O!D9v4c!{{=@?AeaCE literal 0 HcmV?d00001 diff --git a/users/__pycache__/models.cpython-311.pyc b/users/__pycache__/models.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..85e6b332bf840a9c12f7effbdcb73bef422d2d70 GIT binary patch literal 1173 zcmZuw%}*0S6rb6Tc3ZY!Z1rGDqDe#2gYCh<0f>nOYht7x1QTn_X4)CLh5f+UZ6ZdK z9yoCDz>S*+548pk9Q_0Q14`0EvnLZzcq%C;PQK~3DB$eQZ{FK^AHVlz_G=;$M=*X& z%(LGZp?4NCn4+>IAtrAqV?&B5K9pJ# zB!d}_vO2UG`vaw+m2!nr^oo^QLp1UQ;z7h{3o;yBWGQPy+t@e*)ed7VXwm`9QO-Dx z@1XJooq#g+KoQlfW~D%J8kQBP6^l5VCsSaXm4moV-We8iYQD)e_{5_CC!+gVS-7ka zi*a43QV=OJTd0XpRiFDN<9t$R3KuRxv}(HbD)at^DneVMl&zD7mHVSPe>OnIM)`#6L`ooupusl_XYsCV%$UN d&gHj<9&|3h{fLHv>vh;&JQZKh{zi-n(6vxlbOPt0vMc6@wt%{18w5gSWfhZwM5es5LSt3wn@R7LqM|6&XX6o1h zp$wH+nFTiJ=^(!Ok@f+a)gfHh#gTtrf6pDi~}7IkchBg0*1Y8diY~5wf>%u+2ZRT zhnfABJI*i<`;#{3NQ@(;o=b7^3pq=SlfM$Du#h7&PMQmJsd$zba+E9Q=i2|AZnje} zSDv8q^%MTEvPhwC40=?u+!uCW;uBUWR2FFVwT0jKL&>+gZqV0hE-}~+xQ2s=Ios=6 zu1>S_c_^{T3kFP=7{h#@crPs*>r}e1D5BsPmixFYQ`y`z+^)AB5Zfobb_Dpa%m-d} z!mCFm!{6m$&_dv2vOB+t%Bjt+BQlrCjKbb9z{K^xpflz|=XJf!j`%w9dWP#87@PVI z_FoOWzHVF3i9z|l4GbEL2HV7B}F=lO=?nSqV(lba01^Wpzu!)Znkgc({7 z7xfuZ!+-k^$RF$+-WokPdNkEGCfY`%Rbs6&UJaohK|O~0Y_3=x-Hp}KRNb7Yn~_?L z)#~_R2#p9DF*FhhgT&hURI5(3YNYA0rjL6ev?6H5&`Kn?NA06$(_&>(tVG4FxVSaG w7eX_FW(>_lapSQ4?&(xnn<#6MQi_$*=Q|WZw82kvc8xX-k zRN~;EsBlXT95_@o5gekPQ2&axN%oi7`DVVI`5wRd z@@HRPkU;zQms7gwC*&V|X*Q|R+4>tg%S0m@mnQ`-#TEDz&*3|t7YbrZEJ!J-;7j?~ zn2`4uu0hc z$UxX@TK{E|P~YMw61?rBdQsDr=sn|QVh*&VWlobcUzyKw-mn6@ z`loDp&d_NwQ_$_eY{oF|m8f=nji+H)Z_CY*?ZAyv>GrXF&M>z_jweQMnuWYAPJ>Gm z0g9Poi8PMulZo6o}ae; zRKGK)8z$X_BHRIu0N5gK(ZH24*0xV4ui{9OmTqQ>Mn>1Qp z$DfQZo>@AxNqm9Ch7x{y;mL)?i%SDdO3YGX^~m0pi`B?TEiz&$BXxD>vze8J)w}EFYO$)0 z*VJ)K9^Zl;k=_A62@-F>dxLj@H`_uN0)W#X?0W=&FhzHQE@trr&)n$vM4XCKQI}5J!F0M%(&qBm zSJLS_bD6v&p)r_C;{a=ftz#dj{WyvMq)d!&0Uo(On|wf;*d#9O;_|b``N6N22OEZtF?0qvQ0}Oc-SW3p3q?%(aRh-ERR#V3;dCW&uiRTym(+?{ zSEDQbsv4`QF-wj)W=@FoFn(hgVFUpk)oJ(RIEH}!Fb)B<+ntvVpp`qpu`;g8!s9mA z%Ac&_{IgCu=&>_i?99%8L1!6DH&=7#J$B12kjgwzsJCPi%EIRqY;*_A6Wvd=b-ZZ= zKE;e^G@vwIgD-U7p=%=2nVc&cW~P|c=at48+X&1@zXUZ@L1?iUQjl}mimga+W?}(k z;2z<|b*@}?7q)aGg?)pQE&)6u8|p6S%8k8<{;}_kXsP2)8PUOITwu^s!Z>&I!*$;q zarI$Uov5i3mOR1S+}lOh;By~!5xNE9p{?E)%;rB!u=c}dq~C!!A+%WvV}gDU&|!%< z49$m{R)*X-g>#Ys?S@#5TWYeZCTnW4NlQJ?In|SvPJlLwfNHyH3`v4=(1m^hU%SD{ z7F05o7_h_ItxR#IG-})|Q8PPd8qD>K3G7HimMs-cn!7QI|8O})GUf)O3|nc;VRbCU zlGT>5_%@uP4MWulFjgKR6SDMXhv-QDZF$ToxF#r48>X+ZA8=FPIBtU+vwHn*kki(O ze>cc}%lrHB`J29e4hpkws9br6qwiaygZ&(^eK$PYfiuT(WxPQ<4oBbj5HWB52j^Zl8vp{w1y&21SPCo#O2Ne- z@6U%8d4aph5%EtP3DCfDTT|GE$Z@aW>pzQagnz`PgS*(hmlnKeNiCR)ts1)Jg-QmY znw4u{S(R*b-n|AH-*c4Nu_zFJQ6xfvUknHw4K9b8ONdBtq-{Ce8sP~~f+V!rwh;hJ z;OjqmfrJ?{(i|ZX65fn%2!Mib3)Rk0j4d1kX*`K-c6_`qkk-j??Tv*T=sZN?n~8n6 zu1~ZcCfzDeddLyN)7WxHbNzB>t97W^T8}qdd+QD8ylM>;c+$1my8(>6YOw;=9sNWr z5BiR6_U*Io_yM@&0l0pKOElF2Cj%sP08V1Ky{rt9p#xYs@d=J6!{p=vxKj+*@&+*0 z)wE&xaI4kbY?0HOXZCqC&1CenFyPV6k$tF9hWc`Za}ezTrD7Mo zlVfA!=Ve8+sVP@1DDtXl*|M&bs9aKB$QsoP01M2+oF}Mc#uH|z(*Z9As|`74QpKjk zYcHE>NikRDr*zee08~{pwMxC%b80Rb7G?6ha9Ode6~iREFJTWX;j}cE7+79ZQ$V?9 z6jZ&++7fH0MK8FdDf&|{pjR}_$Hr7kwkl<6qS@8^)6`N6I#^>#c2TjRP%R0kq@rR; zil#{bEvc4;=}lTu?V?e!CHkVQsX5iwRwb|v1gLremeNwD8gB`gEL*WF7Ff|nXkMvk zwihW%JsWEGUFmThIKGY{#rifU4l zk;X5MNx7n8Dmie7B^joarz_OVNO!1>BWER|7E~KHq!Z~{Hj^FAp3BOTp=+y|-M=EM zA+M8~reVq@YFSEwTINw0HZd~IKF0BL@C{LH!?YTte{gv<%Gwg{BrTd4y8cS$oe1*| z&Q)2H!Mq?XDXO;nU%*y7SX)vEF+sZ*Mi<#iK41N8k9$^%6c{#T_D92g+=E-2(q=L|USf?H^Kbu;j1INb|ZyHJWRj z5>>ZsaEN5&CHT#wHl6_`moq9lc*hI*i@bK=jLOS~s#8*B9m(&c1ruY_C$od0jJ&+0 znsyPU7>AhOykNO#=yVsU{D@mN87fenP%|xJWZqRYYK|aI@Io`dDRf8uZt!d5&O8gf zUCg}c0Mp>L<%))y18*}&Gm#h|n!02v5RH18XGVIVf@xIBR#lk;_Wia`ISZ8~su_9# zBFM-{t@8_^Q=s;~5Q3|M4zUkdi7L4wvInNAWyc)%XlVLj3A)gmK znqJJL8fFncNpv-P5JZqrSWF3USlJ1Tqab-tAXiU3D$|^rS92eQcOC+#l>jo;Lrn9B zWmP6;?+P!7k|D%>J%{(^ExD{!Ohxm;%93ScWO{AJ(lVSL3-VyV5Bj`HHDbX;*}p!8 zONtJ`XIl5t$GouY=Tq5>$}-%mDjJn#FDA>+DvE~dq1UGBstsAwixFDJqoC(h@Frf? zy!I(}g74yu%*0ER7n@WI*C7GVpjt071sTI{c1#14b83nD-PojIXjIYtUWhC!dclCR zV(7LBCj)<6%zhMjbY53;Ab-A*#ul16!i(O(@b(1+E4HdZSlghW3TN39bz{YgpiUof z=&qu#&KX$x1MMgfy2ynWHNXY_{qjfd9jN7gxtm3Rl{Jl`qFV~3Bnwgf)Hcdl|LCrs z^O-DB-Oe%}Wk1|fvt#hWw8RU3f5nMy_c=e&z)T_Z`MOx+Jf7E zZtL)y%TE8oPCs-OocK4jM8A`|u=d;R?25ttS8n_h%1e5@P5=IiULAI?d zZY%qmY+KF~>ZI~Jsl1!YJMls-k#q(!Yk7Ad^LlPO=RD3i17v4_xC6wA(^}%F(>Jp~%R~H;=I+C>`S+3-J zRdR;Tub*;<&Tn;ZPdh`iJ43VX(5w@`&9*RtTNruWy*>11!s)xe(|6zPyYIvw)Dp*> z^Tt5;MC6Glsh=(#HX3i zaTGefh0dAfHC*z0;Rfz#QT!cNRD6cjwZJWeBxeJtU=}?KC5$9)2Wp8E&dDq53+~A) z+r!So6&SrKJU~%-fk}MkpS=fS4n>_JNFJ0R14@)Z#rlb^?#}udZt!&Nbf%UZthWVv zI_n%3F|Oc)rP;>7y{W|?jO185hFp#T5? literal 0 HcmV?d00001 diff --git a/users/migrations/__pycache__/__init__.cpython-311.pyc b/users/migrations/__pycache__/__init__.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..19895a71415d819322c65919fdf8a3c46afc6f3d GIT binary patch literal 182 zcmZ3^%ge<81f6{LsUZ3>h=2h`DC095kTIPhg&~+hlhJP_LlF~@{~09t%TqtJIJKx) zzbHQ=F|Rl=H8n-wCAB!aB)>pECo`!iv8YlvH!&|UJvBEquSCBTtTs0@y(qCHGe56b xKR!M)FS8^*Uaz3?7l%!5eoARhs$CH)&}5L^#r#0x12ZEd;|B&9QN#=s0|4k3Esg*H literal 0 HcmV?d00001 diff --git a/users/models.py b/users/models.py new file mode 100644 index 0000000..03c46e1 --- /dev/null +++ b/users/models.py @@ -0,0 +1,13 @@ +from django.db import models +from django.contrib.auth.models import AbstractUser + + +class User(AbstractUser): + date_of_birth = models.DateField(null=True, blank=True) + phone = models.CharField(max_length=15, blank=True, null=True) + gender = models.CharField(max_length=10, choices=[( + 'Male', 'Male'), ('Female', 'Female'), ('Other', 'Other')], blank=True, null=True) + is_librarian = models.BooleanField(default=False) + + def __str__(self): + return self.username diff --git a/users/tests.py b/users/tests.py new file mode 100644 index 0000000..7ce503c --- /dev/null +++ b/users/tests.py @@ -0,0 +1,3 @@ +from django.test import TestCase + +# Create your tests here. diff --git a/users/urls.py b/users/urls.py new file mode 100644 index 0000000..40984b2 --- /dev/null +++ b/users/urls.py @@ -0,0 +1,9 @@ +from django.urls import path, include +from . import views +urlpatterns = [ + path('signup/', views.signup.as_view(), name='signup'), + path('login/', views.user_login.as_view(), name='login'), + path('logout/', views.user_logout.as_view(), name='logout'), + path('profile/', views.profile.as_view(), name='profile'), + path('', views.signup.as_view(), name='main') +] diff --git a/users/views.py b/users/views.py new file mode 100644 index 0000000..67c5cbf --- /dev/null +++ b/users/views.py @@ -0,0 +1,58 @@ +from django.shortcuts import render, redirect +from django.contrib.auth import login, authenticate, logout +from django.views import View +from .forms import SignUpForm, LoginForm, ProfileUpdateForm + + +class signup(View): + def post(self, request): + form = SignUpForm(request.POST) + if form.is_valid(): + form.save() + username = form.cleaned_data['username'] + password = form.cleaned_data['password1'] + user = authenticate(username=username, password=password) + login(request, user) + return redirect('book-list') + return render(request, 'signup.html', {'form': form}) + + def get(self, request): + form = SignUpForm() + return render(request, 'signup.html', {'form': form}) + + +class user_login(View): + def post(self, request): + form = LoginForm(data=request.POST) + if form.is_valid(): + username = form.cleaned_data['username'] + password = form.cleaned_data['password'] + user = authenticate(username=username, password=password) + if user is not None: + login(request, user) + return redirect('book-list') + return render(request, 'login.html', {'form': form}) + + def get(self, request): + form = LoginForm() + return render(request, 'login.html', {'form': form}) + + +class user_logout(View): + def get(self, request): + logout(request) + return redirect('login') + + +class profile(View): + def post(self, request): + user = request.user + form = ProfileUpdateForm(request.POST, instance=user) + if form.is_valid(): + form.save() + return render(request, 'profile.html', {'form': form}) + + def get(self, request): + user = request.user + form = ProfileUpdateForm(instance=user) + return render(request, 'profile.html', {'form': form}) From b1f74c5c381dc7f1d096b425dc1516e60e92fbde Mon Sep 17 00:00:00 2001 From: RohanSaeed Date: Mon, 6 Nov 2023 10:05:04 +0500 Subject: [PATCH 2/3] changes made in library management system --- .gitignore | 17 +- db.sqlite3 | Bin 184320 -> 0 bytes library/__pycache__/settings.cpython-311.pyc | Bin 3478 -> 0 bytes library/__pycache__/urls.cpython-311.pyc | Bin 1261 -> 0 bytes library/__pycache__/wsgi.cpython-311.pyc | Bin 695 -> 0 bytes .../__pycache__/admin.cpython-311.pyc | Bin 794 -> 0 bytes .../__pycache__/apps.cpython-311.pyc | Bin 578 -> 0 bytes .../__pycache__/models.cpython-311.pyc | Bin 4145 -> 0 bytes .../__pycache__/serializers.cpython-311.pyc | Bin 2152 -> 0 bytes .../__pycache__/urls.cpython-311.pyc | Bin 1883 -> 0 bytes .../__pycache__/views.cpython-311.pyc | Bin 10281 -> 0 bytes library_management/admin.py | 4 +- library_management/forms.py | 22 --- library_management/migrations/0001_initial.py | 24 +-- .../__pycache__/0001_initial.cpython-311.pyc | Bin 4084 -> 0 bytes .../__pycache__/__init__.cpython-311.pyc | Bin 195 -> 0 bytes library_management/models.py | 31 +-- library_management/permissions.py | 24 +-- library_management/serializers.py | 44 ++++- library_management/urls.py | 16 +- library_management/views.py | 187 ++++++------------ users/__pycache__/admin.cpython-311.pyc | Bin 374 -> 0 bytes users/__pycache__/apps.cpython-311.pyc | Bin 540 -> 0 bytes users/__pycache__/forms.cpython-311.pyc | Bin 2393 -> 0 bytes users/__pycache__/models.cpython-311.pyc | Bin 1173 -> 0 bytes users/__pycache__/urls.cpython-311.pyc | Bin 981 -> 0 bytes users/__pycache__/views.cpython-311.pyc | Bin 4116 -> 0 bytes users/migrations/0001_initial.py | 2 +- .../__pycache__/0001_initial.cpython-311.pyc | Bin 4112 -> 0 bytes .../__pycache__/__init__.cpython-311.pyc | Bin 182 -> 0 bytes 30 files changed, 130 insertions(+), 241 deletions(-) delete mode 100644 db.sqlite3 delete mode 100644 library/__pycache__/settings.cpython-311.pyc delete mode 100644 library/__pycache__/urls.cpython-311.pyc delete mode 100644 library/__pycache__/wsgi.cpython-311.pyc delete mode 100644 library_management/__pycache__/admin.cpython-311.pyc delete mode 100644 library_management/__pycache__/apps.cpython-311.pyc delete mode 100644 library_management/__pycache__/models.cpython-311.pyc delete mode 100644 library_management/__pycache__/serializers.cpython-311.pyc delete mode 100644 library_management/__pycache__/urls.cpython-311.pyc delete mode 100644 library_management/__pycache__/views.cpython-311.pyc delete mode 100644 library_management/forms.py delete mode 100644 library_management/migrations/__pycache__/0001_initial.cpython-311.pyc delete mode 100644 library_management/migrations/__pycache__/__init__.cpython-311.pyc delete mode 100644 users/__pycache__/admin.cpython-311.pyc delete mode 100644 users/__pycache__/apps.cpython-311.pyc delete mode 100644 users/__pycache__/forms.cpython-311.pyc delete mode 100644 users/__pycache__/models.cpython-311.pyc delete mode 100644 users/__pycache__/urls.cpython-311.pyc delete mode 100644 users/__pycache__/views.cpython-311.pyc delete mode 100644 users/migrations/__pycache__/0001_initial.cpython-311.pyc delete mode 100644 users/migrations/__pycache__/__init__.cpython-311.pyc diff --git a/.gitignore b/.gitignore index 49f1a84..a1a43d4 100644 --- a/.gitignore +++ b/.gitignore @@ -1,8 +1,21 @@ +# Created by https://www.toptal.com/developers/gitignore/api/django +# Edit at https://www.toptal.com/developers/gitignore?templates=django + +### Django ### *.log *.pot *.pyc -__pycache__ +__pycache__/ +local_settings.py db.sqlite3 +db.sqlite3-journal media -venv/ + +# Environments .env +.venv +env/ +venv/ +ENV/ +env.bak/ +venv.bak/ diff --git a/db.sqlite3 b/db.sqlite3 deleted file mode 100644 index 708bb54cc954912a15e20a4e5ccc4d9a97901f5f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 184320 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 V1V8`;K;XqDaMm&B>AnB|{{gB{Mppm; diff --git a/library/__pycache__/settings.cpython-311.pyc b/library/__pycache__/settings.cpython-311.pyc deleted file mode 100644 index 0ea90e8d9452ab2c15dfcd36b206508733ddf4c4..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3478 zcmb6b&2QV*{ZZedMOl^=MR5{GuJd7MG3B;N+YPA~S)v^+vgAo}yb%QmTJKq=Es_dJ zIWtchkVCf>Sb!eZLk~d@8HWBdc443fPX>0{O+a_*W&1r!vSm5IGJZV1_xt{QkALSl z7QyxPf0oE!#u54_T@0>3fAZ768HE0ZFcJ}Fu&2q041B#!kLne@Ob_N0eI7)7yZ!<5 zTbO)5SRgSljC&J2LkvwWa)4Z)7y_9A?0*aTzlXPXiD4WNSsWC{Tx@6r8*!oG5hw>x zFNt1+z5$OfUl;AzjSVQyXW|5A#W+|n*+62Vf$-ROjCcjU5%?xCCtk%-Jln(WGI4#cL8Sw-B0Z5&tvBI9DbFAkHD~-BB5hQKiZeL`SkG3go8?O0UhcIRr2Z_Nkog}z`_ z!MI6Y%8&y$LW*_3S81qVvUY~EACB75x11m1ul8U=T=SQeKqacW#^>D6{~$GuZ9WIX zbA`MdBK>s478&9`Y)2N>5Co;}Hp&p=s1t)I4>PazB0t3S$vd2AD)qfxC{1Wq{&y=h z%;gsCN^^)W($5RuHkziL=}WPQ+G@g1a9-?vMBd#LYJIfnga?$6VYi6>U`f!kPbg z9!m2?Q?ba$HVeT1eBR>(gwkrEBsjiOc1ib9%r-eZRs z(~If*^tKl+??yb`bzpbVuw)RcZD{a;lMmC)3)#VpO0Xhl9KZXWpL2qe1V@-8IUe0~ zf-N{Js7x>9%?T21Ujb>3SJ3tyFRYx9L1Zk^8P_`i`o(4VC`13;ST9#<13VlSQmt4u z=jphO`_qB|;R48p#tH}{DXXu*yM8);}c3*=Co4qFv+6`>|Q6Mpab^TP7Rs>5ZA z#qy?*caNp26D^dgH2?tsD!S^hYlVEiC~Rgcf)lBf%Qb1EQp}Z0D^9p3tgRQbHKFRn zHmj=zN?$DGvb6Y}a6VhhQnghlmEEX4l?I2I^gLTE0J01{Gwx#OxhJia^Fq<#irLcY zMs`(@aTu!1&q_|fbzKBkYM?4d&2i#+VI{j!tVtlSEUgrTV%`bm zD&^8|%F9(Jye8xeS(ng96XE!FbwvZuTrlCQr;g z_}j?zD`MgNd>Vkxeh&E7!Ox+`P+aXMSu&PDApNB^SvcvtUWQ@19+vTS5gk&9VLM@Z zpP)k>@_P0#dG9DbcO0MVjGrX0y{;clWsZ`I$H~P*G}#TINbJjp zuS0)Y`fBONv6&ynW{$>YkLh#&c< z@9s33yww@+vS=dJ;Z7qHo$%?{cqeoUUIw}m6uk;wuqgTH5XHfFe~tn6hz9}^>W6&% sVxSW=x{%39pyra0R&M;O&A)!}=P$mQd$W4PJvinbbXa;DkD(_13+#$ef&c&j diff --git a/library/__pycache__/urls.cpython-311.pyc b/library/__pycache__/urls.cpython-311.pyc deleted file mode 100644 index a78759719665940d1e23b8fa7bdfacf91a6ce432..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1261 zcmb7Dzi-n(6h1qbA9Yo#b|A1Fs*qzTwMAQ&sDKcqq7v!=bjgxl?Mvcd`>Z<$Xa>}g z31z4Re*h{%{4OIT zw@T(*egfwM@=z0bnx_X^s5f;@`Guem;wBD@&7y{M#IT2%-YewjlI=?Hy=duA!J z2y4+RooTQG_so8SE2p^1-*BBmv*Im0N0vd~LK5TP*;C^3sO@+9f+jwXNSg~1_(y_@ zV-gGAV{T#_#)~c^hkX&mG)b6<;gr|1tWe0Y~hSI z4j7e;NX8ll0qZ77EE|sFaaY=2k47Dyr*nDeu*li6H=KmWzAGICb|AfUjK^aX6{rH{Duh>|*lx`< z>sei09CdB&ik{MHim!{I39&%HH);fRyJnsnjMF&8lH>Hu=TVl|E%^X z;2j4Vm}fFoAmueJ%lNJ)+0rIO>VCg*2ia7P2TwxA(1uNx9X6(Q36O*RpD$35kHghHn>57UxP77$Tym!dUtVn_yM= zWN~g7zMxCkMpxU;fzsdz-ldVGjCsxulP_UPolMI5PbqmQ9b7v;zN&18-0KJIzE}n_ z^(D*quuKb@rcL!_4Ns9;2-0qyBQk$opxfuayQU>nTsYZzcVl?>v~l`igxAJ+?E+UI zR2`Z_^J9IqYK~XU5w4AKZMJcJSRGc+Z*GiMHpeTQBfK@nThlUL)=w7IPb`6?9}p9E Aga7~l diff --git a/library/__pycache__/wsgi.cpython-311.pyc b/library/__pycache__/wsgi.cpython-311.pyc deleted file mode 100644 index 1e5f647cf586504491f3eaf3d668ecac3a88cec9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 695 zcmY*XOG_L<5U!q4HyPt1A$kim;zh{LB$88*K%z!A4?V1su$S3(x^{LpJ>A1}tI?B( zKz>55IT?a~W(|Tcr-htyTkz&7J^O%7^|PwGzVEB1e=aO|VD0g{8h#@He@bU!Gvm!| z$8Np@hbC~s9YLDJuC8!Wx9Ji<(w*FdAG4F>>6Op$*$W5Y(vFc4Z~)y4>s(Gk(46B= z1J>rwZoH3;ojQ$_Y$q{otDK7DFlYHG&2rVn$oQUDHx$2QN~5NxgLIU@gkXmPDbtkE zRPiH$HG#({=rPNa;gMu1a@uOKEE7q@Orm6~W%1rvmQ>|P6KM(4;Q>|Bf+w1`6M;{t zM)W$yWco!Aa208vcbSaUL{p^F0A=vpUk^I!#HfH{Ce&$)(gY_uP6F?5S?cZ@DIUdW z!ZH?4$tae$-oD!1*$W%n`}_6XoksX!Z|mUw_SxdNdS9b4iH!AHrKp6Vl@Nx7qja%2 z65>ZzzhA=Ut|cleD36m|$-=XV9NX+jm|}j4@fX~ditaXo1C6;3a@Ao{GejP2q5f=C z7L2KDDU&S5VJ+j(uqHn{y}P$Ddg+&W)q>eS1p1Sm1}-6F;8e)W0Ltkh5bykc+4}IT v_kZt$^VPe7rQfjBTlRZTUthuIHEi}^vtM25RadU6tJl@l^ZByn4=ngUcM{BC diff --git a/library_management/__pycache__/admin.cpython-311.pyc b/library_management/__pycache__/admin.cpython-311.pyc deleted file mode 100644 index 95405e2abd7c90881ede1ff31711f2bb7f545297..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 794 zcmbVJJ5R$f5I&PfOHo0HsY_e2Wq?Y|2qe^jhhX5bWPyNBB{WXJPKDU{0c@;HAjA*g zZzL!Z$P*G%w@PfCuz{e!gnBxk@B6Ip?DO4Ks})doFu9Bl0eI6OH{&~bUr;C4K!K6~ z7;y;!I!29Pj2W)MOxI+VYcbokS;;LCKyp&fOWcg-S#d|>R#kjZ>&yP7F-Oo?BWUaq zG^M{9YVLqz^>up=k(Ni9ANF;>jwQ{NDC){_9oK~Dp`6g^HlFoR#Io`Q;vNrWbqmim z-1U#T7;iZhIZ02vuoKN6MPbbSL#{_8Z5B}s1h*96whkp7^bolIe`yLoMp@?A@kNaM z9^MrT!`0TFKrUK5I`%^0A<|YGMK_L4TY;+W@rya;gTN4|gJxqZvL$|KSX<;J|u!3Y=_hyu?=hD;?x zp)%)ClC5*A7m#4kAuchQ!`vvNy5FWZ#5FyQ_B6+%%nr3<%RGuB@6=*8O=@VbDn z+>kIv^%e_nBhT0Ks?G1J%cmb7(TVSenm-7{cvGct5H`3PuGX}%KT+z_^3Jd&R#08W zc2zkk=gkYEKny;kstA+@Zg8|H9%LOJ2AkXz^A69rn#l;EDeO&t@7bD!c4zQcJy{>( K_46NBTI>r@+L%iK diff --git a/library_management/__pycache__/models.cpython-311.pyc b/library_management/__pycache__/models.cpython-311.pyc deleted file mode 100644 index b30d9689fbe705ed257d074348f2a1cb44a01e51..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4145 zcmcha&2JmW6~K4N<;QYKks%oiuq8)T+z5=UueMTZS9PPvVx&5zQ;W`lhb&f_iA0)Q zDzi%`atoA)9)zMOco5(ML4h0sSAuoWAq8^iA%DUW*aNZXAwW(JdY~Yka%tb2B}I{@ zWv2x?Kd;4}~=l9+W{}zda1Sns4entNk5QJ~B(JsDL<@ldac_a{lh()0!=0p+e zo}#DZ&3Q$^BfKjR?;ivrQL!MkZ+`3*geP#hCFkQ-KCtqiW98>o0k8_5V-?_5GFXMq zu?li41+2p7Sji-^Dx?OU;xJR9<1dv7EgDdh?irM=w}#JuPG84Ap!rCkLQW(?&f^iN zw=-=b9(W#$Fm<@xf>VEi1x)(|7BFS72)2C^FOi6J;OlwGGPmLjik8HG5a=0;LV_?| z*^%BUm+wC%V6-nfp_2BgTBQ1hx%tq)1`1;;oANqxWvf`$h-#J{Nv{-(j&H4~>Gzq( zy(>WIM_Q$5W>R4%sH(bFqN?hIR25!frHJ*gs(xJ2imrws3y!?Fsj+mP776%-I~>1O zF*nQ1k+&*q#k{denG;$mX&clv^5wDaB;PL^c{BfjuIMJ+pe+wU@UEMAb9-Mn2Is=} zD^s{=#uO`WYPz9ON~Ug7FP=&JiL>(!^3;QL-XsOS>fe+c-amwSC<;mH+LS`(Kiogtmte#I%`K~ ztIPOdm)fK00)2;2e0NMU+T@ug{SY-xb5CP{3C%>na2-HEEim`%EgvqVUUN zC|*Iq*$bu1jOI7=TXdV@gq^_R!s_C}%_T>w05*KJ9SQk&i#PzjfJ0cj+!i=gzCZu;Zik_!T>TrFyH;+m4PRQlopbR&=Hwow1`c)#XNV ztd_QuV~0K~Iag24*~z);ZTz^y#1VFJcAEIU0ZoT9BIdlXVp5^47pNavu#30_5@9!M zkdeEr<#Vk=+*)aSBi;k4hZiJDDs+ef(s{~*)jqTHAXQQUf#3yFr}rS(GqMBkjnnET$8#|gYob&}UN*d(}sc5q>9i09qcs_ zS=d9uklf0uUj9VY2zi=B6?)kBG8ulH!1`u6zfKJ{0IigVh0y>fynecQKm*yu>-gs& z9tpn_3h?We!l~V7us4I|G_DJH2QQxqfAzwwJeh}~5$4Xx7)eR&bGn1`ObY$R+t3o4wVK)UFTG6-RdnkP=e>vdR zt>D`nu1qT46PwP3yGy^hx3rp7SF;P*d#mc=@|~5%rBxoY>__022P+%J8a~TS%{X2s zf?=A?ms+73Zq1K}CyS$n-!L_^VmNY^ermdb8e@E|@{lzc)r_*vuA$eSFujU>C@#Qd z{2fFmOq(9*vfq*}HbVlW@*fzmiLu(8oftdJT8ZoR#C1Dyz4~5z?`R}mwO*V3YP;zb z2YxLc2`Epvtfs#i9IHLB2gmlvS4nH|Mt$&xJ$S>Cl1)kUEr?B_zjPxS=dljgX^~pB z<3B^C6VVVUXO1%e&z*yKApXJxNtK+COBrTb9!mYg0SV|1hgJ}r2?|7iAJF%XOpHK) zaeVMT_7;dUgmVNQ#yih#!;NpwKr~u#ThVd&elC3>yEQ8~-r_pa!}Uw>%YKYQ8AH(z z!39*HKnsI{=pgv~4dG>X3gqT0V$&;JWbnCN$h4Du4>JGdCV=^mmp*CTP5d2;{%IXf zvK$#1kO?`F4E+RGFPmS#Pfa!fzBxKi|BW>~H?yCh!1T+03gUlbiYE*K~rbD)j;+H7; z0k?z-6u5~QzX#C)4szZo;Ta;%dJrUxQ4|}(kk$Qd2*XzQx9RtZb4}q{u`~Cl`6KK<=_q4<@vWxttf={S z!$;VE(ox0-M9k^^W$lgKt4CaSa@JzhFG46kD{2>ZhtU63^xv|GhedeT&x%@l_q`+R KKk1|7tMMPPyMaRh diff --git a/library_management/__pycache__/serializers.cpython-311.pyc b/library_management/__pycache__/serializers.cpython-311.pyc deleted file mode 100644 index d918d977461d1e640fa6de2b50bedabcb24530ad..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2152 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 H>dF5fI6so_ diff --git a/library_management/admin.py b/library_management/admin.py index 7f115cd..3834417 100644 --- a/library_management/admin.py +++ b/library_management/admin.py @@ -1,10 +1,8 @@ from django.contrib import admin -from .models import Book, BookIssue, BookRequest, BookReturn, NewBookTicket +from .models import Book, BookIssue, NewBookTicket # Register your models here. admin.site.register(Book) admin.site.register(BookIssue) -admin.site.register(BookRequest) -admin.site.register(BookReturn) admin.site.register(NewBookTicket) diff --git a/library_management/forms.py b/library_management/forms.py deleted file mode 100644 index 4cd578f..0000000 --- a/library_management/forms.py +++ /dev/null @@ -1,22 +0,0 @@ -from .models import Book, BookIssue, NewBookTicket -from django import forms - - -class BookSearchForm(forms.Form): - q = forms.CharField(label='Search for books', required=False) - - -class BookReturnForm(forms.Form): - book_issue = forms.ModelChoiceField(queryset=BookIssue.objects.filter( - returned=False), label='Select a Book to Return', empty_label='-- Select a Book to Return --') - - -class BookRequestForm(forms.Form): - book = forms.ModelChoiceField(queryset=Book.objects.all( - ), label='Select a Book', empty_label='-- Select a Book --') - - -class NewTicketForm(forms.ModelForm): - class Meta: - model = NewBookTicket - fields = ['user', 'book_name'] diff --git a/library_management/migrations/0001_initial.py b/library_management/migrations/0001_initial.py index 359f5ee..91138b2 100644 --- a/library_management/migrations/0001_initial.py +++ b/library_management/migrations/0001_initial.py @@ -1,4 +1,4 @@ -# Generated by Django 4.2.6 on 2023-10-30 02:01 +# Generated by Django 4.2.6 on 2023-11-05 23:47 from django.conf import settings from django.db import migrations, models @@ -29,27 +29,7 @@ class Migration(migrations.Migration): name='NewBookTicket', fields=[ ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('book_name', models.CharField(max_length=255)), ('status', models.CharField(choices=[('Pending', 'Pending'), ('Approved', 'Approved'), ('Rejected', 'Rejected')], default='Pending', max_length=20)), - ('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)), - ], - ), - migrations.CreateModel( - name='BookReturn', - fields=[ - ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('return_date', models.DateField()), - ('book', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='library_management.book')), - ('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)), - ], - ), - migrations.CreateModel( - name='BookRequest', - fields=[ - ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('request_date', models.DateTimeField(auto_now_add=True)), - ('status', models.CharField(choices=[('Pending', 'Pending'), ('Approved', 'Approved'), ('Rejected', 'Rejected')], default='Pending', max_length=20)), - ('rejection_reason', models.TextField(blank=True, null=True)), ('book', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='library_management.book')), ('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)), ], @@ -61,7 +41,7 @@ class Migration(migrations.Migration): ('issued_date', models.DateField()), ('return_date', models.DateField()), ('returned', models.BooleanField(default=False)), - ('reminder_sent', models.BooleanField(default=False)), + ('status', models.CharField(choices=[('Issued', 'Issued'), ('Pending', 'Pending'), ('Rejected', 'Rejected')], default='Pending', max_length=20)), ('book', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='library_management.book')), ('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)), ], diff --git a/library_management/migrations/__pycache__/0001_initial.cpython-311.pyc b/library_management/migrations/__pycache__/0001_initial.cpython-311.pyc deleted file mode 100644 index 18b931a43414bfe8fa232edcd5af90757dd076ec..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4084 zcmdT{O;8(07M>aXjefuq!N>wj7T7ozRDfhxTk$$;LJ$rln79lkyUJm9P&Z=4Xh!K7 z;o!rT4|~{SZp+cN2X?o@fx{j+`j}&@Y7SJNQne@F>gjY|jfJ^QSSX7~C`(8z2P6RpYrf3_4j?PkaoUEmMzUJm9@74U+3$=Ir+2c{(x%#?)t5P+1hR@jx z_?&ZX?Dcov2If1zBR~wU{ahbV{!Po#{|k}93m`J&dVJXj0f{@;Pi7suNEY01_4OU; z1C7HcWBMz>`K({t%?sfC?irbPR%YIE*QXD04Zc|&P~jXhzm5!#oczsKL**-I1Wue$ z7QOEuFH0==iD|AgNkjLTG*>DFSwd~vrcxnTwJ~Dx2GQy&*;Ll?CW~5_XsWI~!7Q*1v!0z09rW6Vs-T!MaM?fUSnZUwq_C*Z8TSO&052Rg+N~wKMAkEzSejl zz(Om!YOI5frmnMSv!R6Sl0r6 z%)MCBD(l#0QLfpw>&5?EG0Rr%rd0^Q!5Vph4FrcQxyDsWOrB~qh`E6g$#(`G;u@}i z=VTBDT(K9t*nypq%9^QFuthR_hF4}5Yyu*nCTbcA9MagvOajYe+?t2jZW4pViThR% zz{!H#v?pm@TOl0Nx@rIvb!^yUe1gTjbze8JWwQjqF5|8Q@4dJf=3_-gh$V?@C)^Me zh?Hd-017Wbgx3ug<%;GktBF}$<1ggxFMGy7T)POaYX-tZv0(d!LWaqTiB*c?w6kMDh8TCo2H zo-=G*#lFNnlVGiCd=42JMm5!_noL3~Om-sz2(ifY)Z+A1X@*5h5CuDw@^@g9$w_`%|8lTJUr_w*9F4OeLw;N7+WH0#r4O&*HL1@})r7b6I(WDJB zG*j5>b25e9MVh(Y%G`D`w`ubC`>6~a7~T4vGcdYq(SbXyfjiE?9h&@TKXsMn#xKub%pkiZrybHM|W@REq(t-+P~cDUv~PJY4Xec)Bw$XxV7wL zKYX5|+38kx+R0ASWU1X1>FsWZV$s-30muO-?Y<)y^5<~jtp**s&=!Q^lyriAE-mpP zRjTmURV2N1>48gOB!wjxo)Heu$nNrg{^S&AoZ^C0T&7=DoUbgJv0EA2$=Ed6Y)3=f z51IP`?`H5#?CqL23f8gXlpvm97eSe!~nypOJ$uwzlH8Xb( zGq2IX;wO^4@O!}HGY zJWbwzyNf>;i8B)K>N$`&EnugOLGDlR+@ILHOtX`%?4*;Oq{)x>Q+Ya6e0I|rD(+!A zRB8>CoS_m;&iwMuUXpos#(8!EIpCzdC>DFdPe0=yGUu0^g3RJx{T!>9#;RAzqn#17 z;ud|cT4xRi$Gm^1V}7kAlfE`G%Q;v1XTbd^f8-r1cgX^D`QK2>2GS0Qq6kGz9Hc`2 k_;+8pMNj+g9}{bb{~(6j!kgsVn3KHml206*GV5CP6Q*VXF8}}l diff --git a/library_management/migrations/__pycache__/__init__.cpython-311.pyc b/library_management/migrations/__pycache__/__init__.cpython-311.pyc deleted file mode 100644 index 3ef11548fc1e8d89db71da5bf26df2b755a5d255..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 195 zcmZ3^%ge<81a*A&sUZ3>h=2h`DC095kTIPhg&~+hlhJP_LlF~@{~09tD@;GMIJKx) zzbHQ=F|Rl=H8n-wCAB!aB)>pECo`!iv8YlvH!&|UJvBEquLLF(k0g|vnO>Awl9``Z ytREkrnU`4-AFo$X`HRCQH$SB`C)KWq6=)5}A;tVa;sY}yBjX1K7*WIw6axU-oifh= diff --git a/library_management/models.py b/library_management/models.py index 600ac1d..f49d7a9 100644 --- a/library_management/models.py +++ b/library_management/models.py @@ -1,3 +1,4 @@ +from django.conf import settings from django.db import models from users.models import User @@ -11,38 +12,18 @@ class Book(models.Model): class BookIssue(models.Model): - user = models.ForeignKey(User, on_delete=models.CASCADE) - book = models.ForeignKey(Book, on_delete=models.CASCADE) - issued_date = models.DateField() - return_date = models.DateField() - returned = models.BooleanField(default=False) - reminder_sent = models.BooleanField(default=False) - - -class BookRequest(models.Model): REQUEST_STATUS_CHOICES = ( + ('Issued', 'Issued'), ('Pending', 'Pending'), - ('Approved', 'Approved'), ('Rejected', 'Rejected'), ) user = models.ForeignKey(User, on_delete=models.CASCADE) book = models.ForeignKey(Book, on_delete=models.CASCADE) - request_date = models.DateTimeField(auto_now_add=True) + issued_date = models.DateField() + return_date = models.DateField() + returned = models.BooleanField(default=False) status = models.CharField( max_length=20, choices=REQUEST_STATUS_CHOICES, default='Pending') - rejection_reason = models.TextField(blank=True, null=True) - - def __str__(self): - return f'{self.user.username} requests {self.book.name}' - - -class BookReturn(models.Model): - user = models.ForeignKey(User, on_delete=models.CASCADE) - book = models.ForeignKey(Book, on_delete=models.CASCADE) - return_date = models.DateField() - - def __str__(self): - return f'{self.user} - {self.book}' class NewBookTicket(models.Model): @@ -52,7 +33,7 @@ class NewBookTicket(models.Model): ('Rejected', 'Rejected'), ) user = models.ForeignKey(User, on_delete=models.CASCADE) - book_name = models.CharField(max_length=255) + book = models.ForeignKey(Book, on_delete=models.CASCADE) status = models.CharField( max_length=20, choices=BOOK_TICKET_STATUS_CHOICES, default='Pending') diff --git a/library_management/permissions.py b/library_management/permissions.py index 9c84cd7..902f3f5 100644 --- a/library_management/permissions.py +++ b/library_management/permissions.py @@ -3,24 +3,6 @@ class IsStaffEditorPermission(permissions.DjangoModelPermissions): def has_permission(self, request, view): - user = request.user - if user.is_librarian: - if user.has_perm("library_management.add_book"): - return True - if user.has_perm("library_management.view_book"): - return True - if user.has_perm("library_management.delete_book"): - return True - if user.has_perm("library_management.change_book"): - return True - - if user.is_librarian == False: - if user.has_perm("library_management.add_book"): - return True - if user.has_perm("library_management.view_book"): - return True - if user.has_perm("library_management.delete_book"): - return False - if user.has_perm("library_management.change_book"): - return False - return False + if request.method == 'GET': + return request.user and request.user.is_authenticated + return request.user and request.user.is_authenticated and (request.user.is_librarian or request.user.is_staff) diff --git a/library_management/serializers.py b/library_management/serializers.py index 4047451..228e2d2 100644 --- a/library_management/serializers.py +++ b/library_management/serializers.py @@ -1,26 +1,52 @@ from rest_framework import serializers -from .models import Book, BookIssue, BookRequest, NewBookTicket +from .models import Book, BookIssue, NewBookTicket class BookSerializer(serializers.ModelSerializer): class Meta: model = Book - fields = '__all__' + fields = ['name', 'author', 'publisher', 'image', 'quantity'] -class BookIssueSerializer(serializers.ModelSerializer): +class UserIssueSerializer(serializers.ModelSerializer): class Meta: model = BookIssue - fields = '__all__' + fields = ['id', 'user', 'book', + 'issued_date', 'returned', 'return_date'] -class BookRequestSerializer(serializers.ModelSerializer): +class LibrarianIssueSerializer(serializers.ModelSerializer): class Meta: - model = BookRequest - fields = '__all__' + model = BookIssue + fields = ['id', 'user', 'book', 'issued_date', + 'returned', 'return_date', 'status'] + read_only_fields = fields -class BookTicketSerializer(serializers.ModelSerializer): +class LibrarianUpdateIssueSerializer(serializers.ModelSerializer): + class Meta: + model = BookIssue + fields = ['id', 'user', 'book', 'issued_date', + 'returned', 'return_date', 'status'] + read_only_fields = ['id', 'user', 'book'] + + +class UserTicketSerializer(serializers.ModelSerializer): class Meta: model = NewBookTicket - fields = '__all__' + fields = ['id', 'user', 'book', 'status'] + read_only_fields = ['status'] + + +class LibrarianTicketSerializer(serializers.ModelSerializer): + class Meta: + model = NewBookTicket + fields = ['id', 'user', 'book', 'status'] + read_only_fields = fields + + +class LibrarianUpdateTicketSerializer(serializers.ModelSerializer): + class Meta: + model = BookIssue + fields = ['id', 'user', 'book', 'status'] + read_only_fields = ['id', 'user', 'book'] diff --git a/library_management/urls.py b/library_management/urls.py index 140bfef..b6e6cb4 100644 --- a/library_management/urls.py +++ b/library_management/urls.py @@ -1,17 +1,13 @@ from django.urls import path from . import views urlpatterns = [ + path('', views.BookList.as_view(), name='book-list'), - path('book_search//', - views.BookSearchView.as_view(), name='book_search_results'), path('/', views.BookDetail.as_view()), + path('issues/', views.BookIssueList.as_view(), name='issues'), - path('requests/', views.BookRequestList.as_view(), name='requests'), - path('book_request/', views.BookRequestView.as_view(), name='book_request'), - path('book_return/', views.BookReturnView.as_view(), name='book_return'), - path('my_books/', views.MyBooksView.as_view(), name='my_books'), - path('new_ticket/', views.NewTicketCreateView.as_view(), name='new_ticket'), - path('my_tickets', views.BookTicketView.as_view(), name='my_tickets'), - path('dashboard/', views.librarian_dashboard, - name='librarian_dashboard'), + path('issues//', views.BookIssueDetail.as_view()), + + path('tickets/', views.BookTicketView.as_view(), name='tickets'), + path('tickets//', views.BookTicketDetail.as_view()), ] diff --git a/library_management/views.py b/library_management/views.py index 3edeca8..e984c9f 100644 --- a/library_management/views.py +++ b/library_management/views.py @@ -1,24 +1,7 @@ -from .models import BookRequest -from .forms import NewTicketForm -from .models import BookIssue, BookRequest, BookReturn, NewBookTicket -from .forms import BookReturnForm -from .models import BookIssue -from .forms import BookRequestForm -from django.shortcuts import render, redirect -from django.views import View -from .models import Book -from django.views.generic import ListView -from django.shortcuts import render +from .models import Book, BookIssue, NewBookTicket from .permissions import IsStaffEditorPermission -from django.urls import reverse_lazy -from django.views.generic.edit import CreateView -from .models import NewBookTicket -from .forms import NewTicketForm from rest_framework import generics -from .models import Book, BookIssue, BookRequest -from .serializers import BookSerializer, BookIssueSerializer, BookRequestSerializer, BookTicketSerializer -from django.utils import timezone -from django.http import HttpResponse +from .serializers import BookSerializer, UserIssueSerializer, LibrarianIssueSerializer, LibrarianUpdateIssueSerializer, UserTicketSerializer, LibrarianTicketSerializer, LibrarianUpdateTicketSerializer class BookList(generics.ListCreateAPIView): @@ -26,6 +9,13 @@ class BookList(generics.ListCreateAPIView): serializer_class = BookSerializer permission_classes = [IsStaffEditorPermission] + def get_queryset(self): + queryset = super().get_queryset() + name = self.request.query_params.get('name') + if name is not None: + queryset = queryset.filter(name__contains=name) + return queryset + class BookDetail(generics.RetrieveAPIView): queryset = Book.objects.all() @@ -35,130 +25,75 @@ class BookDetail(generics.RetrieveAPIView): class BookIssueList(generics.ListCreateAPIView): queryset = BookIssue.objects.all() - serializer_class = BookIssueSerializer - - -class BookRequestList (generics.ListAPIView): - queryset = BookRequest.objects.all() - serializer_class = BookRequestSerializer - - -class BookSearchView(View): - template_name = 'book_search_results.html' - - def get(self, request, *args, **kwargs): - book_name = self.kwargs['book_name'] - books = Book.objects.filter(name__icontains=book_name) - return render(request, 'book_search_results.html', {'books': books, 'book_name': book_name}) - - -class BookRequestView(View): - template_name = 'book_request.html' - - def get(self, request): - form = BookRequestForm() - return render(request, self.template_name, {'form': form}) - - def post(self, request): - form = BookRequestForm(request.POST) - if form.is_valid(): - book = form.cleaned_data['book'] - max_requests = 3 - user_requests = BookRequest.objects.filter( - user=request.user, status='Pending').count() - - if user_requests >= max_requests: - return render(request, 'max_requests.html') - BookRequest.objects.create(user=request.user, book=book) - return redirect('requests') - - return render(request, self.template_name, {'form': form}) - - -class BookReturnView(View): - template_name = 'book_return.html' - def get(self, request): - books_issued = BookIssue.objects.filter( - user=request.user, returned=False) - form = BookReturnForm() - return render(request, self.template_name, {'books_issued': books_issued, 'form': form}) - - def post(self, request): - form = BookReturnForm(request.POST) - if form.is_valid(): - - book_issue_id = form.cleaned_data['book_issue_id'] - book_issue = BookIssue.objects.get(id=book_issue_id) - - book_issue.returned = True - - book_issue.return_date = timezone.now() + def get_queryset(self): + queryset = super().get_queryset() + queryset = queryset.filter(user=self.request.user) + return queryset - book_issue.save() + def get_serializer_class(self): + if self.request.user.is_librarian: + return LibrarianIssueSerializer + return UserIssueSerializer - return redirect('issues') - books_issued = BookIssue.objects.filter( - user=request.user, returned=False) - return render(request, self.template_name, {'books_issued': books_issued, 'form': form}) +class BookIssueDetail(generics.RetrieveUpdateAPIView): + queryset = BookIssue.objects.all() + lookup_field = 'pk' + def get_serializer_class(self): + if self.request.user.is_librarian: + return LibrarianUpdateIssueSerializer + return UserIssueSerializer -class MyBooksView(ListView): - template_name = 'my_books.html' - context_object_name = 'my_books' - def get_queryset(self): - user = self.request.user - issued_books = BookIssue.objects.filter(user=user, returned=False) - requested_books = BookRequest.objects.filter(user=user) - returned_books = BookReturn.objects.filter(user=user) +# class BookRequestView(View): +# template_name = 'book_request.html' - return { - 'issued_books': issued_books, - 'requested_books': requested_books, - 'returned_books': returned_books, - } +# def get(self, request): +# form = BookRequestForm() +# return render(request, self.template_name, {'form': form}) +# def post(self, request): +# form = BookRequestForm(request.POST) +# if form.is_valid(): +# book = form.cleaned_data['book'] +# max_requests = 3 +# user_requests = BookRequest.objects.filter( +# user=request.user, status='Pending').count() -class NewTicketCreateView(CreateView): - model = NewBookTicket - form_class = NewTicketForm - template_name = 'new_ticket.html' - success_url = reverse_lazy('my_tickets') +# if user_requests >= max_requests: +# return render(request, 'max_requests.html') +# BookRequest.objects.create(user=request.user, book=book) +# return redirect('requests') - def form_valid(self, form): - form.instance.user = self.request.user - return super().form_valid(form) +# return render(request, self.template_name, {'form': form}) -class BookTicketView(generics.ListAPIView): +class BookTicketView(generics.ListCreateAPIView): queryset = NewBookTicket.objects.all() - serializer_class = BookTicketSerializer + def get_serializer_class(self): + if self.request.user.is_librarian: + return LibrarianTicketSerializer + return UserTicketSerializer -def librarian_dashboard(request): - pending_requests = BookRequest.objects.filter(status='Pending') - return render(request, 'librarian_dashboard.html', {'pending_requests': pending_requests}) - - -def accept_request(request, request_id): - book_request = BookRequest.objects.get(pk=request_id) - if book_request.status == 'pending': - book_request.save(status='accepted') - - return redirect('librarian_dashboard') + def get_queryset(self): + queryset = super().get_queryset() + queryset = queryset.filter(user=self.request.user) + return queryset - return HttpResponse('Invalid request') +class BookTicketDetail(generics.RetrieveUpdateAPIView): + queryset = BookIssue.objects.all() + lookup_field = 'pk' -def reject_request(request, request_id): - book_request = BookRequest.objects.get(pk=request_id) - if book_request.status == 'pending': - book_request.status = 'rejected' - rejection_reason = request.POST.get('rejection_reason') - book_request.rejection_reason = rejection_reason - book_request.save() - return redirect('librarian_dashboard') + def get_serializer_class(self): + if self.request.user.is_librarian: + return LibrarianUpdateTicketSerializer + return UserTicketSerializer - return HttpResponse('Invalid request') + def get_queryset(self): + queryset = super().get_queryset() + queryset = queryset.filter(user=self.request.user) + return queryset diff --git a/users/__pycache__/admin.cpython-311.pyc b/users/__pycache__/admin.cpython-311.pyc deleted file mode 100644 index 99929f088ef2bf0fcaec7ffc7a3be409cafbd889..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 374 zcmY*Tu};G<5WTCDs45Ce7rL=#X!8LerbbbXozX)JZY8D|Bhn zTjTbrgS=3bS>p!Po=r=t+lG?VmSo;w!&TUx#LmLTrnr~dN+J~x$v%|DB+l4Jnpr=W zS|*f}F5~I$?{0;`WVUUe@`PzdXC`DXx05~RYb_9Q3CGobEa9lyk97bTJa!h){eo4GgO%weSeOD#fC5Dx_{c^G z6gUB@+yhk^dR776#45~IsCEv9{vksHW$WE2ItqiK>s*$Md_!fhXbCU@1~#G~?jl>I zimg#qXlPmOB4#`;uHS9bYZ5r2Ne8AMQs%|xq3d+hBs_MRM>9Q@+`ge_6^sMoGmNt; z#)6u964x=lO^H`#nv@Mm>Lr*60X)nVG?{yag?!p_&&q3CJiH=7Oc z;DnDlJ_(4!d=?~DUfUv36r0hA%f{tS6CiF2H~ty3_U=?`&1%hYPY&K#ar=gv)ygkQ zAud~5NYy3Ei5mhfEBnQ#4)~@BWhdiP;pQqrXa+me-*djEpshLlb&tlUJpKA7l^6R4 D$oz;8 diff --git a/users/__pycache__/forms.cpython-311.pyc b/users/__pycache__/forms.cpython-311.pyc deleted file mode 100644 index fa42cf8ebe27269168b617a1db259f5b9e94da45..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2393 zcmbVN&2Jk;6yMn|f5e-{Q5#BA650U52yCdJmsCh7vD+ZxAVMy_Sewk)-eB*#vul-H zXbv25;J~3$bLfdfAZiXhBJoeSQV!M}P$f>iIdV=p@!o7~*Xt-kj6FZi%zN|Z&F{T= z`@3Z&6=<_7i)>$0lz(v2Z^rqc_XGw{6{=8DR~n>52#(dd+R#c`Loewt*Qj1M8fM8P zN>!o8Z=@7cmHP@ce^zLWX$N5YIrOlV;!+j|S%T>iSwhN^Ae&%hTY87PB3ctPwXS5W z*C@&mVN^Wc@H48I+VB});>->l&n>{BnEt92)R-GMTZ6UNB;2K=az=w~`l?-LJdVq% zFbk}K(?mEm)?h#9=*brJL5rP_dL0-%RhUvDR4J*d!nAF@uSJQR_o)QhsOFF({Qz8e zj&8_yWE`k4haR?)DR=cx0OI8w{gVx>nE$~FPzk;aD5Qi<9K|9hrG}x1NGzHJiYG*J z-Kn}8O(e4*^kApSgih^%A?5xJMQplhxc%YqK8G4XiWr3ZEiFgY_=h_V>5>4CpA9ul{Fv( zbLg|5lc}0*?m*JPUHCPylZNiU2e3Q%b*8TF8C{i3-|Z@W*fa6RQIUTDP|Qs7Ih@QR zyo-QuOeB`!)&+Dl9Im*{R=|;FkyxtP{9N=sL?{%^qG)1C1}PLy-p?18^WT-19;~e_ z<=6R5G>&KT1qA8B`#4JV0n^O?3*e1ATwVAz|75L`p4orA-+K1=Mdi;*`-^;gzVLFs za6Dh=YUJ7ja-txfO59z2m73kl|8nUbOYQ-LJ%GFUSJvF##<4Z`hw!R zvPR7I3vLg&83qzd4kguL!I>E|6Y`Hw=n~fNf*9YUkMC)W^;_-q?J>^z9Z-#i@N-;4 z!025-@d8pD1*CWZDUJ$4iqTv#lM*J~w%w{17K*pSNp{O~1MX~QZTM7XWqslp0gj(7 zVam$q%QDD6#%1~DF=isMid7MLmi|UAau&ZAmeeo#B4{J~{@(!b?g{BA*W082j`DT; zqW`#NS68Q1AmJQ#C%efcfu}wW?ewh^Ts|GjZfFE@bR61Kx1lf)NYjBVr4e9r9QKW8 NS5O!D9v4c!{{=@?AeaCE diff --git a/users/__pycache__/models.cpython-311.pyc b/users/__pycache__/models.cpython-311.pyc deleted file mode 100644 index 85e6b332bf840a9c12f7effbdcb73bef422d2d70..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1173 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 diff --git a/users/migrations/__pycache__/__init__.cpython-311.pyc b/users/migrations/__pycache__/__init__.cpython-311.pyc deleted file mode 100644 index 19895a71415d819322c65919fdf8a3c46afc6f3d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 182 zcmZ3^%ge<81f6{LsUZ3>h=2h`DC095kTIPhg&~+hlhJP_LlF~@{~09t%TqtJIJKx) zzbHQ=F|Rl=H8n-wCAB!aB)>pECo`!iv8YlvH!&|UJvBEquSCBTtTs0@y(qCHGe56b xKR!M)FS8^*Uaz3?7l%!5eoARhs$CH)&}5L^#r#0x12ZEd;|B&9QN#=s0|4k3Esg*H From 2124812f66a5f50b6f3b71f093bfe04b8da11b61 Mon Sep 17 00:00:00 2001 From: RohanSaeed Date: Tue, 7 Nov 2023 11:07:06 +0500 Subject: [PATCH 3/3] worked on previous issues --- library/settings.py | 12 ++--- library_management/cron.py | 12 ++--- library_management/management/__init__.py | 0 .../management/commands/__init__.py | 0 .../commands/my_books.py} | 6 +-- library_management/migrations/0001_initial.py | 4 +- .../migrations/0002_alter_bookissue_status.py | 18 +++++++ library_management/models.py | 47 +++++++++++++++---- library_management/serializers.py | 26 ++++++++-- library_management/views.py | 37 ++++----------- users/migrations/0001_initial.py | 2 +- 11 files changed, 101 insertions(+), 63 deletions(-) create mode 100644 library_management/management/__init__.py create mode 100644 library_management/management/commands/__init__.py rename library_management/{managment/commands/import_books_from_csv.py => management/commands/my_books.py} (87%) create mode 100644 library_management/migrations/0002_alter_bookissue_status.py diff --git a/library/settings.py b/library/settings.py index bf9b89b..8c691e9 100644 --- a/library/settings.py +++ b/library/settings.py @@ -13,6 +13,7 @@ import os from pathlib import Path import environ +import certifi env = environ.Env() environ.Env.read_env() @@ -24,6 +25,7 @@ EMAIL_USE_TLS = True EMAIL_HOST_USER = env('EMAIL_HOST_USER') EMAIL_HOST_PASSWORD = env('EMAIL_HOST_PASSWORD') +os.environ['SSL_CERT_FILE'] = certifi.where() # Build paths inside the project like this: BASE_DIR / 'subdir'. @@ -141,16 +143,10 @@ DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField' CRONJOBS = [ - ('0 0 * * *', 'library_management.cron.send_return_reminders') + ('* * * * *', 'library_management.cron.send_return_reminders', + '>> /Users/rohansaeed/Desktop/library-management/library_management/debug7.log') ] -EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend' -EMAIL_HOST = '' -EMAIL_PORT = 587 -EMAIL_USE_TLS = True -EMAIL_HOST_USER = '' -EMAIL_HOST_PASSWORD = '' - MEDIA_URL = '/media/' MEDIA_ROOT = os.path.join(BASE_DIR, 'media') diff --git a/library_management/cron.py b/library_management/cron.py index 853179e..e425b94 100644 --- a/library_management/cron.py +++ b/library_management/cron.py @@ -1,18 +1,18 @@ from django.core.mail import send_mail from django.utils import timezone -from .models import BookIssue, Book +from .models import BookIssue def send_return_reminders(): - actual_return_date = timezone.now() - timezone.timedelta(days=15) + actual_return_date = timezone.now() + timezone.timedelta(days=15) overdue_books = BookIssue.objects.filter( - return_date__lt=actual_return_date, is_returned=False) - + return_date__lt=actual_return_date, returned=True) for book in overdue_books: user = book.user subject = 'Return Reminder' - message = f"Dear {user.username}, please remember to return the book '{book.book.name}' as soon as possible." + message = f"Dear {user.username}, please remember to return the book '{book.name}' as soon as possible." from_email = 'rohan.saeed@arbisoft.com' recipient_list = [user.email] - send_mail(subject, message, from_email, recipient_list) + send_mail(subject, message, from_email, + recipient_list, fail_silently=False) diff --git a/library_management/management/__init__.py b/library_management/management/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/library_management/management/commands/__init__.py b/library_management/management/commands/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/library_management/managment/commands/import_books_from_csv.py b/library_management/management/commands/my_books.py similarity index 87% rename from library_management/managment/commands/import_books_from_csv.py rename to library_management/management/commands/my_books.py index b2082f0..782d050 100644 --- a/library_management/managment/commands/import_books_from_csv.py +++ b/library_management/management/commands/my_books.py @@ -23,14 +23,14 @@ def handle(self, *args, **kwargs): available_quantity = int(row['available_quantity']) book, created = Book.objects.get_or_create( - title=title, + name=title, author=author, publisher=publisher, - defaults={'available_quantity': available_quantity} + defaults={'quantity': available_quantity} ) if not created: - book.available_quantity = available_quantity + book.quantity = available_quantity book.save() self.stdout.write(self.style.SUCCESS( diff --git a/library_management/migrations/0001_initial.py b/library_management/migrations/0001_initial.py index 91138b2..32bcf4f 100644 --- a/library_management/migrations/0001_initial.py +++ b/library_management/migrations/0001_initial.py @@ -1,4 +1,4 @@ -# Generated by Django 4.2.6 on 2023-11-05 23:47 +# Generated by Django 4.2.6 on 2023-11-06 05:45 from django.conf import settings from django.db import migrations, models @@ -38,7 +38,7 @@ class Migration(migrations.Migration): name='BookIssue', fields=[ ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('issued_date', models.DateField()), + ('issued_date', models.DateField(auto_now=True)), ('return_date', models.DateField()), ('returned', models.BooleanField(default=False)), ('status', models.CharField(choices=[('Issued', 'Issued'), ('Pending', 'Pending'), ('Rejected', 'Rejected')], default='Pending', max_length=20)), diff --git a/library_management/migrations/0002_alter_bookissue_status.py b/library_management/migrations/0002_alter_bookissue_status.py new file mode 100644 index 0000000..9e5cfef --- /dev/null +++ b/library_management/migrations/0002_alter_bookissue_status.py @@ -0,0 +1,18 @@ +# Generated by Django 4.2.6 on 2023-11-07 05:21 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('library_management', '0001_initial'), + ] + + operations = [ + migrations.AlterField( + model_name='bookissue', + name='status', + field=models.CharField(choices=[('pending', 'Pending'), ('issued', 'Issued'), ('rejected', 'Rejected')], default='pending', max_length=9), + ), + ] diff --git a/library_management/models.py b/library_management/models.py index f49d7a9..6a5cac6 100644 --- a/library_management/models.py +++ b/library_management/models.py @@ -1,6 +1,9 @@ from django.conf import settings from django.db import models from users.models import User +from django.db.models.signals import post_save +from django.dispatch import receiver +from django.core.mail import send_mail class Book(models.Model): @@ -12,18 +15,30 @@ class Book(models.Model): class BookIssue(models.Model): - REQUEST_STATUS_CHOICES = ( - ('Issued', 'Issued'), - ('Pending', 'Pending'), - ('Rejected', 'Rejected'), - ) + # REQUEST_STATUS_CHOICES = ( + # ('Issued', 'Issued'), + # ('Pending', 'Pending'), + # ('Rejected', 'Rejected'), + # ) user = models.ForeignKey(User, on_delete=models.CASCADE) book = models.ForeignKey(Book, on_delete=models.CASCADE) - issued_date = models.DateField() + issued_date = models.DateField(auto_now=True) return_date = models.DateField() returned = models.BooleanField(default=False) - status = models.CharField( - max_length=20, choices=REQUEST_STATUS_CHOICES, default='Pending') + + class Status(models.TextChoices): + """ + Status of each request, changed to depict the current status + Utilized TextChoices here as I required some comparisons with keys using request data + """ + PENDING = "pending", "Pending" + ISSUED = "issued", "Issued" + REJECTED = "rejected", "Rejected" + status = models.CharField(choices=Status.choices, + max_length=9, default=Status.PENDING) + + # status = models.CharField( + # max_length=20, choices=REQUEST_STATUS_CHOICES, default='Pending') class NewBookTicket(models.Model): @@ -38,4 +53,18 @@ class NewBookTicket(models.Model): max_length=20, choices=BOOK_TICKET_STATUS_CHOICES, default='Pending') def __str__(self): - return f'{self.user} - {self.book_name}' + return f'{self.user} - {self.book}' + + +@receiver(post_save, sender=NewBookTicket) +def call_car_api(sender, instance, **kwargs): + subject = 'Ticket Received' + message = f"Dear {instance.user.username}, we have got your request regarding '{instance.book.name}'. We will soon inform you about availability ." + from_email = 'rohan.saeed@arbisoft.com' + recipient_list = [instance.user.email] + + send_mail(subject, message, from_email, + recipient_list, fail_silently=False) + + print('Ticket object created') + print(sender, instance, kwargs) diff --git a/library_management/serializers.py b/library_management/serializers.py index 228e2d2..a1f6104 100644 --- a/library_management/serializers.py +++ b/library_management/serializers.py @@ -11,26 +11,35 @@ class Meta: class UserIssueSerializer(serializers.ModelSerializer): class Meta: model = BookIssue - fields = ['id', 'user', 'book', + fields = ['user', 'book', 'issued_date', 'returned', 'return_date'] + read_only_fields = ['returned'] + extra_kwargs = {'user': {'default': serializers.CurrentUserDefault()}} class LibrarianIssueSerializer(serializers.ModelSerializer): class Meta: model = BookIssue - fields = ['id', 'user', 'book', 'issued_date', + fields = ['user', 'book', 'issued_date', 'returned', 'return_date', 'status'] - read_only_fields = fields class LibrarianUpdateIssueSerializer(serializers.ModelSerializer): class Meta: model = BookIssue - fields = ['id', 'user', 'book', 'issued_date', + fields = ['user', 'book', 'issued_date', 'returned', 'return_date', 'status'] read_only_fields = ['id', 'user', 'book'] +class UserUpdateIssueSerializer(serializers.ModelSerializer): + class Meta: + model = BookIssue + fields = ['user', 'book', + 'issued_date', 'returned', 'return_date'] + read_only_fields = fields + + class UserTicketSerializer(serializers.ModelSerializer): class Meta: model = NewBookTicket @@ -47,6 +56,13 @@ class Meta: class LibrarianUpdateTicketSerializer(serializers.ModelSerializer): class Meta: - model = BookIssue + model = NewBookTicket fields = ['id', 'user', 'book', 'status'] read_only_fields = ['id', 'user', 'book'] + + +class UserUpdateTicketSerializer(serializers.ModelSerializer): + class Meta: + model = NewBookTicket + fields = ['id', 'user', 'book', 'status'] + read_only_fields = fields diff --git a/library_management/views.py b/library_management/views.py index e984c9f..d0b9d35 100644 --- a/library_management/views.py +++ b/library_management/views.py @@ -1,7 +1,7 @@ from .models import Book, BookIssue, NewBookTicket from .permissions import IsStaffEditorPermission from rest_framework import generics -from .serializers import BookSerializer, UserIssueSerializer, LibrarianIssueSerializer, LibrarianUpdateIssueSerializer, UserTicketSerializer, LibrarianTicketSerializer, LibrarianUpdateTicketSerializer +from .serializers import BookSerializer, UserIssueSerializer, LibrarianIssueSerializer, LibrarianUpdateIssueSerializer, UserTicketSerializer, LibrarianTicketSerializer, LibrarianUpdateTicketSerializer, UserUpdateIssueSerializer, UserUpdateTicketSerializer class BookList(generics.ListCreateAPIView): @@ -28,7 +28,8 @@ class BookIssueList(generics.ListCreateAPIView): def get_queryset(self): queryset = super().get_queryset() - queryset = queryset.filter(user=self.request.user) + if not self.request.user.is_librarian: + queryset = queryset.filter(user=self.request.user) return queryset def get_serializer_class(self): @@ -44,30 +45,7 @@ class BookIssueDetail(generics.RetrieveUpdateAPIView): def get_serializer_class(self): if self.request.user.is_librarian: return LibrarianUpdateIssueSerializer - return UserIssueSerializer - - -# class BookRequestView(View): -# template_name = 'book_request.html' - -# def get(self, request): -# form = BookRequestForm() -# return render(request, self.template_name, {'form': form}) - -# def post(self, request): -# form = BookRequestForm(request.POST) -# if form.is_valid(): -# book = form.cleaned_data['book'] -# max_requests = 3 -# user_requests = BookRequest.objects.filter( -# user=request.user, status='Pending').count() - -# if user_requests >= max_requests: -# return render(request, 'max_requests.html') -# BookRequest.objects.create(user=request.user, book=book) -# return redirect('requests') - -# return render(request, self.template_name, {'form': form}) + return UserUpdateIssueSerializer class BookTicketView(generics.ListCreateAPIView): @@ -80,18 +58,19 @@ def get_serializer_class(self): def get_queryset(self): queryset = super().get_queryset() - queryset = queryset.filter(user=self.request.user) + if not self.request.user.is_librarian: + queryset = queryset.filter(user=self.request.user) return queryset class BookTicketDetail(generics.RetrieveUpdateAPIView): - queryset = BookIssue.objects.all() + queryset = NewBookTicket.objects.all() lookup_field = 'pk' def get_serializer_class(self): if self.request.user.is_librarian: return LibrarianUpdateTicketSerializer - return UserTicketSerializer + return UserUpdateTicketSerializer def get_queryset(self): queryset = super().get_queryset() diff --git a/users/migrations/0001_initial.py b/users/migrations/0001_initial.py index 4b348de..875d6b5 100644 --- a/users/migrations/0001_initial.py +++ b/users/migrations/0001_initial.py @@ -1,4 +1,4 @@ -# Generated by Django 4.2.6 on 2023-11-05 23:47 +# Generated by Django 4.2.5 on 2023-11-06 05:42 import django.contrib.auth.models import django.contrib.auth.validators