Pagini

2013-09-19

Site in Common Lisp, partea 4

Hai sa facem niste template-uri pentru pagini. Facem intai niste pagini de
administrare, care nu vor fi disponibile vizitatorilor obisnuiti ai site-ului.
Pentru asta ar trebui sa implementam functionalitate de login si logout.



Paginile le vom crea ca sabloane care vor fi umplute de HTML-TEMPLATE. Vor fi,
deci, cateva fisiere in plus.

1. Pagina de login
Functionalitate: momentan va fi doar un camp text pentru parola, si un buton
de submit. Inca nu avem utilizatori, deci daca ajungi la pagina respectiva
nu poti sa vrei decat sa fii admin. Va fi pusa la adresa /login si va fi
submisa la acelasi URL, prin POST, urmand ca in caz de succes sa redirecteze
la /, iar in caz de eroare tot la /login, dar cu un mesaj de eroare.

Fisier: login.tmpl
Ca sa exersam CL-WHO, il voi scrie utilizand aceasta biblioteca:
(ql:quickload 'cl-who)

(with-open-file (g "login.tmpl" :direction :output 
     :if-exists :supersede :if-does-not-exist :create)
  (cl-who:with-html-output (g nil :indent t)
    (:html 
     (:head (:title "Login"))
     (:body
      ""
      (:div :style "color: red;" "Parola gresita")
      ""
      (:form :action "/login" :method "POST"
      (:input :type "password" :name +PASSWORD-POST-PARAMETER+)
      (:br)
      (:input :type "submit" :value "OK"))))))
Rezulta un fisier login.tmpl care are continutul:
<html>
  <head>
    <title>Login
    </title>
  </head>
  <body><!-- TMPL_IF error -->
    <div style='color: red;'>Parola gresita
    </div><!-- /TMPL_IF -->
    <form action='/login' method='POST'>
      <input type='password' name='pwd' />
      <br />
      <input type='submit' value='OK' />
    </form>
  </body>
</html>
Ulterior, acest template va fi procesat cu HTML-TEMPLATE. Acum modificam si
prima linie din fisier, pentru a incarca de la inceput si biblioteca HTML-TEMPLATE.

Trebuie creata functia de procesare. Aceasta se va uita daca exista sesiune;
daca da, atunci va redirecta catre pagina principala (/), altfel afiseaza
formularul de autentificare.
Intai definesc cativa parametri, momentan ca si constante (de vazut conventia
de denumire cu numele incadrat intre "+" - fiind conventie, nu e obligatorie)
(defconstant +COOKIE-NAME+ "ebwuoeir") ; abstract, nu spune nimic
(defconstant +COOKIE-VALABILITY+ (* 60 60)) ; 1h
(defconstant +PASS+ "somepass") ; parola de admin :)
(defconstant +PASSWORD-POST-PARAMETER+ "pwd")
(defconstant +TEMPLATE-ROOT+ "~/cars-site/")
Apoi fac si o functie care sa returneze calea completa catre template-uri
atunci cand primeste un nume de template:
(defun get-template (name)
  (merge-pathnames name +TEMPLATE-ROOT+))
Practic concateneaza +TEMPLATE-ROOT+ cu name, la modul "cale catre fisier"
+ "fisier".

Functia de procesare:
(defun web-login ()
  (if (cookie-in +COOKIE-NAME+)
      (redirect "/")
      (let ((pass (post-parameter +PASSWORD-POST-PARAMETER+))
     (wrong nil))
 (if pass
     (if (string= pass +PASS+)
  (progn
    (set-cookie +COOKIE-NAME+ :value t 
    :expires (+ +COOKIE-VALABILITY+ (get-universal-time)))
    (redirect "/"))
  (setf wrong t)))
 (with-output-to-string (s)
   (html-template:fill-and-print-template 
    (get-template "login.tmpl") 
    (list :wrong-password wrong) 
    :stream s)
   s))))
Explicatii:
- daca exista cookie, atunci utilizatorul este deja autentificat, redirect la /
- altfel caut parametru "pwd" printre parametrii de post, incercand sa aflu
daca tocmai suntem in curs de logare
- daca da, atunci verific daca parametrul respectiv contine parola si daca iara
da atunci setez un cookie si fac redirect la /
- daca parola furnizata nu este corecta, setez un flag, wrong
- pe care apoi il folosesc atunci cand "umplu" template-ul din login.tmpl
Parola are valabilitate 1 ora, GET-UNIVERSAL-TIME ofera numarul de secunde
de la 1 ianuarie 1900, ora 00:00.

La final nu trebuie decat sa spunem lui Hunchentoot sa foloseasca functia
WEB-LOGIN pentru a raspunde cererilor care vin la adresa /login.
(pushnew (create-prefix-dispatcher "/login" 'web-login) *dispatch-table*)
Creem un dispatcher Hunchentoot pe baza de prefix si ii zicem sa serveasca
cererile care vin la /login folosind functia WEB-LOGIN, apoi il adaugam in
tabela de dispecerat. Destul de simplu, nu? se poate face similar un dispatcher
care sa actioneze atunci cand exista o potrivire pe baza de regex, folosind
CREATE-REGEX-DISPATCHER.

2. Pagina principala
Acum ca am facut pagina de login imi dau seama ca in pagina principala trebuie
sa existe o indicatie a faptului ca suntem sau nu logati. O sa lucrez simplu si
pun un text in titlu, gen [ ADMIN ].

Functionalitate: in pagina principala vrem sa vedem vehiculele de pe site,
sa facem filtrarile, d-astea. Fiind pus pe chestii administrative, o s-o las
mai la urma, acum doar afisez la gramada continutul "bazei de date" si pun
un link catre pagina/paginile de administrare.

Faza e ca trebuie sa ma lupt un pic cu Hunchentoot, sa-l inteleg, ca sa pot
sa tratez si cereri din astea, catre pagini "virtuale", cat si cereri catre
fisiere de pe disc, gen favicon.ico. Revin.

Niciun comentariu:

Trimiteți un comentariu

S-ar putea sa nu vedeti comentariul aparand imediat, asta inseamna ca el asteapta aprobarea mea. Aceasta e o masura anti-SPAM.