def evolve(root): former_id = 'formeruser' profiles = find_profiles(root) search = ICatalogSearch(root) catalog = find_catalog(root) creators = catalog['creator']._fwd_index.keys() modifiers = catalog['modified_by']._fwd_index.keys() userids = set(creators) | set(modifiers) for userid in userids: if userid not in profiles: if former_id not in profiles: workflow = get_workflow(IProfile, 'security') former_id = make_unique_name(profiles, 'formeruser') print "Creating profile for former user content:", former_id former_profile = create_content(IProfile, firstname='Former', lastname='User') profiles[former_id] = former_profile workflow.initialize(former_profile) workflow.transition_to_state(former_profile, None, 'inactive') count, docids, resolver = search(creator=userid) for docid in docids: doc = resolver(docid) print "Updating 'creator' for", resource_path(doc) doc.creator = former_id count, docids, resolver = search(modified_by=userid) for docid in docids: doc = resolver(docid) print "Updating 'modified_by' for", resource_path(doc) doc.modified_by = former_id
def validate(self): email = self.request.POST.get('email', '').lower() self.data = {'email': email, 'date_requested': datetime.utcnow()} if not email or not EMAIL_RE.match(email): self.errors.append('Must provide valid email') if email in self.context.access_requests: self.errors.append('You have already requested access') search = ICatalogSearch(self.context) total, docids, resolver = search(email=email, interfaces=[IProfile]) if total: self.errors.append('You have already have access to system') for field in self.fields: val = self.request.POST.get(field['id'], '') if not val: self.errors.append('Must provide %s' % field['label']) else: self.data[field['id']] = val if not verify_recaptcha( self.context, self.request, self.request.POST.get('g-recaptcha-response', '')): self.errors.append('Invalid recaptcha') return len(self.errors) == 0
def evolve(context): # add default category and layer to all calendars # Prevent 'set_created' event handler from being called since it will, # in turn, set the content_modified attribute of community which is used # as the "Last Activity" in the user interface. We don't want this tweak # to impact a community's last activity. This means we need to set created # and modified on the new layers and categories ourselves. registry = getSiteManager() registry.adapters.unsubscribe((IContent, IObjectWillBeAddedEvent), None, set_created) try: search = ICatalogSearch(context) default_category_name = ICalendarCategory.getTaggedValue( 'default_name') default_layer_name = ICalendarLayer.getTaggedValue('default_name') now = datetime.now() cnt, docids, resolver = search(interfaces=[ICalendar]) for docid in docids: calendar = resolver(docid) default_category = create_content(ICalendarCategory, 'Default') default_category.created = default_category.modified = now if not default_category_name in calendar: calendar[default_category_name] = default_category local_layer = create_content(ICalendarLayer, "This Calendar's Events Only", 'blue', [resource_path(default_category)]) local_layer.created = local_layer.modified = now if not default_layer_name in calendar: calendar[default_layer_name] = local_layer finally: registry.adapters.subscribe((IContent, IObjectWillBeAddedEvent), None, set_created)
def evolve(root): catalog = find_catalog(root) mimetype_index = catalog['mimetype'] search = ICatalogSearch(root) docid_for_addr = catalog.document_map.docid_for_address count, docids, resolver = search(interfaces=[ICommunityFile], mimetype={ 'operator': 'or', 'query': [ 'application/x-download', 'application/x-application', 'application/binary', 'application/octet-stream', ] }) for docid in docids: doc = resolver(docid) mimetype = mimetypes.guess_type(doc.filename)[0] if mimetype is not None and mimetype != doc.mimetype: addr = resource_path(doc) print "Updating mimetype for %s: %s" % (addr, mimetype) doc.mimetype = mimetype mimetype_index.reindex_doc(docid_for_addr(addr), doc)
def collect_profile_metrics(context, year, month): result = {} search = ICatalogSearch(context) begin, end = date_range(year, month) users = find_users(context) staff_set = users.users_in_group('group.KarlStaff') _, docids, resolver = search( creation_date=(None, end), interfaces=[IProfile], ) for profile in (resolver(docid) for docid in docids): userid = profile.__name__ created_count, _, _ = search(creation_date=(begin, end), creator=userid) total_count, _, _ = search(creation_date=(None, end), creator=userid) is_staff = userid in staff_set result[userid] = dict( total=total_count, created=created_count, is_staff=is_staff, ) return result
def member_search_json_view(context, request): try: # Query parameter shall be 'term'. prefix = request.params['term'] except UnicodeDecodeError: # not utf8, just return empty list since tags can't have these chars result = JSONEncoder().encode([]) return Response(result, content_type="application/x-json") # case insensitive prefix = prefix.lower() community = find_interface(context, ICommunity) member_names = community.member_names moderator_names = community.moderator_names community_member_names = member_names.union(moderator_names) query = dict( member_name='%s*' % prefix, sort_index='title', limit=20, ) searcher = ICatalogSearch(context) try: total, docids, resolver = searcher(**query) profiles = filter(None, map(resolver, docids)) records = [ dict( value=profile.__name__, label=profile.title, ) for profile in profiles if profile.__name__ not in community_member_names and profile.security_state != 'inactive' ] except ParseError: records = [] result = JSONEncoder().encode(records) return Response(result, content_type="application/x-json")
def create_access_request(self): email = self.data.get('email') system_name = get_setting(self.context, 'title') self.context.access_requests[email] = self.data mailer = getUtility(IMailDelivery) message = MIMEMultipart('alternative') message['Subject'] = '%s Access Request(%s)' % ( system_name, self.data.get('fullname')) message['From'] = get_setting(self.context, 'admin_email') bodyhtml = u'''<html><body> <p>New access request has been submitted for the site %s</p> <p><b>Email</b>: %s <br /> %s </p> </body></html>''' % (self.request.application_url, email, '<br />'.join([ _email_field_tmp % (f['label'], self.data.get(f['id'], '')) for f in self.fields ])) bodyplain = html2text.html2text(bodyhtml) htmlpart = MIMEText(bodyhtml.encode('UTF-8'), 'html', 'UTF-8') plainpart = MIMEText(bodyplain.encode('UTF-8'), 'plain', 'UTF-8') message.attach(plainpart) message.attach(htmlpart) # First, send mail to all admins users = find_users(self.context) search = ICatalogSearch(self.context) count, docids, resolver = search(interfaces=[IProfile]) for docid in docids: profile = resolver(docid) if getattr(profile, 'security_state', None) == 'inactive': continue userid = profile.__name__ if not users.member_of_group(userid, 'group.KarlAdmin'): continue copyofmsg = copy.deepcopy(message) fullemail = '%s <%s>' % (profile.title, profile.email) copyofmsg['To'] = fullemail mailer.send([profile.email], copyofmsg) # next, send to person that submitted message = MIMEMultipart('alternative') message['Subject'] = 'Access Request to %s' % system_name message['From'] = get_setting(self.context, 'admin_email') user_message = get_setting( self.context, 'request_access_user_message', '') % (SafeDict( self.data, {'system_name': system_name})) bodyhtml = u'<html><body>%s</body></html>' % user_message bodyplain = html2text.html2text(bodyhtml) htmlpart = MIMEText(bodyhtml.encode('UTF-8'), 'html', 'UTF-8') plainpart = MIMEText(bodyplain.encode('UTF-8'), 'plain', 'UTF-8') message.attach(plainpart) message.attach(htmlpart) copyofmsg = copy.deepcopy(message) fullemail = '%s <%s>' % (self.data.get('fullname', ''), email) copyofmsg['To'] = fullemail mailer.send([email], copyofmsg) self.submitted = True self.errors.append('Successfully requested access')
def jquery_member_search_view(context, request): prefix = request.params['val'].lower() community = find_interface(context, ICommunity) member_names = community.member_names moderator_names = community.moderator_names community_member_names = member_names.union(moderator_names) query = dict( member_name='%s*' % prefix, sort_index='title', limit=20, ) searcher = ICatalogSearch(context) try: total, docids, resolver = searcher(**query) profiles = filter(None, map(resolver, docids)) records = [ dict( id=profile.__name__, text=profile.title, ) for profile in profiles if profile.__name__ not in community_member_names and profile.security_state != 'inactive' ] except ParseError: records = [] result = JSONEncoder().encode(records) return Response(result, content_type="application/x-json")
def evolve(context): """ Upgrades required for new Image Drawer functionality. """ # Add IImage marker to instances of ICommunityFile which are images. catalog = find_catalog(context) search = ICatalogSearch(context) cnt, docids, resolver = search(interfaces=[ICommunityFile]) for docid in docids: obj = resolver(docid) if obj is None: continue # Work around catalog bug obj._init_image() if obj.is_image: print "Image: %s" % resource_path(obj) catalog.reindex_doc(obj.docid, obj) # Convert WikiPages to Folders so they can contain attachments cnt, docids, resolver = search(interfaces=[IWikiPage]) for docid in docids: obj = resolver(docid) if obj is None: continue # Work around catalog bug print "Convert wiki page to folder: %s" % resource_path(obj) Folder.__init__(obj) catalog.reindex_doc(obj.docid, obj)
def get_members_batch(community, request, size=10): mods = list(community.moderator_names) any = list(community.member_names | community.moderator_names) principals = effective_principals(request) searcher = ICatalogSearch(community) total, docids, resolver = searcher( interfaces=[IProfile], limit=size, name={ 'query': any, 'operator': 'or' }, allowed={ 'query': principals, 'operator': 'or' }, ) mod_entries = [] other_entries = [] for docid in docids: model = resolver(docid) if model is not None: if model.__name__ in mods: mod_entries.append(model) else: other_entries.append(model) return (mod_entries + other_entries)[:size]
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(root): former_id = None # Create lazily, in case we don't need it profiles = find_profiles(root) search = ICatalogSearch(root) catalog = find_catalog(root) creators = catalog['creator']._fwd_index.keys() modifiers = catalog['modified_by']._fwd_index.keys() userids = set(creators) | set(modifiers) for userid in userids: if userid not in profiles: if former_id is None: former_id = make_unique_name(profiles, 'formeruser') print "Creating profile for former user content:", former_id former_profile = create_content(IProfile, firstname='Former', lastname='User') profiles[former_id] = former_profile count, docids, resolver = search(creator=userid) for docid in docids: doc = resolver(docid) print "Updating 'creator' for", resource_path(doc) doc.creator = former_id count, docids, resolver = search(modified_by=userid) for docid in docids: doc = resolver(docid) print "Updating 'modified_by' for", resource_path(doc) doc.modified_by = former_id
def show_profiles_view(context, request): system_name = get_setting(context, 'system_name', 'KARL') page_title = '%s Profiles' % system_name api = TemplateAPI(context, request, page_title) # Grab the data for the two listings, main communities and portlet search = ICatalogSearch(context) query = dict(sort_index='title', interfaces=[IProfile], limit=5) titlestartswith = request.params.get('titlestartswith') if titlestartswith: query['titlestartswith'] = (titlestartswith, titlestartswith) num, docids, resolver = search(**query) profiles = [] for docid in docids: model = resolver(docid) if model is None: continue profiles.append(model) mgr = ILetterManager(context) letter_info = mgr.get_info(request) return render_to_response( 'templates/profiles.pt', dict(api=api, profiles=profiles, letters=letter_info), request=request, )
def related_communities_ajax_view(context, request): assert ICommunity.providedBy(context), str(type(context)) related = [] principals = effective_principals(request) searcher = ICatalogSearch(context) search = ' OR '.join(context.title.lower().split()) total, docids, resolver = searcher( interfaces=[ICommunity], limit=5, reverse=True, sort_index="modified_date", texts=search, allowed={ 'query': principals, 'operator': 'or' }, ) for docid in docids: model = resolver(docid) if model is not None: if model is not context: adapted = getMultiAdapter((model, request), IGridEntryInfo) related.append(adapted) return {'items': related}
def debugsearch(context, **kw): searcher = ICatalogSearch(context) kw['use_cache'] = False num, docids, resolver = searcher(**kw) L = [] for docid in docids: L.append(resolver(docid)) return num, L
def _iter_userids(context, request, profile_text): """Yield userids given a profile text search string.""" search = ICatalogSearch(context) num, docids, resolver = search(interfaces=[IProfile], texts=profile_text) for docid in docids: profile = resolver(docid) if profile: yield profile.__name__
def number_of_comments(forum, request): searcher = ICatalogSearch(forum) total, docids, resolver = searcher( interfaces=[IComment], path={'query': resource_path(forum)}, allowed={'query': effective_principals(request), 'operator': 'or'}, ) return total
def _reportAddresses(self, report): query = report.getQuery() searcher = ICatalogSearch(report) total, docids, resolver = searcher(**query) for docid in docids: profile = resolver(docid) if profile is not None: yield profile.email
def _reportAddresses(self, report): query = report.getQuery() searcher = ICatalogSearch(report) total, docids, resolver = searcher(**query) for docid in docids: profile = resolver(docid) security_state = getattr(profile, 'security_state') if profile is not None and security_state != 'inactive': yield profile.email
def get_catalog_batch(context, request, **kw): batch_start = kw.pop('batch_start', 0) batch_start = int(request.params.get("batch_start", batch_start)) batch_size = kw.pop('batch_size', 20) batch_size = int( request.params.get("batch_size", request.params.get('limit', batch_size))) sort_index = kw.pop('sort_index', None) sort_index = request.params.get('sort_index', sort_index) reverse = kw.pop('reverse', False) reverse = bool(int(request.params.get('reverse', reverse))) # XXX Asserting a default 'modified' sort order here is # fragrant. It's unclear which callers depend on the behavior # and which don't. Most callers probably don't even know we # do this. We should make this each caller's responsibility # instead of embedding this policy here. if sort_index is None: sort_index = 'modified_date' kw['sort_index'] = sort_index # the reverse parameter is only useful when there's a sort index kw['reverse'] = reverse # Adding a limit will cause some indexes to use an NBEST sort # which is dramatically faster than sorting an entire large result set. kw['limit'] = batch_start + batch_size searcher = ICatalogSearch(context) numdocs, docids, resolver = searcher(**kw) # Use of indirection here is to avoid having to rewrite 70 tests to # use repoze.catalog.catalog.ResultSetSize instead of int total = getattr(numdocs, 'total', numdocs) if total < batch_start: batch_start = total # Lazily slice a lazy generator for getting models from result set docs = (model for model in (resolver(docid) for docid in docids) if model is not None) batch = list(islice(docs, batch_start, batch_start + batch_size)) batch_end = batch_start + len(batch) info = { 'entries': batch, 'batch_start': batch_start, 'batch_size': batch_size, 'batch_end': batch_end, 'total': getattr(numdocs, 'total', numdocs), 'sort_index': sort_index, 'reverse': reverse, } _add_link_data(info, context, request) return info
def evolve(root): search = ICatalogSearch(root) catalog = find_catalog(root) index = catalog['mimetype'] for old_type, new_type in ie_types.items(): cnt, docids, resolver = search(mimetype=old_type) for docid in docids: doc = resolver(docid) print "Adjusting mimetype for %s" % resource_path(doc) doc.mimetype = new_type index.reindex_doc(docid, doc)
def evolve(site): """Convert profile's '_pending_alerts' to an Accumulator. """ catalog = find_catalog(site) search = ICatalogSearch(site) count, docids, resolver = search( interfaces={'query': [IProfile]}) for docid in docids: doc = resolver(docid) alerts = doc._pending_alerts if not isinstance(alerts, Accumulator): doc._pending_alerts = Accumulator(list(alerts))
def evolve(site): print "Updating acl for /" update_acl(site) catalog = find_catalog(site) search = ICatalogSearch(site) cnt, docids, resolver = search(interfaces=[ICommunity]) for docid in docids: obj = resolver(docid) if obj is None: continue # Work around catalog bug print "Updating acl for %s" % resource_path(obj) update_acl(obj)
def _get_valid_login(context, users, login): """ could be username or email """ user = users.get(login=login) if user: return user # now try to see if email search = ICatalogSearch(context) count, docids, resolver = search(interfaces=[IProfile], email=login.lower()) if count == 1: profile = resolver(docids[0]) if profile.security_state != 'inactive': return users.get(userid=profile.__name__)
def evolve(root): search = ICatalogSearch(root) num, docids, resolver = search(interfaces=[IProfile]) allowed_index = find_catalog(root)['allowed'] for docid in docids: profile = resolver(docid) if profile.security_state != 'inactive': continue print "Updating acl for %s" % resource_path(profile) workflow = get_workflow(IProfile, 'security', profile) workflow.reset(profile) allowed_index.reindex_doc(docid, profile)
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 latest_object(forum, request): searcher = ICatalogSearch(forum) total, docids, resolver = searcher( sort_index='modified_date', interfaces={'query': [IForumTopic, IComment], 'operator':'or'}, path={'query': resource_path(forum)}, allowed={'query': effective_principals(request), 'operator': 'or'}, reverse=True) docids = list(docids) if docids: return resolver(docids[0]) else: return None
def evolve(site): """ Add the IPhoto marker interface to profile and news item photos. """ catalog = find_catalog(site) search = ICatalogSearch(site) count, docids, resolver = search( interfaces={'operator': 'or', 'query': [INewsItem, IProfile]}) for docid in docids: doc = resolver(docid) photo = doc.get('photo') if photo is not None and not IPhoto.providedBy(photo): alsoProvides(photo, IPhoto) catalog.reindex_doc(photo.docid, photo)
def archive_to_box_view(context, request): """ Archive inactive communities to the Box storage service. """ api = AdminTemplateAPI(context, request, 'Admin UI: Archive to Box') communities = None box = find_box(context) client = BoxClient(box, request.registry.settings) logged_in = False state = request.params.get('state', None) if state: if state == box.state: client.authorize(request.params['code']) else: raise HTTPBadRequest("Box state does not match") state = box.state = None #return HTTPFound(request.path_url) if box.logged_in: logged_in = True # Find inactive communities search = ICatalogSearch(context) now = datetime.datetime.now() timeago = now - datetime.timedelta(days=425) # ~14 months count, docids, resolver = search( interfaces=[ICommunity], content_modified=(None, coarse_datetime_repr(timeago))) communities = [{ 'title': community.title, 'url': request.resource_url(community), 'path': resource_path(community) } for community in (resolver(docid) for docid in docids)] communities.sort(key=itemgetter('path')) if not box.logged_in: state = box.state = str(uuid.uuid4()) return { 'api': api, 'menu': _menu_macro(), 'communities': communities, 'logged_in': logged_in, 'state': state, 'client_id': client.client_id, 'authorize_url': client.authorize_url, 'redirect_uri': request.path_url, }
def verified_email_user_finder(site, context): email = context.profile.get('verifiedEmail') if not email: return None search = ICatalogSearch(site) count, docids, resolver = search(interfaces=[IProfile], email=email) if not count: return None if count > 1: log.warn('Unable to authenticate ambiguous email address: %s' % email) return None profile = resolver(docids[0]) users = find_users(site) return users.get(profile.__name__)