| [12139] | 1 | # -*- coding: utf-8 -*- |
|---|
| [1482] | 2 | |
|---|
| [909] | 3 | from tracdiscussion.api import * |
|---|
| [1066] | 4 | from tracdiscussion.core import * |
|---|
| [66] | 5 | from trac.core import * |
|---|
| [909] | 6 | from trac.wiki import IWikiSyntaxProvider, IWikiMacroProvider |
|---|
| [1262] | 7 | from trac.web.main import IRequestHandler, IRequestFilter |
|---|
| [909] | 8 | from trac.web.chrome import add_stylesheet |
|---|
| 9 | from trac.util import format_datetime |
|---|
| [1252] | 10 | from trac.util.html import html |
|---|
| [2836] | 11 | from trac.util.text import to_unicode |
|---|
| [1262] | 12 | import time, re |
|---|
| [66] | 13 | |
|---|
| [909] | 14 | view_topic_doc = """Displays content of discussion topic. If no argument passed |
|---|
| 15 | tries to find topic with same name as name of current wiki page. If topic name |
|---|
| 16 | passed displays that topic. """ |
|---|
| 17 | |
|---|
| [66] | 18 | class DiscussionWiki(Component): |
|---|
| [804] | 19 | """ |
|---|
| 20 | The wiki module implements macros for forums, topics and messages |
|---|
| 21 | referencing. |
|---|
| 22 | """ |
|---|
| [1262] | 23 | implements(IWikiSyntaxProvider, IWikiMacroProvider, IRequestFilter) |
|---|
| [66] | 24 | |
|---|
| [1262] | 25 | # IWikiSyntaxProvider methods |
|---|
| [3373] | 26 | |
|---|
| [66] | 27 | def get_link_resolvers(self): |
|---|
| 28 | yield ('forum', self._discussion_link) |
|---|
| 29 | yield ('topic', self._discussion_link) |
|---|
| 30 | yield ('message', self._discussion_link) |
|---|
| 31 | |
|---|
| 32 | def get_wiki_syntax(self): |
|---|
| 33 | return [] |
|---|
| 34 | |
|---|
| [1262] | 35 | # IWikiMacroProvider methods |
|---|
| [3373] | 36 | |
|---|
| [909] | 37 | def get_macros(self): |
|---|
| 38 | yield 'ViewTopic' |
|---|
| 39 | |
|---|
| 40 | def get_macro_description(self, name): |
|---|
| 41 | if name == 'VisitCounter': |
|---|
| 42 | return view_topic_doc |
|---|
| 43 | else: |
|---|
| 44 | return "" |
|---|
| 45 | |
|---|
| 46 | def render_macro(self, req, name, content): |
|---|
| 47 | if name == 'ViewTopic': |
|---|
| [2014] | 48 | self.log.debug("Rendering ViewTopic macro...") |
|---|
| 49 | |
|---|
| [1066] | 50 | # Determine topic subject |
|---|
| [909] | 51 | if content: |
|---|
| 52 | subject = content |
|---|
| 53 | else: |
|---|
| 54 | subject = req.path_info[6:] or 'WikiStart' |
|---|
| 55 | |
|---|
| [2541] | 56 | # Get database access. |
|---|
| [1252] | 57 | db = self.env.get_db_cnx() |
|---|
| 58 | cursor = db.cursor() |
|---|
| 59 | |
|---|
| [1066] | 60 | # Get topic by subject |
|---|
| [3518] | 61 | api = self.env[DiscussionApi] |
|---|
| [1252] | 62 | topic = api.get_topic_by_subject(cursor, subject) |
|---|
| [2014] | 63 | self.log.debug('subject: %s' % (subject,)) |
|---|
| [1221] | 64 | self.log.debug('topic: %s' % (topic,)) |
|---|
| [909] | 65 | |
|---|
| [1262] | 66 | # Return macro content |
|---|
| [2014] | 67 | req.args['component'] = 'wiki' |
|---|
| [1066] | 68 | if topic: |
|---|
| [2014] | 69 | req.args['forum'] = topic['forum'] |
|---|
| 70 | req.args['topic'] = topic['id'] |
|---|
| [2836] | 71 | return to_unicode(req.hdf.render(api.render_discussion(req)[0])) |
|---|
| [909] | 72 | else: |
|---|
| 73 | raise TracError('Not implemented macro %s' % (name)) |
|---|
| 74 | |
|---|
| [1262] | 75 | # IRequestFilter methods |
|---|
| 76 | def pre_process_request(self, req, handler): |
|---|
| [2014] | 77 | # Change method from POST to GET. |
|---|
| [1262] | 78 | match = re.match(r'^/wiki(?:/(.*))?', req.path_info) |
|---|
| 79 | action = req.args.get('discussion_action') |
|---|
| [2014] | 80 | if match and action and req.method == 'POST': |
|---|
| 81 | req.environ['REQUEST_METHOD'] = 'GET' |
|---|
| [1262] | 82 | |
|---|
| [2014] | 83 | # Continue processing request. |
|---|
| 84 | return handler |
|---|
| 85 | |
|---|
| [1262] | 86 | def post_process_request(self, req, template, content_type): |
|---|
| 87 | return (template, content_type) |
|---|
| 88 | |
|---|
| 89 | # Core code methods |
|---|
| [66] | 90 | def _discussion_link(self, formatter, ns, params, label): |
|---|
| [804] | 91 | id = params |
|---|
| 92 | |
|---|
| [2541] | 93 | # Get database access. |
|---|
| [66] | 94 | db = self.env.get_db_cnx() |
|---|
| 95 | cursor = db.cursor() |
|---|
| [2541] | 96 | |
|---|
| [66] | 97 | if ns == 'forum': |
|---|
| [804] | 98 | columns = ('subject',) |
|---|
| [1482] | 99 | sql = "SELECT f.subject FROM forum f WHERE f.id = %s" |
|---|
| [1066] | 100 | self.log.debug(sql % (id,)) |
|---|
| [1006] | 101 | cursor.execute(sql, (id,)) |
|---|
| [804] | 102 | for row in cursor: |
|---|
| 103 | row = dict(zip(columns, row)) |
|---|
| [1252] | 104 | return html.a(label, href = formatter.href.discussion(id), |
|---|
| [3464] | 105 | title = row['subject'].replace('"', '')) |
|---|
| [1252] | 106 | return html.a(label, href = '%s/%s' % (formatter.href.discussion(), |
|---|
| [3464] | 107 | id), title = label.replace('"', ''), class_ = 'missing') |
|---|
| [66] | 108 | elif ns == 'topic': |
|---|
| [804] | 109 | columns = ('forum', 'forum_subject', 'subject') |
|---|
| [1497] | 110 | sql = "SELECT t.forum, f.subject, t.subject FROM topic t LEFT" \ |
|---|
| [2236] | 111 | " JOIN forum f ON t.forum = f.id WHERE t.id = %s" |
|---|
| [1066] | 112 | self.log.debug(sql % (id,)) |
|---|
| [1006] | 113 | cursor.execute(sql, (id,)) |
|---|
| [804] | 114 | for row in cursor: |
|---|
| 115 | row = dict(zip(columns, row)) |
|---|
| [1252] | 116 | return html.a(label, href = '%s#-1' % \ |
|---|
| 117 | (formatter.href.discussion(row['forum'], id),), title = |
|---|
| [3464] | 118 | ('%s: %s' % (row['forum_subject'], row['subject'])) |
|---|
| 119 | .replace('"', '')) |
|---|
| [1252] | 120 | return html.a(label, href = '%s/%s' % (formatter.href.discussion(), |
|---|
| [3464] | 121 | id), title = label.replace('"', ''), class_ = 'missing') |
|---|
| [66] | 122 | elif ns == 'message': |
|---|
| [804] | 123 | columns = ('forum', 'topic', 'forum_subject', 'subject') |
|---|
| [1497] | 124 | sql = "SELECT m.forum, m.topic, f.subject, t.subject FROM" \ |
|---|
| [2236] | 125 | " message m, (SELECT subject, id FROM forum) f," \ |
|---|
| 126 | " (SELECT subject, id FROM topic) t WHERE" \ |
|---|
| [1497] | 127 | " m.forum = f.id AND m.topic = t.id AND m.id = %s" |
|---|
| [1066] | 128 | self.log.debug(sql % (id,)) |
|---|
| [1006] | 129 | cursor.execute(sql, (id,)) |
|---|
| [804] | 130 | for row in cursor: |
|---|
| 131 | row = dict(zip(columns, row)) |
|---|
| [1252] | 132 | return html.a(label, href = '%s#%s' % \ |
|---|
| 133 | (formatter.href.discussion(row['forum'], row['topic'], id), |
|---|
| [3464] | 134 | id), title = ('%s: %s' % (row['forum_subject'], |
|---|
| 135 | row['subject'])).replace('"', '')) |
|---|
| [1252] | 136 | return html.a(label, href = '%s/%s' % (formatter.href.discussion(), |
|---|
| [3464] | 137 | id), title = label.replace('"', ''), class_ = 'missing') |
|---|
| [909] | 138 | else: |
|---|
| [1252] | 139 | return html.a(label, href = '%s/%s' % (formatter.href.discussion(), |
|---|
| [3464] | 140 | id), title = label.replace('"', ''), class_ = 'missing') |
|---|