Пример #1
0
def messages_change_state(request):
    if request.method == "POST":
        choice = request.POST.get("choice", False)

        # get all message ids in the format `cb_[number]` which have a value of 'on'
        message_ids = []
        for key, val in request.POST.items():
            if key.startswith('cb_') and val == 'on':
                try:
                    msgid = int(key.replace('cb_', ''))
                    message_ids.append(msgid)
                except ValueError:
                    pass

        if choice and message_ids:
            messages = Message.objects.filter(
                Q(user_to=request.user, is_sent=False)
                | Q(user_from=request.user, is_sent=True)).filter(
                    id__in=message_ids)

            if choice == "a":
                messages.update(is_archived=True)
            elif choice == "d":
                messages.delete()
            elif choice == "r":
                messages.update(is_read=True)

            invalidate_template_cache("user_header", request.user.id)

    return HttpResponseRedirect(request.POST.get("next", reverse("messages")))
Пример #2
0
def messages_change_state(request):
    if request.method == "POST":
        choice = request.POST.get("choice", False)

        # get all ids, prefixed by "cb_" and after than an integer
        # only get the checkboxes that are "on"
        message_ids = filter(lambda x: x != None, [
            exceptional(int)(key.replace("cb_", ""))
            for key in request.POST.keys()
            if key.startswith("cb_") and request.POST.get(key) == "on"
        ])

        if choice and message_ids:
            messages = Message.objects.filter(
                Q(user_to=request.user, is_sent=False)
                | Q(user_from=request.user, is_sent=True)).filter(
                    id__in=message_ids)

            if choice == "a":
                messages.update(is_archived=True)
            elif choice == "d":
                messages.delete()
            elif choice == "r":
                messages.update(is_read=True)

            invalidate_template_cache("user_header", request.user.id)

    return HttpResponseRedirect(request.POST.get("next", reverse("messages")))
Пример #3
0
def update_last_post_on_post_delete(sender, instance, **kwargs):
    """Update num_posts counts and last_post pointers when a Post is deleted.

    Reduce num_posts by 1 for the author, forum, and thread
    Set last_post for the forum
    Set last_post for the thread. If this was the only remaining post
    in the thread and it was deleted, also delete the thread.

    If the post was not moderated, don't update the values
    """
    post = instance
    delete_post_from_solr(post)
    if post.moderation_state == "OK":
        try:
            with transaction.atomic():
                post.author.profile.num_posts = F('num_posts') - 1
                post.author.profile.save()
                post.thread.forum.refresh_from_db()
                post.thread.forum.num_posts = F('num_posts') - 1
                post.thread.forum.set_last_post()
                post.thread.forum.save()
                thread_has_posts = post.thread.set_last_post()
                if thread_has_posts:
                    post.thread.num_posts = F('num_posts') - 1
                    post.thread.save()
                else:
                    post.thread.delete()
        except Thread.DoesNotExist:
            # This happens when the thread has already been deleted, for example
            # when a user is deleted through the admin interface. We don't need
            # to update the thread, but it would be nice to get to the forum object
            # somehow and update that one....
            logger.info('Tried setting last posts for thread and forum, but the thread has already been deleted?')
    invalidate_template_cache('latest_posts')
Пример #4
0
def messages_change_state(request):
    if request.method == "POST":
        choice = request.POST.get("choice", False)
        
        # get all message ids in the format `cb_[number]` which have a value of 'on'
        message_ids = []
        for key, val in request.POST.items():
            if key.startswith('cb_') and val == 'on':
                try:
                    msgid = int(key.replace('cb_', ''))
                    message_ids.append(msgid)
                except ValueError:
                    pass

        if choice and message_ids:
            messages = Message.objects.filter(Q(user_to=request.user, is_sent=False) | Q(user_from=request.user, is_sent=True)).filter(id__in=message_ids)

            if choice == "a":
                messages.update(is_archived=True)
            elif choice == "d":
                messages.delete()
            elif choice == "r":
                messages.update(is_read=True)

            invalidate_template_cache("user_header", request.user.id)

    return HttpResponseRedirect(request.POST.get("next", reverse("messages")))
Пример #5
0
def update_thread_on_post_delete(sender, instance, **kwargs):
    """Update num_posts counts and last_post pointers when a Post is deleted.

    Reduce num_posts by 1 for the author, forum, and thread
    Set last_post for the forum
    Set last_post for the thread. If this was the only remaining post
    in the thread and it was deleted, also delete the thread.

    If the post was not moderated, don't update num_posts counts, but if it's
    the only post in a thread, also delete the thread.
    """
    post = instance
    delete_post_from_solr(post.id)
    if post.moderation_state == "NM":
        # If the first post is NM and there are subsequent posts in this thread then
        # we won't correctly set thread.first_post. This won't happen in regular use,
        # so we ignore this case

        # Even though we call set_last_post, we just use it to see if there exist OK posts
        # on this thread so that we can delete the thread if necessary.
        thread_has_posts = post.thread.set_last_post()
        if not thread_has_posts:
            post.thread.delete()
    elif post.moderation_state == "OK":
        try:
            with transaction.atomic():
                post.author.profile.num_posts = F('num_posts') - 1
                post.author.profile.save()
                post.thread.forum.refresh_from_db()
                post.thread.forum.num_posts = F('num_posts') - 1
                post.thread.forum.set_last_post()
                post.thread.forum.save()
                thread_has_posts = post.thread.set_last_post()
                if thread_has_posts:
                    post.thread.num_posts = F('num_posts') - 1
                    post.thread.save()

                    # If this post was the first post in the thread then we should set it to the next one
                    # We leave the author of the thread as the author of the first post
                    if post.thread.first_post_id == post.id:
                        # This is unconditionally the first post, even if it's not moderated
                        post.thread.first_post = post.thread.post_set.first()
                        post.thread.save(update_fields=['first_post'])
                else:
                    post.thread.delete()
        except Thread.DoesNotExist:
            # This happens when the thread has already been deleted, for example
            # when a user is deleted through the admin interface. We don't need
            # to update the thread, but it would be nice to get to the forum object
            # somehow and update that one....
            logger.info('Tried setting last posts for thread and forum, but the thread has already been deleted?')
        except accounts.models.Profile.DoesNotExist:
            # When a user is deleted using the admin, is possible that his posts are deleted after the profile has been
            # deleted. In that case we shouldn't update the value of num_posts because the profile doesn't exists
            # anymore, here it's safe to ignore the exception since we are deleting all the objects.
            logger.info('Tried setting last posts for thread and forum, but the profile has already been deleted?')
    invalidate_template_cache('latest_posts')
Пример #6
0
def update_last_post_on_post_delete(**kwargs):
    post = kwargs['instance']
    try:
        post.thread.set_last_post()
    except Thread.DoesNotExist:
        # This happens when the thread has already been deleted, for example
        # when a user is deleted through the admin interface. We don't need
        # to update the thread, but it would be nice to get to the forum object
        # somehow and update that one....
        logger.info('Tried setting last posts for thread and forum, but the thread has already been deleted?')
    invalidate_template_cache('latest_posts')
Пример #7
0
def rate_sound(request, username, sound_id, rating):
    sound = get_object_or_404(Sound.objects.select_related("user"),
                              id=sound_id)
    if sound.user.username.lower() != username.lower():
        raise Http404

    rating = int(rating)
    if 1 <= rating <= 5:
        # in order to keep the ratings compatible with freesound 1, we multiply by two...
        rating = rating * 2
        rating_obj, created = SoundRating.objects.get_or_create(
            user=request.user, sound_id=sound_id, defaults={'rating': rating})

        if not created:
            rating_obj.rating = rating
            rating_obj.save()

        # make sure the rating is seen on the next page load by invalidating the cache for it.
        invalidate_template_cache("sound_header", sound_id, True)
        invalidate_template_cache("sound_header", sound_id, False)
        invalidate_template_cache("display_sound", sound_id, True, 'OK')
        invalidate_template_cache("display_sound", sound_id, False, 'OK')
        Sound.objects.filter(id=sound_id).update(
            is_index_dirty=True)  # Set index dirty to true

    return HttpResponse(
        str(SoundRating.objects.filter(sound_id=sound_id).count()))
Пример #8
0
def add(request, content_type_id, object_id, rating):
    rating = int(rating)
    if rating in range(1, 6):
        # in order to keep the ratings compatible with freesound 1, we multiply by two...
        rating = rating * 2
        content_type = ContentType.objects.get(id=content_type_id)
        try:
            rating_object = Rating.objects.get(user=request.user,
                                               object_id=object_id,
                                               content_type=content_type)
            rating_object.rating = rating
            rating_object.save()
        except Rating.DoesNotExist:  #@UndefinedVariable
            rating_object = Rating.objects.create(user=request.user,
                                                  object_id=object_id,
                                                  content_type=content_type,
                                                  rating=rating)
        # make sure the rating is seen on the next page load by invalidating the cache for it.
        ct = ContentType.objects.get(id=content_type_id)
        if ct.name == 'sound':
            # invalidate for logged in/not logged in, only for 'OK' sounds
            invalidate_template_cache("sound_header", object_id, True)
            invalidate_template_cache("sound_header", object_id, False)
            invalidate_template_cache("display_sound", object_id, True, 'OK')
            invalidate_template_cache("display_sound", object_id, False, 'OK')
            # if you want to invalidate some other caches for other content types add them here

    return HttpResponse(
        str(
            Rating.objects.filter(object_id=object_id,
                                  content_type=content_type).count()))
Пример #9
0
def add(request, content_type_id, object_id, rating):
    rating = int(rating)
    content_type = ContentType.objects.get(id=content_type_id)
    if rating in range(1, 6):
        # in order to keep the ratings compatible with freesound 1, we multiply by two...
        rating = rating * 2
        try:
            rating_object = Rating.objects.get(user=request.user,
                                               object_id=object_id,
                                               content_type=content_type)
            rating_object.rating = rating
            rating_object.save()
        except Rating.DoesNotExist:  #@UndefinedVariable
            rating_object = Rating.objects.create(user=request.user,
                                                  object_id=object_id,
                                                  content_type=content_type,
                                                  rating=rating)
        # make sure the rating is seen on the next page load by invalidating the cache for it.
        ct = ContentType.objects.get(id=content_type_id)
        if ct.name == 'sound':
            invalidate_template_cache("sound_header", object_id, True)
            invalidate_template_cache("sound_header", object_id, False)
            invalidate_template_cache("display_sound", object_id, True, 'OK')
            invalidate_template_cache("display_sound", object_id, False, 'OK')
            Sound.objects.filter(id=object_id).update(
                is_index_dirty=True)  # Set index dirty to true

    return HttpResponse(
        str(
            Rating.objects.filter(object_id=object_id,
                                  content_type=content_type).count()))
Пример #10
0
def message(request, message_id):
    try:
        message = base_qs.get(id=message_id)
    except Message.DoesNotExist:  #@UndefinedVariable
        raise Http404

    if message.user_from != request.user and message.user_to != request.user:
        raise Http404

    if not message.is_read:
        message.is_read = True
        invalidate_template_cache("user_header", request.user.id)
        message.save()

    return render(request, 'messages/message.html', locals())
Пример #11
0
def message(request, message_id):
    try:
        message = base_qs.get(id=message_id)
    except Message.DoesNotExist: #@UndefinedVariable
        raise Http404
    
    if message.user_from != request.user and message.user_to != request.user:
        raise Http404
    
    if not message.is_read:
        message.is_read = True
        invalidate_template_cache("user_header", request.user.id)
        message.save()
        
    return render_to_response('messages/message.html', locals(), context_instance=RequestContext(request))
Пример #12
0
def message(request, message_id):
    try:
        message = base_qs.get(id=message_id)
    except Message.DoesNotExist:
        raise Http404

    if message.user_from != request.user and message.user_to != request.user:
        raise Http404

    if not message.is_read:
        message.is_read = True
        invalidate_template_cache("user_header", request.user.id)
        message.save()

    tvars = {'message': message}
    return render(request, 'messages/message.html', tvars)
