From achiumenti at common-lisp.net Tue Aug 26 10:59:27 2008 From: achiumenti at common-lisp.net (achiumenti at common-lisp.net) Date: Tue, 26 Aug 2008 06:59:27 -0400 (EDT) Subject: [claw-cvs] r73 - in trunk/main/claw: . src Message-ID: <20080826105927.763231D165@common-lisp.net> Author: achiumenti Date: Tue Aug 26 06:59:27 2008 New Revision: 73 Modified: trunk/main/claw/claw.asd trunk/main/claw/src/auth.lisp trunk/main/claw/src/lisplet.lisp trunk/main/claw/src/misc.lisp trunk/main/claw/src/packages.lisp trunk/main/claw/src/server.lisp Log: CLAW application server Modified: trunk/main/claw/claw.asd ============================================================================== --- trunk/main/claw/claw.asd (original) +++ trunk/main/claw/claw.asd Tue Aug 26 06:59:27 2008 @@ -31,7 +31,7 @@ :name "claw" :author "Andrea Chiumenti" :description "Common Lisp Active Web.A famework to write web applications" - :depends-on (:closer-mop :alexandria :cl-ppcre :cl-fad :local-time :split-sequence :bordeaux-threads :md5) + :depends-on (:closer-mop :cl-ppcre :cl-fad :alexandria :local-time :split-sequence :bordeaux-threads :md5) :components ((:module src :components ((:file "packages") (:file "mime-type" :depends-on ("packages")) Modified: trunk/main/claw/src/auth.lisp ============================================================================== --- trunk/main/claw/src/auth.lisp (original) +++ trunk/main/claw/src/auth.lisp Tue Aug 26 06:59:27 2008 @@ -57,4 +57,5 @@ (defun login () "Performs user authentication for the reaml where the request has been created" (let* ((login-config (gethash *claw-current-realm* (clawserver-login-config *clawserver*)))) - (configuration-login login-config))) \ No newline at end of file + (when (and login-config (null (current-principal))) + (setf (current-principal) (configuration-login login-config))))) \ No newline at end of file Modified: trunk/main/claw/src/lisplet.lisp ============================================================================== --- trunk/main/claw/src/lisplet.lisp (original) +++ trunk/main/claw/src/lisplet.lisp Tue Aug 26 06:59:27 2008 @@ -125,6 +125,8 @@ (defmethod clawserver-register-lisplet ((clawserver clawserver) (lisplet lisplet)) (let ((lisplets (clawserver-lisplets clawserver)) (location (lisplet-base-path lisplet))) + (unless (string= "/" (subseq location 0 1)) + (setf location (concatenate 'string "/" location))) (setf (clawserver-lisplets clawserver) (sort-by-location (pushnew-location (cons location lisplet) @@ -133,6 +135,8 @@ (defmethod clawserver-unregister-lisplet ((clawserver clawserver) (lisplet lisplet)) (let ((lisplets (clawserver-lisplets clawserver)) (location (lisplet-base-path lisplet))) + (unless (string= "/" (subseq location 0 1)) + (setf location (concatenate 'string "/" location))) (remove-by-location location lisplets))) @@ -146,6 +150,8 @@ :basic)) (defmethod lisplet-register-function-location ((lisplet lisplet) function location &key welcome-page-p login-page-p) + (unless (string= "/" (subseq location 0 1)) + (setf location (concatenate 'string "/" location))) (let ((pages (lisplet-pages lisplet))) (setf (lisplet-pages lisplet) (sort-by-location (pushnew-location (cons location function) pages))) @@ -155,6 +161,8 @@ (setf (lisplet-login-page lisplet) location)))) (defmethod lisplet-register-resource-location ((lisplet lisplet) resource-path location &optional content-type) + (unless (string= "/" (subseq location 0 1)) + (setf location (concatenate 'string "/" location))) (let ((pages (lisplet-pages lisplet))) (setf (lisplet-pages lisplet) (sort-by-location (pushnew-location @@ -165,7 +173,7 @@ (uri-to-pathname (subseq (claw-script-name) (+ (length (clawserver-base-path *clawserver*)) (length (lisplet-base-path lisplet)) - (length location) 1))) + (length location) ))) resource-path))) (claw-handle-static-file resource-full-path content-type))) #'(lambda () (claw-handle-static-file resource-path content-type)))) @@ -174,11 +182,14 @@ (defmethod lisplet-dispatch-request ((lisplet lisplet) uri) (let ((dispatchers (lisplet-pages lisplet)) - (rel-script-name (subseq uri (1+ (length (build-lisplet-location lisplet)))))) + (rel-script-name (subseq uri (length (build-lisplet-location lisplet))))) + (setf (claw-return-code) +http-not-found+) (loop for dispatcher in dispatchers for url = (car dispatcher) for action = (cdr dispatcher) - do (when (starts-with-subseq rel-script-name url) (return (funcall action)))))) + do (when (starts-with-subseq url rel-script-name) + (setf (claw-return-code) +http-ok+) + (return (funcall action)))))) (defmethod lisplet-dispatch-method ((lisplet lisplet)) (let* ((*claw-current-realm* (lisplet-realm lisplet)) @@ -232,18 +243,19 @@ (loop for protected-resource in protected-resources for match = (format nil "~a/~a" base-path (car protected-resource)) for allowed-roles = (cdr protected-resource) - do (when (or (starts-with-subseq match uri) (string= login-page-url uri)) - (cond - ((and princp (not (user-in-role-p allowed-roles)) (not (string= login-page-url uri))) - (setf (claw-return-code) +http-forbidden+) - (throw 'handler-done nil)) - ((and (null princp) auth-basicp) - (setf (claw-return-code) +http-authorization-required+ - (claw-header-out "WWW-Authenticate") (format nil "Basic realm=\"~A\"" *claw-current-realm*)) - (throw 'handler-done nil)) - ((and (null princp) (null auth-basicp) (not (string= login-page-url uri))) - (redirect-to-https login-page-url) - (throw 'handler-done nil)) - ((and sslport (not (= (claw-server-port) sslport))) - (redirect-to-https) - (throw 'handler-done nil)))))))) + do + (when (or (starts-with-subseq match uri) (string= login-page-url uri)) + (cond + ((and princp (not (user-in-role-p allowed-roles)) (not (string= login-page-url uri))) + (setf (claw-return-code) +http-forbidden+) + (throw 'handler-done nil)) + ((and (null princp) auth-basicp) + (setf (claw-return-code) +http-authorization-required+ + (claw-header-out "WWW-Authenticate") (format nil "Basic realm=\"~A\"" *claw-current-realm*)) + (throw 'handler-done nil)) + ((and (null princp) (null auth-basicp) (not (string= login-page-url uri))) + (redirect-to-https login-page-url) + (throw 'handler-done nil)) + ((and sslport (not (= (claw-server-port) sslport))) + (redirect-to-https) + (throw 'handler-done nil)))))))) Modified: trunk/main/claw/src/misc.lisp ============================================================================== --- trunk/main/claw/src/misc.lisp (original) +++ trunk/main/claw/src/misc.lisp Tue Aug 26 06:59:27 2008 @@ -415,7 +415,7 @@ "Detects if current principal belongs to any of the expressed roles" (let ((principal (current-principal))) (when principal - (loop for el in (principal-roles principal) thereis (member el roles))))) + (loop for el in (principal-roles principal) thereis (member el roles :test #'string-equal))))) (defun current-config () "Returns the current configuration object for the realm of the request" @@ -495,6 +495,8 @@ (defun register-library-resource (location resource-path &optional content-type) "Adds a RESOURCE \(a file or directory) as a library exposed resource to the given relative LOCATION." + (unless (string= "/" (subseq location 0 1)) + (setf location (concatenate 'string "/" location))) (setf *claw-libraries-resources* (sort-by-location (pushnew-location (cons location Modified: trunk/main/claw/src/packages.lisp ============================================================================== --- trunk/main/claw/src/packages.lisp (original) +++ trunk/main/claw/src/packages.lisp Tue Aug 26 06:59:27 2008 @@ -31,8 +31,9 @@ (defpackage :claw - (:use :cl :closer-mop :alexandria :cl-ppcre :cl-fad :local-time :split-sequence :bordeaux-threads :md5) + (:use :cl :closer-mop :alexandria :cl-ppcre :local-time :split-sequence :bordeaux-threads :md5) (:shadow :flatten) + (:import-from :cl-fad :directory-pathname-p) (:documentation "A comprehensive web application framework and server for the Common Lisp programming language") (:export #:*clawserver-base-path* #:*apache-http-port* @@ -135,15 +136,10 @@ #:session-manager #:default-session-manager - - #:error-page - #:error-page-renderer + #:error-renderer #:mime-type #:duplicate-back-slashes - - #:make-page-renderer - #:lisplet #:lisplet-log-manager #:lisplet-server-addrss Modified: trunk/main/claw/src/server.lisp ============================================================================== --- trunk/main/claw/src/server.lisp (original) +++ trunk/main/claw/src/server.lisp Tue Aug 26 06:59:27 2008 @@ -1,4 +1,4 @@ -;; -*- Mode: LISP; Syntax: COMMON-LISP; Package: CL-USER; Base: 10 -*- +;;; -*- Mode: LISP; Syntax: COMMON-LISP; Package: CL-USER; Base: 10 -*- ;;; $Header: src/server.lisp $ ;;; Copyright (c) 2008, Andrea Chiumenti. All rights reserved. @@ -30,7 +30,7 @@ (in-package :claw) ;;------------------------------------------------------------------------------------------ -(defgeneric error-page-renderer (clawserver &key error-code) +(defgeneric error-renderer (clawserver &key error-code) (:documentation "Method for rendering http errors. This method should be overridden.")) (defgeneric clawserver-host (clawserver) @@ -41,11 +41,11 @@ (:documentation "Returns the request method as a keyword, i.e. something like :POST. \(This corresponds to the environment variable REQUEST_METHOD in CGI scripts.)")) (defgeneric clawserver-request-uri (clawserver) - (:documentation "Returns the URI for request. + (:documentation "Returns the URI for request. Note that this not the full URI but only the part behind the scheme and authority components, so that if the user has typed http://user:password at www.domain.com/xxx/frob.html?foo=bar into his browser, this function will return \"/xxx/frob.html?foo=bar\". \(This corresponds to the environment variable REQUEST_URI in CGI scripts.")) (defgeneric clawserver-script-name (connector) - (:documentation "Returns the file name \(or path) component of the URI for request, i.e. the part of the string returned by REQUEST-URI in front of the first question mark \(if any). + (:documentation "Returns the file name \(or path) component of the URI for request, i.e. the part of the string returned by REQUEST-URI in front of the first question mark \(if any). \(This corresponds to the environment variable SCRIPT_NAME in CGI scripts.)")) (defgeneric clawserver-query-string (clawserver) @@ -61,14 +61,14 @@ The elements of this list are in the same order as they were within the request URI. See also CLAWSERVER-GET-PARAMETER.")) (defgeneric clawserver-post-parameter (clawserver name) - (:documentation "Returns the value of the POST parameter \(as provided in the request's body) named by the string name. -Note that only the first value will be returned if the client provided more than one POST parameter with the name name. + (:documentation "Returns the value of the POST parameter \(as provided in the request's body) named by the string name. +Note that only the first value will be returned if the client provided more than one POST parameter with the name name. This value will usually be a string \(or NIL if there ain't no POST parameter with this name). If, however, the browser sent a file through a multipart/form-data form, the value of this function is a three-element list \(path file-name content-type) -where path is a pathname denoting the place were the uploaded file was stored, file-name \(a string) is the file name sent by the browser, and content-type \(also a string) is the content type sent by the browser. +where path is a pathname denoting the place were the uploaded file was stored, file-name \(a string) is the file name sent by the browser, and content-type \(also a string) is the content type sent by the browser. The file denoted by path will be deleted after the request has been handled - you have to move or copy it somewhere else if you want to keep it.")) (defgeneric clawserver-post-parameters (clawserver) @@ -80,7 +80,7 @@ If both a GET and a POST parameter with the name name exist, the GET parameter will be returned. See also CLAWSERVER-GET-PARAMETER and CLAWSERVER-POST-PARAMETER.")) (defgeneric clawserver-header-in (clawserver name) - (:documentation "Returns the incoming header named by the keyword name as a string \(or NIL if there ain't no header with this name). + (:documentation "Returns the incoming header named by the keyword name as a string \(or NIL if there ain't no header with this name). Note that this queries the headers sent to Hunchentoot by the client or by mod_lisp. In the latter case this may not only include the incoming http headers but also some headers sent by mod_lisp. For backwards compatibility, name can also be a string which is matched case-insensitively. See also CLAWSERVER-HEADERS-IN.")) @@ -100,7 +100,7 @@ (:documentation "Returns the IP port (as a number) of the client which sent the request.")) (defgeneric clawserver-real-remote-addr (clawserver) - (:documentation "Returns the value of the incoming X-Forwarded-For http header as the second value in the form of a list of IP addresses and the first element of this list as the first value if this header exists. + (:documentation "Returns the value of the incoming X-Forwarded-For http header as the second value in the form of a list of IP addresses and the first element of this list as the first value if this header exists. Otherwise returns the value of CLAWSERVER-REMOTE-ADDR as the only value.")) (defgeneric clawserver-server-addr (clawserver) @@ -145,15 +145,15 @@ See also CLAWSERVER-HEADERS-OUT, CLAWSERVER-CONTENT-TYPE, CLAWSERVER-CONTENT-LENGTH, CLAWSERVER-COOKIES-OUT, and CLAWSERVER-COOKIE-OUT")) (defgeneric (setf clawserver-header-out) (value clawserver name) - (:documentation "SETF of HEADER-OUT changes the current value of the header named name \(name parameter must be a symbol). -If no header named name exists it is created. -Note that the headers Set-Cookie, Content-Length, and Content-Type must not be set by SETF of HEADER-OUT. + (:documentation "SETF of HEADER-OUT changes the current value of the header named name \(name parameter must be a symbol). +If no header named name exists it is created. +Note that the headers Set-Cookie, Content-Length, and Content-Type must not be set by SETF of HEADER-OUT. Also, there are a couple of \"technical\" headers like Connection or Transfer-Encoding that you're not supposed to set yourself. See also CLAWSERVER-HEADERS-OUT, CLAWSERVER-CONTENT-TYPE, CLAWSERVER-CONTENT-LENGTH, CLAWSERVER-COOKIES-OUT, and CLAWSERVER-COOKIE-OUT")) (defgeneric clawserver-headers-out (clawserver) (:documentation "Returns an alist of all outgoing http parameters \(except for Set-Cookie, Content-Length, and Content-Type). -The car of each element of this list is the headers's name while the cdr is its value. +The car of each element of this list is the headers's name while the cdr is its value. This alist should not be manipulated directly, use SETF of CLAWSERVER-HEADER-OUT instead")) (defgeneric clawserver-cookie-out (clawserver name) @@ -296,53 +296,58 @@ (script-name (connector-script-name connector)) (rel-script-name) (rel-script-name-libs) - (http-result)) - (handler-bind ((error (lambda (cond) - (logger-log (clawserver-log-manager clawserver) :error "~a" cond) - (with-output-to-string (*standard-output*) - (error-page-renderer clawserver :error-code +http-internal-server-error+))))) - (unwind-protect - (catch 'handler-done - (if (starts-with-subseq script-name base-path) - (progn - (setf rel-script-name (subseq script-name (length base-path)) - rel-script-name-libs (subseq script-name (1+ (length base-path)))) - (setf http-result (or - (loop for dispatcher in *claw-libraries-resources* - for url = (car dispatcher) - for action = (cdr dispatcher) - do (when (starts-with-subseq rel-script-name-libs url) (funcall action))) - (loop for lisplet-cons in lisplets - for url = (car lisplet-cons) - for lisplet = (cdr lisplet-cons) - do (when (starts-with-subseq rel-script-name url) (return (funcall #'lisplet-dispatch-method lisplet)))))))))) - (or http-result - (let ((error-handler (and *claw-current-lisplet* - (gethash (or - (let ((return-code (claw-return-code))) - (if (= return-code +http-ok+) - nil - return-code)) - +http-not-found+) - (lisplet-error-handlers *claw-current-lisplet*))))) - (when error-handler - (funcall error-handler))) - (with-output-to-string (*standard-output*) - (error-page-renderer clawserver (or - (let ((return-code (claw-return-code))) - (if (= return-code +http-ok+) - nil - return-code)) - +http-not-found+))))))) + (http-result nil)) + (handler-case + (progn + (unwind-protect + (catch 'handler-done + (progn + (setf (claw-return-code) +http-not-found+) + (if (starts-with-subseq base-path script-name) + (progn + (setf rel-script-name (subseq script-name (length base-path)) + rel-script-name-libs (subseq script-name (length base-path))) + (setf http-result (or + (loop for dispatcher in *claw-libraries-resources* + for url = (car dispatcher) + for action = (cdr dispatcher) + do (when (starts-with-subseq url rel-script-name-libs) + (setf (claw-return-code) +http-ok+) + (funcall action))) + (loop for lisplet-cons in lisplets + for url = (car lisplet-cons) + for lisplet = (cdr lisplet-cons) + do (when (starts-with-subseq url rel-script-name) + (setf (claw-return-code) +http-ok+) + (return (funcall #'lisplet-dispatch-method lisplet))))))))))) + (or http-result + (and (>= (claw-return-code) 400) + (or + (let ((error-handler (and *claw-current-lisplet* + (gethash (or + (let ((return-code (claw-return-code))) + (if (= return-code +http-ok+) + nil + return-code)) + +http-not-found+) + (lisplet-error-handlers *claw-current-lisplet*))))) + (when error-handler + (funcall error-handler))) + (with-output-to-string (*standard-output*) + (error-renderer clawserver :error-code (or + (let ((return-code (claw-return-code))) + (if (= return-code +http-ok+) + nil + return-code)) + +http-not-found+))))) + )) + (error (cond) + (logger-log (clawserver-log-manager clawserver) :error "~a" cond) + (with-output-to-string (*standard-output*) (error-renderer clawserver :error-code +http-internal-server-error+)))))) (defmethod clawserver-dispatch-method ((clawserver clawserver)) - (let ((result (clawserver-dispatch-request clawserver)) - (connector (clawserver-connector clawserver))) - (if (null result) - #'(lambda () (when (= (connector-return-code connector) 200) ;OK - (setf (connector-return-code connector) 404))) ; Not found - #'(lambda () result)))) + #'(lambda () (clawserver-dispatch-request clawserver))) (defmethod clawserver-start ((clawserver clawserver)) (let ((*clawserver* clawserver) @@ -511,13 +516,63 @@ (defmethod clawserver-script-name ((clawserver clawserver)) (connector-script-name (clawserver-connector clawserver))) -(defmethod error-page-renderer ((clawserver clawserver) &key (error-code 404)) - (format nil " +(defmethod error-renderer ((clawserver clawserver) &key (error-code 404)) + (let ((request-uri (connector-request-uri (clawserver-connector clawserver))) + (connector (clawserver-connector clawserver)) + (style "body { + font-family: arial, elvetica; + font-size: 7pt; +} +span.blue { + padding: 0 3px; + background-color: #525D76; + color: white; + font-weight: bolder; + margin-right: .25em; +} +p.h1, p.h2 { + padding: 0 3px; + background-color: #525D76; + color: white; + font-weight: bolder; + font-size: 2em; + margin: 0; + margin-bottom: .5em; +} +p.h2 {font-size: 1.5em;}")) + (setf (connector-return-code connector) error-code) + (format t " Error ~a + -

