Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make graphite's /render/?.... urls copy-pastable #158

Merged
merged 2 commits into from Aug 11, 2014
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions setup.py
Expand Up @@ -85,6 +85,7 @@
'graphite.graphlot',
'graphite.metrics',
'graphite.render',
'graphite.url_shortener',
'graphite.version',
'graphite.whitelist',
],
Expand Down
Binary file added webapp/content/img/browser.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
43 changes: 43 additions & 0 deletions webapp/content/js/composer_widgets.js
Expand Up @@ -45,6 +45,7 @@ function createComposerWindow(myComposer) {
createToolbarButton('Select Recent Data', 'arrow1.gif', toggleWindow(createRecentWindow) ),
createToolbarButton('Open in GraphPlot', 'line_chart.png', function() { window.open('/graphlot/?' + Composer.url.queryString,'_blank') }),
createToolbarButton('Create from URL', 'link.png', toggleWindow(createURLWindow) ),
createToolbarButton('Short URL', 'browser.png', showShortUrl),
'-',
timeDisplay
];
Expand Down Expand Up @@ -260,6 +261,48 @@ function asDateString(dateObj) {
return dateObj.format('H:i_Ymd');
}

/* Short url window */
function showShortUrl() {
showUrl = function(options, success, response) {
if(success) {
var win = new Ext.Window({
title: "Graph URL",
width: 600,
height: 125,
layout: 'border',
modal: true,
items: [
{
xtype: "label",
region: 'north',
style: "text-align: center;",
text: "Short Direct URL to this graph"
}, {
xtype: 'textfield',
region: 'center',
value: window.location.origin + response.responseText,
editable: false,
style: "text-align: center; font-size: large;",
listeners: {
focus: function (field) { field.selectText(); }
}
}
],
buttonAlign: 'center',
buttons: [
{text: "Close", handler: function () { win.close(); } }
]
});
win.show();
}
}
Ext.Ajax.request({
method: 'GET',
url: '/s/render/?' + Composer.url.queryString,
callback: showUrl,
});
}

/* "Recent Data" dialog */
function toggleWindow(createFunc) {
function toggler (button, e) {
Expand Down
46 changes: 46 additions & 0 deletions webapp/content/js/dashboard.js
Expand Up @@ -1865,6 +1865,52 @@ function graphClicked(graphView, graphIndex, element, evt) {
});
win.show();
}
}, {
xtype: 'button',
fieldLabel: "<span style='visibility: hidden'>",
text: "Short Direct URL",
width: 100,
handler: function () {
menu.destroy();
showUrl = function(options, success, response) {
if(success) {
var win = new Ext.Window({
title: "Graph URL",
width: 600,
height: 125,
layout: 'border',
modal: true,
items: [
{
xtype: "label",
region: 'north',
style: "text-align: center;",
text: "Short Direct URL to this graph"
}, {
xtype: 'textfield',
region: 'center',
value: window.location.origin + response.responseText,
editable: false,
style: "text-align: center; font-size: large;",
listeners: {
focus: function (field) { field.selectText(); }
}
}
],
buttonAlign: 'center',
buttons: [
{text: "Close", handler: function () { win.close(); } }
]
});
win.show();
}
}
Ext.Ajax.request({
method: 'GET',
url: '/s' + record.data.url,
callback: showUrl,
});
}
}]
});

Expand Down
1 change: 1 addition & 0 deletions webapp/graphite/app_settings.py
Expand Up @@ -77,6 +77,7 @@
'graphite.dashboard',
'graphite.whitelist',
'graphite.events',
'graphite.url_shortener',
'django.contrib.auth',
'django.contrib.sessions',
'django.contrib.admin',
Expand Down
Empty file.
58 changes: 58 additions & 0 deletions webapp/graphite/url_shortener/baseconv.py
@@ -0,0 +1,58 @@
"""
Convert numbers from base 10 integers to base X strings and back again.

Original: http://www.djangosnippets.org/snippets/1431/

Sample usage:

>>> base20 = BaseConverter('0123456789abcdefghij')
>>> base20.from_decimal(1234)
'31e'
>>> base20.to_decimal('31e')
1234
"""

class BaseConverter(object):
decimal_digits = "0123456789"

def __init__(self, digits):
self.digits = digits

def from_decimal(self, i):
return self.convert(i, self.decimal_digits, self.digits)

def to_decimal(self, s):
return int(self.convert(s, self.digits, self.decimal_digits))

def convert(number, fromdigits, todigits):
# Based on http://code.activestate.com/recipes/111286/
if str(number)[0] == '-':
number = str(number)[1:]
neg = 1
else:
neg = 0

# make an integer out of the number
x = 0
for digit in str(number):
x = x * len(fromdigits) + fromdigits.index(digit)

# create the result in base 'len(todigits)'
if x == 0:
res = todigits[0]
else:
res = ""
while x > 0:
digit = x % len(todigits)
res = todigits[digit] + res
x = int(x / len(todigits))
if neg:
res = '-' + res
return res
convert = staticmethod(convert)

bin = BaseConverter('01')
hexconv = BaseConverter('0123456789ABCDEF')
base62 = BaseConverter(
'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyz'
)
5 changes: 5 additions & 0 deletions webapp/graphite/url_shortener/models.py
@@ -0,0 +1,5 @@
from django.db import models

class Link(models.Model):
url = models.TextField()
date_submitted = models.DateTimeField(auto_now_add=True)
24 changes: 24 additions & 0 deletions webapp/graphite/url_shortener/views.py
@@ -0,0 +1,24 @@
from django.core.urlresolvers import reverse
from django.shortcuts import get_object_or_404
from django.http import HttpResponse, HttpResponsePermanentRedirect

from graphite.url_shortener.baseconv import base62
from graphite.url_shortener.models import Link
import re

def follow(request, link_id):
"""Follow existing links"""
key = base62.to_decimal(link_id)
link = get_object_or_404(Link, pk=key)
return HttpResponsePermanentRedirect('/' + link.url)

def shorten(request, path):
if request.META.get('QUERY_STRING', None):
path += '?' + request.META['QUERY_STRING']
# Remove _salt, _dc and _uniq to avoid creating many copies of the same URL
path = re.sub('&_(uniq|salt|dc)=[0-9.]+', "", path)

link, created = Link.objects.get_or_create(url=path)
link_id = base62.from_decimal(link.id)
url = reverse('graphite.url_shortener.views.follow', kwargs={'link_id': link_id})
return HttpResponse(url, content_type='text/plain')
2 changes: 2 additions & 0 deletions webapp/graphite/urls.py
Expand Up @@ -30,6 +30,8 @@
('^graphlot/', include('graphite.graphlot.urls')),
('^version/', include('graphite.version.urls')),
('^events/', include('graphite.events.urls')),
('^s/(?P<path>.*)', 'graphite.url_shortener.views.shorten'),
('^S/(?P<link_id>[a-zA-Z0-9]+)/?$', 'graphite.url_shortener.views.follow'),
('^$', 'graphite.browser.views.browser'),
)
urlpatterns += staticfiles_urlpatterns()
Expand Down