Extract features from blob with Librosa - javascript

I am trying to record a voice message in the frontend and send it to the Django backend to test it against a ML algorithm of voice gender recognition. In the frontend I record the voice using videojs-record and I use AJAX to send the blob to the backend like so:
{% extends 'base.html' %}
{% load static %}
{% block title %}Voice Detector{% endblock %}
{% block extracss %}
<link href="{% static 'css/voice_detector.css' %}" rel="stylesheet" />
<link href="{% static 'css/video-js.css' %}" rel="stylesheet" />
<link href="{% static 'css/all.min.css' %}" rel="stylesheet" />
<link href="{% static 'css/videojs.wavesurfer.min.css' %}" rel="stylesheet" />
<link href="{% static 'css/videojs.record.css' %}" rel="stylesheet" />
{% endblock %}
{% block content %}
<div class="banner">
<div class="max-width">
<div class="banner-content">
<p class="motto">Test your voice right now!</p>
<p class="description">
Register your voice while reading the text below and our program will
detect your gender in a few seconds!
</p>
</div>
</div>
</div>
<div class="details">
<section class="section">
<div class="container">
<div class="columns">
<div class="column is-offset-4 is-4">
<h1 class="title">Record audio</h1>
<article class="message is-success" id="alert">
<div class="message-header">
<p>Recorded successfully!</p>
<button class="delete" aria-label="delete"></button>
</div>
<div class="message-body">
You have successfully recorded your message. You can now click on
the Submit button to post it.
</div>
</article>
<div class="field">
<div
class="control has-icons-left has-icons-right"
style="margin-top: 1rem"
>
<audio
id="recordAudio"
class="video-js vjs-default-skin"
></audio>
</div>
<div class="control" style="margin-top: 1rem">
<button class="home-btn" id="submit" disabled>Submit</button>
</div>
</div>
</div>
</div>
</div>
</section>
</div>
{% endblock %}
{% block extrajs %}
<script src="{% static 'js/video.min.js' %}"></script>
<script src="{% static 'js/RecordRTC.js' %}"></script>
<script src="{% static 'js/adapter-latest.js' %}"></script>
<script src="{% static 'js/wavesurfer.js' %}"></script>
<script src="{% static 'js/wavesurfer.microphone.min.js' %}"></script>
<script src="{% static 'js/videojs.wavesurfer.min.js' %}"></script>
<script src="{% static 'js/videojs.record.min.js' %}"></script>
<script src="{% static 'js/browser-workaround.js' %}"></script>
<script>
// First lets hide the message
document.getElementById("alert").style.display = "none";
// Next, declare the options that will passed into the recording constructor
const options = {
controls: true,
bigPlayButton: false,
width: 600,
height: 300,
fluid: true, // this ensures that it's responsive
plugins: {
wavesurfer: {
backend: "WebAudio",
waveColor: "#f7fff7", // change the wave color here. Background color was set in the css above
progressColor: "#ffe66d",
displayMilliseconds: true,
debug: true,
cursorWidth: 1,
hideScrollbar: true,
plugins: [
// enable microphone plugin
WaveSurfer.microphone.create({
bufferSize: 4096,
numberOfInputChannels: 1,
numberOfOutputChannels: 1,
constraints: {
video: false,
audio: true,
},
}),
],
},
record: {
audio: true, // only audio is turned on
video: false, // you can turn this on as well if you prefer video recording.
maxLength: 180, // how long do you want the recording?
displayMilliseconds: true,
debug: true,
},
},
};
// apply audio workarounds for certain browsers
applyAudioWorkaround();
// create player and pass the the audio id we created then
var player = videojs("recordAudio", options, function () {
// print version information at startup
var msg =
"Using video.js " +
videojs.VERSION +
" with videojs-record " +
videojs.getPluginVersion("record") +
", videojs-wavesurfer " +
videojs.getPluginVersion("wavesurfer") +
", wavesurfer.js " +
WaveSurfer.VERSION +
" and recordrtc " +
RecordRTC.version;
videojs.log(msg);
});
// error handling
player.on("deviceError", function () {
console.log("device error:", player.deviceErrorCode);
});
player.on("error", function (element, error) {
console.error(error);
});
// user clicked the record button and started recording
player.on("startRecord", function () {
console.log("started recording!");
$("#submit").prop("disabled", true);
});
// user completed recording and stream is available
player.on("finishRecord", function () {
const audioFile = player.recordedData;
console.log("finished recording: ", audioFile);
$("#submit").prop("disabled", false);
document.getElementById("alert").style.display = "block";
});
// Give event listener to the submit button
$("#submit").on("click", function (event) {
event.preventDefault();
let btn = $(this);
// change the button text and disable it
btn.html("Submitting...").prop("disabled", true).addClass("disable-btn");
// create a new File with the recordedData and its name
const recordedFile = new File([player.recordedData], `test.wav`);
// initializes an empty FormData
let data = new FormData();
// appends the recorded file and language value
data.append("file", recordedFile);
// post url endpoint
$.ajax({
url: "{% url 'detector' %}",
method: "POST",
data: data,
dataType: "json",
success: function (response) {
if (response.success) {
document.getElementById("alert").style.display = "block";
window.location.href = `${response.url}`;
} else {
btn.html("Error").prop("disabled", false);
}
},
error: function (error) {
console.error(error);
},
cache: false,
processData: false,
contentType: false,
});
});
</script>
{% endblock %}
On the backend I try to use wave to save the file as a valid .wav, like so:
def post(self, request):
f = request.FILES['file']
with open('file.wav', 'wb+') as destination:
for chunk in f.chunks():
destination.write(chunk)
with open('file.wav', 'rb') as file:
file_content = file.read()
audio = wave.open('test.wav', 'wb')
audio.setnchannels(1)
audio.setnframes(1)
audio.setsampwidth(1)
audio.setframerate(8000)
audio.writeframes(file_content)
audio.close()
(prediction, probability) = predict('test.wav')
context["prediction"] = prediction
context["probability"] = probability*100
os.remove(file_name)
return render(request, self.template_name, context=context)
Here, I tried 2 things. The first try was to save the blob directly into a file using open with 'wb'. The problem with this is approach is that librosa complains that the file type is not recognized. The other try was with wave, but whatever I try, the file saved with wave results in noise and the prediction algorithm fails. Here is how I would like to use the file with the recorded voice to make the prediction:
def predict(file_name):
# construct the model
model = create_model()
# load the saved/trained weights
model.load_weights('model.h5')
# extract features and reshape it
features = extract_feature(file_name, mel=True).reshape(1, -1)
# predict the gender!
male_prob = model.predict(features)[0][0]
female_prob = 1 - male_prob
gender = "male" if male_prob > female_prob else "female"
if gender == "male":
return (gender, male_prob)
return (gender, female_prob)
And here is the extract_feature function where I load the file and process it:
def extract_feature(file_name, **kwargs):
mfcc = kwargs.get("mfcc")
chroma = kwargs.get("chroma")
mel = kwargs.get("mel")
contrast = kwargs.get("contrast")
tonnetz = kwargs.get("tonnetz")
X, sample_rate = librosa.core.load(file_name)
if chroma or contrast:
stft = np.abs(librosa.stft(X))
result = np.array([])
if mfcc:
mfccs = np.mean(librosa.feature.mfcc(y=X, sr=sample_rate, n_mfcc=40).T, axis=0)
result = np.hstack((result, mfccs))
if chroma:
chroma = np.mean(librosa.feature.chroma_stft(S=stft, sr=sample_rate).T,axis=0)
result = np.hstack((result, chroma))
if mel:
mel = np.mean(librosa.feature.melspectrogram(X, sr=sample_rate).T,axis=0)
result = np.hstack((result, mel))
if contrast:
contrast = np.mean(librosa.feature.spectral_contrast(S=stft, sr=sample_rate).T,axis=0)
result = np.hstack((result, contrast))
if tonnetz:
tonnetz = np.mean(librosa.feature.tonnetz(y=librosa.effects.harmonic(X), sr=sample_rate).T,axis=0)
result = np.hstack((result, tonnetz))
return result
What am I doing wrong? Is there a way to create a valid WAV file having the same content as the blob that I record on the frontend? Or is there a way to directly use the blob that I receive from the frontend?

