Example #1
0
def api_response(request, data, callback=None, format='json'):
    # http://www.loggly.com/blog/2011/12/enabling-cors-in-django-piston/
    # for how to enable CORS
    request_method = request.method.upper()
    if request_method in ["OPTIONS", "HEAD"]:
        response = HttpResponse()
    elif isinstance(data, HttpResponseRedirect):
        response = data
    elif callback:
        body = u'%s(%s);' % (callback, dumps(data))
        response = HttpResponse(body, mimetype='application/javascript')
    elif format == 'html':
        response = HttpResponse(data)
    else:
        response = HttpResponse(mimetype='application/json')
        dump(data, response)

    origin = request.META.get('HTTP_REFERER', '') or \
             request.META.get('HTTP_ORIGIN', '')
    allowed = allow_origin_sites()
    if origin:
        allowed = [a for a in allowed if origin.find(a) >= 0]
    response["Access-Control-Allow-Origin"] = " ".join(allowed)
    response['Access-Control-Allow-Methods'] = \
        'POST, GET, OPTIONS, HEAD, PUT, DELETE'
    response["Access-Control-Allow-Headers"] = 'Authorization'
    response["Access-Control-Allow-Credentials"] = 'true'

    return response
Example #2
0
def location_question_results(
        request,
        question_id,
        limit_map_answers,
        survey_report_slug=""):
    question = get_object_or_404(Question.objects.select_related("survey"),
                                 pk=question_id,
                                 answer_is_public=True)
    is_staff = request.user.is_staff
    if not question.survey.can_have_public_submissions() and not is_staff:
        raise Http404
    featured = limit_results_to = False
    if survey_report_slug:
        survey_report = get_object_or_404(SurveyReport.objects,
                                          survey=question.survey,
                                          slug=survey_report_slug)
        featured = survey_report.featured
        limit_results_to = survey_report.limit_results_to
    icon_lookup = {}
    icon_questions = question.survey.icon_questions()
    for icon_question in icon_questions:
        icon_by_answer = {}
        for (option, icon) in icon_question.parsed_option_icon_pairs():
            if icon:
                icon_by_answer[option] = icon
        answer_set = icon_question.answer_set.all()
        for answer in answer_set.select_related("question"):
            if answer.value in icon_by_answer:
                icon = icon_by_answer[answer.value]
                icon_lookup[answer.submission_id] = icon

    answers = question.answer_set.filter(
        ~Q(latitude=None),
        ~Q(longitude=None)).order_by("-submission__submitted_at")
    if not is_staff:
        answers = answers.filter(submission__is_public=True)
    if featured:
        answers = answers.filter(submission__featured=True)
    answers = extra_from_filters(
        answers,
        "submission_id",
        question.survey,
        request.GET)
    limit_map_answers = int(limit_map_answers) if limit_map_answers else 0
    if limit_map_answers or limit_results_to:
        answers = answers[:min(filter(None, [limit_map_answers,
                                             limit_results_to, ]))]
    entries = []
    view = "survey.views.submission_for_map"
    for answer in answers:
        kwargs = {"id": answer.submission_id}
        d = {
            "lat": answer.latitude,
            "lng": answer.longitude,
            "url": reverse(view, kwargs=kwargs)}
        if answer.submission_id in icon_lookup:
            d["icon"] = icon_lookup[answer.submission_id]
        entries.append(d)
    response = HttpResponse(mimetype='application/json')
    dump({"entries": entries}, response)
    return response
