Skip to content

Commit

Permalink
Fix bug 963248: Add size validation to snippet admin.
Browse files Browse the repository at this point in the history
  • Loading branch information
koddsson authored and Michael Kelly committed Dec 30, 2014
1 parent 1aed8e0 commit 4e77df9
Show file tree
Hide file tree
Showing 6 changed files with 66 additions and 4 deletions.
8 changes: 6 additions & 2 deletions snippets/base/forms.py
Expand Up @@ -66,15 +66,19 @@ def render(self, name, value, attrs=None):
<div class="widget-container">
<div class="template-data-widget"
data-select-name="{select_name}"
data-input-name="{input_name}">
data-input-name="{input_name}"
data-snippet-size-limit="{size_limit}"
data-snippet-img-size-limit="{img_size_limit}">
</div>
<div class="snippet-preview-container"
data-preview-url="{preview_url}">
</div>
</div>
""".format(select_name=self.template_select_name,
input_name=name,
preview_url=reverse('base.preview'))
preview_url=reverse('base.preview'),
size_limit=settings.SNIPPET_SIZE_LIMIT,
img_size_limit=settings.SNIPPET_IMAGE_SIZE_LIMIT)
]))

class Media:
Expand Down
47 changes: 46 additions & 1 deletion snippets/base/static/js/templateDataWidget.js
Expand Up @@ -41,6 +41,9 @@
this.$templateSelect = $('select[name="' + selectName + '"]');
this.$dataInput = $('input[name="' + inputName + '"]');

this.snippetSizeThreshold = this.$container.data('snippetSizeLimit')
this.snippetImgSizeThreshold = this.$container.data('snippetImgSizeLimit');

// Throw an error if we can't find the elements we need.
if (!(this.$templateSelect.exists() && this.$dataInput.exists())) {
throw ('Snippet data widget error: Template select or data ' +
Expand Down Expand Up @@ -76,13 +79,29 @@
SnippetDataWidget.prototype = {
bindEvents: function() {
var self = this;

$(document).ready(function() {
self.$container.find('img').each(function(_, img) {
if (!img.src) return;
var data = img.src.split(',')[1];
var binary = atob(data.replace(/\s/g, ''));

if (binary.length / 1024 > self.snippetImgSizeThreshold) {
var msg = 'Icon file too large. Consider using a smaller ' +
'icon. (Under ' + self.snippetImgSizeThreshold + 'kb)';
$(img).siblings('.fileSize').html(msg).css('color', 'red');
} else {
$(img).siblings('.fileSize').html('');
}
});
});

this.$templateSelect.change(function() {
self.onTemplateChange();
});

this.$container.parents('form').submit(function() {
self.onFormSubmit();
return self.onFormSubmit();
});

this.$container.on('change', '.image-input', function() {
Expand Down Expand Up @@ -151,6 +170,14 @@
return;
}

if (file.size / 1024 > self.snippetImgSizeThreshold) {
var msg = 'Icon file too large. Consider using a smaller ' +
'icon. (Under ' + self.snippetImgSizeThreshold + 'kb)';
$(input).siblings('.fileSize').html(msg).css('color', 'red');
} else {
$(input).siblings('.fileSize').html('');
}

// Load file.
var preview = $(input).siblings('img')[0];
var reader = new FileReader();
Expand Down Expand Up @@ -197,7 +224,25 @@
* the original data input.
*/
onFormSubmit: function() {
var confirmed;
var self = this;
this.$dataInput.val(JSON.stringify(this.generateData()));
var data = this.$dataInput.serialize() + '&template_id=' + this.$templateSelect.val() + '&skip_boilerplate=true';
$.ajax({
type: 'POST',
url:'/preview/',
data: data,
async: false,
success: function(data, textStatus, request) {
var size = new Blob([data], {type: 'text/html'}).size / 1024;
if (size > self.snippetSizeThreshold) {
var msg = "This snippet is over " + self.snippetSizeThreshold + "kb threshold! (" +
size.toFixed() + "kb) Are you sure you want to save it?";
confirmed = confirm(msg);
}
}
});
return confirmed;
}
};

Expand Down
1 change: 1 addition & 0 deletions snippets/base/static/templates/snippetDataWidget.html
Expand Up @@ -12,6 +12,7 @@
{% elif variable.type == types.image %}
<img src="{{ originalData[variable.name] }}">
<input type="file" class="image-input">
<div class='fileSize'></div>
{% elif variable.type == types.smalltext %}
<input class="smalltext" value="{{ originalData[variable.name] }}">
{% elif variable.type == types.checkbox %}
Expand Down
1 change: 1 addition & 0 deletions snippets/base/templates/base/preview_without_shell.html
@@ -0,0 +1 @@
{{ snippet.render() }}
10 changes: 9 additions & 1 deletion snippets/base/views.py
@@ -1,6 +1,8 @@
import hashlib
import json

from distutils.util import strtobool

from django.conf import settings
from django.contrib.auth.decorators import permission_required
from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger
Expand Down Expand Up @@ -151,7 +153,13 @@ def preview_snippet(request):

# Build a snippet that isn't saved so we can render it.
snippet = Snippet(template=template, data=data)
return render(request, 'base/preview.html', {

skip_boilerplate = request.POST.get('skip_boilerplate', 'false')
skip_boilerplate = strtobool(skip_boilerplate)

template_name = 'base/preview_without_shell.html' if skip_boilerplate else 'base/preview.html'

return render(request, template_name, {
'snippet': snippet,
'client': PREVIEW_CLIENT,
'preview': True
Expand Down
3 changes: 3 additions & 0 deletions snippets/settings/base.py
Expand Up @@ -85,3 +85,6 @@ def _allowed_hosts():
ALLOWED_HOSTS = lazy(_allowed_hosts, list)()

# CDN_URL = 'https://snippets.cdn.mozilla.net/'

SNIPPET_SIZE_LIMIT = 200
SNIPPET_IMAGE_SIZE_LIMIT = 100

0 comments on commit 4e77df9

Please sign in to comment.