From 5de7cad2494cca63009d34e972fc77e815c68826 Mon Sep 17 00:00:00 2001
From: David Botton [in package CLOG]
@@ -4049,7 +4052,8 @@ by doubling) unless is the single character '?'.
Create a new CLOG-Database element, for use in CLOG-Builder. If not using builder use to connect: - (dbi:connect (database-connection clog-obj) ...)
+ (dbi:connect (database-connection clog-obj) ...) or if a +connection exists assign it to the database-connecton.@@ -5673,7 +5677,7 @@ https://developer.mozilla.org/en-US/docs/Web/CSS/font
-+
Create a CLOG video control
+ + ++ +
CLOG-AUTH - authorization abstraction for CLOG
+ + + +[function] GET-AUTHENTICATION-TOKEN BODY &KEY AUTH-PATH
+ +Retrieve the stored authentication token
+
-
ON-FILE-NAME called with filename or nil if fai
-+
-
OBJ instead of bottom of OBJ
[function] CLOG-WEB-FORM OBJ CONTENT FIELDS ON-INPUT &KEY (MODAL NIL) (OK-TEXT "OK") (CANCEL-TEXT "Cancel") (HTML-ID NIL)
[function] CLOG-WEB-FORM OBJ CONTENT FIELDS ON-INPUT &KEY (MODAL NIL) (OK-TEXT "OK") (CANCEL-TEXT "Cancel") (CLASS NIL) (HTML-ID NIL)
Create a form with CONTENT followed by FIELDS.
FIELDS is a list of lists each list has:
OBJ instead of bottom of OBJCANCEL-TEXT is only displayed if modal is t[function] FORM-RESULT RESULT KEY
+ +Return the value for KEY from RESULT
CLOG-WEB - Websites
@@ -7235,24 +7289,32 @@ element.
[function] CLOG-WEB-META DESCRIPTION
-Returns a boot-function for use with CLOG:INITIALIZE to add meta and body
-information for search engines with DESCRIPTION.
Returns a boot-function for use with CLOG:INITIALIZE to add meta
+and no-script body information for search engines with DESCRIPTION.
[function] DEFAULT-THEME BODY WEBSITE PAGE PROPERTIES
+[generic-function] CREATE-WEB-SITE CLOG-OBJ &KEY THEME SETTINGS URL TITLE FOOTER LOGO PROFILE
-The default theme for clog-web-site. -Settings available: - :menu-class - w3 color class for menu bar -Page properties: - :menu - (("Menu Name" (("Menu Item" "link")))) - :content
Attach a clog-web-site to a CLOG-OBJ generally a
+clog-body.
[generic-function] CREATE-WEB-PAGE CLOG-OBJ PAGE PROPERTIES
+ +Use the clog-web-site THEME to create PAGE with
+CLOG-OBJ as parent
CLOG-WEB-SITE - Accessors
[generic-function] CREATE-WEB-SITE CLOG-OBJ &KEY THEME SETTINGS URL TITLE FOOTER LOGO
- -Attach a clog-web-site to a CLOG-OBJ generally a
-clog-body.
[generic-function] CREATE-WEB-PAGE CLOG-OBJ PAGE PROPERTIES
- -Use the clog-web-site THEME to create PAGE with
-CLOG-OBJ as parent
CLOG-WEB - Utilities
@@ -7348,12 +7397,98 @@ clog-body.
Split path by / adjusting for base-url
+ + ++ +
Authentication
+ + + +[function] LOGIN OBJ SQL-CONNECTION USERNAME PASSWORD
+ +Login and set current authentication token, it does not remove token +if one is present and login fails.
[function] LOGOUT OBJ
+ +Logout and remove current authenitcation token
[function] GET-PROFILE OBJ SQL-CONNECTION
+ +Retrieve profile based on current authentication token. If there is +no token or fails to match as user returns nil
+ +
Built in themes
+ + + +[function] DEFAULT-THEME BODY WEBSITE PAGE PROPERTIES
+ +The default theme for clog-web-site. +Settings available: + :menu-class - w3 color class for menu bar +Page properties: + :menu - (("Menu Name" (("Menu Item" "link")))) + :content
+
-
CLOG-Body - CLOG Body Objects
@@ -7429,7 +7564,7 @@ withHTML.
-
CLOG-Window - CLOG Window Objects
@@ -7834,7 +7969,7 @@ on-storage event is fired for changes to :local storage keys.-
CLOG-Document - CLOG Document Objects
@@ -8006,7 +8141,7 @@ IfON-FULL-SCREEN-CHANGE-HANDLER is nil unbind the event.
-
Clog-Location - CLOG Location Objects
@@ -8117,7 +8252,7 @@ IfON-FULL-SCREEN-CHANGE-HANDLER is nil unbind the event.
[generic-function] URL-REPLACE CLOG-WINDOW REPLACE-URL
+[generic-function] URL-REPLACE CLOG-LOCATION REPLACE-URL
Replace browser url, ie a redirection and current URL not
saved in session history and back button will not return to it.
[generic-function] URL-ASSIGN CLOG-WINDOW ASSIGN-URL
+[generic-function] URL-ASSIGN CLOG-LOCATION ASSIGN-URL
Assign browser url.
-
CLOG-Navigator - CLOG Navigator Objects
@@ -8193,7 +8328,7 @@ saved in session history and back button will not return to it.-
CLOG-jQuery - Base class for CLOG jQuery Objects
@@ -8260,7 +8395,7 @@ result orDEFAULT-ANSWER on time out.
-
Tutorial and demo helpers
@@ -8379,7 +8514,7 @@ set (logging to browser console),-
* Introduction to Internals *
diff --git a/source/clog-web-dbi.lisp b/source/clog-web-dbi.lisp new file mode 100644 index 0000000..64c1cdf --- /dev/null +++ b/source/clog-web-dbi.lisp @@ -0,0 +1,142 @@ +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;; CLOG - The Common Lisp Omnificent GUI ;;;; +;;;; (c) 2020-2022 David Botton ;;;; +;;;; License BSD 3 Clause ;;;; +;;;; ;;;; +;;;; clog-web-dbi.lisp ;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;; Database components for use with clog-web-website + +(mgl-pax:define-package :clog-web-dbi + (:documentation "CLOG-WEB-DBI - dbi based website helpers") + (:use #:cl #:parse-float #:clog #:clog-web #:clog-auth #:mgl-pax)) + +(cl:in-package :clog-web-dbi) + +(defsection @clog-web-dbi (:title "CLOG Web DBI - dbi based website") + "Authentication" + (login function) + (logout function) + (get-profile function) + (sign-up function) + (make-token function) + (create-base-tables function)) + +;;;;;;;;;;;;;;;;; +;; get-profile ;; +;;;;;;;;;;;;;;;;; + +(defun get-profile (obj sql-connection) + "Retrieve profile based on current authentication token. If there is +no token or fails to match as user returns nil" + (let ((token (clog-auth:get-authentication-token obj))) + (when token + (let ((contents (dbi:fetch-all + (dbi:execute + (dbi:prepare + sql-connection + "select * from users where token=?") + (list token))))) + (when contents + (car contents)))))) + +;;;;;;;;;;; +;; login ;; +;;;;;;;;;;; + +(defun login (obj sql-connection username password) + "Login and set current authentication token, it does not remove token +if one is present and login fails." + (let ((contents (dbi:fetch-all + (dbi:execute + (dbi:prepare + sql-connection + "select token from users where username=? and password=?") + (list username password))))) + (when contents + (store-authentication-token obj (getf (car contents) :|token|))))) + +;;;;;;;;;;;; +;; logout ;; +;;;;;;;;;;;; + +(defun logout (obj) + "Logout and remove current authenitcation token" + (remove-authentication-token obj)) + +;;;;;;;;;;;;; +;; sign-up ;; +;;;;;;;;;;;;; + +(defun sign-up (obj sql-connection &key (title "Sign Up") + (next-step "/login")) + (clog-web-form + obj title + `(("Username" "username") + ("Password" "password" :password) + ("Retype Password" "repass" :password)) + (lambda (result) + (cond ((not + (equal (form-result result "password") + (form-result result "repass"))) + (clog-web-alert obj "Mismatch" + "The passwords do match." + :time-out 3 + :place-top t)) + ((< (length (form-result result "password")) 4) + (clog-web-alert obj "Missize" + "The passwords must at least 4 characters." + :time-out 3 + :place-top t)) + ((< (length (form-result result "username")) 4) + (clog-web-alert obj "Missize" + "The username must be at least 4 characters." + :time-out 3 + :place-top t)) + (t + (let ((contents (dbi:fetch-all + (dbi:execute + (dbi:prepare + sql-connection + "select username from users where username=?") + (list (form-result result "username")))))) + (cond (contents + (clog-web-alert obj "Exists" + "The username is not available." + :time-out 3 + :place-top t)) + (t + (dbi:do-sql + sql-connection + (sql-insert* + "users" + `(:username ,(form-result result "username") + :password ,(form-result result "password") + :token ,(make-token)))) + (url-replace (location obj) next-step))))))))) + +;;;;;;;;;;;;;;;; +;; make-token ;; +;;;;;;;;;;;;;;;; + +(defun make-token () + (get-universal-time)) + +;;;;;;;;;;;;;;;;;;;;;;; +;; create-base-table ;; +;;;;;;;;;;;;;;;;;;;;;;; + +(defun create-base-tables (sql-connection) + (dbi:do-sql + sql-connection + "create table config (key varchar, value varchar)") + (dbi:do-sql + sql-connection + "create table users (username varchar, password varchar, token varchar)") + (dbi:do-sql + sql-connection + (sql-insert* "users" `(:username "admin" + :password "admin" + :token ,(make-token))))) + diff --git a/source/clog-web-themes.lisp b/source/clog-web-themes.lisp index 187a221..20c9840 100644 --- a/source/clog-web-themes.lisp +++ b/source/clog-web-themes.lisp @@ -70,7 +70,8 @@ Page properties: (l2 (create-label p2 :content "Password")) (pass (create-form-element p2 :password :name "password" :class "w3-input")) (p3 (create-p form))) - (declare (ignore l1 l2)) + + (declare (ignore l1 l2 p3)) (setf (maximum-width outter) (unit :px 500)) (setf (requiredp user) t) (setf (requiredp pass) t) @@ -78,7 +79,9 @@ Page properties: :class (format nil "~A ~A" "w3-button" (getf (settings website) :menu-class))) - (set-on-submit form (getf properties :on-submit)))) + (set-on-submit form (getf properties :on-submit)) + (when (getf properties :sign-up) + (create-a form :class "w3-right" :content "sign up" :link (getf properties :sign-up))))) (create-br body) (create-br body) (create-div body :content (format nil "~A" (footer website)))) diff --git a/source/clog-web.lisp b/source/clog-web.lisp index 3519c7e..db6e91a 100644 --- a/source/clog-web.lisp +++ b/source/clog-web.lisp @@ -93,19 +93,23 @@ "CLOG-WEB - Interactions" (clog-web-alert function) (clog-web-form function) + (form-result function) "CLOG-WEB - Websites" (clog-web-site class) (clog-web-routes-from-menu function) (clog-web-meta function) + (create-web-site generic-function) + (create-web-page generic-function) + + "CLOG-WEB-SITE - Accessors" (theme generic-function) (settings generic-function) + (profile generic-function) (url generic-function) (title generic-function) (footer generic-function) (logo generic-function) - (create-web-site generic-function) - (create-web-page generic-function) "CLOG-WEB - Utilities" (base-url-p function) @@ -862,9 +866,14 @@ is placed in DOM at top of OBJ instead of bottom of OBJ." (sleep time-out) (destroy panel)))) +(defun form-result (result key) + "Return the value for KEY from RESULT" + (second (assoc key result :test #'equal))) + (defun clog-web-form (obj content fields on-input &key (modal nil) (ok-text "OK") (cancel-text "Cancel") + (class nil) (html-id nil)) "Create a form with CONTENT followed by FIELDS. FIELDS is a list of lists each list has: @@ -1015,6 +1024,8 @@ if confirmed or nil if canceled. CANCEL-TEXT is only displayed if modal is t" (defclass clog-web-site () ((theme :initarg :theme :accessor theme) + (profile :initarg :profile + :accessor profile) (settings :initarg :settings :reader settings) (url :initarg :url @@ -1032,13 +1043,14 @@ if confirmed or nil if canceled. CANCEL-TEXT is only displayed if modal is t" ;;;;;;;;;;;;;;;;;;; (defun clog-web-meta (description) - "Returns a boot-function for use with CLOG:INITIALIZE to add meta and body -information for search engines with DESCRIPTION." + "Returns a boot-function for use with CLOG:INITIALIZE to add meta +and no-script body information for search engines with DESCRIPTION." (lambda (path content) (declare (ignore path)) (funcall (cl-template:compile-template content) - (list :meta (format nil "" description) - :body description)))) + (list :meta (format nil "" + description) + :body description)))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; clog-web-routes-from-menu ;; @@ -1067,18 +1079,20 @@ clog-body.")) (defmethod create-web-site ((obj clog-obj) &key settings + (profile nil) (theme 'default-theme) (url "/") (title "") (footer "") (logo "")) (let ((website (make-instance 'clog-web-site - :theme theme :settings settings - :url url - :title title - :footer footer - :logo logo)) + :profile profile + :theme theme + :url url + :title title + :footer footer + :logo logo)) (app (connection-data-item obj "clog-web"))) (setf (web-site app) website) website)) diff --git a/source/clog.lisp b/source/clog.lisp index 4984cb3..8ff0926 100644 --- a/source/clog.lisp +++ b/source/clog.lisp @@ -48,6 +48,7 @@ embedded in a native template application.)" (@clog-auth section) (@clog-gui section) (@clog-web section) + (@clog-web-dbi section) (@clog-web-themes section) (@clog-body section) (@clog-window section)