Пример #13
0
def update_last_post_on_post_delete(sender, instance, **kwargs):
    """Update num_posts counts and last_post pointers when a Post is deleted.

    Reduce num_posts by 1 for the author, forum, and thread
    Set last_post for the forum
    Set last_post for the thread. If this was the only remaining post
    in the thread and it was deleted, also delete the thread.

    If the post was not moderated, don't update the values
    """
    post = instance
    delete_post_from_solr(post)
    if post.moderation_state == "OK":
        try:
            with transaction.atomic():
                post.author.profile.num_posts = F('num_posts') - 1
                post.author.profile.save()
                post.thread.forum.refresh_from_db()
                post.thread.forum.num_posts = F('num_posts') - 1
                post.thread.forum.set_last_post()
                post.thread.forum.save()
                thread_has_posts = post.thread.set_last_post()
                if thread_has_posts:
                    post.thread.num_posts = F('num_posts') - 1
                    post.thread.save()

                    # If this post was the first post in the thread then we should set it to the next one
                    # We leave the author of the thread as the author of the first post
                    if post.thread.first_post_id == post.id:
                        # This is unconditionally the first post, even if it's not moderated
                        post.thread.first_post = post.thread.post_set.first()
                        post.thread.save(update_fields=['first_post'])
                else:
                    post.thread.delete()
        except Thread.DoesNotExist:
            # This happens when the thread has already been deleted, for example
            # when a user is deleted through the admin interface. We don't need
            # to update the thread, but it would be nice to get to the forum object
            # somehow and update that one....
            logger.info('Tried setting last posts for thread and forum, but the thread has already been deleted?')
        except accounts.models.Profile.DoesNotExist:
            # When a user is deleted using the admin, is possible that his posts are deleted after the profile has been
            # deleted. In that case we shouldn't update the value of num_posts because the profile doesn't exists
            # anymore, here it's safe to ignore the exception since we are deleting all the objects.
            logger.info('Tried setting last posts for thread and forum, but the profile has already been deleted?')
    invalidate_template_cache('latest_posts')
Пример #14
0
def update_num_posts_on_post_insert(sender, instance, created, **kwargs):
    """Increase num_posts and set last_post when a new Post is created"""
    post = instance
    if created and post.moderation_state == "OK":
        with transaction.atomic():
            post.author.profile.num_posts = F('num_posts') + 1
            post.author.profile.save()
            post.thread.forum.num_posts = F('num_posts') + 1
            post.thread.forum.last_post = post
            post.thread.forum.save()
            post.thread.num_posts = F('num_posts') + 1
            post.thread.last_post = post
            post.thread.save()
        invalidate_template_cache('latest_posts')
    elif not created and post.moderation_state == "OK":
        post.thread.forum.set_last_post()
        post.thread.forum.save(update_fields=['last_post'])
        post.thread.set_last_post()
        post.thread.save(update_fields=['last_post'])
Пример #15
0
def update_num_posts_on_post_insert(sender, instance, created, **kwargs):
    """Increase num_posts and set last_post when a new Post is created"""
    post = instance
    if created and post.moderation_state == "OK":
        with transaction.atomic():
            post.author.profile.num_posts = F('num_posts') + 1
            post.author.profile.save()
            post.thread.forum.num_posts = F('num_posts') + 1
            post.thread.forum.last_post = post
            post.thread.forum.save()
            post.thread.num_posts = F('num_posts') + 1
            post.thread.last_post = post
            post.thread.save()
        invalidate_template_cache('latest_posts')
    elif not created and post.moderation_state == "OK":
        post.thread.forum.set_last_post()
        post.thread.forum.save(update_fields=['last_post'])
        post.thread.set_last_post()
        post.thread.save(update_fields=['last_post'])
Пример #16
0
def messages_change_state(request):
    if request.method == "POST":
        choice = request.POST.get("choice", False)
        
        # get all ids, prefixed by "cb_" and after than an integer
        # only get the checkboxes that are "on"
        message_ids = filter(lambda x: x != None, [exceptional(int)(key.replace("cb_", "")) for key in request.POST.keys() if key.startswith("cb_") and request.POST.get(key) == "on"])

        if choice and message_ids:
            messages = Message.objects.filter(Q(user_to=request.user, is_sent=False) | Q(user_from=request.user, is_sent=True)).filter(id__in=message_ids)

            if choice == "a":
                messages.update(is_archived=True)
            elif choice == "d":
                messages.delete()
            elif choice == "r":
                messages.update(is_read=True)
            
            invalidate_template_cache("user_header", request.user.id)
            
    return HttpResponseRedirect(request.POST.get("next", reverse("messages")))
Пример #17
0
def update_num_posts_on_post_insert(sender, instance, created, **kwargs):
    """Increase num_posts counts when a new Post is created, and update last_posts
    If a new post is created with a moderation state of OK, update counts
    and set last_post explicitly to this post.
    If a post is edited, set thread and forum last posts (this considers the case where
    a post moderation state changes to or from OK and now becomes or is removed from
    last_post of the forum or thread)"""
    post = instance
    if created and post.moderation_state == "OK":
        with transaction.atomic():
            post.author.profile.num_posts = F('num_posts') + 1
            post.author.profile.save()
            post.thread.forum.num_posts = F('num_posts') + 1
            post.thread.forum.last_post = post
            post.thread.forum.save()
            post.thread.num_posts = F('num_posts') + 1
            post.thread.last_post = post
            post.thread.save()
        invalidate_template_cache('latest_posts')
    elif not created:
        post.thread.forum.set_last_post()
        post.thread.forum.save(update_fields=['last_post'])
        post.thread.set_last_post()
        post.thread.save(update_fields=['last_post'])
Пример #18
0
def add(request, content_type_id, object_id, rating):
    rating = int(rating)
    if rating in range(1,6):
        # in order to keep the ratings compatible with freesound 1, we multiply by two...
        rating = rating*2
        content_type = ContentType.objects.get(id=content_type_id)
        try:
            rating_object = Rating.objects.get(user=request.user, object_id=object_id, content_type=content_type)
            rating_object.rating = rating;
            rating_object.save()
        except Rating.DoesNotExist: #@UndefinedVariable
            rating_object = Rating.objects.create(user=request.user, object_id=object_id, content_type=content_type, rating=rating)
        # make sure the rating is seen on the next page load by invalidating the cache for it.
        ct = ContentType.objects.get(id=content_type_id)
        if ct.name == 'sound':
            # invalidate for logged in/not logged in, only for 'OK' sounds
            invalidate_template_cache("sound_header", object_id, True)
            invalidate_template_cache("sound_header", object_id, False)
            invalidate_template_cache("display_sound", object_id, True, 'OK')
            invalidate_template_cache("display_sound", object_id, False, 'OK')
            # if you want to invalidate some other caches for other content types add them here
    return HttpResponse(Rating.objects.filter(object_id=object_id, content_type=content_type).count())
Пример #19
0
def add(request, content_type_id, object_id, rating):
    rating = int(rating)
    if rating in range(1,6):
        # in order to keep the ratings compatible with freesound 1, we multiply by two...
        rating = rating*2
        content_type = ContentType.objects.get(id=content_type_id)
        try:
            rating_object = Rating.objects.get(user=request.user, object_id=object_id, content_type=content_type)
            rating_object.rating = rating;
            rating_object.save()
        except Rating.DoesNotExist: #@UndefinedVariable
            rating_object = Rating.objects.create(user=request.user, object_id=object_id, content_type=content_type, rating=rating)
        # make sure the rating is seen on the next page load by invalidating the cache for it.
        ct = ContentType.objects.get(id=content_type_id)
        if ct.name == 'sound':
            invalidate_template_cache("sound_header", object_id, True)
            invalidate_template_cache("sound_header", object_id, False)
            invalidate_template_cache("display_sound", object_id, True, 'OK')
            invalidate_template_cache("display_sound", object_id, False, 'OK')
            Sound.objects.filter(id=object_id).update(is_index_dirty=True)  # Set index dirty to true

    return HttpResponse(str(Rating.objects.filter(object_id=object_id, content_type=content_type).count()))
Пример #20
0
 def invalidate_template_caches(self):
     invalidate_template_cache("sound_header", self.id, True)
     invalidate_template_cache("sound_header", self.id, False)
     invalidate_template_cache("sound_footer_top", self.id)
     invalidate_template_cache("sound_footer_bottom", self.id)
     invalidate_template_cache("display_sound", self.id, True, self.processing_state, self.moderation_state)
     invalidate_template_cache("display_sound", self.id, False, self.processing_state, self.moderation_state)
Пример #21
0
def ticket(request, ticket_key):
    can_view_moderator_only_messages = __can_view_mod_msg(request)
    clean_status_forms = True
    clean_comment_form = True
    ticket = get_object_or_404(Ticket, key=ticket_key)
    if request.method == 'POST':

        invalidate_template_cache("user_header", ticket.sender.id)
        invalidate_all_moderators_header_cache()

        # Left ticket message
        if is_selected(request,
                       'recaptcha') or (request.user.is_authenticated()
                                        and is_selected(request, 'message')):
            tc_form = __get_tc_form(request)
            if tc_form.is_valid():
                tc = TicketComment()
                tc.text = tc_form.cleaned_data['message']
                tc.moderator_only = tc_form.cleaned_data.get(
                    'moderator_only', False)
                if tc.text:
                    if request.user.is_authenticated():
                        tc.sender = request.user
                    tc.ticket = ticket
                    tc.save()
                    if not request.user.is_authenticated():
                        email_to = Ticket.MODERATOR_ONLY
                    elif request.user == ticket.sender:
                        email_to = Ticket.MODERATOR_ONLY
                    else:
                        email_to = Ticket.USER_ONLY
                    ticket.send_notification_emails(
                        ticket.NOTIFICATION_UPDATED, email_to)
            else:
                clean_comment_form = False
        # update sound ticket
        elif is_selected(request, 'tm') or is_selected(request, 'ss'):
            ticket_form = TicketModerationForm(request.POST, prefix="tm")
            sound_form = SoundStateForm(request.POST, prefix="ss")
            if ticket_form.is_valid() and sound_form.is_valid():
                clean_status_forms = True
                clean_comment_form = True
                sound_state = sound_form.cleaned_data.get('state')
                # Sound should be deleted
                if sound_state == 'DE':
                    if ticket.content:
                        ticket.content.content_object.delete()
                        ticket.content.delete()
                        ticket.content = None
                    ticket.status = TICKET_STATUS_CLOSED
                    tc = TicketComment(
                        sender=request.user,
                        text=
                        "Moderator %s deleted the sound and closed the ticket"
                        % request.user,
                        ticket=ticket,
                        moderator_only=False)
                    tc.save()
                    ticket.send_notification_emails(
                        ticket.NOTIFICATION_DELETED, ticket.USER_ONLY)
                # Set another sound state that's not delete
                else:
                    if ticket.content:
                        ticket.content.content_object.moderation_state = sound_state
                        # Mark the index as dirty so it'll be indexed in Solr
                        if sound_state == "OK":
                            ticket.content.content_object.mark_index_dirty()
                        ticket.content.content_object.save()
                    ticket.status = ticket_form.cleaned_data.get('status')
                    tc = TicketComment(sender=request.user,
                                       text="Moderator %s set the sound to %s and the ticket to %s." % \
                                                (request.user,
                                                 'pending' if sound_state == 'PE' else sound_state,
                                                 ticket.status),
                                       ticket=ticket,
                                       moderator_only=False)
                    tc.save()
                    ticket.send_notification_emails(
                        ticket.NOTIFICATION_UPDATED, ticket.USER_ONLY)
                ticket.save()

    if clean_status_forms:
        ticket_form = TicketModerationForm(initial={'status': ticket.status},
                                           prefix="tm")
        sound_form = SoundStateForm(initial={'state':
                                             ticket.content.content_object.moderation_state \
                                             if ticket.content else 'DE'},
                                             prefix="ss")
    if clean_comment_form:
        tc_form = __get_tc_form(request, False)
    return render_to_response('tickets/ticket.html',
                              locals(),
                              context_instance=RequestContext(request))
