Skip to content

Commit 578a8e0

Browse files
committed
Dodana registracija in prijava
1 parent 0b4a70e commit 578a8e0

6 files changed

Lines changed: 406 additions & 29 deletions

File tree

predavanja/primeri/banka/banka.py

Lines changed: 218 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
1-
from model import Kraj, Oseba, Racun, Transakcija, vzpostavi_povezavo
1+
from functools import wraps
2+
from model import Entiteta, Kraj, Oseba, Racun, Transakcija, IntegrityError, vzpostavi_povezavo
23
import bottle
34
import bottleext
5+
import json
46
import os
57

68

@@ -15,13 +17,170 @@
1517
bottle.debug(True) # za izpise pri razvoju
1618

1719

20+
def nastavi_piskotek(piskotek, vsebina):
21+
"""
22+
Nastavi podani piškotek.
23+
"""
24+
bottle.response.set_cookie(piskotek, vsebina, secret=SKRIVNOST, path='/')
25+
26+
27+
def preberi_piskotek(piskotek, izbrisi=False):
28+
"""
29+
Preberi podani piškotek.
30+
"""
31+
if izbrisi:
32+
pobrisi_piskotek(piskotek)
33+
return bottle.request.get_cookie(piskotek, secret=SKRIVNOST)
34+
35+
36+
def pobrisi_piskotek(piskotek):
37+
"""
38+
Pobriši podani piškotek.
39+
"""
40+
bottle.response.delete_cookie(piskotek, path='/')
41+
42+
43+
def nastavi_sporocilo(sporocilo):
44+
"""
45+
Nastavi podano sporočilo.
46+
"""
47+
nastavi_piskotek('sporocilo', sporocilo)
48+
49+
50+
def preberi_sporocilo():
51+
"""
52+
Vrni sporočilo in pobriši piškotek.
53+
"""
54+
return preberi_piskotek('sporocilo', izbrisi=True)
55+
56+
57+
def nastavi_obrazec(piskotek, objekt):
58+
"""
59+
Nastavi piškotek s polji objekta.
60+
"""
61+
nastavi_piskotek(piskotek, json.dumps(objekt.kot_slovar()))
62+
63+
64+
def preberi_obrazec(piskotek, obj):
65+
"""
66+
Vrni objekt iz piškotka in ga pobriši.
67+
"""
68+
try:
69+
slovar = json.loads(preberi_piskotek(piskotek, izbrisi=True))
70+
if isinstance(obj, Entiteta):
71+
obj.posodobi_polja(**slovar)
72+
return obj
73+
else:
74+
return obj(**slovar)
75+
except (TypeError, json.JSONDecodeError):
76+
return obj if isinstance(obj, Entiteta) else obj.NULL
77+
78+
79+
def prijavljeni_uporabnik():
80+
"""
81+
Vrni prijavljenega uporabnika z ID-jem iz piškotka.
82+
"""
83+
try:
84+
return Oseba.z_id(preberi_piskotek('uporabnik'))
85+
except ValueError:
86+
return Oseba.NULL
87+
88+
89+
def prijavi_uporabnika(uporabnik, geslo, piskotek=None):
90+
"""
91+
Nastavi piškotek na podanega uporabnika.
92+
"""
93+
if not uporabnik or not uporabnik.prijavi(geslo):
94+
nastavi_sporocilo("Prijava ni bila uspešna!")
95+
if piskotek:
96+
nastavi_obrazec(piskotek, uporabnik)
97+
bottle.redirect(bottle.url('prijava'))
98+
print(uporabnik.emso, type(uporabnik.emso))
99+
nastavi_piskotek('uporabnik', uporabnik.emso)
100+
bottle.redirect(bottle.url('index'))
101+
102+
103+
def odjavi_uporabnika():
104+
"""
105+
Pobriši piškotek z ID-jem prijavljenega uporabnika.
106+
"""
107+
pobrisi_piskotek('uporabnik')
108+
bottle.redirect(bottle.url('index'))
109+
110+
111+
def status(preveri):
112+
"""
113+
Vrni dekorator, ki preveri prijavljenega uporabnika v skladu s podano
114+
funkcijo in elemente vrnjenega zaporedja preda kot začetne argumente
115+
dekorirani funkciji.
116+
"""
117+
@wraps(preveri)
118+
def decorator(fun):
119+
@wraps(fun)
120+
def wrapper(*largs, **kwargs):
121+
uporabnik = prijavljeni_uporabnik()
122+
out = fun(*preveri(uporabnik), *largs, **kwargs)
123+
if out is None:
124+
out = {}
125+
if isinstance(out, dict):
126+
out['uporabnik'] = uporabnik
127+
return out
128+
return wrapper
129+
return decorator
130+
131+
132+
@status
133+
def admin(uporabnik):
134+
"""
135+
Preveri, ali ima uporabnik administratorske pravice.
136+
137+
Dekorirana funkcija kot prvi argument sprejme prijavljenega uporabnika.
138+
"""
139+
if not uporabnik.admin:
140+
bottle.abort(401, "Dostop prepovedan!")
141+
return (uporabnik, )
142+
143+
144+
@status
145+
def prijavljen(uporabnik):
146+
"""
147+
Preveri, ali je uporabnik prijavljen.
148+
149+
Dekorirana funkcija kot prvi argument sprejme prijavljenega uporabnika.
150+
"""
151+
if not uporabnik:
152+
bottle.redirect(bottle.url('prijava'))
153+
return (uporabnik, )
154+
155+
156+
@status
157+
def odjavljen(uporabnik):
158+
"""
159+
Preveri, ali je uporabnik odjavljen.
160+
"""
161+
if uporabnik:
162+
bottle.redirect(bottle.url('index'))
163+
return ()
164+
165+
166+
def preveri_lastnika(uporabnik, emso):
167+
"""
168+
Preveri, ali ima prijavljeni uporabnik dovoljenje dostopa za podani EMŠO.
169+
"""
170+
if uporabnik.emso != emso and not uporabnik.admin:
171+
bottle.abort(401, "Dostop prepovedan!")
172+
173+
18174
bottle.BaseTemplate.defaults.update(
19175
Kraj=Kraj,
20176
Oseba=Oseba,
21177
Racun=Racun,
22178
Transakcija=Transakcija,
23179
url=bottle.url,
24180
urlencode=bottle.urlencode,
181+
preberi_sporocilo=preberi_sporocilo,
182+
preberi_obrazec=preberi_obrazec,
183+
prijavljeni_uporabnik=prijavljeni_uporabnik,
25184
)
26185

