Switch to side-by-side view

--- a/ForgeTracker/forgetracker/tracker_main.py
+++ b/ForgeTracker/forgetracker/tracker_main.py
@@ -23,6 +23,8 @@
 from pyforge.lib.decorators import audit, react
 from pyforge.lib.security import require, has_artifact_access
 from pyforge.model import ProjectRole, TagEvent, UserTags, ArtifactReference, Feed
+from pyforge.lib import widgets as w
+from pyforge.controllers import AppDiscussionController
 
 # Local imports
 from forgetracker import model
@@ -33,19 +35,39 @@
 
 log = logging.getLogger(__name__)
 
+class W:
+    thread=w.Thread(
+        offset=None, limit=None, page_size=None, total=None,
+        style='linear')
+
 class ForgeTrackerApp(Application):
     __version__ = version.__version__
-    permissions = ['configure', 'read', 'write', 'comment']
+    permissions = ['configure', 'read', 'write',
+                    'unmoderated_post', 'post', 'moderate', 'admin']
 
     def __init__(self, project, config):
         Application.__init__(self, project, config)
         self.root = RootController()
         self.admin = TrackerAdminController(self)
 
-    @audit('Tickets.#')
-    def auditor(self, routing_key, data):
+    def has_access(self, user, topic):
+        return has_artifact_access('post', user=user)
+
+    @audit('Tickets.msg.#')
+    def message_auditor(self, routing_key, data):
         log.info('Auditing data from %s (%s)',
                  routing_key, self.config.options.mount_point)
+        log.info('Headers are: %s', data['headers'])
+        try:
+            ticket_num = routing_key.split('.')[-1]
+            t = model.Ticket.query.get(ticket_num=int(ticket_num))
+        except:
+            log.exception('Unexpected error routing tkt msg: %s', routing_key)
+            return
+        if t is None:
+            log.error("Can't find ticket %s (routing key was %s)",
+                      ticket_num, routing_key)
+        super(ForgeTrackerApp, self).message_auditor(routing_key, data, t)
 
     @react('Tickets.#')
     def reactor(self, routing_key, data):
@@ -72,6 +94,7 @@
             ticket = None
         links = [
             SitemapEntry('Home', self.config.url()),
+            SitemapEntry('Discuss', c.app.url + '_discuss/'),
             SitemapEntry('Create New Ticket', self.config.url() + 'new/')]
         if ticket:
             links.append(SitemapEntry('Update this Ticket',ticket.url() + 'edit/'))
@@ -111,13 +134,14 @@
         'Set up any default permissions and roles here'
 
         self.uninstall(project)
+        super(ForgeTrackerApp, self).install(project)
         # Give the installing user all the permissions
         pr = c.user.project_role()
         for perm in self.permissions:
               self.config.acl[perm] = [ pr._id ]
         self.config.acl['read'].append(
             ProjectRole.query.get(name='*anonymous')._id)
