Ejemplo n.º 1
0
def toggle(request, klass, oid, key):
    """ Toggle any object property, given its a boolean on the DB side. """

    #
    # TODO: push notifications on error to the user.
    #

    try:
        obj = get_object_or_404(globals()[klass], id=oid)

    except:
        LOGGER.exception(u'Oops in toggle! Model “%s” not imported?', klass)
        return HttpResponseTemporaryServerError()

    if obj.user != request.user:
        return HttpResponseForbidden(u'Not owner')

    try:
        new_value = not getattr(obj, key)
        setattr(obj, key, new_value)

    except:
        msg = (u'Unable to toggle %s of %s', key, obj)
        LOGGER.exception(*msg)
        return HttpResponseTemporaryServerError(msg[0] % msg[1:])

    else:
        if key.startswith('is_'):
            date_attr = 'date_' + key[3:]

            if hasattr(obj, date_attr):
                # LOGGER.info(u'%s %s: set %s to NOW.',
                #             obj._meta.verbose_name, obj.id, date_attr)
                setattr(obj, date_attr, now() if new_value else None)

        try:
            getattr(obj, key + '_changed')()

        except AttributeError:
            pass

        except:
            LOGGER.exception(
                u'Unhandled exception while running '
                u', %s.%s_changed() on %s.', obj.__class__.__name__, key, obj)

        obj.save()

    if request.is_ajax():
        return HttpResponse(u'DONE.')

    else:
        return HttpResponseRedirect(
            request.META.get('HTTP_REFERER', reverse('home')))
Ejemplo n.º 2
0
def article_conversion_status(request, article_id):
    """ Return a 202 if article is converting, else redirect to article. """

    try:
        article = get_object_or_404(Article, id=article_id)

    except:
        return HttpResponseTemporaryServerError(
            u'Could not find article #{0}'.format(article_id))

    if article.content_type not in CONTENT_TYPES_FINAL:
        # The user is already waiting.
        # Process the item now for immediate markdown content.
        article.process()

    return HttpResponse(redirect_to_read(request.user, article))

    # read = get_object_or_404(Read, user=request.user, item=article)
    # return HttpResponse(u'http://' + settings.SITE_DOMAIN +
    #                     reverse('read_one', args=(read.item.id, )))

    res = HttpResponse(u'IN PROGRESS')
    res.status = 202

    return res
Ejemplo n.º 3
0
def set_preference(request, base, sub, value):
    """ Set a preference, via ajax or not. """

    # Do not is_staff_or_superuser_and_enabled here, else staff users
    # who have de-activated their super-powers cannot re-enable them.
    if 'staff' in base and not (request.user.is_staff
                                or request.user.is_superuser):
        return HttpResponseForbidden(u'Forbidden. BAD™.')

    prefs = request.user.preferences

    try:
        base_pref = getattr(prefs, base)
        setattr(base_pref, sub, value)

    except:
        return HttpResponseBadRequest(u'Bad preference name or value.')

    else:

        try:
            base_pref.save()

        except:
            LOGGER.exception(u'Could not save preference %s for user %s',
                             base_pref, request.user)
            return HttpResponseTemporaryServerError(
                u'Could not save preference.')

    if request.is_ajax():
        return HttpResponse(u'DONE')

    return HttpResponseRedirect(
        request.META.get('HTTP_REFERER', reverse('home')))
Ejemplo n.º 4
0
def error_handler(request, *args, **kwargs):
    """ Our error handler returns a 503 instead of a bare 500.

    Returning a 503 seems much more correct: the situation is clearly
    temporary and the error will certainly be resolved. For search robots
    this is better too.

    Besides that point, our handler passes the whole request to the 500
    template, via the whole template context processors chain, which could
    be considered risky, but is really not because we don't have any
    custom processor and Django's one are fully tested (at least we hope).
    """

    return HttpResponseTemporaryServerError(
        render_to_string('500.html', context_instance=RequestContext(request)))
Ejemplo n.º 5
0
def read_meta_staff(request, read_id):
    """ Return the staff-related meta-data of a Read. """

    try:
        read = get_object_or_404(Read, id=read_id)

    except:
        return HttpResponseTemporaryServerError()

    if not request.is_ajax() and not settings.DEBUG:
        return HttpResponseBadRequest('Must be called via Ajax')

    return render(request,
                  'snippets/read/read-meta-async-staff.html',
                  {'read': read, 'article': read.item})
Ejemplo n.º 6
0
def maintenance_mode(request, *args, **kwargs):
    """ Self-explanatory. """

    return HttpResponseTemporaryServerError(
        render_to_string('503.html', context_instance=RequestContext(request)))