Пример #22
0
def moderation_assigned(request, user_id):

    can_view_moderator_only_messages = __can_view_mod_msg(request)
    clear_forms = True
    if request.method == 'POST':
        mod_sound_form = SoundModerationForm(request.POST)
        msg_form = ModerationMessageForm(request.POST)

        if mod_sound_form.is_valid() and msg_form.is_valid():

            ticket = Ticket.objects.get(
                id=mod_sound_form.cleaned_data.get("ticket", False))
            invalidate_template_cache("user_header", ticket.sender.id)
            invalidate_all_moderators_header_cache()
            action = mod_sound_form.cleaned_data.get("action")
            msg = msg_form.cleaned_data.get("message", False)
            moderator_only = msg_form.cleaned_data.get("moderator_only", False)

            if msg:
                tc = TicketComment(sender=ticket.assignee,
                                   text=msg,
                                   ticket=ticket,
                                   moderator_only=moderator_only)
                tc.save()

            if action == "Approve":
                ticket.status = TICKET_STATUS_CLOSED
                ticket.content.content_object.moderation_state = "OK"
                ticket.content.content_object.save()
                ticket.save()
                ticket.content.content_object.mark_index_dirty()
                if msg:
                    ticket.send_notification_emails(
                        Ticket.NOTIFICATION_APPROVED_BUT, Ticket.USER_ONLY)
                else:
                    ticket.send_notification_emails(
                        Ticket.NOTIFICATION_APPROVED, Ticket.USER_ONLY)
            elif action == "Defer":
                ticket.status = TICKET_STATUS_DEFERRED
                ticket.save()
                # only send a notification if a message was added
                if msg:
                    ticket.send_notification_emails(
                        Ticket.NOTIFICATION_QUESTION, Ticket.USER_ONLY)
            elif action == "Return":
                ticket.assignee = None
                ticket.status = TICKET_STATUS_NEW
                # no notification here
                ticket.save()
            elif action == "Delete":
                ticket.send_notification_emails(Ticket.NOTIFICATION_DELETED,
                                                Ticket.USER_ONLY)
                # to prevent a crash if the form is resubmitted
                if ticket.content:
                    ticket.content.content_object.delete()
                    ticket.content.delete()
                    ticket.content = None
                ticket.status = TICKET_STATUS_CLOSED
                ticket.save()
            elif action == "Whitelist":

                th = Thread(target=call_command,
                            args=(
                                'whitelist_user',
                                ticket.id,
                            ))
                th.start()
                ticket.send_notification_emails(
                    Ticket.NOTIFICATION_WHITELISTED, Ticket.USER_ONLY)

                messages.add_message(
                    request, messages.INFO,
                    'User %s has been whitelisted but some of his tickets might '
                    'still appear on this list for some time. Please reload the page in a few '
                    'seconds to see the updated list of pending tickets' %
                    ticket.sender.username)

        else:
            clear_forms = False
    if clear_forms:
        mod_sound_form = SoundModerationForm(initial={'action': 'Approve'})
        msg_form = ModerationMessageForm()

    qs = Ticket.objects.select_related() \
                       .filter(assignee=user_id) \
                       .exclude(status=TICKET_STATUS_CLOSED) \
                       .exclude(content=None) \
                       .order_by('status', '-created')
    paginaion_response = paginate(request, qs,
                                  MAX_TICKETS_IN_MODERATION_ASSIGNED_PAGE)
    paginaion_response['page'].object_list = list(
        paginaion_response['page'].object_list)
    for ticket in paginaion_response['page'].object_list:
        sound_id = ticket.content.object_id
        try:
            Sound.objects.get(id=sound_id)
        except:
            paginaion_response['page'].object_list.remove(ticket)
            try:
                # Try to delete ticket so error does not happen again
                ticket.delete()
            except:
                pass

    moderator_tickets_count = qs.count()
    moderation_texts = MODERATION_TEXTS
    show_pagination = moderator_tickets_count > MAX_TICKETS_IN_MODERATION_ASSIGNED_PAGE

    return render_to_response('tickets/moderation_assigned.html',
                              combine_dicts(paginaion_response, locals()),
                              context_instance=RequestContext(request))
Пример #23
0
def moderation_assigned(request, user_id):

    clear_forms = True
    if request.method == 'POST':
        mod_sound_form = SoundModerationForm(request.POST)
        msg_form = ModerationMessageForm(request.POST)

        if mod_sound_form.is_valid() and msg_form.is_valid():
            ticket_ids = mod_sound_form.cleaned_data.get("ticket", '').split('|')
            tickets = Ticket.objects.filter(id__in=ticket_ids)
            msg = msg_form.cleaned_data.get("message", False)
            action = mod_sound_form.cleaned_data.get("action")

            notification = None
            users_to_update = set()
            packs_to_update = set()

            if action == "Approve":
                tickets.update(status=TICKET_STATUS_CLOSED)
                Sound.objects.filter(ticket__in=tickets).update(
                        is_index_dirty=True,
                        moderation_state='OK',
                        moderation_date=datetime.datetime.now())
                if msg:
                    notification = Ticket.NOTIFICATION_APPROVED_BUT
                else:
                    notification = Ticket.NOTIFICATION_APPROVED

            elif action == "Defer":
                tickets.update(status=TICKET_STATUS_DEFERRED)

                # only send a notification if a message was added
                if msg:
                    notification = Ticket.NOTIFICATION_QUESTION

            elif action == "Return":
                tickets.update(status=TICKET_STATUS_NEW, assignee=None)
                # no notification here

            elif action == "Delete":
                # to prevent a crash if the form is resubmitted
                tickets.update(status=TICKET_STATUS_CLOSED)
                # if tickets are being deleted we have to fill users_to_update
                # and sounds_to_update before we delete the sounds and they dissapear
                # from the ticket (thus losing reference)
                for ticket in tickets:
                    users_to_update.add(ticket.sound.user.profile)
                    if ticket.sound.pack:
                        packs_to_update.add(ticket.sound.pack)
                Sound.objects.filter(ticket__in=tickets).delete()
                notification = Ticket.NOTIFICATION_DELETED

            elif action == "Whitelist":
                ticket_ids = list(tickets.values_list('id',flat=True))
                gm_client = gearman.GearmanClient(settings.GEARMAN_JOB_SERVERS)
                gm_client.submit_job("whitelist_user", json.dumps(ticket_ids),
                        wait_until_complete=False, background=True)
                notification = Ticket.NOTIFICATION_WHITELISTED

                users = set(tickets.values_list('sender__username', flat=True))
                messages.add_message(request, messages.INFO,
                    """User(s) %s has/have been whitelisted. Some of tickets might
                    still appear on this list for some time. Please reload the
                    page in a few seconds to see the updated list of pending
                    tickets""" % ", ".join(users))

            for ticket in tickets:
                if action != "Delete":
                    # We only fill here users_to_update and packs_to_update if action is not
                    # "Delete". See comment in "Delete" action case some lines above
                    users_to_update.add(ticket.sound.user.profile)
                    if ticket.sound.pack:
                        packs_to_update.add(ticket.sound.pack)
                invalidate_template_cache("user_header", ticket.sender.id)
                invalidate_all_moderators_header_cache()
                moderator_only = msg_form.cleaned_data.get("moderator_only", False)

                if msg:
                    tc = TicketComment(sender=ticket.assignee,
                                       text=msg,
                                       ticket=ticket,
                                       moderator_only=moderator_only)
                    tc.save()

                # Send emails
                if notification:
                    ticket.send_notification_emails(notification, Ticket.USER_ONLY)

            # Update number of sounds for each user
            for profile in users_to_update:
                profile.update_num_sounds()

            # Process packs
            for pack in packs_to_update:
                pack.process()
        else:
            clear_forms = False
    if clear_forms:
        mod_sound_form = SoundModerationForm(initial={'action': 'Approve'})
        msg_form = ModerationMessageForm()

    qs = Ticket.objects.select_related() \
                       .filter(assignee=user_id) \
                       .exclude(status=TICKET_STATUS_CLOSED) \
                       .exclude(sound=None) \
                       .order_by('status', '-created')
    pagination_response = paginate(request, qs, settings.MAX_TICKETS_IN_MODERATION_ASSIGNED_PAGE)
    pagination_response['page'].object_list = list(pagination_response['page'].object_list)
    # Because some tickets can have related sound which has disappeared or on deletion time the ticket
    # has not been properly updated, we need to check whether the sound that is related does in fact
    # exist. If it does not, we set the related sound to None and the status of the ticket to closed
    # as should have been set at sound deletion time.
    for ticket in pagination_response['page'].object_list:
        if not ticket.sound:
            pagination_response['page'].object_list.remove(ticket)
            ticket.status = TICKET_STATUS_CLOSED
            ticket.save()

    moderator_tickets_count = qs.count()
    moderation_texts = MODERATION_TEXTS
    show_pagination = moderator_tickets_count > settings.MAX_TICKETS_IN_MODERATION_ASSIGNED_PAGE

    tvars = {
            "moderator_tickets_count": moderator_tickets_count,
            "moderation_texts": moderation_texts,
            "page": pagination_response['page'],
            "paginator": pagination_response['paginator'],
            "current_page": pagination_response['current_page'],
            "show_pagination": show_pagination,
            "mod_sound_form": mod_sound_form,
            "msg_form": msg_form,
            "selected": "queue"
            }

    return render(request, 'tickets/moderation_assigned.html', tvars)
Пример #24
0
def new_message(request, username=None, message_id=None):
    
    if request.method == 'POST':

        if request.user.profile.num_sounds:
            form = MessageReplyFormNoCaptcha(request.POST)
        else:
            form = MessageReplyForm(request.POST)

        if request.user.profile.is_blocked_for_spam_reports():
            messages.add_message(request, messages.INFO, "You're not allowed to send the message because your account has been temporaly blocked after multiple spam reports")
        else:
            if form.is_valid():
                user_from = request.user
                user_to = form.cleaned_data["to"]
                subject = form.cleaned_data["subject"]
                body = MessageBody.objects.create(body=form.cleaned_data["body"])

                Message.objects.create(user_from=user_from, user_to=user_to, subject=subject, body=body, is_sent=True, is_archived=False, is_read=False)
                Message.objects.create(user_from=user_from, user_to=user_to, subject=subject, body=body, is_sent=False, is_archived=False, is_read=False)

                invalidate_template_cache("user_header", user_to.id)

                try:
                    # send the user an email to notify him of the sent message!
                    send_mail_template(u'you have a private message.', 'messages/email_new_message.txt', locals(), None, user_to.email)
                except:
                    # if the email sending fails, ignore...
                    pass

                return HttpResponseRedirect(reverse("messages"))
    else:
        if request.user.profile.num_sounds:
            form = MessageReplyFormNoCaptcha()
        else:
            form = MessageReplyForm()

        if message_id:
            try:
                message = Message.objects.get(id=message_id)

                if message.user_from != request.user and message.user_to != request.user:
                    raise Http404
                
                body = message.body.body.replace("\r\n", "\n").replace("\r", "\n")
                body = ''.join(BeautifulSoup(body).findAll(text=True))
                body = "\n".join([(">" if line.startswith(">") else "> ") + "\n> ".join(wrap(line.strip(),60)) for line in body.split("\n")])
                body = "> --- " + message.user_from.username + " wrote:\n>\n" + body
                
                subject = "re: " + message.subject
                to = message.user_from.username

                if request.user.profile.num_sounds:
                    form = MessageReplyFormNoCaptcha(initial=dict(to=to, subject=subject, body=body))
                else:
                    form = MessageReplyForm(initial=dict(to=to, subject=subject, body=body))
            except Message.DoesNotExist:
                pass
        elif username:
            if request.user.profile.num_sounds:
                form = MessageReplyFormNoCaptcha(initial=dict(to=username))
            else:
                form = MessageReplyForm(initial=dict(to=username))
    
    return render_to_response('messages/new.html', locals(), context_instance=RequestContext(request))
Пример #25
0
def ticket(request, ticket_key):
    can_view_moderator_only_messages = _can_view_mod_msg(request)
    clean_status_forms = True
    clean_comment_form = True
    ticket = get_object_or_404(Ticket, key=ticket_key)

    if request.method == 'POST':

        invalidate_template_cache("user_header", ticket.sender.id)
        invalidate_all_moderators_header_cache()

        # Left ticket message
        if is_selected(request, 'recaptcha') or (request.user.is_authenticated() and is_selected(request, 'message')):
            tc_form = _get_tc_form(request)
            if tc_form.is_valid():
                tc = TicketComment()
                tc.text = tc_form.cleaned_data['message']
                tc.moderator_only = tc_form.cleaned_data.get('moderator_only', False)
                if tc.text:
                    if request.user.is_authenticated():
                        tc.sender = request.user
                    tc.ticket = ticket
                    tc.save()
                    if not request.user.is_authenticated():
                        email_to = Ticket.MODERATOR_ONLY
                    elif request.user == ticket.sender:
                        email_to = Ticket.MODERATOR_ONLY
                    else:
                        email_to = Ticket.USER_ONLY
                    ticket.send_notification_emails(ticket.NOTIFICATION_UPDATED,
                                                    email_to)
            else:
                clean_comment_form = False
        # update sound ticket
        elif is_selected(request, 'tm') or is_selected(request, 'ss'):
            ticket_form = TicketModerationForm(request.POST, prefix="tm")
            sound_form = SoundStateForm(request.POST, prefix="ss")
            if ticket_form.is_valid() and sound_form.is_valid():
                clean_status_forms = True
                clean_comment_form = True
                sound_state = sound_form.cleaned_data.get('state')
                # Sound should be deleted
                if sound_state == 'DE':
                    if ticket.sound:
                        ticket.sound.delete()
                        ticket.sound = None
                    ticket.status = TICKET_STATUS_CLOSED
                    tc = TicketComment(sender=request.user,
                                       text="Moderator %s deleted the sound and closed the ticket" % request.user,
                                       ticket=ticket,
                                       moderator_only=False)
                    tc.save()
                    ticket.send_notification_emails(ticket.NOTIFICATION_DELETED,
                                                    ticket.USER_ONLY)
                # Set another sound state that's not delete
                else:
                    if ticket.sound:
                        ticket.sound.moderation_state = sound_state
                        # Mark the index as dirty so it'll be indexed in Solr
                        if sound_state == "OK":
                            ticket.sound.mark_index_dirty()
                        ticket.sound.save()
                    ticket.status = ticket_form.cleaned_data.get('status')
                    tc = TicketComment(sender=request.user,
                                       text="Moderator %s set the sound to %s and the ticket to %s." %
                                            (request.user,
                                             'pending' if sound_state == 'PE' else sound_state,
                                             ticket.status),
                                       ticket=ticket,
                                       moderator_only=False)
                    tc.save()
                    ticket.send_notification_emails(ticket.NOTIFICATION_UPDATED,
                                                    ticket.USER_ONLY)
                ticket.save()

    if clean_status_forms:
        ticket_form = TicketModerationForm(initial={'status': ticket.status}, prefix="tm")
        state = ticket.sound.moderation_state if ticket.sound else 'DE'
        sound_form = SoundStateForm(initial={'state': state}, prefix="ss")
    if clean_comment_form:
        tc_form = _get_tc_form(request, False)

    num_sounds_pending = ticket.sender.profile.num_sounds_pending_moderation()
    tvars = {"ticket": ticket,
             "num_sounds_pending": num_sounds_pending,
             "tc_form": tc_form,
             "ticket_form": ticket_form,
             "sound_form": sound_form,
             "can_view_moderator_only_messages": can_view_moderator_only_messages}
    return render(request, 'tickets/ticket.html', tvars)
