git ssb

0+

Kira / %V53yIAO6ZNGv1Lx9tCP…



forked from cel / ssb-issues

Tree: 8127f3c7642cecdccfe264896c26a8cade5df1b6

Files: 8127f3c7642cecdccfe264896c26a8cade5df1b6 / index.js

6136 bytesRaw
1var pull = require('pull-stream')
2var paramap = require('pull-paramap')
3var asyncMemo = require('asyncmemo')
4var issueSchemas = require('./lib/schemas')
5
6function Cache(fn, ssb) {
7 return asyncMemo(fn)
8 return function (key, cb) { ac.get(key, cb) }
9}
10
11function isUpdateValid(issue, msg) {
12 return msg.value.author == issue.author
13 || msg.value.author == issue.projectAuthor
14}
15
16exports.name = 'issues'
17
18exports.manifest = {
19 get: 'async',
20 list: 'source',
21 new: 'async',
22 edit: 'async',
23 close: 'async',
24 reopen: 'async',
25 getMention: 'sync',
26 isStatusChanged: 'sync'
27}
28
29exports.schemas = issueSchemas
30
31function isStatusChanged(msg, issue) {
32 var mention = getMention(msg, issue)
33 return mention ? mention.open : null
34}
35
36function getMention(msg, issue) {
37 var c = msg.value.content
38 if (msg.key == issue.id || c.issue == issue.id || c.link == issue.id)
39 if (c.open != null)
40 return c
41 if (c.issues) {
42 var mention
43 for (var i = 0; i < c.issues.length; i++) {
44 mention = getMention({value: {
45 timestamp: msg.value.timestamp,
46 author: msg.value.author,
47 content: c.issues[i]
48 }}, issue)
49 if (mention)
50 return mention
51 }
52 }
53}
54
55exports.init = function (ssb) {
56
57 var ssbGet = asyncMemo(ssb.get)
58
59 var getIssue = asyncMemo(function (id, cb) {
60 var issue = {}
61 var issueMsg
62
63 ssbGet(id, function (err, msg) {
64 msg = {key: id, value: msg}
65 if (err) return cb(err)
66 issueMsg = msg
67 issue.id = msg.key
68 issue.msg = msg
69 issue.author = msg.value.author
70 var c = msg.value.content
71 issue.project = c.project
72 issue.text = c.text
73 issue.created_at = issue.updated_at = msg.value.timestamp
74 if (c.project)
75 ssbGet(c.project, gotProjectMsg)
76 else
77 getLinks()
78 })
79
80 function gotProjectMsg(err, msg) {
81 if (err) return cb(err)
82 issue.projectAuthor = msg.author
83 getLinks()
84 }
85
86 function getLinks() {
87 var now = Date.now()
88 // compute the result from the past data
89 pull(
90 ssb.links({dest: id, reverse: true, values: true,
91 old: true, live: false, sync: false}),
92 pull.drain(onOldMsg, onOldEnd)
93 )
94 // keep the results up-to-date in the future
95 pull(
96 ssb.links({dest: id, values: true,
97 old: false, live: true, sync: false}),
98 pull.drain(onNewMsg, onNewEnd)
99 )
100 }
101
102 function onOldMsg(msg) {
103 if (!msg.value || !isUpdateValid(issue, msg))
104 return
105 var c = msg.value.content
106
107 // handle updates to issue
108 if (msg.key == id || c.issue == id || c.link == id) {
109 if (c.open != null && issue.open == null)
110 issue.open = c.open
111 if (c.title != null && issue.title == null)
112 issue.title = c.title
113 if (msg.value.timestamp > issue.updated_at)
114 issue.updated_at = msg.value.timestamp
115 }
116
117 // handle updates via mention
118 if (c.issues) {
119 for (var i = 0; i < c.issues.length; i++)
120 onOldMsg({value: {
121 timestamp: msg.value.timestamp,
122 author: msg.value.author,
123 content: c.issues[i]
124 }})
125 }
126
127 checkReady()
128 }
129
130 function onNewMsg(msg) {
131 if (!msg.value || !isUpdateValid(issue, msg))
132 return
133 var c = msg.value.content
134
135 // handle updates to issue
136 if (msg.key == id || c.issue == id || c.link == id) {
137 if (c.open != null)
138 issue.open = c.open
139 if (c.title != null)
140 issue.title = c.title
141 if (msg.value.timestamp > issue.updated_at)
142 issue.updated_at = msg.value.timestamp
143 }
144
145 // handle updates via mention
146 if (c.issues) {
147 for (var i = 0; i < c.issues.length; i++)
148 onNewMsg({value: {
149 timestamp: msg.value.timestamp,
150 author: msg.value.author,
151 content: c.issues[i]
152 }})
153 }
154 }
155
156 function checkReady() {
157 // call back once all the issue properties are set
158 if (issue.open != null && issue.title != null) {
159 var _cb = cb
160 delete cb
161 _cb(null, issue)
162 }
163 }
164
165 function onOldEnd(err) {
166 if (err) {
167 if (cb) cb(err)
168 else console.error(err)
169 return
170 }
171 // process the root message last
172 onOldMsg(issueMsg)
173 // if callback hasn't been called yet, the issue is missing a field
174 if (cb) {
175 if (issue.open == null)
176 issue.open = true
177 if (issue.title == null)
178 issue.title = issue.id
179 checkReady()
180 }
181 }
182
183 function onNewEnd(err) {
184 if (err) {
185 if (cb) cb(err)
186 else console.error(err)
187 }
188 }
189 })
190
191 function listIssues(opts) {
192 opts.type = 'issue'
193 return pull(
194 // TODO: use links2 for this
195 ssb.messagesByType(opts),
196 pull.filter(function (msg) {
197 return (!opts.project || opts.project == msg.value.content.project)
198 && (!opts.author || opts.author == msg.value.author)
199 }),
200 paramap(function (msg, cb) {
201 getIssue(msg.key, cb)
202 }, 8),
203 pull.filter(opts.open != null && function (pr) {
204 return pr.open == opts.open
205 })
206 )
207 }
208
209 function editIssue(id, opts, cb) {
210 var msg
211 try { ssb.publish(issueSchemas.edit(id, opts), cb) }
212 catch(e) { return cb(e) }
213 }
214
215 function closeIssue(id, cb) {
216 var msg
217 try { ssb.publish(issueSchemas.close(id), cb) }
218 catch(e) { return cb(e) }
219 }
220
221 function reopenIssue(id, cb) {
222 var msg
223 try { msg = issueSchemas.reopen(id) }
224 catch(e) { return cb(e) }
225 ssb.publish(msg, cb)
226 }
227
228 function newIssue(opts, cb) {
229 var msg
230 try { msg = issueSchemas.new(opts.project, opts.title, opts.text) }
231 catch(e) { return cb(e) }
232 ssb.publish(msg, function (err, msg) {
233 if (err) return cb(err)
234 getIssue(msg.key, cb)
235 })
236 }
237
238 return {
239 get: getIssue,
240 list: listIssues,
241 new: newIssue,
242 edit: editIssue,
243 close: closeIssue,
244 reopen: reopenIssue,
245 getMention: getMention,
246 isStatusChanged: isStatusChanged
247 }
248}
249

Built with git-ssb-web