Skip to content

Commit

Permalink
Merge pull request mozilla#1 from Osmose/663576-snippet-service-impr
Browse files Browse the repository at this point in the history
663576 Basic Snippet Body Editor
  • Loading branch information
Michael Kelly authored and Michael Kelly committed Jun 16, 2011
2 parents 32c1a7c + e2695f7 commit 7ba7981
Show file tree
Hide file tree
Showing 8 changed files with 339 additions and 52 deletions.
90 changes: 57 additions & 33 deletions apps/homesnippets/admin.py
@@ -1,18 +1,15 @@
import os
from datetime import datetime

from django.contrib import admin, messages
from django import forms
from django.contrib import admin, messages
from django.db import models
from django.http import HttpResponse
from django.template.loader import render_to_string
from django.utils.encoding import smart_unicode
from django.utils.safestring import mark_safe

from django.db.models import get_app, get_apps, get_model, get_models
from django.http import HttpResponse, HttpResponseRedirect
from django.shortcuts import render_to_response

from smuggler.settings import SMUGGLER_FORMAT, SMUGGLER_FIXTURE_DIR
from smuggler.utils import (get_excluded_models_set, get_file_list,
save_uploaded_file_on_disk, serialize_to_response,
superuser_required)
from smuggler.settings import SMUGGLER_FORMAT
from smuggler.utils import serialize_to_response

from homesnippets.models import Snippet, ClientMatchRule

Expand All @@ -28,54 +25,59 @@ def dump_selected(modeladmin, request, queryset):

dump_selected.short_description = "Dump selected objects as JSON data"


def dump_selected_snippets(modeladmin, request, queryset):
"""Produce a smuggler dump for a selected set of snippets, along with
associated client match rules."""
snippets = queryset.all()

# Assemble a unique set of client match rules used by selected snippets.
rules = dict( )
rules = dict()
for s in snippets:
for rule in s.client_match_rules.all():
rules[rule.pk] = rule

# Combine set of rules and snippets for output
objects = rules.values() + list( snippets )
objects = rules.values() + list(snippets)

filename = '%s-%s_%s.%s' % ('homesnippets', 'snippets',
datetime.now().isoformat(), SMUGGLER_FORMAT)
response = HttpResponse(mimetype="text/plain")
response['Content-Disposition'] = 'attachment; filename=%s' % filename
return serialize_to_response(objects, response)

dump_selected_snippets.short_description = "Dump selected snippets (and client match rules) as JSON data"
dump_selected_snippets.short_description = "Dump selected snippets (and " \
"client match rules) as JSON data"


def disable_selected_snippets(modeladmin, request, queryset):
cnt = 0
for snippet in queryset.all():
snippet.disabled = True
snippet.save()
cnt += 1
messages.add_message(request, messages.INFO,
messages.add_message(request, messages.INFO,
('%(cnt)d snippet(s) disabled') % dict(cnt=cnt))

disable_selected_snippets.short_description = "Disable selected snippets"


def enable_selected_snippets(modeladmin, request, queryset):
cnt = 0
for snippet in queryset.all():
snippet.disabled = False
snippet.save()
cnt += 1
messages.add_message(request, messages.INFO,
messages.add_message(request, messages.INFO,
('%(cnt)d snippet(s) enabled') % dict(cnt=cnt))

enable_selected_snippets.short_description = "Enable selected snippets"


class ClientMatchRuleAdmin(admin.ModelAdmin):
change_list_template = 'smuggler/change_list.html'

actions = [ dump_selected ]
actions = [dump_selected]
dump_name = 'clientmatchrules'

list_per_page = 250
Expand All @@ -84,9 +86,9 @@ class ClientMatchRuleAdmin(admin.ModelAdmin):
'description',
'related_snippets',
'exclude',
'startpage_version', 'name', 'version',
'startpage_version', 'name', 'version',
'locale',
'appbuildid', 'build_target',
'appbuildid', 'build_target',
'channel', 'os_version', 'distribution', 'distribution_version',
'modified',
)
Expand All @@ -95,23 +97,39 @@ class ClientMatchRuleAdmin(admin.ModelAdmin):
)