Example #3
0
def submissions(request, format):
    """ Use this view to make arbitrary queries on submissions. If the user is
    a logged in staff member, ignore submission.is_public,
    question.answer_is_public, and survey.can_have_public_submissions. Use the
    query string to pass keys and values. For example,
    /crowdsourcing/submissions/?survey=my-survey will return all submissions
    for the survey with slug my-survey.
    survey - the slug for the survey
    user - the username of the submittor. Leave blank for submissions without
        a logged in user.
    submitted_from and submitted_to - strings in the format YYYY-mm-ddThh:mm:ss
        For example, 2010-04-05T13:02:03
    featured - A blank value, 'f', 'false', 0, 'n', and 'no' all mean ignore
        the featured flag. Everything else means display only featured.
    You can also use filters in the survey report sense. Rather than document
    exactly what parameters you would pass, follow these steps to figure it
    out:
    1. Enable filters on your survey and the questions you want to filter on.
    2. Go to the report page and fill out the filters you want.
    3. Click Submit.
    4. Examine the query string of the page you end up on and note which
        parameters are filled out. Use those same parameters here. """
    format = format.lower()
    if format not in FORMAT_CHOICES:
        msg = ("%s is an unrecognized format. Crowdsourcing recognizes "
               "these: %s") % (format, ", ".join(FORMAT_CHOICES))
        return HttpResponse(msg)
    is_staff = request.user.is_authenticated() and request.user.is_staff
    if is_staff:
        results = Submission.objects.all(status=Submission.COMPLETED)
    else:
        # survey.can_have_public_submissions is complicated enough that
        # we'll check it in Python, not the database.
        results = Submission.objects.filter(is_public=True, status=Submission.COMPLETED)
    results = results.select_related("survey", "user")
    get = request.GET.copy()
    limit = int(get.pop("limit", [0])[0])
    keys = get.keys()
    basic_filters = (
        'survey',
        'user',
        'submitted_from',
        'submitted_to',
        'featured',
        'is_public')
    if is_staff:
        basic_filters += BALLOT_STUFFING_FIELDS
    survey_slug = ""
    for field in [f for f in keys if f in basic_filters]:
        value = get[field]
        search_field = field
        if 'survey' == field:
            search_field = 'survey__slug'
            survey_slug = value
        elif 'user' == field:
            if '' == value:
                value = None
            else:
                search_field = 'user__username'
        elif field in ('submitted_from', 'submitted_to'):
            date_format = "%Y-%m-%dT%H:%M:%S"
            try:
                value = datetime.strptime(value, date_format)
            except ValueError:
                return HttpResponse(
                    ("Invalid %s format. Try, for example, "
                     "%s") % (field, datetime.now().strftime(date_format),))
            if 'submitted_from' == field:
                search_field = 'submitted_at__gte'
            else:
                search_field = 'submitted_at__lte'
        elif field in ('featured', 'is_public',):
            falses = ('f', 'false', 'no', 'n', '0',)
            value = len(value) and not value.lower() in falses
        # search_field is unicode but needs to be ascii.
        results = results.filter(**{str(search_field): value})
        get.pop(field)

    def get_survey():
        survey = Survey.objects.get(slug=survey_slug)
        get_survey = lambda: survey
        return survey

    if get:
        if survey_slug:
            results = extra_from_filters(
                results,
                "survey_submission.id",
                get_survey(),
                get)
        else:
            message = (
                "You've got a couple of extra filters here, and we "
                "aren't sure what to do with them. You may have just "
                "misspelled one of the basic filters (%s). You may have a "
                "filter from a particular survey in mind. In that case, just "
                "include survey=my-survey-slug in the query string. You may "
                "also be trying to pull some hotshot move like, \"Get me all "
                "submissions that belong to a survey with a filter named '%s' "
                "that match '%s'.\" Crowdsourcing could support this, but it "
                "would be pretty inefficient and, we're guessing, pretty "
                "rare. If that's what you're trying to do I'm afraid you'll "
                "have to do something more complicated like iterating through "
                "all your surveys.")
            item = get.items()[0]
            message = message % (", ".join(basic_filters), item[0], item[1])
            return HttpResponse(message)
    if not is_staff:
        if survey_slug:
            if not get_survey().can_have_public_submissions():
                results = []
        else:
            rs = [r for r in results if r.survey.can_have_public_submissions()]
            results = rs
    if limit:
        results = results[:limit]
    answer_lookup = get_all_answers(results,
                                    include_private_questions=is_staff)
    result_data = []
    for r in results:
        data = r.to_jsondata(answer_lookup, include_private_questions=is_staff)
        result_data.append(data)

    for data in result_data:
        data.update(data["data"])
        data.pop("data")

    def get_keys():
        key_lookup = {}
        for data in result_data:
            for key in data.keys():
                key_lookup[key] = True
        return sorted(key_lookup.keys())

    if format == 'json':
        response = HttpResponse(mimetype='application/json')
        dump(result_data, response)
    elif format == 'csv':
        response = HttpResponse(mimetype='text/csv')
        writer = csv.writer(response)
        keys = get_keys()
        writer.writerow(keys)
        for data in result_data:
            row = []
            for k in keys:
                row.append((u"%s" % _encode(data.get(k, ""))).encode("utf-8"))
            writer.writerow(row)
    elif format == 'xml':
        doc = Document()
        submissions = doc.createElement("submissions")
        doc.appendChild(submissions)
        for data in result_data:
            submission = doc.createElement("submission")
            submissions.appendChild(submission)
            for key, value in data.items():
                if value:
                    cell = doc.createElement(key)
                    submission.appendChild(cell)
                    cell.appendChild(doc.createTextNode(u"%s" % value))
        response = HttpResponse(doc.toxml(), mimetype='text/xml')
    elif format == 'html':  # mostly for debugging.
        keys = get_keys()
        results = [
            "<html><body><table>",
            "<tr>%s</tr>" % "".join(["<th>%s</th>" % k for k in keys])]
        for data in result_data:
            cell = "<td>%s</td>"
            cells = [cell % _encode(data.get(key, "")) for key in keys]
            results.append("<tr>%s</tr>" % "".join(cells))
        results.append("</table></body></html>")
        response = HttpResponse("\n".join(results))
    else:
        return HttpResponse("Unsure how to handle %s format" % format)
    return response