27186

@@ -36,4 +195,61 @@ def index():
36195
pass
37196

38197

39-
bottle.run(host='localhost', port=SERVER_PORT, reloader=RELOADER)
198+
@bottle.get('/prijava/')
199+
@bottle.view('prijava.html')
200+
@odjavljen
201+
def prijava():
202+
pass
203+
204+
205+
@bottle.post('/prijava/')
206+
@odjavljen
207+
def prijava_post():
208+
uporabnisko_ime = bottle.request.forms.getunicode('uporabnisko_ime')
209+
geslo = bottle.request.forms.getunicode('geslo')
210+
uporabnik = Oseba.z_uporabniskim_imenom(uporabnisko_ime)
211+
prijavi_uporabnika(uporabnik, geslo, 'prijava')
212+
213+
214+
@bottle.get('/registracija/')
215+
@bottle.view('registracija.html')
216+
@odjavljen
217+
def registracija():
218+
pass
219+
220+
221+
@bottle.post('/registracija/')
222+
@odjavljen
223+
def registracija_post():
224+
emso = bottle.request.forms.getunicode('emso')
225+
ime = bottle.request.forms.getunicode('ime')
226+
priimek = bottle.request.forms.getunicode('priimek')
227+
naslov = bottle.request.forms.getunicode('naslov')
228+
kraj = bottle.request.forms.getunicode('kraj')
229+
uporabnisko_ime = bottle.request.forms.getunicode('uporabnisko_ime')
230+
geslo = bottle.request.forms.getunicode('geslo')
231+
geslo2 = bottle.request.forms.getunicode('geslo2')
232+
uporabnik = Oseba(emso, ime, priimek, naslov, kraj, uporabnisko_ime, geslo)
233+
if geslo != geslo2:
234+
uporabnik.geslo = None
235+
nastavi_sporocilo("Gesli se ne ujemata!")
236+
nastavi_obrazec('registracija', uporabnik)
237+
bottle.redirect(bottle.url('registracija'))
238+
try:
239+
uporabnik.vstavi()
240+
except IntegrityError:
241+
uporabnik.geslo = None
242+
nastavi_sporocilo("Dodajanje uporabnika ni uspelo!")
243+
nastavi_obrazec('registracija', uporabnik)
244+
bottle.redirect(bottle.url('registracija'))
245+
prijavi_uporabnika(uporabnik, geslo, 'registracija')
246+
247+
248+
@bottle.post('/odjava/')
249+
@prijavljen
250+
def odjava_post(uporabnik):
251+
odjavi_uporabnika()
252+
253+
254+
with vzpostavi_povezavo(port=DB_PORT):
255+
bottle.run(host='localhost', port=SERVER_PORT, reloader=RELOADER)

predavanja/primeri/banka/model.py

Lines changed: 68 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,46 @@
11
import bcrypt
22
import csv
3-
from psycopg import connect, sql, errors
3+
from psycopg import connect, sql
4+
from psycopg.errors import IntegrityError
45
from auth import auth
56
from dataclasses import dataclass
67
from datetime import datetime
78

89

