Exemplo n.º 1
0
 def update_sound_tickets(sound, text):
     tickets = Ticket.objects.filter(content__object_id=sound.id, source=TICKET_SOURCE_NEW_SOUND).exclude(
         status=TICKET_STATUS_CLOSED
     )
     for ticket in tickets:
         tc = TicketComment(sender=request.user, ticket=ticket, moderator_only=False, text=text)
         tc.save()
         ticket.send_notification_emails(ticket.NOTIFICATION_UPDATED, ticket.MODERATOR_ONLY)
Exemplo n.º 2
0
 def update_sound_tickets(sound, text):
     tickets = Ticket.objects.filter(sound_id=sound.id)\
                            .exclude(status=TICKET_STATUS_CLOSED)
     for ticket in tickets:
         tc = TicketComment(sender=request.user,
                            ticket=ticket,
                            moderator_only=False,
                            text=text)
         tc.save()
         ticket.send_notification_emails(ticket.NOTIFICATION_UPDATED,
                                         ticket.MODERATOR_ONLY)
Exemplo n.º 3
0
def ticketComments(request):
    if request.method == "POST":
        comment = request.POST.get('comment')
        user = request.user
        ticketTno = request.POST.get('ticketTno')
        ticket = Ticket.objects.get(tno=ticketTno)

        comment = TicketComment(comment=comment, user=user, ticket=ticket)
        comment.save()
        messages.success(request, "Your comment has been added, successfully")

    return redirect(f'/tickets/{ticket.tno}')
Exemplo n.º 4
0
def ticket_detail(request, pk=None):
    try:
        ticket = Ticket.objects.prefetch_related().get(pk=pk)
    except Ticket.DoesNotExist:
        raise Http404

    if request.method == 'POST':
        form = TicketCommentForm(request.POST)
        if form.is_valid():
            ticket_comment = TicketComment(
                ticket=ticket,
                author=request.user,
                content=form.cleaned_data.get('content'),
            )
            ticket_comment.save()
            messages.success(request, 'Successfully added comment.')
            return redirect(ticket.get_absolute_url())
    else:
        form = TicketCommentForm()

    ticket_comments = (TicketComment.objects.select_related()
                       .filter(ticket=ticket).order_by('-created_date'))

    ticket_attachments = (TicketAttachment.objects.select_related()
                          .filter(ticket=ticket).order_by('-created_date'))

    if 'ticket-comments-wrapper' in request.get_full_path():
        selected_tab = 'comments'
    else:
        selected_tab = 'view'

    ticket_watchers = ticket.watchers.all()

    if request.user in ticket_watchers:
        is_watching = True
    else:
        is_watching = False

    initial = {'ticket_id': ticket.pk}
    watch_ticket_form = WatchTicketForm(initial=initial, user=request.user)

    dict_context = {
        'form': form,
        'selected_tab': selected_tab,
        'ticket': ticket,
        'ticket_comments': ticket_comments,
        'ticket_attachments': ticket_attachments,
        'watchers': ticket_watchers,
        'is_watching': is_watching,
        'watch_ticket_form': watch_ticket_form,
    }
    return render(request, 'tickets/detail.html', dict_context)
Exemplo n.º 5
0
def delete(request, username, sound_id):
    sound = get_object_or_404(Sound, id=sound_id)
    if sound.user.username.lower() != username.lower():
        raise Http404

    if not (request.user.has_perm('sound.delete_sound')
            or sound.user == request.user):
        raise PermissionDenied

    encrypted_string = request.GET.get("sound", None)
    waited_too_long = False
    if encrypted_string is not None:
        sound_id, now = decrypt(encrypted_string).split("\t")
        sound_id = int(sound_id)
        link_generated_time = float(now)

        if sound_id != sound.id:
            raise PermissionDenied

        if abs(time.time() - link_generated_time) < 10:
            logger.debug("User %s requested to delete sound %s" %
                         (request.user.username, sound_id))
            try:
                ticket = sound.ticket
                tc = TicketComment(sender=request.user,
                                   text="User %s deleted the sound" %
                                   request.user,
                                   ticket=ticket,
                                   moderator_only=False)
                tc.save()
            except Ticket.DoesNotExist:
                # No ticket assigned, not adding any message (should not happen)
                pass
            sound.delete()

            return HttpResponseRedirect(reverse("accounts-home"))
        else:
            waited_too_long = True

    encrypted_link = encrypt(u"%d\t%f" % (sound.id, time.time()))
    return render_to_response('sounds/delete.html',
                              locals(),
                              context_instance=RequestContext(request))