After some digging, I discovered the ffmpeg tool on Linux and I used it in python to convert the file from WebM format to WAV. Here is the solution:
def post(self, request):
webm_file = str(datetime.datetime.now()) + ".webm"
wav_file = str(datetime.datetime.now()) + ".wav"
f = request.FILES['file']
with open(webm_file, 'wb+') as destination:
for chunk in f.chunks():
destination.write(chunk)
destination.close()
# convert file from WebM to WAV format
subprocess.run(["ffmpeg", "-i", webm_file, "-vn", wav_file])
(prediction, probability) = predict(wav_file)
context["prediction"] = prediction
context["probability"] = probability*100
os.remove(webm_file)
os.remove(wav_file)
return render(request, self.template_name, context=context)

Related

How to create if statement on a redirect to change Django model

I am trying to create a if statement in my Django view that detects when I am redirected to my complete order url. I want to do this because I would like to change my Django model Order 'complete' field to true. My redirect is coming from a javascript function in my paypal intergration.
checkout.html
{% extends 'base.html' %}
{% load crispy_forms_tags %}
{% block content %}
<h1>Checkout</h1>
<div class='container'>
<div class='row'>
<div class='col-6'>
<form action="" method='post' id='payement-form'>
{% csrf_token %}
<!-- {{ form|crispy }} -->
<div class='col-12' id='paypal-button-container'></div>
</form>
<script
src="https://www.paypal.com/sdk/js?client-id="> // Required. Replace YOUR_CLIENT_ID with your sandbox client ID.
</script>
<script>
function redirect() {
var url = "{% url 'complete-order' %}"
window.location.href = url
}
paypal.Buttons({
createOrder: function (data, actions) {
return actions.order.create({
purchase_units: [{
amount: {
value: '0.01'
}
}]
});
},
onApprove: function (data, actions) {
// This function captures the funds from the transaction.
return actions.order.capture().then(function (details) {
// This function is the redirect
redirect()
alert('Transaction completed by ' + details.payer.name.given_name);
});
}
}).render('#paypal-button-container');
</script>
</div>
{% endblock content %}
views.py
#login_required(login_url='login')
def checkout(request):
order = Order.objects.get(user=request.user, complete=False)
context = {
'order': order
}
return render(request, 'videogames/checkout.html', context)
#login_required(login_url='login')
def paymentComplete(request):
order = Order.objects.get(user=request.user, complete=True)
context = {
'order': order
}
return render(request, 'videogames/complete.html', context)
There are many ways that should be selected according to your project.
before redirection, in the view , call a link with Ajax to change the status
#login_required(login_url='login')
def paymentSetComplete(request):
order = Order.objects.get(id=request.payment_id=,user=request.user, complete=False)
order.complete=True
order.save() # or update directly
return
Change the status when the request to load the complate page was sent to django
I do not know what measures you have taken to secure and prevent the fake purchases
But know that users can repeat requests that come to the server

