from bson import ObjectId
from bson.errors import InvalidId
from ming.orm import ThreadLocalORMSession
from pylons import tmpl_context as c
from allura.command import base
from allura import model as M
from allura.lib import exceptions as exc
from forgetracker.model import Ticket
class FixDiscussion(base.Command):
"""Fixes trackers that had used buggy 'ticket move' feature before it was fixed.
See [#5727] for details.
Usage:
paster fix-discussion ../Allura/development.ini [project_name_or_id]
If used with optional parameter will fix trackers for specified project,
else will fix all trackers in all projects.
"""
group_name = 'ForgeTracker'
min_args = 1
max_args = 2
usage = '<ini file> [project_name_or_id]'
summary = "Fix trackers that had used buggy 'ticket move' feature"
parser = base.Command.standard_parser(verbose=True)
def command(self):
self.basic_setup()
if len(self.args) >= 2:
p_name_or_id = self.args[1]
try:
project = M.Project.query.get(_id=ObjectId(p_name_or_id))
except InvalidId:
projects = M.Project.query.find({'$or': [
{'shortname': p_name_or_id},
{'name': p_name_or_id}
]})
if projects.count() > 1:
raise exc.ForgeError('Multiple projects has a shortname %s. '
'Use project _id instead.' % p_name_or_id)
project = projects.first()
if not project:
raise exc.NoSuchProjectError('The project %s '
'could not be found' % p_name_or_id)
self.fix_for_project(project)
else:
base.log.info('Checking discussion instances for each tracker in all projects')
for project in M.Project.query.find():
self.fix_for_project(project)
def fix_for_project(self, project):
c.project = project
base.log.info('Checking discussion instances for each tracker in project %s' % project.shortname)
trackers = [ac for ac in project.app_configs
if ac.tool_name.lower() == 'tickets']
for tracker in trackers:
base.log.info('Found tracker %s' % tracker)
for ticket in Ticket.query.find({'app_config_id': tracker._id}):
base.log.info('Processing ticket %s [#%s] %s'
% (ticket._id, ticket.ticket_num, ticket.summary))
if ticket.discussion_thread.discussion.app_config_id != tracker._id:
# Some tickets were moved from this tracker,
# and Discussion instance for entire tracker was moved too.
# Should move it back.
base.log.info("Some tickets were moved from this tracker. "
"Moving tracker's discussion instance back.")
ticket.discussion_thread.discussion.app_config_id = tracker._id
if ticket.discussion_thread.discussion_id != tracker.discussion_id:
# Ticket was moved from another tracker.
# Should bind his comment thread to tracker's Discussion
base.log.info("Ticket was moved from another tracker. "
"Bind ticket's comment thread to tracker's Discussion instance.")
ticket.discussion_thread.discussion_id = tracker.discussion_id
for post in ticket.discussion_thread.posts:
post.discussion_id = tracker.discussion_id
ThreadLocalORMSession.flush_all()