Exemplo n.º 6
0
def delete(request, username, sound_id):
    sound = get_object_or_404(Sound, id=sound_id)
    if sound.user.username.lower() != username.lower():
        raise Http404

    if not (request.user.has_perm('sound.delete_sound')
            or sound.user == request.user):
        raise PermissionDenied

    error_message = None
    if request.method == "POST":
        form = DeleteSoundForm(request.POST, sound_id=sound_id)
        if not form.is_valid():
            error_message = "Sorry, you waited too long, ... try again?"
            form = DeleteSoundForm(sound_id=sound_id)
        else:

            logger.debug("User %s requested to delete sound %s" %
                         (request.user.username, sound_id))
            try:
                ticket = sound.ticket
                tc = TicketComment(sender=request.user,
                                   text="User %s deleted the sound" %
                                   request.user,
                                   ticket=ticket,
                                   moderator_only=False)
                tc.save()
            except Ticket.DoesNotExist:
                # No ticket assigned, not adding any message (should not happen)
                pass
            sound.delete()

            return HttpResponseRedirect(reverse("accounts-home"))
    else:
        form = DeleteSoundForm(sound_id=sound_id)

    tvars = {
        'error_message': error_message,
        'delete_form': form,
        'sound': sound
    }
    return render(request, 'sounds/delete.html', tvars)
Exemplo n.º 7
0
def delete(request, username, sound_id):
    sound = get_object_or_404(Sound, id=sound_id)
    if sound.user.username.lower() != username.lower():
        raise Http404

    if not (request.user.has_perm('sound.delete_sound') or sound.user == request.user):
        raise PermissionDenied

    error_message = None
    if request.method == "POST" :
        form = DeleteSoundForm(request.POST, sound_id=sound_id)
        if not form.is_valid():
            error_message = "Sorry, you waited too long, ... try again?"
            form = DeleteSoundForm(sound_id=sound_id)
        else:

            logger.info("User %s requested to delete sound %s" % (request.user.username,sound_id))
            try:
                ticket = sound.ticket
                tc = TicketComment(sender=request.user,
                                   text="User %s deleted the sound" % request.user,
                                   ticket=ticket,
                                   moderator_only=False)
                tc.save()
            except Ticket.DoesNotExist:
                # No ticket assigned, not adding any message (should not happen)
                pass
            sound.delete()

            return HttpResponseRedirect(reverse("accounts-home"))
    else:
        form = DeleteSoundForm(sound_id=sound_id)

    tvars = {
            'error_message': error_message,
            'delete_form': form,
            'sound': sound
            }
    return render(request, 'sounds/delete.html', tvars)
Exemplo n.º 8
0
def delete(request, username, sound_id):
    sound = get_object_or_404(Sound, id=sound_id)
    if sound.user.username.lower() != username.lower():
        raise Http404

    if not (request.user.has_perm('sound.delete_sound') or sound.user == request.user):
        raise PermissionDenied

    encrypted_string = request.GET.get("sound", None)
    waited_too_long = False
    if encrypted_string is not None:
        sound_id, now = decrypt(encrypted_string).split("\t")
        sound_id = int(sound_id)
        link_generated_time = float(now)

        if sound_id != sound.id:
            raise PermissionDenied

        if abs(time.time() - link_generated_time) < 10:
            logger.debug("User %s requested to delete sound %s" % (request.user.username,sound_id))
            try:
                ticket = sound.ticket
                tc = TicketComment(sender=request.user,
                                   text="User %s deleted the sound" % request.user,
                                   ticket=ticket,
                                   moderator_only=False)
                tc.save()
            except Ticket.DoesNotExist:
                # No ticket assigned, not adding any message (should not happen)
                pass
            sound.delete()

            return HttpResponseRedirect(reverse("accounts-home"))
        else:
            waited_too_long = True

    encrypted_link = encrypt(u"%d\t%f" % (sound.id, time.time()))
    return render_to_response('sounds/delete.html', locals(), context_instance=RequestContext(request))
Exemplo n.º 9
0
 def create_moderation_ticket(self):
     ticket = Ticket()
     ticket.title = 'Moderate sound %s' % self.original_filename
     ticket.source = TICKET_SOURCE_NEW_SOUND
     ticket.status = TICKET_STATUS_NEW
     ticket.queue = Queue.objects.get(name='sound moderation')
     ticket.sender = self.user
     lc = LinkedContent()
     lc.content_object = self
     lc.save()
     ticket.content = lc
     ticket.save()
     tc = TicketComment()
     tc.sender = self.user
     tc.text = "I've uploaded %s. Please moderate!" % self.original_filename
     tc.ticket = ticket
     tc.save()
