def all_forums_view(context, request): page_title = "Message Boards" api = TemplateAPI(context, request, page_title) # Don't use the forums folder as the starting point, use its # parent (the community) to allow recursion context_path = model_path(context.__parent__) searcher = ICatalogSearch(context) total, docids, resolver = searcher( interfaces=[ICommunity], path={'query': context_path, 'include_path': True}, allowed={'query': effective_principals(request), 'operator': 'or'}, sort_index='title', ) community_data = [] for docid in docids: community = resolver(docid) if community is not None: forum_data = get_forum_data(community, request) if forum_data: community_data.append({'title': community.title, 'forum_data': forum_data}) return render_to_response( 'templates/all_forums.pt', {'api': api, 'community_data': community_data}, request=request )
def evolve(context): # Need to fix up acl's for blog entries in 'inherits' state. # See LP #407011 search = ICatalogSearch(context) cnt, docids, resolver = search(interfaces=[IBlogEntry]) for docid in docids: doc = resolver(docid) if (getattr(doc, 'security_state', 'inherits') == 'inherits'): print model_path(doc) doc.__acl__ = [ (Allow, 'group.KarlAdmin', ADMINISTRATOR_PERMS), (Allow, doc.creator, MEMBER_PERMS), (Deny, Everyone, ('edit', 'delete')), ] doc.security_state = 'inherits' _reindex(doc)
def main(argv=sys.argv): parser = create_karl_argparser( description='Add a fake blog tool to community for receiving mailin ' 'trace emails.' ) parser.add_argument('community', help='Community name.') parser.add_argument('file', help='Path to file to touch when a tracer ' 'email is received.') args = parser.parse_args(argv[1:]) env = args.bootstrap(args.config_uri) root, closer = env['root'], env['closer'] root, closer = args.get_root(args.inst) community = find_communities(root).get(args.community) if community is None: args.parser.error('Could not find community: %s' % args.community) blog = community.get('blog') if blog is not None: if len(blog) > 0: args.parser.error('Cannot replace blog with blog entries.') else: del community['blog'] community['blog'] = blog = MailinTraceBlog() out = args.out print >> out, 'Added mailin trace tool at: %s' % model_path(blog) settings = root._p_jar.root.instance_config settings['mailin_trace_file'] = args.file print >> out, 'The mailin trace file is: %s' % args.file transaction.commit() print >> out, ('You must restart the mailin daemon in order for the new ' 'settings to take effect.')
def main(argv=sys.argv): parser = create_karl_argparser( description='Add a fake blog tool to community for receiving mailin ' 'trace emails.') parser.add_argument('community', help='Community name.') parser.add_argument('file', help='Path to file to touch when a tracer ' 'email is received.') args = parser.parse_args(argv[1:]) env = args.bootstrap(args.config_uri) root, closer = env['root'], env['closer'] root, closer = args.get_root(args.inst) community = find_communities(root).get(args.community) if community is None: args.parser.error('Could not find community: %s' % args.community) blog = community.get('blog') if blog is not None: if len(blog) > 0: args.parser.error('Cannot replace blog with blog entries.') else: del community['blog'] community['blog'] = blog = MailinTraceBlog() out = args.out print >> out, 'Added mailin trace tool at: %s' % model_path(blog) settings = root._p_jar.root.instance_config settings['mailin_trace_file'] = args.file print >> out, 'The mailin trace file is: %s' % args.file transaction.commit() print >> out, ('You must restart the mailin daemon in order for the new ' 'settings to take effect.')
def get_resource_url(resource): """ Returns the URL for the given resource. """ path = model_path(resource) parsed = list(urlparse(path)) parsed[1] = "" return urlunparse(parsed)
def evolve(context): for path in exceptions: d = traverse(context, path) ob = d['context'] if model_path(ob) == path: if hasattr(ob, '__acl__'): ob.__custom_acl__ = ob.__acl__ reset_security_workflow(context)
def get_forum_data(community, request): karldates = getUtility(IKarlDates) searcher = ICatalogSearch(community) total, docids, resolver = searcher( interfaces=[IForum], path={'query': model_path(community), 'depth': 2}, allowed={'query': effective_principals(request), 'operator': 'or'}, sort_index='title', ) if not total: return None forum_data = [] profiles = find_profiles(community) profiles_href = model_url(profiles, request) for docid in docids: forum = resolver(docid) if forum is not None: D = {} D['title'] = forum.title D['url'] = model_url(forum, request) D['number_of_topics'] = len(forum) D['number_of_comments'] = number_of_comments(forum, request) latest = latest_object(forum, request) _NOW = datetime.datetime.now() if latest: D['latest_activity_url'] = model_url(latest, request) D['latest_activity_link'] = getattr(latest, 'title', None) creator = getattr(latest, 'creator', None) D['latest_activity_byhref'] = profiles_href + creator profile = profiles[creator] D['latest_activity_byname'] = profile.title modified = getattr(latest, 'modified_date', _NOW) modified_str = karldates(modified, 'longform') D['latest_activity_at'] = modified_str else: D['latest_activity_url'] = None D['latest_activity_link'] = None D['latest_activity_by'] = None D['latest_activity_at'] = None forum_data.append(D) return forum_data
def make_type_counter(community): path = model_path(community) def count(content_type, creation_date): n, _, _ = search(path=path, interfaces=[content_type], creation_date=creation_date) return n def count_type(content_type): return (count(content_type, (begin, end)), count(content_type, (None, end))) return count_type
def fix_wiki_links(site): """ Check wiki pages for malformed links. """ searcher = ICatalogSearch(site) total, docids, resolver = searcher(interfaces=[ IWikiPage, ], ) for docid in docids: doc = resolver(docid) changes = doc.fix_links() if changes: # log the changes path = model_path(doc) for old_link, new_link in changes: log.info("Replaced wiki link at %s: ((%s)) -> ((%s))", path, old_link, new_link)
def evolve(context): """ Remove any people directory categories set for non-Staff users. """ profiles = find_profiles(context) users = find_users(context) catalog = find_peopledirectory_catalog(context) docid_for_address = catalog.document_map.docid_for_address for profile in profiles.values(): user = users.get_by_id(profile.__name__) if user is None: continue if 'group.KarlStaff' not in user['groups']: if getattr(profile, 'categories', None): print "Removing categories for", profile.__name__ profile.categories = {} docid = docid_for_address(model_path(profile)) catalog.reindex_doc(docid, profile)
def main(args): root, closer = args.get_root(args.inst) community = find_communities(root).get(args.community) if community is None: args.parser.error('Could not find community: %s' % args.community) blog = community.get('blog') if blog is not None: if len(blog) > 0: args.parser.error('Cannot replace blog with blog entries.') else: del community['blog'] community['blog'] = blog = MailinTraceBlog() out = args.out print >> out, 'Added mailin trace tool at: %s' % model_path(blog) settings = root._p_jar.root.instance_config settings['mailin_trace_file'] = args.file print >> out, 'The mailin trace file is: %s' % args.file transaction.commit() print >> out, ('You must restart the mailin daemon in order for the new ' 'settings to take effect.')
def _fix_link_traverser(context, traversed, subpath): if not subpath: # We're done, return traversed path return '/' + '/'.join(traversed) next = subpath.pop(0) # Easy case, normal traversal if hasattr(context, '__getitem__') and next in context: traversed.append(next) return _fix_link_traverser(context[next], traversed, subpath) # Karl2 site was actually rooted at /Plone/public # Although you wouldn't normally include that in a link url, # because of acquisition you could! # If we find this or some variation at the beginning of a link # just try to skip it. skippable = ( 'Plone', 'public', ) if not traversed and next in skippable: return _fix_link_traverser(context, traversed, subpath) # An 'index_html' at the end is not necessary and skippable. # Some links inexplicably end with a '/&', which is also # skippable. skippable2 = ( 'index_html', '&', ) if next in skippable2: return _fix_link_traverser(context, traversed, subpath) # Can't find next element. Maybe it is a view if _check_view(context, next): # We can stop here, traversed path with view traversed.append(next) return '/' + '/'.join(traversed + subpath) # In Karl2 there was a content type for images that used a view # In Karl3, these are just files, so where we might have had a # view named 'image' in Karl2, we just have the 'dl' view in Karl3 if next == 'image' and _check_view(context, 'dl'): # Got the view, we can stop here traversed.append('dl') return '/' + '/'.join(traversed + subpath) # Maybe next was resolved via acquisition in Karl2 aq_context = _acquire(context, next) if aq_context: # Rewrite the leading part of this path as the model_path of the # acquired context. aq_path = model_path(aq_context) log.debug("Acquisition: rewrote path: %s -> %s", traversed, aq_path) traversed = aq_path[1:].split('/') return _fix_link_traverser(aq_context, traversed, subpath) # Next may have been processed through make_name in Karl3. Try # processing the name and see if that finds the next element. if hasattr(context, '__getitem__'): # This fix only makes sense if current node is traversable try: name = make_name({}, urllib.unquote(next)) if name in context: traversed.append(name) return _fix_link_traverser(context[name], traversed, subpath) except ValueError: # make_name will throw ValueError if there are no alphanumerics # in next pass # Some links in Karl2 are to /profile/<user> rather than # /profiles/<user>. Try changing profile to profiles and # see if that fixes the problem. if next == 'profile': subpath.insert(0, 'profiles') return _fix_link_traverser(context, traversed, subpath) # Links to /osipeople_*.html can be rewritten as just /people if next.startswith('osipeople_') and next.endswith('.html'): subpath.insert(0, 'people') return _fix_link_traverser(context, traversed, subpath) # There are some links to just /network-news and /network-events. # These are located in /offices/files if next in ('network-news', 'network-events'): subpath.insert(0, next) subpath.insert(0, 'files') subpath.insert(0, 'offices') return _fix_link_traverser(context, traversed, subpath) # Out of tricks, give up log.debug("Couldn't fix") log.debug("Traversed: %s", traversed) log.debug("Not found: %s", next) return None
def scrub(site): """ Given root, find content with HTML body, look for bad links or other errors. """ searcher = ICatalogSearch(site) total, docids, resolver = searcher(interfaces=[IContent], ) log.info("Found a total of %d documents", total) for docid in docids: doc = resolver(docid) if not hasattr(doc, 'text'): continue path = model_path(doc) log.debug("Checking %s", path) text = doc.text if not text: # Some types we're expecting not to have text, so don't warn # about those if not (ICommunity.providedBy(doc) or ICalendarEvent.providedBy(doc)): log.warn("No text: %s %s", type(doc), path) continue try: try: # Will throw ParserError if fragment doesn't have a single # root element. html = fragment_fromstring(doc.text) except ParserError: # Wrap in a single div to make the parser happy html = fragment_fromstring('<div>%s</div>' % doc.text) except XMLSyntaxError: log.error("Unparseable: %s", path, exc_info=True) # Check and fix links def callback(link): fixed = _rewrite_link(site, path, link) if fixed != link: log.info("Link rewritten at %s", path) log.info("Old link: %s", link) log.info("New link: %s", fixed) if not isinstance(fixed, unicode): fixed = unicode(fixed, 'utf-8') return fixed html.rewrite_links(callback) # Need to also change any instances of the 'mce_href' attribute to # match newly rewritten 'href' attribute. for element in html.getiterator(): if 'mce_href' in element.keys(): element.set('mce_href', element.get('href')) doc.text = unicode(lxml.html.tostring(html, 'utf-8'), 'utf-8') log.info("Done.") log.info("Unknown schemes: %s", ', '.join(unknown_schemes))
def path(self): """ Returns the path to this resource in the tree of resources. """ return model_path(self)
def get_success_url(self): return model_path(self.context)
def make_non_staff(profile, inform_moderators=True): """ When a user is removed from the KarlStaff role, their community memberships are removed. Moderators of their communities are optionally informed via email. """ id = profile.__name__ moderators = {} users = find_users(profile) profile.categories = {} for group in list(users.get_by_id(id)['groups']): if group.startswith('group.community'): # Remove user from group users.remove_user_from_group(id, group) if not inform_moderators: continue # Keep track of moderators we need to email making sure # each moderator is emailed only once and each community is # only mentioned once in any given email. community_name = group.split(':')[1] moderators_group = ('group.community:%s:moderators' % community_name) for moderator in users.users_in_group(moderators_group): if moderator == id: continue # Really should only come up in unittests if moderator not in moderators: moderators[moderator] = set() moderators[moderator].add(community_name) if not inform_moderators: return communities = find_communities(profile) profiles = profile.__parent__ mailer = getUtility(IMailDelivery) for moderator_id in moderators: moderator = profiles[moderator_id] msg = Message() msg['From'] = get_setting(profile, 'admin_email') msg['To'] = '%s <%s>' % (moderator.title, moderator.email) msg['Subject'] = 'Notice that %s is now former staff' % profile.title former_communities = sorted( [communities[c] for c in moderators[moderator_id]], key=lambda x: x.title) app_url = get_setting(profile, 'offline_app_url') communities_info = [ dict(title=c.title, unremove_url='%s%s?user_id=%s' % (app_url, model_path(c, 'members', 'add_existing.html'), id)) for c in former_communities ] body = render( 'templates/email_notify_former_staff.pt', dict(name=profile.title, communities=communities_info), ) if isinstance(body, unicode): body = body.encode('UTF-8') msg.set_payload(body, 'UTF-8') msg.set_type('text/html') mailer.send([msg['To']], msg)
def _callFUT(self, model, *elements): from pyramid.traversal import model_path return model_path(model, *elements)