aboutsummaryrefslogtreecommitdiffstats
path: root/data.lisp
blob: 03b9dcbc4133cba39be384ae583a670d94455d3d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
;; scrumli --- A simple scrum web application
;; Copyright (C) 2013  Tom Willemse

;; scrumli is free software: you can redistribute it and/or modify
;; it under the terms of the GNU Affero General Public License as published by
;; the Free Software Foundation, either version 3 of the License, or
;; (at your option) any later version.

;; scrumli is distributed in the hope that it will be useful,
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
;; GNU Affero General Public License for more details.

;; You should have received a copy of the GNU Affero General Public License
;; along with scrumli.  If not, see <http://www.gnu.org/licenses/>.

(in-package :scrumli)

(defclass story ()
  ((id :col-type serial :reader story-id)
   (state :col-type string :reader state :initform "TODO")
   (role :col-type string :reader role :initarg :role)
   (necessity :col-type string :reader necessity :initarg :necessity)
   (title :col-type string :reader title :initarg :title)
   (priority :col-type integer :reader priority :initarg :priority)
   (content :col-type string :reader content :initarg :content)
   (reporter :col-type string :reader reporter :initarg :reporter)
   (assignee :col-type string :reader assignee :initarg :assignee))
  (:metaclass dao-class)
  (:keys id))

(defclass task ()
  ((id :col-type serial :reader story-id)
   (state :col-type string :reader state :initform "TODO")
   (description :col-type string :reader description :initarg :description)
   (priority :col-type integer :reader priority :initarg :priority)
   (reporter :col-type string :reader reporter :initarg :reporter)
   (assignee :col-type string :reader assignee :initarg :assignee)
   (story-id :col-type integer :reader story-id :initarg :story-id))
  (:metaclass dao-class)
  (:keys id))

(deftable task
  (!dao-def)
  (!foreign 'story 'story-id 'id))

(defun datainit ()
  (unless (table-exists-p 'story)
    (execute (dao-table-definition 'story)))
  (unless (table-exists-p 'task) (create-table 'task)))

(defun get-all-stories ()
  (query (:order-by (:select :* (:as (:md5 'assignee) 'md5)
                             :from 'story) 'priority) :alists))

(defun get-stories-for (username)
  (query (:order-by (:select :* (:as (:md5 'assignee) 'md5)
                             :from 'story
                             :where (:= 'assignee username))
                    'priority) :alists))

(defun get-story (id)
  (append (query (:select :* (:as (:md5 'assignee) 'md5) :from 'story
                          :where (:= 'id id)) :alist)
          `((tasks . ,(get-tasks-for-story id)))))

(defun get-tasks-for-story (id)
  (query (:order-by (:select :* (:as (:md5 'assignee) 'md5) :from 'task
                             :where (:= 'story-id id))
                    'priority)
         :alists))

(defun post-story (role necessity title content reporter)
  (let ((obj (make-instance
              'story :role role :necessity necessity :title title
              :priority (+ 1 (or (query (:select
                                         (:coalesce (:max 'priority) 0)
                                         :from 'story) :single)
                                 0))
              :content content :assignee "" :reporter reporter)))
    (save-dao obj)))

(defun post-task (story-id description reporter)
  (let ((obj (make-instance
              'task :description description
              :priority (+ 1 (query (:select
                                     (:coalesce (:max 'priority) 0)
                                     :from 'task
                                     :where (:= 'story-id story-id))
                                    :single))
              :reporter reporter :story-id (parse-integer story-id)
              :assignee "")))
    (save-dao obj)))

(defun story-get-state (type id)
  (query (:select 'state :from type :where (:= 'id id)) :single))

(defun story-set-state (type id state)
  (execute (:update type :set 'state state :where (:= 'id id))))

(defun story-change-priority (type id dir)
  (let* ((current-priority (query (:select 'priority :from type
                                           :where (:= 'id id))
                                  :single))
         (next-priority (funcall (ecase dir (:up #'-) (:down #'+))
                                 current-priority 1))
         (max-priority
          (case type
            ('story (query (:select (:max 'priority) :from type)
                           :single))
            ('task
             (query (:select
                     (:max 'priority) :from type
                     :where (:= 'story-id
                                (:select 'story-id
                                         :from 'task
                                         :where (:= 'id id))))
                    :single)))))
    (execute (:update type :set 'priority current-priority
                      :where (:= 'priority next-priority)))
    (execute (:update type :set
                      'priority (max 1 (min next-priority max-priority))
                      :where (:= 'id id)))))

(defun set-assignee (type id assignee)
  (execute (:update type :set 'assignee assignee
                    :where (:= 'id id))))