Merge pull request #104 from plone/maurits-remove-migration

Removed `comment-migration` view.
This commit is contained in:
Jens W. Klein 2016-06-13 09:48:39 +02:00 committed by GitHub
commit 69ded592c3
5 changed files with 4 additions and 321 deletions

View File

@ -31,6 +31,10 @@ Bug fixes:
user to fill in the form without validation error. Or when in the
control panel the field is set as not required anymore, that change
would have no effect until the instance was restarted. [maurits]
- Removed ``comment-migration`` view. This did not work anymore on
Plone 5. If you still need to migrate from old-style comments, so
from Plone 4.0 or earlier, please upgrade to Plone 4.3 first.
[maurits]
2.4.14 (2016-06-06)

View File

@ -11,15 +11,6 @@
<!-- Traversal adapter -->
<adapter factory=".traversal.ConversationNamespace" name="conversation" />
<!-- Migration view -->
<browser:page
for="Products.CMFCore.interfaces.ISiteRoot"
name="comment-migration"
layer="..interfaces.IDiscussionLayer"
class=".migration.View"
permission="cmf.ManagePortal"
/>
<!-- Moderation view -->
<browser:page
for="Products.CMFCore.interfaces.ISiteRoot"

View File

@ -49,25 +49,6 @@
</span>
</div>
<div class="portalMessage warning"
tal:condition="view/unmigrated_comments_warning">
<strong i18n:translate="">
Warning
</strong>
<span tal:omit-tag="" i18n:translate="text_unmigrated_comments">
You have comments that have not been migrated to the new
commenting system that has been introduced in Plone 4.1.
Please
<tal:link i18n:name="label_comments_migration_link">
<a href=""
i18n:translate="text_comments_migration_link"
tal:attributes="href string:${view/site_url}/@@comment-migration"
>migrate your comments</a>
</tal:link>
to fix this.
</span>
</div>
<div metal:use-macro="context/global_statusmessage/macros/portal_message">
Portal status message
</div>

View File