Пример #26
0
def create_sound(user, sound_fields, apiv2_client=None, process=True, remove_exists=False):
    """
    This function is used by the upload handler to create a sound object with
    the information provided through sound_fields parameter.
    """

    # Import models using apps.get_model (to avoid circular dependencies)
    Sound = apps.get_model('sounds', 'Sound')
    License = apps.get_model('sounds', 'License')
    Pack = apps.get_model('sounds', 'Pack')

    # 1 make sound object
    sound = Sound()
    sound.user = user
    sound.original_filename = sound_fields['name']
    sound.original_path = sound_fields['dest_path']
    try:
        sound.filesize = os.path.getsize(sound.original_path)
    except OSError:
        raise NoAudioException()

    license = License.objects.get(name=sound_fields['license'])
    sound.type = get_sound_type(sound.original_path)
    sound.license = license
    sound.md5 = md5file(sound.original_path)

    sound_already_exists = Sound.objects.filter(md5=sound.md5).exists()
    if sound_already_exists:
        existing_sound = Sound.objects.get(md5=sound.md5)
        if remove_exists:
            existing_sound.delete()
        else:
            msg = 'The file %s is already part of freesound and has been discarded, see <a href="%s">here</a>.' % \
                    (sound_fields['name'], reverse('sound', args=[existing_sound.user.username, existing_sound.id]))

            # Remove file (including mirror locations)
            os.remove(sound.original_path)
            remove_uploaded_file_from_mirror_locations(sound.original_path)
            _remove_user_uploads_folder_if_empty(sound.user)

            raise AlreadyExistsException(msg)

    # 2 save
    sound.save()

    # Create corresponding SoundLicenseHistory object (can't be done before Sound is saved for the first time)
    sound.set_license(license)

    # 3 move to new path
    orig = os.path.splitext(os.path.basename(sound.original_filename))[0]  # WATCH OUT!
    sound.base_filename_slug = "%d__%s__%s" % (sound.id, slugify(sound.user.username), slugify(orig))
    new_original_path = sound.locations("path")
    if sound.original_path != new_original_path:
        try:
            os.makedirs(os.path.dirname(new_original_path))
        except OSError:
            pass
        try:
            shutil.move(sound.original_path, new_original_path)

            # Check if user upload folder still has files and remove if empty
            # NOTE: we first need to remove the file from the mirror locations as we do not perform
            # a 'move' operation there.
            remove_uploaded_file_from_mirror_locations(sound.original_path)
            _remove_user_uploads_folder_if_empty(sound.user)

        except IOError as e:
            raise CantMoveException("Failed to move file from %s to %s" % (sound.original_path, new_original_path))
        sound.original_path = new_original_path
        sound.save()

    # Copy to mirror location
    copy_sound_to_mirror_locations(sound)

    # 4 create pack if it does not exist
    if 'pack' in sound_fields:
        if sound_fields['pack']:
            if Pack.objects.filter(name=sound_fields['pack'], user=user).exclude(is_deleted=True).exists():
                p = Pack.objects.get(name=sound_fields['pack'], user=user)
            else:
                p, created = Pack.objects.get_or_create(user=user, name=sound_fields['pack'])
            sound.pack = p

    # 5 create geotag objects
    if 'geotag' in sound_fields:
        # Create geotag from lat,lon,zoom text format
        if sound_fields['geotag']:
            lat, lon, zoom = sound_fields['geotag'].split(',')
            geotag = GeoTag(user=user,
                            lat=float(lat),
                            lon=float(lon),
                            zoom=int(zoom))
            geotag.save()
            sound.geotag = geotag
    else:
        # Create geotag from lat, lon, zoom separated fields (if available)
        lat = sound_fields.get('lat', None)
        lon = sound_fields.get('lon', None)
        zoom = sound_fields.get('zoom', None)
        if lat is not None and lon is not None and zoom is not None:
            geotag = GeoTag(user=user,
                            lat=float(lat),
                            lon=float(lon),
                            zoom=int(zoom))
            geotag.save()
            sound.geotag = geotag

    # 6 set description, tags
    sound.description = sound_fields['description']
    sound.set_tags(sound_fields['tags'])

    if 'is_explicit' in sound_fields:
        sound.is_explicit = sound_fields['is_explicit']

    # 6.5 set uploaded apiv2 client
    sound.uploaded_with_apiv2_client = apiv2_client

    # 7 save!
    sound.save()

    # 8 create moderation tickets if needed
    if user.profile.is_whitelisted:
        sound.change_moderation_state('OK', do_not_update_related_stuff=True)
    else:
        # create moderation ticket!
        sound.create_moderation_ticket()
        invalidate_template_cache("user_header", user.id)
        moderators = Group.objects.get(name='moderators').user_set.all()
        for moderator in moderators:
            invalidate_template_cache("user_header", moderator.id)

    # 9 process sound and packs
    sound.compute_crc()

    if process:
        try:
            sound.process()

            if sound.pack:
                sound.pack.process()
        except ServerUnavailable:
            pass

    return sound
Пример #27
0
def new_message(request, username=None, message_id=None):

    if request.method == 'POST':

        if request.user.profile.num_sounds:
            form = MessageReplyFormNoCaptcha(request.POST)
        else:
            form = MessageReplyForm(request.POST)

        if request.user.profile.is_blocked_for_spam_reports():
            messages.add_message(
                request, messages.INFO,
                "You're not allowed to send the message because your account has been temporaly blocked after multiple spam reports"
            )
        else:
            if form.is_valid():
                user_from = request.user
                user_to = form.cleaned_data["to"]
                subject = form.cleaned_data["subject"]
                body = MessageBody.objects.create(
                    body=form.cleaned_data["body"])

                Message.objects.create(user_from=user_from,
                                       user_to=user_to,
                                       subject=subject,
                                       body=body,
                                       is_sent=True,
                                       is_archived=False,
                                       is_read=False)
                Message.objects.create(user_from=user_from,
                                       user_to=user_to,
                                       subject=subject,
                                       body=body,
                                       is_sent=False,
                                       is_archived=False,
                                       is_read=False)

                invalidate_template_cache("user_header", user_to.id)

                try:
                    # send the user an email to notify him of the sent message!
                    send_mail_template(u'you have a private message.',
                                       'messages/email_new_message.txt',
                                       locals(), None, user_to.email)
                except:
                    # if the email sending fails, ignore...
                    pass

                return HttpResponseRedirect(reverse("messages"))
    else:
        if request.user.profile.num_sounds:
            form = MessageReplyFormNoCaptcha()
        else:
            form = MessageReplyForm()

        if message_id:
            try:
                message = Message.objects.get(id=message_id)

                if message.user_from != request.user and message.user_to != request.user:
                    raise Http404

                body = message.body.body.replace("\r\n",
                                                 "\n").replace("\r", "\n")
                body = ''.join(BeautifulSoup(body).findAll(text=True))
                body = "\n".join([(">" if line.startswith(">") else "> ") +
                                  "\n> ".join(wrap(line.strip(), 60))
                                  for line in body.split("\n")])
                body = "> --- " + message.user_from.username + " wrote:\n>\n" + body

                subject = "re: " + message.subject
                to = message.user_from.username

                if request.user.profile.num_sounds:
                    form = MessageReplyFormNoCaptcha(
                        initial=dict(to=to, subject=subject, body=body))
                else:
                    form = MessageReplyForm(
                        initial=dict(to=to, subject=subject, body=body))
            except Message.DoesNotExist:
                pass
        elif username:
            if request.user.profile.num_sounds:
                form = MessageReplyFormNoCaptcha(initial=dict(to=username))
            else:
                form = MessageReplyForm(initial=dict(to=username))

    return render_to_response('messages/new.html',
                              locals(),
                              context_instance=RequestContext(request))
Пример #28
0
def ticket(request, ticket_key):
    can_view_moderator_only_messages = _can_view_mod_msg(request)
    clean_status_forms = True
    clean_comment_form = True
    ticket = get_object_or_404(Ticket.objects.select_related(
        'sound__license', 'sound__user'),
                               key=ticket_key)

    if request.method == 'POST':

        invalidate_template_cache("user_header", ticket.sender.id)
        invalidate_all_moderators_header_cache()

        # Left ticket message
        if is_selected(request,
                       'recaptcha') or (request.user.is_authenticated
                                        and is_selected(request, 'message')):
            tc_form = _get_tc_form(request)
            if tc_form.is_valid():
                tc = TicketComment()
                tc.text = tc_form.cleaned_data['message']
                tc.moderator_only = tc_form.cleaned_data.get(
                    'moderator_only', False)
                if tc.text:
                    if request.user.is_authenticated:
                        tc.sender = request.user
                    tc.ticket = ticket
                    tc.save()
                    if not request.user.is_authenticated:
                        email_to = Ticket.MODERATOR_ONLY
                    elif request.user == ticket.sender:
                        email_to = Ticket.MODERATOR_ONLY
                    else:
                        email_to = Ticket.USER_ONLY
                    ticket.send_notification_emails(
                        ticket.NOTIFICATION_UPDATED, email_to)
            else:
                clean_comment_form = False
        # update sound ticket
        elif is_selected(request, 'ss'):
            sound_form = SoundStateForm(request.POST, prefix='ss')
            if sound_form.is_valid():
                clean_status_forms = True
                clean_comment_form = True
                sound_action = sound_form.cleaned_data.get('action')
                comment = 'Moderator {} '.format(request.user)
                notification = None

                # If there is no one assigned, then changing the state self-assigns the ticket
                if ticket.assignee is None:
                    ticket.assignee = request.user

                if sound_action == 'Delete':
                    if ticket.sound:
                        ticket.sound.delete()
                        ticket.sound = None
                    ticket.status = TICKET_STATUS_CLOSED
                    comment += 'deleted the sound and closed the ticket'
                    notification = ticket.NOTIFICATION_DELETED

                elif sound_action == 'Defer':
                    ticket.status = TICKET_STATUS_DEFERRED
                    ticket.sound.change_moderation_state(
                        'PE')  # not sure if this state have been used before
                    comment += 'deferred the ticket'

                elif sound_action == "Return":
                    ticket.status = TICKET_STATUS_NEW
                    ticket.assignee = None
                    ticket.sound.change_moderation_state('PE')
                    comment += 'returned the ticket to new sounds queue'

                elif sound_action == 'Approve':
                    ticket.status = TICKET_STATUS_CLOSED
                    ticket.sound.change_moderation_state('OK')
                    comment += 'approved the sound and closed the ticket'
                    notification = ticket.NOTIFICATION_APPROVED

                elif sound_action == 'Whitelist':
                    _whitelist_gearman([
                        ticket.id
                    ])  # async job should take care of whitelisting
                    comment += 'whitelisted all sounds from user {}'.format(
                        ticket.sender)
                    notification = ticket.NOTIFICATION_WHITELISTED

                if notification is not None:
                    ticket.send_notification_emails(notification,
                                                    ticket.USER_ONLY)

                if ticket.sound is not None:
                    ticket.sound.save()

                ticket.save()
                tc = TicketComment(sender=request.user,
                                   text=comment,
                                   ticket=ticket,
                                   moderator_only=False)
                tc.save()

    if clean_status_forms:
        default_action = 'Return' if ticket.sound and ticket.sound.moderation_state == 'OK' else 'Approve'
        sound_form = SoundStateForm(initial={'action': default_action},
                                    prefix="ss")
    if clean_comment_form:
        tc_form = _get_tc_form(request, False)

    num_sounds_pending = ticket.sender.profile.num_sounds_pending_moderation()
    tvars = {
        "ticket": ticket,
        "num_sounds_pending": num_sounds_pending,
        "tc_form": tc_form,
        "sound_form": sound_form,
        "can_view_moderator_only_messages": can_view_moderator_only_messages
    }
    return render(request, 'tickets/ticket.html', tvars)
