var pull = require('pull-stream') var cat = require('pull-cat') var u = require('../util') var markdown = require('../markdown') var forms = require('../forms') module.exports = function (repoRoutes, web) { return new RepoIssueRoutes(repoRoutes, web) } function RepoIssueRoutes(repoRoutes, web) { this.repo = repoRoutes this.web = web } var I = RepoIssueRoutes.prototype function getMention(msg, id) { if (msg.key == id) return msg var mentions = msg.value.content.mentions if (mentions) for (var i = 0; i < mentions.length; i++) { var mention = mentions[i] if (mention.link == id) return mention } return null } /* Issues */ I.serveRepoIssues = function (req, repo, isPRs) { var self = this var count = 0 var state = req._u.query.state || 'open' var newPath = isPRs ? [repo.id, 'compare'] : [repo.id, 'issues', 'new'] var title = req._t('Issues') + ' · %{author}/%{repo}' var page = isPRs ? 'pulls' : 'issues' return self.repo.renderRepoPage(req, repo, page, null, title, cat([ pull.once( (self.web.isPublic ? '' : '
' + '' + '
') + '

' + req._t(isPRs ? 'PullRequests' : 'Issues') + '

' + u.nav([ ['?', req._t('issues.Open'), 'open'], ['?state=closed', req._t('issues.Closed'), 'closed'], ['?state=all', req._t('issues.All'), 'all'] ], state)), pull( (isPRs ? self.web.pullReqs : self.web.issues).list({ repo: repo.id, project: repo.id, reverse: true, open: {open: true, closed: false}[state] }), pull.map(function (issue) { count++ var state = (issue.open ? 'open' : 'closed') var stateStr = req._t(issue.open ? 'issue.state.Open' : 'issue.state.Closed') return '
' + ' ' + '' + u.escape(issue.title) + '' + new Date(issue.created_at).toLocaleString(req._locale) + '' + '' + '
' }) ), u.readOnce(function (cb) { cb(null, count > 0 ? '' : '

' + req._t(isPRs ? 'NoPullRequests' : 'NoIssues') + '

') }) ])) } /* New Issue */ I.serveRepoNewIssue = function (req, repo, issueId, path) { var title = req._t('issue.New') + ' · %{author}/%{repo}' return this.repo.renderRepoPage(req, repo, 'issues', null, title, pull.once( '

' + req._t('issue.New') + '

' + '
' + '' + forms.post(req, repo, null, 8) + '' + '
')) } /* Issue */ I.serveRepoIssue = function (req, repo, issue, path, postId) { var self = this var newestMsg = {key: issue.id, value: {timestamp: issue.created_at}} var title = u.escape(issue.title) + ' · %{author}/%{repo}' return self.repo.renderRepoPage(req, repo, 'issues', null, title, cat([ pull.once( '

' + u.link([issue.id], issue.title) + '

' + '' + issue.id + '' + '
' + (issue.open ? '' + req._t('issue.state.Open') + '' : '' + req._t('issue.state.Closed') + '')), u.readOnce(function (cb) { self.web.about.getName(issue.author, function (err, authorName) { if (err) return cb(err) var authorLink = u.link([issue.author], authorName) cb(null, req._t('issue.Opened', {name: authorLink, datetime: u.timestamp(issue.created_at, req)})) }) }), pull.once('
' + markdown(issue.text, repo) + '
'), // render posts and edits pull( self.web.ssb.links({ dest: issue.id, values: true }), pull.unique('key'), self.web.addAuthorName(), u.sortMsgs(), pull.through(function (msg) { // the newest message in the issue thread // becomes the branch of the new post if (msg.value && msg.value.timestamp > newestMsg.value.timestamp && msg.value.content.root == issue.id) newestMsg = msg }), pull.map(self.renderIssueActivityMsg.bind(self, req, repo, issue, req._t('issue.'), postId)) ), self.web.isPublic ? pull.empty() : u.readOnce(function (cb) { cb(null, forms.issueComment(req, issue, repo, newestMsg.key, req._t('issue.'))) }) ])) } I.renderIssueActivityMsg = function (req, repo, issue, type, postId, msg) { var authorLink = u.link([msg.value.author], msg.authorName) var msgHref = u.encodeLink(msg.key) + '#' + encodeURIComponent(msg.key) var msgTimeLink = '' + new Date(msg.value.timestamp).toLocaleString(req._locale) + '' var c = msg.value.content switch (c.type) { case 'vote': return '' case 'post': if (c.root == issue.id) { var changed = this.web.issues.isStatusChanged(msg, issue) return '
' + (msg.key == postId ? '
' : '') + '' + msg.key + ' ' + (changed == null ? authorLink : req._t( changed ? 'issue.Reopened' : 'issue.Closed', {name: authorLink, type: type})) + ' · ' + msgTimeLink + (msg.key == postId ? '
' : '') + markdown(c.text, repo) + '
' } else { var text = c.text || (c.type + ' ' + msg.key) return '
' + req._t('issue.MentionedIn', { name: authorLink, type: type, post: '' + String(text).substr(0, 140) + '' }) + '
' } case 'issue': case 'pull-request': return '
' + req._t('issue.MentionedIn', { name: authorLink, type: type, post: u.link([msg.key], u.messageTitle(msg)) }) + '
' case 'issue-edit': return '
' + (msg.key == postId ? '
' : '') + // handle deprecated rename (c.title == null ? '' : req._t('issue.Renamed', { author: authorLink, type: type, name: '' + u.escape(c.title) + '' })) + ' · ' + msgTimeLink + (msg.key == postId ? '
' : '') + '
' case 'git-update': var mention = this.web.issues.getMention(msg, issue) if (mention) { var commitLink = u.link([repo.id, 'commit', mention.object], mention.label || mention.object) return '
' + req._t(mention.open ? 'issue.Reopened' : 'issue.Closed', { name: authorLink, type: type }) + ' · ' + msgTimeLink + '
' + commitLink + '
' } else if ((mention = getMention(msg, issue.id))) { var commitLink = u.link(mention.object ? [repo.id, 'commit', mention.object] : [msg.key], mention.label || mention.object || msg.key) return '
' + req._t('issue.Mentioned', { name: authorLink, type: type }) + ' · ' + msgTimeLink + '
' + commitLink + '
' } else { // fallthrough } default: return '
' + authorLink + ' · ' + msgTimeLink + u.json(c) + '
' } }