Django and Javascript - Like Button Not Working

I am new to Django and Javascript - I am making a project that has posts on a site, and I want to create a 'like' button on each post. So far here is my code - I am not getting any errors at all. No console errors in the browser either. But nothing happens. When you click the heart image, if it is liked, it should be a red image. When it is not liked, it is the white heart image. Currently when I click the image, it just stays white. It is always defaulting to that white image. The code doesn't work. Any help is appreciated.
views.py for the like button:
#csrf_exempt
def like(request):
if request.method == "POST":
post_id = request.POST.get('id')
is_liked = request.POST.get('is_liked')
try:
post = Post.objects.get(id=post_id)
if is_liked == 'no':
post.like.add(request.user)
is_liked = 'yes'
elif is_liked == 'yes':
post.like.remove(request.user)
is_liked = 'no'
post.save()
return JsonResponse({'like_count': post.like.count(), 'is_liked': is_liked,
"status": 201})
except:
return JsonResponse({'error': "Post not found", "status": 404})
return JsonResponse({}, status=400)
views.py for the page to show all the posts:
def index(request):
list_of_posts = Post.objects.all().order_by('id').reverse()
paginator = Paginator(list_of_posts, 10)
page_number = request.GET.get('page', 1)
page_obj = paginator.get_page(page_number)
return render(request, "network/index.html", {
"list_of_posts": list_of_posts,
"page_obj": page_obj
})
Javascript file:
like = document.querySelectorAll(".liked");
edit = document.querySelectorAll(".edit");
text_area = document.querySelectorAll(".textarea");
like.forEach((element) => {
like_handeler(element);
});
function like_handeler(element) {
element.addEventListener("click", () => {
id = element.getAttribute("data-id");
is_liked = element.getAttribute("data-is_liked");
icon = document.querySelector(`#post-like-${id}`);
count = document.querySelector(`#post-count-${id}`);
form = new FormData();
form.append("id", id);
form.append("is_liked", is_liked);
fetch("/like/", {
method: "POST",
body: form,
})
.then((res) => res.json())
.then((res) => {
if (res.status == 201) {
if (res.is_liked === "yes") {
icon.src = "https://img.icons8.com/plasticine/100/000000/like.png";
element.setAttribute("data-is_liked", "yes");
} else {
icon.src =
"https://img.icons8.com/carbon-copy/100/000000/like--v2.png";
element.setAttribute("data-is_liked", "no");
}
count.textContent = res.like_count;
}
})
.catch(function (res) {
alert("Network Error. Please Check your connection.");
});
});
}
html file for each post: index.html:
{% extends "network/layout.html" %}
{% load static %}
{% block body %}
<h3> Welcome. Here is your news feed: </h3>
{% for i in page_obj %}
<div class='card mb-3' style="max-width: 530px;" id="card-posts">
<div class="row no-gutters">
<div class="col-md-8">
<div class="card-body">
<h5 class="card-title"><a href="{% url 'profile' username=i.username
%}">{{i.username}}</a></h5>
<p class="card-text">{{i.text}}</p>
<div class="like mt-3">
<img
data-id="{{i.id}}"
id="post-like-{{i.id}}"
class="liked"
{% if not request.user in i.like.all %}
data-is_liked="no"
src="https://img.icons8.com/carbon-copy/100/000000/like--v2.png"
{%else%}
data-is_liked="yes"
src="https://img.icons8.com/plasticine/100/000000/like.png"
{%endif%}
/>
<span id="post-count-{{post.id}}">{{i.like.count}}</span>
</div>
</div>
</div>
</div>
</div>
{% endfor %}
{% block script %}
<script src="{% static 'network/network.js'%}"></script>
{% endblock %}
When I click the 'like' heart button on the page this is what I get. Each instance of 2, happens when I click it once. So this image is from clicking the heart button 3 times:

