Skip to content
This repository has been archived by the owner on Jun 20, 2018. It is now read-only.

Add session specific controls to dashboard so that users who have permiss #13

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 6 additions & 2 deletions gargoyle/media/css/gargoyle.css
Original file line number Diff line number Diff line change
Expand Up @@ -133,18 +133,22 @@
margin-bottom: 2px;
}

#container table.switches td.status {
#container table.switches td.status, #container table.switches td.sessionStatus {
width: 200px;
text-align: center;
}
#container table.switches td.status p {
#container table.switches td.sessionStatus {
width: 330px;
}
#container table.switches td.status p, #container table.switches td.sessionStatus p {
color: #999;
margin-top: 15px;
font-size: 85%;
text-transform: lowercase;
margin-bottom: 0;
}


#container table.switches td.actions {
text-align: right;
width: 70px;
Expand Down
28 changes: 27 additions & 1 deletion gargoyle/media/js/gargoyle.js
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ $(document).ready(function () {

function (swtch) {
if (swtch.status == status) {
row.find(".toggled").removeClass("toggled");
row.find(".status .toggled").removeClass("toggled");
el.addClass("toggled");
if (!swtch.conditions && swtch.status == 2) {
swtch.status = 3;
Expand All @@ -108,6 +108,32 @@ $(document).ready(function () {
});
});

$(".switches td.sessionStatus button").live("click", function () {
var row = $(this).parents("tr:first");
var el = $(this);
var session_status = el.attr("data-session-status");
var labels = {}
labels[GARGOYLE.SESSION_BYPASS] = "(No manual override)"
labels[GARGOYLE.SESSION_DISABLED] = "(Manually disabled for my session)"
labels[GARGOYLE.SESSION_ENABLED] = "(Manually enabled for my session)"

api(GARGOYLE.updateSessionStatus,
{
key: row.attr("data-switch-key"),
session_status: session_status
},

function (data) {
if (data.session_status == session_status) {
document.cookie = data.cookie_key + '=' + data.cookie_value + ';path=/'
row.find(".sessionStatus .toggled").removeClass("toggled");
el.addClass("toggled");
row.find('.sessionStatus p').text(labels[data.session_status]);
}
});
});


$("p.addCondition a").live("click", function (ev) {
ev.preventDefault();
var form = $(this).parents("td:first").find("div.conditionsForm:first");
Expand Down
47 changes: 35 additions & 12 deletions gargoyle/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,25 @@
from jsonfield import JSONField
from modeldict import ModelDict

from nexus import site

DISABLED = 1
SELECTIVE = 2
GLOBAL = 3

INCLUDE = 'i'
EXCLUDE = 'e'

SESSION_BYPASS = 'bypass'
SESSION_DISABLED = 'disabled'
SESSION_ENABLED = 'enabled'

SESSION_STATUS_CHOICES = (
(SESSION_BYPASS, 'Session Bypass'),
(SESSION_ENABLED, 'Session Enabled'),
(SESSION_DISABLED, 'Session Disabled'),
)

class Switch(models.Model):
"""
Stores information on all switches. Generally handled through an instance of ``ModelDict``,
Expand All @@ -28,13 +40,13 @@ class Switch(models.Model):
>>> }
>>> }
"""

STATUS_CHOICES = (
(DISABLED, 'Disabled'),
(SELECTIVE, 'Selective'),
(GLOBAL, 'Global'),
)

key = models.CharField(max_length=32, primary_key=True)
value = JSONField(default="{}")
label = models.CharField(max_length=32, null=True)
Expand Down Expand Up @@ -143,7 +155,7 @@ def remove_condition(self, manager, condition_set, field_name, condition, commit

if namespace not in self.value:
return

if field_name not in self.value[namespace]:
return

Expand Down Expand Up @@ -176,14 +188,14 @@ def clear_conditions(self, manager, condition_set, field_name=None, commit=True)

if namespace not in self.value:
return

if not field_name:
del self.value[namespace]
elif field_name not in self.value[namespace]:
return
else:
del self.value[namespace][field_name]

if commit:
self.save()

Expand Down Expand Up @@ -265,12 +277,28 @@ def is_active(self, key, *instances):

>>> gargoyle.is_active('my_feature', request) #doctest: +SKIP
"""

try:
switch = self[key]
except KeyError:
return False

if instances:
# HACK: support request.user by swapping in User instance
instances = list(instances)
for v in instances:
if isinstance(v, HttpRequest) and hasattr(v, 'user'):
instances.append(v.user)
if site.has_permission(v):
try:
session_status = v.COOKIES.get('switch_%s' % key)
if session_status == SESSION_DISABLED:
return False
elif session_status == SESSION_ENABLED:
return True
except ValueError:
pass

if switch.status == GLOBAL:
return True
elif switch.status == DISABLED:
Expand All @@ -281,11 +309,6 @@ def is_active(self, key, *instances):
return True

if instances:
# HACK: support request.user by swapping in User instance
instances = list(instances)
for v in instances:
if isinstance(v, HttpRequest) and hasattr(v, 'user'):
instances.append(v.user)

for instance in instances:
# check each switch to see if it can execute
Expand All @@ -295,7 +318,7 @@ def is_active(self, key, *instances):
return True

return False

def register(self, condition_set):
"""
Registers a condition set with the manager.
Expand Down
46 changes: 42 additions & 4 deletions gargoyle/nexus_modules.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,14 @@
from django.utils import simplejson

from gargoyle import gargoyle, autodiscover
from gargoyle.models import Switch, DISABLED
from gargoyle.models import (
Switch,
DISABLED,
SESSION_BYPASS,
SESSION_ENABLED,
SESSION_DISABLED,
)

from gargoyle.conditions import ValidationError

GARGOYLE_ROOT = os.path.dirname(__file__)
Expand Down Expand Up @@ -70,6 +77,7 @@ def get_urls(self):
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'^status/session/$', self.as_view(self.session_status), name='session-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'),
Expand All @@ -89,11 +97,41 @@ def render_on_dashboard(self, request):

def index(self, request):
switches = list(Switch.objects.all().order_by("date_created"))
switches = [s.to_dict(gargoyle) for s in switches]
for s in switches:
session_status = request.COOKIES.get('switch_%s' % (s['key']))
if session_status not in (SESSION_ENABLED, SESSION_DISABLED):
session_status = SESSION_BYPASS

s['session_status'] = session_status

return self.render_to_response("gargoyle/index.html", {
"switches": [s.to_dict(gargoyle) for s in switches],
context = {
"switches": switches,
"all_conditions": list(gargoyle.get_all_conditions()),
}, request)
"SESSION_ENABLED": SESSION_ENABLED,
"SESSION_DISABLED": SESSION_DISABLED,
"SESSION_BYPASS": SESSION_BYPASS,
}

return self.render_to_response("gargoyle/index.html", context, request)

def session_status(self, request):
switch = Switch.objects.get(key=request.POST.get("key"))

session_status = request.POST.get("session_status")
if session_status not in (
SESSION_BYPASS,
SESSION_DISABLED,
SESSION_ENABLED,
):
raise GargoyleException("Not a valid Session Status")

return {
'cookie_key': 'switch_%s' % (request.POST.get("key")),
'cookie_value': session_status,
'session_status': session_status,
}
session_status = json(session_status)

def add(self, request):
key = request.POST.get("key")
Expand Down
45 changes: 44 additions & 1 deletion gargoyle/templates/gargoyle/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,18 @@
updateSwitch: "{% url gargoyle:update %}",
deleteSwitch: "{% url gargoyle:delete %}",
updateStatus: "{% url gargoyle:status %}",
updateSessionStatus: "{% url gargoyle:session-status %}",
addCondition: "{% url gargoyle:add-condition %}",
delCondition: "{% url gargoyle:remove-condition %}",

deleteImage: "{% url nexus:media 'gargoyle' 'img/delete.png' %}",
facebox: {
loadingImage: "{% url nexus:media 'gargoyle' 'img/facebox/loading.gif' %}",
closeImage: "{% url nexus:media 'gargoyle' 'img/facebox/closelabel.png' %}"
}
},
SESSION_BYPASS: "{{SESSION_BYPASS}}",
SESSION_ENABLED: "{{SESSION_ENABLED}}",
SESSION_DISABLED: "{{SESSION_DISABLED}}"
};
</script>

Expand Down Expand Up @@ -69,6 +73,28 @@ <h4>{{ switch.label }} <small class="command">({{ switch.key }})</small></h4>
<div class="conditionsForm">
</div>
</td>
<td class="sessionStatus">
<button class="xtrasmall button {% if switch.session_status == SESSION_ENABLED %}toggled{% endif %}" data-session-status="{{ SESSION_ENABLED }}">
Session Enable
</button>

<button class="xtrasmall button {% if switch.session_status == SESSION_DISABLED %}toggled{% endif %}" data-session-status="{{ SESSION_DISABLED }}">
Session Disable
</button>

<button class="xtrasmall button {% if switch.session_status == SESSION_BYPASS %}toggled{% endif %}" data-session-status="{{ SESSION_BYPASS }}">
Session Bypass
</button>
<p>
{% if switch.session_status == SESSION_ENABLED %}
(Manually enabled for my session)
{% else %}{% if switch.session_status == SESSION_DISABLED %}
(Manually disabled for my session)
{% else %}
(No manual override)
{% endif %}{% endif %}
</p>
</td>

<td class="status">
<button class="xtrasmall button {% if switch.status == 3 %}toggled{% endif %}" data-status="3">
Expand Down Expand Up @@ -175,6 +201,23 @@ <h4>${label} <small class="command">(${key})</small></h4>
<p class="addCondition"><a href="#">Add a condition</a></p>
<div class="conditionsForm"></div>
</td>

<td class="sessionStatus">
<button class="xtrasmall button" data-session-status="${GARGOYLE.SESSION_ENABLED}">
Session Enable
</button>

<button class="xtrasmall button" data-session-status="${GARGOYLE.SESSION_DISABLED}">
Session Disable
</button>

<button class="xtrasmall button toggled" data-session-status="${GARGOYLE.SESSION_BYPASS}">
Session Bypass
</button>
<p>
(No manual override)
</p>
</td>

<td class="status">
<button class="xtrasmall button {{if status == 3}}toggled{{/if}}" data-status="3">
Expand Down
Loading