def last_modifier(self): # Let's see if we have any last_modifier annotation raw_last_modifier = self._raw_last_modifier() if raw_last_modifier: return raw_last_modifier # If we are here: try with with history support if is available. history = queryMultiAdapter((self.context, self.request), interface=Interface, name=u"contenthistory") # Security is in the view definition. Here we act as an omnipotent user old_sm = getSecurityManager() tmp_user = UnrestrictedUser(old_sm.getUser().getId() or '', '', ['Manager'], '') newSecurityManager(None, tmp_user) try: if not history and sys.version_info < (2, 6): # We didn't found any history... is this a Plone 3? Let's try with the old history viewlet # To be sure of that let's do it only if we are using Python 2.4 # Please remove this abomination when Plone 3.3 compatibity will be dropped history = ContentHistoryViewlet(self.context, self.request, None, manager=None) history.update() if history: full_history = history.fullHistory() if full_history: return full_history[0].get('actorid') or full_history[0].get('actor').get('username') finally: setSecurityManager(old_sm)
def reply(self): # Traverse to historical version if self.version: serializer = queryMultiAdapter((self.context, self.request), ISerializeToJson) data = serializer(version=self.version) return data # Listing historical data content_history_viewlet = ContentHistoryViewlet( self.context, self.request, None, None) site_url = getSite().absolute_url() content_history_viewlet.navigation_root_url = site_url content_history_viewlet.site_url = site_url history = content_history_viewlet.fullHistory() unwanted_keys = [ 'diff_current_url', 'diff_previous_url', 'preview_url', 'actor_home', 'actorid', 'revert_url', 'version_id', ] for item in history: item['actor'] = { '@id': '{}/@users/{}'.format(site_url, item['actorid']), 'id': item['actorid'], 'fullname': item['actor'].get('fullname'), 'username': item['actor'].get('username'), } if item['type'] == 'versioning': item['version'] = item['version_id'] item['@id'] = '{}/@history/{}'.format( self.context.absolute_url(), item['version']) # If a revert_url is present, then CMFEditions has checked our # permissions. item['may_revert'] = bool(item.get('revert_url')) # Versioning entries use a timestamp, # workflow ISO formatted string if not isinstance(item['time'], basestring): item['time'] = dt.fromtimestamp(item['time']).isoformat() # The create event has an empty 'action', but we like it to say # 'Create', alike the transition_title if item['action'] is None: item['action'] = 'Create' # clean up for key in unwanted_keys: if key in item: del item[key] return json_compatible(history)
def getFullHistory(item): """ http://docs.plone.org/develop/plone/content/history.html """ history = None # TODO: user must exist in plonsite ! Zopeadmin can watch anyway. #admin = portal().acl_users.getUser('siteadmin') #newSecurityManager(request, admin) request = TestRequest() chv = ContentHistoryViewlet(item, request, None, None) # These attributes are needed, the fullHistory() call fails otherwise chv.navigation_root_url = chv.site_url = 'http://www.example.org' history = chv.fullHistory() return history
def test_statictime_full_history(self): frozen_time = datetime(1950, 7, 31, 17, 30) statictime = StaticTime(modified=frozen_time) statictime.start() doc1 = self.create_document("doc1") doc1.setTitle("Current version") api.content.transition(doc1, "publish") viewlet = ContentHistoryViewlet(doc1, doc1.REQUEST, None) viewlet.update() history = viewlet.fullHistory() real_datetimes = list(map(itemgetter("time"), history)) self.assertEqual( real_datetimes, [ DateTime("1950/07/31 17:30:00 UTC"), -612855000.0, DateTime("1950/07/31 19:30:00 UTC"), ], ) statictime.stop() doc2 = self.create_document("doc2") doc2.setTitle("Current version") api.content.transition(doc2, "publish") viewlet = ContentHistoryViewlet(doc2, doc2.REQUEST, None) viewlet.update() history = viewlet.fullHistory() fake_datetimes = list(map(itemgetter("time"), history)) for ts in fake_datetimes: self.assert_roughly_now(ts) self.assert_of_same_type(fake_datetimes, real_datetimes)
def test_revertAbility(self): # check revert URL is generated only if the user has the appropriate permission repo_tool = self.portal.portal_repository request = self.app.REQUEST context = getattr(self.folder, 'd1') self.loginAsPortalOwner() repo_tool.save(context, comment='Initial Revision') repo_tool.save(context, comment='Second Revision') viewlet = ContentHistoryViewlet(context, request, None, None) viewlet.update() history = viewlet.revisionHistory() self.assertTrue( 'http://nohost/plone/Members/test_user_1_/d1/revertversion' in history[0]['revert_url']) # noqa self.portal.manage_permission('CMFEditions: Revert to previous versions', [], False) viewlet.update() history = viewlet.revisionHistory() self.assertEqual(history[0]['revert_url'], None)
def test_revertAbility(self): # check revert URL is generated only if the user has the appropriate permission repo_tool = self.portal.portal_repository request = self.app.REQUEST context = getattr(self.folder, 'd1') self.loginAsPortalOwner() repo_tool.save(context, comment='Initial Revision') repo_tool.save(context, comment='Second Revision') viewlet = ContentHistoryViewlet(context, request, None, None) viewlet.update() history = viewlet.revisionHistory() self.assertEqual(history[0]['revert_url'], 'http://nohost/plone/Members/test_user_1_/d1/revertversion') self.portal.manage_permission('CMFEditions: Revert to previous versions', [], False) viewlet.update() history = viewlet.revisionHistory() self.assertEqual(history[0]['revert_url'], None)
def folderitems(self): rc = getToolByName(self.context, REFERENCE_CATALOG) wf = getToolByName(self.context, 'portal_workflow') pr = getToolByName(self.context, 'portal_repository') isVersionable = pr.isVersionable(aq_inner(self.context)) review_history = wf.getInfoFor(self.context, 'review_history') review_history.reverse() items = [] for entry in review_history: # this folderitems doesn't subclass from the bika_listing.py # so we create items from scratch review_state = entry.get('review_state') state_title = wf.getTitleForStateOnType(review_state, self.context.portal_type) item = { 'obj': self.context, 'id': self.context.id, 'uid': self.context.UID(), 'title': self.context.title_or_id(), 'type_class': '', 'url': self.context.absolute_url(), 'relative_url': self.context.absolute_url(), 'view_url': self.context.absolute_url(), 'path': "/".join(self.context.getPhysicalPath()), 'replace': {}, 'before': {}, 'after': {}, 'choices':{}, 'class': {}, 'state_class': '', 'allow_edit': [], 'Version': isVersionable and self.context.get('version_id', '') or '0', 'Date': TimeOrDate(self.context, entry.get('time'), long_format=1), 'sortable_date': entry.get('time'), 'User': entry.get('actor'), 'Action': entry.get('action') and entry.get('action') or 'Create', 'Description': "review state: %s" % state_title, } items.append(item) if isVersionable: request = TestRequest() chv = ContentHistoryViewlet(self.context, request, None, None) chv.navigation_root_url = chv.site_url = 'http://localhost:8080/bikas' version_history = chv.revisionHistory() else: version_history = [] for entry in version_history: # this folderitems doesn't subclass from the bika_listing.py # so we create items from scratch # disregard the first entry of version history, as it is # represented by the first entry in review_history if not entry.get('version_id'): continue item = { 'obj': self.context, 'id': self.context.id, 'uid': self.context.UID(), 'title': self.context.title_or_id(), 'type_class': '', 'url': self.context.absolute_url(), 'relative_url': self.context.absolute_url(), 'view_url': self.context.absolute_url(), 'path': "/".join(self.context.getPhysicalPath()), 'replace': {}, 'before': {}, 'after': {}, 'choices':{}, 'class': {}, 'state_class': '', 'allow_edit': [], 'Version': entry.get('version_id'), 'Date': TimeOrDate(self.context, DateTime(entry.get('time')), long_format=1), 'sortable_date': entry.get('time'), 'User': entry.get('actor').get('fullname'), 'Action': entry.get('action') and entry.get('action') or 'Create', 'Description': entry.get('comments'), } items.append(item) items = sorted(items, key = itemgetter('sortable_date')) items.reverse() return items
def test_revisionHistory(self): repo_tool = self.portal.portal_repository request = self.app.REQUEST context = getattr(self.folder, 'd1') self.loginAsPortalOwner() repo_tool.save(context, comment='Initial Revision') viewlet = ContentHistoryViewlet(context, request, None, None) viewlet.update() history = viewlet.revisionHistory() self.assertEqual(len(history), 1) self.assertEqual(history[0]['comments'], 'Initial Revision') repo_tool.save(context, comment='Second Revision') viewlet.update() history = viewlet.revisionHistory() self.assertTrue( 'http://nohost/plone/Members/test_user_1_/d1/@@history?one=1&two=0' in history[0]['diff_previous_url'] ) # check diff link does not appear if content is not diffable diff_tool = self.portal.portal_diff diff_tool.setDiffForPortalType('Document', {}) viewlet.update() history = viewlet.revisionHistory() self.assertFalse('diff_previous_url' in history[0])
def test_emptyHistory(self): request = self.app.REQUEST context = getattr(self.folder, 'd1') viewlet = ContentHistoryViewlet(context, request, None, None) viewlet.update() self.assertEqual(viewlet.revisionHistory(), [])
def folderitems(self): rc = getToolByName(self.context, REFERENCE_CATALOG) wf = getToolByName(self.context, 'portal_workflow') pr = getToolByName(self.context, 'portal_repository') isVersionable = pr.isVersionable(aq_inner(self.context)) review_history = wf.getInfoFor(self.context, 'review_history') review_history = list(review_history) review_history.reverse() items = [] for entry in review_history: # this folderitems doesn't subclass from the bika_listing.py # so we create items from scratch review_state = entry.get('review_state') state_title = wf.getTitleForStateOnType(review_state, self.context.portal_type) item = { 'obj': self.context, 'id': self.context.id, 'uid': self.context.UID(), 'title': self.context.title_or_id(), 'type_class': '', 'url': self.context.absolute_url(), 'relative_url': self.context.absolute_url(), 'view_url': self.context.absolute_url(), 'path': "/".join(self.context.getPhysicalPath()), 'replace': {}, 'before': {}, 'after': {}, 'choices': {}, 'class': {}, 'state_class': '', 'allow_edit': [], 'Version': isVersionable and self.context.get('version_id', '') or '0', 'Date': self.ulocalized_time(entry.get('time')), 'sortable_date': entry.get('time'), 'User': entry.get('actor'), 'Action': entry.get('action') and entry.get('action') or 'Create', 'Description': "review state: %s" % state_title, } items.append(item) if isVersionable: request = TestRequest() chv = ContentHistoryViewlet(self.context, request, None, None) chv.navigation_root_url = chv.site_url = 'http://localhost:8080/bikas' version_history = chv.revisionHistory() else: version_history = [] for entry in version_history: # this folderitems doesn't subclass from the bika_listing.py # so we create items from scratch # disregard the first entry of version history, as it is # represented by the first entry in review_history if not entry.get('version_id'): continue item = { 'obj': self.context, 'id': self.context.id, 'uid': self.context.UID(), 'title': self.context.title_or_id(), 'type_class': '', 'url': self.context.absolute_url(), 'relative_url': self.context.absolute_url(), 'view_url': self.context.absolute_url(), 'path': "/".join(self.context.getPhysicalPath()), 'replace': {}, 'before': {}, 'after': {}, 'choices': {}, 'class': {}, 'state_class': '', 'allow_edit': [], 'Version': entry.get('version_id'), 'Date': self.ulocalized_time(DateTime(entry.get('time'))), 'sortable_date': entry.get('time'), 'User': entry.get('actor').get('fullname'), 'Action': entry.get('action') and entry.get('action') or 'Create', 'Description': entry.get('comments'), } items.append(item) items = sorted(items, key=itemgetter('sortable_date')) items.reverse() return items
def reply(self): # Traverse to historical version if self.version: serializer = queryMultiAdapter((self.context, self.request), ISerializeToJson) data = serializer(version=self.version) return data # Listing historical data content_history_viewlet = ContentHistoryViewlet( self.context, self.request, None, None) site_url = getSite().absolute_url() content_history_viewlet.navigation_root_url = site_url content_history_viewlet.site_url = site_url history = content_history_viewlet.fullHistory() if history is None: history = [] unwanted_keys = [ "diff_current_url", "diff_previous_url", "preview_url", "actor_home", "actorid", "revert_url", "version_id", ] for item in history: item["actor"] = { "@id": "{}/@users/{}".format(site_url, item["actorid"]), "id": item["actorid"], "fullname": item["actor"].get("fullname"), "username": item["actor"].get("username"), } if item["type"] == "versioning": item["version"] = item["version_id"] item["@id"] = "{}/@history/{}".format( self.context.absolute_url(), item["version"]) # If a revert_url is present, then CMFEditions has checked our # permissions. item["may_revert"] = bool(item.get("revert_url")) # Versioning entries use a timestamp, # workflow ISO formatted string if not isinstance(item["time"], str): item["time"] = dt.fromtimestamp(int(item["time"])).isoformat() # The create event has an empty 'action', but we like it to say # 'Create', alike the transition_title if item["action"] is None: item["action"] = "Create" # We want action, state and transition names translated if "state_title" in item: item["state_title"] = self.context.translate( safe_unicode(item["state_title"]), context=self.request) if "transition_title" in item: item["transition_title"] = self.context.translate( safe_unicode(item["transition_title"]), context=self.request) if "action" in item: item["action"] = self.context.translate(safe_unicode( item["action"]), context=self.request) # clean up for key in unwanted_keys: if key in item: del item[key] return json_compatible(history)