git ssb

0+

cel / ssb-issues



Tree: 3c92db173ab8661c8ac76098857639346343f9c4

Files: 3c92db173ab8661c8ac76098857639346343f9c4 / index.js

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

Built with git-ssb-web