Uploading crop image and form using cropperjs in Django

I am using https://github.com/fengyuanchen/cropper/blob/master/README.md as the cropper function. However, I want to submit field objects (in this case the title) and the cropped image. But I got an error on the admin. And of course, I have done the makemigrations and migrate before running the server
Error Picture
admin.py
from django.contrib import admin
from .models import Image
# Register your models here.
class ImageAdmin(admin.ModelAdmin):
pass
admin.site.register(Image, ImageAdmin)
models.py
from django.db import models
# Create your models here.
class Image(models.Model):
title = models.CharField(max_length=10)
image = models.ImageField(upload_to='images')
def __str__(self):
return str(self.pk)
forms.py
from django import forms
from .models import Image
class ImageForm(forms.Form):
image = forms.ImageField()
title = forms.CharField(
max_length=10,
widget=forms.TextInput(
attrs={
"class": "form-control",
"placeholder": "Title",
},
),
required=True
)
views.py
from django.shortcuts import render, redirect
from .models import Image
from .forms import ImageForm
from django.http import JsonResponse
from django.http import HttpResponseRedirect
def main_view(request):
form = ImageForm()
if request.method == "POST":
form = ImageForm(request.POST, request.FILES)
if form.is_valid():
addimage = Image(
title=form.cleaned_data['title'],
image = form.cleaned_data['image'],
)
addimage.save()
else:
form = ImageForm()
context = {'form': form}
return render(request, 'photo_list.html', context)
photo_list.html
{% extends "base.html" %}
{% block javascript %}
<script>
console.log("Hello");
const imageBox = document.getElementById("image-box");
const confirmButton = document.getElementById("confirm-button")
const input = document.getElementById("id_image");
const csrf = document.getElementsByName("csrfmiddlewaretoken")
const imageForm = document.getElementById("image-form")
input.addEventListener("change", () => {
console.log("change")
const img_data = input.files[0]
const url = URL.createObjectURL(img_data)
imageBox.innerHTML = `<img src="${url}" id="image" width="500px">`
var $image = $('#image');
$image.cropper({
aspectRatio: 16 / 9,
crop: function (event) {
console.log(event.detail.x);
console.log(event.detail.y);
console.log(event.detail.width);
console.log(event.detail.height);
console.log(event.detail.rotate);
console.log(event.detail.scaleX);
console.log(event.detail.scaleY);
}
});
// Get the Cropper.js instance after initialized
var cropper = $image.data('cropper');
confirmButton.addEventListener('click', () => {
cropper.getCroppedCanvas().toBlob((blob) => {
const fd = new FormData()
fd.append('csrfmiddlewaretoken', csrf[0].value)
fd.append('image', blob, 'my-image.png')
console.log("append pass")
$.ajax({
type: "POST",
url: imageForm.action,
enctype: 'multipart/form-data',
data: fd,
success: function (response) {
console.log(response)
},
error: function (error) {
console.log(error)
},
cache: false,
contentType: false,
processData: false,
})
})
})
});
</script>
{% endblock %}
{% block page_content %}
<form action="/cropimage/" id="image-form" method="POST">
{% csrf_token %}
{{form}}
{% comment %} <button class="btn" id="confirm-button"> confirm </button> {% endcomment %}
<input class="btn btn-lg btn-primary btn-block" type="submit" value="Submit" id="confirm-button">
</form>
<div id="image-box" class="mb-3"> </div>
{% endblock %}
I was following this tutorial https://www.youtube.com/watch?v=oWd7SAuCIRM
Basically, I am making an album of images recorded with title, but this time with cropperjs. Any solutions or suggestions would be appreciated :).
Ahh silly me, after a week of finding solutions, I finally realize that I did not put and after deleting some of the database cache.
fd.append('title', $("input[name='title']").val())
on the getCroppedCanvas()
For those who had the same problem, please..
Ref :
How to append more data in FormData for django?
OperationalError, no such column. Django
https://developer.mozilla.org/en-US/docs/Web/API/FormData/append