Пример #29
0
def moderation_assigned(request, user_id):

    clear_forms = True
    mod_sound_form = None
    msg_form = None
    if request.method == 'POST':
        mod_sound_form = SoundModerationForm(request.POST)
        msg_form = ModerationMessageForm(request.POST)

        if mod_sound_form.is_valid() and msg_form.is_valid():

            ticket_ids = mod_sound_form.cleaned_data.get("ticket",
                                                         '').split('|')
            tickets = Ticket.objects.filter(id__in=ticket_ids)
            msg = msg_form.cleaned_data.get("message", False)
            action = mod_sound_form.cleaned_data.get("action")

            notification = None
            users_to_update = set()
            packs_to_update = set()

            if action == "Approve":
                tickets.update(status=TICKET_STATUS_CLOSED)
                sounds_update_params = {
                    'is_index_dirty': True,
                    'moderation_state': 'OK',
                    'moderation_date': datetime.datetime.now()
                }
                is_explicit_choice_key = mod_sound_form.cleaned_data.get(
                    "is_explicit")
                if is_explicit_choice_key == IS_EXPLICIT_ADD_FLAG_KEY:
                    sounds_update_params['is_explicit'] = True
                elif is_explicit_choice_key == IS_EXPLICIT_REMOVE_FLAG_KEY:
                    sounds_update_params['is_explicit'] = False

                # Otherwise is_explicit_choice_key = IS_EXPLICIT_KEEP_USER_PREFERENCE_KEY, don't update the
                # 'is_explicit' field and leave it as the user originally set it

                Sound.objects.filter(ticket__in=tickets).update(
                    **sounds_update_params)

                if msg:
                    notification = Ticket.NOTIFICATION_APPROVED_BUT
                else:
                    notification = Ticket.NOTIFICATION_APPROVED

            elif action == "Defer":
                tickets.update(status=TICKET_STATUS_DEFERRED)

                # only send a notification if a message was added
                if msg:
                    notification = Ticket.NOTIFICATION_QUESTION

            elif action == "Return":
                tickets.update(status=TICKET_STATUS_NEW, assignee=None)
                # no notification here

            elif action == "Delete":
                # to prevent a crash if the form is resubmitted
                tickets.update(status=TICKET_STATUS_CLOSED)
                # if tickets are being deleted we have to fill users_to_update
                # and sounds_to_update before we delete the sounds and they dissapear
                # from the ticket (thus losing reference)
                for ticket in tickets:
                    users_to_update.add(ticket.sound.user.profile)
                    if ticket.sound.pack:
                        packs_to_update.add(ticket.sound.pack)
                Sound.objects.filter(ticket__in=tickets).delete()
                # After we delete sounds that these tickets are associated with,
                # we refresh the ticket list so that sound_id is null and this does
                # not affect the TicketComment post_save trigger
                tickets = Ticket.objects.filter(id__in=ticket_ids)
                notification = Ticket.NOTIFICATION_DELETED

            elif action == "Whitelist":
                ticket_ids = list(tickets.values_list('id', flat=True))
                _whitelist_gearman(ticket_ids)
                notification = Ticket.NOTIFICATION_WHITELISTED

                users = set(tickets.values_list('sender__username', flat=True))
                messages.add_message(
                    request, messages.INFO,
                    """User(s) %s has/have been whitelisted. Some of tickets might
                    still appear on this list for some time. Please reload the
                    page in a few seconds to see the updated list of pending
                    tickets""" % ", ".join(users))

            for ticket in tickets:
                if action != "Delete":
                    # We only fill here users_to_update and packs_to_update if action is not
                    # "Delete". See comment in "Delete" action case some lines above
                    users_to_update.add(ticket.sound.user.profile)
                    if ticket.sound.pack:
                        packs_to_update.add(ticket.sound.pack)
                invalidate_template_cache("user_header", ticket.sender.id)
                invalidate_all_moderators_header_cache()
                moderator_only = msg_form.cleaned_data.get(
                    "moderator_only", False)

                if msg:
                    tc = TicketComment(sender=ticket.assignee,
                                       text=msg,
                                       ticket=ticket,
                                       moderator_only=moderator_only)
                    tc.save()

                # Send emails
                if notification:
                    ticket.send_notification_emails(notification,
                                                    Ticket.USER_ONLY)

            # Update number of sounds for each user
            for profile in users_to_update:
                profile.update_num_sounds()

            # Process packs
            for pack in packs_to_update:
                pack.process()
        else:
            clear_forms = False
    if clear_forms:
        mod_sound_form = SoundModerationForm(initial={'action': 'Approve'})
        msg_form = ModerationMessageForm()

    qs = Ticket.objects.select_related('sound') \
                       .filter(assignee=user_id) \
                       .exclude(status=TICKET_STATUS_CLOSED) \
                       .exclude(sound=None) \
                       .order_by('status', '-created')
    pagination_response = paginate(
        request, qs, settings.MAX_TICKETS_IN_MODERATION_ASSIGNED_PAGE)
    pagination_response['page'].object_list = list(
        pagination_response['page'].object_list)
    # Because some tickets can have related sound which has disappeared or on deletion time the ticket
    # has not been properly updated, we need to check whether the sound that is related does in fact
    # exist. If it does not, we set the related sound to None and the status of the ticket to closed
    # as should have been set at sound deletion time.
    for ticket in pagination_response['page'].object_list:
        if not ticket.sound:
            pagination_response['page'].object_list.remove(ticket)
            ticket.status = TICKET_STATUS_CLOSED
            ticket.save()

    moderator_tickets_count = qs.count()
    show_pagination = moderator_tickets_count > settings.MAX_TICKETS_IN_MODERATION_ASSIGNED_PAGE

    tvars = {
        "moderator_tickets_count": moderator_tickets_count,
        "moderation_texts": MODERATION_TEXTS,
        "page": pagination_response['page'],
        "paginator": pagination_response['paginator'],
        "current_page": pagination_response['current_page'],
        "show_pagination": show_pagination,
        "max_selected_tickets_in_right_panel":
        settings.MAX_TICKETS_IN_MODERATION_ASSIGNED_PAGE_SELECTED_COLUMN,
        "mod_sound_form": mod_sound_form,
        "msg_form": msg_form,
        "default_autoplay": request.GET.get('autoplay', 'on') == 'on',
        "default_include_deferred": request.GET.get('include_d', '') == 'on',
    }

    return render(request, 'tickets/moderation_assigned.html', tvars)
Пример #30
0
    sound.set_tags(clean_and_split_tags(sound_fields['tags']))
    #sound.set_tags([t.lower() for t in sound_fields['tags'].split(" ") if t])

    # 8.5 set uploaded apiv2 client
    sound.uploaded_with_apiv2_client = apiv2_client

    # 9 save!
    sound.save()

    # 10 create moderation tickets if needed
    if user.profile.is_whitelisted:
        sound.change_moderation_state('OK', do_not_update_related_stuff=True)
    else:
        # create moderation ticket!
        sound.create_moderation_ticket()
        invalidate_template_cache("user_header", user.id)
        moderators = Group.objects.get(name='moderators').user_set.all()
        for moderator in moderators:
            invalidate_template_cache("user_header", moderator.id)

    # 11 proces sound and packs
    try:
        sound.compute_crc()
    except:
        pass

    transaction.commit()  # Need to commit transaction manually so that worker can find the sound in db
    try:
        sound.process()

        if sound.pack:
Пример #31
0
def invalidate_all_moderators_header_cache():
    mods = Group.objects.get(name='moderators').user_set.all()
    for mod in mods:
        invalidate_template_cache("user_header", mod.id)
Пример #32
0
 def invalidate_sound_cache(sound):
     invalidate_template_cache("sound_header", sound.id, True)
     invalidate_template_cache("sound_header", sound.id, False)
     invalidate_template_cache("sound_footer_top", sound.id)
     invalidate_template_cache("sound_footer_bottom", sound.id)
     invalidate_template_cache("display_sound", sound.id, True, sound.processing_state, sound.moderation_state)
     invalidate_template_cache("display_sound", sound.id, False, sound.processing_state, sound.moderation_state)
Пример #33
0
        ticket.source = TICKET_SOURCE_NEW_SOUND
        ticket.status = TICKET_STATUS_NEW
        ticket.queue = Queue.objects.get(name='sound moderation')
        ticket.sender = user
        lc = LinkedContent()
        lc.content_object = sound
        lc.save()
        ticket.content = lc
        ticket.save()
        tc = TicketComment()
        tc.sender = user
        tc.text = "I've uploaded %s. Please moderate!" % sound.original_filename
        tc.ticket = ticket
        tc.save()

        invalidate_template_cache("user_header", ticket.sender.id)
        moderators = Group.objects.get(name='moderators').user_set.all()
        for moderator in moderators:
            invalidate_template_cache("user_header", moderator.id)

    # 11 proces
    try:
        sound.compute_crc()
    except:
        pass

    try:
        sound.process()
    except Exception, e:
        # Log that sound could not be processed, but do not throw any exception
        request_info = basic_request_info_for_log_message(resource.auth_method_name, resource.developer, resource.user, resource.client_id, resource.end_user_ip)
