JSON API refactoring
* Introduced json decorator * Changed signatures of API URIs * Extract common js code into separate static file * Move all renderers (chart, table, timeline) * Move common functions Resolves bug 1221185 Change-Id: I7146fda70b4892d3d08c35682ff452cc4b891f58
This commit is contained in:
211
dashboard/static/js/stackalytics-ui.js
Normal file
211
dashboard/static/js/stackalytics-ui.js
Normal file
@@ -0,0 +1,211 @@
|
|||||||
|
/*
|
||||||
|
Copyright (c) 2013 Mirantis Inc.
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||||
|
implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
function createTimeline(data) {
|
||||||
|
var plot = $.jqplot('timeline', data, {
|
||||||
|
gridPadding: {
|
||||||
|
right: 35
|
||||||
|
},
|
||||||
|
cursor: {
|
||||||
|
show: false
|
||||||
|
},
|
||||||
|
highlighter: {
|
||||||
|
show: true,
|
||||||
|
sizeAdjust: 6
|
||||||
|
},
|
||||||
|
axes: {
|
||||||
|
xaxis: {
|
||||||
|
tickRenderer: $.jqplot.CanvasAxisTickRenderer,
|
||||||
|
tickOptions: {
|
||||||
|
fontSize: '8pt',
|
||||||
|
angle: -90,
|
||||||
|
formatString: '%b \'%y'
|
||||||
|
},
|
||||||
|
renderer: $.jqplot.DateAxisRenderer,
|
||||||
|
tickInterval: '1 month'
|
||||||
|
},
|
||||||
|
yaxis: {
|
||||||
|
min: 0,
|
||||||
|
label: ''
|
||||||
|
},
|
||||||
|
y2axis: {
|
||||||
|
min: 0,
|
||||||
|
label: ''
|
||||||
|
}
|
||||||
|
},
|
||||||
|
series: [
|
||||||
|
{
|
||||||
|
shadow: false,
|
||||||
|
fill: true,
|
||||||
|
fillColor: '#4bb2c5',
|
||||||
|
fillAlpha: 0.3
|
||||||
|
},
|
||||||
|
{
|
||||||
|
shadow: false,
|
||||||
|
fill: true,
|
||||||
|
color: '#4bb2c5',
|
||||||
|
fillColor: '#4bb2c5'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
shadow: false,
|
||||||
|
lineWidth: 1.5,
|
||||||
|
showMarker: true,
|
||||||
|
markerOptions: { size: 5 },
|
||||||
|
yaxis: 'y2axis'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function renderTimeline(options) {
|
||||||
|
$(document).ready(function () {
|
||||||
|
$.ajax({
|
||||||
|
url: make_uri("/api/1.0/stats/timeline", options),
|
||||||
|
dataType: "json",
|
||||||
|
success: function (data) {
|
||||||
|
createTimeline(data["timeline"]);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function renderTableAndChart(url, container_id, table_id, chart_id, link_param, options) {
|
||||||
|
|
||||||
|
$(document).ready(function () {
|
||||||
|
|
||||||
|
$.ajax({
|
||||||
|
url: make_uri(url, options),
|
||||||
|
dataType: "json",
|
||||||
|
success: function (data) {
|
||||||
|
|
||||||
|
var tableData = [];
|
||||||
|
var chartData = [];
|
||||||
|
|
||||||
|
var limit = 10;
|
||||||
|
var aggregate = 0;
|
||||||
|
var index = 1;
|
||||||
|
var i;
|
||||||
|
var hasComment = false;
|
||||||
|
|
||||||
|
data = data["stats"];
|
||||||
|
|
||||||
|
if (data.length == 0) {
|
||||||
|
$("#" + container_id).hide();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < data.length; i++) {
|
||||||
|
if (i < limit - 1) {
|
||||||
|
chartData.push([data[i].name, data[i].metric]);
|
||||||
|
} else {
|
||||||
|
aggregate += data[i].metric;
|
||||||
|
}
|
||||||
|
|
||||||
|
var index_label = index;
|
||||||
|
if (data[i].name == "*independent") {
|
||||||
|
index_label = "";
|
||||||
|
} else {
|
||||||
|
index++;
|
||||||
|
}
|
||||||
|
var link;
|
||||||
|
if (data[i].id) {
|
||||||
|
link = make_link(data[i].id, data[i].name, link_param);
|
||||||
|
} else {
|
||||||
|
link = data[i].name
|
||||||
|
}
|
||||||
|
var rec = {"index": index_label, "link": link, "metric": data[i].metric};
|
||||||
|
if (data[i].comment) {
|
||||||
|
rec["comment"] = data[i].comment;
|
||||||
|
hasComment = true;
|
||||||
|
}
|
||||||
|
tableData.push(rec);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (i == limit) {
|
||||||
|
chartData.push([data[i - 1].name, data[i - 1].metric]);
|
||||||
|
} else if (i > limit) {
|
||||||
|
chartData.push(["others", aggregate]);
|
||||||
|
}
|
||||||
|
|
||||||
|
var tableColumns = [
|
||||||
|
{ "mData": "index" },
|
||||||
|
{ "mData": "link" },
|
||||||
|
{ "mData": "metric" }
|
||||||
|
];
|
||||||
|
if (hasComment) {
|
||||||
|
tableColumns.push({ "mData": "comment"})
|
||||||
|
}
|
||||||
|
|
||||||
|
if (table_id) {
|
||||||
|
$("#" + table_id).dataTable({
|
||||||
|
"aLengthMenu": [
|
||||||
|
[25, 50, -1],
|
||||||
|
[25, 50, "All"]
|
||||||
|
],
|
||||||
|
"aaSorting": [
|
||||||
|
[ 2, "desc" ]
|
||||||
|
],
|
||||||
|
"sPaginationType": "full_numbers",
|
||||||
|
"iDisplayLength": 25,
|
||||||
|
"aaData": tableData,
|
||||||
|
"aoColumns": tableColumns
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (chart_id) {
|
||||||
|
var plot = $.jqplot(chart_id, [chartData], {
|
||||||
|
seriesDefaults: {
|
||||||
|
renderer: jQuery.jqplot.PieRenderer,
|
||||||
|
rendererOptions: {
|
||||||
|
showDataLabels: true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
legend: { show: true, location: 'e' }
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function getUrlVars() {
|
||||||
|
var vars = {};
|
||||||
|
var parts = window.location.href.replace(/[?&]+([^=&]+)=([^&]*)/gi, function (m, key, value) {
|
||||||
|
vars[key] = value;
|
||||||
|
});
|
||||||
|
return vars;
|
||||||
|
}
|
||||||
|
|
||||||
|
function make_link(id, title, param_name) {
|
||||||
|
var options = {};
|
||||||
|
options[param_name] = encodeURIComponent(id).toLowerCase();
|
||||||
|
var link = make_uri("/", options);
|
||||||
|
return "<a href=\"" + link + "\">" + title + "</a>"
|
||||||
|
}
|
||||||
|
|
||||||
|
function make_uri(uri, options) {
|
||||||
|
var ops = {};
|
||||||
|
$.extend(ops, getUrlVars());
|
||||||
|
if (options != null) {
|
||||||
|
$.extend(ops, options);
|
||||||
|
}
|
||||||
|
var str = $.map(ops,function (val, index) {
|
||||||
|
return index + "=" + val;
|
||||||
|
}).join("&");
|
||||||
|
|
||||||
|
return (str == "") ? uri : uri + "?" + str;
|
||||||
|
}
|
@@ -37,179 +37,10 @@
|
|||||||
<script type="text/javascript" src="{{ url_for('static', filename='js/jqplot.highlighter.min.js') }}"></script>
|
<script type="text/javascript" src="{{ url_for('static', filename='js/jqplot.highlighter.min.js') }}"></script>
|
||||||
<script type="text/javascript" src="{{ url_for('static', filename='js/select2.min.js') }}"></script>
|
<script type="text/javascript" src="{{ url_for('static', filename='js/select2.min.js') }}"></script>
|
||||||
<script type="text/javascript" src="{{ url_for('static', filename='js/jquery.tmpl.js') }}"></script>
|
<script type="text/javascript" src="{{ url_for('static', filename='js/jquery.tmpl.js') }}"></script>
|
||||||
|
<script type="text/javascript" src="{{ url_for('static', filename='js/stackalytics-ui.js') }}"></script>
|
||||||
|
|
||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
|
|
||||||
function showTimeline(data) {
|
|
||||||
var plot = $.jqplot('timeline', data, {
|
|
||||||
gridPadding: {
|
|
||||||
right: 35
|
|
||||||
},
|
|
||||||
cursor: {
|
|
||||||
show: false
|
|
||||||
},
|
|
||||||
highlighter: {
|
|
||||||
show: true,
|
|
||||||
sizeAdjust: 6
|
|
||||||
},
|
|
||||||
axes: {
|
|
||||||
xaxis: {
|
|
||||||
tickRenderer: $.jqplot.CanvasAxisTickRenderer,
|
|
||||||
tickOptions: {
|
|
||||||
fontSize: '8pt',
|
|
||||||
angle: -90,
|
|
||||||
formatString: '%b \'%y'
|
|
||||||
},
|
|
||||||
renderer: $.jqplot.DateAxisRenderer,
|
|
||||||
tickInterval: '1 month'
|
|
||||||
},
|
|
||||||
yaxis: {
|
|
||||||
min: 0,
|
|
||||||
label: ''
|
|
||||||
},
|
|
||||||
y2axis: {
|
|
||||||
min: 0,
|
|
||||||
label: ''
|
|
||||||
}
|
|
||||||
},
|
|
||||||
series: [
|
|
||||||
{
|
|
||||||
shadow: false,
|
|
||||||
fill: true,
|
|
||||||
fillColor: '#4bb2c5',
|
|
||||||
fillAlpha: 0.3
|
|
||||||
},
|
|
||||||
{
|
|
||||||
shadow: false,
|
|
||||||
fill: true,
|
|
||||||
color: '#4bb2c5',
|
|
||||||
fillColor: '#4bb2c5'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
shadow: false,
|
|
||||||
lineWidth: 1.5,
|
|
||||||
showMarker: true,
|
|
||||||
markerOptions: { size: 5 },
|
|
||||||
yaxis: 'y2axis'
|
|
||||||
}
|
|
||||||
]
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function timelineRenderer(options) {
|
|
||||||
$(document).ready(function () {
|
|
||||||
$.ajax({
|
|
||||||
url: make_uri("/data/timeline", options),
|
|
||||||
dataType: "json",
|
|
||||||
success: function (data) {
|
|
||||||
showTimeline(data);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function chartAndTableRenderer(url, container_id, table_id, chart_id, link_param, options) {
|
|
||||||
|
|
||||||
$(document).ready(function () {
|
|
||||||
|
|
||||||
$.ajax({
|
|
||||||
url: make_uri(url, options),
|
|
||||||
dataType: "json",
|
|
||||||
success: function (data) {
|
|
||||||
|
|
||||||
var tableData = [];
|
|
||||||
var chartData = [];
|
|
||||||
|
|
||||||
var limit = 10;
|
|
||||||
var aggregate = 0;
|
|
||||||
var index = 1;
|
|
||||||
var i;
|
|
||||||
var hasComment = false;
|
|
||||||
|
|
||||||
if (data.length == 0) {
|
|
||||||
$("#" + container_id).hide();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (i = 0; i < data.length; i++) {
|
|
||||||
if (i < limit - 1) {
|
|
||||||
chartData.push([data[i].name, data[i].metric]);
|
|
||||||
} else {
|
|
||||||
aggregate += data[i].metric;
|
|
||||||
}
|
|
||||||
|
|
||||||
var index_label = index;
|
|
||||||
if (data[i].name == "*independent") {
|
|
||||||
index_label = "";
|
|
||||||
} else {
|
|
||||||
index++;
|
|
||||||
}
|
|
||||||
var link;
|
|
||||||
if (data[i].id) {
|
|
||||||
link = make_link(data[i].id, data[i].name, link_param);
|
|
||||||
} else {
|
|
||||||
link = data[i].name
|
|
||||||
}
|
|
||||||
var rec = {"index": index_label, "link": link, "metric": data[i].metric};
|
|
||||||
if (data[i].comment) {
|
|
||||||
rec["comment"] = data[i].comment;
|
|
||||||
hasComment = true;
|
|
||||||
}
|
|
||||||
tableData.push(rec);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (i == limit) {
|
|
||||||
chartData.push([data[i-1].name, data[i-1].metric]);
|
|
||||||
} else if (i > limit) {
|
|
||||||
chartData.push(["others", aggregate]);
|
|
||||||
}
|
|
||||||
|
|
||||||
var tableColumns = [
|
|
||||||
{ "mData": "index" },
|
|
||||||
{ "mData": "link" },
|
|
||||||
{ "mData": "metric" }
|
|
||||||
];
|
|
||||||
if (hasComment) {
|
|
||||||
tableColumns.push({ "mData": "comment"})
|
|
||||||
}
|
|
||||||
|
|
||||||
$("#" + table_id).dataTable({
|
|
||||||
"aLengthMenu": [
|
|
||||||
[25, 50, -1],
|
|
||||||
[25, 50, "All"]
|
|
||||||
],
|
|
||||||
"aaSorting": [
|
|
||||||
[ 2, "desc" ]
|
|
||||||
],
|
|
||||||
"sPaginationType": "full_numbers",
|
|
||||||
"iDisplayLength": 25,
|
|
||||||
"aaData": tableData,
|
|
||||||
"aoColumns": tableColumns
|
|
||||||
});
|
|
||||||
|
|
||||||
var plot = $.jqplot(chart_id, [chartData], {
|
|
||||||
seriesDefaults: {
|
|
||||||
renderer: jQuery.jqplot.PieRenderer,
|
|
||||||
rendererOptions: {
|
|
||||||
showDataLabels: true
|
|
||||||
}
|
|
||||||
},
|
|
||||||
legend: { show: true, location: 'e' }
|
|
||||||
});
|
|
||||||
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function getUrlVars() {
|
|
||||||
var vars = {};
|
|
||||||
var parts = window.location.href.replace(/[?&]+([^=&]+)=([^&]*)/gi, function (m, key, value) {
|
|
||||||
vars[key] = value;
|
|
||||||
});
|
|
||||||
return vars;
|
|
||||||
}
|
|
||||||
|
|
||||||
$(document).ready(function () {
|
$(document).ready(function () {
|
||||||
$('#metric').val('{{ metric }}');
|
$('#metric').val('{{ metric }}');
|
||||||
$('#release').val('{{ release }}');
|
$('#release').val('{{ release }}');
|
||||||
@@ -227,7 +58,7 @@
|
|||||||
$("#company").select2({
|
$("#company").select2({
|
||||||
allowClear: true,
|
allowClear: true,
|
||||||
ajax: {
|
ajax: {
|
||||||
url: make_uri("/data/companies.json"),
|
url: make_uri("/api/1.0/companies"),
|
||||||
dataType: 'json',
|
dataType: 'json',
|
||||||
data: function (term, page) {
|
data: function (term, page) {
|
||||||
return {
|
return {
|
||||||
@@ -241,7 +72,7 @@
|
|||||||
initSelection: function (element, callback) {
|
initSelection: function (element, callback) {
|
||||||
var id = $(element).val();
|
var id = $(element).val();
|
||||||
if (id !== "") {
|
if (id !== "") {
|
||||||
$.ajax(make_uri("/data/companies/" + id + ".json"), {
|
$.ajax(make_uri("/api/1.0/companies/" + id), {
|
||||||
dataType: "json"
|
dataType: "json"
|
||||||
}).done(function (data) {
|
}).done(function (data) {
|
||||||
callback(data["company"]);
|
callback(data["company"]);
|
||||||
@@ -256,7 +87,7 @@
|
|||||||
$("#module").select2({
|
$("#module").select2({
|
||||||
allowClear: true,
|
allowClear: true,
|
||||||
ajax: {
|
ajax: {
|
||||||
url: make_uri("/data/modules.json"),
|
url: make_uri("/api/1.0/modules"),
|
||||||
dataType: 'json',
|
dataType: 'json',
|
||||||
data: function (term, page) {
|
data: function (term, page) {
|
||||||
return {
|
return {
|
||||||
@@ -270,7 +101,7 @@
|
|||||||
initSelection: function (element, callback) {
|
initSelection: function (element, callback) {
|
||||||
var id = $(element).val();
|
var id = $(element).val();
|
||||||
if (id !== "") {
|
if (id !== "") {
|
||||||
$.ajax(make_uri("/data/modules/" + id + ".json"), {
|
$.ajax(make_uri("/api/1.0/modules/" + id), {
|
||||||
dataType: "json"
|
dataType: "json"
|
||||||
}).done(function (data) {
|
}).done(function (data) {
|
||||||
callback(data["module"]);
|
callback(data["module"]);
|
||||||
@@ -291,7 +122,7 @@
|
|||||||
$("#user").select2({
|
$("#user").select2({
|
||||||
allowClear: true,
|
allowClear: true,
|
||||||
ajax: {
|
ajax: {
|
||||||
url: make_uri("/data/users.json"),
|
url: make_uri("/api/1.0/users"),
|
||||||
dataType: 'json',
|
dataType: 'json',
|
||||||
data: function (term, page) {
|
data: function (term, page) {
|
||||||
return {
|
return {
|
||||||
@@ -305,7 +136,7 @@
|
|||||||
initSelection: function (element, callback) {
|
initSelection: function (element, callback) {
|
||||||
var id = $(element).val();
|
var id = $(element).val();
|
||||||
if (id !== "") {
|
if (id !== "") {
|
||||||
$.ajax(make_uri("/data/users/" + id + ".json"), {
|
$.ajax(make_uri("/api/1.0/users/" + id), {
|
||||||
dataType: "json"
|
dataType: "json"
|
||||||
}).done(function (data) {
|
}).done(function (data) {
|
||||||
callback(data["user"]);
|
callback(data["user"]);
|
||||||
@@ -318,26 +149,6 @@
|
|||||||
.on("change", function(e) { reload(); });
|
.on("change", function(e) { reload(); });
|
||||||
});
|
});
|
||||||
|
|
||||||
function make_link(id, title, param_name) {
|
|
||||||
var options = {};
|
|
||||||
options[param_name] = encodeURIComponent(id).toLowerCase();
|
|
||||||
var link = make_uri("/", options);
|
|
||||||
return "<a href=\"" + link + "\">" + title + "</a>"
|
|
||||||
}
|
|
||||||
|
|
||||||
function make_uri(uri, options) {
|
|
||||||
var ops = {};
|
|
||||||
$.extend(ops, getUrlVars());
|
|
||||||
if (options != null) {
|
|
||||||
$.extend(ops, options);
|
|
||||||
}
|
|
||||||
var str = $.map(ops,function (val, index) {
|
|
||||||
return index + "=" + val;
|
|
||||||
}).join("&");
|
|
||||||
|
|
||||||
return (str == "")? uri: uri + "?" + str;
|
|
||||||
}
|
|
||||||
|
|
||||||
function make_std_options() {
|
function make_std_options() {
|
||||||
var options = {};
|
var options = {};
|
||||||
options['release'] = getRelease();
|
options['release'] = getRelease();
|
||||||
|
@@ -14,16 +14,16 @@
|
|||||||
{% block scripts %}
|
{% block scripts %}
|
||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
|
|
||||||
timelineRenderer();
|
renderTimeline();
|
||||||
|
|
||||||
{% if show_company_breakdown %}
|
{% if show_company_breakdown %}
|
||||||
chartAndTableRenderer("/data/companies", "company_container", "company_table", "company_chart", "company");
|
renderTableAndChart("/api/1.0/stats/companies", "company_container", "company_table", "company_chart", "company");
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% if show_engineer_breakdown %}
|
{% if show_engineer_breakdown %}
|
||||||
chartAndTableRenderer("/data/engineers", "engineer_container", "engineer_table", "engineer_chart", "user_id", {company: "{{ company|encode }}" });
|
renderTableAndChart("/api/1.0/stats/engineers", "engineer_container", "engineer_table", "engineer_chart", "user_id", {company: "{{ company|encode }}" });
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% if show_module_breakdown %}
|
{% if show_module_breakdown %}
|
||||||
chartAndTableRenderer("/data/modules", "module_container", "module_table", "module_chart", "module");
|
renderTableAndChart("/api/1.0/stats/modules", "module_container", "module_table", "module_chart", "module");
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
{% if show_activity %}
|
{% if show_activity %}
|
||||||
@@ -33,7 +33,7 @@
|
|||||||
|
|
||||||
function load_activity() {
|
function load_activity() {
|
||||||
$.ajax({
|
$.ajax({
|
||||||
url: make_uri("/data/activity.json", {page_size: page_size, start_record: start_record}),
|
url: make_uri("/api/1.0/activity", {page_size: page_size, start_record: start_record}),
|
||||||
dataType: "json",
|
dataType: "json",
|
||||||
success: function (data) {
|
success: function (data) {
|
||||||
if (data["activity"].length < page_size) {
|
if (data["activity"].length < page_size) {
|
||||||
@@ -65,7 +65,7 @@
|
|||||||
{% if show_user_profile %}
|
{% if show_user_profile %}
|
||||||
$(document).ready(function () {
|
$(document).ready(function () {
|
||||||
$.ajax({
|
$.ajax({
|
||||||
url: make_uri("/data/users/{{ user_id }}.json"),
|
url: make_uri("/api/1.0/users/{{ user_id }}"),
|
||||||
dataType: "json",
|
dataType: "json",
|
||||||
success: function (data) {
|
success: function (data) {
|
||||||
$("#user_profile_template").tmpl(data["user"]).appendTo("#user_profile_container");
|
$("#user_profile_template").tmpl(data["user"]).appendTo("#user_profile_container");
|
||||||
@@ -77,7 +77,7 @@
|
|||||||
{% if show_contribution %}
|
{% if show_contribution %}
|
||||||
$(document).ready(function () {
|
$(document).ready(function () {
|
||||||
$.ajax({
|
$.ajax({
|
||||||
url: make_uri("/data/contribution.json"),
|
url: make_uri("/api/1.0/contribution"),
|
||||||
dataType: "json",
|
dataType: "json",
|
||||||
success: function (data) {
|
success: function (data) {
|
||||||
$("#contribution_template").tmpl(data["contribution"]).appendTo("#contribution_container");
|
$("#contribution_template").tmpl(data["contribution"]).appendTo("#contribution_container");
|
||||||
|
122
dashboard/web.py
122
dashboard/web.py
@@ -511,6 +511,26 @@ def templated(template=None, return_code=200):
|
|||||||
return decorator
|
return decorator
|
||||||
|
|
||||||
|
|
||||||
|
def jsonify(root='data'):
|
||||||
|
def decorator(func):
|
||||||
|
@functools.wraps(func)
|
||||||
|
def jsonify_decorated_function(*args, **kwargs):
|
||||||
|
callback = flask.app.request.args.get('callback', False)
|
||||||
|
data = json.dumps({root: func(*args, **kwargs)})
|
||||||
|
|
||||||
|
if callback:
|
||||||
|
data = str(callback) + '(' + data + ')'
|
||||||
|
content_type = 'application/javascript'
|
||||||
|
else:
|
||||||
|
content_type = 'application/json'
|
||||||
|
|
||||||
|
return app.response_class(data, mimetype=content_type)
|
||||||
|
|
||||||
|
return jsonify_decorated_function
|
||||||
|
|
||||||
|
return decorator
|
||||||
|
|
||||||
|
|
||||||
# Handlers ---------
|
# Handlers ---------
|
||||||
|
|
||||||
@app.route('/')
|
@app.route('/')
|
||||||
@@ -604,41 +624,41 @@ def _get_aggregated_stats(records, metric_filter, keys, param_id,
|
|||||||
return response
|
return response
|
||||||
|
|
||||||
|
|
||||||
@app.route('/data/companies')
|
@app.route('/api/1.0/stats/companies')
|
||||||
|
@jsonify('stats')
|
||||||
@exception_handler()
|
@exception_handler()
|
||||||
@record_filter()
|
@record_filter()
|
||||||
@aggregate_filter()
|
@aggregate_filter()
|
||||||
def get_companies(records, metric_filter, finalize_handler):
|
def get_companies(records, metric_filter, finalize_handler):
|
||||||
response = _get_aggregated_stats(records, metric_filter,
|
return _get_aggregated_stats(records, metric_filter,
|
||||||
get_memory_storage().get_companies(),
|
get_memory_storage().get_companies(),
|
||||||
'company_name')
|
'company_name')
|
||||||
return json.dumps(response)
|
|
||||||
|
|
||||||
|
|
||||||
@app.route('/data/modules')
|
@app.route('/api/1.0/stats/modules')
|
||||||
|
@jsonify('stats')
|
||||||
@exception_handler()
|
@exception_handler()
|
||||||
@record_filter()
|
@record_filter()
|
||||||
@aggregate_filter()
|
@aggregate_filter()
|
||||||
def get_modules(records, metric_filter, finalize_handler):
|
def get_modules(records, metric_filter, finalize_handler):
|
||||||
response = _get_aggregated_stats(records, metric_filter,
|
return _get_aggregated_stats(records, metric_filter,
|
||||||
get_memory_storage().get_modules(),
|
get_memory_storage().get_modules(),
|
||||||
'module')
|
'module')
|
||||||
return json.dumps(response)
|
|
||||||
|
|
||||||
|
|
||||||
@app.route('/data/engineers')
|
@app.route('/api/1.0/stats/engineers')
|
||||||
|
@jsonify('stats')
|
||||||
@exception_handler()
|
@exception_handler()
|
||||||
@record_filter()
|
@record_filter()
|
||||||
@aggregate_filter()
|
@aggregate_filter()
|
||||||
def get_engineers(records, metric_filter, finalize_handler):
|
def get_engineers(records, metric_filter, finalize_handler):
|
||||||
response = _get_aggregated_stats(records, metric_filter,
|
return _get_aggregated_stats(records, metric_filter,
|
||||||
get_memory_storage().get_user_ids(),
|
get_memory_storage().get_user_ids(),
|
||||||
'user_id', 'author_name',
|
'user_id', 'author_name',
|
||||||
finalize_handler=finalize_handler)
|
finalize_handler=finalize_handler)
|
||||||
return json.dumps(response)
|
|
||||||
|
|
||||||
|
|
||||||
def extend_record(record):
|
def _extend_record(record):
|
||||||
record['date_str'] = format_datetime(record['date'])
|
record['date_str'] = format_datetime(record['date'])
|
||||||
record['author_link'] = make_link(
|
record['author_link'] = make_link(
|
||||||
record['author_name'], '/',
|
record['author_name'], '/',
|
||||||
@@ -649,7 +669,8 @@ def extend_record(record):
|
|||||||
record['gravatar'] = gravatar(record['author_email'])
|
record['gravatar'] = gravatar(record['author_email'])
|
||||||
|
|
||||||
|
|
||||||
@app.route('/data/activity.json')
|
@app.route('/api/1.0/activity')
|
||||||
|
@jsonify('activity')
|
||||||
@exception_handler()
|
@exception_handler()
|
||||||
@record_filter()
|
@record_filter()
|
||||||
def get_activity_json(records):
|
def get_activity_json(records):
|
||||||
@@ -665,7 +686,7 @@ def get_activity_json(records):
|
|||||||
if 'correction_comment' not in commit:
|
if 'correction_comment' not in commit:
|
||||||
commit['correction_comment'] = ''
|
commit['correction_comment'] = ''
|
||||||
commit['message'] = make_commit_message(record)
|
commit['message'] = make_commit_message(record)
|
||||||
extend_record(commit)
|
_extend_record(commit)
|
||||||
result.append(commit)
|
result.append(commit)
|
||||||
elif record['record_type'] == 'mark':
|
elif record['record_type'] == 'mark':
|
||||||
review = record.copy()
|
review = record.copy()
|
||||||
@@ -678,45 +699,41 @@ def get_activity_json(records):
|
|||||||
parent['author_name'], '/',
|
parent['author_name'], '/',
|
||||||
{'user_id': parent['user_id'],
|
{'user_id': parent['user_id'],
|
||||||
'company': ''})
|
'company': ''})
|
||||||
extend_record(review)
|
_extend_record(review)
|
||||||
result.append(review)
|
result.append(review)
|
||||||
|
|
||||||
result.sort(key=lambda x: x['date'], reverse=True)
|
result.sort(key=lambda x: x['date'], reverse=True)
|
||||||
return json.dumps({'activity':
|
return result[start_record:start_record + page_size]
|
||||||
result[start_record:start_record + page_size]})
|
|
||||||
|
|
||||||
|
|
||||||
@app.route('/data/contribution.json')
|
@app.route('/api/1.0/contribution')
|
||||||
|
@jsonify('contribution')
|
||||||
@exception_handler()
|
@exception_handler()
|
||||||
@record_filter(ignore='metric')
|
@record_filter(ignore='metric')
|
||||||
def get_contribution_json(records):
|
def get_contribution_json(records):
|
||||||
return json.dumps({'contribution': contribution_details(records)})
|
return contribution_details(records)
|
||||||
|
|
||||||
|
|
||||||
def _get_collection(records, collection_name, name_key, query_param=None):
|
@app.route('/api/1.0/companies')
|
||||||
if not query_param:
|
@jsonify('companies')
|
||||||
query_param = name_key
|
@exception_handler()
|
||||||
query = flask.request.args.get(query_param) or ''
|
@record_filter(ignore='company')
|
||||||
|
def get_companies_json(records):
|
||||||
|
query = flask.request.args.get('company_name') or ''
|
||||||
options = set()
|
options = set()
|
||||||
for record in records:
|
for record in records:
|
||||||
name = record[name_key]
|
name = record['company_name']
|
||||||
if name in options:
|
if name in options:
|
||||||
continue
|
continue
|
||||||
if name.lower().find(query.lower()) >= 0:
|
if name.lower().find(query.lower()) >= 0:
|
||||||
options.add(name)
|
options.add(name)
|
||||||
result = [{'id': safe_encode(c.lower()), 'text': c}
|
result = [{'id': safe_encode(c.lower()), 'text': c}
|
||||||
for c in sorted(options)]
|
for c in sorted(options)]
|
||||||
return json.dumps({collection_name: result})
|
return result
|
||||||
|
|
||||||
|
|
||||||
@app.route('/data/companies.json')
|
@app.route('/api/1.0/modules')
|
||||||
@exception_handler()
|
@jsonify('modules')
|
||||||
@record_filter(ignore='company')
|
|
||||||
def get_companies_json(records):
|
|
||||||
return _get_collection(records, 'companies', 'company_name')
|
|
||||||
|
|
||||||
|
|
||||||
@app.route('/data/modules.json')
|
|
||||||
@exception_handler()
|
@exception_handler()
|
||||||
@record_filter(ignore='module')
|
@record_filter(ignore='module')
|
||||||
def get_modules_json(records):
|
def get_modules_json(records):
|
||||||
@@ -743,34 +760,34 @@ def get_modules_json(records):
|
|||||||
if module.find(query) >= 0:
|
if module.find(query) >= 0:
|
||||||
options.append(module_id_index[module])
|
options.append(module_id_index[module])
|
||||||
|
|
||||||
result = sorted(options, key=operator.itemgetter('text'))
|
return sorted(options, key=operator.itemgetter('text'))
|
||||||
return json.dumps({'modules': result})
|
|
||||||
|
|
||||||
|
|
||||||
@app.route('/data/companies/<company_name>.json')
|
@app.route('/api/1.0/companies/<company_name>')
|
||||||
|
@jsonify('company')
|
||||||
def get_company(company_name):
|
def get_company(company_name):
|
||||||
memory_storage = get_vault()['memory_storage']
|
memory_storage = get_vault()['memory_storage']
|
||||||
for company in memory_storage.get_companies():
|
for company in memory_storage.get_companies():
|
||||||
if company.lower() == company_name.lower():
|
if company.lower() == company_name.lower():
|
||||||
return json.dumps({
|
return {
|
||||||
'company': {
|
|
||||||
'id': company_name,
|
'id': company_name,
|
||||||
'text': memory_storage.get_original_company_name(
|
'text': memory_storage.get_original_company_name(company_name)
|
||||||
company_name)}
|
}
|
||||||
})
|
flask.abort(404)
|
||||||
return json.dumps({})
|
|
||||||
|
|
||||||
|
|
||||||
@app.route('/data/modules/<module>.json')
|
@app.route('/api/1.0/modules/<module>')
|
||||||
|
@jsonify('module')
|
||||||
def get_module(module):
|
def get_module(module):
|
||||||
module_id_index = get_vault()['module_id_index']
|
module_id_index = get_vault()['module_id_index']
|
||||||
module = module.lower()
|
module = module.lower()
|
||||||
if module in module_id_index:
|
if module in module_id_index:
|
||||||
return json.dumps({'module': module_id_index[module]})
|
return module_id_index[module]
|
||||||
return json.dumps({})
|
flask.abort(404)
|
||||||
|
|
||||||
|
|
||||||
@app.route('/data/users.json')
|
@app.route('/api/1.0/users')
|
||||||
|
@jsonify('users')
|
||||||
@exception_handler()
|
@exception_handler()
|
||||||
@record_filter(ignore='user_id')
|
@record_filter(ignore='user_id')
|
||||||
def get_users_json(records):
|
def get_users_json(records):
|
||||||
@@ -786,10 +803,11 @@ def get_users_json(records):
|
|||||||
user_ids.add(user_id)
|
user_ids.add(user_id)
|
||||||
result.append({'id': user_id, 'text': user_name})
|
result.append({'id': user_id, 'text': user_name})
|
||||||
result.sort(key=lambda x: x['text'])
|
result.sort(key=lambda x: x['text'])
|
||||||
return json.dumps({'users': result})
|
return result
|
||||||
|
|
||||||
|
|
||||||
@app.route('/data/users/<user_id>.json')
|
@app.route('/api/1.0/users/<user_id>')
|
||||||
|
@jsonify('user')
|
||||||
def get_user(user_id):
|
def get_user(user_id):
|
||||||
user = get_user_from_runtime_storage(user_id)
|
user = get_user_from_runtime_storage(user_id)
|
||||||
if not user:
|
if not user:
|
||||||
@@ -803,10 +821,11 @@ def get_user(user_id):
|
|||||||
else:
|
else:
|
||||||
user['company_link'] = ''
|
user['company_link'] = ''
|
||||||
user['gravatar'] = gravatar(user['emails'][0])
|
user['gravatar'] = gravatar(user['emails'][0])
|
||||||
return json.dumps({'user': user})
|
return user
|
||||||
|
|
||||||
|
|
||||||
@app.route('/data/timeline')
|
@app.route('/api/1.0/stats/timeline')
|
||||||
|
@jsonify('timeline')
|
||||||
@exception_handler()
|
@exception_handler()
|
||||||
@record_filter(ignore='release')
|
@record_filter(ignore='release')
|
||||||
def timeline(records, **kwargs):
|
def timeline(records, **kwargs):
|
||||||
@@ -871,10 +890,11 @@ def timeline(records, **kwargs):
|
|||||||
array_commits.append([week_str, week_stat_commits[week]])
|
array_commits.append([week_str, week_stat_commits[week]])
|
||||||
array_commits_hl.append([week_str, week_stat_commits_hl[week]])
|
array_commits_hl.append([week_str, week_stat_commits_hl[week]])
|
||||||
|
|
||||||
return json.dumps([array_commits, array_commits_hl, array_loc])
|
return [array_commits, array_commits_hl, array_loc]
|
||||||
|
|
||||||
|
|
||||||
@app.route('/data/report/commit')
|
@app.route('/api/1.0/report/commits')
|
||||||
|
@jsonify('commits')
|
||||||
@exception_handler()
|
@exception_handler()
|
||||||
@record_filter()
|
@record_filter()
|
||||||
def get_commit_report(records):
|
def get_commit_report(records):
|
||||||
@@ -885,7 +905,7 @@ def get_commit_report(records):
|
|||||||
nr = dict([(k, record[k]) for k in ['loc', 'subject', 'module',
|
nr = dict([(k, record[k]) for k in ['loc', 'subject', 'module',
|
||||||
'primary_key', 'change_id']])
|
'primary_key', 'change_id']])
|
||||||
response.append(nr)
|
response.append(nr)
|
||||||
return json.dumps(response, skipkeys=True, indent=2)
|
return response
|
||||||
|
|
||||||
|
|
||||||
# Jinja Filters ---------
|
# Jinja Filters ---------
|
||||||
|
Reference in New Issue
Block a user