Livewire and FilePond. Change image order

I'm using Livewire and Filepond to allow users to upload images to a gallery.
I need my users to be able to set the order of the images and save that to the database.
Filepond has an option allowReorder: true and a callback that fires when the order has been changed onreorderfiles(files, origin, target)
Here is the basics of my upload component
<div
x-data="{ 'images': null }"
x-init="
FilePond.registerPlugin(FilePondPluginImagePreview);
FilePond.registerPlugin(FilePondPluginImageExifOrientation);
FilePond.registerPlugin(FilePondPluginFileValidateType);
FilePond.registerPlugin(FilePondPluginFileValidateSize);
FilePond.registerPlugin(FilePondPluginImageResize);
FilePond.setOptions({
allowMultiple: true,
allowReorder: true,
server: {
process: (fieldName, file, metadata, load, error, progress, abort, transfer, options) => {
#this.upload('images', file, load, error, progress)
},
revert: (filename, load) => {
#this.removeUpload('images', filename, load)
},
},
onreorderfiles(files, origin, target){
// **** What do I put here to update the order of the images in my livewire component? ******
},
});
const pond = FilePond.create($refs.input, {
acceptedFileTypes: ['image/png', 'image/jpeg'],
maxFileSize: '7MB',
allowImageCrop: true,
allowImageResize: true,
imageResizeTargetWidth: '1000px',
imageResizeTargetHeight: '1000px',
});
pond.on('addfile', (error, file) => {
if (error) {
console.log('Oh no');
return;
}
images = true;
});
"
>
<div wire:ignore wire:key="images">
<div x-show="images == null" class="ex-builder-no-images">
<i class="fas fa-image"></i>
<p>There are no images for this experience.
<br>Upload some below. <br><small>(MAX 10 Images)</small></p>
</div>
<div class="form-group text-center">
<input
id="image-upload"
type="file"
x-ref="input"
multiple
>
#error('images.*')
<p wire:key="error_images" class="mt-2 text-sm text-red-600" id="email-error">{{ $message }}</p>
#enderror
</div>
</div>
</div>
I'm also showing a preview of the first image in the gallery (this is the gallery's featured image) like this <img src="{{ $images ? $images[0]->temporaryUrl() : '/images/placeholder.jpg' }}"> I'm expecting this image to update after the user drags a new image to be the first.
How can I update the image order in the public $images = []; found in my livewire componenet using the onreoderfiles() callback?
Thanks!
Not sure if this is correct, but it seems to work
I added this to FilePond.setOptions()
FilePond.setOptions({
allowMultiple: true,
allowReorder: true,
server: {
process: (fieldName, file, metadata, load, error, progress, abort, transfer, options) => {
#this.upload('images', file, load, error, progress)
},
revert: (filename, load) => {
#this.removeUpload('images', filename, load)
},
},
// Added this ----------------------------------------
onreorderfiles(files, origin, target){
#this.set('images', null);
files.forEach(function(file) {
#this.upload('images', file.file);
});
},
});
This removes the previous uploaded images and reuploads with the new order.

