From 3f456a6d1e08fc0930e9d73e8988934f41d79603 Mon Sep 17 00:00:00 2001 From: ckonstanski Date: Sun, 23 Aug 2026 23:10:30 -0600 Subject: stuff --- lisp/resume.asd | 1 + lisp/service/resume-service.lisp | 280 +++++++++++++-------- lisp/sql/job-skill.lisp | 18 ++ .../clojurescript/resume/src/resume/core.clj | 93 ++++++- .../clojurescript/resume/src/resume/core.cljs | 31 +-- 5 files changed, 302 insertions(+), 121 deletions(-) create mode 100644 lisp/sql/job-skill.lisp (limited to 'lisp') diff --git a/lisp/resume.asd b/lisp/resume.asd index 00d7f9b..6681333 100644 --- a/lisp/resume.asd +++ b/lisp/resume.asd @@ -50,6 +50,7 @@ (:file "language" :depends-on ("generics")) (:file "resume" :depends-on ("generics")) (:file "skill" :depends-on ("generics")) + (:file "job-skill" :depends-on ("generics")) (:file "states" :depends-on ("generics")) (:file "visastatus" :depends-on ("generics")) (:file "auth-pkg" :depends-on ("user-session-pkg" "user" "role-group" "user-role" "registration")) diff --git a/lisp/service/resume-service.lisp b/lisp/service/resume-service.lisp index 6a8e589..c4a4d16 100644 --- a/lisp/service/resume-service.lisp +++ b/lisp/service/resume-service.lisp @@ -21,6 +21,39 @@ `(:label ,level :value ,level)) '("A1" "A2" "B1" "B2" "C1" "C2"))) + (defun skill-checkboxes (resume-pkg user-id job-id) + (let ((skills (get-records resume-pkg (make-instance 'skill :user_id user-id) "skill asc")) + (job-skills (get-records resume-pkg (make-instance 'job-skill :job_id job-id) "skill_id asc"))) + (mapcar (lambda (skill) + (let ((checked (when (intersection `(,(id skill)) + (mapcar (lambda (x) + (skill_id x)) + job-skills) + :test '=) + '(:checked "checked" :value "on")))) + `(:name ,(format nil "chk_job_skill_link_~a" (id skill)) :label ,(skill skill) :field-type "checkbox" ,@checked))) + skills))) + + (defun link-job (id skill-ids) + (with-resume-database + (let* ((resume-pkg (make-instance 'resume-pkg)) + (skill-id-list (cl-ppcre:split "\\|" skill-ids))) + (loop for skill-id in skill-id-list + do (let* ((job-skill (make-instance 'job-skill + :job_id id + :skill_id skill-id))) + (when (null (get-record resume-pkg job-skill)) + (insert-record resume-pkg job-skill)))) + (delete-records-where resume-pkg + (make-instance 'job-skill) + (format nil + "job_id = ~a and skill_id not in (~a)" + id + (org-ckons-core::reduce-to-comma-separated-string skill-id-list)))))) + + (defun link-resume () + ) + (defclass resume/resume-service (auth-service) ((title :initarg :title :initform nil @@ -42,7 +75,7 @@ ;; macros -(defmacro define-resume-component ((component-s rest-args input-add-fields input-modify-fields order-by &key view-p)) +(defmacro define-resume-component ((&key component-s rest-args link-rest-args add-fields modify-fields link-fields order-by view-p)) "`component-s' is a symbol that matches the component's record object name, i.e SKILL, JOB, EDUCATION, LANGUAGE, CONTACTINFO. This will be used all over the place. The record name equals the component name. @@ -50,8 +83,12 @@ used all over the place. The record name equals the component name. `rest-args' is the list of REST API arguments for the add and modify forms. In the form like this example: ((id :parameter-type 'integer)) -`input-add-fields' and `input-modify-fields' are lists of generic form -fields that get inserted into the add and modify forms. +`link-rest-args' is the the same, but only for the linking form (job +and resume). + +`add-fields', `modify-fields' and `link-fields' are lists of generic +form fields that get inserted into the add, modify and link forms. If +`link-fields' is `nil' then the linking form will not be included. `view-p' is `t' if the component has a view in the database because it needs to JOIN with other data." @@ -60,15 +97,19 @@ needs to JOIN with other data." (component-s (intern (format nil "~a" component))) (table (format nil "resume.~a~a" component-lcase (if view-p "_v" ""))) (arg-names (loop for arg in rest-args collect (car arg))) + (link-arg-names (loop for arg in link-rest-args collect (car arg))) (func-root-s (intern (format nil "~a-JSON" component))) (func-view-s (intern (format nil "~a-VIEW-JSON" component))) (func-add-s (intern (format nil "~a-ADD-JSON" component))) (func-add-submit-s (intern (format nil "~a-ADD-SUBMIT-JSON" component))) (func-modify-s (intern (format nil "~a-MODIFY-JSON" component))) (func-modify-submit-s (intern (format nil "~a-MODIFY-SUBMIT-JSON" component))) + (func-link-s (intern (format nil "~a-LINK-JSON" component))) + (func-link-submit-s (intern (format nil "~a-LINK-SUBMIT-JSON" component))) (func-delete-s (intern (format nil "~a-DELETE-JSON" component))) (form-add (format nil "~a-add-form" component-lcase)) - (form-modify (format nil "~a-modify-form" component-lcase))) + (form-modify (format nil "~a-modify-form" component-lcase)) + (form-link (format nil "~a-link-form" component-lcase))) `(progn (defun ,func-root-s () (with-auth (instance resume/resume-service "resume-view") @@ -90,11 +131,13 @@ needs to JOIN with other data." (defun ,func-add-s () (with-auth (instance resume/resume-component/modify-service "resume-modify") - (setf (title instance) (format nil "~a - Add" ,component)) - (setf (form instance) (make-form ,form-add - nil - t - ,input-add-fields)))) + (with-resume-database + (let* ((resume-pkg (make-instance 'resume-pkg))) + (setf (title instance) (format nil "~a - Add" ,component)) + (setf (form instance) (make-form ,form-add + nil + t + ,add-fields)))))) (defun ,func-add-submit-s (,@arg-names) (declare (special ,@arg-names)) @@ -127,13 +170,12 @@ needs to JOIN with other data." (setf (form instance) (make-form ,form-modify nil t - ,input-modify-fields)) + ,modify-fields)) (setf (session-value :errormsg) (format nil "Error: could not modify ~a. Not found." ,component))))))) (defun ,func-modify-submit-s (,@(append '(id) arg-names)) (declare (special ,@(append '(id) arg-names))) (with-auth (instance resume/resume-component/modify-service "resume-modify") - (setf (title instance) (format nil "~a - Modify" ,component)) (with-resume-database (handler-case (let* ((resume-pkg (make-instance 'resume-pkg)) @@ -155,6 +197,34 @@ needs to JOIN with other data." (setf (session-value :errormsg) (format nil "Error modifying ~a. ~a" ,component e)) (setf (errormsg instance) (session-value :errormsg))))))) + (defun ,func-link-s (&optional id) + (with-auth (instance resume/resume-component/modify-service "resume-modify") + (setf (title instance) (format nil "~a - Link" ,component)) + (when (> (length ',link-arg-names) 0) + (with-resume-database + (let* ((resume-pkg (make-instance 'resume-pkg)) + (user (get-user)) + (,component-s (get-record resume-pkg (make-instance ',component-s + :id id + :user_id (id user) + :*table ,table)))) + (if ,component-s + (setf (form instance) (make-form ,form-link + nil + t + ,link-fields)) + (setf (session-value :errormsg) (format nil "Error: could not link ~a. Not found." ,component)))))))) + + (defun ,func-link-submit-s (&rest args) + (with-auth (instance resume/resume-component/modify-service "resume-modify") + (handler-case + (progn + (apply `,(intern (format nil "LINK-~a" ,component) (intern (package-name #.*package*))) args) + (setf (message instance) (format nil "~a linked successfully." ,component))) + (error (e) + (setf (errormsg instance) (format nil "Error linking ~a. ~a" ,component e)))))) + + (defun ,func-delete-s (id) (with-auth (instance resume/resume-component/modify-service "resume-modify") (with-resume-database @@ -179,101 +249,107 @@ needs to JOIN with other data." (define-endpoint (,(format nil "/resume/~a/add/submit" component-lcase) :method :post) (&post ,@rest-args) ,func-add-submit-s ,@arg-names) (define-endpoint (,(format nil "/resume/~a/modify" component-lcase) :method :post) (&post (id :parameter-type 'integer)) ,func-modify-s id) (define-endpoint (,(format nil "/resume/~a/modify/submit" component-lcase) :method :post) (&post (id :parameter-type 'integer) ,@rest-args) ,func-modify-submit-s ,@(append '(id) arg-names)) + (define-endpoint (,(format nil "/resume/~a/link" component-lcase) :method :post) (&post (id :parameter-type 'integer)) ,func-link-s id) + (define-endpoint (,(format nil "/resume/~a/link/submit" component-lcase) :method :post) (&post (id :parameter-type 'integer) ,@link-rest-args) ,func-link-submit-s ,@(append '(id) link-arg-names)) (define-endpoint (,(format nil "/resume/~a/delete/:id" component-lcase) :method :delete) (&path (id 'integer)) ,func-delete-s id)))) -(define-resume-component (resume - ((name :parameter-type 'string)) - `((:name "name" :label "Name" :field-type "text" :required "required") - (:label "Add RESUME" :field-type "button" :onclick "on_resume_add_submit_clicked()")) - `((:name "id" :field-type "hidden" :value ,(id resume) :required "required") - (:name "name" :label "Name" :field-type "text" :value ,(name resume) :required "required") - (:label "Modify RESUME" :field-type "button" :onclick "on_resume_modify_submit_clicked()")) - "name asc")) +(define-resume-component (:component-s resume + :rest-args ((name :parameter-type 'string)) + :add-fields `((:name "name" :label "Name" :field-type "text" :required "required") + (:label "Add RESUME" :field-type "button" :onclick "on_resume_add_submit_clicked()")) + :modify-fields `((:name "id" :field-type "hidden" :value ,(id resume) :required "required") + (:name "name" :label "Name" :field-type "text" :value ,(name resume) :required "required") + (:label "Modify RESUME" :field-type "button" :onclick "on_resume_modify_submit_clicked()")) + :order-by "name asc")) -(define-resume-component (contactinfo - ((address :parameter-type 'string) (city :parameter-type 'string) (state_id :parameter-type 'integer) (phone :parameter-type 'string) (email :parameter-type 'string) (url :parameter-type 'string) (visastatus_id :parameter-type 'integer)) - `((:name "address" :label "Address" :field-type "text" :required "required") - (:name "city" :label "City" :field-type "text" :required "required") - (:name "state_id" :label "State" :field-type "select" :options ,(state-options (get-records resume-pkg (make-instance 'states) "abbr asc")) :required "required") - (:name "phone" :label "Phone" :field-type "text" :required "required") - (:name "email" :label "Email" :field-type "text" :required "required") - (:name "url" :label "URL" :field-type "text") - (:name "visastatus_id" :label "VISA Status" :field-type "select" :options ,(visastatus-options (get-records resume-pkg (make-instance 'visastatus) "visastatus asc")) :required "required") - (:label "Add CONTACTINFO" :field-type "button" :onclick "on_contactinfo_add_submit_clicked()")) - `((:name "id" :field-type "hidden" :value ,(id contactinfo) :required "required") - (:name "address" :label "Address" :field-type "text" :value ,(address contactinfo) :required "required") - (:name "city" :label "City" :field-type "text" :value ,(city contactinfo) :required "required") - (:name "state_id" :label "State" :field-type "select" :value ,(state_id contactinfo) :options ,(state-options (get-records resume-pkg (make-instance 'states) "abbr asc")) :required "required") - (:name "phone" :label "Phone" :field-type "text" :value ,(phone contactinfo) :required "required") - (:name "email" :label "Email" :field-type "text" :value ,(email contactinfo) :required "required") - (:name "url" :label "URL" :field-type "text" :value ,(url contactinfo)) - (:name "visastatus_id" :label "VISA Status" :field-type "select" :value (visastatus_id contactinfo) :options ,(visastatus-options (get-records resume-pkg (make-instance 'visastatus) "visastatus asc")) :required "required") - (:label "Modify CONTACTINFO" :field-type "button" :onclick "on_contactinfo_modify_submit_clicked()")) - "state_abbr asc, city asc, address asc" - :view-p t)) +(define-resume-component (:component-s job + :rest-args ((company :parameter-type 'string) (location :parameter-type 'string) (start_date :parameter-type 'string) (end_date :parameter-type 'string) (overview :parameter-type 'string)) + :link-rest-args ((skill :parameter-type 'string)) + :add-fields `((:name "company" :label "Company" :field-type "text" :required "required") + (:name "location" :label "Location" :field-type "text" :required "required") + (:name "start_date" :label "Start Date" :field-type "text" :required "required") + (:name "end_date" :label "End Date" :field-type "text" :required "required") + (:name "overview" :label "Overview" :field-type "textarea" :required "required") + (:label "Add Job" :field-type "button" :onclick "on_job_add_submit_clicked()")) + :modify-fields `((:name "id" :field-type "hidden" :value ,(id job) :required "required") + (:name "company" :label "Company" :field-type "text" :value ,(company job) :required "required") + (:name "location" :label "Location" :field-type "text" :value ,(location job) :required "required") + (:name "start_date" :label "Start Date" :field-type "text" :value ,(start_date job) :required "required") + (:name "end_date" :label "End Date" :field-type "text" :value ,(end_date job) :required "required") + (:name "overview" :label "Overview" :field-type "textarea" :value ,(overview job) :required "required") + (:label "Modify JOB" :field-type "button" :onclick "on_job_modify_submit_clicked()")) + :link-fields `((:name "id" :field-type "hidden" :value ,(id job) :required "required") + ,@(skill-checkboxes resume-pkg (id user) (id job)) + (:label "Link Skills to Job" :field-type "button" :onclick "on_job_link_submit_clicked()")) + :order-by "end_date desc, start_date desc, company asc")) -(define-resume-component (education - ((school :parameter-type 'string) (major :parameter-type 'string) (minor :parameter-type 'string) (degree :parameter-type 'string) (progress :parameter-type 'string) (start_date :parameter-type 'string) (end_date :parameter-type 'string)) - `((:name "school" :label "School" :field-type "text" :required "required") - (:name "major" :label "Major" :field-type "text" :required "required") - (:name "minor" :label "Minor" :field-type "text") - (:name "degree" :label "Degree" :field-type "text" :required "required") - (:name "progress" :label "Progress" :field-type "text" :required "required") - (:name "start_date" :label "Start Date" :field-type "text" :required "required") - (:name "end_date" :label "End Date" :field-type "text" :required "required") - (:label "Add EDUCATION" :field-type "button" :onclick "on_education_add_submit_clicked()")) - `((:name "id" :field-type "hidden" :value ,(id education) :required "required") - (:name "school" :label "School" :field-type "text" :value ,(school education) :required "required") - (:name "major" :label "Major" :field-type "text" :value ,(major education) :required "required") - (:name "minor" :label "Minor" :field-type "text" :value ,(minor education)) - (:name "degree" :label "Degree" :field-type "text" :value ,(degree education) :required "required") - (:name "progress" :label "Progress" :field-type "text" :value ,(progress education) :required "required") - (:name "start_date" :label "Start Date" :field-type "text" :value ,(start_date education) :required "required") - (:name "end_date" :label "End Date" :field-type "text" :value ,(end_date education) :required "required") - (:label "Modify EDUCATION" :field-type "button" :onclick "on_education_modify_submit_clicked()")) - "end_date desc, start_date desc, school asc, degree asc, major asc, minor asc")) +(define-resume-component (:component-s contactinfo + :rest-args ((address :parameter-type 'string) (city :parameter-type 'string) (state_id :parameter-type 'integer) (phone :parameter-type 'string) (email :parameter-type 'string) (url :parameter-type 'string) (visastatus_id :parameter-type 'integer)) + :add-fields `((:name "address" :label "Address" :field-type "text" :required "required") + (:name "city" :label "City" :field-type "text" :required "required") + (:name "state_id" :label "State" :field-type "select" :options ,(state-options (get-records resume-pkg (make-instance 'states) "abbr asc")) :required "required") + (:name "phone" :label "Phone" :field-type "text" :required "required") + (:name "email" :label "Email" :field-type "text" :required "required") + (:name "url" :label "URL" :field-type "text") + (:name "visastatus_id" :label "VISA Status" :field-type "select" :options ,(visastatus-options (get-records resume-pkg (make-instance 'visastatus) "visastatus asc")) :required "required") + (:label "Add CONTACTINFO" :field-type "button" :onclick "on_contactinfo_add_submit_clicked()")) + :modify-fields `((:name "id" :field-type "hidden" :value ,(id contactinfo) :required "required") + (:name "address" :label "Address" :field-type "text" :value ,(address contactinfo) :required "required") + (:name "city" :label "City" :field-type "text" :value ,(city contactinfo) :required "required") + (:name "state_id" :label "State" :field-type "select" :value ,(state_id contactinfo) :options ,(state-options (get-records resume-pkg (make-instance 'states) "abbr asc")) :required "required") + (:name "phone" :label "Phone" :field-type "text" :value ,(phone contactinfo) :required "required") + (:name "email" :label "Email" :field-type "text" :value ,(email contactinfo) :required "required") + (:name "url" :label "URL" :field-type "text" :value ,(url contactinfo)) + (:name "visastatus_id" :label "VISA Status" :field-type "select" :value (visastatus_id contactinfo) :options ,(visastatus-options (get-records resume-pkg (make-instance 'visastatus) "visastatus asc")) :required "required") + (:label "Modify CONTACTINFO" :field-type "button" :onclick "on_contactinfo_modify_submit_clicked()")) + :order-by "state_abbr asc, city asc, address asc" + :view-p t)) -(define-resume-component (language - ((name :parameter-type 'string) (understanding_listening :parameter-type 'string) (understanding_reading :parameter-type 'string) (speaking_interaction :parameter-type 'string) (speaking_production :parameter-type 'string) (writing :parameter-type 'string)) - `((:name "name" :label "Name" :field-type "text" :required "required") - (:name "understanding_listening" :label "Understanding Listening" :field-type "select" :options ,(language-options) :required "required") - (:name "understanding_reading" :label "Understanding Reading" :field-type "select" :options ,(language-options) :required "required") - (:name "speaking_interaction" :label "Speaking Interaction" :field-type "select" :options ,(language-options) :required "required") - (:name "speaking_production" :label "Speaking Production" :field-type "select" :options ,(language-options) :required "required") - (:name "writing" :label "Writing" :field-type "select" :options ,(language-options) :required "required") - (:label "Add LANGUAGE" :field-type "button" :onclick "on_language_add_submit_clicked()")) - `((:name "id" :field-type "hidden" :value ,(id language) :required "required") - (:name "name" :label "Name" :field-type "text" :value ,(name language) :required "required") - (:name "understanding_listening" :label "Understanding Listening" :field-type "select" :options ,(language-options) :value ,(understanding_listening language) :required "required") - (:name "understanding_reading" :label "Understanding Reading" :field-type "select" :options ,(language-options) :value ,(understanding_reading language) :required "required") - (:name "speaking_interaction" :label "Speaking Interaction" :field-type "select" :options ,(language-options) :value ,(speaking_interaction language) :required "required") - (:name "speaking_production" :label "Speaking Production" :field-type "select" :options ,(language-options) :value ,(speaking_production language) :required "required") - (:name "writing" :label "Writing" :field-type "select" :options ,(language-options) :value ,(writing language) :required "required") - (:label "Modify LANGUAGE" :field-type "button" :onclick "on_language_modify_submit_clicked()")) - "name asc")) +(define-resume-component (:component-s education + :rest-args ((school :parameter-type 'string) (major :parameter-type 'string) (minor :parameter-type 'string) (degree :parameter-type 'string) (progress :parameter-type 'string) (start_date :parameter-type 'string) (end_date :parameter-type 'string)) + :add-fields `((:name "school" :label "School" :field-type "text" :required "required") + (:name "major" :label "Major" :field-type "text" :required "required") + (:name "minor" :label "Minor" :field-type "text") + (:name "degree" :label "Degree" :field-type "text" :required "required") + (:name "progress" :label "Progress" :field-type "text" :required "required") + (:name "start_date" :label "Start Date" :field-type "text" :required "required") + (:name "end_date" :label "End Date" :field-type "text" :required "required") + (:label "Add EDUCATION" :field-type "button" :onclick "on_education_add_submit_clicked()")) + :modify-fields `((:name "id" :field-type "hidden" :value ,(id education) :required "required") + (:name "school" :label "School" :field-type "text" :value ,(school education) :required "required") + (:name "major" :label "Major" :field-type "text" :value ,(major education) :required "required") + (:name "minor" :label "Minor" :field-type "text" :value ,(minor education)) + (:name "degree" :label "Degree" :field-type "text" :value ,(degree education) :required "required") + (:name "progress" :label "Progress" :field-type "text" :value ,(progress education) :required "required") + (:name "start_date" :label "Start Date" :field-type "text" :value ,(start_date education) :required "required") + (:name "end_date" :label "End Date" :field-type "text" :value ,(end_date education) :required "required") + (:label "Modify EDUCATION" :field-type "button" :onclick "on_education_modify_submit_clicked()")) + :order-by "end_date desc, start_date desc, school asc, degree asc, major asc, minor asc")) -(define-resume-component (skill - ((skill :parameter-type 'string)) - `((:name "skill" :label "Skill" :field-type "text" :required "required") - (:label "Add Skill" :field-type "button" :onclick "on_skill_add_submit_clicked()")) - `((:name "id" :field-type "hidden" :value ,(id skill) :required "required") - (:name "skill" :label "Skill" :field-type "text" :value ,(skill skill) :required "required") - (:label "Modify SKILL" :field-type "button" :onclick "on_skill_modify_submit_clicked()")) - "skill asc")) +(define-resume-component (:component-s language + :rest-args ((name :parameter-type 'string) (understanding_listening :parameter-type 'string) (understanding_reading :parameter-type 'string) (speaking_interaction :parameter-type 'string) (speaking_production :parameter-type 'string) (writing :parameter-type 'string)) + :add-fields `((:name "name" :label "Name" :field-type "text" :required "required") + (:name "understanding_listening" :label "Understanding Listening" :field-type "select" :options ,(language-options) :required "required") + (:name "understanding_reading" :label "Understanding Reading" :field-type "select" :options ,(language-options) :required "required") + (:name "speaking_interaction" :label "Speaking Interaction" :field-type "select" :options ,(language-options) :required "required") + (:name "speaking_production" :label "Speaking Production" :field-type "select" :options ,(language-options) :required "required") + (:name "writing" :label "Writing" :field-type "select" :options ,(language-options) :required "required") + (:label "Add LANGUAGE" :field-type "button" :onclick "on_language_add_submit_clicked()")) + :modify-fields `((:name "id" :field-type "hidden" :value ,(id language) :required "required") + (:name "name" :label "Name" :field-type "text" :value ,(name language) :required "required") + (:name "understanding_listening" :label "Understanding Listening" :field-type "select" :options ,(language-options) :value ,(understanding_listening language) :required "required") + (:name "understanding_reading" :label "Understanding Reading" :field-type "select" :options ,(language-options) :value ,(understanding_reading language) :required "required") + (:name "speaking_interaction" :label "Speaking Interaction" :field-type "select" :options ,(language-options) :value ,(speaking_interaction language) :required "required") + (:name "speaking_production" :label "Speaking Production" :field-type "select" :options ,(language-options) :value ,(speaking_production language) :required "required") + (:name "writing" :label "Writing" :field-type "select" :options ,(language-options) :value ,(writing language) :required "required") + (:label "Modify LANGUAGE" :field-type "button" :onclick "on_language_modify_submit_clicked()")) + :order-by "name asc")) -(define-resume-component (job - ((company :parameter-type 'string) (location :parameter-type 'string) (start_date :parameter-type 'string) (end_date :parameter-type 'string) (overview :parameter-type 'string)) - `((:name "company" :label "Company" :field-type "text" :required "required") - (:name "location" :label "Location" :field-type "text" :required "required") - (:name "start_date" :label "Start Date" :field-type "text" :required "required") - (:name "end_date" :label "End Date" :field-type "text" :required "required") - (:name "overview" :label "Overview" :field-type "textarea" :required "required") - (:label "Add Job" :field-type "button" :onclick "on_job_add_submit_clicked()")) - `((:name "id" :field-type "hidden" :value ,(id job) :required "required") - (:name "company" :label "Company" :field-type "text" :value ,(company job) :required "required") - (:name "location" :label "Location" :field-type "text" :value ,(location job) :required "required") - (:name "start_date" :label "Start Date" :field-type "text" :value ,(start_date job) :required "required") - (:name "end_date" :label "End Date" :field-type "text" :value ,(end_date job) :required "required") - (:name "overview" :label "Overview" :field-type "textarea" :value ,(overview job) :required "required") - (:label "Modify JOB" :field-type "button" :onclick "on_job_modify_submit_clicked()")) - "end_date desc, start_date desc, company asc")) +(define-resume-component (:component-s skill + :rest-args ((skill :parameter-type 'string)) + :add-fields `((:name "skill" :label "Skill" :field-type "text" :required "required") + (:label "Add Skill" :field-type "button" :onclick "on_skill_add_submit_clicked()")) + :modify-fields `((:name "id" :field-type "hidden" :value ,(id skill) :required "required") + (:name "skill" :label "Skill" :field-type "text" :value ,(skill skill) :required "required") + (:label "Modify SKILL" :field-type "button" :onclick "on_skill_modify_submit_clicked()")) + :order-by "skill asc")) diff --git a/lisp/sql/job-skill.lisp b/lisp/sql/job-skill.lisp new file mode 100644 index 0000000..98799bf --- /dev/null +++ b/lisp/sql/job-skill.lisp @@ -0,0 +1,18 @@ +;;; -*- Mode: Lisp; Syntax: ANSI-Common-Lisp; Base: 10 -*- +(declaim (optimize (speed 0) (safety 3) (debug 3))) + +(in-package :resume) + +(defclass job-skill (postgres-record) + ((id :initarg :id + :initform nil + :accessor id) + (job_id :initarg :job_id + :initform nil + :accessor job_id) + (skill_id :initarg :skill_id + :initform nil + :accessor skill_id) + (*table :initform "resume.job_skill") + (*where-expression :initform "id = ~a")) + (:documentation "Holds the data for a resume.job_skill record.")) diff --git a/lisp/webapps/resume/clojurescript/resume/src/resume/core.clj b/lisp/webapps/resume/clojurescript/resume/src/resume/core.clj index 829fa66..146fa6c 100644 --- a/lisp/webapps/resume/clojurescript/resume/src/resume/core.clj +++ b/lisp/webapps/resume/clojurescript/resume/src/resume/core.clj @@ -1,12 +1,13 @@ (ns resume.core (:require [clojure.string :as str])) -(defmacro define-resume-component [component] +(defmacro define-resume-component [component & [links]] `(do (declare ~(symbol (str "reset-" component "-state"))) (declare ~(symbol (str "reset-" component "-view-state"))) (declare ~(symbol (str "reset-" component "-add-state"))) (declare ~(symbol (str "reset-" component "-modify-state"))) + (declare ~(symbol (str "reset-" component "-link-state"))) (declare ~(symbol (str "comp-" component))) (declare ~(symbol (str "handler-" component))) (declare ~(symbol (str "render-" component))) @@ -27,6 +28,27 @@ (declare ~(symbol (str "on-" component "-modify-submit-clicked"))) (declare ~(symbol (str "handler-" component "-modify-submit"))) (declare ~(symbol (str "render-" component "-modify-submit"))) + (declare ~(symbol (str "on-" component "-modify-clicked"))) + (declare ~(symbol (str "comp-" component "-modify"))) + (declare ~(symbol (str "handler-" component "-modify"))) + (declare ~(symbol (str "render-" component "-modify"))) + (declare ~(symbol (str "on-" component "-modify-submit-clicked"))) + (declare ~(symbol (str "handler-" component "-modify-submit"))) + (declare ~(symbol (str "render-" component "-modify-submit"))) + (declare ~(symbol (str "on-" component "-link-clicked"))) + (declare ~(symbol (str "comp-" component "-link"))) + (declare ~(symbol (str "handler-" component "-link"))) + (declare ~(symbol (str "render-" component "-link"))) + (declare ~(symbol (str "on-" component "-link-submit-clicked"))) + (declare ~(symbol (str "handler-" component "-link-submit"))) + (declare ~(symbol (str "render-" component "-link-submit"))) + (declare ~(symbol (str "on-" component "-link-clicked"))) + (declare ~(symbol (str "comp-" component "-link"))) + (declare ~(symbol (str "handler-" component "-link"))) + (declare ~(symbol (str "render-" component "-link"))) + (declare ~(symbol (str "on-" component "-link-submit-clicked"))) + (declare ~(symbol (str "handler-" component "-link-submit"))) + (declare ~(symbol (str "render-" component "-link-submit"))) (declare ~(symbol (str "on-" component "-delete-clicked"))) (declare ~(symbol (str "handler-" component "-delete"))) (declare ~(symbol (str "render-" component "-delete"))) @@ -35,6 +57,7 @@ (def ~(symbol (str component "-view-state")) (r/atom {})) (def ~(symbol (str component "-add-state")) (r/atom {})) (def ~(symbol (str component "-modify-state")) (r/atom {})) + (def ~(symbol (str component "-link-state")) (r/atom {})) (defn ~(symbol (str "reset-" component "-state")) [jsonobj#] (reset! ~(symbol (str component "-state")) jsonobj#)) @@ -48,6 +71,9 @@ (defn ~(symbol (str "reset-" component "-modify-state")) [jsonobj#] (reset! ~(symbol (str component "-modify-state")) jsonobj#)) + (defn ~(symbol (str "reset-" component "-link-state")) [jsonobj#] + (reset! ~(symbol (str component "-link-state")) jsonobj#)) + (defn ~(symbol (str "comp-" component)) [] [:div {:style {:display (cond (or (= @location-state ~(str "/resume/" component))) "block" :else "none")}} [:h3 {:style {:text-align "center"}} (get (deref ~(symbol (str component "-state"))) "title")] @@ -59,7 +85,7 @@ [:div {:class "modal-dialog modal-lg"} [:div {:class "modal-content"} [:div {:class "modal-header"} - [:h5 (get (deref ~(symbol (str component "-state"))) "title")] + [:h5 (get (deref ~(symbol (str component "-add-state"))) "title")] [:button {:type "button" :class "close" :data-dismiss "modal"} @@ -80,7 +106,7 @@ [:div {:class "modal-dialog modal-lg"} [:div {:class "modal-content"} [:div {:class "modal-header"} - [:h5 (get (deref ~(symbol (str component "-state"))) "title")] + [:h5 (get (deref ~(symbol (str component "-modify-state"))) "title")] [:button {:type "button" :class "close" :data-dismiss "modal"} @@ -88,6 +114,27 @@ [:div {:class "modal-body" :style {:height "460px;"}} [~(symbol (str "comp-" component "-modify"))]] + [:div {:class "modal-footer"} + [:button {:type "submit" + :class "btn btn-danger btn-default" + :data-dismiss "modal"} + [:span {:class "glyphicon glyphicon-remove"}] + "Cancel"]]]]] + [:div {:id (str "modal-" ~component "-link") + :class "modal fade" + :role "dialog" + :tab-index "-1"} + [:div {:class "modal-dialog modal-lg"} + [:div {:class "modal-content"} + [:div {:class "modal-header"} + [:h5 (get (deref ~(symbol (str component "-link-state"))) "title")] + [:button {:type "button" + :class "close" + :data-dismiss "modal"} + "X"]] + [:div {:class "modal-body" + :style {:height "460px;"}} + [~(symbol (str "comp-" component "-link"))]] [:div {:class "modal-footer"} [:button {:type "submit" :class "btn btn-danger btn-default" @@ -130,7 +177,7 @@ (for [rec# results#] (let [tr-attributes# (atom {:id (str "tr-" ~component "-" (get rec# "id")) :key (str "tr-" ~component "-" (get rec# "id"))}) - td-attributes# (atom {:on-click #(print "yourmom")})] + td-attributes# (atom {:on-click #(~(symbol (str "on-" component "-link-clicked")) (get rec# "id"))})] [:tr @tr-attributes# (for [key# (filter #(not (str/includes? % "_id")) keys#)] [:td @td-attributes# @@ -218,6 +265,44 @@ :params (form-fields-to-map (str "#" ~component "-modify-form :input")) :handler ~(symbol (str "handler-" component "-modify-submit"))})) + (defn ~(symbol (str "on-" component "-link-clicked")) [id#] + (~(symbol (str "render-" component "-link")) id#)) + + (defn ~(symbol (str "comp-" component "-link")) [] + [:div {:dangerouslySetInnerHTML (r/unsafe-html (ck-form/template-generic-form (get (deref ~(symbol (str component "-link-state"))) "form") (namespace ::x)))}]) + + (defn ~(symbol (str "handler-" component "-link")) [response#] + (let [jsonobj# (cljs.core/js->clj (js/JSON.parse response#))] + (~(symbol (str "reset-" component "-link-state")) jsonobj#) + (.modal (jquery (str "#modal-" ~component "-link"))))) + + (defn ~(symbol (str "render-" component "-link")) [id#] + (ajax.core/POST ~(str "/resume/" component "/link") + {:format :raw + :params {:id id#} + :handler ~(symbol (str "handler-" component "-link"))})) + + (defn ~(symbol (str "on-" component "-link-submit-clicked")) [] + (when (-> (jquery ~(str "#" component "-link-form")) + (.get "0") + (.checkValidity)) + (.modal (jquery (str "#modal-" ~component "-link")) "hide") + (~(symbol (str "render-" component "-link-submit"))))) + + (defn ~(symbol (str "handler-" component "-link-submit")) [response#] + (let [jsonobj# (cljs.core/js->clj (js/JSON.parse response#))] + (auth-notifications jsonobj#) + (~(symbol (str "render-" component "-view"))))) + + (defn ~(symbol (str "render-" component "-link-submit")) [] + (ajax.core/POST (str "/resume/" ~component "/link/submit") + {:format :raw + :params (into (form-fields-to-map (str "#" ~component "-link-form :input")) + (for [link# ~links] + {link# + (reduce-checkboxes (str "[id^='" ~component "_link_form-chk_" ~component "_" link# "_link_']"))})) + :handler ~(symbol (str "handler-" component "-link-submit"))})) + (defn ~(symbol (str "on-" component "-delete-clicked")) [id#] (when (js/confirm (str "Are you sure you want to delete " id# "? This action cannot be undone.")) (~(symbol (str "render-" component "-delete")) id#))) diff --git a/lisp/webapps/resume/clojurescript/resume/src/resume/core.cljs b/lisp/webapps/resume/clojurescript/resume/src/resume/core.cljs index 35ea5aa..5283292 100644 --- a/lisp/webapps/resume/clojurescript/resume/src/resume/core.cljs +++ b/lisp/webapps/resume/clojurescript/resume/src/resume/core.cljs @@ -265,16 +265,17 @@ `chk_something-more'. The important thing is the underscore separating the throwaway prefix and the remaining useful bit. `selector' will likely be something like: [id^='chk_']" - (reduce (fn [x y] - (cond (and (not (empty? x)) (not (empty? y))) (str x "|" y) - (and (not (empty? x)) (empty? y)) x - (and (empty? x) (not (empty? y))) y - :else "")) - (map (fn [elem] - (let [this (jquery (str "#" (dommy/attr elem :id)))] - (when (-> this (.prop "checked")) - (last (str/split (-> this (.prop "id")) "_"))))) - (.toArray (jquery selector))))) + (or (reduce (fn [x y] + (cond (and (not (empty? x)) (not (empty? y))) (str x "|" y) + (and (not (empty? x)) (empty? y)) x + (and (empty? x) (not (empty? y))) y + :else "")) + (map (fn [elem] + (let [this (jquery (str "#" (dommy/attr elem :id)))] + (when (-> this (.prop "checked")) + (last (str/split (-> this (.prop "id")) "_"))))) + (.toArray (jquery selector)))) + "")) (defn form-fields-to-map [selector] (let [form-name (str/replace (str/replace-first (first (str/split selector " ")) "#" "") "-" "_")] @@ -1064,12 +1065,12 @@ ;; resume -(define-resume-component "resume") +(define-resume-component "resume" ["contactinfo" "language" "education" "job"]) +(define-resume-component "job" ["skill"]) +(define-resume-component "skill") (define-resume-component "contactinfo") (define-resume-component "education") (define-resume-component "language") -(define-resume-component "skill") -(define-resume-component "job") ;; location @@ -1083,11 +1084,11 @@ (push-menu-hook {:handler "/users" :func #(render-users)}) (push-menu-hook {:handler "/users/register" :func #(render-users)}) (push-menu-hook {:handler "/resume/resume" :func #(render-resume)}) +(push-menu-hook {:handler "/resume/job" :func #(render-job)}) +(push-menu-hook {:handler "/resume/skill" :func #(render-skill)}) (push-menu-hook {:handler "/resume/contactinfo" :func #(render-contactinfo)}) (push-menu-hook {:handler "/resume/education" :func #(render-education)}) (push-menu-hook {:handler "/resume/language" :func #(render-language)}) -(push-menu-hook {:handler "/resume/skill" :func #(render-skill)}) -(push-menu-hook {:handler "/resume/job" :func #(render-job)}) (defn on-menu-clicked [handler] (reset-location handler) -- cgit v1.3