Exemplo n.º 10
0
 def create_moderation_ticket(self):
     ticket = Ticket()
     ticket.title = 'Moderate sound %s' % self.original_filename
     ticket.source = TICKET_SOURCE_NEW_SOUND
     ticket.status = TICKET_STATUS_NEW
     ticket.queue = Queue.objects.get(name='sound moderation')
     ticket.sender = self.user
     lc = LinkedContent()
     lc.content_object = self
     lc.save()
     ticket.content = lc
     ticket.save()
     tc = TicketComment()
     tc.sender = self.user
     tc.text = "I've uploaded %s. Please moderate!" % self.original_filename
     tc.ticket = ticket
     tc.save()
Exemplo n.º 11
0
def sound_edit(request, username, sound_id):
    sound = get_object_or_404(Sound, user__username__iexact=username, id=sound_id, processing_state='OK')

    if not (request.user.has_perm('sound.can_change') or sound.user == request.user):
        raise PermissionDenied

    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)

    def is_selected(prefix):
        if request.method == "POST":
            for name in request.POST.keys():
                if name.startswith(prefix + '-'):
                    return True
        return False

    if is_selected("description"):
        description_form = SoundDescriptionForm(request.POST, prefix="description")
        if description_form.is_valid():
            data = description_form.cleaned_data
            sound.set_tags(data["tags"])
            sound.description = data["description"]
            sound.original_filename = data["name"]
            sound.mark_index_dirty()
            invalidate_sound_cache(sound)
            
            # also update any possible related sound ticket
            tickets = Ticket.objects.filter(content__object_id=sound.id,
                                            source=TICKET_SOURCE_NEW_SOUND) \
                                   .exclude(status=TICKET_STATUS_CLOSED)
            for ticket in tickets:
                tc = TicketComment(sender=request.user,
                                   ticket=ticket,
                                   moderator_only=False,
                                   text='%s updated the sound description and/or tags.' % request.user.username)
                tc.save()
                ticket.send_notification_emails(ticket.NOTIFICATION_UPDATED,
                                                ticket.MODERATOR_ONLY)
            return HttpResponseRedirect(sound.get_absolute_url())
    else:
        tags = " ".join([tagged_item.tag.name for tagged_item in sound.tags.all().order_by('tag__name')])
        description_form = SoundDescriptionForm(prefix="description",
                                                initial=dict(tags=tags,
                                                             description=sound.description,
                                                             name=sound.original_filename))

    packs = Pack.objects.filter(user=request.user)

    if is_selected("pack"):
        pack_form = PackForm(packs, request.POST, prefix="pack")
        if pack_form.is_valid():
            data = pack_form.cleaned_data
            dirty_packs = []
            if data['new_pack']:
                (pack, created) = Pack.objects.get_or_create(user=sound.user, name=data['new_pack'])
                sound.pack = pack
            else:
                new_pack = data["pack"]
                old_pack = sound.pack
                if new_pack != old_pack:
                    sound.pack = new_pack
                if new_pack:
                    dirty_packs.append(new_pack)
                if old_pack:
                    dirty_packs.append(old_pack)

            for p in dirty_packs:
               p.process()

            sound.mark_index_dirty()
            invalidate_sound_cache(sound)
            return HttpResponseRedirect(sound.get_absolute_url())
    else:
        pack_form = PackForm(packs, prefix="pack", initial=dict(pack=sound.pack.id) if sound.pack else None)

    if is_selected("geotag"):
        geotag_form = GeotaggingForm(request.POST, prefix="geotag")
        
        if geotag_form.is_valid():
            data = geotag_form.cleaned_data
            
            if data["remove_geotag"]:
                if sound.geotag:
                    geotag = sound.geotag.delete()
                    sound.geotag = None
                    sound.mark_index_dirty()
            else:
                if sound.geotag:
                    sound.geotag.lat = data["lat"]
                    sound.geotag.lon = data["lon"]
                    sound.geotag.zoom = data["zoom"]
                    sound.geotag.save()
                else:
                    sound.geotag = GeoTag.objects.create(lat=data["lat"], lon=data["lon"], zoom=data["zoom"], user=request.user)
                    sound.mark_index_dirty()

            invalidate_sound_cache(sound)
            
            return HttpResponseRedirect(sound.get_absolute_url())
    else:
        if sound.geotag:
            geotag_form = GeotaggingForm(prefix="geotag", initial=dict(lat=sound.geotag.lat, lon=sound.geotag.lon, zoom=sound.geotag.zoom))
        else:
            geotag_form = GeotaggingForm(prefix="geotag")

    license_form = NewLicenseForm(request.POST)
    if request.POST and license_form.is_valid():
        sound.license = license_form.cleaned_data["license"]
        sound.mark_index_dirty()
        invalidate_sound_cache(sound)
        return HttpResponseRedirect(sound.get_absolute_url())
    else:
        license_form = NewLicenseForm(initial={'license': sound.license})
    
    google_api_key = settings.GOOGLE_API_KEY

    return render_to_response('sounds/sound_edit.html', locals(), context_instance=RequestContext(request))