HTTP Status ~a

-

~a

+

+

+ HTTP Status ~a - ~a +

+
+

+ type + Status report +

+

+ url + ~a +

+

+ description + ~a +

+
+

+ CLAW server +

+

-" error-code error-code (gethash error-code *http-reason-phrase-map*))) \ No newline at end of file +" + error-code ;title + style ;tyle + error-code request-uri + request-uri + (gethash error-code *http-reason-phrase-map*)))) \ No newline at end of file From achiumenti at common-lisp.net Tue Aug 26 11:03:41 2008 From: achiumenti at common-lisp.net (achiumenti at common-lisp.net) Date: Tue, 26 Aug 2008 07:03:41 -0400 (EDT) Subject: [claw-cvs] r74 - trunk/main/claw-demo/test/backend Message-ID: <20080826110341.560E670308@common-lisp.net> Author: achiumenti Date: Tue Aug 26 07:03:39 2008 New Revision: 74 Added: trunk/main/claw-demo/test/backend/ trunk/main/claw-demo/test/backend/tests.lisp Log: CLAW demo tests Added: trunk/main/claw-demo/test/backend/tests.lisp ============================================================================== --- (empty file) +++ trunk/main/claw-demo/test/backend/tests.lisp Tue Aug 26 07:03:39 2008 @@ -0,0 +1,226 @@ +;;; -*- Mode: LISP; Syntax: COMMON-LISP; Package: CL-USER; Base: 10 -*- +;;; $Header: src/setup.lisp $ + +;;; Copyright (c) 2008, Andrea Chiumenti. All rights reserved. + +;;; Redistribution and use in source and binary forms, with or without +;;; modification, are permitted provided that the following conditions +;;; are met: + +;;; * Redistributions of source code must retain the above copyright +;;; notice, this list of conditions and the following disclaimer. + +;;; * Redistributions in binary form must reproduce the above +;;; copyright notice, this list of conditions and the following +;;; disclaimer in the documentation and/or other materials +;;; provided with the distribution. + +;;; THIS SOFTWARE IS PROVIDED BY THE AUTHOR 'AS IS' AND ANY EXPRESSED +;;; OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +;;; WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +;;; ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY +;;; DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +;;; DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE +;;; GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +;;; INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +;;; WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +;;; NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +;;; SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +(in-package :claw-demo-backend) + +(lift:deftestsuite claw-demo-backend-testsuite () + () + (:setup (let ((*default-database* + (db-connect '("127.0.0.1" "claw-demo-test" "claw-demo" "demo")))) + (drop-claw-demo-tables) + (create-claw-demo-tables))) + (:teardown (db-disconnect))) + +(lift:addtest (claw-demo-backend-testsuite) + simple-insert + (let ((role (make-instance 'role :name "admin" :description "Administration role"))) + (update-db-item role) + (lift:ensure (table-id role)) + (setf role (first (find-vo 'role + :where (sql-operation 'like + (sql-expression-upper :attribute (slot-column-name 'role 'name)) + (string-upcase "admiN"))))) + (lift:ensure role) + (lift:ensure (= (table-version role) 0)) + (setf (role-description role) "Administration") + (update-db-item role) + (setf role (first (find-vo 'role + :where (sql-operation 'like + (sql-expression-upper :attribute (slot-column-name 'role 'name)) + (string-upcase "admiN"))))) + (lift:ensure (> (table-version role) 0)))) + +(lift:addtest (claw-demo-backend-testsuite) + simple-empty-table + (let* ((name "simple-empty-table") + (role (make-instance 'role :name name))) + (update-db-item role) + (lift:ensure (find-vo 'role) :report "Role table is empty") + (delete-class-records 'role) + (let ((rs (find-vo 'role :refresh t))) + (lift:ensure-null rs :report "Role table is NOT empty ~a" :arguments ((length rs)))))) + +(lift:addtest (claw-demo-backend-testsuite) + user-roles-relation + (let ((role1 (make-instance 'role :name "role1")) + (role2 (make-instance 'role :name "role2")) + (user (make-instance 'user :firstname "Jhon" + :surname "Doe" + :username "jd" + :password "pwd" + :email "jd at new.com"))) + (delete-class-records 'user-role) + (delete-class-records 'user) + (delete-class-records 'role) + (update-db-item role1) + (update-db-item role2) + (lift:ensure (= (length (find-vo 'role)) 2) :report "Role table size is not 2") + (setf (user-roles user) (list role1 role2)) ;here we add two roles to the user + (update-db-item user) + (multiple-value-bind (records count) + (find-vo 'user) + (lift:ensure (= count 1)) + (lift:ensure (= (length (user-roles (first records))) 2))) + (setf (user-username user) "changed") ;here we ensure that the user doesn't loose roles after a change + (update-db-item user) + (multiple-value-bind (records count) + (find-vo 'user) + (lift:ensure (= count 1)) + (lift:ensure (= (length (user-roles (first records))) 2))))) + +(lift:addtest (claw-demo-backend-testsuite) + user-roles-fk + (let ((role1 (make-instance 'role :name "roleA")) + (role2 (make-instance 'role :name "roleB")) + (user (make-instance 'user :firstname "Jhon" + :surname "Doe" + :username "jd" + :password "pwd" + :email "jd at new.com"))) + (delete-class-records 'user) + (delete-class-records 'role) + (update-db-item role1) + (update-db-item role2) + (setf (user-roles user) (list role1 role2)) + (update-db-item user) + (delete-class-records 'role + :where (sql-operation '= + (sql-expression :attribute (slot-column-name 'role 'name)) + "roleA")) + (setf user (reload-db-item user)) + (lift:ensure (= (length (user-roles user)) 1) + :report "Expected 1 role for test user, found ~d" + :arguments ((length (user-roles user)))) + (lift:ensure (= (length (role-users role2)) 1) + :report "Expected 1 user for test role \"roleB\", found ~d" + :arguments ((length (role-users role2)))) + (delete-class-records 'user) + (lift:ensure (null (find-vo 'user)) + :report "Users table is not empty") + (setf role2 (reload-db-item role2)) + (let ((role-users (role-users role2))) + (lift:ensure (null role-users) + :report "Role \"roleB\" still contains references to ~d user\(s)" + :arguments ((length role-users)))))) + +(lift:addtest (claw-demo-backend-testsuite) + cusromer-creation + (let ((customer (make-instance 'customer + :name1 "Andrea" + :name2 "Chiumenti" + :email "a.chiumenti at new.com" + :phone1 "+393900001" + :phone2 "+393900002" + :phone3 "+393900003" + :fax "+393900010" + :vat "9999999999" + :code1 "code1" + :code1 "code2" + :code1 "code3" + :code1 "code4" + :addresses (list (make-instance 'customer-address + :address "St. Foo, 1" + :city "Milano" + :zip "20100" + :state "MI" + :country "ITALY") + (make-instance 'customer-address + :address-type 1 + :address "St. Bar, 1" + :zip "20100" + :city "Milano" + :state "MI" + :country "ITALY"))))) + (delete-class-records 'customer) + (update-db-item customer) + (let ((addresses (find-vo 'customer-address + :where (sql-operation '= + (sql-expression :attribute (slot-column-name 'customer-address 'customer-id)) + (table-id customer))))) + (lift:ensure (= (length addresses) + 2) + :report "Expected 2 customer address records, found ~d" + :arguments ((length addresses))) + ;;testing referential integrity + (delete-db-item customer) + (let ((addresses (find-vo 'customer-address))) + (lift:ensure-null addresses + :report "Table cutomer-addresses expected to be empty. Found ~d records." + :arguments ((length addresses))))))) + +(lift:addtest (claw-demo-backend-testsuite) + find-user-by-name + (let ((admin-role (make-instance 'role :name "administrator")) + (user-role (make-instance 'role :name "user"))) + (update-db-item admin-role) + (update-db-item user-role) + (update-db-item (make-instance 'user :firstname "Andrea" + :surname "Chiumenti" + :username "admin" + :password "admin" + :email "admin at new.com" + :roles (list admin-role user-role))) + (lift:ensure (find-user-by-name "admin")))) + +(lift:addtest (claw-demo-backend-testsuite) + like-operation + (let ((admin-role (make-instance 'role :name "administrator")) + (user-role (make-instance 'role :name "user"))) + (update-db-item admin-role) + (update-db-item user-role) + (update-db-item (make-instance 'user :firstname "Andrea" + :surname "Chiumenti" + :username "admin\\&1" + :password "admin" + :email "admin at new.com" + :roles (list admin-role user-role))) + (lift:ensure (find-vo 'user :where (like-operation 'username "*n\\&1"))) + (lift:ensure-null (find-vo 'user :where (like-operation 'username "*n\\&"))))) + + +(lift:addtest (claw-demo-backend-testsuite) + find-customers + (let ((customer (make-instance 'customer + :name1 "Andrea" + :name2 "Chiumenti" + :email "a.chiumenti at new.com" + :phone1 "+393900001" + :phone2 "+393900002" + :phone3 "+393900003" + :fax "+393900010" + :vat "9999999999" + :code1 "code1" + :code1 "code2" + :code1 "code3" + :code1 "code4"))) + (delete-class-records 'customer) + (update-db-item customer) + (lift:ensure (find-customers :name1 "andrea")) + (lift:ensure (find-customers :name1 "andrea" :name2 "ch*")) + (lift:ensure (find-customers)))) From achiumenti at common-lisp.net Tue Aug 26 11:06:04 2008 From: achiumenti at common-lisp.net (achiumenti at common-lisp.net) Date: Tue, 26 Aug 2008 07:06:04 -0400 (EDT) Subject: [claw-cvs] r75 - trunk/main/dojo Message-ID: <20080826110604.4148018@common-lisp.net> Author: achiumenti Date: Tue Aug 26 07:06:04 2008 New Revision: 75 Removed: trunk/main/dojo/ Log: CLAW deleted old demo integration From achiumenti at common-lisp.net Tue Aug 26 11:08:36 2008 From: achiumenti at common-lisp.net (achiumenti at common-lisp.net) Date: Tue, 26 Aug 2008 07:08:36 -0400 (EDT) Subject: [claw-cvs] r76 - trunk/main/connectors/hunchentoot/src Message-ID: <20080826110836.0BCD81B000@common-lisp.net> Author: achiumenti Date: Tue Aug 26 07:08:35 2008 New Revision: 76 Modified: trunk/main/connectors/hunchentoot/src/hunchentoot.lisp Log: updated hunchentoot connector Modified: trunk/main/connectors/hunchentoot/src/hunchentoot.lisp ============================================================================== --- trunk/main/connectors/hunchentoot/src/hunchentoot.lisp (original) +++ trunk/main/connectors/hunchentoot/src/hunchentoot.lisp Tue Aug 26 07:08:35 2008 @@ -29,8 +29,9 @@ (in-package :hunchentoot-connector) -(setf hunchentoot:*hunchentoot-default-external-format* (flex:make-external-format :utf-8 :eol-style :lf)) -(setf hunchentoot:*default-content-type* "text/html; charset=utf-8") +(setf hunchentoot:*hunchentoot-default-external-format* (flex:make-external-format :utf-8 :eol-style :lf) + hunchentoot:*default-content-type* "text/html; charset=utf-8" + hunchentoot:*handle-http-errors-p* nil) (defgeneric claw-to-hunchentoot-cookie (claw-cookie) (:documentation "Returns hunchentoot cookie from a claw cookie")) @@ -313,14 +314,12 @@ (defmethod (setf connector-reply-external-format-encoding) (value (connector hunchentoot-connector)) (let ((encoding (flexi-streams:external-format-name (hunchentoot:reply-external-format)))) - ;(log-message :info "ENCODING: ~a| VALUE: ~a" encoding value) (unless (and (null value) (equal encoding value)) (setf (hunchentoot:reply-external-format) (flex:make-external-format value :eol-style :lf))))) (defmethod connector-writer ((connector hunchentoot-connector)) (hunchentoot:send-headers)) - ;*standard-output*) (defmethod connector-redirect ((connector hunchentoot-connector) target &key host port protocol add-session-id code) (hunchentoot:redirect target From achiumenti at common-lisp.net Tue Aug 26 10:49:31 2008 From: achiumenti at common-lisp.net (achiumenti at common-lisp.net) Date: Tue, 26 Aug 2008 06:49:31 -0400 (EDT) Subject: [claw-cvs] r70 - in trunk/main/claw-html.dojo: . src src/js Message-ID: <20080826104931.1144E28266@common-lisp.net> Author: achiumenti Date: Tue Aug 26 06:49:29 2008 New Revision: 70 Added: trunk/main/claw-html.dojo/ trunk/main/claw-html.dojo/README trunk/main/claw-html.dojo/claw-html.dojo.asd trunk/main/claw-html.dojo/src/ trunk/main/claw-html.dojo/src/dijit.lisp trunk/main/claw-html.dojo/src/djbody.lisp trunk/main/claw-html.dojo/src/djbutton.lisp trunk/main/claw-html.dojo/src/djclaw.lisp trunk/main/claw-html.dojo/src/djcolorpalette.lisp trunk/main/claw-html.dojo/src/djcontainers.lisp trunk/main/claw-html.dojo/src/djcontent-pane.lisp trunk/main/claw-html.dojo/src/djdialog.lisp trunk/main/claw-html.dojo/src/djform.lisp trunk/main/claw-html.dojo/src/djlayout.lisp trunk/main/claw-html.dojo/src/djlink.lisp trunk/main/claw-html.dojo/src/djmenu.lisp trunk/main/claw-html.dojo/src/djprogressbar.lisp trunk/main/claw-html.dojo/src/djtitlepane.lisp trunk/main/claw-html.dojo/src/djtoolbar.fasl (contents, props changed) trunk/main/claw-html.dojo/src/djtoolbar.lisp trunk/main/claw-html.dojo/src/djtooltip.lisp trunk/main/claw-html.dojo/src/djtree.lisp trunk/main/claw-html.dojo/src/djwidget.lisp trunk/main/claw-html.dojo/src/js/ trunk/main/claw-html.dojo/src/js/ActionLink.js trunk/main/claw-html.dojo/src/js/Dialog.js trunk/main/claw-html.dojo/src/js/Editor.js trunk/main/claw-html.dojo/src/js/Editor2.js trunk/main/claw-html.dojo/src/js/FloatingContent.js trunk/main/claw-html.dojo/src/js/Form.js trunk/main/claw-html.dojo/src/js/HardLink.js trunk/main/claw-html.dojo/src/js/Rounded.js trunk/main/claw-html.dojo/src/js/claw.js trunk/main/claw-html.dojo/src/misc.lisp trunk/main/claw-html.dojo/src/packages.lisp Log: CLAW dojo integration Added: trunk/main/claw-html.dojo/README ============================================================================== --- (empty file) +++ trunk/main/claw-html.dojo/README Tue Aug 26 06:49:29 2008 @@ -0,0 +1,6 @@ +to use claw-dojo library download dojo at + +http://download.dojotoolkit.org/release-1.1.1/dojo-release-1.1.1.tar.gz + +Then unpack it into the src directory and rename the extacted directory +"dojo-release-1.1.1" from to "dojotoolkit" \ No newline at end of file Added: trunk/main/claw-html.dojo/claw-html.dojo.asd ============================================================================== --- (empty file) +++ trunk/main/claw-html.dojo/claw-html.dojo.asd Tue Aug 26 06:49:29 2008 @@ -0,0 +1,54 @@ +;;; -*- Mode: LISP; Syntax: COMMON-LISP; Package: CL-USER; Base: 10 -*- +;;; $Header: dojo/claw-dojo.asd $ + +;;; Copyright (c) 2008, Andrea Chiumenti. All rights reserved. + +;;; Redistribution and use in source and binary forms, with or without +;;; modification, are permitted provided that the following conditions +;;; are met: + +;;; * Redistributions of source code must retain the above copyright +;;; notice, this list of conditions and the following disclaimer. + +;;; * Redistributions in binary form must reproduce the above +;;; copyright notice, this list of conditions and the following +;;; disclaimer in the documentation and/or other materials +;;; provided with the distribution. + +;;; THIS SOFTWARE IS PROVIDED BY THE AUTHOR 'AS IS' AND ANY EXPRESSED +;;; OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +;;; WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +;;; ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY +;;; DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +;;; DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE +;;; GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +;;; INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +;;; WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +;;; NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +;;; SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +(asdf:defsystem :claw-html.dojo + :name "claw-html.dojo" + :author "Andrea Chiumenti" + :description "claw dojo-1.1.0 integration" + :depends-on (:claw :claw-html :parenscript) + :components ((:module src + :components ((:file "packages") + (:file "misc" :depends-on ("packages")) + (:file "djlink" :depends-on ("misc")) + (:file "djwidget" :depends-on ("misc")) + (:file "djcontent-pane" :depends-on ("misc")) + (:file "djbody" :depends-on ("djcontent-pane")) + (:file "dijit" :depends-on ("djwidget")) + (:file "djclaw" :depends-on ("djwidget")) + (:file "djform" :depends-on ("djwidget")) + (:file "djbutton" :depends-on ("djwidget")) + (:file "djmenu" :depends-on ("djwidget")) + (:file "djdialog" :depends-on ("djwidget")) + (:file "djcolorpalette" :depends-on ("djwidget")) + (:file "djprogressbar" :depends-on ("djwidget")) + (:file "djtitlepane" :depends-on ("djwidget")) + (:file "djtree" :depends-on ("djwidget")) + (:file "djlayout" :depends-on ("djwidget")) + (:file "djtooltip" :depends-on ("djwidget")) + (:file "djtoolbar" :depends-on ("djwidget")))))) Added: trunk/main/claw-html.dojo/src/dijit.lisp ============================================================================== --- (empty file) +++ trunk/main/claw-html.dojo/src/dijit.lisp Tue Aug 26 06:49:29 2008 @@ -0,0 +1,35 @@ +;;; -*- Mode: LISP; Syntax: COMMON-LISP; Package: CL-USER; Base: 10 -*- +;;; $Header: dojo/src/dijit.lisp $ + +;;; Copyright (c) 2008, Andrea Chiumenti. All rights reserved. + +;;; Redistribution and use in source and binary forms, with or without +;;; modification, are permitted provided that the following conditions +;;; are met: + +;;; * Redistributions of source code must retain the above copyright +;;; notice, this list of conditions and the following disclaimer. + +;;; * Redistributions in binary form must reproduce the above +;;; copyright notice, this list of conditions and the following +;;; disclaimer in the documentation and/or other materials +;;; provided with the distribution. + +;;; THIS SOFTWARE IS PROVIDED BY THE AUTHOR 'AS IS' AND ANY EXPRESSED +;;; OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +;;; WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +;;; ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY +;;; DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +;;; DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE +;;; GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +;;; INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +;;; WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +;;; NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +;;; SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +(in-package :dojo) + +(defclass djbackground-iframe (djwidget) + () + (:metaclass metacomponent) + (:documentation "Class for dojo dijit.BackgroundIframe component. More info at http://api.dojotoolkit.org/")) Added: trunk/main/claw-html.dojo/src/djbody.lisp ============================================================================== --- (empty file) +++ trunk/main/claw-html.dojo/src/djbody.lisp Tue Aug 26 06:49:29 2008 @@ -0,0 +1,121 @@ +;;; -*- Mode: LISP; Syntax: COMMON-LISP; Package: CL-USER; Base: 10 -*- +;;; $Header: dojo/src/djbody.lisp $ + +;;; Copyright (c) 2008, Andrea Chiumenti. All rights reserved. + +;;; Redistribution and use in source and binary forms, with or without +;;; modification, are permitted provided that the following conditions +;;; are met: + +;;; * Redistributions of source code must retain the above copyright +;;; notice, this list of conditions and the following disclaimer. + +;;; * Redistributions in binary form must reproduce the above +;;; copyright notice, this list of conditions and the following +;;; disclaimer in the documentation and/or other materials +;;; provided with the distribution. + +;;; THIS SOFTWARE IS PROVIDED BY THE AUTHOR 'AS IS' AND ANY EXPRESSED +;;; OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +;;; WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +;;; ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY +;;; DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +;;; DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE +;;; GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +;;; INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +;;; WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +;;; NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +;;; SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +(in-package :dojo) + +(defgeneric scripts-content-pane> (&rest rest)) + +(defclass djbody (wcomponent) + ((class :initarg :class + :reader djbody-class + :documentation "The css class of the tag element") + (theme :initarg :theme + :reader djbody-theme + :documentation "The theme name. See http://dojotoolkit.org/book/dojo-book-0-9/part-2-dijit/themes-and-design for more details") + (themes-url :initarg :themes-url + :reader djbody-themes-url + :documentation "The url that contains dojo themes") + (parse-on-load-p :initarg :parse-on-load + :reader djbody-parse-on-load-p + :documentation "Shoul always be true") + (debugp :initarg :is-debug + :reader djbody-debugp + :documentation "Set to true if you want to debug dojo calls") + (load-dojo-js :initarg :load-dojo-js + :reader load-dojo-js + :documentation "When not nil it loads the dojo.js file with a