@ -6,7 +6,6 @@ from plone.app.discussion.upgrades import update_registry
from plone.app.registry.browser import controlpanel
from plone.registry.interfaces import IRecordModifiedEvent
from plone.registry.interfaces import IRegistry
from Products.CMFCore.interfaces._content import IDiscussionResponse
from Products.CMFCore.utils import getToolByName
from Products.CMFPlone.interfaces.controlpanel import IMailSchema
from Products.Five.browser.pagetemplatefile import ViewPageTemplateFile
@ -182,15 +181,6 @@ class DiscussionSettingsControlPanel(controlpanel.ControlPanelFormWrapper):
return
return True
def unmigrated_comments_warning(self):
"""Returns true if site contains unmigrated comments.
"""
catalog = getToolByName(self.context, 'portal_catalog', None)
count_comments_old = catalog.searchResults(
object_provides=IDiscussionResponse.__identifier__)
if count_comments_old:
return True
def notify_configuration_changed(event):
"""Event subscriber that is called every time the configuration changed.

View File

@ -1,283 +0,0 @@
# -*- coding: utf-8 -*-
from Acquisition import aq_inner
from Acquisition import aq_parent
from datetime import datetime
from DateTime import DateTime
from plone.app.discussion.comment import CommentFactory
from plone.app.discussion.interfaces import IComment
from plone.app.discussion.interfaces import IConversation
from plone.app.discussion.interfaces import IReplies
from Products.CMFCore.interfaces._content import IDiscussionResponse
from Products.CMFCore.utils import getToolByName
from Products.Five.browser import BrowserView
from types import TupleType
import transaction
def DT2dt(DT):
"""Convert a Zope DateTime (with timezone) into a Python datetime (GMT)."""
DT = DT.toZone('GMT')
return datetime(
DT.year(),
DT.month(),
DT.day(),
DT.hour(),
DT.minute(),
int(DT.second()))
class View(BrowserView):
"""Migration View
"""
def __call__(self, filter_callback=None):
context = aq_inner(self.context)
out = []
self.total_comments_migrated = 0
self.total_comments_deleted = 0
dry_run = 'dry_run' in self.request
# This is for testing only.
# Do not use transactions during a test.
test = 'test' in self.request
if not test:
transaction.begin() # pragma: no cover
catalog = getToolByName(context, 'portal_catalog')
def log(msg):
# encode string before sending it to external world
if isinstance(msg, unicode):
msg = msg.encode('utf-8') # pragma: no cover
context.plone_log(msg)
out.append(msg)
def migrate_replies(context, in_reply_to, replies,
depth=0, just_delete=0):
# Recursive function to migrate all direct replies
# of a comment. Returns True if there are no replies to
# this comment left, and therefore the comment can be removed.
if len(replies) == 0:
return True
workflow = context.portal_workflow
oldchain = workflow.getChainForPortalType('Discussion Item')
new_workflow = workflow.comment_review_workflow
mt = getToolByName(self.context, 'portal_membership')
if type(oldchain) == TupleType and len(oldchain) > 0:
oldchain = oldchain[0]
for reply in replies:
# log
indent = ' '
for i in range(depth):
indent += ' '
log('{0}migrate_reply: "{1}".'.format(indent, reply.title))
should_migrate = True
if filter_callback and not filter_callback(reply):
should_migrate = False
if just_delete:
should_migrate = False
new_in_reply_to = None
if should_migrate:
# create a reply object
comment = CommentFactory()
comment.title = reply.Title()
comment.text = reply.cooked_text
comment.mime_type = 'text/html'
comment.creator = reply.Creator()
try:
comment.author_username = reply.author_username
except AttributeError:
comment.author_username = reply.Creator()
member = mt.getMemberById(comment.author_username)
if member:
comment.author_name = member.fullname
if not comment.author_name:
# In migrated site member.fullname = ''
# while member.getProperty('fullname') has the
# correct value
if member:
comment.author_name = member.getProperty(
'fullname'
)
else:
comment.author_name = comment.author_username
try:
comment.author_email = reply.email
except AttributeError:
comment.author_email = None
comment.creation_date = DT2dt(reply.creation_date)
comment.modification_date = DT2dt(reply.modification_date)
comment.reply_to = in_reply_to
if in_reply_to == 0:
# Direct reply to a content object
new_in_reply_to = conversation.addComment(comment)
else:
# Reply to another comment
comment_to_reply_to = conversation.get(in_reply_to)
replies = IReplies(comment_to_reply_to)
new_in_reply_to = replies.addComment(comment)
# migrate the review state
old_status = workflow.getStatusOf(oldchain, reply)
new_status = {
'action': None,
'actor': None,
'comment': 'Migrated workflow state',
'review_state': old_status and old_status.get(
'review_state',
new_workflow.initial_state
) or 'published',
'time': DateTime()
}
workflow.setStatusOf('comment_review_workflow',
comment,
new_status)
auto_transition = new_workflow._findAutomaticTransition(
comment,
new_workflow._getWorkflowStateOf(comment))
if auto_transition is not None:
new_workflow._changeStateOf(comment, auto_transition)
else:
new_workflow.updateRoleMappingsFor(comment)
comment.reindexObject(idxs=['allowedRolesAndUsers',
'review_state'])
self.total_comments_migrated += 1
# migrate all talkbacks of the reply
talkback = getattr(reply, 'talkback', None)
no_replies_left = migrate_replies(
context,
new_in_reply_to,
talkback.getReplies(),
depth=depth + 1,
just_delete=not should_migrate)
if no_replies_left:
# remove reply and talkback
talkback.deleteReply(reply.id)
obj = aq_parent(talkback)
obj.talkback = None
log('{0}remove {1}'.format(indent, reply.id))
self.total_comments_deleted += 1
# Return True when all comments on a certain level have been
# migrated.
return True
# Find content
brains = catalog.searchResults(
object_provides='Products.CMFCore.interfaces._content.IContentish')
log('Found {0} content objects.'.format(len(brains)))
count_discussion_items = len(
catalog.searchResults(Type='Discussion Item')
)
count_comments_pad = len(
catalog.searchResults(object_provides=IComment.__identifier__)
)
count_comments_old = len(
catalog.searchResults(
object_provides=IDiscussionResponse.__identifier__
)
)
log(
'Found {0} Discussion Item objects.'.format(
count_discussion_items
)
)
log('Found {0} old discussion items.'.format(count_comments_old))
log(
'Found {0} plone.app.discussion comments.'.format(
count_comments_pad
)
)
log('\n')
log('Start comment migration.')
# This loop is necessary to get all contentish objects, but not
# the Discussion Items. This wouldn't be necessary if the
# zcatalog would support NOT expressions.
new_brains = []
for brain in brains:
if brain.portal_type != 'Discussion Item':
new_brains.append(brain)
# Recursively run through the comment tree and migrate all comments.
for brain in new_brains:
obj = brain.getObject()
talkback = getattr(obj, 'talkback', None)
if talkback:
replies = talkback.getReplies()
if replies:
conversation = IConversation(obj)
log('\n')
log(
'Migrate "{0}" ({1})'.format(
obj.Title(),
obj.absolute_url(relative=1)
)
)
migrate_replies(context, 0, replies)
obj = aq_parent(talkback)
obj.talkback = None
if self.total_comments_deleted != self.total_comments_migrated:
log(
'Something went wrong during migration. The number of '
'migrated comments ({0}) differs from the number of deleted '
'comments ({1}).'.format(
self.total_comments_migrated,
self.total_comments_deleted
)
)
if not test: # pragma: no cover
transaction.abort() # pragma: no cover
log('Abort transaction') # pragma: no cover
log('\n')
log('Comment migration finished.')
log('\n')
log(
'{0} of {1} comments migrated.'.format(
self.total_comments_migrated,
count_comments_old
)
)
if self.total_comments_migrated != count_comments_old:
log(
'{0} comments could not be migrated.'.format(
count_comments_old - self.total_comments_migrated
)
) # pragma: no cover
log('Please make sure your ' +
'portal catalog is up-to-date.') # pragma: no cover
if dry_run and not test:
transaction.abort() # pragma: no cover
log('Dry run') # pragma: no cover
log('Abort transaction') # pragma: no cover
if not test:
transaction.commit() # pragma: no cover
return '\n'.join(out)