From 3901201460ed3366e0413d7ccccf274553888d18 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Krop=C3=A1=C4=8Dek?= <kropikuba@gmail.com> Date: Mon, 18 Dec 2023 21:00:37 +0100 Subject: [PATCH] Initial commit --- .gitignore | 1 + account/__init__.py | 0 account/__pycache__/__init__.cpython-312.pyc | Bin 0 -> 158 bytes account/__pycache__/admin.cpython-312.pyc | Bin 0 -> 205 bytes account/__pycache__/apps.cpython-312.pyc | Bin 0 -> 469 bytes account/__pycache__/models.cpython-312.pyc | Bin 0 -> 202 bytes account/__pycache__/urls.cpython-312.pyc | Bin 0 -> 743 bytes account/__pycache__/views.cpython-312.pyc | Bin 0 -> 2094 bytes account/admin.py | 3 + account/apps.py | 6 + account/migrations/__init__.py | 0 .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 172 bytes account/models.py | 3 + account/templates/account/login.html | 20 ++ account/templates/account/me.html | 15 ++ account/templates/account/register.html | 5 + account/tests.py | 3 + account/urls.py | 12 ++ account/views.py | 40 ++++ db.sqlite3 | Bin 0 -> 131072 bytes facturio/__init__.py | 0 facturio/__pycache__/__init__.cpython-312.pyc | Bin 0 -> 162 bytes facturio/__pycache__/settings.cpython-312.pyc | Bin 0 -> 2820 bytes facturio/__pycache__/urls.cpython-312.pyc | Bin 0 -> 1482 bytes facturio/__pycache__/wsgi.cpython-312.pyc | Bin 0 -> 652 bytes facturio/asgi.py | 16 ++ facturio/settings.py | 128 ++++++++++++ facturio/urls.py | 34 ++++ facturio/wsgi.py | 16 ++ manage.py | 22 ++ poetry.lock | 67 +++++++ pyproject.toml | 16 ++ templates/facturio/base.html | 53 +++++ templates/facturio/invoice.html | 189 ++++++++++++++++++ 34 files changed, 649 insertions(+) create mode 100644 .gitignore create mode 100644 account/__init__.py create mode 100644 account/__pycache__/__init__.cpython-312.pyc create mode 100644 account/__pycache__/admin.cpython-312.pyc create mode 100644 account/__pycache__/apps.cpython-312.pyc create mode 100644 account/__pycache__/models.cpython-312.pyc create mode 100644 account/__pycache__/urls.cpython-312.pyc create mode 100644 account/__pycache__/views.cpython-312.pyc create mode 100644 account/admin.py create mode 100644 account/apps.py create mode 100644 account/migrations/__init__.py create mode 100644 account/migrations/__pycache__/__init__.cpython-312.pyc create mode 100644 account/models.py create mode 100644 account/templates/account/login.html create mode 100644 account/templates/account/me.html create mode 100644 account/templates/account/register.html create mode 100644 account/tests.py create mode 100644 account/urls.py create mode 100644 account/views.py create mode 100644 db.sqlite3 create mode 100644 facturio/__init__.py create mode 100644 facturio/__pycache__/__init__.cpython-312.pyc create mode 100644 facturio/__pycache__/settings.cpython-312.pyc create mode 100644 facturio/__pycache__/urls.cpython-312.pyc create mode 100644 facturio/__pycache__/wsgi.cpython-312.pyc create mode 100644 facturio/asgi.py create mode 100644 facturio/settings.py create mode 100644 facturio/urls.py create mode 100644 facturio/wsgi.py create mode 100755 manage.py create mode 100644 poetry.lock create mode 100644 pyproject.toml create mode 100644 templates/facturio/base.html create mode 100644 templates/facturio/invoice.html diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..9f11b75 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +.idea/ diff --git a/account/__init__.py b/account/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/account/__pycache__/__init__.cpython-312.pyc b/account/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..4dc59183f14502018846314279713d77bb102a65 GIT binary patch literal 158 zcmX@j%ge<81m5RsQ$h4&5P=Rpvj9b=GgLBYGWxA#C}INgK7-W!venPX&rQ|OF3K;^ z4@xb_FU~B<FUm|U*7qtcE(uO9N=@{w)K5!HE-5X_%-2sWEy>W2kI&4@EQycTE2#X% fVUwGmQks)$SHuc5jS+~8L5z>gjEsy$%s>_ZF4ZSl literal 0 HcmV?d00001 diff --git a/account/__pycache__/admin.cpython-312.pyc b/account/__pycache__/admin.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..c572795b665183ead3be3822fe484928142ea7de GIT binary patch literal 205 zcmX@j%ge<81m5RsQ|*EDV-N=hn4pZ$0zk%eh7^Vr#vF!R#wbQchDs()=9eI8O~zZS zi7C06d48HqxA;=B67$mY^^)`RN{TX*ikN{4Rx*4BsrzNCpOK%Ns-InyU!Wh9T999y zS(0CrnOdyxRa#sUoLrQe=v%3umY7^pT9lcupO~DSUz%5<4>nq_pz;@oO>TZlX-=wL Z5eLvTMj$Q*F+MOeGBVy{P$*&pasY18HDmw) literal 0 HcmV?d00001 diff --git a/account/__pycache__/apps.cpython-312.pyc b/account/__pycache__/apps.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..9afe1475a7911875e7ba328986cd965fa9bb3bec GIT binary patch literal 469 zcmXv~Jxjzu5S>kOdftbKoPvdjjgTg3Ee_#S6a}x)F3qxLH)k}-#!XVhLJ;l;h|T>5 z@u%2mcLc1g?1a<iDtD8(#mt+1Z)SJiYq#41dEU3~*^|tls`x*R8q9Vim;eQe0tk_V z5NL1=R2u`;8G6wxoulQ3+4xe0iHfB`93Sw=^G9w)R}t04tS7+)7&wT6qfzAORCA16 zH;tk@a9y57Y1MwWNv}yX;ugKMLQYwbSo{8Hkfr>{X8|o1Nu?f|jiQNhL_&sf(ZX1Y zvq0ev#<v*>YG#!(k7PlLi5!8wa)zO}XPBwa&HMHh51D-<cx<1um?wV9h0hZEG)vM8 zS1@vx+a7V#O!(ZcU$;pdCsv#bWm*{w36ic1W0-F2z8UM&cJJX(sGE`>ntIW$S5wVG s*;uuA6e@+w63v_aYLz{)B1`39qTKt|5keoZ{j;E<wa1fRkg4qY17*m0EC2ui literal 0 HcmV?d00001 diff --git a/account/__pycache__/models.cpython-312.pyc b/account/__pycache__/models.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..0140df8fbc821e0aabc851310f8164a23a2e9a7e GIT binary patch literal 202 zcmX@j%ge<81m5RsQ!Rn?V-N=hn4pZ$0zk%eh7^Vr#vF!R#wbQchDs()=9eI8O~zYn zx%nxnImLdOOt&~wvJ&&s^Yv1aikN|tD;Yk6)cms3&&bbB)z2=<FVGK4Eyyp<EXgm* zOfA;;DlIMvPA*DK^sUrSOH3{)Ey~Q-PfSkEFU>2_hZw6@Q2C3)2FNbWNwq8D02;># U#Kj=S2WCb_#(NAhMQlJ00HTF7A^-pY literal 0 HcmV?d00001 diff --git a/account/__pycache__/urls.cpython-312.pyc b/account/__pycache__/urls.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..9152a610ca2d836f699670f3aeee4620d4486cc5 GIT binary patch literal 743 zcmZ`$L2J}N6rLoLY<9ET*6zAgJV{+_E)57hSv)BeK@Sz7<g$d#xJgYiVKUL~9t3ae z$@SF!go+;gAD$Khiv!|8JoHxSMSAkh))-iD4)1;6d*8hG=FOK@tAXI;z1JjA5c(lW zdFp?`#cu$|$Va{sp;&PhMPfBlW6jlK>|)@Wk0U)cTth)BBATxg<8Y-cRC(X{RQsr1 z@rBO(kFLI?Yk+R8s#7B0TGBN^w_au|@3)q8E1>IC`4ai7m2RlJ)@aSXb|#ayBAR=g zr~4#JX_66J6*%>HAZm>CB{+laNtOOGB(E}ogc=i|IPqdK)?(raBPM-vl#Y#v4#UI| z`ofQE;AqYve+9;MMuuU=33G&5!Y6i9SpK1x4C!_NV=%eHf03L;8N(1^x-_OVHEHAz ziiVf-pucD)tP(><(OQtQg|MIuyaXC2*#~q1SJCCJ6Hu7_1*566Pg0tNoU)K)&Z9iz zPX~;6k4MgPZ@_aFQpXz%Xr6FK&a<74F3sJT`gug|vkfRF7nH?d&NW3*zM<RSQST>e z|1ywXpR7-wy*qe&aPpwQx4vR?a(${FoA1q&qXKV9zA@dIw>M|)&C@#tzAGa)rVr<x j-mKF*-7D~pjNF`(dDotG?az$@-#fRARrQU<y3p|tta`be literal 0 HcmV?d00001 diff --git a/account/__pycache__/views.cpython-312.pyc b/account/__pycache__/views.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..d10ca6a5da903204a48840d35e0f5ec18bd4607c GIT binary patch literal 2094 zcmbtV&2Jk;6rcU@=dSI<P8+EE5t>4?m9SG9sYL~PC~ea;Bvn2TGDu<ZPLoZ&yJ2SB zk`PdlA`wow5-2&QCt4*(4*U;XoF-Dk%2kl)g_~)5>WMdFZ=6K*#7Leu@6CH}e(!7j zdm<4>u*Uno#pw`2e{m*Qz>Br>5Xcg;kR_FnBNZfxpXHM5C<Vn)3#t<;goI2fg`G$t zBF<_l>ck2$Ctip<T0s-CP)T<Zg@ltVB!Lg(m=(eCTdEaZPzxy>*&~T9sH@HA3vGMk zanNkvr>X7HOwZ~@;%{zeNPd)J#%y<z8j7!*Wj2LfW*1F{{ZPr9v|T?8#49sUO$xyT z!C#hbf-Nx6`Wc%U0UlH4>kWp^crL}hK0rNp1UEQC_M>0{Rz>EA33e?^d<7hFhLwq1 zl$v31!ZWJCZ|8H6E}?le&7}vHCEe~ph|I#ReBcULOMV^pZ=_e;D&kgVLG9p;d1+o= zQ&;)B+)|lWXo^J|9QX@aVOz2yYthx_Yomz8f?Kdw0=a~k){;-_!MR1P7)u7+bX#z0 z(OnEG%LLMSb+wtH(O2aoF7lzXL%TM}(gIX~wlk1hIz+MS%}5OS>doQNF+W<Sn7F2c z{pgHI>0OUlhD_SQjHF@nBMzq2oWygP>+T)1WLsTDC?3?(HcQmL4<4aM!jze;OnueG zUol^~c4cfXZ5E4O*=2drKDjC8l<c3mw(f@=%%(hx@GKCOZ+y-OFN+_U#Ndh%a+r&F zUHtUm@U`nh6C+nXygqW}^4P@q$ROd#COpf8m%|8=1V6V>t2`=S54vxnOiGmd@8av_ z`}rx)!TH<7o5_#h8IRh`BQ~b_fih*I5TE(cZ2p#6gdVlMd=SVT8{eh5nOQ&12WCRV zMUH{fDE#OeZ1>PsB>w%}cXO4GA4jrVnZrvL?q66QSkIhZjPB=ZsqFIQhdsZ2vYEQN zsQ!`4)G{aj>^N3E(N|aG_H;drUdz6Sg*uXT6iOstBvB$=>8`L%{b((Fa^>7F=O3JZ zc=gx*Cw;@~eZw2sn~Q_BOm=y2BV$x`V=Jcrc;ts8mGa}*(OT+IrC818H&VUTXm3sH zT&9~^cUA4)0laA60P<vu0UUtC5@O9}LC|_Z<3O7?M+G6qD<{@;I5@RvU@;2qF=VKO zt2C-6YMOzX4v&xRE9xUjRFU#`yU0=4eJ#i|e2U0PknnWVBe2~=&(!$hxrG}wE%Q_V zlaAi?j@}LJY*jr=j>Gl7z&KD57&qJ>m?gDl#gK>Q4h6*~c+#c}6VbSUO!V3tV80h$ zLcj}D$(wN9%~g0~-$OO6z0zIn%x!4-s+#{_uu=gm2Ma*t6udwV!jT<JPQ%4pEey{Z z7<x7|qpBJL!;q2jHEY^*C%s(Jb8j_<EYp%OVt<k2ku_$MkBumwfBZjmauzOn#Dw{w zgnu`8T~EP(1mTk*CR9wg-_~?Mr#!-nWk&bRF|VvBu}Gtc;}H^oMJv3FzUO#Wxr9F; zInd-iLKk4GE0QEVMP1wI;ySwc6urBRF0G?W+vx3jI4zy3+^8cUD}y_n)XyNftuD*b zJC#rC2*}E3&pFvq0(m_yNxhY?>j=oo{0=8Di`+<(&Mbm6Aj^Z#IT1$xaJfMFFTIr0 A`v3p{ literal 0 HcmV?d00001 diff --git a/account/admin.py b/account/admin.py new file mode 100644 index 0000000..8c38f3f --- /dev/null +++ b/account/admin.py @@ -0,0 +1,3 @@ +from django.contrib import admin + +# Register your models here. diff --git a/account/apps.py b/account/apps.py new file mode 100644 index 0000000..2c684a9 --- /dev/null +++ b/account/apps.py @@ -0,0 +1,6 @@ +from django.apps import AppConfig + + +class AccountConfig(AppConfig): + default_auto_field = "django.db.models.BigAutoField" + name = "account" diff --git a/account/migrations/__init__.py b/account/migrations/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/account/migrations/__pycache__/__init__.cpython-312.pyc b/account/migrations/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..415a57d1bbf13dba6b881357ee3bccf218367a18 GIT binary patch literal 172 zcmX@j%ge<81m5RsQ$h4&5P=Rpvj9b=GgLBYGWxA#C}INgK7-W!^48DD&rQ|OF3K;^ z4@xb_FU~B<FUm|U*7qtcE(uO9N=@{w)K5!HE-5X_%-2s$PR=jQE78x*OfO0-$;{6y t){l?R%*!l^kJl@x{Ka9Do1apelWJGQ3N)J$h>JmtkIamWj77{q769<-Ee-$x literal 0 HcmV?d00001 diff --git a/account/models.py b/account/models.py new file mode 100644 index 0000000..71a8362 --- /dev/null +++ b/account/models.py @@ -0,0 +1,3 @@ +from django.db import models + +# Create your models here. diff --git a/account/templates/account/login.html b/account/templates/account/login.html new file mode 100644 index 0000000..5fc5313 --- /dev/null +++ b/account/templates/account/login.html @@ -0,0 +1,20 @@ +{% extends "facturio/base.html" %} + +{% block title %}Login{% endblock %} + +{% block content %} + <div class="container mt-5"> + <form class="col-md-6 offset-md-3" action="{% url 'login' %}" method="post"> + {% csrf_token %} + <div class="mb-3"> + <label for="username" class="form-label">Username</label> + <input type="text" class="form-control" name="username" id="username" required> + </div> + <div class="mb-3"> + <label for="password" class="form-label">Password</label> + <input type="password" class="form-control" name="password" id="password" required> + </div> + <button type="submit" class="btn btn-primary">Login</button> + </form> + </div> +{% endblock %} diff --git a/account/templates/account/me.html b/account/templates/account/me.html new file mode 100644 index 0000000..636e701 --- /dev/null +++ b/account/templates/account/me.html @@ -0,0 +1,15 @@ +{% extends "facturio/base.html" %} + +{% block title %}About Me{% endblock %} + +{% block content %} + <div class="container mt-4"> + <h2 class="mb-4">About Me</h2> + <div class="card"> + <div class="card-body"> + <h5 class="card-title">Welcome, {{ request.user.username }}!</h5> + <p class="card-text">Email: {{ request.user.email }}</p> + </div> + </div> + </div> +{% endblock %} diff --git a/account/templates/account/register.html b/account/templates/account/register.html new file mode 100644 index 0000000..cd31cfa --- /dev/null +++ b/account/templates/account/register.html @@ -0,0 +1,5 @@ +{% extends "facturio/base.html" %} +{% block title %}Register{% endblock %} +{% block content %} + <h1>TODO: register</h1> +{% endblock %} \ No newline at end of file diff --git a/account/tests.py b/account/tests.py new file mode 100644 index 0000000..7ce503c --- /dev/null +++ b/account/tests.py @@ -0,0 +1,3 @@ +from django.test import TestCase + +# Create your tests here. diff --git a/account/urls.py b/account/urls.py new file mode 100644 index 0000000..2184e52 --- /dev/null +++ b/account/urls.py @@ -0,0 +1,12 @@ +from django.http import HttpResponse +from django.urls import path, re_path + +from . import views + +urlpatterns = [ + path("", views.me, name="me"), + path("me/", views.me, name="me_exp"), + path("login/", views.auth_login, name="login"), + path("logout/", views.auth_logout, name="logout"), + path("register/", views.auth_register, name="register"), +] diff --git a/account/views.py b/account/views.py new file mode 100644 index 0000000..6e1a9c4 --- /dev/null +++ b/account/views.py @@ -0,0 +1,40 @@ +from django.conf import settings +from django.contrib.auth import authenticate, login, logout +from django.contrib.auth.decorators import login_required +from django.http import HttpRequest, HttpResponse, JsonResponse +from django.shortcuts import redirect, render + + +def auth_login(req: HttpRequest) -> HttpResponse: + if req.method == "POST": + username = req.POST["username"] + password = req.POST["password"] + user = authenticate(req, username=username, password=password) + if not user: + return JsonResponse( + { + "message": "Invalid cretendials" + }, + status=401 + ) + else: + login(req, user) + redirect_url = getattr(req.GET, "next", settings.LOGIN_REDIRECT_URL) + return redirect(redirect_url) + elif req.method == "GET": + return render(req, "account/login.html") + return HttpResponse(status=405) + + +@login_required +def auth_logout(req: HttpRequest) -> HttpResponse: + logout(req) + return redirect(settings.LOGOUT_REDIRECT_URL) + + +def auth_register(req: HttpRequest) -> HttpResponse: + return render(req, "account/register.html") + +@login_required +def me(req: HttpRequest) -> HttpResponse: + return render(req, "account/me.html") diff --git a/db.sqlite3 b/db.sqlite3 new file mode 100644 index 0000000000000000000000000000000000000000..ce718fefd44d1b34fa0dc746287201f90f2b3682 GIT binary patch literal 131072 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 DDisfP literal 0 HcmV?d00001 diff --git a/facturio/__init__.py b/facturio/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/facturio/__pycache__/__init__.cpython-312.pyc b/facturio/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..a6b7f860aec0eb079ab2011d51c64ee601011a7d GIT binary patch literal 162 zcmX@j%ge<81bbK2rh@3lAOanHW&w&!XQ*V*Wb|9fP{ah}eFmxd<*1*LpPQ<mU6fy- zACy{<Uz}NzUzC|ztnXD?ToRmIl$z*Ush^gZTvA$;nU7$^$7kkcmc+;F6;%G>u*uC& bDa}c>D`Ewj$Oy#6AjU^#Mn=XWW*`dyA(kms literal 0 HcmV?d00001 diff --git a/facturio/__pycache__/settings.cpython-312.pyc b/facturio/__pycache__/settings.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..3e2e0ceb91312a547f0186257c8ea65cd3371281 GIT binary patch literal 2820 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 Wtn`!7>iR#d(WQ-3s$gzHJ^v3N*Qlrf literal 0 HcmV?d00001 diff --git a/facturio/__pycache__/urls.cpython-312.pyc b/facturio/__pycache__/urls.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..f2edb07ca84c58a51af9ec44e5989e56abae366b GIT binary patch literal 1482 zcmb7EPjB2r6d!wM|Jg}4tyIyL%RoRIONreg^|GQ=2vM~NdPs|q_Ry_k&+a<4J?_l7 zG^>h'G#lzfFMd<4D$mrCIP7Kj4}#4T0Cr6=C=+R+LL34C~d@6DUvy!U(a=7;5F zi@^8O+h1{)67oA5_1CVH)9*n!AR!r&&<M@gNX(&Wpx%fZ2_4d;Ic%0Tjax~3*e>;E z+)28_Zek5Buv?slZQdNyu=6b)+9u)Mu*>bx`p!OT%+D!(OCYUq`N)|2j?9I%6>jca zoZE|X=klU8*Xw<g#&Bh~=dAkA0Lc1$>r)npbR11`>FY?OY%C-j`+?47Bv>ZJ4iB_z zS@))#J;-I8`C4<Css}8Nlx9-onkxn{ifO?fNBm3WvYUXB2+3KL0$ef&&SLH>&J^bZ zi@`V5I#UDB3q_#ZaK}$4qCPGViN{m#ntR35B8vj$VXz0sE6@7)iJt(L8dx{;G$?Z} zk1av3y6nR+WPZw`Bok5(7#mBGuw-}SXIbT(r&-3oSH)umSinMsuoa4(uJ`*JRb5k& z@C}yw3BTS)z3*5b#lBLT+fZ1zfckG)2tDNz6LHIo>vV1b*8j-{<6U2k5M<r?M@F~P zAkM=mod5~tc~}~@xaQ|}NeqKjpgkDN*Bv&ls2t4cnzzG6!s{ff*o~5u|D5f1EG8Zh zSfA8KM~T~a9P3ZKnvPL4{V<7A$1Lny(C01wDCbHSOLIeIB31l_QM4paLoOkVVq=PS z1zI#De}t=WXVah>lk(ET_!1nYQ=EqbqR-Zz!l>2*ahEveo!N!@&U;b%SVRGLr#gvc z3pP52#1}!~Zua`RhpqP>N|AY6JQFI?LPlJ9pX5s44J7wJ+x5=C&J?85&2|eKa+r)2 zfVza3t02B6zu4!Vuf2T3J+{4<)H?+qDafpw_))r<`4bKlQM`7ujvoXfPqjB&s<e{J zS*s+_yW{kV_GknXH5wHwRTH82T1MLvi74#KiSs0p9@#|qYUNf_n3*8gO5#g*7LCcv z4n}uTVD<%t!g)b)sjxxT55o&0dl<9~;&tc!M1*<FKag*Ni3BPi#7V<2j8|sQpnox9 zy!8jU`YT!cjl6r(F^nsF4^IgE4&zh&y|PHNyLW!?-l6>?edlM|*}J^|#o_(q3meCD d6U~dyuN@5b2M0IyZyeLLlQ!*{-`Hgee*>X~ss;c6 literal 0 HcmV?d00001 diff --git a/facturio/__pycache__/wsgi.cpython-312.pyc b/facturio/__pycache__/wsgi.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..ee5289ed690b72fc71367a6d6fef77724305b173 GIT binary patch literal 652 zcmYjP!EO^V5VdzhQ*CGji1utDE|Fjz4qOl*AyT4LG?hpZQZ5^JJxLwB>y_=Kq!Ndo z5MRJIK)-=6;8Fw<Xip%-fg32dp71tZrE~DS@#xKaWBJqCT7X=9{O}syVuXGbMH!WI zFyC|F9pb2uIOd+jeeAL?y~OYP7y%xymXu{4*Os_MyuvRXdy5Jq4}pJt-s-Q+yvEAm z_uxgZ-663`hhjvAN|Par?L-SjGOflC+b{?^mcXk_88F1|16eSblx$A|VTLf0C_a&J zTf!71nKCWTS}99_lfi&xnG`XzLZyR&oA<=YBuWDjsZ&hO8bqaTxG-cWB-|nfAlSDy zGxsRvDmEb>vvj0NPq9iUr1Wmsr2Fc?D#{^~YL-B1>46yu8vH5t>^5+IeFQct?xG7e z@{QKkqi%aA>TT}scDn6ew7t`M{&e&3YPo)Bz*>=xOrx4tqsV!PqTEv^zp`)=#%_VI zn5%uKlvg303a!#Sa6}G6Hjy^3U66c_=7pux2hMQ<^rcoAeFpATg;iRBp<5GUd$9(# zJ)@<IB`B1_Y<9YOfAQ82b=^&K9|)PIJO26@<9}WiSLW9c4t}FMKalq(I10X@_0MSi YWFtIjKK_bYKkGNX)NdZu^kql-4}<Z*^Z)<= literal 0 HcmV?d00001 diff --git a/facturio/asgi.py b/facturio/asgi.py new file mode 100644 index 0000000..e395568 --- /dev/null +++ b/facturio/asgi.py @@ -0,0 +1,16 @@ +""" +ASGI config for facturio project. + +It exposes the ASGI callable as a module-level variable named ``application``. + +For more information on this file, see +https://docs.djangoproject.com/en/5.0/howto/deployment/asgi/ +""" + +import os + +from django.core.asgi import get_asgi_application + +os.environ.setdefault("DJANGO_SETTINGS_MODULE", "facturio.settings") + +application = get_asgi_application() diff --git a/facturio/settings.py b/facturio/settings.py new file mode 100644 index 0000000..b63d289 --- /dev/null +++ b/facturio/settings.py @@ -0,0 +1,128 @@ +""" +Django settings for facturio project. + +Generated by 'django-admin startproject' using Django 5.0. + +For more information on this file, see +https://docs.djangoproject.com/en/5.0/topics/settings/ + +For the full list of settings and their values, see +https://docs.djangoproject.com/en/5.0/ref/settings/ +""" + +from pathlib import Path + +# Build paths inside the project like this: BASE_DIR / 'subdir'. +BASE_DIR = Path(__file__).resolve().parent.parent + +# Quick-start development settings - unsuitable for production +# See https://docs.djangoproject.com/en/5.0/howto/deployment/checklist/ + +# SECURITY WARNING: keep the secret key used in production secret! +SECRET_KEY = "django-insecure-+l+g3)q1zz2bz7=mz4ys6lhu5uj+=ucj34flm^clo4vb3(wmdp" + +# SECURITY WARNING: don't run with debug turned on in production! +DEBUG = True + +ALLOWED_HOSTS = ['*'] + +# Application definition + +INSTALLED_APPS = [ + "django.contrib.admin", + "django.contrib.auth", + "django.contrib.contenttypes", + "django.contrib.sessions", + "django.contrib.messages", + "django.contrib.staticfiles", + "account.apps.AccountConfig" +] + +MIDDLEWARE = [ + "django.middleware.security.SecurityMiddleware", + "django.contrib.sessions.middleware.SessionMiddleware", + "django.middleware.common.CommonMiddleware", + "django.middleware.csrf.CsrfViewMiddleware", + "django.contrib.auth.middleware.AuthenticationMiddleware", + "django.contrib.messages.middleware.MessageMiddleware", + "django.middleware.clickjacking.XFrameOptionsMiddleware", +] + +ROOT_URLCONF = "facturio.urls" + +TEMPLATES = [ + { + "BACKEND": "django.template.backends.django.DjangoTemplates", + "DIRS": [BASE_DIR / "templates"], + "APP_DIRS": True, + "OPTIONS": { + "context_processors": [ + "django.template.context_processors.debug", + "django.template.context_processors.request", + "django.contrib.auth.context_processors.auth", + "django.contrib.messages.context_processors.messages", + ], + }, + }, +] + +STATICFILES_DIRS = [ + BASE_DIR / "static", +] + +WSGI_APPLICATION = "facturio.wsgi.application" + +# Database +# https://docs.djangoproject.com/en/5.0/ref/settings/#databases + +DATABASES = { + "default": { + "ENGINE": "django.db.backends.sqlite3", + "NAME": BASE_DIR / "db.sqlite3", + } +} + +# Password validation +# https://docs.djangoproject.com/en/5.0/ref/settings/#auth-password-validators + +AUTH_PASSWORD_VALIDATORS = [ + { + "NAME": "django.contrib.auth.password_validation.UserAttributeSimilarityValidator", + }, + { + "NAME": "django.contrib.auth.password_validation.MinimumLengthValidator", + }, + { + "NAME": "django.contrib.auth.password_validation.CommonPasswordValidator", + }, + { + "NAME": "django.contrib.auth.password_validation.NumericPasswordValidator", + }, +] + +# Internationalization +# https://docs.djangoproject.com/en/5.0/topics/i18n/ + +LANGUAGE_CODE = "en-us" + +TIME_ZONE = "UTC" + +USE_I18N = True + +USE_TZ = True + +# Static files (CSS, JavaScript, Images) +# https://docs.djangoproject.com/en/5.0/howto/static-files/ + +STATIC_URL = "static/" + +# Default primary key field type +# https://docs.djangoproject.com/en/5.0/ref/settings/#default-auto-field + +DEFAULT_AUTO_FIELD = "django.db.models.BigAutoField" + +# Login configuration +LOGIN_BASE_URL = "/account" +LOGIN_URL = f"{LOGIN_BASE_URL}/login" +LOGOUT_REDIRECT_URL = f"/" +LOGIN_REDIRECT_URL = f"{LOGIN_BASE_URL}/me" diff --git a/facturio/urls.py b/facturio/urls.py new file mode 100644 index 0000000..5f34c30 --- /dev/null +++ b/facturio/urls.py @@ -0,0 +1,34 @@ +""" +URL configuration for facturio project. + +The `urlpatterns` list routes URLs to views. For more information please see: + https://docs.djangoproject.com/en/5.0/topics/http/urls/ +Examples: +Function views + 1. Add an import: from my_app import views + 2. Add a URL to urlpatterns: path('', views.home, name='home') +Class-based views + 1. Add an import: from other_app.views import Home + 2. Add a URL to urlpatterns: path('', Home.as_view(), name='home') +Including another URLconf + 1. Import the include() function: from django.urls import include, path + 2. Add a URL to urlpatterns: path('blog/', include('blog.urls')) +""" +from django.contrib import admin +# TODO: remove +from django.http import HttpRequest, HttpResponse +from django.shortcuts import render +from django.urls import path, include + + +# TODO: remove +def demo(req: HttpRequest) -> HttpResponse: + return render(req, "facturio/invoice.html") + + +urlpatterns = [ + path("", demo, name="main-page"), + path("account/", include("account.urls")), + path("admin/", admin.site.urls), +] + diff --git a/facturio/wsgi.py b/facturio/wsgi.py new file mode 100644 index 0000000..57369aa --- /dev/null +++ b/facturio/wsgi.py @@ -0,0 +1,16 @@ +""" +WSGI config for facturio project. + +It exposes the WSGI callable as a module-level variable named ``application``. + +For more information on this file, see +https://docs.djangoproject.com/en/5.0/howto/deployment/wsgi/ +""" + +import os + +from django.core.wsgi import get_wsgi_application + +os.environ.setdefault("DJANGO_SETTINGS_MODULE", "facturio.settings") + +application = get_wsgi_application() diff --git a/manage.py b/manage.py new file mode 100755 index 0000000..3e35f11 --- /dev/null +++ b/manage.py @@ -0,0 +1,22 @@ +#!/usr/bin/env python +"""Django's command-line utility for administrative tasks.""" +import os +import sys + + +def main(): + """Run administrative tasks.""" + os.environ.setdefault("DJANGO_SETTINGS_MODULE", "facturio.settings") + try: + from django.core.management import execute_from_command_line + except ImportError as exc: + raise ImportError( + "Couldn't import Django. Are you sure it's installed and " + "available on your PYTHONPATH environment variable? Did you " + "forget to activate a virtual environment?" + ) from exc + execute_from_command_line(sys.argv) + + +if __name__ == "__main__": + main() diff --git a/poetry.lock b/poetry.lock new file mode 100644 index 0000000..1b9573a --- /dev/null +++ b/poetry.lock @@ -0,0 +1,67 @@ +# This file is automatically @generated by Poetry 1.7.1 and should not be changed by hand. + +[[package]] +name = "asgiref" +version = "3.7.2" +description = "ASGI specs, helper code, and adapters" +optional = false +python-versions = ">=3.7" +files = [ + {file = "asgiref-3.7.2-py3-none-any.whl", hash = "sha256:89b2ef2247e3b562a16eef663bc0e2e703ec6468e2fa8a5cd61cd449786d4f6e"}, + {file = "asgiref-3.7.2.tar.gz", hash = "sha256:9e0ce3aa93a819ba5b45120216b23878cf6e8525eb3848653452b4192b92afed"}, +] + +[package.extras] +tests = ["mypy (>=0.800)", "pytest", "pytest-asyncio"] + +[[package]] +name = "django" +version = "5.0" +description = "A high-level Python web framework that encourages rapid development and clean, pragmatic design." +optional = false +python-versions = ">=3.10" +files = [ + {file = "Django-5.0-py3-none-any.whl", hash = "sha256:3a9fd52b8dbeae335ddf4a9dfa6c6a0853a1122f1fb071a8d5eca979f73a05c8"}, + {file = "Django-5.0.tar.gz", hash = "sha256:7d29e14dfbc19cb6a95a4bd669edbde11f5d4c6a71fdaa42c2d40b6846e807f7"}, +] + +[package.dependencies] +asgiref = ">=3.7.0" +sqlparse = ">=0.3.1" +tzdata = {version = "*", markers = "sys_platform == \"win32\""} + +[package.extras] +argon2 = ["argon2-cffi (>=19.1.0)"] +bcrypt = ["bcrypt"] + +[[package]] +name = "sqlparse" +version = "0.4.4" +description = "A non-validating SQL parser." +optional = false +python-versions = ">=3.5" +files = [ + {file = "sqlparse-0.4.4-py3-none-any.whl", hash = "sha256:5430a4fe2ac7d0f93e66f1efc6e1338a41884b7ddf2a350cedd20ccc4d9d28f3"}, + {file = "sqlparse-0.4.4.tar.gz", hash = "sha256:d446183e84b8349fa3061f0fe7f06ca94ba65b426946ffebe6e3e8295332420c"}, +] + +[package.extras] +dev = ["build", "flake8"] +doc = ["sphinx"] +test = ["pytest", "pytest-cov"] + +[[package]] +name = "tzdata" +version = "2023.3" +description = "Provider of IANA time zone data" +optional = false +python-versions = ">=2" +files = [ + {file = "tzdata-2023.3-py2.py3-none-any.whl", hash = "sha256:7e65763eef3120314099b6939b5546db7adce1e7d6f2e179e3df563c70511eda"}, + {file = "tzdata-2023.3.tar.gz", hash = "sha256:11ef1e08e54acb0d4f95bdb1be05da659673de4acbd21bf9c69e94cc5e907a3a"}, +] + +[metadata] +lock-version = "2.0" +python-versions = "^3.12" +content-hash = "1c6ab57fc89858a0923620d3307e9173662bad9b58d9dde4f567267506e03587" diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..9c01d30 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,16 @@ +[tool.poetry] +name = "facturio" +version = "0.1.0" +description = "" +authors = ["Jakub Kropáček <kropikuba@gmail.com>"] +license = "MIT" +readme = "README.md" + +[tool.poetry.dependencies] +python = "^3.12" +django = "^5.0" + + +[build-system] +requires = ["poetry-core"] +build-backend = "poetry.core.masonry.api" diff --git a/templates/facturio/base.html b/templates/facturio/base.html new file mode 100644 index 0000000..9615bd7 --- /dev/null +++ b/templates/facturio/base.html @@ -0,0 +1,53 @@ +<!DOCTYPE html> +<html lang="cs"> +<head> + <meta charset="UTF-8"> + <title>Facturio - {% block title %}App{% endblock %}</title> + <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css" rel="stylesheet" + integrity="sha384-T3c6CoIi6uLrA9TneNEoa7RxnatzjcDSCmG1MXxSR1GAsXEV/Dwwykc2MPK8M2HN" crossorigin="anonymous"> +</head> +<body> +<nav class="navbar navbar-expand-lg navbar-dark bg-dark"> + <div class="container-fluid"> + <a class="navbar-brand" href="#">Facturio</a> + + <!-- Left-aligned items --> + <div class="collapse navbar-collapse" id="navbarLeft"> + <ul class="navbar-nav"> + <!-- Additional items on the left --> + <li class="nav-item"> + <a class="nav-link" href="#">Item 1</a> + </li> + <li class="nav-item"> + <a class="nav-link" href="#">Item 2</a> + </li> + <!-- Add more items as needed --> + </ul> + </div> + + <!-- Right-aligned login/logout links --> + <div class="collapse navbar-collapse justify-content-end" id="navbarRight"> + <ul class="navbar-nav"> + {% if request.user.is_authenticated %} + <li class="nav-item"> + <a class="nav-link" href="{% url 'logout' %}">Logout</a> + </li> + {% else %} + <li class="nav-item"> + <a class="nav-link" href="{% url 'login' %}">Login</a> + </li> + <li class="nav-item"> + <a class="nav-link" href="{% url 'register' %}">Register</a> + </li> + {% endif %} + </ul> + </div> + </div> +</nav> + +<div class="container mt-4"> + {% block content %} {% endblock %} +</div> + +</body> +</html> \ No newline at end of file diff --git a/templates/facturio/invoice.html b/templates/facturio/invoice.html new file mode 100644 index 0000000..12413f2 --- /dev/null +++ b/templates/facturio/invoice.html @@ -0,0 +1,189 @@ +<!-- Vaše faktura s aktualizacemi --> +<!DOCTYPE html> +<html lang="cs"> + <head> + <meta charset="UTF-8" /> + <meta name="viewport" content="width=device-width, initial-scale=1.0" /> + <title>Faktura</title> + <style> + @import url("https://fonts.googleapis.com/css2?family=Ubuntu&display=swap"); + + :root { + --font-family: "Ubuntu", sans-serif; + --main-color: #333; + --secondary-color: #888; + --border-color: #ddd; + --background-color: #fff; + } + + body { + font-family: var(--font-family); + margin: 20px; + color: var(--main-color); + background-color: var(--background-color); + } + + header { + text-align: left; + margin-bottom: 20px; + } + + .parties ul { + list-style-type: none; + padding: 0; + margin: 0; + } + + .parties li { + margin-top: 5px; + } + + .parties h2 { + border-bottom: 1px solid var(--border-color); + padding-bottom: 8px; + font-size: 1.2rem; + } + + .invoice-id { + color: var(--secondary-color); + } + + #invoice { + border-collapse: collapse; + width: 100%; + } + + #invoice th, + #invoice td { + padding: 12px; + text-align: left; + border-bottom: 1px solid var(--border-color); + } + + .invoice-total { + margin-top: 20px; + text-align: right; + } + + .parties-section { + display: flex; + justify-content: space-between; + margin-bottom: 20px; + } + + .parties { + width: 48%; + } + + #invoice tbody tr { + border-bottom: 1px solid var(--border-color); + } + + .small-col { + width: 5%; + } + .medium-col { + width: 15%; + } + .big-col { + width: 25%; + } + .right-align { + text-align: right; + } + + footer { + position: fixed; + bottom: 0; + width: 100%; + text-align: center; + left: 0; + right: 0; + padding: 0; + margin-top: 20px; + color: var(--main-color); + background-color: var(--background-color); + } + + @media print { + @page { + size: auto; + margin: 0; + } + + body { + margin: 10mm 10mm; + } + } + </style> + </head> + <body> + <header> + <h1>Faktura <span class="invoice-id">2023-0001</span></h1> + </header> + + <section class="parties-section"> + <div class="parties"> + <h2>Dodavatel</h2> + <ul> + <li>Název Vaší společnosti nebo jméno</li> + <li>Vaše adresa</li> + <li>Vaše město, PSČ</li> + <p></p> + <li>IČO: 123456789</li> + <li>DIČ: CZ123456789 jestli jste plátce DPH</li> + <p></p> + <li>Bankovní účet: 123-456789</li> + </ul> + </div> + + <div class="parties"> + <h2>Odběratel</h2> + <ul> + <li>Název společnosti nebo jméno zákazníka</li> + <li>Adresa zákazníka</li> + <li>Město zákazníka, PSČ</li> + <p></p> + <li>IČO zákazníka: 987654321</li> + <li>DIČ zákazníka: CZ987654321 jestli je plátce DPH</li> + <p></p> + <li><strong>Datum vystavení:</strong> 16. prosince 2023</li> + <li><strong>Datum splatnosti:</strong> 16. prosince 2023</li> + </ul> + </div> + </section> + + <section> + <h2>Detaily faktury</h2> + <table id="invoice"> + <thead> + <tr> + <th class="small-col">#</th> + <th class="small-col">Jednotka</th> + <th class="big-col">Popis položky</th> + <th class="medium-col right-align">Cena za MJ</th> + <th class="medium-col right-align">Celkem</th> + </tr> + </thead> + <tbody> + <tr> + <td>1</td> + <td>ks</td> + <td>Položka 1</td> + <td class="right-align">50,00 Kč</td> + <td class="right-align">50,00 Kč</td> + </tr> + </tbody> + </table> + + <div class="invoice-total"> + <p><strong>Celkem: 100,00 Kč</strong></p> + </div> + </section> + + <footer> + <p>Fyzická osoba zapsaná v živnostenském rejstříku.</p> + <p>Fakturu vygenerovala aplikace Facturio</p> + </footer> + </body> +</html>