def get(self, request): tracker, create = Tracker.objects.get_or_create(user=self.request.user) yesterday = date.today() - timedelta(days=1) if not create and tracker.date <= yesterday: tracker.days_row = 1 if tracker.date < yesterday else tracker.days_row + 1 create = True if create: self.add_energy(tracker.days_row) tracker.save() serializer = TrackerSerializer(data=tracker.__dict__) serializer.is_valid(raise_exception=True) return Response(data=serializer.data, status=status.HTTP_201_CREATED if create else status.HTTP_200_OK)
def add_event_fields(fields, event, prefix): dumped_event = TrackerSerializer(models.Event, request).serialize([event])[ 0 ] for key, value in dumped_event['fields'].items(): if key not in ['canonical_url', 'name', 'short', 'timezone']: continue try: value = DjangoJSONEncoder().default(value) except TypeError: pass fields[prefix + '__' + key] = value fields[prefix + '__datetime'] = DjangoJSONEncoder().default( event.datetime.astimezone(pytz.utc) ) fields[prefix + '__public'] = str(event)
def add_run_fields(fields, run, prefix): dumped_run = TrackerSerializer(models.SpeedRun, request).serialize([run])[0] for key, value in dumped_run['fields'].items(): if key not in [ 'canonical_url', 'endtime', 'name', 'starttime', 'display_name', 'order', ]: continue try: value = DjangoJSONEncoder().default(value) except TypeError: pass fields[prefix + '__' + key] = value fields[prefix + '__public'] = str(run)
def add_parent_fields(fields, parent, prefix): dumped_bid = TrackerSerializer(models.Bid, request).serialize([parent])[0] for key, value in dumped_bid['fields'].items(): if key not in [ 'canonical_url', 'name', 'state', 'goal', 'allowuseroptions', 'option_max_length', 'total', 'count', ]: continue try: value = DjangoJSONEncoder().default(value) except TypeError: pass fields[prefix + '__' + key] = value fields[prefix + '__public'] = str(parent)
def search(request): search_params = QueryDict.copy(request.GET) search_type = single(search_params, 'type') queries = present(search_params, 'queries') donor_names = present(search_params, 'donor_names') all_comments = present(search_params, 'all_comments') tech_notes = present(search_params, 'tech_notes') Model = modelmap.get(search_type, None) if Model is None: raise KeyError('%s is not a recognized model type' % search_type) if queries and not request.user.has_perm('tracker.view_queries'): raise PermissionDenied # TODO: move these to a lookup table? if donor_names: if search_type != 'donor': raise KeyError('"donor_names" can only be applied to donor searches') if not request.user.has_perm('tracker.view_usernames'): raise PermissionDenied if all_comments: if search_type != 'donation': raise KeyError('"all_comments" can only be applied to donation searches') if not request.user.has_perm('tracker.view_comments'): raise PermissionDenied if tech_notes: if search_type != 'run': raise KeyError('"tech_notes" can only be applied to run searches') if not request.user.has_perm('tracker.can_view_tech_notes'): raise PermissionDenied offset = int(single(search_params, 'offset', 0)) limit = getattr(settings, 'TRACKER_PAGINATION_LIMIT', DEFAULT_PAGINATION_LIMIT) limit_param = int(single(search_params, 'limit', limit)) if limit_param > limit: raise ValueError('limit can not be above %d' % limit) if limit_param < 1: raise ValueError('limit must be at least 1') limit = min(limit, limit_param) qs = search_filters.run_model_query(search_type, search_params, request.user,) qs = qs[offset : (offset + limit)] # Django 3.1 doesn't like Model.Meta.ordering when combined with annotations, so this guarantees the # correct subset when using annotations, even if it does result in an extra query if search_type in annotations: qs = ( Model.objects.filter(pk__in=(m.pk for m in qs)) .annotate(**annotations[search_type]) .order_by() ) if search_type in related: qs = qs.select_related(*related[search_type]) if search_type in prefetch: qs = qs.prefetch_related(*prefetch[search_type]) include_fields = included_fields.get(search_type, {}) result = TrackerSerializer(Model, request).serialize( qs, fields=include_fields.get('__self__', None) ) objs = {o.id: o for o in qs} related_cache = {} for obj in result: base_obj = objs[int(obj['pk'])] if hasattr(base_obj, 'visible_name'): obj['fields']['public'] = base_obj.visible_name() else: obj['fields']['public'] = str(base_obj) for a in annotations.get(search_type, {}): func = annotation_coercions.get(search_type, {}).get(a, str) obj['fields'][a] = func(getattr(base_obj, a)) for prefetched_field in prefetch.get(search_type, []): if '__' in prefetched_field: continue obj['fields'][prefetched_field] = [ po.id for po in getattr(base_obj, prefetched_field).all() ] for related_field in related.get(search_type, []): related_object = base_obj for field in related_field.split('__'): if not related_object: break if not related_object._meta.get_field(field).serialize: related_object = None else: related_object = getattr(related_object, field) if not related_object: continue if related_object not in related_cache: related_cache[related_object] = ( TrackerSerializer(type(related_object), request).serialize( [related_object], fields=include_fields.get(related_field, None) ) )[0] related_data = related_cache[related_object] for field, values in related_data['fields'].items(): if field.endswith('id'): continue obj['fields'][related_field + '__' + field] = values if hasattr(related_object, 'visible_name'): obj['fields'][ related_field + '__public' ] = related_object.visible_name() else: obj['fields'][related_field + '__public'] = str(related_object) if search_type == 'donor' and not donor_names: donor_privacy_filter(obj['fields']) elif search_type == 'donation' and not all_comments: donation_privacy_filter(obj['fields']) elif search_type == 'run' and not tech_notes: run_privacy_filter(obj['fields']) resp = HttpResponse( json.dumps(result, ensure_ascii=False, cls=DjangoJSONEncoder), content_type='application/json;charset=utf-8', ) if queries: return HttpResponse( json.dumps(connection.queries, ensure_ascii=False, indent=1), content_type='application/json;charset=utf-8', ) # TODO: cache control for certain kinds of searches return resp