summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorckonstanski <kostcarl@isu.edu>2026-08-23 23:10:30 -0600
committerckonstanski <kostcarl@isu.edu>2026-08-23 23:10:30 -0600
commit3f456a6d1e08fc0930e9d73e8988934f41d79603 (patch)
tree41ffb87e4915599c4f4fec438a59d8e79aaf9fba
parent50c7e42495e802800e2d06731a17f848641da4ca (diff)
stuff
-rw-r--r--lisp/resume.asd1
-rw-r--r--lisp/service/resume-service.lisp280
-rw-r--r--lisp/sql/job-skill.lisp18
-rw-r--r--lisp/webapps/resume/clojurescript/resume/src/resume/core.clj93
-rw-r--r--lisp/webapps/resume/clojurescript/resume/src/resume/core.cljs31
5 files changed, 302 insertions, 121 deletions
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"}
@@ -93,6 +119,27 @@
: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"
+ :data-dismiss "modal"}
+ [:span {:class "glyphicon glyphicon-remove"}]
"Cancel"]]]]]])
(defn ~(symbol (str "handler-" component)) [response#]
@@ -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)