Exemplo n.º 12
0
def describe_sounds(request):
    sounds_to_process = []
    sounds = request.session.get('describe_sounds', False)
    selected_license = request.session.get('describe_license', False)
    selected_pack = request.session.get('describe_pack', False)

    # This is to prevent people browsing to the /home/describe/sounds page
    # without going through the necessary steps.
    # selected_pack can be False, but license and sounds have to be picked at least
    if not (sounds):
        msg = 'Please pick at least one sound.'
        messages.add_message(request, messages.WARNING, msg)
        return HttpResponseRedirect(reverse('accounts-describe'))

    # So SOUNDS_PER_DESCRIBE_ROUND is available in the template
    sounds_per_round = SOUNDS_PER_DESCRIBE_ROUND
    sounds_to_describe = sounds[0:sounds_per_round]
    forms = []
    request.session['describe_sounds_number'] = len(request.session.get('describe_sounds'))

    # 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'))

    if request.method == 'POST':
        # first get all the data
        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():
                    return render_to_response('accounts/describe_sounds.html',
                                              locals(),
                                              context_instance=RequestContext(request))
        # all valid, then create sounds and moderation tickets
                
        dirty_packs = []
        for i in range(len(sounds_to_describe)):
            sound = Sound()
            sound.user = request.user
            sound.original_filename = forms[i]['description'].cleaned_data['name']
            sound.original_path = forms[i]['sound'].full_path
            sound.filesize = os.path.getsize(sound.original_path)

            try:
                sound.md5 = md5file(forms[i]['sound'].full_path)
            except IOError:
                messages.add_message(request, messages.ERROR, 'Something went wrong with accessing the file %s.' % sound.original_path)
                continue
            sound.type = get_sound_type(sound.original_path)
            # check if file exists or not
            try:
                existing_sound = Sound.objects.get(md5=sound.md5)
                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, e:
                pass

            # set the license
            sound.license = forms[i]['license'].cleaned_data['license']
            sound.save()
            # now move the original
            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)
                    #shutil.copy(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 the 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 the geotag (if 'lat' is there, all fields are)
            data = forms[i]['geotag'].cleaned_data
            if not data.get('remove_geotag') and data.get('lat'):
                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 descriptions
            data = forms[i]['description'].cleaned_data
            sound.description = data.get('description', '')
            sound.set_tags(data.get('tags'))
            sound.save()
            # remember to process the file
            sounds_to_process.append(sound)
            if request.user.profile.is_whitelisted:
                sound.moderation_state = 'OK'
                sound.save()
                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:
                # create moderation ticket!
                ticket = Ticket()
                ticket.title = 'Moderate sound %s' % sound.original_filename
                ticket.source = TICKET_SOURCE_NEW_SOUND
                ticket.status = TICKET_STATUS_NEW
                ticket.queue = Queue.objects.get(name='sound moderation')
                ticket.sender = request.user
                lc = LinkedContent()
                lc.content_object = sound
                lc.save()
                ticket.content = lc
                ticket.save()
                tc = TicketComment()
                tc.sender = request.user
                tc.text = "I've uploaded %s. Please moderate!" % sound.original_filename
                tc.ticket = ticket
                tc.save()
                # add notification that the file was described successfully
                messages.add_message(request, messages.INFO,
                                     'File <a href="%s">%s</a> has been described and is awaiting moderation.' % \
                                     (sound.get_absolute_url(), forms[i]['sound'].name))
            # compute crc
            # TEMPORARY
            try:
                sound.compute_crc()
            except:
                pass
Exemplo n.º 13
0
        sound.moderation_state = 'OK'
        sound.save()
    else:
        # create moderation ticket!
        ticket = Ticket()
        ticket.title = 'Moderate sound %s' % sound.original_filename
        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
Exemplo n.º 14
0
        sound.moderation_state = 'OK'
        sound.save()
    else:
        # create moderation ticket!
        ticket = Ticket()
        ticket.title = 'Moderate sound %s' % sound.original_filename
        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
