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")))
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")))
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')
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")))
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')
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')
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()))
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()))
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()))
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())
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))
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)
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')
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'])
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")))
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'])
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())
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()))
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)
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))
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))
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)
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))
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)
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
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))
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)
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)
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:
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)
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)
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)
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(
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
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)
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)
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)
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
#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)
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))
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'))
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)