How to show custom server errors in UI using Plupload and Symfony3

INTRODUCTION
In order to upload multiple files to the server I am using:
Symfony v3.2.6
OneUpUploaderBundle
OneUpFlysystemBundle
Plupload file uploading library
NOTE
Please note that: this configuration works without a hitch for single and multiple file uploads. It just does not show custom server errors in the clients browser.
TARGET
I would like to show file exists error in UI
PROBLEM
I am using validator to restrict some uploadable files.
At the moment files that validator restricts are not uploaded (ValidationException is beeing trown).
I do not know how to make Plupload to show file already exist errors.
CODE
My template with relevant javascript code
{% extends 'base.html.twig' %}
{% block stylesheets %}
{{ parent() }}
<link type="text/css" rel="stylesheet" href="{{ asset('js/plupload/jquery-ui-1.12.1/jquery-ui.css') }}" />
<link type="text/css" rel="stylesheet" href="{{ asset('js/plupload/jquery.ui.plupload/css/jquery.ui.plupload.css') }}" media="screen" />
{% endblock %}
{% block content %}
<div id="box-upload">
<div id="uploader">
<p>Your browser doesn't have HTML5 support.</p>
</div>
</div>
{% endblock %}
{% block javascripts %}
<script type="text/javascript" src="{{ asset('js/browserplus/browserplus.js') }}"></script>
<script type="text/javascript" src="{{ asset('js/plupload/plupload.full.min.js') }}"></script>
<script type="text/javascript" src="{{ asset('js/jquery-2.2.4.js') }}"></script>
<script type="text/javascript" src="{{ asset('js/plupload/jquery-ui-1.12.1/jquery-ui.js') }}"></script>
<script type="text/javascript" src="{{ asset('js/plupload/jquery.ui.plupload/jquery.ui.plupload.js') }}"></script>
<script type="text/javascript" src="{{ asset('js/plupload/i18n/lv.js') }}"></script>
<script type="text/javascript">
'use strict';
$(function()
{
var uploader;
uploader = $("#uploader");
uploader.plupload(
{
// General settings
runtimes: 'html5',
url: "{{ oneup_uploader_endpoint('gallery') }}",
multi_selection: true,
// Maximum file size
max_file_size: '5mb',
chunk_size: '5mb',
// Specify what files to browse for
filters: [
{title: "Image files", extensions: "jpg,jpeg,png,gif"},
{title: "Zip files", extensions: "zip,7z"},
{title: "Pdf files", extensions: "pdf"},
{title: "Binary files", extensions: "bin"},
{title: "Text files", extensions: "txt"},
{title: "Media files", extensions: "avi"}
],
// Rename files by clicking on their titles
rename: true,
// Sort files
sortable: true,
// Enable ability to drag'n'drop files onto the widget (currently only HTML5 supports that)
dragdrop: true,
// Views to activate
views: {
list: true,
thumbs: false, // Show thumbs
active: 'list'
}
});
var $uploader = uploader.plupload('getUploader');
// Add Clear Button
var $button = $("<button>"+ plupload.translate("Clear list") + "</button>").button({icons: {primary: "ui-icon-trash"}}).button("disable").appendTo('.plupload_buttons');
// Clear Button Action
$button.click(function()
{
removeErrorMessages();
$uploader.splice();
$(".plupload_filelist_content").html('');
$button.button("disable");
return true;
});
// Clear Button Toggle Enabled
$uploader.bind('QueueChanged', function ()
{
if ($uploader.files.length > 0)
{
$button.button("enable");
}
else
{
$button.button("disable");
}
});
// Clear Button Toggle Hidden
$uploader.bind('StateChanged', function ()
{
if ($uploader.state == plupload.STARTED)
{
$button.hide();
}
else
{
$button.show();
}
});
// Clear Button Toggle Hidden
$uploader.bind('Browse', function ()
{
removeErrorMessages();
$uploader.splice();
});
$uploader.bind('Error', function(uploader, error)
{
console.error(error.message);
console.log(error.message);
});
function removeErrorMessages()
{
$(".ui-state-error").remove();
}
});
</script>
{% endblock %}
My validator
<?php
namespace AppBundle\EventListener;
use Oneup\UploaderBundle\Event\ValidationEvent;
use Oneup\UploaderBundle\Uploader\Exception\ValidationException;
use Symfony\Component\DependencyInjection\ContainerInterface as Container;
class AllowedMimeTypeValidationListener
{
/**
* #var Container
*/
private $container;
private $file_extension_array = [];
private $file_type_array = [];
private $banned_files = [];
public function __construct(Container $container)
{
$this->container = $container;
}
public function onValidate(ValidationEvent $event)
{
$ultra_helpers = $this->container->get('app.ultra_helpers');
$ultra_text = $this->container->get('app.ultra_text');
array_push($this->file_extension_array, '.gif');
array_push($this->file_extension_array, '.jpg');
array_push($this->file_extension_array, '.jpeg');
array_push($this->file_extension_array, '.png');
array_push($this->file_extension_array, '.zip');
array_push($this->file_extension_array, '.7z');
array_push($this->file_extension_array, '.pdf');
array_push($this->file_extension_array, '.bin');
array_push($this->file_extension_array, '.txt');
array_push($this->file_type_array, 'image/gif');
array_push($this->file_type_array, 'image/jpg');
array_push($this->file_type_array, 'image/jpeg');
array_push($this->file_type_array, 'image/png');
array_push($this->file_type_array, 'application/zip');
array_push($this->file_type_array, 'application/x-7z-compressed');
array_push($this->file_type_array, 'application/pdf');
array_push($this->file_type_array, 'application/octet-stream');
array_push($this->file_type_array, 'text/plain');
array_push($this->banned_files, 'do_not_allow_me_1.txt');
array_push($this->banned_files, 'do_not_allow_me_3.txt');
array_push($this->banned_files, 'do_not_allow_me_2.txt');
$file = $event->getFile();
$file_extension = '.'. $file->getExtension();
$file_mime_type = $file->getMimeType();
$file_info = $ultra_helpers->filterFileInfoFromFilename($file->getClientOriginalName());
$transliterated_file_name = $ultra_text->transliterateText($file_info['name']);
$full_file_name = $transliterated_file_name .'.'. $file_info['extension'];
if (in_array($full_file_name, $this->banned_files))
{
throw new ValidationException('error.file_exists');
}
// Is file mime type the same as extension mime type
$mime_type_position = array_search($file_extension, $this->file_extension_array);
if ($mime_type_position !== false)
{
$mime_type_by_extension = $this->file_type_array[$mime_type_position];
if ($mime_type_by_extension !== $file_mime_type)
{
throw new ValidationException('error.mime_type_mismatch');
}
}
// Is file type not in activated file type array
if (!in_array($file_mime_type, $this->file_type_array))
{
throw new ValidationException('error.forbidden_mime_type');
}
}
}
FINALLY
What am I missing?
CONCLUSION
Please advise.
Thank You for your time and knowledge.
To show error in UI one has to listen to FileUploaded event and manually trigger an error (like in code example below).
$uploader.bind('FileUploaded', function(up, file, info)
{
var response;
response = jQuery.parseJSON(info.response);
// trigger error manually
up.trigger("error", {message: "Test error message", code: 12345, details: "Testing errors"});
// add some CSS class to the corresponding file in UI
$("#"+ file.id).addClass("highlight-file");
});

Categories

Resources