9-
@dataclass
10-
class Kraj:
11-
posta: int
12-
kraj: str
10+
class Entiteta:
11+
def __init_subclass__(cls):
12+
"""
13+
Inicializiraj prazen objekt.
14+
"""
15+
dataclass(cls)
16+
cls.NULL = cls()
17+
18+
def __bool__(self):
19+
return getattr(self, self.GLAVNI_KLJUC) is not None
20+
21+
def __getitem__(self, kljuc):
22+
"""
23+
Vrni vrednost v stolpcu v obliki, kot je zapisana v bazi.
24+
"""
25+
vrednost = getattr(self, kljuc)
26+
if isinstance(vrednost, Entiteta):
27+
return vrednost[vrednost.GLAVNI_KLJUC]
28+
else:
29+
return vrednost
30+
31+
def posodobi_polja(self, **polja):
32+
"""
33+
Posodobi podana polja.
34+
"""
35+
for polje, vrednost in polja.items():
36+
setattr(self, polje, vrednost)
37+
38+
39+
class Kraj(Entiteta):
40+
posta: int = None
41+
kraj: str = None
42+
43+
GLAVNI_KLJUC = 'posta'
1344

1445
def __str__(self):
1546
return f"{self.posta} {self.kraj}"
@@ -118,17 +149,19 @@ def izbrisi(self):
118149
def kot_slovar(self):
119150
return dict(posta=self.posta, kraj=self.kraj)
120151

121-
@dataclass
122-
class Oseba:
123-
emso: str
124-
ime: str
125-
priimek: str
152+
153+
class Oseba(Entiteta):
154+
emso: str = None
155+
ime: str = None
156+
priimek: str = None
126157
naslov: str = None
127158
kraj: Kraj = None
128159
uporabnisko_ime: str = None
129160
geslo: bytes = None
130161
admin: bool = False
131162

163+
GLAVNI_KLJUC = 'emso'
164+
132165
@classmethod
133166
def ustvari_tabelo(cls, pobrisi=False, ce_ne_obstaja=False):
134167
with conn.transaction():
@@ -202,24 +235,37 @@ def z_id(cls, id):
202235
return Oseba(*podatki, Kraj(posta, kraj), uporabnisko_ime, admin=admin)
203236

204237
@classmethod
205-
def prijavi(cls, uporabnisko_ime, geslo):
238+
def z_uporabniskim_imenom(cls, uporabnisko_ime):
206239
with conn.transaction():
207240
with conn.cursor() as cur:
208241
cur.execute(
209242
"""
210-
SELECT emso, ime, priimek, naslov, kraj.posta, kraj.kraj, uporabnisko_ime, geslo, admin FROM oseba
243+
SELECT emso, ime, priimek, naslov, kraj.posta, kraj.kraj, uporabnisko_ime, admin FROM oseba
211244
JOIN kraj ON oseba.kraj = posta
212245
WHERE uporabnisko_ime = %s
213246
""", (uporabnisko_ime, )
214247
)
215248
vrstica = cur.fetchone()
216249
if vrstica is None:
217-
raise ValueError(f"Uporabnik z uporabniškim imenom {uporabnisko_ime} ne obstaja!")
218-
*podatki, posta, kraj, uporabnisko_ime, zgostitev, admin = vrstica
219-
if not Oseba._preveri_geslo(geslo, zgostitev):
220-
raise ValueError(f"Geslo za uporabnika z uporabniškim imenom {uporabnisko_ime} ni pravilno!")
250+
return cls.NULL
251+
*podatki, posta, kraj, uporabnisko_ime, admin = vrstica
221252
return Oseba(*podatki, Kraj(posta, kraj), uporabnisko_ime, admin=admin)
222253

254+
def prijavi(self, geslo):
255+
with conn.transaction():
256+
with conn.cursor() as cur:
257+
cur.execute(
258+
"""
259+
SELECT geslo FROM oseba
260+
WHERE uporabnisko_ime = %s
261+
""", (self.uporabnisko_ime, )
262+
)
263+
vrstica = cur.fetchone()
264+
if vrstica is None:
265+
return False
266+
zgostitev, = vrstica
267+
return Oseba._preveri_geslo(geslo, zgostitev)
268+
223269
@classmethod
224270
def seznam(cls):
225271
with conn.transaction():
@@ -315,11 +361,12 @@ def _preveri_geslo(geslo, zgostitev):
315361
return bcrypt.checkpw(geslo, zgostitev)
316362

317363

318-
@dataclass
319-
class Racun:
364+
class Racun(Entiteta):
320365
stevilka: int = None
321366
lastnik: Oseba = None
322367

368+
GLAVNI_KLJUC = 'stevilka'
369+
323370
@classmethod
324371
def ustvari_tabelo(cls, pobrisi=False, ce_ne_obstaja=False):
325372
with conn.transaction():
@@ -462,14 +509,15 @@ def kot_slovar(self):
462509
return dict(stevilka=self.stevilka, lastnik=lastnik)
463510

464511

465-
@dataclass
466-
class Transakcija:
512+
class Transakcija(Entiteta):
467513
id: int = None
468514
racun: Racun = None
469515
znesek: int = None
470516
cas: datetime = None
471517
opis: str = None
472518

519+
GLAVNI_KLJUC = 'id'
520+
473521
@classmethod
474522
def ustvari_tabelo(cls, pobrisi=False, ce_ne_obstaja=False):
475523
with conn.transaction():

0 commit comments

Comments
 (0)