list_filter = (
'name', 'version', 'os_version',
'name', 'version', 'os_version',
'appbuildid', 'build_target', 'channel', 'distribution',
'locale',
'locale',
)

admin.site.register(ClientMatchRule, ClientMatchRuleAdmin)


class SnippetBodyWidget(forms.Textarea):
class Media:
css = {
'all': ('snippetBodyWidget.css',)
}
js = ('jquery-1.6.1.min.js', 'jquery.easytabs.min.js',
'snippetBodyWidget.js')

def render(self, name, value, attrs=None):
textarea = super(SnippetBodyWidget, self).render(name, value, attrs)
widget = render_to_string('snippetBodyWidget.html',
{"textarea": textarea})
return mark_safe(smart_unicode(widget))


class SnippetAdmin(admin.ModelAdmin):
change_list_template = 'smuggler/change_list.html'

actions = [
actions = [
dump_selected_snippets,
disable_selected_snippets,
enable_selected_snippets,
]
dump_name = 'snippets'

save_on_top = True
actions_on_bottom = True

Expand All @@ -126,20 +144,20 @@ class SnippetAdmin(admin.ModelAdmin):
'client_match_rules',
)

fields = (
'name', 'body',
fields = (
'name', 'body',
'preview', 'disabled',
'priority', 'pub_start', 'pub_end',
'client_match_rules',
'priority', 'pub_start', 'pub_end',
'client_match_rules',
)

list_per_page = 250
list_display = (
'name',

list_display = (
'name',
'disabled',
'priority', 'pub_start', 'pub_end',
'modified'
'modified'
)

list_links = (
Expand All @@ -151,12 +169,18 @@ class SnippetAdmin(admin.ModelAdmin):
'pub_start', 'pub_end',
)

filter_horizontal = ( 'client_match_rules', )
filter_horizontal = ('client_match_rules',)

formfield_overrides = {
models.ManyToManyField: {
"widget": forms.widgets.SelectMultiple(attrs={"size":50})
"widget": forms.widgets.SelectMultiple(attrs={"size": 50})
}
}

def formfield_for_dbfield(self, db_field, **kwargs):
if db_field.name == 'body':
kwargs['widget'] = SnippetBodyWidget
return super(SnippetAdmin, self).formfield_for_dbfield(db_field,
**kwargs)

admin.site.register(Snippet, SnippetAdmin)
23 changes: 23 additions & 0 deletions apps/homesnippets/templates/snippetBodyWidget.html
@@ -0,0 +1,23 @@
<div id="snippet-editor">
<ul id="snippet-tabs">
<li><a href="#snippet-basic">{{ _('Basic') }}</a></li>
<li><a href="#snippet-advanced">{{ _('Advanced') }}</a></li>
</ul>
<div id="snippet-basic" class="panel-container">
<div>{{ _('Snippet Preview') }}</div>
<div id="snippet-preview"></div>
<div id="snippet-basic-inputs">
<label for="snippet-icon-url">{{ _('Icon URL (png only)') }}:</label>
<input type="text" id="snippet-icon-url" />
<div>
<button type="button" id="snippet-embed-button">{{ _('Change Icon') }}</button>
</div>
<label for="snippet-text">{{ _('Text') }}:</label>
<textarea id="snippet-text"></textarea>
</div>
<div>{{ _('Add a link using wiki-syntax') }}: <code>[http://www.mozilla.com|{{ _('Link Text') }}]</code></div>
</div>
<div id="snippet-advanced" class="panel-container">
{{ textarea }}
</div>
</div>
1 change: 1 addition & 0 deletions apps/homesnippets/urls.py
Expand Up @@ -13,5 +13,6 @@
url(r'^preview/(?P<startpage_version>[^/]+)/(?P<name>[^/]+)/(?P<version>[^/]+)/(?P<appbuildid>[^/]+)/(?P<build_target>[^/]+)/(?P<locale>[^/]+)/(?P<channel>[^/]+)/(?P<os_version>[^/]+)/(?P<distribution>[^/]+)/(?P<distribution_version>[^/]+)/$',
'view_snippets', name='preview_snippets', kwargs={'preview':True}),

url(r"^base64encode/(?P<url>.+)$", "base64_encode", name="base64_encode"),
url(r"^$", "index", name="index"),
)
49 changes: 30 additions & 19 deletions apps/homesnippets/views.py
@@ -1,23 +1,17 @@
"""
Views for home snippets server
"""
import random
from time import time, mktime, gmtime, strftime
import base64
import json
from time import gmtime, strftime
from urllib2 import urlopen, URLError

from django.conf import settings

from django.core.urlresolvers import reverse

from django.http import HttpResponseRedirect, HttpResponse
from django.http import HttpResponseForbidden, HttpResponseNotModified

from django.template import RequestContext

from django.views.decorators import http
from django.views.decorators.vary import vary_on_headers
from django.views.decorators.cache import cache_control, cache_page

from django.contrib.admin.views.decorators import staff_member_required
from django.http import HttpResponse, Http404
from django.shortcuts import render_to_response
from django.template import RequestContext
from django.views.decorators.cache import cache_control

from homesnippets.models import Snippet

Expand All @@ -32,6 +26,7 @@ def index(request):
return render_to_response('index.html', {},
context_instance=RequestContext(request))


@cache_control(public=True, max_age=HTTP_MAX_AGE)
def handler404(request):
"""For 404's, just return a blank cacheable 200 OK response.
Expand All @@ -40,11 +35,12 @@ def handler404(request):
server as much.
"""
resp = HttpResponse('')
resp['Access-Control-Allow-Origin'] = '*'
resp['Access-Control-Allow-Origin'] = '*'
resp['Access-Control-Max-Age'] = HTTP_MAX_AGE
resp['Access-Control-Allow-Methods'] = 'GET, HEAD, OPTIONS'
return resp


def view_snippets(request, **kwargs):
"""Fetch and render snippets matching URL segment args"""

Expand All @@ -54,10 +50,10 @@ def view_snippets(request, **kwargs):
if len(snippets) == 0:
out_txt = ''
else:
out = [ snippet['body'] for snippet in snippets ]
out = [snippet['body'] for snippet in snippets]

out.append('<!-- content generated at %s -->' %
( strftime('%Y-%m-%dT%H:%M:%SZ', gmtime() ) ) )
(strftime('%Y-%m-%dT%H:%M:%SZ', gmtime())))

out_txt = '<div class="snippet_set">%s</div>' % "\n\n".join(out)

Expand All @@ -69,13 +65,28 @@ def view_snippets(request, **kwargs):
resp['Cache-Control'] = 'public, must-revalidate, max-age=0'
else:
max_age = HTTP_MAX_AGE
resp['Cache-Control'] = 'public, max-age=%s' % ( HTTP_MAX_AGE )
resp['Cache-Control'] = 'public, max-age=%s' % (HTTP_MAX_AGE)

# TODO: bug 606555 - Get ACAO working with about:home?
resp['Access-Control-Allow-Origin'] = '*'
resp['Access-Control-Allow-Origin'] = '*'
resp['Access-Control-Max-Age'] = max_age
resp['Access-Control-Allow-Methods'] = 'GET, HEAD, OPTIONS'

resp['X-FRAME-OPTIONS'] = None

return resp


@staff_member_required
def base64_encode(request, **kwargs):
"""Encode a remote image to base64, and output as JSON"""

url = kwargs['url']
try:
img_file = urlopen(url)
base64_str = base64.encodestring(img_file.read())
except (URLError, ValueError):
raise Http404

return HttpResponse(json.dumps({'img': base64_str}),
mimetype='applications/json')
18 changes: 18 additions & 0 deletions site_media/jquery-1.6.1.min.js

Large diffs are not rendered by default.

12 changes: 12 additions & 0 deletions site_media/jquery.easytabs.min.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit 7ba7981

Please sign in to comment.