Ejemplo n.º 7
0
def edit_field(request, klass, oid, form_class):
    """ Edit any object field, with minimal permissions checking, via Ajax.

    For permission to succeed, request.user must be staff or the owner
    of the object.

    The form class can define an optional ``redirect_url`` attribute. This
    attribute will be used after form save (when valid) to redirect the user
    instead of just displaying him/her a notification and staying on the
    current page.
    """

    if not request.is_ajax():
        return HttpResponseBadRequest('This request needs Ajax')

    try:
        obj_class = globals()[klass]

    except KeyError:
        LOGGER.exception(u'KeyError on “%s” in edit! Model not imported?',
                         klass)
        return HttpResponseTemporaryServerError()

    if 'history_id' in (x.name for x in obj_class._meta.fields):
        obj = get_object_or_404(obj_class, history_id=oid)

    else:
        obj = get_object_or_404(obj_class, id=oid)

    try:
        if obj.user != request.user \
                and not request.user.is_staff_or_superuser_and_enabled:
            return HttpResponseForbidden(u'Not owner nor superuser/staff')

    except AttributeError:
        if not request.user.is_staff_or_superuser_and_enabled:
            return HttpResponseForbidden(
                u'Not superuser/staff and no owner/creator field on instance')
    try:
        instance_name = obj.name

    except:
        instance_name = unicode(obj)

    form_klass = getattr(forms, form_class)

    if request.POST:
        form_get_args = request.GET.copy()

        if bool(form_get_args):
            form = form_klass(request.POST,
                              instance=obj,
                              form_get_args=form_get_args)

        else:
            form = form_klass(request.POST, instance=obj)

        redirect_url = None

        if form.is_valid():
            obj = form.save(request.user)

            try:
                redirect_url = form.redirect_url

            except AttributeError:
                # The form didn't set it, this is a supported behavior.
                # Just do as usual and simply render the JS template.
                pass

        return render(
            request, 'snippets/edit_field/result.html', {
                'instance_name': instance_name,
                'form': form,
                'obj': obj,
                'field_name': [f for f in form][0].name,
                'form_class': form_class,
                'klass': klass,
                'redirect_url': redirect_url,
            })

    else:
        form_get_args = request.GET.copy()

        if bool(form_get_args):
            form = form_klass(instance=obj, form_get_args=form_get_args)

        else:
            form = form_klass(instance=obj)

    return render(
        request, 'snippets/edit_field/modal.html', {
            'instance_name': instance_name,
            'form': form,
            'obj': obj,
            'field_name': [f for f in form][0].name,
            'form_class': form_class,
            'klass': klass,
        })
Ejemplo n.º 8
0
def share_one(request, item_id):
    """ Base view for sharing an article / read. """

    user = request.user

    def format_recipients(recipients):
        def pretty_name(recipient):
            return recipient.username \
                if recipient.is_active else recipient.email

        first = recipients.pop(0)

        recipients_len = len(recipients)

        if recipients_len == 0:
            return pretty_name(first)

        if recipients_len > 1:
            return _(u'{0} and {1} other persons').format(
                pretty_name(first), recipients_len)

        return _(u'{0} and another person').format(pretty_name(first))

    if not request.is_ajax():
        return HttpResponseBadRequest(u'Ajax is needed for this…')

    try:
        item = get_object_or_404(BaseItem, id=int(item_id))
        read = request.user.reads.get(item=item)

    except:
        LOGGER.exception(u'Could not load things to share item #%s', item_id)
        return HttpResponseTemporaryServerError('BOOM')

    user_share_lock = user.share_lock
    user_share_lock.acquire()

    if request.POST:
        form = ReadShareForm(request.POST, user=request.user)

        if form.is_valid():
            message, recipients = form.save()

            if recipients:
                # Creating new friends on the fly will make
                # new accounts active by default. New friends
                # will be able to login straight ahead.
                recipients = User.get_from_emails(recipients,
                                                  create_active=True)

                try:
                    # HEADS UP: we NEED to create a new poke if the message
                    # changed. This gracefully handles the case where user A
                    # shares item I with user B with a personnal/confidential
                    # message, then shares it again with user C with a more
                    # standard message.
                    #
                    # Without the `message` field, user C will get the private
                    # message redacted for user B, which absolutely not what we
                    # want.
                    #
                    # But, if user A doesn't change the message between pokes,
                    # we can pack the recipients on the same poke in database,
                    # which seems always a good thing to save some space and
                    # avoid DB scans.

                    poke = Poke.objects.get(
                        user=request.user,
                        attachments=item,
                        # `message` is *very* important,
                        # see comment above.
                        message=message)
                    created = False

                except Poke.DoesNotExist:
                    poke = Poke.create_poke(
                        sender=request.user,
                        message=message,
                        recipients=recipients,
                        attachments=[item],
                    )
                    created = True

                except Exception, e:
                    LOGGER.exception('sharing article via poke failed')
                    messages.warning(
                        request,
                        _(u'Sharing article failed: {0}').format(e),
                        extra_tags='sticky safe')
                    poke = None

                if poke is not None:
                    if not created:
                        new_recipients = [
                            r for r in recipients
                            if r not in poke.recipients.all()
                        ]

                        if new_recipients:
                            poke.resend(recipients=new_recipients)

                    messages.info(request,
                                  _(u'Successfully shared <em>{0}</em> '
                                    u'with {1}').format(
                                        read.item.name,
                                        format_recipients(
                                            list(recipients)[:])),
                                  extra_tags='safe')

                user_share_lock.release()

            else:
                messages.success(request,
                                 _(u'OK, I will tenderly keep <em>{0}</em> '
                                   u'for yourself only.').format(
                                       read.item.name),
                                 extra_tags='safe')

            return render(request, u'snippets/share/share-one-result.html')