Exemplo n.º 15
0
def sound_edit(request, username, sound_id):
    ONLY_RECOMMEND_TAGS_TO_HALF_OF_UPLOADS = settings.ONLY_RECOMMEND_TAGS_TO_HALF_OF_UPLOADS

    sound = get_object_or_404(Sound, id=sound_id, processing_state='OK')
    if sound.user.username.lower() != username.lower():
        raise Http404

    if not (request.user.has_perm('sound.can_change') or sound.user == request.user):
        raise PermissionDenied

    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)

    def is_selected(prefix):
        if request.method == "POST":
            for name in request.POST.keys():
                if name.startswith(prefix + '-'):
                    return True
        return False

    if is_selected("description"):
        description_form = SoundDescriptionForm(request.POST, prefix="description")
        if description_form.is_valid():
            data = description_form.cleaned_data
            sound.set_tags(data["tags"])
            sound.description = remove_control_chars(data["description"])
            sound.original_filename = data["name"]
            sound.mark_index_dirty()
            invalidate_sound_cache(sound)
            
            # also update any possible related sound ticket
            tickets = Ticket.objects.filter(content__object_id=sound.id,
                                            source=TICKET_SOURCE_NEW_SOUND) \
                                   .exclude(status=TICKET_STATUS_CLOSED)
            for ticket in tickets:
                tc = TicketComment(sender=request.user,
                                   ticket=ticket,
                                   moderator_only=False,
                                   text='%s updated the sound description and/or tags.' % request.user.username)
                tc.save()
                ticket.send_notification_emails(ticket.NOTIFICATION_UPDATED,
                                                ticket.MODERATOR_ONLY)
            return HttpResponseRedirect(sound.get_absolute_url())
    else:
        tags = " ".join([tagged_item.tag.name for tagged_item in sound.tags.all().order_by('tag__name')])
        description_form = SoundDescriptionForm(prefix="description",
                                                initial=dict(tags=tags,
                                                             description=sound.description,
                                                             name=sound.original_filename))

    packs = Pack.objects.filter(user=request.user)

    if is_selected("pack"):
        pack_form = PackForm(packs, request.POST, prefix="pack")
        if pack_form.is_valid():
            data = pack_form.cleaned_data
            dirty_packs = []
            if data['new_pack']:
                (pack, created) = Pack.objects.get_or_create(user=sound.user, name=data['new_pack'])
                sound.pack = pack
            else:
                new_pack = data["pack"]
                old_pack = sound.pack
                if new_pack != old_pack:
                    sound.pack = new_pack
                if new_pack:
                    dirty_packs.append(new_pack)
                if old_pack:
                    dirty_packs.append(old_pack)

            for p in dirty_packs:
               p.process()

            sound.mark_index_dirty()
            invalidate_sound_cache(sound)
            return HttpResponseRedirect(sound.get_absolute_url())
    else:
        pack_form = PackForm(packs, prefix="pack", initial=dict(pack=sound.pack.id) if sound.pack else None)

    if is_selected("geotag"):
        geotag_form = GeotaggingForm(request.POST, prefix="geotag")
        
        if geotag_form.is_valid():
            data = geotag_form.cleaned_data
            
            if data["remove_geotag"]:
                if sound.geotag:
                    geotag = sound.geotag.delete()
                    sound.geotag = None
                    sound.mark_index_dirty()
            else:
                if sound.geotag:
                    sound.geotag.lat = data["lat"]
                    sound.geotag.lon = data["lon"]
                    sound.geotag.zoom = data["zoom"]
                    sound.geotag.save()
                else:
                    sound.geotag = GeoTag.objects.create(lat=data["lat"], lon=data["lon"], zoom=data["zoom"], user=request.user)
                    sound.mark_index_dirty()

            invalidate_sound_cache(sound)
            
            return HttpResponseRedirect(sound.get_absolute_url())
    else:
        if sound.geotag:
            geotag_form = GeotaggingForm(prefix="geotag", initial=dict(lat=sound.geotag.lat, lon=sound.geotag.lon, zoom=sound.geotag.zoom))
        else:
            geotag_form = GeotaggingForm(prefix="geotag")

    license_form = NewLicenseForm(request.POST)
    if request.POST and license_form.is_valid():
        sound.license = license_form.cleaned_data["license"]
        sound.mark_index_dirty()
        invalidate_sound_cache(sound)
        return HttpResponseRedirect(sound.get_absolute_url())
    else:
        license_form = NewLicenseForm(initial={'license': sound.license})
    
    google_api_key = settings.GOOGLE_API_KEY

    return render_to_response('sounds/sound_edit.html', locals(), context_instance=RequestContext(request))