Пример #34
0
        ticket.source = TICKET_SOURCE_NEW_SOUND
        ticket.status = TICKET_STATUS_NEW
        ticket.queue = Queue.objects.get(name='sound moderation')
        ticket.sender = user
        lc = LinkedContent()
        lc.content_object = sound
        lc.save()
        ticket.content = lc
        ticket.save()
        tc = TicketComment()
        tc.sender = user
        tc.text = "I've uploaded %s. Please moderate!" % sound.original_filename
        tc.ticket = ticket
        tc.save()

        invalidate_template_cache("user_header", ticket.sender.id)
        moderators = Group.objects.get(name='moderators').user_set.all()
        for moderator in moderators:
            invalidate_template_cache("user_header", moderator.id)

    # 11 proces
    try:
        sound.compute_crc()
    except:
        pass

    try:
        sound.process()
    except Exception, e:
        # Log that sound could not be processed, but do not throw any exception
        request_info = basic_request_info_for_log_message(
Пример #35
0
def invalidate_all_moderators_header_cache():
    mods = Group.objects.get(name='moderators').user_set.all()
    for mod in mods:
        invalidate_template_cache("user_header", mod.id)
Пример #36
0
def create_sound(user,
                 sound_fields,
                 apiv2_client=None,
                 bulk_upload_progress=None,
                 process=True,
                 remove_exists=False):
    """
    This function is used to create sound objects uploaded via the sound describe form, the API or the bulk describe
    feature.

    Args:
        user (User): user that will appear as the uploader of the sound (author)
        sound_fields (dict): dictionary with data to populate the different fields of the sound object. Check example
            usages of create_sound for more information about what are these fields and their expected format
        apiv2_client (ApiV2Client): ApiV2Client object corresponding to the API account that triggered the creation
            of that sound object (if not provided, will be set to None)
        bulk_upload_progress (BulkUploadProgress): BulkUploadProgress object corresponding to the bulk upload progress
            that triggered the creation of this sound object (if not provided, will be set to None)
        process (bool): whether to trigger processing and analysis of the sound object after being created
            (defaults to True)
        remove_exists (bool): if the sound we're trying to create an object for already exists (according to
            md5 check), delete it (defaults to False)

    Returns:
        Sound: returns the created Sound object
    """

    # Import models using apps.get_model (to avoid circular dependencies)
    Sound = apps.get_model('sounds', 'Sound')
    License = apps.get_model('sounds', 'License')
    Pack = apps.get_model('sounds', 'Pack')

    # 1 make sound object
    sound = Sound()
    sound.user = user
    sound.original_filename = sound_fields['name']
    sound.original_path = sound_fields['dest_path']
    try:
        sound.filesize = os.path.getsize(sound.original_path)
    except OSError:
        raise NoAudioException()

    license = License.objects.get(name=sound_fields['license'])
    sound.type = get_sound_type(sound.original_path)
    sound.license = license
    sound.md5 = md5file(sound.original_path)

    sound_already_exists = Sound.objects.filter(md5=sound.md5).exists()
    if sound_already_exists:
        existing_sound = Sound.objects.get(md5=sound.md5)
        if remove_exists:
            existing_sound.delete()
        else:
            msg = 'The file %s is already part of freesound and has been discarded, see <a href="%s">here</a>.' % \
                    (sound_fields['name'], reverse('sound', args=[existing_sound.user.username, existing_sound.id]))

            # Remove file (including mirror locations)
            os.remove(sound.original_path)
            remove_uploaded_file_from_mirror_locations(sound.original_path)
            _remove_user_uploads_folder_if_empty(sound.user)

            raise AlreadyExistsException(msg)

    # 2 save
    sound.save()

    # Create corresponding SoundLicenseHistory object (can't be done before Sound is saved for the first time)
    sound.set_license(license)

    # 3 move to new path
    orig = os.path.splitext(os.path.basename(
        sound.original_filename))[0]  # WATCH OUT!
    sound.base_filename_slug = "%d__%s__%s" % (
        sound.id, slugify(sound.user.username), slugify(orig))
    new_original_path = sound.locations("path")
    if sound.original_path != new_original_path:
        create_directories(os.path.dirname(new_original_path), exist_ok=True)
        try:
            shutil.move(sound.original_path, new_original_path)

            # Check if user upload folder still has files and remove if empty
            # NOTE: we first need to remove the file from the mirror locations as we do not perform
            # a 'move' operation there.
            remove_uploaded_file_from_mirror_locations(sound.original_path)
            _remove_user_uploads_folder_if_empty(sound.user)

        except IOError as e:
            raise CantMoveException("Failed to move file from %s to %s" %
                                    (sound.original_path, new_original_path))
        sound.original_path = new_original_path
        sound.save()

    # Copy to mirror location
    copy_sound_to_mirror_locations(sound)

    # 4 create pack if it does not exist
    if 'pack' in sound_fields:
        if sound_fields['pack']:
            if Pack.objects.filter(
                    name=sound_fields['pack'],
                    user=user).exclude(is_deleted=True).exists():
                p = Pack.objects.get(name=sound_fields['pack'], user=user)
            else:
                p, created = Pack.objects.get_or_create(
                    user=user, name=sound_fields['pack'])
            sound.pack = p

    # 5 create geotag objects
    if 'geotag' in sound_fields:
        # Create geotag from lat,lon,zoom text format
        if sound_fields['geotag']:
            lat, lon, zoom = sound_fields['geotag'].split(',')
            geotag = GeoTag(user=user,
                            lat=float(lat),
                            lon=float(lon),
                            zoom=int(zoom))
            geotag.save()
            sound.geotag = geotag
    else:
        # Create geotag from lat, lon, zoom separated fields (if available)
        lat = sound_fields.get('lat', None)
        lon = sound_fields.get('lon', None)
        zoom = sound_fields.get('zoom', None)
        if lat is not None and lon is not None and zoom is not None:
            geotag = GeoTag(user=user,
                            lat=float(lat),
                            lon=float(lon),
                            zoom=int(zoom))
            geotag.save()
            sound.geotag = geotag

    # 6 set description, tags
    sound.description = remove_control_chars(sound_fields['description'])
    sound.set_tags(sound_fields['tags'])

    if 'is_explicit' in sound_fields:
        sound.is_explicit = sound_fields['is_explicit']

    # 6.5 set uploaded apiv2 client or bulk progress object (if any)
    sound.uploaded_with_apiv2_client = apiv2_client
    sound.uploaded_with_bulk_upload_progress = bulk_upload_progress

    # 7 save!
    sound.save()

    # 8 create moderation tickets if needed
    if user.profile.is_whitelisted:
        sound.change_moderation_state('OK')
    else:
        # create moderation ticket!
        sound.create_moderation_ticket()
        invalidate_template_cache("user_header", user.id)
        moderators = Group.objects.get(name='moderators').user_set.all()
        for moderator in moderators:
            invalidate_template_cache("user_header", moderator.id)

    # 9 process sound and packs
    sound.compute_crc()

    if process:
        try:
            sound.process_and_analyze(high_priority=True)

            if sound.pack:
                sound.pack.process()
        except ServerUnavailable:
            pass

    # Log
    if sound.uploaded_with_apiv2_client is not None:
        upload_source = 'api'
    elif sound.uploaded_with_bulk_upload_progress is not None:
        upload_source = 'bulk'
    else:
        upload_source = 'web'
    sounds_logger.info('Created Sound object (%s)' %
                       json.dumps({
                           'sound_id': sound.id,
                           'username': sound.user.username,
                           'upload_source': upload_source,
                       }))

    return sound
Пример #37
0
def moderation_assigned(request, user_id):

    can_view_moderator_only_messages = _can_view_mod_msg(request)
    clear_forms = True
    if request.method == 'POST':
        mod_sound_form = SoundModerationForm(request.POST)
        msg_form = ModerationMessageForm(request.POST)

        if mod_sound_form.is_valid() and msg_form.is_valid():

            ticket = Ticket.objects.get(
                id=mod_sound_form.cleaned_data.get("ticket", False))
            invalidate_template_cache("user_header", ticket.sender.id)
            invalidate_all_moderators_header_cache()
            action = mod_sound_form.cleaned_data.get("action")
            msg = msg_form.cleaned_data.get("message", False)
            moderator_only = msg_form.cleaned_data.get("moderator_only", False)

            if msg:
                tc = TicketComment(sender=ticket.assignee,
                                   text=msg,
                                   ticket=ticket,
                                   moderator_only=moderator_only)
                tc.save()

            if action == "Approve":
                ticket.status = TICKET_STATUS_CLOSED
                ticket.content.content_object.change_moderation_state(
                    "OK")  # change_moderation_state does the saving
                ticket.save()
                ticket.content.content_object.mark_index_dirty()
                if msg:
                    ticket.send_notification_emails(
                        Ticket.NOTIFICATION_APPROVED_BUT, Ticket.USER_ONLY)
                else:
                    ticket.send_notification_emails(
                        Ticket.NOTIFICATION_APPROVED, Ticket.USER_ONLY)
            elif action == "Defer":
                ticket.status = TICKET_STATUS_DEFERRED
                ticket.save()
                # only send a notification if a message was added
                if msg:
                    ticket.send_notification_emails(
                        Ticket.NOTIFICATION_QUESTION, Ticket.USER_ONLY)
            elif action == "Return":
                ticket.assignee = None
                ticket.status = TICKET_STATUS_NEW
                # no notification here
                ticket.save()
            elif action == "Delete":
                ticket.send_notification_emails(Ticket.NOTIFICATION_DELETED,
                                                Ticket.USER_ONLY)
                # to prevent a crash if the form is resubmitted
                if ticket.content:
                    ticket.content.content_object.delete()
                    ticket.content.delete()
                    ticket.content = None
                ticket.status = TICKET_STATUS_CLOSED
                ticket.save()
            elif action == "Whitelist":
                th = Thread(target=call_command,
                            args=(
                                'whitelist_user',
                                "%i" % ticket.id,
                            ))
                th.start()
                ticket.send_notification_emails(
                    Ticket.NOTIFICATION_WHITELISTED, Ticket.USER_ONLY)

                messages.add_message(
                    request, messages.INFO,
                    """User %s has been whitelisted but some of their tickets might
                                     still appear on this list for some time. Please reload the page in a few
                                     seconds to see the updated list of pending tickets"""
                    % ticket.sender.username)

        else:
            clear_forms = False
    if clear_forms:
        mod_sound_form = SoundModerationForm(initial={'action': 'Approve'})
        msg_form = ModerationMessageForm()

    qs = Ticket.objects.select_related() \
                       .filter(assignee=user_id) \
                       .exclude(status=TICKET_STATUS_CLOSED) \
                       .exclude(content=None) \
                       .order_by('status', '-created')
    pagination_response = paginate(
        request, qs, settings.MAX_TICKETS_IN_MODERATION_ASSIGNED_PAGE)
    pagination_response['page'].object_list = list(
        pagination_response['page'].object_list)
    # Because some tickets can have linked content which has disappeared or on deletion time the ticket
    # has not been properly updated, we need to check whether the sound that is linked does in fact exist. If it does
    # not, we set the linked content to None and the status of the ticket to closed as should have been set at sound
    # deletion time.
    for ticket in pagination_response['page'].object_list:
        sound_id = ticket.content.object_id
        try:
            Sound.objects.get(id=sound_id)
        except Sound.DoesNotExist:
            pagination_response['page'].object_list.remove(ticket)
            ticket.content = None
            ticket.status = TICKET_STATUS_CLOSED
            ticket.save()

    moderator_tickets_count = qs.count()
    moderation_texts = MODERATION_TEXTS
    show_pagination = moderator_tickets_count > settings.MAX_TICKETS_IN_MODERATION_ASSIGNED_PAGE

    tvars = locals()
    tvars.update(pagination_response)

    return render(request, 'tickets/moderation_assigned.html', tvars)
Пример #38
0
def moderation_assigned(request, user_id):

    clear_forms = True
    if request.method == 'POST':
        mod_sound_form = SoundModerationForm(request.POST)
        msg_form = ModerationMessageForm(request.POST)

        if mod_sound_form.is_valid() and msg_form.is_valid():
            ticket_ids = mod_sound_form.cleaned_data.get("ticket",
                                                         '').split('|')
            tickets = Ticket.objects.filter(id__in=ticket_ids)
            msg = msg_form.cleaned_data.get("message", False)
            action = mod_sound_form.cleaned_data.get("action")

            notification = None
            users_to_update = set()
            packs_to_update = set()

            if action == "Approve":
                tickets.update(status=TICKET_STATUS_CLOSED)
                Sound.objects.filter(ticket__in=tickets).update(
                    is_index_dirty=True,
                    moderation_state='OK',
                    moderation_date=datetime.datetime.now())
                if msg:
                    notification = Ticket.NOTIFICATION_APPROVED_BUT
                else:
                    notification = Ticket.NOTIFICATION_APPROVED

            elif action == "Defer":
                tickets.update(status=TICKET_STATUS_DEFERRED)

                # only send a notification if a message was added
                if msg:
                    notification = Ticket.NOTIFICATION_QUESTION

            elif action == "Return":
                tickets.update(status=TICKET_STATUS_NEW, assignee=None)
                # no notification here

            elif action == "Delete":
                # to prevent a crash if the form is resubmitted
                tickets.update(status=TICKET_STATUS_CLOSED)
                # if tickets are being deleted we have to fill users_to_update
                # and sounds_to_update before we delete the sounds and they dissapear
                # from the ticket (thus losing reference)
                for ticket in tickets:
                    users_to_update.add(ticket.sound.user.profile)
                    if ticket.sound.pack:
                        packs_to_update.add(ticket.sound.pack)
                Sound.objects.filter(ticket__in=tickets).delete()
                notification = Ticket.NOTIFICATION_DELETED

            elif action == "Whitelist":
                ticket_ids = list(tickets.values_list('id', flat=True))
                gm_client = gearman.GearmanClient(settings.GEARMAN_JOB_SERVERS)
                gm_client.submit_job("whitelist_user",
                                     json.dumps(ticket_ids),
                                     wait_until_complete=False,
                                     background=True)
                notification = Ticket.NOTIFICATION_WHITELISTED

                users = set(tickets.values_list('sender__username', flat=True))
                messages.add_message(
                    request, messages.INFO,
                    """User(s) %s has/have been whitelisted. Some of tickets might
                    still appear on this list for some time. Please reload the
                    page in a few seconds to see the updated list of pending
                    tickets""" % ", ".join(users))

            for ticket in tickets:
                if action != "Delete":
                    # We only fill here users_to_update and packs_to_update if action is not
                    # "Delete". See comment in "Delete" action case some lines above
                    users_to_update.add(ticket.sound.user.profile)
                    if ticket.sound.pack:
                        packs_to_update.add(ticket.sound.pack)
                invalidate_template_cache("user_header", ticket.sender.id)
                invalidate_all_moderators_header_cache()
                moderator_only = msg_form.cleaned_data.get(
                    "moderator_only", False)

                if msg:
                    tc = TicketComment(sender=ticket.assignee,
                                       text=msg,
                                       ticket=ticket,
                                       moderator_only=moderator_only)
                    tc.save()

                # Send emails
                if notification:
                    ticket.send_notification_emails(notification,
                                                    Ticket.USER_ONLY)

            # Update number of sounds for each user
            for profile in users_to_update:
                profile.update_num_sounds()

            # Process packs
            for pack in packs_to_update:
                pack.process()
        else:
            clear_forms = False
    if clear_forms:
        mod_sound_form = SoundModerationForm(initial={'action': 'Approve'})
        msg_form = ModerationMessageForm()

    qs = Ticket.objects.select_related() \
                       .filter(assignee=user_id) \
                       .exclude(status=TICKET_STATUS_CLOSED) \
                       .exclude(sound=None) \
                       .order_by('status', '-created')
    pagination_response = paginate(
        request, qs, settings.MAX_TICKETS_IN_MODERATION_ASSIGNED_PAGE)
    pagination_response['page'].object_list = list(
        pagination_response['page'].object_list)
    # Because some tickets can have related sound which has disappeared or on deletion time the ticket
    # has not been properly updated, we need to check whether the sound that is related does in fact
    # exist. If it does not, we set the related sound to None and the status of the ticket to closed
    # as should have been set at sound deletion time.
    for ticket in pagination_response['page'].object_list:
        if not ticket.sound:
            pagination_response['page'].object_list.remove(ticket)
            ticket.status = TICKET_STATUS_CLOSED
            ticket.save()

    moderator_tickets_count = qs.count()
    moderation_texts = MODERATION_TEXTS
    show_pagination = moderator_tickets_count > settings.MAX_TICKETS_IN_MODERATION_ASSIGNED_PAGE

    tvars = {
        "moderator_tickets_count": moderator_tickets_count,
        "moderation_texts": moderation_texts,
        "page": pagination_response['page'],
        "paginator": pagination_response['paginator'],
        "current_page": pagination_response['current_page'],
        "show_pagination": show_pagination,
        "mod_sound_form": mod_sound_form,
        "msg_form": msg_form,
        "selected": "queue"
    }

    return render(request, 'tickets/moderation_assigned.html', tvars)
Пример #39
0
def ticket(request, ticket_key):
    can_view_moderator_only_messages = _can_view_mod_msg(request)
    clean_status_forms = True
    clean_comment_form = True
    ticket = get_object_or_404(Ticket, key=ticket_key)
    if ticket.content:
        # Becuase it can happen that some tickets have linked content which has dissapeared or on deletion time the ticket
        # has not been propertly updated, we need to check whether the sound that is linked does in fact exist. If it does
        # not, we set the linked content to None and the status of the ticket to closed as should have been set at sound
        # deletion time.
        sound_id = ticket.content.object_id
        try:
            Sound.objects.get(id=sound_id)
        except Sound.DoesNotExist:
            ticket.content = None
            ticket.status = TICKET_STATUS_CLOSED
            ticket.save()

    if request.method == 'POST':

        invalidate_template_cache("user_header", ticket.sender.id)
        invalidate_all_moderators_header_cache()

        # Left ticket message
        if is_selected(request,
                       'recaptcha') or (request.user.is_authenticated()
                                        and is_selected(request, 'message')):
            tc_form = _get_tc_form(request)
            if tc_form.is_valid():
                tc = TicketComment()
                tc.text = tc_form.cleaned_data['message']
                tc.moderator_only = tc_form.cleaned_data.get(
                    'moderator_only', False)
                if tc.text:
                    if request.user.is_authenticated():
                        tc.sender = request.user
                    tc.ticket = ticket
                    tc.save()
                    if not request.user.is_authenticated():
                        email_to = Ticket.MODERATOR_ONLY
                    elif request.user == ticket.sender:
                        email_to = Ticket.MODERATOR_ONLY
                    else:
                        email_to = Ticket.USER_ONLY
                    ticket.send_notification_emails(
                        ticket.NOTIFICATION_UPDATED, email_to)
            else:
                clean_comment_form = False
        # update sound ticket
        elif is_selected(request, 'tm') or is_selected(request, 'ss'):
            ticket_form = TicketModerationForm(request.POST, prefix="tm")
            sound_form = SoundStateForm(request.POST, prefix="ss")
            if ticket_form.is_valid() and sound_form.is_valid():
                clean_status_forms = True
                clean_comment_form = True
                sound_state = sound_form.cleaned_data.get('state')
                # Sound should be deleted
                if sound_state == 'DE':
                    if ticket.content:
                        ticket.content.content_object.delete()
                        ticket.content.delete()
                        ticket.content = None
                    ticket.status = TICKET_STATUS_CLOSED
                    tc = TicketComment(
                        sender=request.user,
                        text=
                        "Moderator %s deleted the sound and closed the ticket"
                        % request.user,
                        ticket=ticket,
                        moderator_only=False)
                    tc.save()
                    ticket.send_notification_emails(
                        ticket.NOTIFICATION_DELETED, ticket.USER_ONLY)
                # Set another sound state that's not delete
                else:
                    if ticket.content:
                        ticket.content.content_object.moderation_state = sound_state
                        # Mark the index as dirty so it'll be indexed in Solr
                        if sound_state == "OK":
                            ticket.content.content_object.mark_index_dirty()
                        ticket.content.content_object.save()
                    ticket.status = ticket_form.cleaned_data.get('status')
                    tc = TicketComment(
                        sender=request.user,
                        text=
                        "Moderator %s set the sound to %s and the ticket to %s."
                        % (request.user, 'pending' if sound_state == 'PE' else
                           sound_state, ticket.status),
                        ticket=ticket,
                        moderator_only=False)
                    tc.save()
                    ticket.send_notification_emails(
                        ticket.NOTIFICATION_UPDATED, ticket.USER_ONLY)
                ticket.save()

    if clean_status_forms:
        ticket_form = TicketModerationForm(initial={'status': ticket.status},
                                           prefix="tm")
        state = ticket.content.content_object.moderation_state if ticket.content else 'DE'
        sound_form = SoundStateForm(initial={'state': state}, prefix="ss")
    if clean_comment_form:
        tc_form = _get_tc_form(request, False)

    num_sounds_pending = ticket.sender.profile.num_sounds_pending_moderation()
    tvars = {
        "ticket": ticket,
        "num_sounds_pending": num_sounds_pending,
        "tc_form": tc_form,
        "ticket_form": ticket_form,
        "sound_form": sound_form,
        "can_view_moderator_only_messages": can_view_moderator_only_messages
    }
    return render(request, 'tickets/ticket.html', tvars)
Пример #40
0
def create_sound(user,
                 sound_fields,
                 apiv2_client=None,
                 process=True,
                 remove_exists=False):
    """
    This function is used by the upload handler to create a sound object with
    the information provided through sound_fields parameter.
    """

    # Import models using apps.get_model (to avoid circular dependencies)
    Sound = apps.get_model('sounds', 'Sound')
    License = apps.get_model('sounds', 'License')
    Pack = apps.get_model('sounds', 'Pack')

    # 1 make sound object
    sound = Sound()
    sound.user = user
    sound.original_filename = sound_fields['name']
    sound.original_path = sound_fields['dest_path']
    try:
        sound.filesize = os.path.getsize(sound.original_path)
    except OSError:
        raise NoAudioException()

    license = License.objects.get(name=sound_fields['license'])
    sound.type = get_sound_type(sound.original_path)
    sound.license = license
    sound.md5 = md5file(sound.original_path)

    sound_already_exists = Sound.objects.filter(md5=sound.md5).exists()
    if sound_already_exists:
        existing_sound = Sound.objects.get(md5=sound.md5)
        if remove_exists:
            existing_sound.delete()
        else:
            msg = 'The file %s is already part of freesound and has been discarded, see <a href="%s">here</a>.' % \
                    (sound_fields['name'], reverse('sound', args=[existing_sound.user.username, existing_sound.id]))

            # Remove file (including mirror locations)
            os.remove(sound.original_path)
            remove_uploaded_file_from_mirror_locations(sound.original_path)
            _remove_user_uploads_folder_if_empty(sound.user)

            raise AlreadyExistsException(msg)

    # 2 save
    sound.save()

    # Create corresponding SoundLicenseHistory object (can't be done before Sound is saved for the first time)
    sound.set_license(license)

    # 3 move to new path
    orig = os.path.splitext(os.path.basename(
        sound.original_filename))[0]  # WATCH OUT!
    sound.base_filename_slug = "%d__%s__%s" % (
        sound.id, slugify(sound.user.username), slugify(orig))
    new_original_path = sound.locations("path")
    if sound.original_path != new_original_path:
        try:
            os.makedirs(os.path.dirname(new_original_path))
        except OSError:
            pass
        try:
            shutil.move(sound.original_path, new_original_path)

            # Check if user upload folder still has files and remove if empty
            # NOTE: we first need to remove the file from the mirror locations as we do not perform
            # a 'move' operation there.
            remove_uploaded_file_from_mirror_locations(sound.original_path)
            _remove_user_uploads_folder_if_empty(sound.user)

        except IOError as e:
            raise CantMoveException("Failed to move file from %s to %s" %
                                    (sound.original_path, new_original_path))
        sound.original_path = new_original_path
        sound.save()

    # Copy to mirror location
    copy_sound_to_mirror_locations(sound)

    # 4 create pack if it does not exist
    if 'pack' in sound_fields:
        if sound_fields['pack']:
            if Pack.objects.filter(
                    name=sound_fields['pack'],
                    user=user).exclude(is_deleted=True).exists():
                p = Pack.objects.get(name=sound_fields['pack'], user=user)
            else:
                p, created = Pack.objects.get_or_create(
                    user=user, name=sound_fields['pack'])
            sound.pack = p

    # 5 create geotag objects
    if 'geotag' in sound_fields:
        # Create geotag from lat,lon,zoom text format
        if sound_fields['geotag']:
            lat, lon, zoom = sound_fields['geotag'].split(',')
            geotag = GeoTag(user=user,
                            lat=float(lat),
                            lon=float(lon),
                            zoom=int(zoom))
            geotag.save()
            sound.geotag = geotag
    else:
        # Create geotag from lat, lon, zoom separated fields (if available)
        lat = sound_fields.get('lat', None)
        lon = sound_fields.get('lon', None)
        zoom = sound_fields.get('zoom', None)
        if lat is not None and lon is not None and zoom is not None:
            geotag = GeoTag(user=user,
                            lat=float(lat),
                            lon=float(lon),
                            zoom=int(zoom))
            geotag.save()
            sound.geotag = geotag

    # 6 set description, tags
    sound.description = remove_control_chars(sound_fields['description'])
    sound.set_tags(sound_fields['tags'])

    if 'is_explicit' in sound_fields:
        sound.is_explicit = sound_fields['is_explicit']

    # 6.5 set uploaded apiv2 client
    sound.uploaded_with_apiv2_client = apiv2_client

    # 7 save!
    sound.save()

    # 8 create moderation tickets if needed
    if user.profile.is_whitelisted:
        sound.change_moderation_state('OK')
    else:
        # create moderation ticket!
        sound.create_moderation_ticket()
        invalidate_template_cache("user_header", user.id)
        moderators = Group.objects.get(name='moderators').user_set.all()
        for moderator in moderators:
            invalidate_template_cache("user_header", moderator.id)

    # 9 process sound and packs
    sound.compute_crc()

    if process:
        try:
            sound.process_and_analyze(high_priority=True)

            if sound.pack:
                sound.pack.process()
        except ServerUnavailable:
            pass

    return sound
Пример #41
0
    #sound.set_tags([t.lower() for t in sound_fields['tags'].split(" ") if t])

    # 8.5 set uploaded apiv2 client
    sound.uploaded_with_apiv2_client = apiv2_client

    # 9 save!
    sound.save()

    # 10 create moderation tickets if needed
    if user.profile.is_whitelisted:
        sound.moderation_state = 'OK'
        sound.save()
    else:
        # create moderation ticket!
        sound.create_moderation_ticket()
        invalidate_template_cache("user_header", user.id)
        moderators = Group.objects.get(name='moderators').user_set.all()
        for moderator in moderators:
            invalidate_template_cache("user_header", moderator.id)

    # 11 proces
    try:
        sound.compute_crc()
    except:
        pass

    try:
        sound.process()
    except Exception, e:
        # Log that sound could not be processed, but do not throw any exception
        request_info = basic_request_info_for_log_message(resource.auth_method_name, resource.developer, resource.user, resource.client_id, resource.end_user_ip)
Пример #42
0
def moderation_assigned(request, user_id):
    
    can_view_moderator_only_messages = __can_view_mod_msg(request)
    clear_forms = True
    if request.method == 'POST':
        mod_sound_form = SoundModerationForm(request.POST)
        msg_form = ModerationMessageForm(request.POST)

        if mod_sound_form.is_valid() and msg_form.is_valid():

            ticket = Ticket.objects.get(id=mod_sound_form.cleaned_data.get("ticket", False))
            invalidate_template_cache("user_header", ticket.sender.id)
            invalidate_all_moderators_header_cache()
            action = mod_sound_form.cleaned_data.get("action")
            msg = msg_form.cleaned_data.get("message", False)
            moderator_only = msg_form.cleaned_data.get("moderator_only", False)

            if msg:
                tc = TicketComment(sender=ticket.assignee,
                                   text=msg,
                                   ticket=ticket,
                                   moderator_only=moderator_only)
                tc.save()

            if action == "Approve":
                ticket.status = TICKET_STATUS_CLOSED
                ticket.content.content_object.change_moderation_state("OK")  # change_moderation_state does the saving
                ticket.save()
                ticket.content.content_object.mark_index_dirty()
                if msg:
                    ticket.send_notification_emails(Ticket.NOTIFICATION_APPROVED_BUT,
                                                    Ticket.USER_ONLY)
                else:
                    ticket.send_notification_emails(Ticket.NOTIFICATION_APPROVED,
                                                    Ticket.USER_ONLY)
            elif action == "Defer":
                ticket.status = TICKET_STATUS_DEFERRED
                ticket.save()
                # only send a notification if a message was added
                if msg:
                    ticket.send_notification_emails(Ticket.NOTIFICATION_QUESTION,
                                                    Ticket.USER_ONLY)
            elif action == "Return":
                ticket.assignee = None
                ticket.status = TICKET_STATUS_NEW
                # no notification here
                ticket.save()
            elif action == "Delete":
                ticket.send_notification_emails(Ticket.NOTIFICATION_DELETED,
                                                Ticket.USER_ONLY)
                # to prevent a crash if the form is resubmitted
                if ticket.content:
                    ticket.content.content_object.delete()
                    ticket.content.delete()
                    ticket.content = None
                ticket.status = TICKET_STATUS_CLOSED
                ticket.save()
            elif action == "Whitelist":

                th = Thread(target=call_command, args=('whitelist_user', ticket.id,))
                th.start()
                ticket.send_notification_emails(Ticket.NOTIFICATION_WHITELISTED,
                                                Ticket.USER_ONLY)

                messages.add_message(request, messages.INFO, 'User %s has been whitelisted but some of his tickets might '
                                                             'still appear on this list for some time. Please reload the page in a few '
                                                             'seconds to see the updated list of pending tickets' % ticket.sender.username)

        else:
            clear_forms = False
    if clear_forms:
        mod_sound_form = SoundModerationForm(initial={'action': 'Approve'})
        msg_form = ModerationMessageForm()

    qs = Ticket.objects.select_related() \
                       .filter(assignee=user_id) \
                       .exclude(status=TICKET_STATUS_CLOSED) \
                       .exclude(content=None) \
                       .order_by('status', '-created')
    paginaion_response = paginate(request, qs, settings.MAX_TICKETS_IN_MODERATION_ASSIGNED_PAGE)
    paginaion_response['page'].object_list = list(paginaion_response['page'].object_list)
    for ticket in paginaion_response['page'].object_list:
        sound_id = ticket.content.object_id
        try:
            Sound.objects.get(id=sound_id)
        except:
            paginaion_response['page'].object_list.remove(ticket)
            try:
                # Try to delete ticket so error does not happen again
                ticket.delete()
            except:
                pass

    moderator_tickets_count = qs.count()
    moderation_texts = MODERATION_TEXTS
    show_pagination = moderator_tickets_count > settings.MAX_TICKETS_IN_MODERATION_ASSIGNED_PAGE

    return render_to_response('tickets/moderation_assigned.html',
                              combine_dicts(paginaion_response, locals()),
                              context_instance=RequestContext(request))
Пример #43
0
def describe_sounds(request):
    forms = []
    sounds_to_process = []
    sounds = request.session.get('describe_sounds', False)
    if not sounds:
        msg = 'Please pick at least one sound.'
        messages.add_message(request, messages.WARNING, msg)
        return HttpResponseRedirect(reverse('accounts-describe'))
    sounds_to_describe = sounds[0:settings.SOUNDS_PER_DESCRIBE_ROUND]
    request.session['describe_sounds_number'] = len(request.session.get('describe_sounds'))
    selected_license = request.session.get('describe_license', False)
    selected_pack = request.session.get('describe_pack', False)

    # If there are no files in the session redirect to the first describe page
    if len(sounds_to_describe) <= 0:
        msg = 'You have finished describing your sounds.'
        messages.add_message(request, messages.WARNING, msg)
        return HttpResponseRedirect(reverse('accounts-describe'))

    tvars = {
        'sounds_per_round': settings.SOUNDS_PER_DESCRIBE_ROUND,
        'forms': forms,
    }

    if request.method == 'POST':
        # First get all the data
        n_sounds_already_part_of_freesound = 0
        for i in range(len(sounds_to_describe)):
            prefix = str(i)
            forms.append({})
            forms[i]['sound'] = sounds_to_describe[i]
            forms[i]['description'] = SoundDescriptionForm(request.POST, prefix=prefix)
            forms[i]['geotag'] = GeotaggingForm(request.POST, prefix=prefix)
            forms[i]['pack'] = PackForm(Pack.objects.filter(user=request.user),
                                        request.POST,
                                        prefix=prefix)
            forms[i]['license'] = NewLicenseForm(request.POST, prefix=prefix)
        # Validate each form
        for i in range(len(sounds_to_describe)):
            for f in ['license', 'geotag', 'pack', 'description']:
                if not forms[i][f].is_valid():
                    # If at least one form is not valid, render template with form errors
                    return render(request, 'accounts/describe_sounds.html', tvars)

        # All valid, then create sounds and moderation tickets
        dirty_packs = []
        for i in range(len(sounds_to_describe)):
            # Create sound object and set basic properties
            sound = Sound()
            sound.user = request.user
            sound.original_filename = forms[i]['description'].cleaned_data['name']
            sound.original_path = forms[i]['sound'].full_path
            try:
                sound.filesize = os.path.getsize(sound.original_path)
            except OSError:
                # If for some reason audio file does not exist, skip creating this sound
                messages.add_message(request, messages.ERROR,
                                     'Something went wrong with accessing the file %s.' % sound.original_path)
                continue
            sound.md5 = md5file(forms[i]['sound'].full_path)
            sound.type = get_sound_type(sound.original_path)
            sound.license = forms[i]['license'].cleaned_data['license']
            try:
                # Check if another file with same md5 already exists, if it does, delete the sound and post a message
                existing_sound = Sound.objects.get(md5=sound.md5)
                n_sounds_already_part_of_freesound += 1
                msg = 'The file %s is already part of freesound and has been discarded, see <a href="%s">here</a>' % \
                    (forms[i]['sound'].name, reverse('sound', args=[existing_sound.user.username, existing_sound.id]))
                messages.add_message(request, messages.WARNING, msg)
                os.remove(forms[i]['sound'].full_path)
                continue
            except Sound.DoesNotExist:
                # Reaching here means that no other sound already exists with the same md5
                pass
            sound.save()

            # Move the original audio file
            orig = os.path.splitext(os.path.basename(sound.original_filename))[0]
            sound.base_filename_slug = "%d__%s__%s" % (sound.id, slugify(sound.user.username), slugify(orig))
            new_original_path = sound.locations("path")
            if sound.original_path != new_original_path:
                try:
                    os.makedirs(os.path.dirname(new_original_path))
                except OSError:
                    pass
                try:
                    shutil.move(sound.original_path, new_original_path)
                except IOError, e:
                    logger.info("Failed to move file from %s to %s" % (sound.original_path, new_original_path), e)
                logger.info("Moved original file from %s to %s" % (sound.original_path, new_original_path))
                sound.original_path = new_original_path
                sound.save()

            # Set pack (optional)
            pack = forms[i]['pack'].cleaned_data.get('pack', False)
            new_pack = forms[i]['pack'].cleaned_data.get('new_pack', False)
            if not pack and new_pack:
                pack, created = Pack.objects.get_or_create(user=request.user, name=new_pack)
            if pack:
                sound.pack = pack
                dirty_packs.append(sound.pack)

            # Set geotag
            data = forms[i]['geotag'].cleaned_data
            if not data.get('remove_geotag') and data.get('lat'):  # if 'lat' is in data, we assume other fields are too
                geotag = GeoTag(user=request.user,
                                lat=data.get('lat'),
                                lon=data.get('lon'),
                                zoom=data.get('zoom'))
                geotag.save()
                sound.geotag = geotag

            # Set the tags and description
            data = forms[i]['description'].cleaned_data
            sound.description = remove_control_chars(data.get('description', ''))
            sound.set_tags(data.get('tags'))
            sound.save()

            # Remember to process the file and create moderation ticket if user is not whitelisted
            sounds_to_process.append(sound)
            if request.user.profile.is_whitelisted:
                sound.change_moderation_state('OK', do_not_update_related_stuff=True)
                messages.add_message(request, messages.INFO,
                                     'File <a href="%s">%s</a> has been described and has been added to freesound.' % \
                                     (sound.get_absolute_url(), forms[i]['sound'].name))
            else:
                sound.create_moderation_ticket()
                messages.add_message(request, messages.INFO,
                                     'File <a href="%s">%s</a> has been described and is now awaiting processing '
                                     'and moderation.' % (sound.get_absolute_url(), forms[i]['sound'].name))

                # Invalidate affected caches in user header
                invalidate_template_cache("user_header", request.user.id)
                for moderator in Group.objects.get(name='moderators').user_set.all():
                    invalidate_template_cache("user_header", moderator.id)

            # Compute sound crc
            try:
                sound.compute_crc()
            except:
                pass

        # Remove the files we just described from the session and redirect to this page
        request.session['describe_sounds'] = request.session['describe_sounds'][len(sounds_to_describe):]

        # Process sounds and packs
        # N.B. we do this at the end to avoid conflicts between django-web and django-workers
        # If we're not careful django's save() functions will overwrite any processing we
        # do on the workers.
        # In the future if django-workers do not write to the db this might be changed
        try:
            for s in sounds_to_process:
                s.process()
        except Exception as e:
            audio_logger.error('Sound with id %s could not be scheduled. (%s)' % (s.id, str(e)))
        for p in dirty_packs:
            p.process()

        # Check if all sounds have been described after that round and redirect accordingly
        if len(request.session['describe_sounds']) <= 0:
            if len(sounds_to_describe) != n_sounds_already_part_of_freesound:
                msg = 'You have described all the selected files and are now awaiting processing and moderation. ' \
                      'You can check the status of your uploaded sounds in your <a href="%s">home page</a>. ' \
                      'Once your sounds have been processed, you can also get information about the moderation ' \
                      'status in the <a href="%s">uploaded sounds awaiting moderation' \
                      '</a> page.' % (reverse('accounts-home'), reverse('accounts-pending'))
                messages.add_message(request, messages.WARNING, msg)
            return HttpResponseRedirect(reverse('accounts-describe'))
        else:
            return HttpResponseRedirect(reverse('accounts-describe-sounds'))
Пример #44
0
def new_message(request, username=None, message_id=None):

    if request.user.profile.is_trustworthy():
        form_class = MessageReplyForm
    else:
        form_class = MessageReplyFormWithCaptcha

    if request.method == 'POST':
        form = form_class(request.POST)

        if request.user.profile.is_blocked_for_spam_reports():
            messages.add_message(
                request, messages.INFO,
                "You're not allowed to send the message because your account "
                "has been temporaly blocked after multiple spam reports")
        else:
            if form.is_valid():
                user_from = request.user
                user_to = form.cleaned_data["to"]
                subject = form.cleaned_data["subject"]
                body = MessageBody.objects.create(
                    body=form.cleaned_data["body"])

                Message.objects.create(user_from=user_from,
                                       user_to=user_to,
                                       subject=subject,
                                       body=body,
                                       is_sent=True,
                                       is_archived=False,
                                       is_read=False)
                Message.objects.create(user_from=user_from,
                                       user_to=user_to,
                                       subject=subject,
                                       body=body,
                                       is_sent=False,
                                       is_archived=False,
                                       is_read=False)

                invalidate_template_cache("user_header", user_to.id)

                try:
                    # send the user an email to notify him of the sent message!
                    tvars = {'user_to': user_to, 'user_from': user_from}
                    if user_to.profile.email_not_disabled("private_message"):
                        send_mail_template(u'you have a private message.',
                                           'messages/email_new_message.txt',
                                           tvars,
                                           user_to=user_to)
                except:
                    # if the email sending fails, ignore...
                    pass

                return HttpResponseRedirect(reverse("messages"))
    else:
        form = form_class(request.POST)
        if message_id:
            try:
                message = Message.objects.get(id=message_id)

                if message.user_from != request.user and message.user_to != request.user:
                    raise Http404

                body = message.body.body.replace("\r\n",
                                                 "\n").replace("\r", "\n")
                body = ''.join(BeautifulSoup(body).findAll(text=True))
                body = "\n".join([(">" if line.startswith(">") else "> ") +
                                  "\n> ".join(wrap(line.strip(), 60))
                                  for line in body.split("\n")])
                body = "> --- " + message.user_from.username + " wrote:\n>\n" + body

                subject = "re: " + message.subject
                to = message.user_from.username

                form = form_class(initial={
                    "to": to,
                    "subject": subject,
                    "body": body
                })
            except Message.DoesNotExist:
                pass
        elif username:
            form = form_class(initial={"to": username})

    tvars = {'form': form}
    return render(request, 'messages/new.html', tvars)