Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Fetching contributors…

Cannot retrieve contributors at this time

315 lines (238 sloc) 9.81 kB
"""
gargoyle.nexus_modules
~~~~~~~~~~~~~~~~~~~~~~
:copyright: (c) 2010 DISQUS.
:license: Apache License 2.0, see LICENSE for more details.
"""
import logging
import nexus
import os.path
from functools import wraps
from django.conf import settings
from django.http import HttpResponse, HttpResponseNotFound
from gargoyle import gargoyle, autodiscover
from gargoyle.helpers import dumps
from gargoyle.models import Switch, DISABLED
from gargoyle.conditions import ValidationError
from gargoyle import signals
GARGOYLE_ROOT = os.path.dirname(__file__)
autodiscover()
logger = logging.getLogger('gargoyle.switches')
class GargoyleException(Exception):
def __init__(self, message):
self.message = message
def __str__(self):
return self.message
def json(func):
"Decorator to make JSON views simpler"
def wrapper(self, request, *args, **kwargs):
try:
response = {
"success": True,
"data": func(self, request, *args, **kwargs)
}
except GargoyleException, exc:
response = {
"success": False,
"data": exc.message
}
except Switch.DoesNotExist:
response = {
"success": False,
"data": "Switch cannot be found"
}
except ValidationError, e:
response = {
"success": False,
"data": u','.join(map(unicode, e.messages)),
}
except Exception:
if settings.DEBUG:
import traceback
traceback.print_exc()
raise
return HttpResponse(dumps(response), mimetype="application/json")
wrapper = wraps(func)(wrapper)
return wrapper
class GargoyleModule(nexus.NexusModule):
home_url = 'index'
name = 'gargoyle'
def get_title(self):
return 'Gargoyle'
def get_urls(self):
from django.conf.urls.defaults import patterns, url
urlpatterns = patterns('',
url(r'^add/$', self.as_view(self.add), name='add'),
url(r'^update/$', self.as_view(self.update), name='update'),
url(r'^delete/$', self.as_view(self.delete), name='delete'),
url(r'^status/$', self.as_view(self.status), name='status'),
url(r'^conditions/add/$', self.as_view(self.add_condition), name='add-condition'),
url(r'^conditions/remove/$', self.as_view(self.remove_condition), name='remove-condition'),
url(r'^$', self.as_view(self.index), name='index'),
)
return urlpatterns
def render_on_dashboard(self, request):
active_switches_count = Switch.objects.exclude(status=DISABLED).count()
switches = list(Switch.objects.exclude(status=DISABLED).order_by("date_created")[:5])
return self.render_to_string('gargoyle/nexus/dashboard.html', {
'switches': switches,
'active_switches_count': active_switches_count,
})
def index(self, request):
sort_by = request.GET.get('by', '-date_modified')
if sort_by not in self.valid_sort_orders:
return HttpResponseNotFound('Invalid sort order.')
switches = list(Switch.objects.all().order_by(sort_by))
return self.render_to_response("gargoyle/index.html", {
"switches": [s.to_dict(gargoyle) for s in switches],
"all_conditions": list(gargoyle.get_all_conditions()),
"sorted_by": sort_by
}, request)
def add(self, request):
key = request.POST.get("key")
if not key:
raise GargoyleException("Key cannot be empty")
if len(key) > 32:
raise GargoyleException("Key must be less than or equal to 32 characters in length")
label = request.POST.get("name", "").strip()
if len(label) > 32:
raise GargoyleException("Name must be less than or equal to 32 characters in length")
switch, created = Switch.objects.get_or_create(
key=key,
defaults=dict(
label=label or None,
description=request.POST.get("desc")
)
)
if not created:
raise GargoyleException("Switch with key %s already exists" % key)
logger.info('Switch %r added (%%s)' % switch.key,
', '.join('%s=%r' % (k, getattr(switch, k)) for k in sorted(('key', 'label', 'description', ))))
signals.switch_added.send(
sender=self,
request=request,
switch=switch,
)
return switch.to_dict(gargoyle)
add = json(add)
def update(self, request):
switch = Switch.objects.get(key=request.POST.get("curkey"))
key = request.POST.get("key")
if len(key) > 32:
raise GargoyleException("Key must be less than or equal to 32 characters in length")
label = request.POST.get("name", "")
if len(label) > 32:
raise GargoyleException("Name must be less than or equal to 32 characters in length")
values = dict(
label=label,
key=key,
description=request.POST.get("desc"),
)
changes = {}
for key, value in values.iteritems():
new_value = getattr(switch, key)
if new_value != value:
changes[key] = (value, new_value)
if changes:
if switch.key != key:
switch.delete()
switch.key = key
switch.label = label
switch.description = request.POST.get("desc")
switch.save()
logger.info('Switch %r updated %%s' % switch.key,
', '.join('%s=%r->%r' % (k, v[0], v[1]) for k, v in sorted(changes.iteritems())))
signals.switch_updated.send(
sender=self,
request=request,
switch=switch,
changes=changes,
)
return switch.to_dict(gargoyle)
update = json(update)
def status(self, request):
switch = Switch.objects.get(key=request.POST.get("key"))
try:
status = int(request.POST.get("status"))
except ValueError:
raise GargoyleException("Status must be integer")
old_status = switch.status
old_status_label = switch.get_status_display()
if switch.status != status:
switch.status = status
switch.save()
logger.info('Switch %r updated (status=%%s->%%s)' % switch.key,
old_status_label, switch.get_status_display())
signals.switch_status_updated.send(
sender=self,
request=request,
switch=switch,
old_status=old_status,
status=status,
)
return switch.to_dict(gargoyle)
status = json(status)
def delete(self, request):
switch = Switch.objects.get(key=request.POST.get("key"))
switch.delete()
logger.info('Switch %r removed' % switch.key)
signals.switch_deleted.send(
sender=self,
request=request,
switch=switch,
)
return {}
delete = json(delete)
def add_condition(self, request):
key = request.POST.get("key")
condition_set_id = request.POST.get("id")
field_name = request.POST.get("field")
exclude = int(request.POST.get("exclude") or 0)
if not all([key, condition_set_id, field_name]):
raise GargoyleException("Fields cannot be empty")
field = gargoyle.get_condition_set_by_id(condition_set_id).fields[field_name]
value = field.validate(request.POST)
switch = gargoyle[key]
switch.add_condition(condition_set_id, field_name, value, exclude=exclude)
logger.info('Condition added to %r (%r, %s=%r, exclude=%r)' % (switch.key,
condition_set_id, field_name, value, bool(exclude)))
signals.switch_condition_added.send(
sender=self,
request=request,
switch=switch,
condition={
'condition_set_id': condition_set_id,
'field_name': field_name,
'value': value,
},
)
return switch.to_dict(gargoyle)
add_condition = json(add_condition)
def remove_condition(self, request):
key = request.POST.get("key")
condition_set_id = request.POST.get("id")
field_name = request.POST.get("field")
value = request.POST.get("value")
if not all([key, condition_set_id, field_name, value]):
raise GargoyleException("Fields cannot be empty")
switch = gargoyle[key]
switch.remove_condition(condition_set_id, field_name, value)
logger.info('Condition removed from %r (%r, %s=%r)' % (switch.key,
condition_set_id, field_name, value))
signals.switch_condition_removed.send(
sender=self,
request=request,
switch=switch,
condition={
'condition_set_id': condition_set_id,
'field_name': field_name,
'value': value,
},
)
return switch.to_dict(gargoyle)
remove_condition = json(remove_condition)
@property
def valid_sort_orders(self):
fields = ['label', 'date_created', 'date_modified']
return fields + ['-' + f for f in fields]
nexus.site.register(GargoyleModule, 'gargoyle')
Jump to Line
Something went wrong with that request. Please try again.