-        self.config.acl['comment'].append(
+        self.config.acl['post'].append(
             ProjectRole.query.get(name='*authenticated')._id)
         model.Globals(app_config_id=c.app.config._id,
             last_ticket_num=0,
@@ -129,7 +153,7 @@
         model.Attachment.query.remove({'metadata.app_config_id':c.app.config._id})
         app_config_id = {'app_config_id':c.app.config._id}
         model.Ticket.query.remove(app_config_id)
-        model.Comment.query.remove(app_config_id)
+        # model.Comment.query.remove(app_config_id)
         model.Globals.query.remove(app_config_id)
 
 class RootController(object):
@@ -137,14 +161,20 @@
     def __init__(self):
         setattr(self, 'feed.atom', self.feed)
         setattr(self, 'feed.rss', self.feed)
+        self._discuss = AppDiscussionController()
 
     def ordered_history(self, limit=None):
         q = []
         tickets = model.Ticket.query.find(dict(app_config_id=c.app.config._id)).sort('ticket_num')
         for ticket in tickets:
-            q.append(dict(change_type='ticket',change_date=ticket.created_date,ticket_num=ticket.ticket_num,change_text=ticket.summary))
-            for comment in ticket.ordered_comments(limit):
-                q.append(dict(change_type='comment',change_date=comment.created_date,ticket_num=ticket.ticket_num,change_text=comment.text))
+            q.append(dict(change_type='ticket',change_date=ticket.created_date,
+                          ticket_num=ticket.ticket_num,change_text=ticket.summary))
+            for comment in ticket.discussion_thread().find_posts(limit=limit, style='linear'):
+                # for comment in ticket.ordered_comments(limit):
+                q.append(dict(change_type='comment',
+                              change_date=comment.timestamp,
+                              ticket_num=ticket.ticket_num,
+                              change_text=comment.text))
         q.sort(reverse=True)
         if limit:
             n = len(q)
@@ -371,7 +401,7 @@
             self.ticket = model.Ticket.query.get(app_config_id=c.app.config._id,
                                                     ticket_num=self.ticket_num)
             self.attachment = AttachmentsController(self.ticket)
-            self.comments = CommentController(self.ticket)
+            # self.comments = CommentController(self.ticket)
         setattr(self, 'feed.atom', self.feed)
         setattr(self, 'feed.rss', self.feed)
 
@@ -379,6 +409,7 @@
     @expose('forgetracker.templates.ticket')
     def index(self, **kw):
         require(has_artifact_access('read', self.ticket))
+        c.thread = W.thread
         if self.ticket is not None:
             globals = model.Globals.query.get(app_config_id=c.app.config._id)
             return dict(ticket=self.ticket, globals=globals)
@@ -389,6 +420,7 @@
     @expose('forgetracker.templates.edit_ticket')
     def edit(self, **kw):
         require(has_artifact_access('write', self.ticket))
+        c.thread = W.thread
         globals = model.Globals.query.get(app_config_id=c.app.config._id)
         user_tags = UserTags.upsert(c.user, self.ticket.dump_ref())
         return dict(ticket=self.ticket, globals=globals, user_tags=user_tags)
@@ -502,37 +534,37 @@
             return fp.read()
         return self.filename
 
-class CommentController(object):
-
-    def __init__(self, ticket, comment_id=None):
-        self.ticket = ticket
-        self.comment_id = comment_id
-        self.comment = model.Comment.query.get(slug=comment_id)
-
-    @expose()
-    def reply(self, text):
-        require(has_artifact_access('comment', self.ticket))
-        if self.comment_id:
-            c = self.comment.reply(text)
-        else:
-            c = self.ticket.reply(text)
-        redirect(request.referer)
-
-    @expose()
-    def delete(self):
-#        require(lambda:c.user._id == self.comment.author()._id)
-#        self.comment.text = '[Text deleted by commenter]'
-        self.comment.delete()
-        redirect(request.referer)
-
-    def _lookup(self, next, *remainder):
-        if self.comment_id:
-            return CommentController(
-                self.ticket,
-                self.comment_id + '/' + next), remainder
-        else:
-            return CommentController(
-                self.ticket, next), remainder
+# class CommentController(object):
+
+#     def __init__(self, ticket, comment_id=None):
+#         self.ticket = ticket
+#         self.comment_id = comment_id
+#         # self.comment = model.Comment.query.get(slug=comment_id)
+
+#     @expose()
+#     def reply(self, text):
+#         require(has_artifact_access('comment', self.ticket))
+#         if self.comment_id:
+#             c = self.comment.reply(text)
+#         else:
+#             c = self.ticket.reply(text)
+#         redirect(request.referer)
+
+#     @expose()
+#     def delete(self):
+# #        require(lambda:c.user._id == self.comment.author()._id)
+# #        self.comment.text = '[Text deleted by commenter]'
+#         self.comment.delete()
+#         redirect(request.referer)
+
+#     def _lookup(self, next, *remainder):
+#         if self.comment_id:
+#             return CommentController(
+#                 self.ticket,
+#                 self.comment_id + '/' + next), remainder
+#         else:
+#             return CommentController(
+#                 self.ticket, next), remainder
 
 NONALNUM_RE = re.compile(r'\W+')