def parse_query(query): result = [] for name, value in query.items(): if name in ('Type', 'portal_type'): new_value = [] if type(value) not in (list, tuple): value = [value] for v in value: if v in _type_name_mapping: new_value.append(_type_name_mapping[v]) value = new_value if IImage in value: result.append(Any('mimetype', _image_mimetypes)) query = Any('interfaces', value) elif name == 'path': split = value.split('::') if len(split) == 2: path = split[0] depth = split[1] else: path = value depth = 1 query = Eq(name, { 'query': path, 'depth': int(depth) }) elif name in _index_mapping: name = _index_mapping[name] query = Eq(name, value) else: query = Eq(name, value) result.append(query) return result
def query2(self, soup): # fetch user vendor uids vendor_uids = get_vendor_uids_for() # filter by given vendor uid or user vendor uids vendor_uid = self.request.form.get('vendor') if vendor_uid: vendor_uid = uuid.UUID(vendor_uid) # raise if given vendor uid not in user vendor uids if vendor_uid not in vendor_uids: raise Unauthorized query = Any('vendor_uids', [vendor_uid]) else: query = Any('vendor_uids', vendor_uids) # filter by customer if given customer = self.request.form.get('customer') if customer: query = query & Eq('creator', customer) # filter by search term if given term = self.request.form['sSearch'].decode('utf-8') if term: query = query & Contains(self.search_text_index, term) # query orders and return result sort = self.sort() res = soup.lazy(query, sort_index=sort['index'], reverse=sort['reverse'], with_size=True) length = res.next() return length, res
def get_tag_count(self, tag): """ Returns total count for a tag withing the context this view was registered on. """ try: return self.tag_count[tag] except KeyError: query = Eq('path', resource_path(self.context)) &\ Any('allowed_to_view', self.cached_effective_principals) &\ Any('tags', tag) self.tag_count[tag] = self.root.catalog.query(query)[0] return self.tag_count[tag]
def query(self, soup): soup.reindex() # fetch user vendor uids vendor_uids = get_vendor_uids_for() # filter by given vendor uid or user vendor uids vendor_uid = self.request.form.get('vendor') if vendor_uid: vendor_uid = uuid.UUID(vendor_uid) # raise if given vendor uid not in user vendor uids if vendor_uid not in vendor_uids: raise Unauthorized query = Any('vendor_uid', [vendor_uid]) else: query = Any('vendor_uid', vendor_uids) # filter by customer if given customer = self.request.form.get('customer') if customer: query = query & Eq('creator', customer) # filter by search term if given term = self.request.form['sSearch'].decode('utf-8') if term: query = query & Contains(self.search_text_index, term) # Show only tickets that are paid query = query & Eq('salaried', 'yes') if not IPloneSiteRoot.providedBy(self.context): buyable_uids = self._get_buyables_in_context() query = query & Any('buyable_uids', buyable_uids) # query orders and return result sort = self.sort() try: res = soup.lazy(query, sort_index=sort['index'], reverse=sort['reverse'], with_size=True) length = res.next() except: length = 0 pass return length, res
def query(self, soup): # fetch user vendor uids vendor_uids = get_vendor_uids_for() # filter by given vendor uid or user vendor uids vendor_uid = self.request.form.get('vendor') if vendor_uid: vendor_uid = uuid.UUID(vendor_uid) # raise if given vendor uid not in user vendor uids if vendor_uid not in vendor_uids: raise Unauthorized query = Any('vendor_uids', [vendor_uid]) else: query = Any('vendor_uids', vendor_uids) # filter by customer if given customer = self.request.form.get('customer') if customer: query = query & Eq('creator', customer) # Filter by state if given state = self.request.form.get('state') if state: query = query & Eq('state', state) # Filter by salaried if given salaried = self.request.form.get('salaried') if salaried: query = query & Eq('salaried', salaried) # filter by search term if given term = self.request.form['sSearch'].decode('utf-8') if term: # append * for proper fulltext search term += '*' query = query & Contains(self.search_text_index, term) # get buyable uids for given context, get all buyables on site root # use explicit IPloneSiteRoot to make it play nice with lineage if not IPloneSiteRoot.providedBy(self.context): buyable_uids = self._get_buyables_in_context() query = query & Any('buyable_uids', buyable_uids) # query orders and return result sort = self.sort() res = soup.lazy(query, sort_index=sort['index'], reverse=sort['reverse'], with_size=True) length = res.next() return length, res
def evolve(root): from repoze.catalog.query import Any from repoze.catalog.query import Contains from repoze.catalog.query import Eq from pyramid.traversal import resource_path from voteit.core.models.catalog import reindex_object from voteit.core.models.catalog import resolve_catalog_docid print "Removing absolute urls in profile links" catalog = root.catalog host = None while not host: host = raw_input( "Enter a host to replace (ex http://127.0.0.1:6543): ") count, result = catalog.query(Eq('path', resource_path(root)) & \ Contains('searchable_text', 'class="inlineinfo"') & \ Any('content_type', ('DiscussionPost', 'Proposal', ))) catalog = root.catalog print "Processing %s objects" % count for docid in result: # get object obj = resolve_catalog_docid(catalog, root, docid) obj.title = obj.title.replace(host, '') reindex_object(catalog, obj)
def agenda_data_json(context, request): if not request.is_participant: return {} query = Eq('path', resource_path(context)) & Eq('type_name', 'AgendaItem') # Sanitize to avoid exceptions? state = request.POST.get('state') if state not in _OPEN_STATES and not request.is_moderator: raise HTTPForbidden('State query not allowed') tag = request.session.get('voteit.ai_selected_tag', '') if tag and tag in request.meeting.tags: query &= Any('tags', [tag.lower()]) results = [] hide_type_count = request.session.get('voteit.agenda.hide_type_count', False) if state: query &= Eq('workflow_state', state) count, docids = request.root.catalog.query(query) for ai in request.resolve_docids(docids, perm=None): ai_res = {'title': ai.title, 'name': ai.__name__} if not hide_type_count: ai_res['contents'] = count_types(request, ai) if state is None: ai_res['state'] = ai.get_workflow_state() results.append(ai_res) return {'ais': results, 'hide_type_count': hide_type_count}
def day_entries(request, context, day=None, userid=_marker): """ :param request: :param context: Fetch everything within this contexts path (may be root) :param group: Group entries together within tasks :param day: Limit within this day :type day: date :param userid: User to fetch for. None means all :return: OrderedDict with Task uid as key and time entry objects in a list as value. """ if userid == _marker: userid = request.authenticated_userid #FIXME: Fetch exactly one day and all entries for that day. Sort according to Tasks #min_created = utcnow() - timedelta(days=days) query = Eq('path', resource_path(context)) &\ Eq('type_name', 'TimeEntry') # Gt('created', timegm(min_created.timetuple())) if userid: query &= Any('creator', [userid]) docids = request.root.catalog.query(query, sort_index='created', reverse=True)[1] results = OrderedDict() for obj in request.resolve_docids(docids): items = results.setdefault(obj.__parent__.uid, []) items.append(obj) return results
def get_proposal_objects(self): """ Return proposal objects relevant to this poll. Will sort them in specified order. """ agenda_item = self.__parent__ if agenda_item is None: raise ValueError("Can't find any agenda item in the polls lineage") query = Any('uid', tuple(self.proposal_uids)) & Eq( 'type_name', 'Proposal') root = find_root(agenda_item) results = [] for docid in root.catalog.query(query)[1]: path = root.document_map.address_for_docid(docid) obj = find_resource(root, path) # Permission check shouldn't be needed at this point if obj: results.append(obj) if self.proposal_order: proposal_order = self.proposal_order else: meeting = find_interface(self, IMeeting) # During tests, we might not have a real meeting here :) proposal_order = getattr(meeting, 'poll_proposals_default_order', '') key_method = PROPOSAL_ORDER_KEY_METHODS.get( proposal_order, PROPOSAL_ORDER_KEY_METHODS[PROPOSAL_ORDER_DEFAULT]) return sorted(results, key=key_method)
def count_tags(self, context, request, base_tag, num): results = {} query = Eq('path', resource_path(context)) & Eq('type_name', 'Proposal') query &= NotAny('workflow_state', ['retracted', 'unhandled']) cquery = request.root.catalog.query for i in range(1, num+1): tag = "%s-%s" % (base_tag, i) res = cquery(query & Any('tags', [tag]))[0] results[tag] = res.total return results
def __call__(self): response = {} query = Eq('path', resource_path(self.context)) & \ Eq('type_name', 'Proposal') tags = self.request.GET.getall('tag') if tags: tags = [x.lower() for x in tags] query &= Any('tags', tags) hide = self.request.params.getall('hide') load_hidden = self.request.params.get('load_hidden', False) if load_hidden: # Only load data previously hidden if hide: query &= Any('workflow_state', hide) else: invert_hidden = copy(query) # Normal operation, keep count of hidden if hide: invert_hidden &= Any('workflow_state', hide) query &= NotAny('workflow_state', hide) response['docids'] = tuple( self.catalog_query(query, sort_index='created')) read_names = self.request.get_read_names(self.context) unread_query = query & NotAny( '__name__', set(read_names.get(self.request.authenticated_userid, []))) response['unread_docids'] = tuple( self.catalog_query(unread_query, sort_index='created')) response['contents'] = self.resolve_docids( response['docids']) # A generator if not load_hidden: response['hidden_count'] = self.request.root.catalog.query( invert_hidden)[0].total get_query = {'tag': tags, 'load_hidden': 1, 'hide': hide} response['load_hidden_url'] = self.request.resource_url( self.context, self.request.view_name, query=get_query) else: response['hidden_count'] = False # A more expensive but accurate permission check for a specific object. response['ck_mod'] = lambda obj: self.request.has_permission( security.MODERATE_MEETING, obj) return response
def update_cached_len(self, userid): read_names = self.request.redis_conn.smembers(self.get_key(userid)) base_query = self.path_query & Any('__name__', read_names) for type_name in self.track_types: res = self.request.root.catalog.query( base_query & Eq('type_name', type_name))[0] old_len = self.get_read_type(type_name, userid) self.request.redis_conn.set(self.get_len_key(type_name, userid), res.total) changed = res.total - old_len self.rnc.change(type_name, changed, userid)
def booking(self): if self._booking: return self._booking soup = self.bookings_soup query = Eq('uid', self.uid) if self.vendor_uids: query = query & Any('vendor_uid', self.vendor_uids) result = soup.query(query, with_size=True) if result.next() != 1: # first result is length return None self._booking = result.next() return self._booking
def tag_stats(context, request, *args, **kwargs): api = kwargs['api'] if not api.meeting: return "" query = Eq('path', resource_path(context)) &\ Any('allowed_to_view', effective_principals(request)) &\ Any('content_type', ('Proposal', 'DiscussionPost',)) num, docids = api.root.catalog.query(query) unique_tags = set() #FIXME: There must be a smarter way to load uniques!? for docid in docids: entry = api.root.catalog.document_map.get_metadata(docid) unique_tags.update(entry['tags']) results = [] for tag in unique_tags: count = api.get_tag_count(tag) if count > 1: results.append((tag, count)) if not results: return u"" #Sort the tags based on occurence and show the top 5 results = sorted(results, key=lambda x: x[1], reverse=True)[:5] def _make_url(tag): query = request.GET.copy() query['tag'] = tag return request.resource_url(context, query=query) response = dict( api=api, context=context, stats=results, make_url=_make_url, ) return render('templates/tag_stats.pt', response, request=request)
def change_mentions(root, userid, userid_lower): catalog = root.catalog result = catalog.query(Eq('path', resource_path(root)) & \ Contains('searchable_text', userid) & \ Any('content_type', ('DiscussionPost', 'Proposal', )))[1] for docid in result: # get object obj = resolve_catalog_docid(catalog, root, docid) title = obj.title for match in re.finditer('<a class="inlineinfo" href="http:\/\/[\da-z.-:]*/[\w-]*/_userinfo\?userid=('+userid+')" title="[\w\s-]*">@('+userid+')</a>', title, re.UNICODE): title = title[0:match.start(1)] + userid_lower + title[match.end(1):len(title)] # replace in url title = title[0:match.start(2)] + userid_lower + title[match.end(2):len(title)] # replace in text obj.title = title
def get_vendor_order_uids_for(context, user=None): """Get order uids all orders a given or current user has vendor permissions for. :param user: Optional user object to check permissions on vendor areas. If no user object is give, the current user is used. :type user: MemberData object :returns: List of order UUID objects. :rtype: List of uuid.UUID """ vendors = get_vendor_uids_for(user=user) soup = get_bookings_soup(context) res = soup.query(Any('vendor_uid', vendors)) order_uids = set(booking.attrs['order_uid'] for booking in res) return order_uids
def sum_time(request, context, userid=_marker): """ Build a dict with time summary """ query = Eq('path', resource_path(context)) & Eq('type_name', 'TimeEntry') if userid == _marker: userid = request.authenticated_userid if userid: query &= Any('creator', [userid]) docids = request.root.catalog.query(query)[1] results = {} for obj in request.resolve_docids(docids, perm=None): if obj.stop_time: creator = obj.creator[0] if creator not in results: results[creator] = timedelta() results[creator] += obj.timedelta return results
def _mk_query(self): self.docids = () query = self.request.GET.get('query', None) if not query: return if self.request.GET.get('glob', False): if '*' not in query: query = "%s*" % query query_obj = Contains('searchable_text', query) & Eq( 'search_visible', True) type_name = self.request.GET.getall('type_name') if type_name: query_obj &= Any('type_name', type_name) try: self.docids = self.root.catalog.query(query_obj)[1] except ParseError: if not self.request.is_xhr: msg = _(u"Invalid search query - try something else!") self.flash_messages.add(msg, type="danger")
def parse_query_params(self, query): if not query: return [] queries = [] for index, value in query.items(): if not value or value in ["*", "**"]: continue if index not in self.indexes: continue if six.PY2: value = value.decode("utf-8") if index == self.text_index: queries.append(Contains("text", value)) elif index in self.keyword_indexes: queries.append(Any(index, value)) else: queries.append(Eq(index, value)) if not queries: return None return And(*queries)
def __call__(self): path = resource_path(self.context) query = Eq('path', path) & Eq('type_name', 'Poll') & Any( 'workflow_state', ('private', 'upcoming')) docids = self.request.root.catalog.query(query)[1] polls = tuple(self.request.resolve_docids( docids, perm=security.EDIT)) #Must be able to modify poll query = Eq('path', path) & Eq('type_name', 'Proposal') only_uid = self.request.GET.get('uid', None) if only_uid: query &= Eq('uid', only_uid) docids = self.request.root.catalog.query(query)[1] proposals = tuple(self.request.resolve_docids(docids)) response = {} for proposal in proposals: values = {'context': proposal, 'polls': polls} response[proposal.uid] = render( 'voteit.core:templates/snippets/pick_polls.pt', values, request=self.request) return response
def agenda_states(context, request, va, **kw): states = ['ongoing', 'upcoming', 'closed'] if request.is_moderator: states.append('private') tag = request.session.get('voteit.ai_selected_tag', '') if tag in context.tags: tag = tag.lower() else: tag = None results = {} query = Eq('path', kw['meeting_path']) & Eq('type_name', 'AgendaItem') for state in states: squery = query & Eq('workflow_state', state) res, docids = request.root.catalog.query(squery) results[state] = { 'hash': hash(tuple(docids)), 'count': res.total and str(res.total) or '', } if tag and res.total: tagres = request.root.catalog.query(squery & Any('tags', [tag]))[0] results[state]['count'] = "%s / %s" % (tagres.total, res.total) return results
def poll_listing(context, request, va, **kw): """ This is a view of a poll when it's displayed within an agenda item. It's not the listing for when a user votes. """ api = kw['api'] #The poll query doesn't have to care about path and such since we already have the uids query = Any('uid', context.proposal_uids) get_metadata = api.root.catalog.document_map.get_metadata count, docids = api.root.catalog.query(query, sort_index='created') results = [] for docid in docids: results.append(get_metadata(docid)) response = {} response['proposals'] = tuple(results) response['api'] = api response['poll_plugin'] = context.get_poll_plugin() response['can_vote'] = api.context_has_permission(security.ADD_VOTE, context) response['has_voted'] = api.userid in context response['wf_state'] = wf_state = context.get_workflow_state() response[ 'context'] = context #make sure context within the template is this context and nothing else if wf_state in ('ongoing', 'closed'): response['voted_count'] = len(context.get_voted_userids()) if wf_state == 'ongoing': response['voters_count'] = len( security.find_authorized_userids(context, [security.ADD_VOTE])) else: response['voters_count'] = len(context.voters_mark_closed) try: response['voted_percentage'] = round( 100 * float(response['voted_count']) / float(response['voters_count']), 1) except ZeroDivisionError: response['voted_percentage'] = 0 return render('templates/polls/poll.pt', response, request=request)
def proposal_response(context, request, va, **kw): """ Prepair a response dict for the proposal view. """ api = kw['api'] #Start with checking which polls that exist in this context and store shown uids shown_uids = set() polls = [] for poll in api.get_restricted_content(context, iface=IPoll, sort_on='created'): try: plugin = poll.get_poll_plugin() except ComponentLookupError: err_msg = _( u"plugin_missing_error", default= u"Can't find any poll plugin with name '${name}'. Perhaps that package has been uninstalled?", mapping={'name': poll.get_field_value('poll_plugin')}) api.flash_messages.add(err_msg, type="error") continue shown_uids.update(poll.proposal_uids) polls.append(poll) #The agenda item query must be based on the context and to exclude all already shown #This view also cares about retracted proposals where as poll version doesn't query = Eq('path', resource_path(context)) &\ Eq('content_type', 'Proposal') &\ NotAny('uid', shown_uids) hide_retracted = api.meeting.get_field_value('hide_retracted', False) hide_unhandled = api.meeting.get_field_value('hide_unhandled_proposals', False) hidden_states = [] if hide_retracted: hidden_states.append('retracted') if hide_unhandled: hidden_states.append('unhandled') if hidden_states: query &= NotAny('workflow_state', hidden_states) tag = request.GET.get('tag', None) if tag: #Only apply tag limit for things that aren't polls. #This is a safegard against user errors query &= Any('tags', (tag, )) # build query string and remove tag clear_tag_query = request.GET.copy() if 'tag' in clear_tag_query: del clear_tag_query['tag'] count, docids = api.root.catalog.query(query, sort_index='created') get_metadata = api.root.catalog.document_map.get_metadata results = [get_metadata(x) for x in docids] hidden_proposals = [] if hidden_states: query = Eq('path', resource_path(context)) &\ Eq('content_type', 'Proposal') &\ NotAny('uid', shown_uids) &\ Any('workflow_state', hidden_states) if tag: query &= Any('tags', (tag, )) count, docids = api.root.catalog.query(query, sort_index='created') hidden_proposals = [get_metadata(x) for x in docids] response = {} response['clear_tag_url'] = request.resource_url(context, query=clear_tag_query) response['proposals'] = tuple(results) response['hidden_proposals'] = tuple(hidden_proposals) response['tag'] = tag response['api'] = api response['polls'] = polls return response
def test_negate(self): from repoze.catalog.query import Any inst = self._makeOne('index', 'val') self.assertEqual(inst.negate(), Any('index', 'val'))
from repoze.catalog.query import Contains from repoze.catalog.query import Name from betahaus.pyracont.factories import createSchema from zope.index.text.parsetree import ParseError from voteit.core.views.base_view import BaseView from voteit.core.models.interfaces import IMeeting from voteit.core.models.schemas import button_search from voteit.core.security import VIEW from voteit.core.helpers import strip_and_truncate from voteit.core import VoteITMF as _ SEARCH_VIEW_QUERY = Eq('path', Name('path')) \ & Contains('searchable_text', Name('searchable_text')) \ & Any('content_type', ('DiscussionPost', 'Proposal', 'AgendaItem' )) \ & Any('allowed_to_view', Name('allowed_to_view')) class SearchView(BaseView): """ Handle incoming search query and display result. """ @view_config(context=IMeeting, name="search", renderer="templates/search.pt", permission = VIEW) def search(self): schema = createSchema('SearchSchema').bind(context = self.context, request = self.request) form = Form(schema, buttons=(button_search,)) self.api.register_form_resources(form) appstruct = {} self.response['results'] = [] def _results_ts(count):
def vocabulary_view(context, request): try: attributes = json.loads(request.params.get('attributes', '["title", "id"]')) except: attributes = ['title', 'id'] if 'UID' in attributes: # always put in anyways attributes.remove('UID') try: batch = json.loads(request.params.get('batch')) except: batch = DEFAULT_BATCH query = normalize_query(json.loads(request.params['query'])) criteria = parse_query(query) resolver = ResovlerFactory(context) if 'UID' in query: docids = query['UID'] if type(docids) not in (list, tuple): docids = [docids] # convert to ints new_docids = [] for docid in docids: try: new_docids.append(int(docid)) except: pass docids = new_docids numdocs = len(docids) else: criteria.append(Any('allowed', effective_principals(request))) if 'title' not in query: # we default to requiring a title in these results or # else we get a bunch of junky results criteria.append(NotEq('title', '')) catalog = find_catalog(context) numdocs, docids = catalog.query(And(*criteria)) if batch and ('size' not in batch or 'page' not in batch): batch = DEFAULT_BATCH if batch: # must be slicable for batching support page = int(batch['page']) # page is being passed in is 1-based start = (max(page - 1, 0)) * int(batch['size']) end = start + int(batch['size']) # Try __getitem__-based slice, then iterator slice. # The iterator slice has to consume the iterator through # to the desired slice, but that shouldn't be the end # of the world because at some point the user will hopefully # give up scrolling and search instead. try: docids = docids[start:end] except TypeError: docids = itertools.islice(docids, start, end) # build result items items = [] for docid in docids: result = resolver(docid) if result is None: continue data = { 'UID': docid } for attribute in attributes: attr = attribute if attribute in _attribute_mapping: attr = _attribute_mapping[attribute] if attr in ('Type', 'portal_type'): value = 'Page' if IImage.providedBy(result): value = 'Image' elif ICommunityFile.providedBy(result): value = 'File' elif IFolder.providedBy(result): value = 'Folder' elif attr == 'getURL': value = resource_url(result, request) elif attr == 'path': # a bit weird here... value = resource_path(result, request).split('/GET')[0] else: value = getattr(result, attr, None) data[attribute] = value items.append(data) return { 'results': items, 'total': numdocs }
def _get_motions(request, context, states): query = (Eq("type_name", "Motion") & Any("wf_state", states) & Eq("path", resource_path(context))) docids = request.root.catalog.query(query, sort_index="created")[1] return request.resolve_docids(docids, perm=None)
def get_docids_to_show(request, context, type_name, tags=(), limit=5, start_after=None, end_before=None): """ Helper method to fetch docids that would be a resonable batch to show. This is mostly to allow agenda views to load fast. - Fetch batch from the first unread docid so there will be no items skipped in case they were read from a tag view. - If batch contains less items than limit, insert items from previous. - start_after - remove everything before this docid and the value specified. - end_before - remove this value and everything after it. Result example: {'batch': [4, 5, 6], 'previous': [1, 2, 3], 'over_limit': [7, 8, 9], 'unread': [4, 5, 6, 7, 8, 9]} """ assert IAgendaItem.providedBy(context) query = Eq('path', resource_path(context)) query &= Eq('type_name', type_name) if tags: query &= Any('tags', list(tags)) read_names = request.get_read_names(context) unread_query = query & NotAny( '__name__', set(read_names.get(request.authenticated_userid, []))) unread_docids = list( request.root.catalog.query(unread_query, sort_index='created')[1]) docids_pool = list( request.root.catalog.query(query, sort_index='created')[1]) if start_after and start_after in docids_pool: i = docids_pool.index(start_after) for docid in docids_pool[:i + 1]: if docid in unread_docids: unread_docids.remove(docid) docids_pool[0:i + 1] = [] if end_before and end_before in docids_pool: i = docids_pool.index(end_before) for docid in docids_pool[i:]: if docid in unread_docids: unread_docids.remove(docid) docids_pool[i:] = [] if limit: if unread_docids: first_pos = docids_pool.index(unread_docids[0]) batch = docids_pool[first_pos:first_pos + limit] over_limit = docids_pool[first_pos + limit:] previous = docids_pool[:first_pos] # Fill batch from last item of previous if batch is too small while previous and len(batch) < limit: batch.insert(0, previous.pop(-1)) else: batch = docids_pool[-limit:] previous = docids_pool[:-limit] over_limit = [] return { 'batch': batch, 'previous': previous, 'over_limit': over_limit, 'unread': unread_docids } # no limit return { 'batch': docids_pool, 'previous': [], 'over_limit': [], 'unread': unread_docids }
def get_csv(self): context = self.context # prepare csv writer sio = StringIO() ex = csv.writer(sio, dialect='excel-colon', quoting=csv.QUOTE_MINIMAL) # exported column keys as first line ex.writerow(ORDER_EXPORT_ATTRS + COMPUTED_ORDER_EXPORT_ATTRS.keys() + BOOKING_EXPORT_ATTRS + COMPUTED_BOOKING_EXPORT_ATTRS.keys()) bookings_soup = get_bookings_soup(context) # First, filter by allowed vendor areas vendor_uids = get_vendor_uids_for() query_b = Any('vendor_uid', vendor_uids) # Second, query for the buyable query_cat = {} query_cat['object_provides'] = IBuyable.__identifier__ query_cat['path'] = '/'.join(context.getPhysicalPath()) cat = getToolByName(context, 'portal_catalog') res = cat(**query_cat) buyable_uids = [IUUID(it.getObject()) for it in res] query_b = query_b & Any('buyable_uid', buyable_uids) all_orders = {} for booking in bookings_soup.query(query_b): booking_attrs = [] # booking export attrs for attr_name in BOOKING_EXPORT_ATTRS: val = self.export_val(booking, attr_name) booking_attrs.append(val) # computed booking export attrs for attr_name in COMPUTED_BOOKING_EXPORT_ATTRS: cb = COMPUTED_BOOKING_EXPORT_ATTRS[attr_name] val = cb(context, booking) val = cleanup_for_csv(val) booking_attrs.append(val) # create order_attrs, if it doesn't exist order_uid = booking.attrs.get('order_uid') if order_uid not in all_orders: order = get_order(context, order_uid) order_data = OrderData(context, order=order, vendor_uids=vendor_uids) order_attrs = [] # order export attrs for attr_name in ORDER_EXPORT_ATTRS: val = self.export_val(order, attr_name) order_attrs.append(val) # computed order export attrs for attr_name in COMPUTED_ORDER_EXPORT_ATTRS: cb = COMPUTED_ORDER_EXPORT_ATTRS[attr_name] val = cb(self.context, order_data) val = cleanup_for_csv(val) order_attrs.append(val) all_orders[order_uid] = order_attrs ex.writerow(all_orders[order_uid] + booking_attrs) # TODO: also set for contextual exports? i'd say no. # booking.attrs['exported'] = True # bookings_soup.reindex(booking) ret = sio.getvalue() sio.close() return ret
def csv(self, request): # get orders soup orders_soup = get_orders_soup(self.context) # get bookings soup bookings_soup = get_bookings_soup(self.context) # fetch user vendor uids vendor_uids = get_vendor_uids_for() # base query for time range query = Ge('created', self.from_date) & Le('created', self.to_date) # filter by given vendor uid or user vendor uids vendor_uid = self.vendor if vendor_uid: vendor_uid = uuid.UUID(vendor_uid) # raise if given vendor uid not in user vendor uids if vendor_uid not in vendor_uids: raise Unauthorized query = query & Any('vendor_uids', [vendor_uid]) else: query = query & Any('vendor_uids', vendor_uids) # filter by customer if given customer = self.customer if customer: query = query & Eq('creator', customer) # prepare csv writer sio = StringIO() ex = csv.writer(sio, dialect='excel-colon', quoting=csv.QUOTE_MINIMAL) # exported column keys as first line ex.writerow(ORDER_EXPORT_ATTRS + COMPUTED_ORDER_EXPORT_ATTRS.keys() + BOOKING_EXPORT_ATTRS + COMPUTED_BOOKING_EXPORT_ATTRS.keys()) # query orders for order in orders_soup.query(query): # restrict order bookings for current vendor_uids order_data = OrderData(self.context, order=order, vendor_uids=vendor_uids) order_attrs = list() # order export attrs for attr_name in ORDER_EXPORT_ATTRS: val = self.export_val(order, attr_name) order_attrs.append(val) # computed order export attrs for attr_name in COMPUTED_ORDER_EXPORT_ATTRS: cb = COMPUTED_ORDER_EXPORT_ATTRS[attr_name] val = cb(self.context, order_data) val = cleanup_for_csv(val) order_attrs.append(val) for booking in order_data.bookings: booking_attrs = list() # booking export attrs for attr_name in BOOKING_EXPORT_ATTRS: val = self.export_val(booking, attr_name) booking_attrs.append(val) # computed booking export attrs for attr_name in COMPUTED_BOOKING_EXPORT_ATTRS: cb = COMPUTED_BOOKING_EXPORT_ATTRS[attr_name] val = cb(self.context, booking) val = cleanup_for_csv(val) booking_attrs.append(val) ex.writerow(order_attrs + booking_attrs) booking.attrs['exported'] = True bookings_soup.reindex(booking) # create and return response s_start = self.from_date.strftime('%G-%m-%d_%H-%M-%S') s_end = self.to_date.strftime('%G-%m-%d_%H-%M-%S') filename = 'orders-export-%s-%s.csv' % (s_start, s_end) self.request.response.setHeader('Content-Type', 'text/csv') self.request.response.setHeader('Content-Disposition', 'attachment; filename=%s' % filename) ret = sio.getvalue() sio.close() return ret