adding iotserver

application-manager-new
Rasika 10 years ago
parent 7388502ac2
commit 21e10c2bb2

@ -0,0 +1,111 @@
<%
/*
* Copyright (c) 2015, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
*
* WSO2 Inc. licenses this file to you 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.
*/
var uri = request.getRequestURI();
var uriMatcher = new URIMatcher(String(uri));
var log = new Log("api/device-api.jag");
var constants = require("/modules/constants.js");
var dcProps = require('/config/dc-props.js').config();
var deviceModule = require("/modules/device.js").deviceModule;
var carbon = require('carbon');
var carbonHttpServletTransport = carbon.server.address('http');
var carbonHttpsServletTransport = carbon.server.address('https');
var result;
if (uriMatcher.match("/{context}/api/device/sketch/download")) {
sketchType = request.getParameter("sketchType");
deviceType = request.getParameter("deviceType");
if (!sketchType) {
log.error("Sketch Type is empty");
}
var user = session.get(constants.USER_SESSION_KEY);
if (!user) {
response.sendRedirect(dcProps.appContext + "login?#login-required");
exit();
}
//URL: https://localhost:9443/{deviceType}/download?owner={username}
deviceManagerService = carbonHttpsServletTransport + "/" + deviceType + "/manager";
sketchDownloadEndPoint = deviceManagerService + "/device/" + sketchType + "/download";
response.sendRedirect(sketchDownloadEndPoint + "?owner=" + user.username);
exit();//stop execution
} else if (uriMatcher.match("/{context}/api/devices/all")) {
var user = session.get(constants.USER_SESSION_KEY);
if (!user) {
response.sendRedirect(dcProps.appContext + "login?#login-required");
exit();//stop execution
}
//URL: https://localhost:9443/devicecloud/manager/devices/username/{username}
deviceCloudService = carbonHttpsServletTransport + "/devicecloud/device_manager";
listAllDevicesEndPoint = deviceCloudService + "/devices/username/" + user.username;
var data = {};
//XMLHTTPRequest's GET
result = get(listAllDevicesEndPoint, data, "json");
} else if (uriMatcher.match("/{context}/api/devices/types")) {
result = deviceModule.listDeviceTypes();
} else if (uriMatcher.match("/{context}/api/device/{deviceType}/{deviceId}/remove")) {
var user = session.get(constants.USER_SESSION_KEY);
if (!user) {
response.sendRedirect(dcProps.appContext + "login?#login-required");
exit();//stop execution
}
var elements = uriMatcher.elements();
var deviceId=elements.deviceId;
var deviceType = elements.deviceType;
result = deviceModule.removeDevice(deviceType, deviceId);
} else if (uriMatcher.match("/{context}/api/device/{deviceType}/{deviceId}/update")) {
var user = session.get(constants.USER_SESSION_KEY);
if (!user) {
response.sendRedirect(dcProps.appContext + "login?#login-required");
exit();//stop execution
}
var elements = uriMatcher.elements();
var deviceId=elements.deviceId;
var deviceType = elements.deviceType;
var cont = request.getContent();
if(!cont.device){
// http status code 400 refers to - Bad request.
result = 400;
}else {
result = deviceModule.updateDevice(deviceType, deviceId, cont.device);
}
}
// returning the result.
if (result) {
print(result);
}
%>

@ -0,0 +1,105 @@
<%
/*
* Copyright (c) 2015, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
*
* WSO2 Inc. licenses this file to you 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.
*/
var uri = request.getRequestURI();
var uriMatcher = new URIMatcher(String(uri));
var log = new Log("api/stats-api.jag");
var constants = require("/modules/constants.js");
var dcProps = require('/config/dc-props.js').config();
var utility = require("/modules/utility.js").utility;
var result;
var statsClient = new Packages.org.wso2.carbon.device.mgt.iot.common.devicecloud.usage.statistics.IoTUsageStatisticsClient;
if (uriMatcher.match("/{context}/api/stats")) {
deviceId = request.getParameter("deviceId");
deviceType = request.getParameter("deviceType");
from = request.getParameter("from");
to = request.getParameter("to");
user = session.get(constants.USER_SESSION_KEY);
if (!user) {
response.sendRedirect(dcProps.appContext + "login?#login-required");
exit();
}
log.info("deviceId : " + deviceId + " from : " + from + " to : " + to);
if(deviceType=="firealarm"){
result = getFireAlarmData(user.username, deviceId, from, to);
}else if(deviceType=="sensebot"){
result = getSensebotData(user.username, deviceId, from, to);
}
}
// returning the result.
if (result) {
print(result);
}
function getSensebotData(user, deviceId, from, to){
result = new Object();
result['sonarData'] = getSensorData("SONAR_SENSOR_SUMMARY","sonar",user, deviceId, from, to);
result['motionData'] = getSensorData("PIR_MOTION_SENSOR_SUMMARY","motion",user, deviceId, from, to);
result['lightData'] = getSensorData("LDR_LIGHT_SENSOR_SUMMARY","light",user, deviceId, from, to);
result['temperatureData'] = getSensorData("DEVICE_TEMPERATURE_SUMMARY","TEMPERATURE",user, deviceId, from, to);
return result;
}
function getFireAlarmData(user, deviceId, from, to){
result = new Object();
//result['sonarData'] = getSensorData("SONAR_SENSOR_SUMMARY","sonar",user, deviceId, from, to);
//result['motionData'] = getSensorData("PIR_MOTION_SENSOR_SUMMARY","motion",user, deviceId, from, to);
//result['lightData'] = getSensorData("LDR_LIGHT_SENSOR_SUMMARY","light",user, deviceId, from, to);
result['temperatureData'] = getSensorData("DEVICE_TEMPERATURE_SUMMARY","TEMPERATURE",user, deviceId, from, to);
result['fanData'] = getSensorData("DEVICE_FAN_USAGE_SUMMARY","status",user, deviceId, from, to);
result['bulbData'] = getSensorData("DEVICE_BULB_USAGE_SUMMARY","status",user, deviceId, from, to);
return result;
}
function getSensorData(table, column, user, deviceId, from, to) {
var fetchedData = null;
try {
fetchedData = statsClient.getDeviceStats(table, column, user, deviceId, from, to);
}catch(error){
log.info(error);
}
var temperatureData = [];
if(fetchedData==null) return [];
for (var i = 0; i < fetchedData.size(); i++) {
temperatureData.push({
time: fetchedData.get(i).getTime(),
value: fetchedData.get(i).getValue()
});
}
return temperatureData;
}
%>

@ -0,0 +1,135 @@
<%
/*
* Copyright (c) 2015, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
*
* WSO2 Inc. licenses this file to you 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.
*/
var uri = request.getRequestURI();
var uriMatcher = new URIMatcher(String(uri));
var log = new Log("api/user-api.jag");
var constants = require("/modules/constants.js");
var dcProps = require('/config/dc-props.js').config();
var userModule = require("/modules/user.js").userModule;
var utility = require("/modules/utility.js").utility;
var result;
if (uriMatcher.match("/{context}/api/user/login/")) {
var username = request.getParameter("username");
var password = request.getParameter("password");
try {
userModule.login(username, password, function (user) {
utility.insertAppPermissions(userModule, "login");
if (log.isDebugEnabled()) {
log.debug("User Logged In : " + user);
}
response.sendRedirect(constants.WEB_APP_CONTEXT);
}, function () {
response.sendRedirect(dcProps.appContext + "login?#auth-failed");
});
} catch (e) {
log.error("Exception occurred while a user tried to login to DC", e);
response.sendRedirect(dcProps.appContext + "login?#error");
}
} else if (uriMatcher.match("/{context}/api/user/logout/")) {
userModule.logout(function () {
response.sendRedirect(dcProps.appContext + "login");
});
} else if (uriMatcher.match("/{context}/api/users/register")) {
addUserFormData = request.getContent();
username = addUserFormData.username;
firstname = addUserFormData.firstname;
lastname = addUserFormData.lastname;
emailAddress = addUserFormData.emailAddress;
password = addUserFormData.password;
if (!addUserFormData.userRoles) {
userRoles = null;
} else {
userRoles = String(addUserFormData.userRoles).split(",");
}
try {
result = userModule.registerUser(username, firstname, lastname, emailAddress, password,
userRoles);
} catch (e) {
log.error("Exception occurred while trying to registering a new user to DC User Store", e);
// http status code 400 refers to - Bad request.
result = 400;
}
} else if (uriMatcher.match("/{context}/api/users/add")) {
if (userModule.isAuthorized("/permission/device-mgt/admin/users/add")) {
addUserFormData = request.getContent();
username = addUserFormData.username;
firstname = addUserFormData.firstname;
lastname = addUserFormData.lastname;
emailAddress = addUserFormData.emailAddress;
if (!addUserFormData.userRoles) {
userRoles = null;
} else {
userRoles = String(addUserFormData.userRoles).split(",");
}
try {
result = userModule.addUser(username, firstname, lastname, emailAddress, userRoles);
} catch (e) {
log.error("Exception occurred while trying to add a user to DC User Store", e);
// http status code 400 refers to - Bad request.
result = 400;
}
} else {
// http status code 403 refers to - forbidden.
result = 403;
}
} else if (uriMatcher.match("/{context}/api/users/{username}/remove")) {
if (userModule.isAuthorized("/permission/device-mgt/admin/users/remove")) {
elements = uriMatcher.elements();
username = elements.username;
try {
result = userModule.removeUser(username);
} catch (e) {
log.error("Exception occurred while trying to remove a user from DC User Store", e);
// http status code 400 refers to - Bad request.
result = 400;
}
} else {
// http status code 403 refers to - forbidden.
result = 403;
}
}
// returning the result.
if (result) {
print(result);
}
%>

@ -0,0 +1,16 @@
{
"appContext" : "/iotserver/",
"apiContext" : "api",
"httpsURL": "%https.ip%",
"httpURL": "%http.ip%",
"ssoConfiguration": {
"enabled": false,
"issuer": "iot",
"appName": "iot",
"identityProviderURL": "%https.ip%/sso/samlsso.jag",
"responseSigningEnabled": "true",
"keyStorePassword": "wso2carbon",
"identityAlias": "wso2carbon",
"keyStoreName": "/repository/resources/security/wso2carbon.jks"
}
}

@ -0,0 +1,37 @@
/*
* Copyright (c) 2015, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
*
* WSO2 Inc. licenses this file to you 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.
*/
var config = function () {
var conf = application.get("PINCH_CONFIG");
if (!conf) {//if not in cache
var pinch = require('/modules/pinch.min.js').pinch;
var server = require('carbon').server;
var config = require('/config/config.json');
pinch(config, /^/, function (path, key, value) {
if ((typeof value === 'string') && value.indexOf('%https.ip%') > -1) {
return value.replace('%https.ip%', server.address("https"));
} else if ((typeof value === 'string') && value.indexOf('%http.ip%') > -1) {
return value.replace('%http.ip%', server.address("http"));
}
return value;
});
application.put("PINCH_CONFIG", config);//caching
conf = config;
}
return conf;
};

@ -0,0 +1,28 @@
/*
* Copyright (c) 2015, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
*
* WSO2 Inc. licenses this file to you 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.
*/
var carbonModule = require("carbon");
var dcProps = require('/config/dc-props.js').config();
var carbonServer = new carbonModule.server.Server({
tenanted: true,
url: dcProps.httpsURL + '/admin'
});
application.put("carbonServer", carbonServer);
var userModule = require("/modules/user.js").userModule;
var utility = require("/modules/utility.js").utility;
utility.insertAppPermissions(userModule, "init");

@ -0,0 +1,47 @@
{
"displayName": "Fuse Sample",
"logLevel": "info",
"initScripts": ["/config/init.js"],
"urlMappings": [
{
"url" : "/test/*",
"path" : "test/testExecutor.jag"
},
{
"url": "/api/device/*",
"path": "/api/device-api.jag"
},
{
"url": "/api/devices/*",
"path": "/api/device-api.jag"
},
{
"url": "/api/user/*",
"path": "/api/user-api.jag"
},
{
"url": "/api/users/*",
"path": "/api/user-api.jag"
},
{
"url": "/api/stats/*",
"path": "/api/stats-api.jag"
},
{
"url": "/sso/login",
"path": "/lib/login.jag"
},
{
"url": "/sso/logout",
"path": "/lib/logout.jag"
},
{
"url": "/sso/acs",
"path": "/lib/acs.jag"
},
{
"url": "/*",
"path": "/lib/fuse.jag"
}
]
}

@ -0,0 +1,30 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>
{{ defineZone "title"}}
</title>
{{ defineZone "topLibCss"}}
{{ defineZone "topCss"}}
</head>
<body>
<div class="container col-lg-12 col-md-12 col-sm-12">
<!-- header -->
<header>
<div class="row wr-global-header">
<div class="col-sm-8 app-logo">
{{ defineZone "brand"}}
</div>
</div>
</header>
<!-- /header -->
{{ defineZone "body"}}
{{ defineZone "footer"}}
</div>
{{ defineZone "bottomjquery" }}
{{ defineZone "bottomLibJs" }}
{{ defineZone "bottomJs" }}
</body>
</html>

@ -0,0 +1,38 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- The above 3 meta tags *must* come first in the head; any other head content must come *after* these tags -->
<title>{{ defineZone "title"}}</title>
{{ defineZone "topLibCss"}}
{{ defineZone "topCss"}}
{{ defineZone "topJs"}}
</head>
<body>
<div class="wr-modalpopup">
<div class="modalpopup-container">
<div class="modalpopup-close-btn" onclick="hidePopup();">
<span class="fw-stack">
<i class="fw fw-ring fw-stack-2x"></i>
<i class="fw fw-left-arrow fw-stack-1x"></i>
</span>
GO BACK
</div>
<div class="modalpopup-content"><!-- dynamic content --></div>
</div>
<div class="modalpopup-bg"></div>
</div>
{{ defineZone "notification"}}
<div class="container col-lg-12 col-md-12 col-sm-12">
<!-- header -->
{{ defineZone "header"}}
<!-- /header -->
{{ defineZone "body"}}
{{ defineZone "footer"}}
</div>
{{ defineZone "bottomLibJs" }}
{{ defineZone "bottomJs" }}
</body>
</html>

@ -0,0 +1,50 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>{{ defineZone "title"}}</title>
{{ defineZone "topCss"}}
</head>
<body>
<div class="navbar navbar-default navbar-fixed-top" role="navigation">
<div class="container-liquid">
<div class="navbar-header">
<a class="navbar-brand" href="#">{{defineZone "brand"}}</a>
</div>
<div class="navbar-collapse collapse">
<ul class="nav navbar-nav navbar-right">
<li><a href="/login">Login</a></li>
{{ defineZone "upperRight"}}
</ul>
</div>
</div>
</div>
<div id="wrap">
<div class="container-fluid">
<div class="row">
<div class="col-sm-2">
{{ defineZone "left"}}
</div>
<div class="col-sm-10">
{{ defineZone "content"}}
</div>
</div>
</div>
<!-- /container -->
</div>
<div class="footer">
<div class="container">
<div class="row">
<div class="col-md-12">
{{ defineZone "footer"}}
</div>
</div>
</div>
</div>
</body>
</html>

@ -0,0 +1,49 @@
<%
/*
* Copyright (c) 2015, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
*
* WSO2 Inc. licenses this file to you 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.
*/
var dataConfig = require('/config/dc-props.js').config();
var sso = require('/modules/sso.js').sso;
var constants = require('/modules/constants.js');
var carbonModule = require("carbon");
var log = new Log();
var keyStoreParams = {
keyStoreName: dataConfig.ssoConfiguration.keyStoreName,
keyStorePassword: dataConfig.ssoConfiguration.keyStorePassword,
identityAlias: dataConfig.ssoConfiguration.identityAlias
};
sso.configure(dataConfig.ssoConfiguration.issuer,
dataConfig.ssoConfiguration.appName,
keyStoreParams, dataConfig.ssoConfiguration.identityProviderURL);
sso.acs(
function(loggedInUser) {
var carbonUser = carbonModule.server.tenantUser(loggedInUser);
session.put(constants.USER_SESSION_KEY, carbonUser);
var username = carbonUser.username;
if(log.isDebugEnabled()){
log.debug("User logged in: "+username);
}
response.sendRedirect(dataConfig.appContext);
}, function() {
if(log.isDebugEnabled()){
log.debug("User logged out");
}
response.sendRedirect(dataConfig.appContext);
}
);
%>

@ -0,0 +1,243 @@
//public function declarations
var route;
(function () {
//public
/**
* front controller entity point. acts as the main function for every request.
*/
route = function () {
//lets assume URL looks like https://my.domain.com/app/{one}/{two}/{three}/{four}
var uri = request.getRequestURI(); // = app/{one}/{two}/{three}/{four}
var parts = splitFirst(uri);
fuseState.appName = parts.head;
var path = parts.tail; // = /{one}/{two}/{three}/{four}
var handled = false;
parts = splitFirst(path);
if (parts.head == 'public') { // {one} == 'public'
parts = splitFirst(parts.tail);
if (splitFirst(parts.tail).head == 'less') { // {three} == 'less'
handled = renderLess(parts.head, parts.tail); // renderLess({two},{three}/{four})
} else {
handled = renderStatic(parts.head, parts.tail);
}
} else {
handled = renderPage(path);
if (!handled) {
handled = renderUnit(path);
}
}
if (!handled) {
response.sendError(404, 'Requested resource not found');
}
};
//private
var log = new Log('fuse.router');
var getMime = function (path) {
var index = path.lastIndexOf('.') + 1;
var knowMime = {
'js': 'application/javascript',
'html': 'text/html',
'htm': 'text/html',
'woff': 'application/x-font-woff',
"png": "image/png",
"css": "text/css",
"hbs": "text/x-handlebars-template",
"apk": "application/vnd.android.package-archive",
"ipa": "application/octet-stream"
};
var mime;
if (index >= 0) {
mime = knowMime[path.substr(index)];
}
return mime || 'text/plain';
};
/**
* '/a/b/c/d' -> {'a','b/c/d'}
* @param path URI part, should start with '/'
* @returns {{head: string, tail: string}}
*/
var splitFirst = function (path) {
var firstSlashPos = path.indexOf('/', 1);
var head = path.substring(1, firstSlashPos);
var tail = path.substring(firstSlashPos);
return {head: head, tail: tail};
};
/**
* @param str
* @param prefix
* @returns {boolean} true iif str starts with prefix
*/
var startsWith = function (str, prefix) {
return (str.lastIndexOf(prefix, 0) === 0);
};
var renderStatic = function (unit, path) {
var unitModel = null;
var unitName = "";
var parts = (unit + path).split("/");
//'unitName' name can be "unitA" or "categoryA/unitA" or "categoryA/categoryAb/unitB"...etc
//incrementally trying to resolve a unit using url path parts.
for (var i = 0; i < parts.length; i++) {
if (unitName == "") {
unitName = parts[i];
} else {
unitName += "/" + parts[i];
}
try {
var model = fuse.getUnitDefinition(unitName);
if (model) {
unitModel = {
name: model.name,
path: parts.splice(i + 1).join("/")
};
break;
}
} catch (err) {
//unit not found, ignore error
}
}
if (unitModel == null) {
log.error("unit `"+unit+"` not found!");
return false;
}
var staticFile = fuse.getFile(unitModel.name, 'public' + "/" + unitModel.path);
if (staticFile.isExists() && !staticFile.isDirectory()) {
response.addHeader('Content-type', getMime(path));
response.addHeader('Cache-Control', 'public,max-age=12960000');
staticFile.open('r');
var stream = staticFile.getStream();
print(stream);
staticFile.close();
return true;
}
return false;
};
var renderPage = function (path) {
var jagFile;
if (path.indexOf('/', path.length - 1) !== -1) {
jagFile = new File('/pages' + path + 'index.jag');
} else {
jagFile = new File('/pages' + path + '.jag');
}
if (jagFile.isExists()) {
include(jagFile.getPath());
return true;
} else {
return false;
}
};
var renderUnit = function (path) {
var mainUnit = null;
var matchedUnits = fuse.getMatchedUnitDefinitions();
fuse.addDependencies(matchedUnits);
var zones = fuseState.zones;
// A map of maps. this is used to ensure same zone is not render twice in to same definition.
// zonesAdded = { titleZone : { zoneFromA : true, zoneFromB : true } }
var zonesAdded = {};
for (var i = 0; i < matchedUnits.length; i++) {
var definition = matchedUnits[i];
for (var j = 0; j < definition.zones.length; j++) {
var zone = definition.zones[j];
if (!zones[zone.name]) {
zones[zone.name] = [];
zonesAdded[zone.name] = {};
}
var zoneKey = zone.origin + ':' + zone.name; // temp unique key to identify zone form a given unit.
if (!zonesAdded[zone.name][zoneKey]) {
var zoneInfo = {unitName: definition.name};
if (zone.origin != definition.name) {
zoneInfo.originUnitName = zone.origin;
}
zones[zone.name].push(zoneInfo);
zonesAdded[zone.name][zoneKey] = true;
}
}
}
var layout = fuseState.layout;
if (layout !== null) {
log.debug(
'[' + requestId + '] request for "' + path + '" will be rendered using layout "' +
layout + '" (defined in "' + mainUnit + '") and zones ' +
stringify(zones)
);
var output = handlebars.Handlebars.compileFile(fuse.getLayoutPath(layout))({});
response.addHeader('Content-type', 'text/html');
print(output);
return true;
} else {
log.debug(
'[' + requestId + '] request for "' + path + '" will can\'t be rendered, since no layout is defined' +
'in any of the units ' + stringify(zones));
return false;
}
};
function fileToString(path) {
}
/**
* convert less file to css and print to output. add '?nocache=true' to force regenerate.
* @param unit name of the unit
* @param path the path to the less file relative to unit root (should start with slash)
* @returns {boolean} is successfully rendered.
*/
function renderLess(unit, path) {
//TODO: fix - incorrect less files makes it respond the old less even if it is nocahce.
log.debug('[' + requestId + '] for unit "' + unit + '" a request received for a less file "' + path + '"');
var cacheKey = '/tmp/cached_' + unit + path.replace(/[^\w\.-]/g, '_');
fuseState.currentUnit = unit;
var cachedCss = new File(cacheKey);
//TODO: move this check to caller function ??
if (fuseDebug || request.getParameter('nocache') == 'true' || !cachedCss.isExists()) {
var parts = splitFirst(path);
var lessPath = '/public/less' + parts.tail.replace(/\.css$/, '') + '.less';
var lessFile = fuse.getFile(unit, lessPath);
if (lessFile.isExists()) {
var x = require('less-rhino-1.7.5.js');
x.compile([lessFile.getPath(), cacheKey]);
log.debug('[' + requestId + '] for unit "' + unit + '" request for "' + path + '" is cached as "' + cacheKey + '"');
}
}
if (cachedCss.isExists()) {
response.addHeader('Content-type', 'text/css');
response.addHeader('Cache-Control', 'public,max-age=12960000');
cachedCss.open('r');
var stream = cachedCss.getStream();
print(stream);
cachedCss.close();
return true;
}
return false;
}
})();

@ -0,0 +1,36 @@
<%
var getPath = File.prototype.getPath;
File.prototype.getPath = function() {
var path = getPath.call(this);
path = path.replace(/\\/g, '/');
return path;
};
//global object to pass request stat among fuse framework files.
var fuseState = {
zones: {},
appName: '',
zoneStack: [],
currentUnit: null
};
var requestId = function makeId() {
var text = "";
var possible = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
for (var i = 0; i < 5; i++)
text += possible.charAt(Math.floor(Math.random() * possible.length));
return text;
}();
var fuseDebug = false;
//var fuseDebug = true;
var handlebars = require('handlebars-helpers.js');
var fuseRouter = require('fuse-router.js');
var fuse = require('fuse.js');
fuseRouter.route();
%>

@ -0,0 +1,452 @@
//public function declarations
var getHbsFile, getFile, toRelativePath, cleanupAncestors,
getUnitPath, getMatchedUnitDefinitions, getZoneDefinition, getUnitDefinition,
getUnitDefinitions, getLayoutPath, readUnitDefinitions;
(function () {
//private
var log = new Log('fuse.core');
var lookUpTable = null;
var definitions = null;
var initLookUp = function (definitions) {
if (lookUpTable === null) {
lookUpTable = {};
for (var i = 0; i < definitions.length; i++) {
var definition = definitions[i];
lookUpTable[definition.name] = i;
//log.info("initLookUp()"+definition.name+"<-"+i);
}
}
};
var isMatched = function (definition, layout) {
var urlMatch = function (pattern) {
var uriMatcher = new URIMatcher(request.getRequestURI());
return Boolean(uriMatcher.match('/{appName}' + pattern));
};
var permission = function (permissionStr) {
var carbonModule = require("carbon");
var carbonServer = application.get("carbonServer");
var carbonUser = session.get("USER");
if (carbonUser) {
var userManager = new carbonModule.user.UserManager(carbonServer, carbonUser.tenantId);
var user = new carbonModule.user.User(userManager, carbonUser.username);
return user.isAuthorized(permissionStr, "ui.execute");
}
return false;
};
var config = {'theme': 'default'};
var predicateStr = definition.definition.predicate;
if (predicateStr) {
var js = 'function(config,urlMatch,permission,layout){ return ' + predicateStr + ';}';
return Boolean(eval(js)(config, urlMatch,permission, layout ? layout : NaN));
}
return false;
};
var getAncestorModels = function (unit) {
//log.info('[' + requestId + '] getAncestorModels()'+unit);
var unitModel = getUnitDefinition(unit);
var ancestors = [unitModel];
var parentName;
while ((parentName = unitModel.definition.extends) != null) {
unitModel = getUnitDefinition(parentName);
ancestors.push(unitModel);
}
return ancestors;
};
addDependencies = function (unitModels) {
var resolved = {};
for (var i = 0; i < unitModels.length; i++) {
resolved[unitModels[i].name] = true;
}
for (i = 0; i < unitModels.length; i++) {
var unitModel = unitModels[i];
var dependencies = unitModel.definition.dependencies;
if (dependencies) {
for (var j = 0; j < dependencies.length; j++) {
var dependencyName = dependencies[j];
unitModels.push(getUnitDefinition(dependencyName));
resolved[dependencyName] = true;
}
}
}
};
//public
getMatchedUnitDefinitions = function () {
//TODO: return map not list
var unitDefinitions = getUnitDefinitions();
var matched = [];
var unMatched = [];
var layout = null;
var mainUnit = null;
var addToMatched = function (model) {
matched.push(model);
if (model.layout) {
if (layout == null) {
layout = model.layout;
mainUnit = model.name;
} else {
log.warn(
'[' + requestId + '] multiple layouts ' + mainUnit + ':' +
layout + ' vs ' + model.name + ':' + model.layout
);
}
}
};
// first pass
for (var i = 0; i < unitDefinitions.length; i++) {
var unitDefinition = unitDefinitions[i];
if (isMatched(unitDefinition)) {
addToMatched(unitDefinition);
} else {
unMatched.push(unitDefinition);
}
}
fuseState.layout = layout;
// second pass : we have to do this two passes since we don't know the layout
// first time around
if (layout) {
for (i = 0; i < unMatched.length; i++) {
unitDefinition = unMatched[i];
if (isMatched(unitDefinition, layout)) {
addToMatched(unitDefinition)
}
}
}
var toDelete = [];
for (i = 0; i < matched.length; i++) {
var ancestors = getAncestorModels(matched[i].name);
for (var j = 1; j < ancestors.length; j++) {
var ancestor = ancestors[j];
toDelete.push(ancestor.name);
}
}
for (i = matched.length - 1; i >= 0; i--) {
//log.info(matched[i].name);
if (toDelete.indexOf(matched[i].name) >= 0) {
matched.splice(i, 1);
}
}
return matched;
};
getUnitDefinition = function (unit) {
//log.info('[' + requestId + '] getUnitDefinition()'+unit);
var definitions = getUnitDefinitions();
initLookUp(definitions);
//log.info('[' + requestId + '] lookUpTable[unit]:'+unit);
var model = definitions[lookUpTable[unit]];
if (!model) {
throw '[' + requestId + '] unit "' + unit + '" does not exits';
}
return model;
};
var flattenAllInheritance = function (unitModels) {
var hasFlattend = {};
for (var i = 0; i < unitModels.length; i++) {
var model = unitModels[i];
if (!hasFlattend[model]) {
var ancestors = getAncestorModels(model.name);
for (var j = ancestors.length - 1; j >= 1; j--) {
flattenInheritance(ancestors[j], ancestors[j - 1]);
}
}
}
};
var flattenInheritance = function (parent, child) {
var parentZones = parent.zones;
for (var i = 0; i < parentZones.length; i++) {
var parentZone = parentZones[i];
child.zones.push(parentZone);
}
};
getUnitDefinitions = function () {
if (definitions !== null) {
return definitions;
} else {
definitions = [];
}
var unitDirs = new File('/units').listFiles();
definitions = readUnitDefinitions("",unitDirs,definitions);
//log.info(definitions);
addPageUnitDefinitions(definitions);
initLookUp(definitions);
flattenAllInheritance(definitions);
return definitions;
};
readUnitDefinitions = function(basePath, unitDirs, definitions){
for (var i = 0; i < unitDirs.length; i++) {
var unitDir = unitDirs[i];
if (unitDir.isDirectory()) {
var unitName = unitDir.getName();
//log.info("reading: "+unitName + " basePath:'" + basePath + "'");
var definitionFile = new File(fuse.getUnitPath(basePath+unitName) + '/' + unitName + '.json');
if(definitionFile.isExists()) {
var unitModel = {
name: unitName,
path: unitDir.getPath()
};
if(basePath!=""){
unitModel.name = basePath + unitName;
}
var path = definitionFile.getPath();
log.debug('[' + requestId + '] reading file "' + path + '"');
unitModel.definition = require(path);
// add the information derived by parsing hbs file to the same model
var hbsMetadata = getHbsMetadata(unitModel);
unitModel.zones = hbsMetadata.zones;
if (hbsMetadata.layout) {
unitModel.layout = hbsMetadata.layout;
}
definitions.push(unitModel);
}else{
var unitSubDirs = new File(fuse.getUnitPath(basePath+"/"+unitName)).listFiles();
readUnitDefinitions(basePath+unitName+"/",unitSubDirs,definitions);
}
}
}
return definitions;
};
addPageUnitDefinitions = function (unitModels, dir) {
var pageFiles = new File(dir || '/pages').listFiles();
for (var i = 0; i < pageFiles.length; i++) {
var pageFile = pageFiles[i];
var fileName = pageFile.getName();
if (pageFile.isDirectory()) {
addPageUnitDefinitions(unitModels, pageFile.getPath())
} else if (fileName.indexOf('.hbs', fileName.length - 4) !== -1) { // File name ends with '.hbs'
var isLeaf = true;
//path relative to app root
var relativePath = pageFile.getPath()
.substring(6 + pageFile.getPath().indexOf('/pages/'), pageFile.getPath().length - 4);
if (relativePath.match(/\/index$/)) {
relativePath = relativePath.replace(/\/index$/, '');
var parentFile = new File(pageFile.getPath().substr(0, pageFile.getPath().lastIndexOf('/')));
var hasSiblings = parentFile.listFiles().length != 1;
if (hasSiblings) {
isLeaf = false;
}
}
//this will be used as a name for the virtual unit, useful for debugging purposes.
var unitName = (relativePath == '' ? 'index' : relativePath.substr(1).replace(/\//, '-') ) + '-page';
var predicate = "urlMatch('" + relativePath + "')";
// leaf is page that can handle multiple URLs. in this case it should have a wildcard at end.
// but since our current matcher doesn't support {/wildcard*} patten, "OR" ( || ) is used
if (isLeaf) {
predicate += " || urlMatch('" + relativePath + "/{+wildcard}')";
}
var unitModel = {
name: unitName,
path: pageFile.getPath(),
definition: {predicate: predicate}
};
var hbsMetadata = getHbsMetadata(unitModel);
unitModel.zones = hbsMetadata.zones;
if (hbsMetadata.layout) {
unitModel.layout = hbsMetadata.layout;
}
unitModels.push(unitModel);
}
}
};
getLayoutPath = function (layout) {
return '/layouts/' + layout + '.hbs';
};
getHbsFile = function (unit) {
// we determining if it's page unit or a proper unit
// by checking if path ends with '.hbs'
// TODO: improve getFile to do include this logic
if (unit.path.indexOf('.hbs', unit.path.length - 4) !== -1) {
return new File(unit.path);
} else {
if(unit.name.indexOf('/') !== -1){//a subcategory unit
var rawParts = unit.name.split("/");
return new File(unit.path + '/' + rawParts[rawParts.length-1] + '.hbs');
}else {
return new File(unit.path + '/' + unit.name + '.hbs');
}
}
};
var getHbsMetadata = function (unit) {
var zoneDef = {'zones': []};
var hbsFile = getHbsFile(unit);
if (!hbsFile.isExists()) {
log.error("Couldn't find .hbs file at: `" + unit.path + "`");
return zoneDef;
}
var output = handlebars.Handlebars.compileFile(hbsFile)({});
var zonesAndLayouts = output.trim().split(/\s+/gm);
for (var i = 0; i < zonesAndLayouts.length; i++) {
var name = zonesAndLayouts[i];
if (name.lastIndexOf('zone_', 0) === 0) {
zoneDef.zones.push({name: name.substr(5), origin: unit.name});
} else if (name.lastIndexOf('layout_', 0) === 0) {
zoneDef.layout = name.substr(7);
}
}
return zoneDef;
};
getUnitPath = function (unit) {
return '/units/' + unit;
};
cleanupAncestors = function (units) {
var toDelete = {};
var len = units.length;
for (var i = 0; i < len; i++) {
var unit = units[i];
if (!toDelete[unit]) {
var ancestors = getAncestorModels(unit.name);
for (var j = 1; j < ancestors.length; j++) {
toDelete[ancestors[j].name] = unit;
}
}
}
while (len--) {
if (toDelete[units[len]]) {
log.debug(
'[' + requestId + '] unit "' + units[len] +
'" is overridden by "' + toDelete[units[len]] + '"'
);
units.splice(len, 1);
}
}
};
toRelativePath = function (path) {
var start = 0;
if (path.lastIndexOf('/units/', 0) == 0) {
start = 7; // len('/units/')
}
var slashPos = path.indexOf('/', 7);
return {
unit: path.substring(start, slashPos),
path: path.substr(slashPos)
}
};
/**
* Get a file inside a unit by relative path. if the file is not available in the given unit,
* the closest ancestor's file will be returned. if an optional suffix is used the relative path is
* calculated as ( path + < unit name > + opt_suffix ). if no such a file exists a returned file object will
* point to provided unit's non-existing file location (not to any ancestors).
*
* @param unitName name of the unit
* @param path path relative to unit root.
* @param opt_suffix
* @returns {File}
*/
getFile = function (unitName, path, opt_suffix) {
//log.info("getFile() unitName:"+unitName+", path:"+path+", opt_suffix:"+opt_suffix);
var slashPath = ((path[0] === '/') ? '' : '/') + path;
var selfFileName = '';
var fileName = '';
if (opt_suffix) {
if(unitName.indexOf('/') !== -1) {//a subcategory unit
var rawParts = unitName.split("/");
selfFileName = rawParts[rawParts.length - 1];
}else {
selfFileName = unitName;
}
selfFileName = selfFileName + opt_suffix;
slashPath = slashPath + ((slashPath[slashPath.length - 1] === '/') ? '' : '/');
}
//TODO: remove this hack that makes in page-unit, any file is same
var unitDef = getUnitDefinition(unitName);
if (unitDef.path.indexOf('.hbs', unitDef.path.length - 4) !== -1) {
if (opt_suffix.indexOf('.hbs', opt_suffix.length - 4) !== -1) {
//log.info("1:"+unitDef.path);
return new File(unitDef.path);
} else {
//log.info("2:"+unitDef.path.replace(/.hbs$/, opt_suffix));
return new File(unitDef.path.replace(/.hbs$/, opt_suffix));
}
}
var selfFile = new File(getUnitPath(unitName) + slashPath + selfFileName);
if (selfFile.isExists()) {
log.debug(
'[' + requestId + '] for unit "' + unitName + '" file resolved : "'
+ slashPath + selfFileName + '" -> "' + selfFile.getPath() + '"'
);
//log.info("3:"+getUnitPath(unitName) + slashPath + selfFileName);
return selfFile;
}
var ancestors = getAncestorModels(unitName);
for (var i = 1; i < ancestors.length; i++) {
var ancestorName = ancestors[i].name;
if(ancestorName.indexOf('/') !== -1) {//a subcategory unit
var rawParts = ancestorName.split("/");
ancestorName = rawParts[rawParts.length - 1];
}
if (opt_suffix) {
fileName = ancestorName + opt_suffix;
}
var file = new File(getUnitPath(ancestorName) + slashPath + fileName);
if (file.isExists()) {
log.debug(
'[' + requestId + '] for unit "' + unitName + '" file resolved : "'
+ slashPath + selfFileName + '" -> "' + file.getPath() + '"'
);
//log.info("4:"+getUnitPath(ancestorName) + slashPath + fileName);
return file;
}
}
log.debug(
'[' + requestId + '] for unit "' + unitName + '" (non-excising) file resolved : "'
+ slashPath + selfFileName + '" -> "' + selfFile.getPath() + '"'
);
//log.info("5:"+getUnitPath(unitName) + slashPath + selfFileName);
return selfFile;
};
})();

@ -0,0 +1,204 @@
var log = new Log('fuse.handlebars');
//TODO: create a different set of helpers for init parsing
var Handlebars = require('handlebars-v2.0.0.js').Handlebars;
var USER_SESSION_KEY = "USER";
var getScope = function (unit,configs) {
var jsFile = fuse.getFile(unit, '', '.js');
var templateConfigs = configs || {};
var script;
var onRequestCb = function(){}; //Assume that onRequest function will not be defined by the user
var viewModel = {};
var cbResult;
if (jsFile.isExists()) {
script = require(jsFile.getPath());
//Eagerly make the viewModel the template configs
viewModel = templateConfigs;
//Check if the unit author has specified an onRequest
//callback
if(script.hasOwnProperty('onRequest')){
script.app = {
url: '/' + fuseState.appName,
publicURL: '/' + fuseState.appName + '/public/' + unit,
"class": unit + '-unit'
};
onRequestCb = script.onRequest;
cbResult = onRequestCb(templateConfigs);
log.debug("passing configs to unit "+unit+" configs: "+stringify(templateConfigs));
//If the execution does not yield an object we will print
//a warning as the unit author may have forgotten to return a data object
if(cbResult===undefined){
cbResult = {}; //Give an empty data object
log.warn('[' + requestId + '] unit "' + unit + '" has a onRequest method which does not return a value.This may lead to the '
+'unit not been rendered correctly.');
}
viewModel = cbResult;
}
}
else{
//If there is no script then the view should get the configurations
//passed in the unit call
viewModel = templateConfigs;
}
viewModel.app = {
url: '/' + fuseState.appName
};
viewModel.self = {
publicURL: '/' + fuseState.appName + '/public/' + unit,
"class": unit + '-unit'
};
return viewModel;
};
Handlebars.innerZones = [];
Handlebars.innerZonesFromUnit = null;
Handlebars.registerHelper('defineZone', function (zoneName, zoneContent) {
var result = '';
var zone = Handlebars.Utils.escapeExpression(zoneName);
fuseState.zoneStack.push(zone);
var unitsToRender = fuseState.zones[zone] || [];
if (Handlebars.innerZones.length > 0) {
unitsToRender = fuseState.zones[Handlebars.innerZones[0]] || [];
}
// if there is no one overriding, then display inline zone
if (zoneContent['fn'] && unitsToRender.length == 0) {
return zoneContent.fn(this).trim();
}
for (var i = 0; i < unitsToRender.length; i++) {
var unit = unitsToRender[i];
if (Handlebars.innerZonesFromUnit == null || Handlebars.innerZonesFromUnit.unitName == unit.unitName) {
var template = fuse.getFile(unit.originUnitName || unit.unitName, '', '.hbs');
log.debug('[' + requestId + '] for zone "' + zone + '" including template :"' + template.getPath() + '"');
result += Handlebars.compileFile(template)(getScope(unit.unitName, zoneContent.data.root));
}
}
// we go to inner zones if result is empty, what we should really do it
// if matched zone is fully made of sub-zones. this is a hack to
// make it easy to implement.
if (result.trim().length == 0 && zoneContent['fn']) {
Handlebars.innerZones.push(zoneName);
for (i = 0; i < unitsToRender.length; i++) {
unit = unitsToRender[i];
Handlebars.innerZonesFromUnit = unit;
result += zoneContent.fn(this).trim();
Handlebars.innerZonesFromUnit = null;
}
Handlebars.innerZones.pop();
return result;
}
fuseState.zoneStack.pop();
return new Handlebars.SafeString(result);
});
Handlebars.registerHelper('zone', function (zoneName, zoneContent) {
var currentZone = fuseState.zoneStack[fuseState.zoneStack.length - 1];
if (currentZone == null) {
return 'zone_' + zoneName + ' ';
}
// if it's exact zone match or if any in inner zone matches we render zone.
// this second condition is a hack. what we should really do is to keep another stack,
// and only match with the peek of that stack and always fill it with next in innerZone stack.
if (zoneName == currentZone || Handlebars.innerZones.indexOf(zoneName) >= 0) {
return zoneContent.fn(this).trim();
} else {
return '';
}
});
Handlebars.registerHelper('layout', function (layoutName) {
var currentZone = fuseState.zoneStack[fuseState.zoneStack.length - 1];
if (currentZone == null) {
return 'layout_' + layoutName;
} else {
return '';
}
});
Handlebars.registerHelper('authorized', function () {
var currentZone = fuseState.zoneStack[fuseState.zoneStack.length - 1];
if (currentZone == null) {
return '';
} else {
var loggedUser = session.get(USER_SESSION_KEY);
if(loggedUser == null){
response.sendRedirect("/"+ fuseState.appName + "/login");
exit();
}
}
});
Handlebars.registerHelper('unit', function (unitName,options) {
var unitDef = fuse.getUnitDefinition(unitName);
var baseUnit = null;
var templateConfigs = options.hash || {};
for (var i = 0; i < unitDef.zones.length; i++) {
var zone = unitDef.zones[i];
if (zone.name == 'main') {
baseUnit = zone.origin;
} else {
var golbalZone = fuseState.zones[zone.name];
if (!golbalZone) {
fuseState.zones[zone.name] = [{"unitName": unitName}];
} else {
fuseState.zones[zone.name].push({"unitName": unitName});
}
}
}
if (baseUnit == null) {
log.error('unit does not have a main zone');
}
//TODO warn when unspecified decencies are included.
fuseState.zoneStack.push('main');
var template = fuse.getFile(baseUnit, '', '.hbs');
log.debug('[' + requestId + '] including "' + baseUnit + '"'+" with configs "+stringify(templateConfigs));
var result = new Handlebars.SafeString(Handlebars.compileFile(template)(getScope(baseUnit,templateConfigs)));
fuseState.zoneStack.pop();
return result;
});
Handlebars.compileFile = function (file) {
//TODO: remove this overloaded argument
var f = (typeof file === 'string') ? new File(file) : file;
if (!Handlebars.cache) {
Handlebars.cache = {};
}
if (Handlebars.cache[f.getPath()] != null) {
return Handlebars.cache[f.getPath()];
}
f.open('r');
log.debug('[' + requestId + '] reading file "' + f.getPath() + '"');
var content = f.readAll().trim();
f.close();
var compiled = Handlebars.compile(content);
Handlebars.cache[f.getPath()] = compiled;
return compiled;
};
Handlebars.registerHelper('equal', function(lvalue, rvalue, options) {
if (arguments.length < 3)
throw new Error("Handlebars Helper equal needs 2 parameters");
if( lvalue!=rvalue ) {
return options.inverse(this);
} else {
return options.fn(this);
}
});
Handlebars.registerHelper('unequal', function(lvalue, rvalue, options) {
if (arguments.length < 3)
throw new Error("Handlebars Helper equal needs 2 parameters");
if( lvalue == rvalue ) {
return options.inverse(this);
} else {
return options.fn(this);
}
});

File diff suppressed because one or more lines are too long

@ -0,0 +1,36 @@
<%
/*
* Copyright (c) 2015, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
*
* WSO2 Inc. licenses this file to you 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(){
var constants = require('/modules/constants.js');
if (!session.get(constants.USER_SESSION_KEY)) {
var dataConfig = require('/config/dc-props.js').config();
var sso = require('/modules/sso.js').sso;
var keyStoreParams = {
keyStoreName : dataConfig.ssoConfiguration.keyStoreName,
keyStorePassword : dataConfig.ssoConfiguration.keyStorePassword,
identityAlias : dataConfig.ssoConfiguration.identityAlias
}
sso.configure(dataConfig.ssoConfiguration.issuer, dataConfig.ssoConfiguration.appName, keyStoreParams,
dataConfig.ssoConfiguration.identityProviderURL);
sso.login();
}else{
response.sendRedirect(dataConfig.appContext);
}
}());
%>

@ -0,0 +1,37 @@
<%
/*
* Copyright (c) 2015, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
*
* WSO2 Inc. licenses this file to you 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.
*/
var constants = require('/modules/constants.js');
var user = session.get(constants.USER_SESSION_KEY);
var dataConfig = require('/config/dc-props.js').config();
var log = new Log();
if (user === null) {
log.debug("Cannot perform logout. No user session found.");
response.sendRedirect(dataConfig.appContext+'dashboard');
} else {
var sso = require('/modules/sso.js').sso;
var keyStoreParams = {
keyStoreName: dataConfig.ssoConfiguration.keyStoreName,
keyStorePassword: dataConfig.ssoConfiguration.keyStorePassword,
identityAlias: dataConfig.ssoConfiguration.identityAlias
}
sso.configure(dataConfig.ssoConfiguration.issuer, dataConfig.ssoConfiguration.appName, keyStoreParams,
dataConfig.ssoConfiguration.identityProviderURL);
sso.logout(user);
}
%>

@ -0,0 +1,45 @@
/*
* Copyright (c) 2015, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
*
* WSO2 Inc. licenses this file to you 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.
*/
var WEB_APP_TITLE = "WSO2 DC - Device Cloud";
var WEB_APP_CONTEXT = "/iotserver";
var USER_SESSION_KEY = "USER";
var UNSPECIFIED = "Unspecified";
var DEVICES_UNIT_PATH="/units/devices/";
var DEVICE_IDENTIFIER = "deviceIdentifier";
var DEVICE_NAME = "name";
var DEVICE_OWNERSHIP = "ownership";
var DEVICE_OWNER = "owner";
var DEVICE_TYPE = "type";
var DEVICE_VENDOR = "vendor";
var DEVICE_MODEL = "model";
var DEVICE_PRODUCT = "PRODUCT";
var DEVICE_OS_VERSION = "osVersion";
var DEVICE_PROPERTIES = "properties";
var FEATURE_NAME = "featureName";
var FEATURE_DESCRIPTION = "featureDescription";
var PLATFORM_ANDROID = "android";
var PLATFORM_IOS = "ios";
var VENDOR_APPLE = "Apple";
var ERRORS = {
"USER_NOT_FOUND": "USER_NOT_FOUND"
};

@ -0,0 +1,276 @@
/*
* Copyright (c) 2015, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
*
* WSO2 Inc. licenses this file to you 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.
*/
var deviceModule;
deviceModule = function () {
var log = new Log("modules/device.js");
var constants = require("/modules/constants.js");
var utility = require("/modules/utility.js").utility;
var carbon = require('carbon');
var carbonHttpServletTransport = carbon.server.address('http');
var carbonHttpsServletTransport = carbon.server.address('https');
var ArrayList = Packages.java.util.ArrayList;
var Properties = Packages.java.util.Properties;
var DeviceIdentifier = Packages.org.wso2.carbon.device.mgt.common.DeviceIdentifier;
var DeviceManagerUtil = Packages.org.wso2.carbon.device.mgt.core.util.DeviceManagerUtil;
var SimpleOperation = Packages.org.wso2.carbon.device.mgt.core.operation.mgt.SimpleOperation;
var ConfigOperation = Packages.org.wso2.carbon.device.mgt.core.operation.mgt.ConfigOperation;
var CommandOperation = Packages.org.wso2.carbon.device.mgt.core.operation.mgt.CommandOperation;
var deviceManagementDAOFactory = Packages.org.wso2.carbon.device.mgt.core.dao.DeviceManagementDAOFactory;
var deviceManagementService = utility.getDeviceManagementService();
log.info(deviceManagementService.getDeviceCount());
var publicMethods = {};
var privateMethods = {};
privateMethods.validateAndReturn = function (value) {
return (value == undefined || value == null) ? constants.UNSPECIFIED : value;
};
privateMethods.getStoreDefinition = function (deviceTypeStr) {
var storeJSON = new File(constants.DEVICES_UNIT_PATH + deviceTypeStr + "/public/store.json");
if (storeJSON.isExists()) {
storeJSON.open('r');
log.debug('reading file "' + storeJSON.getPath() + '"');
var content = storeJSON.readAll().trim();
storeJSON.close();
return parse(content);
}
return null;
};
publicMethods.listDevices = function () {
var devices = deviceManagementService.getAllDevices();
var deviceList = [];
var i, device, propertiesList, deviceObject;
for (i = 0; i < devices.size(); i++) {
device = devices.get(i);
propertiesList = DeviceManagerUtil.convertDevicePropertiesToMap(device.getProperties());
deviceObject = {};
deviceObject[constants.DEVICE_IDENTIFIER] =
privateMethods.validateAndReturn(device.getDeviceIdentifier());
deviceObject[constants.DEVICE_NAME] =
privateMethods.validateAndReturn(device.getName());
deviceObject[constants.DEVICE_OWNERSHIP] =
privateMethods.validateAndReturn(device.getOwnership());
deviceObject[constants.DEVICE_OWNER] =
privateMethods.validateAndReturn(device.getOwner());
deviceObject[constants.DEVICE_TYPE] =
privateMethods.validateAndReturn(device.getType());
deviceObject[constants.DEVICE_PROPERTIES] = {};
if (device.getType() == constants.PLATFORM_IOS) {
deviceObject[constants.DEVICE_PROPERTIES][constants.DEVICE_MODEL] =
privateMethods.validateAndReturn(propertiesList.get(constants.DEVICE_PRODUCT));
deviceObject[constants.DEVICE_PROPERTIES][constants.DEVICE_VENDOR] = constants.VENDOR_APPLE;
} else {
deviceObject[constants.DEVICE_PROPERTIES][constants.DEVICE_MODEL] =
privateMethods.validateAndReturn(propertiesList.get(constants.DEVICE_MODEL));
deviceObject[constants.DEVICE_PROPERTIES][constants.DEVICE_VENDOR] =
privateMethods.validateAndReturn(propertiesList.get(constants.DEVICE_VENDOR));
}
deviceObject[constants.DEVICE_PROPERTIES][constants.DEVICE_OS_VERSION] =
privateMethods.validateAndReturn(propertiesList.get(constants.DEVICE_OS_VERSION));
deviceList.push(deviceObject);
}
return deviceList;
};
publicMethods.listDevicesForUser = function (username) {
var devices = deviceManagementService.getDeviceListOfUser(username);
var deviceList = [];
var i, device, propertiesList, deviceObject;
for (i = 0; i < devices.size(); i++) {
device = devices.get(i);
propertiesList = DeviceManagerUtil.convertDevicePropertiesToMap(device.getProperties());
deviceObject = {};
deviceObject[constants.DEVICE_IDENTIFIER] =
privateMethods.validateAndReturn(device.getDeviceIdentifier());
deviceObject[constants.DEVICE_NAME] =
privateMethods.validateAndReturn(device.getName());
deviceObject[constants.DEVICE_OWNERSHIP] =
privateMethods.validateAndReturn(device.getOwnership());
deviceObject[constants.DEVICE_OWNER] =
privateMethods.validateAndReturn(device.getOwner());
deviceObject[constants.DEVICE_TYPE] =
privateMethods.validateAndReturn(device.getType());
deviceObject[constants.DEVICE_PROPERTIES] = {};
if (device.getType() == constants.PLATFORM_IOS) {
deviceObject[constants.DEVICE_PROPERTIES][constants.DEVICE_MODEL] =
privateMethods.validateAndReturn(propertiesList.get(constants.DEVICE_PRODUCT));
deviceObject[constants.DEVICE_PROPERTIES][constants.DEVICE_VENDOR] = constants.VENDOR_APPLE;
} else {
deviceObject[constants.DEVICE_PROPERTIES][constants.DEVICE_MODEL] =
privateMethods.validateAndReturn(propertiesList.get(constants.DEVICE_MODEL));
deviceObject[constants.DEVICE_PROPERTIES][constants.DEVICE_VENDOR] =
privateMethods.validateAndReturn(propertiesList.get(constants.DEVICE_VENDOR));
}
deviceObject[constants.DEVICE_PROPERTIES][constants.DEVICE_OS_VERSION] =
privateMethods.validateAndReturn(propertiesList.get(constants.DEVICE_OS_VERSION));
deviceList.push(deviceObject);
}
return deviceList;
};
/**
* Return list of device types.
* Device types should be registered in CDMF and specific unit with name of '{devicetype}' should be presented.
* @returns {Array}
*/
publicMethods.listDeviceTypes = function () {
var deviceTypes = deviceManagementDAOFactory.getDeviceTypeDAO().getDeviceTypes();
var deviceTypesList = [];
var i, deviceType, deviceTypeObject;
for (i = 0; i < deviceTypes.size(); i++) {
deviceType = deviceTypes.get(i);
var deviceUnit = new File(constants.DEVICES_UNIT_PATH + deviceType.getName());
if (deviceUnit.isExists()) {
deviceTypeObject = {};
deviceTypeObject["name"] = deviceType.getName();
var storeProperties = privateMethods.getStoreDefinition(deviceType.getName());
if (storeProperties) {
deviceTypeObject["storeTitle"] = storeProperties.title;
deviceTypeObject["storeDescription"] = storeProperties.description;
}
deviceTypesList.push(deviceTypeObject);
} else {
log.warn("Device type `" + deviceType.getName() + "` is missing unit implementation at: " + constants.DEVICES_UNIT_PATH);
}
}
return deviceTypesList;
};
publicMethods.removeDevice = function (deviceType, deviceId) {
//URL: https://localhost:9443/{deviceType}/manager/device/remove/{deviceId}
var deviceCloudService = carbonHttpsServletTransport + "/" + deviceType + "/manager",
removeDeviceEndpoint = deviceCloudService + "/device/remove/" + deviceId;
var data = {};
//XMLHTTPRequest's GET
return del(removeDeviceEndpoint, data, "text");
};
publicMethods.updateDevice = function (deviceType, deviceId, device) {
//URL: https://localhost:9443/{deviceType}/manager/device/update/{deviceId}
var deviceCloudService = carbonHttpsServletTransport + "/" + deviceType + "/manager",
updateDeviceEndpoint = deviceCloudService + "/device/update/" + deviceId;
var data = {};
//XMLHTTPRequest's POST
return post(updateDeviceEndpoint+ "?name="+device.name, data, "json");
};
/*
Get the supported features by the device type
*/
publicMethods.getFeatures = function (deviceType) {
var features = deviceManagementService.getFeatureManager(deviceType).getFeatures();
var featuresConverted = {};
if (features) {
var i, feature, featureObject;
for (i = 0; i < features.size(); i++) {
feature = features.get(i);
featureObject = {};
featureObject[constants.FEATURE_NAME] = feature.getName();
featureObject[constants.FEATURE_DESCRIPTION] = feature.getDescription();
featuresConverted[feature.getName()] = featureObject;
}
}
return featuresConverted;
};
publicMethods.performOperation = function (devices, operation) {
var operationInstance;
if (operation.type == "COMMAND") {
operationInstance = new CommandOperation();
} else if (operation.type == "CONFIG") {
operationInstance = new ConfigOperation();
} else {
operationInstance = new SimpleOperation();
}
operationInstance.setCode(operation.featureName);
var props = new Properties();
var i, object;
for (i = 0; i < operation.properties.length; i++) {
object = properties[i];
props.setProperty(object.key, object.value);
}
operationInstance.setProperties(props);
var deviceList = new ArrayList();
var j, device, deviceIdentifier;
for (j = 0; j < devices.length; i++) {
device = devices[j];
deviceIdentifier = new DeviceIdentifier();
deviceIdentifier.setId(device.id);
deviceIdentifier.setType(device.type);
deviceList.add(deviceIdentifier);
}
deviceManagementService.addOperation(operationInstance, deviceList);
};
privateMethods.getDevice = function (type, deviceId) {
var deviceIdentifier = new DeviceIdentifier();
deviceIdentifier.setType(type);
deviceIdentifier.setId(deviceId);
return deviceManagementService.getDevice(deviceIdentifier);
};
publicMethods.viewDevice = function (type, deviceId) {
var device = privateMethods.getDevice(type, deviceId);
if (device) {
var propertiesList = DeviceManagerUtil.convertDevicePropertiesToMap(device.getProperties());
var entries = propertiesList.entrySet();
var iterator = entries.iterator();
var properties = {};
var entry, key, value;
while (iterator.hasNext()) {
entry = iterator.next();
key = entry.getKey();
value = entry.getValue();
properties[key] = privateMethods.validateAndReturn(value);
}
var deviceObject = {};
deviceObject[constants.DEVICE_IDENTIFIER] = device.getDeviceIdentifier();
deviceObject[constants.DEVICE_NAME] = privateMethods.validateAndReturn(device.getName());
deviceObject[constants.DEVICE_OWNERSHIP] = privateMethods.validateAndReturn(device.getOwnership());
deviceObject[constants.DEVICE_OWNER] = device.getOwner();
deviceObject[constants.DEVICE_TYPE] = device.getType();
if (device.getType() == constants.PLATFORM_IOS) {
properties[constants.DEVICE_MODEL] = properties[constants.DEVICE_PRODUCT];
delete properties[constants.DEVICE_PRODUCT];
properties[constants.DEVICE_VENDOR] = constants.VENDOR_APPLE;
}
deviceObject[constants.DEVICE_PROPERTIES] = properties;
return deviceObject;
}
};
return publicMethods;
}();

@ -0,0 +1,68 @@
/*
* Copyright (c) 2015, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
*
* WSO2 Inc. licenses this file to you 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.
*/
var downloadModule;
var Handlebars = require('../lib/handlebars-v2.0.0.js').Handlebars;
downloadModule = function () {
var log = new Log("modules/download.js");
var constants = require("/modules/constants.js");
var publicMethods = {};
var privateMethods = {};
/**
* Downloading a specified sketch file.
*
* @param file File name or file object of the downloading file
* @param replaceParams
*/
publicMethods.downloadSketch = function (file, response, replaceParams) {
var file = new File("../sketch/" + file);
file.open('r');
log.debug("Reading file '" + file.getPath() + "'");
var content = file.readAll().trim();
file.close();
var downloadFile = privateMethods.allReplace(content,replaceParams);
response.contentType = "application/octet-stream";
response.addHeader("Content-Disposition", "attachment; filename='sketch.hbs'");
response.addHeader("Content-Length", String(downloadFile.length));
response.content = downloadFile;
};
/**
* Find and replace all occurrences.
* @param inStr input string
* @param replaceParams key value array
* @returns retStr replaced string
*/
privateMethods.allReplace = function (inStr, replaceParams) {
var retStr = inStr;
for (var x in replaceParams) {
retStr = retStr.replace(new RegExp(x, 'g'), replaceParams[x])
}
return retStr;
};
return publicMethods;
}();

@ -0,0 +1,27 @@
/*
* Copyright (c) 2011 František Hába <hello@frantisekhaba.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the 'Software'), to deal in
* the Software without restriction, including without limitation the rights to use,
* copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
* Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
* THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
* Reference:- https://github.com/Baggz/Pinch
* Pinch is a small JavaScript utility which is able to replace any data in a JavaScript object (or JSON).
* */
(function(){var k=function(a,c){return a.length!==c.length?!1:a.every(function(a,b){return c[b]===a})},j=function(a,c,d){var b,e;if("[object Array]"===Object.prototype.toString.call(a)){b=0;for(e=a.length;b<e;b++)c.apply(d,[b,a[b],a])}else for(b in a)a.hasOwnProperty(b)&&c.apply(d,[b,a[b],a])},h=function(a){for(var c=[],d=!1,b=0,e=a.length,f="",g=function(){f&&(c.push(f),f="")};b<e;b++)a[b].match(/\[|\]/)?(g(),d="]"===a[b]?!1:!0):'"'!==a[b]&&"'"!==a[b]&&("."===a[b]&&!d?g():f+=a[b]),b===e-1&&g();return c},
g=function(a,c,d){var b=-1!==["string","object"].indexOf(typeof a),e="string"===typeof c||c&&c.test&&c.exec,f=-1!==["string","object","function"].indexOf(typeof d);b&&e&&f&&("string"===typeof a?(this.instance=JSON.parse(a),this.json=!0):this.instance=a,this.pattern="string"===typeof c?c.replace(/'/g,'"'):c,this.replacement=d,this.createIndex(this.instance))};g.prototype.createIndex=function(a,c){var d=this;this.index=this.index||[];c=c||"";j(a,function(a,e){var f,a=a+"";f=a.match(/^[a-zA-Z]+$/)?c?
c+"."+a:a:a.match(/\d+/)?c+"["+a+"]":c+'["'+a+'"]';d.index.push(f);"object"===typeof e&&d.createIndex(e,f)})};g.prototype.replace=function(){var a=this;j(this.index,function(c,d){if(a.pattern&&a.pattern.test&&a.pattern.exec&&d.match(a.pattern))return a.replaceValue(d);if("string"===typeof a.pattern){var b=h(d),e=h(a.pattern);if(k(b,e))return a.replaceValue(d)}});return this.json?JSON.stringify(this.instance):this.instance};g.prototype.replaceValue=function(a){var c=this,d=h(a);d.reduce(function(b,
e,f){if(f===d.length-1)f="function"===typeof c.replacement?c.replacement(a,e,b[e]):c.replacement,b[e]=f;else return b[e]},this.instance)};var i=function(a,c,d,b){a=(new g(a,c,d)).replace();return"function"===typeof b?b(null,a):a};"undefined"!==typeof module&&module.exports?module.exports=i:"undefined"!==typeof define?define(function(){return i}):this.pinch=i})();

@ -0,0 +1,161 @@
/*
* Copyright (c) 2015, WSO2 Inc. (http:www.wso2.org) All Rights Reserved.
*
* WSO2 Inc. licenses this file to you 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.
*/
var sso = {};
var ssoMod = require("sso");
var log = new Log();
(function () {
var carbon = require("carbon");
var process = require("process");
var getSSOSessions = function () {
var sso_sessions = application.get('sso_sessions');
if (!sso_sessions) {
application.put('sso_sessions', {});
sso_sessions = application.get('sso_sessions');
}
return sso_sessions;
};
sso.configure = function (issuer, appName, keyStoreParams, address, transport, ssoService, responseSign) {
sso.issuer = issuer;
sso.appName = appName;
sso.relayState = "/" + appName;
sso.transport = (transport ? transport : "https");
sso.ssoService = (ssoService ? ssoService : "/samlsso");
sso.responseSign = (responseSign ? responseSign : true);
sso.log = new Log("SSO Module");
sso.address = carbon.server.address(sso.transport);
sso.keyStoreProps = {
KEY_STORE_NAME: process.getProperty('carbon.home') + keyStoreParams.keyStoreName,
KEY_STORE_PASSWORD: keyStoreParams.keyStorePassword,
IDP_ALIAS: keyStoreParams.identityAlias
};
};
sso.login = function () {
sso.sessionId = session.getId();
var referer = request.getHeader("referer");
sso.relayState = (referer ? referer : sso.relayState);
sso.relayState = sso.relayState;// append query string
var log = new Log();
if (request.getQueryString()) {
sso.relayState += request.getQueryString();
}
sso.encodedSAMLAuthRequest = ssoMod.client.getEncodedSAMLAuthRequest(sso.issuer);
var postUrl = sso.address + sso.ssoService;
if (log.isDebugEnabled()) {
log.debug("Request sent to IdP");
}
print("<div><p>You are now being redirected to SSO Provider. If the redirection fails, please click on the "+
"button below.</p> <form method='post' action='" + postUrl + "'><p><input type='hidden' " +
"name='SAMLRequest' value='" + sso.encodedSAMLAuthRequest + "'/><input type='hidden' " +
"name='RelayState' value='" + sso.relayState + "'/><input type='hidden' name='SSOAuthSessionID' " +
"value='" + sso.sessionId + "'/><button type='submit'>Redirect manually</button></p></form></div>" +
"<script type = 'text/javascript' >document.forms[0].submit();</script>");
};
sso.logout = function (user) {
var sso_sessions = getSSOSessions();
sso.sessionId = session.getId();
sso.sessionIndex = sso_sessions[sso.sessionId];
var referer = request.getHeader("referer");
sso.relayState = (referer ? referer : sso.relayState);
sso.relayState = sso.relayState + request.getQueryString(); // append query string
sso.encodedSAMLLogoutRequest = ssoMod.client.getEncodedSAMLLogoutRequest(user, sso.sessionIndex, sso.issuer);
var postUrl = sso.address + sso.ssoService;
if (log.isDebugEnabled()) {
sso.log.debug("Logout request recieved from session id ::: " + sso.sessionId);
}
print("<div><p>You are now redirected to Stratos Identity. If theredirection fails, please click the post " +
"button.</p> <form id='logoutForm' method='post' action='" + postUrl + "'> <p> <input type='hidden' " +
"name='SAMLRequest' value='" + sso.encodedSAMLLogoutRequest + "'/> <input type='hidden' " +
"name='RelayState' value='" + sso.relayState + "'/> <input type='hidden' name='SSOAuthSessionID' " +
"value='" + sso.sessionId + "'/> <button type='submit'>POST</button> </p> </form> </div> <script " +
"type = 'text/javascript' > document.forms[0].submit(); </script>");
};
sso.acs = function (loginCallback, logoutCallback) {
var sso_sessions = getSSOSessions();
sso.sessionId = session.getId();
var samlResponse = request.getParameter('SAMLResponse');
var samlRequest = request.getParameter('SAMLRequest');
var relayState = request.getParameter('RelayState');
var samlRespObj;
if (samlResponse != null) {
samlRespObj = ssoMod.client.getSamlObject(samlResponse);
if (ssoMod.client.isLogoutResponse(samlRespObj)) {
logoutCallback();
if (log.isDebugEnabled()) {
sso.log.debug('Session Id Invalidated :::' + sso.sessionId);
}
// Invalidating the session after the callback
session.invalidate();
} else {
if (log.isDebugEnabled()) {
sso.log.debug("Login request");
}
// validating the signature
if (sso.responseSign) {
if (ssoMod.client.validateSignature(samlRespObj, sso.keyStoreProps)) {
var sessionObj = ssoMod.client.decodeSAMLLoginResponse(samlRespObj, samlResponse,
sso.sessionId);
if (log.isDebugEnabled()) {
sso.log.debug("Saml object session ID :::" + sessionObj.sessionId);
}
if (sessionObj.sessionIndex != null || sessionObj.sessionIndex != 'undefined') {
sso_sessions[sso_sessions[sessionObj.sessionIndex] = sessionObj.sessionId] =
sessionObj.sessionIndex;
if (log.isDebugEnabled()) {
sso.log.debug("Login successful");
sso.log.debug('User is set :::' + sessionObj.loggedInUser);
}
loginCallback(sessionObj.loggedInUser);
} else {
sso.log.error("Session index invalid");
}
} else {
sso.log.error("Response Signing failed");
}
} else {
if (log.isDebugEnabled()) {
sso.log.debug("Response Signing is disabled");
}
}
}
}
/*
Executed for single logout requests
*/
if (samlRequest != null) {
var index = ssoMod.client.decodeSAMLLogoutRequest(ssoMod.client.getSamlObject(samlRequest));
var jSessionId = getSSOSessions()[index];
delete getSSOSessions()[index];
if (log.isDebugEnabled()) {
sso.log.debug('Backend logout received from store. The index is :::' + index);
sso.log.debug('Session Id Invalidated :::' + jSessionId);
}
session.invalidate();
}
}
})();

@ -0,0 +1,321 @@
/*
* Copyright (c) 2015, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
*
* WSO2 Inc. licenses this file to you 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.
*/
var userModule;
userModule = function () {
var log = new Log("modules/user.js");
var constants = require("/modules/constants.js");
var utility = require("/modules/utility.js").utility;
var userManagementService = utility.getUserManagementService();
var publicMethods = {};
var privateMethods = {};
/**
* Authenticate a user when he or she attempts to login to DC.
*
* @param username Username of the user
* @param password Password of the user
* @param successCallback Function to be called at the event of successful authentication
* @param failureCallback Function to be called at the event of failed authentication
*/
publicMethods.login = function (username, password, successCallback, failureCallback) {
var carbonModule = require("carbon");
var carbonServer = application.get("carbonServer");
try {
// get tenant specific full user name.
username = username + "@" + carbonModule.server.tenantDomain();
// check if the user is an authenticated user.
var isAuthenticated = carbonServer.authenticate(username, password);
if (isAuthenticated) {
var tenantUser = carbonModule.server.tenantUser(username);
session.put(constants.USER_SESSION_KEY, tenantUser);
successCallback(tenantUser);
} else {
failureCallback();
}
} catch (e) {
throw e;
}
};
/**
* Register user to dc-user-store.
*
* @param username Username of the user
* @param firstname First name of the user
* @param lastname Last name of the user
* @param emailAddress Email address of the user
* @param password Password of the user
* @param userRoles Roles assigned to the user
*
* @returns {number} HTTP Status code 201 if succeeded, 409 if user already exists
*/
publicMethods.registerUser = function (username, firstname, lastname, emailAddress, password, userRoles) {
var carbon = require('carbon');
var tenantId = carbon.server.tenantId();
var url = carbon.server.address('https') + "/admin/services";
var server = new carbon.server.Server(url);
var userManager = new carbon.user.UserManager(server, tenantId);
try {
if (userManager.userExists(username)) {
if (log.isDebugEnabled()) {
log.debug("A user with name '" + username + "' already exists.");
}
// http status code 409 refers to - conflict.
return 409;
} else {
var defaultUserClaims = privateMethods.buildDefaultUserClaims(firstname, lastname, emailAddress);
userManager.addUser(username, password, userRoles, defaultUserClaims, "default");
if (log.isDebugEnabled()) {
log.debug("A new user with name '" + username + "' was created.");
}
// http status code 201 refers to - created.
return 201;
}
} catch (e) {
throw e;
}
};
/**
* Add user to dc-user-store.
*
* @param username Username of the user
* @param firstname First name of the user
* @param lastname Last name of the user
* @param emailAddress Email address of the user
* @param userRoles Roles assigned to the user
*
* @returns {number} HTTP Status code 201 if succeeded, 409 if user already exists
*/
publicMethods.addUser = function (username, firstname, lastname, emailAddress, userRoles) {
var carbon = require('carbon');
var tenantId = carbon.server.tenantId();
var url = carbon.server.address('https') + "/admin/services";
var server = new carbon.server.Server(url);
var userManager = new carbon.user.UserManager(server, tenantId);
try {
if (userManager.userExists(username)) {
if (log.isDebugEnabled()) {
log.debug("A user with name '" + username + "' already exists.");
}
// http status code 409 refers to - conflict.
return 409;
} else {
var initialUserPassword = privateMethods.generateInitialUserPassword();
var defaultUserClaims = privateMethods.buildDefaultUserClaims(firstname, lastname, emailAddress);
userManager.addUser(username, initialUserPassword, userRoles, defaultUserClaims, "default");
privateMethods.inviteUserToEnroll(username, initialUserPassword);
if (log.isDebugEnabled()) {
log.debug("A new user with name '" + username + "' was created.");
}
// http status code 201 refers to - created.
return 201;
}
} catch (e) {
throw e;
}
};
/**
* Remove an existing user from mdm-user-store.
*
* @param username Username of the user
* @returns {number} HTTP Status code 200 if succeeded, 409 if the user does not exist
*/
publicMethods.removeUser = function (username) {
var carbon = require('carbon');
var tenantId = carbon.server.tenantId();
var url = carbon.server.address('https') + "/admin/services";
var server = new carbon.server.Server(url);
var userManager = new carbon.user.UserManager(server, tenantId);
try {
if (userManager.userExists(username)) {
userManager.removeUser(username);
if (log.isDebugEnabled()) {
log.debug("An existing user with name '" + username + "' was removed.");
}
// http status code 200 refers to - success.
return 200;
} else {
if (log.isDebugEnabled()) {
log.debug("A user with name '" + username + "' does not exist to remove.");
}
// http status code 409 refers to - conflict.
return 409;
}
} catch (e) {
throw e;
}
};
/**
* Private method to be used by addUser() to
* generate an initial user password for a user.
* This will be the password used by a user for his initial login to the system.
*
* @returns {string} Initial User Password
*/
privateMethods.generateInitialUserPassword = function () {
var passwordLength = 6;
//defining the pool of characters to be used for initial password generation
var lowerCaseCharset = "abcdefghijklmnopqrstuvwxyz";
var upperCaseCharset = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
var numericCharset = "0123456789";
var totalCharset = lowerCaseCharset + upperCaseCharset + numericCharset;
var totalCharsetLength = totalCharset.length;
var initialUserPassword = "";
for (var i = 0; i < passwordLength; ++i) {
initialUserPassword += totalCharset.charAt(Math.floor(Math.random() * totalCharsetLength));
}
if (log.isDebugEnabled()) {
log.debug("Initial password created for new user : " + initialUserPassword);
}
return String(initialUserPassword);
};
/**
* Build default user claims.
*
* @param firstname First name of the user
* @param lastname Last name of the user
* @param emailAddress Email address of the user
*
* @returns {Object} Default user claims to be provided
*/
privateMethods.buildDefaultUserClaims = function (firstname, lastname, emailAddress) {
var defaultUserClaims = {
"http://wso2.org/claims/givenname": firstname,
"http://wso2.org/claims/lastname": lastname,
"http://wso2.org/claims/emailaddress": emailAddress
};
if (log.isDebugEnabled()) {
log.debug("ClaimMap created for new user : " + stringify(defaultUserClaims));
}
return defaultUserClaims;
};
publicMethods.addPermissions = function (permissionList, path, init) {
var carbonModule = require("carbon");
var carbonServer = application.get("carbonServer");
var options = {system: true};
if (init == "login") {
var carbonUser = session.get(constants.USER_SESSION_KEY);
if (carbonUser) {
options.tenantId = carbonUser.tenantId;
}
}
var registry = new carbonModule.registry.Registry(carbonServer, options);
var i, permission, resource;
for (i = 0; i < permissionList.length; i++) {
permission = permissionList[i];
resource = {
collection : true,
name : permission.name,
properties : {
name : permission.name
}
};
registry.put("/_system/governance/permission/" + path + "/" + permission.key, resource);
}
};
publicMethods.getUsers = function () {
var users = [];
var carbonUser = session.get(constants.USER_SESSION_KEY);
if (!carbonUser) {
log.error("User object was not found in the session");
throw constants.ERRORS.USER_NOT_FOUND;
}
var userList = userManagementService.getUsersForTenant(carbonUser.tenantId);
var i, userObject;
for (i = 0; i < userList.size(); i++) {
userObject = userList.get(i);
var userObj = {
"username" : userObject.getUserName(),
"email" : userObject.getEmail(),
"name" : userObject.getFirstName() + " " + userObject.getLastName()
};
if(userObj.username == "admin"){
userObj.name = "admin";
}
users.push(userObj);
}
return users;
};
publicMethods.isAuthorized = function (permission) {
var carbonModule = require("carbon");
var carbonServer = application.get("carbonServer");
var carbonUser = session.get(constants.USER_SESSION_KEY);
if (!carbonUser) {
log.error("User object was not found in the session");
throw constants.ERRORS.USER_NOT_FOUND;
}
var userManager = new carbonModule.user.UserManager(carbonServer, carbonUser.tenantId);
var user = new carbonModule.user.User(userManager, carbonUser.username);
return user.isAuthorized(permission, "ui.execute");
};
publicMethods.getUIPermissions = function(){
var permissions = {};
if (publicMethods.isAuthorized("/permission/device-mgt/admin/devices/list") ||
publicMethods.isAuthorized("/permission/device-mgt/user/devices/list")) {
permissions.LIST_DEVICES = true;
}
if (publicMethods.isAuthorized("/permission/device-mgt/admin/users/list")) {
permissions.LIST_USERS = true;
}
if (publicMethods.isAuthorized("/permission/device-mgt/admin/users/add")) {
permissions.ADD_USER = true;
}
if (publicMethods.isAuthorized("/permission/device-mgt/admin/policies/add")) {
permissions.ADD_POLICY = true;
}
if (publicMethods.isAuthorized("/permission/device-mgt/admin/policies/list")) {
permissions.LIST_POLICIES = true;
}
if (publicMethods.isAuthorized("/permission/device-mgt/admin/dashboard/view")) {
permissions.DASHBOARD_VIEW = true;
}
//TO-DO Apply followings in to carbon permissions
permissions.ADD_DEVICE = true;
return permissions;
};
publicMethods.logout = function (successCallback) {
session.invalidate();
successCallback();
};
return publicMethods;
}();

@ -0,0 +1,65 @@
/*
* Copyright (c) 2015, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
*
* WSO2 Inc. licenses this file to you 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.
*/
var utility;
utility = function () {
var JavaClass = Packages.java.lang.Class;
var PrivilegedCarbonContext = Packages.org.wso2.carbon.context.PrivilegedCarbonContext;
var getOsgiService = function (className) {
return PrivilegedCarbonContext.getThreadLocalCarbonContext().getOSGiService(JavaClass.forName(className));
};
var publicMethods = {};
publicMethods.getDeviceManagementService = function () {
return getOsgiService('org.wso2.carbon.device.mgt.core.service.DeviceManagementService');
};
publicMethods.getUserManagementService = function () {
return getOsgiService('org.wso2.carbon.device.mgt.user.core.UserManager');
};
publicMethods.getPolicyManagementService = function () {
return getOsgiService('org.wso2.carbon.policy.mgt.core.PolicyManagerService');
};
publicMethods.insertAppPermissions = function (userModule, type) {
userModule.addPermissions([{key: "device-mgt", name: "Device Management"}], "", type);
userModule.addPermissions([{key: "admin", name: "Device Management Admin"}], "device-mgt", type);
userModule.addPermissions([{key: "user", name: "Device Management User"}], "device-mgt", type);
userModule.addPermissions([{key: "devices", name: "Devices"}], "device-mgt/admin", type);
userModule.addPermissions([{key: "devices/list", name: "List Devices"}], "device-mgt/admin", type);
userModule.addPermissions([{key: "devices/operation", name: "Perform Operation"}], "device-mgt/admin", type);
userModule.addPermissions([{key: "users", name: "Users"}], "device-mgt/admin", type);
userModule.addPermissions([{key: "users/add", name: "Add New Users"}], "device-mgt/admin", type);
userModule.addPermissions([{key: "users/invite", name: "Invite Users"}], "device-mgt/admin", type);
userModule.addPermissions([{key: "users/list", name: "List Users"}], "device-mgt/admin", type);
userModule.addPermissions([{key: "users/remove", name: "Remove Users"}], "device-mgt/admin", type);
userModule.addPermissions([{key: "devices", name: "Devices"}], "device-mgt/user", type);
userModule.addPermissions([{key: "devices/list", name: "List Devices"}], "device-mgt/user", type);
userModule.addPermissions([{key: "devices/operation", name: "Perform Operation"}], "device-mgt/user", "init");
};
return publicMethods;
}();

@ -0,0 +1,9 @@
{{authorized}}
{{layout "fluid"}}
{{#zone "title"}}
WSO2 DC | My Devices List
{{/zone}}
{{#zone "body"}}
{{unit "appbar"}}
{{unit "alldevices"}}
{{/zone}}

@ -0,0 +1,8 @@
{{layout "fluid"}}
{{#zone "title"}}
WSO2 DC | Device Cloud
{{/zone}}
{{#zone "body"}}
{{unit "appbar"}}
{{unit "dashboard"}}
{{/zone}}

@ -0,0 +1,12 @@
{{authorized}}
{{layout "fluid"}}
{{#zone "title"}}
Device Management
{{/zone}}
{{#zone "body"}}
{{unit "operation-mod"}}
{{unit "appbar" enableBack=true title="Device"}}
{{unit "device-detail"}}
{{/zone}}

@ -0,0 +1,9 @@
{{authorized}}
{{layout "fluid"}}
{{#zone "title"}}
WSO2 MDM | Device Management
{{/zone}}
{{#zone "body"}}
{{unit "appbar" link="device-store" title="Device Store"}}
{{unit "store-listing"}}
{{/zone}}

@ -0,0 +1,9 @@
{{authorized}}
{{layout "fluid"}}
{{#zone "title"}}
WSO2 DC | FireAlarm
{{/zone}}
{{#zone "body"}}
{{unit "appbar" link="device-mgt" title="Device Management"}}
{{unit "analytics"}}
{{/zone}}

@ -0,0 +1,8 @@
{{layout "fluid"}}
{{#zone "title"}}
WSO2 DC | Android
{{/zone}}
{{#zone "body"}}
{{unit "appbar" link="store" title="STORE"}}
{{unit "devices/android"}}
{{/zone}}

@ -0,0 +1,8 @@
{{layout "fluid"}}
{{#zone "title"}}
WSO2 DC | Android Sense
{{/zone}}
{{#zone "body"}}
{{unit "appbar" link="store" title="STORE"}}
{{unit "devices/android_sense"}}
{{/zone}}

@ -0,0 +1,8 @@
{{layout "fluid"}}
{{#zone "title"}}
WSO2 DC | Arduino
{{/zone}}
{{#zone "body"}}
{{unit "appbar" link="store" title="STORE"}}
{{unit "devices/arduino"}}
{{/zone}}

@ -0,0 +1,8 @@
{{layout "fluid"}}
{{#zone "title"}}
WSO2 DC | FireAlarm
{{/zone}}
{{#zone "body"}}
{{unit "appbar" link="store" title="STORE"}}
{{unit "devices/digital_display"}}
{{/zone}}

@ -0,0 +1,8 @@
{{layout "fluid"}}
{{#zone "title"}}
WSO2 DC | FireAlarm
{{/zone}}
{{#zone "body"}}
{{unit "appbar" link="store" title="STORE"}}
{{unit "devices/firealarm"}}
{{/zone}}

@ -0,0 +1,23 @@
{{authorized}}
{{layout "fluid"}}
{{#zone "title"}}
Devices
{{/zone}}
{{#zone "body"}}
{{unit "appbar" link="device-mgt" title="Device Management"}}
{{unit "extended-search-box"}}
{{unit "operation-mod"}}
<div class="wr-device-list row">
<div class="wr-hidden-operations wr-advance-operations">
</div>
<div class="col-md-12 wr-page-content">
<!-- content -->
<div>
{{unit "operation-bar"}}
{{unit "device-listing"}}
</div>
<!-- /content -->
</div>
</div>
{{/zone}}

@ -0,0 +1,8 @@
{{layout "fluid"}}
{{#zone "title"}}
WSO2 DC | FireAlarm
{{/zone}}
{{#zone "body"}}
{{unit "appbar" link="store" title="STORE"}}
{{unit "devices/raspberrypi"}}
{{/zone}}

@ -0,0 +1,8 @@
{{layout "fluid"}}
{{#zone "title"}}
WSO2 DC | FireAlarm
{{/zone}}
{{#zone "body"}}
{{unit "appbar" link="store" title="STORE"}}
{{unit "devices/sensebot"}}
{{/zone}}

@ -0,0 +1,8 @@
{{layout "fluid"}}
{{#zone "title"}}
WSO2 DC | Windows
{{/zone}}
{{#zone "body"}}
{{unit "appbar" link="store" title="STORE"}}
{{unit "devices/windows"}}
{{/zone}}

@ -0,0 +1,8 @@
{{layout "fluid"}}
{{#zone "title"}}
WSO2 DC | Device Cloud
{{/zone}}
{{#zone "body"}}
{{unit "appbar" link="dashboard" title="Device Management"}}
{{unit "showcase"}}
{{/zone}}

@ -0,0 +1,7 @@
{{layout "fluid"}}
{{#zone "title"}}
WSO2 Device Cloud | Login
{{/zone}}
{{#zone "body"}}
{{unit "login"}}
{{/zone}}

@ -0,0 +1,7 @@
{{layout "fluid"}}
{{#zone "title"}}
WSO2 Device Cloud | Register
{{/zone}}
{{#zone "body"}}
{{unit "register"}}
{{/zone}}

@ -0,0 +1,9 @@
{{authorized}}
{{layout "fluid"}}
{{#zone "title"}}
WSO2 MDM | Add User
{{/zone}}
{{#zone "body"}}
{{unit "appbar" title="Add User"}}
{{unit "user-create"}}
{{/zone}}

@ -0,0 +1,9 @@
{{authorized}}
{{layout "fluid"}}
{{#zone "title"}}
User Management
{{/zone}}
{{#zone "body"}}
{{unit "appbar" link="users" title="User Management"}}
{{unit "user-listing"}}
{{/zone}}

@ -0,0 +1,20 @@
<%
/*
* Copyright (c) 2015, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
*
* WSO2 Inc. licenses this file to you 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.
*/
require("jaggery-test").test.run();
%>

@ -0,0 +1,39 @@
{{#zone "main"}}
<div class="container container-bg white-bg " xmlns="http://www.w3.org/1999/html"
xmlns="http://www.w3.org/1999/html">
<div class=" margin-top-double">
<div class="row row padding-top-double padding-bottom-double margin-bottom-double ">
<div class="col-lg-12 margin-top-double">
<h2 class="grey ">My Devices </h2>
<hr>
</div>
</div>
</div>
<div class="row margin-double padding-double">
<form method="GET" action="{{myDevicePath}}">
<table class="table table-hover border" id="devicesTable">
<thead>
<tr class="grey-bg">
<th class="uppercase">Device ID</th>
<th class="uppercase">Name</th>
<th class="uppercase">Type</th>
<th class="uppercase center">Action</th>
</tr>
</thead>
<tbody>
{{! All devices will be listed here @see: alldevices_util.js}}
<tr class="border-top">
<th scope="row"></th>
<td colspan="3">
No Devices available.
</td>
</tr>
</tbody>
</table>
</form>
</div>
</div>
{{/zone}}
{{#zone "bottomJs"}}
<script src="{{self.publicURL}}/js/alldevices_util.js"></script>
{{/zone}}

@ -0,0 +1,4 @@
function onRequest(context) {
context.myDevicePath = "/iotserver/mydevice";
return context;
}

@ -0,0 +1,49 @@
function getAllDevices() {
var getDevicesRequest = $.ajax({
url: "api/devices/all/",
method: "GET",
contentType: "application/json"
});
getDevicesRequest.done(function (data) {
updateDevicesTable(JSON.parse(data));
});
getDevicesRequest.fail(function (jqXHR, textStatus) {
var err = jqXHR;
alert("Request failed: " + textStatus);
});
}
function updateDevicesTable(data) {
devices = data.data.device;
if (devices.length > 0) {
clearTable('devicesTable');
for (var i = 0; i < devices.length; i++) {
var deviceIdentifier = devices[i].deviceIdentifier;
var deviceName = devices[i].name;
var deviceType = devices[i].type;
$('#devicesTable tbody').append(
"<tr class='border-top'><th scope='row'>" + deviceIdentifier + "</th>" +
"<td>" + deviceName + "</td>" +
"<td>" + deviceType + "</td>" +
"<td class='float-right border-top '>" +
"<input type='hidden' name='deviceType' value='" + deviceType + "' >" +
"<button class='btn-black-action' name='deviceId' value='" + deviceIdentifier + "'>" +
"<i class='fw fw-view padding-right'></i>View</button>" +
"<button class='btn-black-action' name='deviceId' value='" + deviceIdentifier + "'>" +
"<i class='fw fw-edit padding-right'></i>Edit</button>" +
"<button class='btn-black-action' name='deviceId' value='" + deviceIdentifier + "'>" +
"<i class='fw fw-delete padding-right'></i>Remove</button>" +
"</td></tr>");
}
}
}
function clearTable(tableId) {
$('#' + tableId + ' tbody > tr').remove();
}
$(document).ready(function () {
getAllDevices();
});

@ -0,0 +1,117 @@
{{#zone "topCss"}}
<!--<link href="{{self.publicURL}}/css/nv.d3.css" rel="stylesheet"/>-->
<link href="{{self.publicURL}}/css/daterangepicker.css" rel="stylesheet"/>
<link href="{{self.publicURL}}/css/graph.css" rel="stylesheet"/>
<link href="{{self.publicURL}}/css/lines.css" rel="stylesheet"/>
<!-- -->
<!--<script src="{{self.publicURL}}/js/d3.min.js"></script>-->
<!--<script src="{{self.publicURL}}/js/nv.d3.js"></script>-->
<script src="{{self.publicURL}}/js/Chart.min.js"></script>
<script src="{{self.publicURL}}/js/stream_layers.js"></script>
<script src="{{self.publicURL}}/js/moment.min.js"></script>
<script src="{{self.publicURL}}/js/jquery.daterangepicker.js"></script>
<script src="{{self.publicURL}}/js/d3.v3.js"></script>
<script src="{{self.publicURL}}/js/rickshaw.min.js"></script>
{{/zone}}
{{#zone "main"}}
<div class="container container-bg white-bg">
<div class=" margin-top-double">
<div class="row row padding-top-double padding-bottom-double margin-bottom-double ">
<div class="col-lg-12 margin-top-double">
<h1 class="grey ">Device Statistics</h1>
<hr>
</div>
</div>
<div id="rangeSliderWrapper" class="pull-right" style="width: 550px;">
<div class="row-fluid">
<div class="span12">
<div id="dateRangePickerContainer">
<div class="btn-group" role="group">
<button id="hour-btn" type="button"
class="btn btn-default date-range">Hour
</button>
<button id="today-btn" type="button"
class="btn btn-default date-range">Day
</button>
<button id="week-btn" type="button"
class="btn btn-default date-range">Week
</button>
<button id="month-btn" type="button"
class="btn btn-default date-range">Month
</button>
<button id="date-range" type="button"
class="btn btn-default date-range last-child"
data-toggle="popup"
title="Click to set custom date range"></button>
</div>
<span class="add-on-cal"><i style="margin-right:0px;"
class="icon-calendar"></i></span>
</div>
</div>
</div>
</div>
<div class="clear"></div>
<div class="row margin-double">
<div>
<h2 class="grey ">Temperature</h2>
<hr>
<div id="canvas-wrapper1">No data available...</div>
</div>
<hr>
</div>
<div class="row margin-double">
<div>
<h2 class="grey ">Light</h2>
<hr>
<div id="canvas-wrapper2">No data available...</div>
</div>
<hr>
</div>
<div class="row margin-double">
<div>
<h2 class="grey ">Motion</h2>
<hr>
<div id="canvas-wrapper3">No data available...</div>
</div>
<hr>
</div>
<div class="row margin-double">
<div>
<h2 class="grey ">Sonar</h2>
<hr>
<div id="canvas-wrapper4">No data available...</div>
</div>
<hr>
</div>
<div class="row margin-double">
<div>
<h2 class="grey ">Fan Status</h2>
<hr>
<div id="canvas-wrapper5">No data available...</div>
</div>
<hr>
</div>
<div class="row margin-double">
<div>
<h2 class="grey ">Bulb Status</h2>
<hr>
<div id="canvas-wrapper6">No data available...</div>
</div>
<hr>
</div>
</div>
</div>
{{/zone}}
{{#zone "bottomJs"}}
<script src="{{self.publicURL}}/js/moment.min.js"></script>
<script src="{{self.publicURL}}/js/graph_util.js"></script>
<script src="{{self.publicURL}}/js/jquery.daterangepicker.js"></script>
<script src="{{self.publicURL}}/js/bulb.js"></script>
<script src="{{self.publicURL}}/js/graphs/fan_graph.js"></script>
<script src="{{self.publicURL}}/js/graphs/bulb_graph.js"></script>
<script src="{{self.publicURL}}/js/graphs/temperature_graph.js"></script>
<script src="{{self.publicURL}}/js/graphs/light_graph.js"></script>
<script src="{{self.publicURL}}/js/graphs/motion_graph.js"></script>
<script src="{{self.publicURL}}/js/graphs/sonar_graph.js"></script>
{{/zone}}

@ -0,0 +1,4 @@
function onRequest(context){
context.sketchPath = "api/device/sketch";
return context;
}

@ -0,0 +1,331 @@
.date-picker {
width: 170px;
height: 25px;
padding: 0;
border: 0;
line-height: 25px;
padding-left: 10px;
font-size: 12px;
font-family: Arial;
font-weight: bold;
cursor: pointer;
color: #303030;
position: relative;
z-index: 2;
}
.date-picker-wrapper {
position: absolute;
z-index: 1;
border: 1px solid #bfbfbf;
background-color: #efefef;
width: 448px;
padding: 5px 12px;
font-size: 12px;
line-height: 20px;
color: #aaa;
font-family: Arial;
box-shadow: 3px 3px 10px rgba(0, 0, 0, 0.5);
}
.date-picker-wrapper.single-date {
width: auto;
}
.date-picker-wrapper.no-shortcuts {
padding-bottom: 12px;
}
.date-picker-wrapper .footer {
display: none;
font-size: 11px;
padding-top: 3px;
}
.date-picker-wrapper b {
color: #666;
font-weight: 700;
}
.date-picker-wrapper a {
color: rgb(107, 180, 214);
text-decoration: underline;
}
.date-picker-wrapper .month-wrapper {
border: 1px solid #bfbfbf;
border-radius: 3px;
background-color: #fff;
padding: 5px;
cursor: default;
position: relative;
_overflow: hidden;
}
.date-picker-wrapper .month-wrapper table {
width: 190px;
float: left;
}
.date-picker-wrapper .month-wrapper table.month2 {
width: 190px;
float: right;
}
.date-picker-wrapper .month-wrapper table th,
.date-picker-wrapper .month-wrapper table td {
vertical-align: middle;
text-align: center;
line-height: 14px;
margin: 0px;
padding: 0px;
}
.date-picker-wrapper .month-wrapper table .day {
height: 19px;
line-height: 19px;
font-size: 12px;
margin-bottom: 1px;
color: #999;
cursor: default;
}
.date-picker-wrapper .month-wrapper table div.day.lastMonth,
.date-picker-wrapper .month-wrapper table div.day.nextMonth {
color: #999;
cursor: default;
}
.date-picker-wrapper .month-wrapper table .day.checked {
background-color: rgb(156, 219, 247);
}
.date-picker-wrapper .month-wrapper table .week-name {
height: 20px;
line-height: 20px;
font-weight: 100;
}
.date-picker-wrapper .month-wrapper table .day.has-tooltip {
cursor: help !important;
}
.date-picker-wrapper .month-wrapper table .day.toMonth.valid {
color: #333;
cursor: pointer;
}
.date-picker-wrapper .month-wrapper table .day.real-today {
background-color: rgb(255, 230, 132);
}
.date-picker-wrapper .month-wrapper table .day.real-today.checked {
background-color: rgb(112, 204, 213);
}
.date-picker-wrapper table .caption {
height: 40px;
}
.date-picker-wrapper table .caption .next,
.date-picker-wrapper table .caption .prev {
padding: 0 5px;
cursor: pointer;
}
.date-picker-wrapper table .caption .next:hover,
.date-picker-wrapper table .caption .prev:hover {
background-color: #ccc;
color: white;
}
.date-picker-wrapper .gap {
position: absolute;
display: none;
top: 0px;
left: 204px;
z-index: 1;
width: 15px;
height: 100%;
background-color: red;
font-size: 0;
line-height: 0;
}
.date-picker-wrapper .gap .gap-lines {
height: 100%;
overflow: hidden;
}
.date-picker-wrapper .gap .gap-line {
height: 15px;
width: 15px;
position: relative;
}
.date-picker-wrapper .gap .gap-line .gap-1 {
z-index: 1;
height: 0;
border-left: 8px solid white;
border-top: 8px solid #eee;
border-bottom: 8px solid #eee;
}
.date-picker-wrapper .gap .gap-line .gap-2 {
position: absolute;
right: 0;
top: 0px;
z-index: 2;
height: 0;
border-left: 8px solid transparent;
border-top: 8px solid white;
}
.date-picker-wrapper .gap .gap-line .gap-3 {
position: absolute;
right: 0;
top: 8px;
z-index: 2;
height: 0;
border-left: 8px solid transparent;
border-bottom: 8px solid white;
}
.date-picker-wrapper .gap .gap-top-mask {
width: 6px;
height: 1px;
position: absolute;
top: -1px;
left: 1px;
background-color: #eee;
z-index: 3;
}
.date-picker-wrapper .gap .gap-bottom-mask {
width: 6px;
height: 1px;
position: absolute;
bottom: -1px;
left: 7px;
background-color: #eee;
z-index: 3;
}
.date-picker-wrapper .selected-days {
display: none;
}
.date-picker-wrapper .drp_top-bar {
line-height: 40px;
height: 40px;
position: relative;
}
.date-picker-wrapper .drp_top-bar .error-top {
display: none;
}
.date-picker-wrapper .drp_top-bar .normal-top {
display: none;
}
.date-picker-wrapper .drp_top-bar .default-top {
display: block;
}
.date-picker-wrapper .drp_top-bar.error .default-top {
display: none;
}
.date-picker-wrapper .drp_top-bar.error .error-top {
display: block;
color: red;
}
.date-picker-wrapper .drp_top-bar.normal .default-top {
display: none;
}
.date-picker-wrapper .drp_top-bar.normal .normal-top {
display: block;
}
.date-picker-wrapper .drp_top-bar .apply-btn {
position: absolute;
right: 0px;
top: 6px;
padding: 3px 5px;
margin: 0;
font-size: 12px;
border-radius: 4px;
cursor: pointer;
color: #d9eef7;
border: solid 1px #0076a3;
background: #0095cd;
background: -webkit-gradient(linear, left top, left bottom, from(#00adee), to(#0078a5));
background: -moz-linear-gradient(top, #00adee, #0078a5);
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#00adee', endColorstr='#0078a5');
color: white;
}
.date-picker-wrapper .drp_top-bar .apply-btn.disabled {
pointer-events: none;
color: #606060;
border: solid 1px #b7b7b7;
background: #fff;
background: -webkit-gradient(linear, left top, left bottom, from(#fff), to(#ededed));
background: -moz-linear-gradient(top, #fff, #ededed);
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#ededed');
}
/*time styling*/
.time {
position: relative;
}
.time input[type=range] {
vertical-align: middle;
}
.time1, .time2 {
width: 180px;
padding: 0 5px;
text-align: center;
}
.time1 {
float: left;
}
.time2 {
float: right;
}
.hour, .minute {
text-align: left;
}
.hide {
display: none;
}
input.hour-range, input.minute-range {
width: 150px;
}
#dateRangePickerContainer .date-range, #dateRangePickerContainer .input-append {
background: none !important;
}
#date-range{
padding-right:30px;
width:300px;
height:100%;
display:inline-block;
}
#dateRangePickerContainer{
float:right;
margin-top:-6px;
}

@ -0,0 +1,197 @@
/* graph */
.rickshaw_graph {
position: relative;
}
.rickshaw_graph svg {
display: block;
overflow: hidden;
}
/* ticks */
.rickshaw_graph .x_tick {
position: absolute;
top: 0;
bottom: 0;
width: 0px;
border-left: 1px dotted rgba(0, 0, 0, 0.2);
pointer-events: none;
}
.rickshaw_graph .x_tick .title {
position: absolute;
font-size: 12px;
font-family: Arial, sans-serif;
opacity: 0.5;
white-space: nowrap;
margin-left: 3px;
bottom: 1px;
}
/* annotations */
.rickshaw_annotation_timeline {
height: 1px;
border-top: 1px solid #e0e0e0;
margin-top: 10px;
position: relative;
}
.rickshaw_annotation_timeline .annotation {
position: absolute;
height: 6px;
width: 6px;
margin-left: -2px;
top: -3px;
border-radius: 5px;
background-color: rgba(0, 0, 0, 0.25);
}
.rickshaw_graph .annotation_line {
position: absolute;
top: 0;
bottom: -6px;
width: 0px;
border-left: 2px solid rgba(0, 0, 0, 0.3);
display: none;
}
.rickshaw_graph .annotation_line.active {
display: block;
}
.rickshaw_graph .annotation_range {
background: rgba(0, 0, 0, 0.1);
display: none;
position: absolute;
top: 0;
bottom: -6px;
}
.rickshaw_graph .annotation_range.active {
display: block;
}
.rickshaw_graph .annotation_range.active.offscreen {
display: none;
}
.rickshaw_annotation_timeline .annotation .content {
background: white;
color: black;
opacity: 0.9;
padding: 5px 5px;
box-shadow: 0 0 2px rgba(0, 0, 0, 0.8);
border-radius: 3px;
position: relative;
z-index: 20;
font-size: 12px;
padding: 6px 8px 8px;
top: 18px;
left: -11px;
width: 160px;
display: none;
cursor: pointer;
}
.rickshaw_annotation_timeline .annotation .content:before {
content: "\25b2";
position: absolute;
top: -11px;
color: white;
text-shadow: 0 -1px 1px rgba(0, 0, 0, 0.8);
}
.rickshaw_annotation_timeline .annotation.active,
.rickshaw_annotation_timeline .annotation:hover {
background-color: rgba(0, 0, 0, 0.8);
cursor: none;
}
.rickshaw_annotation_timeline .annotation .content:hover {
z-index: 50;
}
.rickshaw_annotation_timeline .annotation.active .content {
display: block;
}
.rickshaw_annotation_timeline .annotation:hover .content {
display: block;
z-index: 50;
}
.rickshaw_graph .y_axis,
.rickshaw_graph .x_axis_d3 {
fill: none;
}
.rickshaw_graph .y_ticks .tick line,
.rickshaw_graph .x_ticks_d3 .tick {
stroke: rgba(0, 0, 0, 0.16);
stroke-width: 2px;
shape-rendering: crisp-edges;
pointer-events: none;
}
.rickshaw_graph .y_grid .tick,
.rickshaw_graph .x_grid_d3 .tick {
z-index: -1;
stroke: rgba(0, 0, 0, 0.20);
stroke-width: 1px;
stroke-dasharray: 1 1;
}
.rickshaw_graph .y_grid .tick[data-y-value="0"] {
stroke-dasharray: 1 0;
}
.rickshaw_graph .y_grid path,
.rickshaw_graph .x_grid_d3 path {
fill: none;
stroke: none;
}
.rickshaw_graph .y_ticks path,
.rickshaw_graph .x_ticks_d3 path {
fill: none;
stroke: #808080;
}
.rickshaw_graph .y_ticks text,
.rickshaw_graph .x_ticks_d3 text {
opacity: 0.5;
font-size: 12px;
pointer-events: none;
}
.rickshaw_graph .x_tick.glow .title,
.rickshaw_graph .y_ticks.glow text {
fill: black;
color: black;
text-shadow:
-1px 1px 0 rgba(255, 255, 255, 0.1),
1px -1px 0 rgba(255, 255, 255, 0.1),
1px 1px 0 rgba(255, 255, 255, 0.1),
0px 1px 0 rgba(255, 255, 255, 0.1),
0px -1px 0 rgba(255, 255, 255, 0.1),
1px 0px 0 rgba(255, 255, 255, 0.1),
-1px 0px 0 rgba(255, 255, 255, 0.1),
-1px -1px 0 rgba(255, 255, 255, 0.1);
}
.rickshaw_graph .x_tick.inverse .title,
.rickshaw_graph .y_ticks.inverse text {
fill: white;
color: white;
text-shadow:
-1px 1px 0 rgba(0, 0, 0, 0.8),
1px -1px 0 rgba(0, 0, 0, 0.8),
1px 1px 0 rgba(0, 0, 0, 0.8),
0px 1px 0 rgba(0, 0, 0, 0.8),
0px -1px 0 rgba(0, 0, 0, 0.8),
1px 0px 0 rgba(0, 0, 0, 0.8),
-1px 0px 0 rgba(0, 0, 0, 0.8),
-1px -1px 0 rgba(0, 0, 0, 0.8);
}
.custom_rickshaw_graph {
position: relative;
left: 40px;
}
.custom_y_axis {
position: absolute;
width: 40px;
}
.custom_slider {
left: 40px;
}
.custom_x_axis {
position: relative;
left: 40px;
height: 40px;
}

@ -0,0 +1,18 @@
#chart {
display: inline-block;
}
#legend {
display: inline-block;
position: relative;
left: 8px;
}
#legend_container {
position: absolute;
right: 0;
bottom: 26px;
width: 0;
}
#chart_container {
float: left;
position: relative;
}

@ -0,0 +1,641 @@
/* nvd3 version 1.8.1 (https://github.com/novus/nvd3) 2015-06-17 */
.nvd3 .nv-axis {
pointer-events:none;
opacity: 1;
}
.nvd3 .nv-axis path {
fill: none;
stroke: #000;
stroke-opacity: .75;
shape-rendering: crispEdges;
}
.nvd3 .nv-axis path.domain {
stroke-opacity: .75;
}
.nvd3 .nv-axis.nv-x path.domain {
stroke-opacity: 0;
}
.nvd3 .nv-axis line {
fill: none;
stroke: #e5e5e5;
shape-rendering: crispEdges;
}
.nvd3 .nv-axis .zero line,
/*this selector may not be necessary*/ .nvd3 .nv-axis line.zero {
stroke-opacity: .75;
}
.nvd3 .nv-axis .nv-axisMaxMin text {
font-weight: bold;
}
.nvd3 .x .nv-axis .nv-axisMaxMin text,
.nvd3 .x2 .nv-axis .nv-axisMaxMin text,
.nvd3 .x3 .nv-axis .nv-axisMaxMin text {
text-anchor: middle
}
.nvd3 .nv-axis.nv-disabled {
opacity: 0;
}
.nvd3 .nv-bars rect {
fill-opacity: .75;
transition: fill-opacity 250ms linear;
-moz-transition: fill-opacity 250ms linear;
-webkit-transition: fill-opacity 250ms linear;
}
.nvd3 .nv-bars rect.hover {
fill-opacity: 1;
}
.nvd3 .nv-bars .hover rect {
fill: lightblue;
}
.nvd3 .nv-bars text {
fill: rgba(0,0,0,0);
}
.nvd3 .nv-bars .hover text {
fill: rgba(0,0,0,1);
}
.nvd3 .nv-multibar .nv-groups rect,
.nvd3 .nv-multibarHorizontal .nv-groups rect,
.nvd3 .nv-discretebar .nv-groups rect {
stroke-opacity: 0;
transition: fill-opacity 250ms linear;
-moz-transition: fill-opacity 250ms linear;
-webkit-transition: fill-opacity 250ms linear;
}
.nvd3 .nv-multibar .nv-groups rect:hover,
.nvd3 .nv-multibarHorizontal .nv-groups rect:hover,
.nvd3 .nv-candlestickBar .nv-ticks rect:hover,
.nvd3 .nv-discretebar .nv-groups rect:hover {
fill-opacity: 1;
}
.nvd3 .nv-discretebar .nv-groups text,
.nvd3 .nv-multibarHorizontal .nv-groups text {
font-weight: bold;
fill: rgba(0,0,0,1);
stroke: rgba(0,0,0,0);
}
/* boxplot CSS */
.nvd3 .nv-boxplot circle {
fill-opacity: 0.5;
}
.nvd3 .nv-boxplot circle:hover {
fill-opacity: 1;
}
.nvd3 .nv-boxplot rect:hover {
fill-opacity: 1;
}
.nvd3 line.nv-boxplot-median {
stroke: black;
}
.nv-boxplot-tick:hover {
stroke-width: 2.5px;
}
/* bullet */
.nvd3.nv-bullet { font: 10px sans-serif; }
.nvd3.nv-bullet .nv-measure { fill-opacity: .8; }
.nvd3.nv-bullet .nv-measure:hover { fill-opacity: 1; }
.nvd3.nv-bullet .nv-marker { stroke: #000; stroke-width: 2px; }
.nvd3.nv-bullet .nv-markerTriangle { stroke: #000; fill: #fff; stroke-width: 1.5px; }
.nvd3.nv-bullet .nv-tick line { stroke: #666; stroke-width: .5px; }
.nvd3.nv-bullet .nv-range.nv-s0 { fill: #eee; }
.nvd3.nv-bullet .nv-range.nv-s1 { fill: #ddd; }
.nvd3.nv-bullet .nv-range.nv-s2 { fill: #ccc; }
.nvd3.nv-bullet .nv-title { font-size: 14px; font-weight: bold; }
.nvd3.nv-bullet .nv-subtitle { fill: #999; }
.nvd3.nv-bullet .nv-range {
fill: #bababa;
fill-opacity: .4;
}
.nvd3.nv-bullet .nv-range:hover {
fill-opacity: .7;
}
.nvd3.nv-candlestickBar .nv-ticks .nv-tick {
stroke-width: 1px;
}
.nvd3.nv-candlestickBar .nv-ticks .nv-tick.hover {
stroke-width: 2px;
}
.nvd3.nv-candlestickBar .nv-ticks .nv-tick.positive rect {
stroke: #2ca02c;
fill: #2ca02c;
}
.nvd3.nv-candlestickBar .nv-ticks .nv-tick.negative rect {
stroke: #d62728;
fill: #d62728;
}
.with-transitions .nv-candlestickBar .nv-ticks .nv-tick {
transition: stroke-width 250ms linear, stroke-opacity 250ms linear;
-moz-transition: stroke-width 250ms linear, stroke-opacity 250ms linear;
-webkit-transition: stroke-width 250ms linear, stroke-opacity 250ms linear;
}
.nvd3.nv-candlestickBar .nv-ticks line {
stroke: #333;
}
.nvd3 .nv-legend .nv-disabled rect {
/*fill-opacity: 0;*/
}
.nvd3 .nv-check-box .nv-box {
fill-opacity:0;
stroke-width:2;
}
.nvd3 .nv-check-box .nv-check {
fill-opacity:0;
stroke-width:4;
}
.nvd3 .nv-series.nv-disabled .nv-check-box .nv-check {
fill-opacity:0;
stroke-opacity:0;
}
.nvd3 .nv-controlsWrap .nv-legend .nv-check-box .nv-check {
opacity: 0;
}
/* line plus bar */
.nvd3.nv-linePlusBar .nv-bar rect {
fill-opacity: .75;
}
.nvd3.nv-linePlusBar .nv-bar rect:hover {
fill-opacity: 1;
}
.nvd3 .nv-groups path.nv-line {
fill: none;
}
.nvd3 .nv-groups path.nv-area {
stroke: none;
}
.nvd3.nv-line .nvd3.nv-scatter .nv-groups .nv-point {
fill-opacity: 0;
stroke-opacity: 0;
}
.nvd3.nv-scatter.nv-single-point .nv-groups .nv-point {
fill-opacity: .5 !important;
stroke-opacity: .5 !important;
}
.with-transitions .nvd3 .nv-groups .nv-point {
transition: stroke-width 250ms linear, stroke-opacity 250ms linear;
-moz-transition: stroke-width 250ms linear, stroke-opacity 250ms linear;
-webkit-transition: stroke-width 250ms linear, stroke-opacity 250ms linear;
}
.nvd3.nv-scatter .nv-groups .nv-point.hover,
.nvd3 .nv-groups .nv-point.hover {
stroke-width: 7px;
fill-opacity: .95 !important;
stroke-opacity: .95 !important;
}
.nvd3 .nv-point-paths path {
stroke: #aaa;
stroke-opacity: 0;
fill: #eee;
fill-opacity: 0;
}
.nvd3 .nv-indexLine {
cursor: ew-resize;
}
/********************
* SVG CSS
*/
/********************
Default CSS for an svg element nvd3 used
*/
svg.nvd3-svg {
-webkit-touch-callout: none;
-webkit-user-select: none;
-khtml-user-select: none;
-ms-user-select: none;
-moz-user-select: none;
user-select: none;
display: block;
width:100%;
height:100%;
}
/********************
Box shadow and border radius styling
*/
.nvtooltip.with-3d-shadow, .with-3d-shadow .nvtooltip {
-moz-box-shadow: 0 5px 10px rgba(0,0,0,.2);
-webkit-box-shadow: 0 5px 10px rgba(0,0,0,.2);
box-shadow: 0 5px 10px rgba(0,0,0,.2);
-webkit-border-radius: 5px;
-moz-border-radius: 5px;
border-radius: 5px;
}
.nvd3 text {
font: normal 12px Arial;
}
.nvd3 .title {
font: bold 14px Arial;
}
.nvd3 .nv-background {
fill: white;
fill-opacity: 0;
}
.nvd3.nv-noData {
font-size: 18px;
font-weight: bold;
}
/**********
* Brush
*/
.nv-brush .extent {
fill-opacity: .125;
shape-rendering: crispEdges;
}
.nv-brush .resize path {
fill: #eee;
stroke: #666;
}
/**********
* Legend
*/
.nvd3 .nv-legend .nv-series {
cursor: pointer;
}
.nvd3 .nv-legend .nv-disabled circle {
fill-opacity: 0;
}
/* focus */
.nvd3 .nv-brush .extent {
fill-opacity: 0 !important;
}
.nvd3 .nv-brushBackground rect {
stroke: #000;
stroke-width: .4;
fill: #fff;
fill-opacity: .7;
}
.nvd3.nv-ohlcBar .nv-ticks .nv-tick {
stroke-width: 1px;
}
.nvd3.nv-ohlcBar .nv-ticks .nv-tick.hover {
stroke-width: 2px;
}
.nvd3.nv-ohlcBar .nv-ticks .nv-tick.positive {
stroke: #2ca02c;
}
.nvd3.nv-ohlcBar .nv-ticks .nv-tick.negative {
stroke: #d62728;
}
.nvd3 .background path {
fill: none;
stroke: #EEE;
stroke-opacity: .4;
shape-rendering: crispEdges;
}
.nvd3 .foreground path {
fill: none;
stroke-opacity: .7;
}
.nvd3 .nv-parallelCoordinates-brush .extent
{
fill: #fff;
fill-opacity: .6;
stroke: gray;
shape-rendering: crispEdges;
}
.nvd3 .nv-parallelCoordinates .hover {
fill-opacity: 1;
stroke-width: 3px;
}
.nvd3 .missingValuesline line {
fill: none;
stroke: black;
stroke-width: 1;
stroke-opacity: 1;
stroke-dasharray: 5, 5;
}
.nvd3.nv-pie path {
stroke-opacity: 0;
transition: fill-opacity 250ms linear, stroke-width 250ms linear, stroke-opacity 250ms linear;
-moz-transition: fill-opacity 250ms linear, stroke-width 250ms linear, stroke-opacity 250ms linear;
-webkit-transition: fill-opacity 250ms linear, stroke-width 250ms linear, stroke-opacity 250ms linear;
}
.nvd3.nv-pie .nv-pie-title {
font-size: 24px;
fill: rgba(19, 196, 249, 0.59);
}
.nvd3.nv-pie .nv-slice text {
stroke: #000;
stroke-width: 0;
}
.nvd3.nv-pie path {
stroke: #fff;
stroke-width: 1px;
stroke-opacity: 1;
}
.nvd3.nv-pie .hover path {
fill-opacity: .7;
}
.nvd3.nv-pie .nv-label {
pointer-events: none;
}
.nvd3.nv-pie .nv-label rect {
fill-opacity: 0;
stroke-opacity: 0;
}
/* scatter */
.nvd3 .nv-groups .nv-point.hover {
stroke-width: 20px;
stroke-opacity: .5;
}
.nvd3 .nv-scatter .nv-point.hover {
fill-opacity: 1;
}
.nv-noninteractive {
pointer-events: none;
}
.nv-distx, .nv-disty {
pointer-events: none;
}
/* sparkline */
.nvd3.nv-sparkline path {
fill: none;
}
.nvd3.nv-sparklineplus g.nv-hoverValue {
pointer-events: none;
}
.nvd3.nv-sparklineplus .nv-hoverValue line {
stroke: #333;
stroke-width: 1.5px;
}
.nvd3.nv-sparklineplus,
.nvd3.nv-sparklineplus g {
pointer-events: all;
}
.nvd3 .nv-hoverArea {
fill-opacity: 0;
stroke-opacity: 0;
}
.nvd3.nv-sparklineplus .nv-xValue,
.nvd3.nv-sparklineplus .nv-yValue {
stroke-width: 0;
font-size: .9em;
font-weight: normal;
}
.nvd3.nv-sparklineplus .nv-yValue {
stroke: #f66;
}
.nvd3.nv-sparklineplus .nv-maxValue {
stroke: #2ca02c;
fill: #2ca02c;
}
.nvd3.nv-sparklineplus .nv-minValue {
stroke: #d62728;
fill: #d62728;
}
.nvd3.nv-sparklineplus .nv-currentValue {
font-weight: bold;
font-size: 1.1em;
}
/* stacked area */
.nvd3.nv-stackedarea path.nv-area {
fill-opacity: .7;
stroke-opacity: 0;
transition: fill-opacity 250ms linear, stroke-opacity 250ms linear;
-moz-transition: fill-opacity 250ms linear, stroke-opacity 250ms linear;
-webkit-transition: fill-opacity 250ms linear, stroke-opacity 250ms linear;
}
.nvd3.nv-stackedarea path.nv-area.hover {
fill-opacity: .9;
}
.nvd3.nv-stackedarea .nv-groups .nv-point {
stroke-opacity: 0;
fill-opacity: 0;
}
.nvtooltip {
position: absolute;
background-color: rgba(255,255,255,1.0);
color: rgba(0,0,0,1.0);
padding: 1px;
border: 1px solid rgba(0,0,0,.2);
z-index: 10000;
display: block;
font-family: Arial;
font-size: 13px;
text-align: left;
pointer-events: none;
white-space: nowrap;
-webkit-touch-callout: none;
-webkit-user-select: none;
-khtml-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
}
.nvtooltip {
background: rgba(255,255,255, 0.8);
border: 1px solid rgba(0,0,0,0.5);
border-radius: 4px;
}
/*Give tooltips that old fade in transition by
putting a "with-transitions" class on the container div.
*/
.nvtooltip.with-transitions, .with-transitions .nvtooltip {
transition: opacity 50ms linear;
-moz-transition: opacity 50ms linear;
-webkit-transition: opacity 50ms linear;
transition-delay: 200ms;
-moz-transition-delay: 200ms;
-webkit-transition-delay: 200ms;
}
.nvtooltip.x-nvtooltip,
.nvtooltip.y-nvtooltip {
padding: 8px;
}
.nvtooltip h3 {
margin: 0;
padding: 4px 14px;
line-height: 18px;
font-weight: normal;
background-color: rgba(247,247,247,0.75);
color: rgba(0,0,0,1.0);
text-align: center;
border-bottom: 1px solid #ebebeb;
-webkit-border-radius: 5px 5px 0 0;
-moz-border-radius: 5px 5px 0 0;
border-radius: 5px 5px 0 0;
}
.nvtooltip p {
margin: 0;
padding: 5px 14px;
text-align: center;
}
.nvtooltip span {
display: inline-block;
margin: 2px 0;
}
.nvtooltip table {
margin: 6px;
border-spacing:0;
}
.nvtooltip table td {
padding: 2px 9px 2px 0;
vertical-align: middle;
}
.nvtooltip table td.key {
font-weight:normal;
}
.nvtooltip table td.value {
text-align: right;
font-weight: bold;
}
.nvtooltip table tr.highlight td {
padding: 1px 9px 1px 0;
border-bottom-style: solid;
border-bottom-width: 1px;
border-top-style: solid;
border-top-width: 1px;
}
.nvtooltip table td.legend-color-guide div {
width: 8px;
height: 8px;
vertical-align: middle;
}
.nvtooltip table td.legend-color-guide div {
width: 12px;
height: 12px;
border: 1px solid #999;
}
.nvtooltip .footer {
padding: 3px;
text-align: center;
}
.nvtooltip-pending-removal {
pointer-events: none;
display: none;
}
/****
Interactive Layer
*/
.nvd3 .nv-interactiveGuideLine {
pointer-events:none;
}
.nvd3 line.nv-guideline {
stroke: #ccc;
}

File diff suppressed because one or more lines are too long

@ -0,0 +1,10 @@
function changeImage() {
var image = document.getElementById('myImage');
if (image.src.match("bulb-on")) {
image.src = "/iot/public/mydevice/images/bulb-off.png";
} else {
image.src = "/iot/public/mydevice/images/bulb-on.png";
}
}

File diff suppressed because one or more lines are too long

@ -0,0 +1,245 @@
var fromDate;
var toDate;
// create a custom bar renderer that has no gaps
Rickshaw.Graph.Renderer.BarNoGap = Rickshaw.Class.create(Rickshaw.Graph.Renderer.Bar, {
name: 'bar_no_gap',
barWidth: function (series) {
var frequentInterval = this._frequentInterval(series.stack);
var barWidth = this.graph.x(series.stack[0].x + frequentInterval.magnitude * 1);
return barWidth;
}
});
var currentDay = new Date();
var startDate = new Date(currentDay.getTime() - (60 * 60 * 24 * 100));
var endDate = new Date(currentDay.getTime());
var configObject = {
startOfWeek: 'monday',
separator: ' to ',
format: 'YYYY-MM-DD HH:mm',
autoClose: false,
time: {
enabled: true
},
shortcuts: 'hide',
endDate: currentDay,
getValue: function () {
return this.value;
},
setValue: function (s) {
this.value = s;
}
};
var DateRange = convertDate(startDate) + " " + configObject.separator + " " + convertDate(endDate);
$(document).ready(function () {
$('#date-range').dateRangePicker(configObject)
.bind('datepicker-apply', function (event, dateRange) {
$(this).addClass('active');
$(this).siblings().removeClass('active');
fromDate = dateRange.date1 != "Invalid Date" ? dateRange.date1.getTime() / 1000 : null;
toDate = dateRange.date2 != "Invalid Date" ? dateRange.date2.getTime() / 1000 : null;
getStats(fromDate, toDate);
}
);
});
$(document).ready(function () {
$('#date-range').html(DateRange);
$('#date-range').trigger('datepicker-apply',
{
'value': DateRange,
'date1': startDate,
'date2': endDate
});
});
//day picker
$('#today-btn').on('click', function () {
getDateTime(currentDay.getTime() - 86400000, currentDay.getTime());
});
//hour picker
$('#hour-btn').on('click', function () {
getDateTime(currentDay.getTime() - 3600000, currentDay.getTime());
})
//week picker
$('#week-btn').on('click', function () {
getDateTime(currentDay.getTime() - 604800000, currentDay.getTime());
})
//month picker
$('#month-btn').on('click', function () {
getDateTime(currentDay.getTime() - (604800000 * 4), currentDay.getTime());
});
$('body').on('click', '.btn-group button', function (e) {
$(this).addClass('active');
$(this).siblings().removeClass('active');
});
function getDateTime(from, to) {
startDate = new Date(from);
endDate = new Date(to);
DateRange = convertDate(startDate) + " " + configObject.separator + " " + convertDate(endDate);
console.log(DateRange);
$('#date-range').html(DateRange);
$('#date-range').trigger('datepicker-apply',
{
'value': DateRange,
'date1': startDate,
'date2': endDate
}
);
getStats(from / 1000, to / 1000);
}
function getStats(from, to) {
var deviceId = getUrlParameter('deviceId');
var deviceType = getUrlParameter('deviceType');
var requestData = new Object();
requestData['deviceId'] = deviceId;
requestData['deviceType'] = deviceType;
if (from) {
requestData['from'] = from;
}
if (to) {
requestData['to'] = to;
}
var getStatsRequest = $.ajax({
url: "../api/stats",
method: "GET",
data: requestData
});
getStatsRequest.done(function (stats) {
updateGraphs(JSON.parse(stats));
});
getStatsRequest.fail(function (jqXHR, textStatus) {
alert("Request failed: " + textStatus);
});
}
function getUrlParameter(paramName) {
var pageURL = window.location.search.substring(1);
var urlVariables = pageURL.split('&');
for (var i = 0; i < urlVariables.length; i++) {
var parameterName = urlVariables[i].split('=');
if (parameterName[0] == paramName) {
return parameterName[1];
}
}
}
function updateGraphs(stats) {
console.log(stats);
var temperatureData = stats['temperatureData'];
updateTemperatureGraph(convertStatsToGraphData(temperatureData));
var lightData = stats['lightData'];
updateLightGraph(convertStatsToGraphData(lightData));
var motionData = stats['motionData'];
updateMotionGraph(convertStatsToGraphData(motionData));
var sonarData = stats['sonarData'];
updateSonarGraph(convertStatsToGraphData(sonarData));
var fanData = stats['fanData'];
updateFanGraph(convertStateStatsToGraphData(fanData));
var bulbData = stats['bulbData'];
updateBulbGraph(convertStateStatsToGraphData(bulbData));
scaleGraphs();
}
function scaleGraphs() {
var sliders = $('.right_handle');
if (sliders.length == 0) {
return;
}
var graphWidth = $('#canvas-wrapper1').width() - 50;
//Scale graphs
var sliderX = graphWidth * 60 * 60 / (toDate - fromDate);
if (sliderX < graphWidth) {
// fake handle move
if (sliderX < 100) {
sliderX = 100;
}
var edown = document.createEvent("HTMLEvents");
edown.initEvent("mousedown", true, true);
edown.clientX = graphWidth;
var emove = document.createEvent("HTMLEvents");
emove.initEvent("mousemove", true, true);
emove.clientX = sliderX;
var eup = document.createEvent("HTMLEvents");
eup.initEvent("mouseup", true, true);
for (var slider in sliders) {
sliders[slider].dispatchEvent(edown);
document.dispatchEvent(emove);
document.dispatchEvent(eup);
}
}
}
function convertStatsToGraphData(stats) {
var graphData = new Array();
if (!stats) {
return graphData;
}
for (var i = 0; i < stats.length; i++) {
graphData.push({x: parseInt(stats[i]['time']) * 1000, y: stats[i]['value']})
}
return graphData;
}
function convertStateStatsToGraphData(stats) {
var graphData = new Array();
if (!stats) {
return graphData;
}
var yValue;
for (var i = 0; i < stats.length; i++) {
yValue = -1;
if (stats[i]['value'].toUpperCase() == 'ON') {
yValue = 1;
} else if (stats[i]['value'].toUpperCase() == 'OFF') {
yValue = 0;
}
graphData.push({x: parseInt(stats[i]['time']) * 1000, y: yValue})
}
return graphData;
}
function convertDate(date) {
var month = date.getMonth() + 1;
var day = date.getDate();
var hour=date.getHours();
var minute=date.getMinutes();
return date.getFullYear() + '-' + (('' + month).length < 2 ? '0' : '')
+ month + '-' + (('' + day).length < 2 ? '0' : '') + day +" "+ (('' + hour).length < 2 ? '0' : '')
+ hour +":"+(('' + minute).length < 2 ? '0' : '')+ minute;
}

@ -0,0 +1,85 @@
function updateBulbGraph(bulbData) {
renderBulbChart(bulbData);
}
function renderBulbChart(chartDataRaw){
var chartWrapperElmId = "#canvas-wrapper6";
var graphWidth = $(chartWrapperElmId).width() - 50;
if (chartDataRaw.length == 0) {
$(chartWrapperElmId).html("No data available...");
return;
}
var chartData = [[], []];
for (var i = 0; i < chartDataRaw.length; i++){
chartData[0].push({x:parseInt(chartDataRaw[i].x), y:parseInt(chartDataRaw[i].y)});
chartData[1].push({x:parseInt(chartDataRaw[i].x), y:Math.abs(parseInt(chartDataRaw[i].y) - 1)});
}
//var i = parseInt(fromDate);
//while (i < parseInt(toDate)) {
// var rnd = Math.round(Math.random());
// chartData[0].push({x: i * 1000, y: rnd});
// chartData[1].push({x: i * 1000, y: Math.abs(rnd - 1)});
// i += 60 * 5;
//}
var chartDiv = "chart6";
var sliderDiv = "slider6";
var x_axis = "x_axis6";
var y_axis = "y_axis6";
$(chartWrapperElmId).html("").html('<div id="' + y_axis + '" class="custom_y_axis"></div><div id="' + chartDiv + '" class="custom_rickshaw_graph"></div><div id="' + x_axis + '" class="custom_x_axis"></div><div id="' + sliderDiv + '" class="custom_slider"></div>');
var graph = new Rickshaw.Graph({
element: document.getElementById(chartDiv),
width: graphWidth,
height: 150,
strokeWidth: 0.5,
renderer: 'bar_no_gap',
xScale: d3.time.scale(),
padding: {top: 0.2, left: 0.02, right: 0.02, bottom: 0},
series: [
{color: '#5E610B', data: chartData[0]},
{color: 'white', data: chartData[1]}
]
});
graph.registerRenderer(new Rickshaw.Graph.Renderer.BarNoGap({graph: graph}));
graph.render();
var xAxis = new Rickshaw.Graph.Axis.X({
graph: graph,
orientation: 'bottom',
element: document.getElementById(x_axis),
tickFormat: graph.x.tickFormat()
});
xAxis.render();
var yAxis = new Rickshaw.Graph.Axis.Y({
graph: graph,
orientation: 'left',
element: document.getElementById(y_axis),
width: 40,
height: 160,
tickFormat: function (y) {
switch (y) {
case 1:
return 'ON';
case 0:
return 'OFF';
default :
return '';
}
}
});
yAxis.render();
var slider = new Rickshaw.Graph.RangeSlider.Preview({
graph: graph,
element: document.getElementById(sliderDiv)
});
}

@ -0,0 +1,84 @@
function updateFanGraph(fanData) {
renderFanChart(fanData);
}
function renderFanChart(chartDataRaw) {
var chartWrapperElmId = "#canvas-wrapper5";
var graphWidth = $(chartWrapperElmId).width() - 50;
if (chartDataRaw.length == 0) {
$(chartWrapperElmId).html("No data available...");
return;
}
var chartData = [[], []];
for (var i = 0; i < chartDataRaw.length; i++){
chartData[0].push({x:parseInt(chartDataRaw[i].x), y:parseInt(chartDataRaw[i].y)});
chartData[1].push({x:parseInt(chartDataRaw[i].x), y:Math.abs(parseInt(chartDataRaw[i].y) - 1)});
}
//var i = parseInt(fromDate);
//while (i < parseInt(toDate)) {
// var rnd = Math.round(Math.random());
// chartData[0].push({x: i * 1000, y: rnd});
// chartData[1].push({x: i * 1000, y: Math.abs(rnd - 1)});
// i += 60 * 5;
//}
var chartDiv = "chart5";
var sliderDiv = "slider5";
var x_axis = "x_axis5";
var y_axis = "y_axis5";
$(chartWrapperElmId).html("").html('<div id="' + y_axis + '" class="custom_y_axis"></div><div id="' + chartDiv + '" class="custom_rickshaw_graph"></div><div id="' + x_axis + '" class="custom_x_axis"></div><div id="' + sliderDiv + '" class="custom_slider"></div>');
var graph = new Rickshaw.Graph({
element: document.getElementById(chartDiv),
width: graphWidth,
height: 150,
strokeWidth: 0.5,
renderer: 'bar_no_gap',
xScale: d3.time.scale(),
padding: {top: 0.2, left: 0.02, right: 0.02, bottom: 0},
series: [
{color: '#2F0B3A', data: chartData[0]},
{color: 'white', data: chartData[1]}
]
});
graph.registerRenderer(new Rickshaw.Graph.Renderer.BarNoGap({graph: graph}));
graph.render();
var xAxis = new Rickshaw.Graph.Axis.X({
graph: graph,
orientation: 'bottom',
element: document.getElementById(x_axis),
tickFormat: graph.x.tickFormat()
});
xAxis.render();
var yAxis = new Rickshaw.Graph.Axis.Y({
graph: graph,
orientation: 'left',
element: document.getElementById(y_axis),
width: 40,
height: 160,
tickFormat: function (y) {
switch (y) {
case 1:
return 'ON';
case 0:
return 'OFF';
default :
return '';
}
}
});
yAxis.render();
var slider = new Rickshaw.Graph.RangeSlider.Preview({
graph: graph,
element: document.getElementById(sliderDiv)
});
}

@ -0,0 +1,85 @@
function updateLightGraph(lightData) {
renderLightChart(lightData);
}
function renderLightChart(chartDataRaw){
var chartWrapperElmId = "#canvas-wrapper2";
var graphWidth = $(chartWrapperElmId).width() - 50;
if (chartDataRaw.length == 0) {
$(chartWrapperElmId).html("No data available...");
return;
}
var chartData = [[], []];
for (var i = 0; i < chartDataRaw.length; i++){
chartData[0].push({x:parseInt(chartDataRaw[i].x), y:parseInt(chartDataRaw[i].y)});
chartData[1].push({x:parseInt(chartDataRaw[i].x), y:Math.abs(parseInt(chartDataRaw[i].y) - 1)});
}
//var i = parseInt(fromDate);
//while (i < parseInt(toDate)) {
// var rnd = Math.round(Math.random());
// chartData[0].push({x: i * 1000, y: rnd});
// chartData[1].push({x: i * 1000, y: Math.abs(rnd - 1)});
// i += 60 * 5;
//}
var chartDiv = "chart2";
var sliderDiv = "slider2";
var x_axis = "x_axis2";
var y_axis = "y_axis2";
$(chartWrapperElmId).html("").html('<div id="' + y_axis + '" class="custom_y_axis"></div><div id="' + chartDiv + '" class="custom_rickshaw_graph"></div><div id="' + x_axis + '" class="custom_x_axis"></div><div id="' + sliderDiv + '" class="custom_slider"></div>');
var graph = new Rickshaw.Graph({
element: document.getElementById(chartDiv),
width: graphWidth,
height: 150,
strokeWidth: 0.5,
renderer: 'bar_no_gap',
xScale: d3.time.scale(),
padding: {top: 0.2, left: 0.02, right: 0.02, bottom: 0},
series: [
{color: 'steelblue', data: chartData[0]},
{color: 'white', data: chartData[1]}
]
});
graph.registerRenderer(new Rickshaw.Graph.Renderer.BarNoGap({graph: graph}));
graph.render();
var xAxis = new Rickshaw.Graph.Axis.X({
graph: graph,
orientation: 'bottom',
element: document.getElementById(x_axis),
tickFormat: graph.x.tickFormat()
});
xAxis.render();
var yAxis = new Rickshaw.Graph.Axis.Y({
graph: graph,
orientation: 'left',
element: document.getElementById(y_axis),
width: 40,
height: 160,
tickFormat: function (y) {
switch (y) {
case 1:
return 'ON';
case 0:
return 'OFF';
default :
return '';
}
}
});
yAxis.render();
var slider = new Rickshaw.Graph.RangeSlider.Preview({
graph: graph,
element: document.getElementById(sliderDiv)
});
}

@ -0,0 +1,70 @@
function updateMotionGraph(motionData) {
renderMotionChart(motionData);
}
function renderMotionChart(chartDataRaw){
var chartWrapperElmId = "#canvas-wrapper3";
var graphWidth = $(chartWrapperElmId).width() - 50;
if (chartDataRaw.length == 0) {
$(chartWrapperElmId).html("No data available...");
return;
}
var chartData = [];
for (var i = 0; i < chartDataRaw.length; i++){
chartData.push({x:parseInt(chartDataRaw[i].x), y:parseInt(chartDataRaw[i].y)});
}
//var i = parseInt(fromDate);
//while (i < parseInt(toDate)){
// var rnd = Math.random() * (30 - 20) + 20;
// chartData.push({x:i * 1000, y:rnd});
// i += 60 * 5;
//}
var chartDiv = "chart3";
var sliderDiv = "slider3";
var x_axis = "x_axis3";
var y_axis = "y_axis3";
$(chartWrapperElmId).html("").html('<div id="' + y_axis + '" class="custom_y_axis"></div><div id="' + chartDiv + '" class="custom_rickshaw_graph"></div><div id="' + x_axis + '" class="custom_x_axis"></div><div id="' + sliderDiv + '" class="custom_slider"></div>');
var graph = new Rickshaw.Graph({
element: document.getElementById(chartDiv),
width: graphWidth,
height: 400,
strokeWidth: 0.5,
renderer: 'line',
xScale: d3.time.scale(),
padding: {top: 0.2, left: 0.02, right: 0.02, bottom: 0},
series:[
{ color: '#2F0B3A', data: chartData }
]
});
graph.render();
var xAxis = new Rickshaw.Graph.Axis.X({
graph: graph,
orientation: 'bottom',
element: document.getElementById(x_axis),
tickFormat: graph.x.tickFormat()
});
xAxis.render();
var yAxis = new Rickshaw.Graph.Axis.Y({
graph: graph,
orientation: 'left',
element: document.getElementById(y_axis),
width: 40,
height: 410
});
yAxis.render();
var slider = new Rickshaw.Graph.RangeSlider.Preview({
graph: graph,
element: document.getElementById(sliderDiv)
});
}

@ -0,0 +1,69 @@
function updateSonarGraph(sonarData) {
renderSonarChart(sonarData);
}
function renderSonarChart(chartDataRaw){
var chartWrapperElmId = "#canvas-wrapper4";
var graphWidth = $(chartWrapperElmId).width() - 50;
if (chartDataRaw.length == 0) {
$(chartWrapperElmId).html("No data available...");
return;
}
var chartData = [];
for (var i = 0; i < chartDataRaw.length; i++){
chartData.push({x:parseInt(chartDataRaw[i].x), y:parseInt(chartDataRaw[i].y)});
}
//var i = parseInt(fromDate);
//while (i < parseInt(toDate)){
// var rnd = Math.random() * (30 - 20) + 20;
// chartData.push({x:i * 1000, y:rnd});
// i += 60 * 5;
//}
var chartDiv = "chart4";
var sliderDiv = "slider4";
var x_axis = "x_axis4";
var y_axis = "y_axis4";
$(chartWrapperElmId).html("").html('<div id="' + y_axis + '" class="custom_y_axis"></div><div id="' + chartDiv + '" class="custom_rickshaw_graph"></div><div id="' + x_axis + '" class="custom_x_axis"></div><div id="' + sliderDiv + '" class="custom_slider"></div>');
var graph = new Rickshaw.Graph({
element: document.getElementById(chartDiv),
width: graphWidth,
height: 400,
strokeWidth: 1,
renderer: 'line',
xScale: d3.time.scale(),
padding: {top: 0.2, left: 0.02, right: 0.02, bottom: 0},
series:[
{ color: '#170B3B', data: chartData }
]
});
graph.render();
var xAxis = new Rickshaw.Graph.Axis.X({
graph: graph,
orientation: 'bottom',
element: document.getElementById(x_axis),
tickFormat: graph.x.tickFormat()
});
xAxis.render();
var yAxis = new Rickshaw.Graph.Axis.Y({
graph: graph,
orientation: 'left',
element: document.getElementById(y_axis),
width: 40,
height: 410
});
yAxis.render();
var slider = new Rickshaw.Graph.RangeSlider.Preview({
graph: graph,
element: document.getElementById(sliderDiv)
});
}

@ -0,0 +1,70 @@
function updateTemperatureGraph(temperatureData) {
console.log("temperatureData");
renderTemperatureChart(temperatureData);
}
function renderTemperatureChart(chartDataRaw){
var chartWrapperElmId = "#canvas-wrapper1";
var graphWidth = $(chartWrapperElmId).width() - 50;
if (chartDataRaw.length == 0) {
$(chartWrapperElmId).html("No data available...");
return;
}
var chartData = [];
for (var i = 0; i < chartDataRaw.length; i++){
chartData.push({x:parseInt(chartDataRaw[i].x), y:parseInt(chartDataRaw[i].y)});
}
//var i = parseInt(fromDate);
//while (i < parseInt(toDate)){
// var rnd = Math.random() * (30 - 20) + 20;
// chartData.push({x:i * 1000, y:rnd});
// i += 60 * 5;
//}
var chartDiv = "chart1";
var sliderDiv = "slider1";
var x_axis = "x_axis1";
var y_axis = "y_axis1";
$(chartWrapperElmId).html("").html('<div id="' + y_axis + '" class="custom_y_axis"></div><div id="' + chartDiv + '" class="custom_rickshaw_graph"></div><div id="' + x_axis + '" class="custom_x_axis"></div><div id="' + sliderDiv + '" class="custom_slider"></div>');
var graph = new Rickshaw.Graph({
element: document.getElementById(chartDiv),
width: graphWidth,
height: 400,
strokeWidth: 1,
renderer: 'line',
xScale: d3.time.scale(),
padding: {top: 0.2, left: 0.02, right: 0.02, bottom: 0},
series:[
{ color: '#FF4000', data: chartData }
]
});
graph.render();
var xAxis = new Rickshaw.Graph.Axis.X({
graph: graph,
orientation: 'bottom',
element: document.getElementById(x_axis),
tickFormat: graph.x.tickFormat()
});
xAxis.render();
var yAxis = new Rickshaw.Graph.Axis.Y({
graph: graph,
orientation: 'left',
element: document.getElementById(y_axis),
width: 40,
height: 410
});
yAxis.render();
var slider = new Rickshaw.Graph.RangeSlider.Preview({
graph: graph,
element: document.getElementById(sliderDiv)
});
}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

@ -0,0 +1,35 @@
/* Inspired by Lee Byron's test data generator. */
function stream_layers(n, m, o) {
if (arguments.length < 3) o = 0;
function bump(a) {
var x = 1 / (.1 + Math.random()),
y = 2 * Math.random() - .5,
z = 10 / (.1 + Math.random());
for (var i = 0; i < m; i++) {
var w = (i / m - y) * z;
a[i] += x * Math.exp(-w * w);
}
}
return d3.range(n).map(function() {
var a = [], i;
for (i = 0; i < m; i++) a[i] = o + o * Math.random();
for (i = 0; i < 5; i++) bump(a);
return a.map(stream_index);
});
}
/* Another layer generator using gamma distributions. */
function stream_waves(n, m) {
return d3.range(n).map(function(i) {
return d3.range(m).map(function(j) {
var x = 20 * j / m - i / 3;
return 2 * x * Math.exp(-.5 * x);
}).map(stream_index);
});
}
function stream_index(d, i) {
return {x: i, y: Math.max(0, d)};
}

@ -0,0 +1,57 @@
{{#zone "main"}}
<!-- new markup -->
<!-- secondary header - app bar -->
<div id="nav" class="row wr-app-bar">
<div class="wr-action-container">
<div class="wr-action-btn-bar">
<a href="javascript:openCollapsedNav()" class="cu-btn wr-hidden-nav-toggle-btn">
<span class="fw-stack">
<i class="fw fw-tiles fw-stack-1-5x"></i>
</span>
</a><a class="cu-btn page-title" href='javascript:location.reload();'>
<span class="fw-stack"></span>
{{title}}
</a>{{#each currentActions}}<a href="{{url}}" class="cu-btn">
<span class="fw-stack">
<i class="fw fw-ring fw-stack-2x"></i>
<i class="fw {{icon}} fw-stack-1x"></i>
</span>
{{title}}
</a>
{{/each}}{{#if enableBack}}<a href="javascript:history.go(-1)" class="cu-btn">
<span class="fw-stack">
<i class="fw fw-ring fw-stack-2x"></i>
<i class="fw fw-left-arrow fw-stack-1x"></i>
</span>
Go Back
</a>
{{/if}}
<a href="javascript:toggleNotificationbar()" class="cu-btn wr-notification-toggle-btn">
<span class="fw-stack-md">
<i class="fw fw-bell fw-stack-1-5x"></i>
</span>
<span class="wr-notification-bubble">0</span>
</a>
</div>
</div>
</div>
<!-- secondary header - app bar -->
<!-- common navigation -->
<div id="hiddenNav" class="wr-hidden-nav">
<ul>
<li><a href="/iotserver/devices"><i class="fw fw-mobile"></i>Device Management</a></li>
{{#if permissions.ADD_USER}}
<li><a href="/iotserver/users"><i class="fw fw-user"></i>User Management</a></li>
{{/if}}
<li><a href="#"><i class="fw fw-policy"></i>Policy Management</a></li>
<li><a href="/iotserver/dashboard"><i class="fw fw-settings"></i>Dashboard</a></li>
</ul>
</div>
<!-- /common navigation -->
{{/zone}}

@ -0,0 +1,78 @@
function onRequest(context) {
var constants = require("/modules/constants.js");
var user = session.get(constants.USER_SESSION_KEY);
var links = {
"users": [],
"policies": [],
"profiles": [],
"device-mgt": [],
"store": [],
"dashboard": [],
"statistics" : []
};
var dashboardLink = {
title: "Go back to Dashboard",
icon: "fw-left-arrow",
url: "/iotserver"
};
var deviceMgtLink = {
title: "Go back to Device Management",
icon: "fw-left-arrow",
url: "/iotserver/devices"
};
var storeLink = {
title: "Go back to Store",
icon: "fw-left-arrow",
url: "/iotserver"
};
links.users.push(dashboardLink);
links.policies.push(dashboardLink);
links.profiles.push(dashboardLink);
links.store.push(dashboardLink);
links.store.push(storeLink);
links.statistics.push(deviceMgtLink);
links['device-mgt'].push(dashboardLink);
if (user) {
var userModule = require("/modules/user.js").userModule;
var permissions = userModule.getUIPermissions();
context.permissions = permissions;
//if (permissions.ADD_USER) {
// links.users.push({
// title: "Add User",
// icon: "fw-add-user",
// url: "/iotserver/users/add-user"
// });
//}
if (permissions.ADD_POLICY) {
links.policies.push({
title: "Add Policy",
icon: "fw-policy",
url: "/iotserver/policies/add-policy"
});
}
//if (permissions.ADD_USER) {
// links.profiles.push({
// title: "Add Profile",
// icon: "fw-settings",
// url: "/iotserver/profiles/add-profile"
// });
//}
if (permissions.ADD_DEVICE) {
links["device-mgt"].push({
title: "Add Device",
icon: "fw-add",
url: "/iotserver/devices/add-device"
});
}
}// end-if-user
context.currentActions = links[context.link];
return context;
}

@ -0,0 +1,950 @@
{{#zone "main"}}
<!-- new markup -->
<!-- header -->
<div class="container-fluid">
<header>
<div class="row wr-global-header">
<div class="col-xs-8 col-sm-6 col-lg-8 app-logo">
<a href="home.html"><img src="{{self.publicURL}}/images/logo.png" /><h2 class="app-title">IOT Device Manager</h2></a>
</div>
<div class="col-xs-4 col-sm-6 col-lg-4 wr-auth-container">
<div class="wr-authx pull-right">
<a href="#">
<div class="auth-img">
Login
<span class="fw-stack-md fw-lg">
<i class="fw fw-lock fw-stack-1-5x"></i>
</span>
</div>
</a>
<a href="#">
<div class="auth-img">
Register
<span class="fw-stack-md fw-lg">
<i class="fw fw-register fw-stack-1-5x"></i>
</span>
</div>
</a>
<a href="#" data-toggle="dropdown">
<div class="auth-img">
Administrator
<span class="fw-stack-md fw-lg">
<i class="fw fw-user fw-stack-1-5x"></i>
</span>
</div>
</a>
<div class="dropdown-menu">
<div class="cu-arrow"></div>
<div class="dropdown-menu-content">
<a class="filter-item">Logout</a>
</div>
</div>
</div>
</div>
</div>
</header>
</div>
<!-- /header -->
<!-- secondary header - app bar -->
<div class="container-fluid">
<div id="nav" class="row wr-app-bar">
<div class="wr-action-container">
<div class="wr-action-btn-bar">
<a href="javascript:openCollapsedNav()" class="cu-btn wr-hidden-nav-toggle-btn">
<span class="fw-stack">
<i class="fw fw-tiles fw-stack-1-5x"></i>
</span>
</a><a class="cu-btn page-title" href='home.html'>
<span class="fw-stack"></span>
Devices
</a><a href="dashboard.html" class="cu-btn">
<span class="fw-stack">
<i class="fw fw-ring fw-stack-2x"></i>
<i class="fw fw-left-arrow fw-stack-1x"></i>
</span>
Go Back
</a><a href="#" class="cu-btn">
<span class="fw-stack">
<i class="fw fw-ring fw-stack-2x"></i>
<i class="fw fw-add fw-stack-1x"></i>
</span>
Add New Device
</a>
</div>
</div>
</div>
</div>
<!-- secondary header - app bar -->
<!-- common navigation -->
<div class="container-fluid">
<div id="hiddenNav" class="wr-hidden-nav">
<ul>
<li><a href="#"><i class="fw fw-mobile"></i>Device Management</a></li>
<li><a href="#"><i class="fw fw-user"></i>User Management</a></li>
<li><a href="#"><i class="fw fw-policy"></i>Policy Management</a></li>
<li><a href="#"><i class="fw fw-settings"></i>Dashboard</a></li>
</ul>
</div>
</div>
<!-- /common navigation -->
<!-- dashboard -->
<div class="container-fluid wr-content-alt" style="display:none">
<div class="row wr-stats-board">
<div class="col-md-4">
<div class="wr-stats-board-tile">
<div class="tile-name">Devices</div>
<div>
<div class="tile-icon"><i class="fw fw-devices"></i></div>
<div class="tile-stats">
532
<span class="tile-stats-free">
<a href="home.html">
<span class="fw-stack">
<i class="fw fw-ring fw-stack-2x"></i>
<i class="fw fw-view fw-stack-1x"></i>
</span>
View
</a>
</span>
</div>
</div>
</div>
</div>
<div class="col-md-4">
<div class="wr-stats-board-tile">
<div class="tile-name">Users</div>
<div>
<div class="tile-icon"><i class="fw fw-user"></i></div>
<div class="tile-stats">
503
<span class="tile-stats-free">
<a href="users.html">
<span class="fw-stack">
<i class="fw fw-ring fw-stack-2x"></i>
<i class="fw fw-view fw-stack-1x"></i>
</span>
View
</a>
<a href="user-create.html">
<span class="fw-stack">
<i class="fw fw-ring fw-stack-2x"></i>
<i class="fw fw-add fw-stack-1x"></i>
</span>
Add
</a>
</span>
</div>
</div>
</div>
</div>
<div class="col-md-4">
<div class="wr-stats-board-tile">
<div class="tile-name">Policies</div>
<div>
<div class="tile-icon"><i class="fw fw-policy"></i></div>
<div class="tile-stats">
8
<span class="tile-stats-free">
<a href="policies.html">
<span class="fw-stack">
<i class="fw fw-ring fw-stack-2x"></i>
<i class="fw fw-view fw-stack-1x"></i>
</span>
View
</a>
<a href="policy-create-wizard.html">
<span class="fw-stack">
<i class="fw fw-ring fw-stack-2x"></i>
<i class="fw fw-add fw-stack-1x"></i>
</span>
Add
</a>
</span>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- /dashboard -->
<!-- device search and operations -->
<div class="container-fluid">
<div class="row wr-operations-board">
<div class="wr-secondary-bar">
<div class="wr-filters col-xs-12 col-sm-7 col-md-8">
<!-- asset filter -->
<div class="wr-search">
<div class="wr-asset-type-switcher">
<a href="javascript:void(0)" class="ctrl-asset-type-switcher"><span class="btn-asset"><i class="fw fw-filter"></i></span></a>
<div class="popover menu fade bottom in">
<div class="arrow"></div>
<div class="popover-content">
<div id="advance-filter-options">
<div class="title">Search method</div>
<label class="wr-input-control radio light">
<input type="radio" name="search-method" value="devices" checked />
<span class="helper">Device</span>
</label>
<label class="wr-input-control radio light">
<input type="radio" name="search-method" value="users" />
<span class="helper">User</span>
</label>
<label class="wr-input-control radio light">
<input type="radio" name="search-method" value="user roles" />
<span class="helper">User Role</span>
</label>
</div>
<div id="device-filter-options">
<div id="asset-selected"></div>
<div id="asset-select">
<ul>
<!-- Android -->
<li><i class="fw fw-android"></i><span class="tag-name">Android</span></li>
<ul>
<li><h4>Android</h4><h6 class="tag-name">Ice Cream Sandwich</h6></li>
<ul>
<li><h3 class="tag-name">3.0</h3></li>
<li><h3 class="tag-name">3.0.1</h3></li>
</ul>
<li><h4>Android</h4><h6 class="tag-name">Jelly Bean</h6></li>
<ul>
<li><h3 class="tag-name">4.2</h3></li>
<li><h3 class="tag-name">4.3</h3></li>
</ul>
<li><h4>Android</h4><h6 class="tag-name">KitKat</h6></li>
<ul>
<li><h3 class="tag-name">4.4</h3></li>
</ul>
<li><h4>Android</h4><h6 class="tag-name">Lollipop</h6></li>
<ul>
<li><h3 class="tag-name">5.0</h3></li>
<li><h3 class="tag-name">5.0.1</h3></li>
<li><h3 class="tag-name">5.0.2</h3></li>
</ul>
</ul>
<!-- iOS -->
<li><i class="fw fw-apple"></i><span class="tag-name">iOS</span></li>
<!-- Windows -->
<li><i class="fw fw-windows"></i><span class="tag-name">Windows</span></li>
</ul>
</div>
</div>
</div>
</div>
</div>
<div class="wr-search-tags"></div>
<a href="#" class="btn-search"><i class="fw fw-search"></i></a>
<div class="input" id="search" data-value="" data-placeholder="Search devices ..." contenteditable="true"></div>
<div class="clearfix"></div>
</div>
<!-- /asset filter -->
</div>
<div class="wr-filters col-xs-12 col-sm-5 col-md-4 wr-filters-right">
<div class="wr-filter-sort pull-right">
<a href="javascript:void(0)" onclick="selectAllDevices(this)" class="wr-btn">Select All Devices</a>
<a href="javascript:void(0)" onclick="changeDeviceView('grid', this)" class="ico-filter ctrl-filter-grid view-toggle"><i class="fw fw-grid"></i></a>
<a href="javascript:void(0)" onclick="changeDeviceView('list', this)" class="ico-filter ctrl-filter-list view-toggle selected"><i class="fw fw-list"></i></a>
<span class="wr-filter-type-switcher"><a href="#" class="ico-filter ctrl-filter-type-switcher" data-placement="bottom" data-trigger="focus"><i class="fw fw-list-sort"></i></a></span>
</div>
</div>
</div>
</div>
</div>
<!-- /device search and operations -->
<!-- no devices found -->
<div class="container-fluid wr-content-alt">
<div class="ctrl-info-panel col-md-6 col-centered">
<h2>You dont have any Devices registered at the moment.</h2>
<p>
</a><a href="#" class="cu-btn">
<span class="fw-stack">
<i class="fw fw-ring fw-stack-2x"></i>
<i class="fw fw-add fw-stack-1x"></i>
</span>
Add New Device
</a>
</p>
</div>
</div>
<!-- /no devices found -->
<!-- device list -->
<div class="container-fluid wr-content-alt">
<div class="wr-device-list row">
<div class="col-md-12 wr-page-content">
<!-- content -->
<div>
<!-- form content placeholder -->
<div id="ast-container" class="ast-container list-view">
<div class="ctrl-wr-asset">
<div class="itm-select">
<label class="wr-input-control checkbox">
<input type="checkbox" />
<span class="helper"></span>
</label>
</div>
<div class="itm-ast">
<a href="device.html">
<div class="ast-img"><img src="images/device_icons/windows-mobile.png" /></div>
<div class="ast-desc">
<div class="ast-title">
<h3 class="ast-name" title="mymobile">mymobile</h3>
<span class="ast-auth" title="navinda">navinda</span>
</div>
<div class="ast-model">
<span class="ast-ver">Windows 8</span>
<span class="ast-published">Nokia Lumia 925</span>
<div class="ast-btn-group">
<a href="users.html">
<span class="fw-stack">
<i class="fw fw-ring fw-stack-2x"></i>
<i class="fw fw-view fw-stack-1x"></i>
</span>
<span class="lbl-action">View</span>
</a>
<a href="users.html">
<span class="fw-stack">
<i class="fw fw-ring fw-stack-2x"></i>
<i class="fw fw-edit fw-stack-1x"></i>
</span>
<span class="lbl-action">Edit</span>
</a>
<a href="users.html">
<span class="fw-stack">
<i class="fw fw-ring fw-stack-2x"></i>
<i class="fw fw-delete fw-stack-1x"></i>
</span>
<span class="lbl-action">Delete</span>
</a>
</div>
</div>
</div>
<br class="c-both" />
</a>
</div>
</div>
<div class="ctrl-wr-asset">
<div class="itm-select">
<label class="wr-input-control checkbox">
<input type="checkbox" checked />
<span class="helper"></span>
</label>
</div>
<div class="itm-ast">
<a href="device.html">
<div class="ast-img"><img src="images/device_icons/android-mobile.png" /></div>
<div class="ast-desc">
<div class="ast-title">
<h3 class="ast-name">Ruwan's Phone</h3>
<span class="ast-auth">navinda</span>
</div>
<div class="ast-model">
<span class="ast-ver">Android-KitKat</span>
<span class="ast-published">Samsung Galaxy S4</span>
<div class="ast-btn-group">
<a href="users.html">
<span class="fw-stack">
<i class="fw fw-ring fw-stack-2x"></i>
<i class="fw fw-view fw-stack-1x"></i>
</span>
<span class="lbl-action">View</span>
</a>
<a href="users.html">
<span class="fw-stack">
<i class="fw fw-ring fw-stack-2x"></i>
<i class="fw fw-edit fw-stack-1x"></i>
</span>
<span class="lbl-action">Edit</span>
</a>
<a href="users.html">
<span class="fw-stack">
<i class="fw fw-ring fw-stack-2x"></i>
<i class="fw fw-delete fw-stack-1x"></i>
</span>
<span class="lbl-action">Delete</span>
</a>
</div>
</div>
</div>
<br class="c-both" />
</a>
</div>
</div>
<div class="ctrl-wr-asset">
<div class="itm-select">
<label class="wr-input-control checkbox">
<input type="checkbox" checked />
<span class="helper"></span>
</label>
</div>
<div class="itm-ast">
<a href="device.html">
<div class="ast-img"><img src="images/device_icons/ipad.png" /></div>
<div class="ast-desc">
<div class="ast-title">
<h3 class="ast-name">Brother's iPad</h3>
<span class="ast-auth">navinda</span>
</div>
<div class="ast-model">
<span class="ast-ver">iOS6</span>
<span class="ast-published">Apple iPad3</span>
<div class="ast-btn-group">
<a href="users.html">
<span class="fw-stack">
<i class="fw fw-ring fw-stack-2x"></i>
<i class="fw fw-view fw-stack-1x"></i>
</span>
<span class="lbl-action">View</span>
</a>
<a href="users.html">
<span class="fw-stack">
<i class="fw fw-ring fw-stack-2x"></i>
<i class="fw fw-edit fw-stack-1x"></i>
</span>
<span class="lbl-action">Edit</span>
</a>
<a href="users.html">
<span class="fw-stack">
<i class="fw fw-ring fw-stack-2x"></i>
<i class="fw fw-delete fw-stack-1x"></i>
</span>
<span class="lbl-action">Delete</span>
</a>
</div>
</div>
</div>
<br class="c-both" />
</a>
</div>
</div>
<div class="ctrl-wr-asset">
<div class="itm-select">
<label class="wr-input-control checkbox">
<input type="checkbox" checked />
<span class="helper"></span>
</label>
</div>
<div class="itm-ast">
<a href="device.html">
<div class="ast-img"><img src="images/device_icons/windows-tab.png" /></div>
<div class="ast-desc">
<div class="ast-title">
<h3 class="ast-name">MySurface</h3>
<span class="ast-auth">admin</span>
</div>
<div class="ast-model">
<span class="ast-ver">Windows 8.1</span>
<span class="ast-published">Windows Surface Pro3</span>
<div class="ast-btn-group">
<a href="users.html">
<span class="fw-stack">
<i class="fw fw-ring fw-stack-2x"></i>
<i class="fw fw-view fw-stack-1x"></i>
</span>
<span class="lbl-action">View</span>
</a>
<a href="users.html">
<span class="fw-stack">
<i class="fw fw-ring fw-stack-2x"></i>
<i class="fw fw-edit fw-stack-1x"></i>
</span>
<span class="lbl-action">Edit</span>
</a>
<a href="users.html">
<span class="fw-stack">
<i class="fw fw-ring fw-stack-2x"></i>
<i class="fw fw-delete fw-stack-1x"></i>
</span>
<span class="lbl-action">Delete</span>
</a>
</div>
</div>
</div>
<br class="c-both" />
</a>
</div>
</div>
<div class="ctrl-wr-asset">
<div class="itm-select">
<label class="wr-input-control checkbox">
<input type="checkbox" checked />
<span class="helper"></span>
</label>
</div>
<div class="itm-ast">
<a href="device.html">
<div class="ast-img"><img src="images/device_icons/macbook.png" /></div>
<div class="ast-desc">
<div class="ast-title">
<h3 class="ast-name">John's Macbook</h3>
<span class="ast-auth">admin</span>
</div>
<div class="ast-model">
<span class="ast-ver">OSX 11</span>
<span class="ast-published">Mac Book Air</span>
<div class="ast-btn-group">
<a href="users.html">
<span class="fw-stack">
<i class="fw fw-ring fw-stack-2x"></i>
<i class="fw fw-view fw-stack-1x"></i>
</span>
<span class="lbl-action">View</span>
</a>
<a href="users.html">
<span class="fw-stack">
<i class="fw fw-ring fw-stack-2x"></i>
<i class="fw fw-edit fw-stack-1x"></i>
</span>
<span class="lbl-action">Edit</span>
</a>
<a href="users.html">
<span class="fw-stack">
<i class="fw fw-ring fw-stack-2x"></i>
<i class="fw fw-delete fw-stack-1x"></i>
</span>
<span class="lbl-action">Delete</span>
</a>
</div>
</div>
</div>
<br class="c-both" />
</a>
</div>
</div>
<div class="ctrl-wr-asset">
<div class="itm-select">
<label class="wr-input-control checkbox">
<input type="checkbox" />
<span class="helper"></span>
</label>
</div>
<div class="itm-ast">
<a href="device.html">
<div class="ast-img"><img src="images/device_icons/windows-pc.png" /></div>
<div class="ast-desc">
<div class="ast-title">
<h3 class="ast-name">Developer's PC</h3>
<span class="ast-auth">navinda</span>
</div>
<div class="ast-model">
<span class="ast-ver">Window 8</span>
<span class="ast-published">Dell Inspiron E1564</span>
<div class="ast-btn-group">
<a href="users.html">
<span class="fw-stack">
<i class="fw fw-ring fw-stack-2x"></i>
<i class="fw fw-view fw-stack-1x"></i>
</span>
<span class="lbl-action">View</span>
</a>
<a href="users.html">
<span class="fw-stack">
<i class="fw fw-ring fw-stack-2x"></i>
<i class="fw fw-edit fw-stack-1x"></i>
</span>
<span class="lbl-action">Edit</span>
</a>
<a href="users.html">
<span class="fw-stack">
<i class="fw fw-ring fw-stack-2x"></i>
<i class="fw fw-delete fw-stack-1x"></i>
</span>
<span class="lbl-action">Delete</span>
</a>
</div>
</div>
</div>
<br class="c-both" />
</a>
</div>
</div>
<div class="ctrl-wr-asset">
<div class="itm-select">
<label class="wr-input-control checkbox">
<input type="checkbox" />
<span class="helper"></span>
</label>
</div>
<div class="itm-ast">
<a href="device.html">
<div class="ast-img"><img src="images/device_icons/laptop.png" /></div>
<div class="ast-desc">
<div class="ast-title">
<h3 class="ast-name">Developer's Laptop</h3>
<span class="ast-auth">navinda</span>
</div>
<div class="ast-model">
<span class="ast-ver">Windows 8.1</span>
<span class="ast-published">Alienware MX17</span>
<div class="ast-btn-group">
<a href="users.html">
<span class="fw-stack">
<i class="fw fw-ring fw-stack-2x"></i>
<i class="fw fw-view fw-stack-1x"></i>
</span>
<span class="lbl-action">View</span>
</a>
<a href="users.html">
<span class="fw-stack">
<i class="fw fw-ring fw-stack-2x"></i>
<i class="fw fw-edit fw-stack-1x"></i>
</span>
<span class="lbl-action">Edit</span>
</a>
<a href="users.html">
<span class="fw-stack">
<i class="fw fw-ring fw-stack-2x"></i>
<i class="fw fw-delete fw-stack-1x"></i>
</span>
<span class="lbl-action">Delete</span>
</a>
</div>
</div>
</div>
<br class="c-both" />
</a>
</div>
</div>
<div class="ctrl-wr-asset">
<div class="itm-select">
<label class="wr-input-control checkbox">
<input type="checkbox" />
<span class="helper"></span>
</label>
</div>
<div class="itm-ast">
<a href="device.html">
<div class="ast-img"><img src="images/device_icons/android-tab.png" /></div>
<div class="ast-desc">
<div class="ast-title">
<h3 class="ast-name">Brother's Galaxy Tab</h3>
<span class="ast-auth">navinda</span>
</div>
<div class="ast-model">
<span class="ast-ver">Android-Jellybean</span>
<span class="ast-published">Samsung Galaxy Tab 10</span>
<div class="ast-btn-group">
<a href="users.html">
<span class="fw-stack">
<i class="fw fw-ring fw-stack-2x"></i>
<i class="fw fw-view fw-stack-1x"></i>
</span>
<span class="lbl-action">View</span>
</a>
<a href="users.html">
<span class="fw-stack">
<i class="fw fw-ring fw-stack-2x"></i>
<i class="fw fw-edit fw-stack-1x"></i>
</span>
<span class="lbl-action">Edit</span>
</a>
<a href="users.html">
<span class="fw-stack">
<i class="fw fw-ring fw-stack-2x"></i>
<i class="fw fw-delete fw-stack-1x"></i>
</span>
<span class="lbl-action">Delete</span>
</a>
</div>
</div>
</div>
<br class="c-both" />
</a>
</div>
</div>
<br class="c-both" />
</div>
</div>
<!-- /content -->
</div>
</div>
</div>
<!-- /device list -->
<!-- register form -->
<div class="container col-centered wr-content">
<h1 class="wr-title">Register</h1>
<hr />
<div class="row wr-form">
<div class="col-lg-6">
<label class="wr-input-label">First Name</label>
<div class="wr-input-control">
<input type="text" value="" placeholder="input text"/>
</div>
<label class="wr-input-label">Last Name</label>
<div class="wr-input-control">
<input type="text" value="" placeholder="input text"/>
</div>
<label class="wr-input-label">Last Name</label>
<div class="wr-input-control">
<input type="text" value="" placeholder="input text"/>
</div>
<label class="wr-input-label">Email</label>
<div class="wr-input-control">
<input type="text" value="" placeholder="input text"/>
</div>
<label class="wr-input-label">Password</label>
<div class="wr-input-control">
<input type="text" value="" placeholder="input text"/>
</div>
<label class="wr-input-label">Confirm Password</label>
<div class="wr-input-control">
<input type="text" value="" placeholder="input text"/>
</div>
<div class="ctrl-i-agree">
<input type="checkbox" name="Agree" id="t_and_c" value="Bike"> <span class="italic i-agree">
I Agree by Clicking register, you agree to the Terms and Conditions set out by this site</span>
</div>
<div class="btn-group">
<button class="wr-btn" onclick="window.location.href='policy-created.html'">Register</button>
</div>
</div>
</div>
</div>
<!-- /register form -->
<!-- /new markup -->
<div class="container container-fluid">
<!-- Static navbar -->
<nav class="navbar navbar-default">
<div class=" margin-top">
<!-- Brand and toggle get grouped for better mobile display -->
<div class="navbar-header">
<button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#bs-example-navbar-collapse-1">
<span class="sr-only">Toggle navigation</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a class="navbar-brand" href="/iotserver/"><img src="{{self
.publicURL}}/images/logo.png" </a>
</div>
<!-- Collect the nav links, forms, and other content for toggling -->
<div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
<ul class="nav navbar-nav">
<li><a href="#"></a></li>
<li><a href="#">ARCHITECTURE</a></li>
<li><a href="#">GUIDE</a></li>
<li><a href="#">SUPPORT</a></li>
<li><a href="#">COMMUNITY</a></li>
{{#if user}}
<li><a href="/iotserver/alldevices">MY DEVICES</a></li>
{{/if}}
</ul>
<ul class="nav navbar-nav navbar-right">
{{#if viewonly}}
<li id="flip-login" data-type="login" class="blue sign-toggle-btn" > LOGIN </li>
<li id="flip" data-type="register" class="margin-top blue-btn sign-toggle-btn"> REGISTER </li>
{{/if}}
{{#if user}}
<li class="blue">
<a href="#" data-toggle="dropdown">
<div class="auth-img">
{{user.username}}
<span class="wso2icon-stack-md wso2icon-lg">
<i class="wso2icon wso2-user wso2icon-stack-1-5x"></i>
</span>
</div>
</a>
<div class="dropdown-menu" style="padding:10px" role="menu">
<div class="cu-arrow"></div>
<div class="dropdown-menu-content">
<a href="{{logoutURL}}" class="filter-item pull-right">Logout</a>
</div>
</div>
</li>
{{/if}}
<li >
<form class="navbar-form" role="search">
<div class="input-group">
<input type="text" class="form-control" name="q">
<div class="input-group-btn">
<button class="btn btn-default" type="submit"><i class="glyphicon glyphicon-search"></i></button>
</div>
</div>
</form>
</li>
</ul>
</div><!-- /.navbar-collapse -->
</div><!-- /.container-fluid -->
</nav>
</div><!--container-->
<div class="sign-panel" data-type="register">
<div class="container padding margin-top-double ">
<h5 >Register </h5> <hr class="opacity">
<div class="form-group" align="center">
<span class="wr-validation-summary hidden">
<strong class="label label-danger"></strong>
</span>
</div>
<div class="col-lg-5 padding center ">
<div class="col-lg-5 right padding-top-double uppercase ">
First Name
</div>
<div class="col-lg-7 ">
<input type="text right" id="first_name" placeholder="First Name">
</div>
</div>
<div class="col-lg-5 padding center ">
<div class="col-lg-5 right padding-top-double uppercase ">
Last Name
</div>
<div class="col-lg-7 ">
<input type="text right" id="last_name" placeholder="Last Name">
</div>
</div>
<div class="col-lg-5 padding center ">
<div class="col-lg-5 right padding-top-double uppercase ">
Username
</div>
<div class="col-lg-7 ">
<input type="text right" id="user_name" placeholder="Username ">
</div>
</div>
<div class="col-lg-5 padding center ">
<div class="col-lg-5 right padding-top-double uppercase ">
Email
</div>
<div class="col-lg-7 ">
<input type="text right" id="email" placeholder="Email">
</div>
</div>
<div class="col-lg-5 padding center ">
<div class="col-lg-5 right padding-top-double uppercase ">
Password
</div>
<div class="col-lg-7 ">
<input type="password" id="password" placeholder="Password">
</div>
</div>
<div class="col-lg-5 padding center ">
<div class="col-lg-5 right padding-top-double uppercase ">
Confirm Password
</div>
<div class="col-lg-7 ">
<input type="password" id="password_confirmation"
placeholder="Confirm Password">
</div>
</div>
<div class="col-lg-9 right padding-top-double padding-bottom-double margin-right-none">
<input type="checkbox" name="Agree" id="t_and_c" value="Bike"> <span class="italic">
I Agree by Clicking register, you agree to the Terms and Conditions set out by this site</span>
</div>
<div class="col-lg-12 center padding-top-double padding-bottom-double">
<button id="add-user-btn" class="blue-action-btn uppercase margin">
Register </button>
<button class="black-btn uppercase margin cancel-btn" > Cancel</button>
</div>
</div>
</div>
<div class="sign-panel" data-type="login">
<form method="POST" class="form-login-box" action="{{loginPath}}">
<div class="container padding margin-top-double ">
<h5 >Login </h5> <hr class="opacity">
<div class="col-lg-3 padding ">
Username :<br> <input type="text" name="username" />
</div>
<div class="col-lg-3 padding ">
Password: <br> <input type="password" name="password" />
</div>
<div class="col-lg-6 padding-top-double padding-bottom-double padding-left-none">
<button class="blue-action-btn uppercase margin" onclick="document.location.href='home.html';"> Login</button>
<button class="black-btn uppercase margin cancel-btn " > Cancel</button>
</div>
</div>
</form>
</div>
{{/zone}}

@ -0,0 +1,87 @@
{{#zone "main"}}
<!-- dashboard -->
<div class="container-fluid wr-content-alt">
<div class="row wr-stats-board">
<div class="col-md-4">
<div class="wr-stats-board-tile">
<div class="tile-name">Devices</div>
<div>
<div class="tile-icon"><i class="fw fw-devices"></i></div>
<div class="tile-stats">
<span id="device-count">Loading...</span>
<span class="tile-stats-free">
<a href="home.html">
<span class="fw-stack">
<i class="fw fw-ring fw-stack-2x"></i>
<i class="fw fw-view fw-stack-1x"></i>
</span>
View
</a>
</span>
</div>
</div>
</div>
</div>
<div class="col-md-4">
<div class="wr-stats-board-tile">
<div class="tile-name">Users</div>
<div>
<div class="tile-icon"><i class="fw fw-user"></i></div>
<div class="tile-stats">
<span id="user-count">Loading...</span>
<span class="tile-stats-free">
<a href="users/">
<span class="fw-stack">
<i class="fw fw-ring fw-stack-2x"></i>
<i class="fw fw-view fw-stack-1x"></i>
</span>
View
</a>
<a href="user-create.html">
<span class="fw-stack">
<i class="fw fw-ring fw-stack-2x"></i>
<i class="fw fw-add fw-stack-1x"></i>
</span>
Add
</a>
</span>
</div>
</div>
</div>
</div>
<div class="col-md-4">
<div class="wr-stats-board-tile">
<div class="tile-name">Policies</div>
<div>
<div class="tile-icon"><i class="fw fw-policy"></i></div>
<div class="tile-stats">
<span id="policy-count">Loading...</span>
<span class="tile-stats-free">
<a href="policies.html">
<span class="fw-stack">
<i class="fw fw-ring fw-stack-2x"></i>
<i class="fw fw-view fw-stack-1x"></i>
</span>
View
</a>
<a href="policy-create-wizard.html">
<span class="fw-stack">
<i class="fw fw-ring fw-stack-2x"></i>
<i class="fw fw-add fw-stack-1x"></i>
</span>
Add
</a>
</span>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- /dashboard -->
{{/zone}}
{{#zone "bottomJs"}}
<script src="{{self.publicURL}}/js/dashboard.js"></script>
{{/zone}}

@ -0,0 +1,20 @@
var updateStats = function (serviceURL, id) {
invokerUtil.get(
serviceURL,
function (data) {
$(id).html(data);
}, function (message) {
console.log(message);
}
);
};
$(document).ready(function(){
//updateStats("/mdm-admin/devices/count", "#device-count");
//updateStats("/mdm-admin/policies/count", "#policy-count");
//updateStats("/mdm-admin/users/count/" + "carbon.super", "#user-count");
//TODO: get this value from devicecloud webservice
$("#device-count").html("0");
$("#policy-count").html("0");
$("#user-count").html("0");
});

@ -0,0 +1,195 @@
{{#zone "main"}}
<div class="row wr-device-board">
<div class="col-lg-12 wr-secondary-bar">
<label class="device-id device-select" data-deviceid="{{device.deviceIdentifier}}" data-type="{{device.type}}">
Device {{device.name}}
<span class="lbl-device">
({{device.viewModel.vendor}} {{device.viewModel.model}})
</span>
</label>
</div>
</div>
<div class="wr-device-list row">
<div class="wr-hidden-operations wr-advance-operations">
</div>
<div class="col-md-12 wr-page-content">
{{unit "operation-bar" deviceType=device.type}}
<div class="row">
<div class="col-md-12 wr-stats-board">
<!-- content -->
<div class="col-lg-2 ast-desc-image">
<div class="row">
<div class="col-lg-12 col-sm-4">
<img src="{{self.publicURL}}/img/device_icons/{{device.type}}.png" style="width:200px" />
</div>
<div class="col-lg-12 col-sm-4 ast-desc">
<div class="ast-device-desc"><b>Device:</b> {{device.viewModel.vendor}} {{device.properties.model}}</div>
<div class="ast-device-desc"><b>Model:</b> {{device.viewModel.model}}</div>
<div class="ast-device-desc"><b>IMEI:</b> {{device.viewModel.imei}}</div>
{{#if device.viewModel.udid}}<div class="ast-device-desc"><b>UDID:</b> {{device.viewModel.udid}}</div>{{/if}}
{{#if device.viewModel.phoneNumber}}<div class="ast-device-desc"><b>Phone Number:</b> {{device.viewModel.phoneNumber}}</div>{{/if}}
</div>
</div>
</div>
<div class="col-lg-10 tiles">
<!-- device summary -->
<div class="row">
<div class="col-lg-6 col-md-6">
{{#if device.viewModel.BatteryLevel}}
<div class="col-lg-4">
<div class="wr-stats-board-tile">
<div class="tile-name">BATTERY</div>
<div>
<div class="tile-icon"><i class="fw fw-battery"></i></div>
<div class="tile-stats">{{device.viewModel.BatteryLevel}}%</div>
</div>
</div>
</div>
{{/if}}
{{#if device.viewModel.DeviceCapacity}}
<div class="col-lg-4">
<div class="wr-stats-board-tile">
<div class="tile-name">STORAGE</div>
<div>
<div class="tile-icon"><i class="fw fw-hdd"></i></div>
<div class="tile-stats">{{device.viewModel.DeviceCapacityPercentage}}%<span class="tile-stats-free">{{device.viewModel.DeviceCapacityUsed}} GB Free</span></div>
</div>
</div>
</div>
{{/if}}
{{#if device.viewModel.internal_memory.FreeCapacity}}
<div class="col-lg-4">
<div class="wr-stats-board-tile">
<div class="tile-name">LOCAL STORAGE</div>
<div>
<div class="tile-icon"><i class="fw fw-hdd"></i></div>
<div class="tile-stats">{{device.viewModel.internal_memory.DeviceCapacityPercentage}}%<span class="tile-stats-free">{{device.viewModel.internal_memory.FreeCapacity}} GB Free</span></div>
</div>
</div>
</div>
{{/if}}
{{#if device.viewModel.external_memory.FreeCapacity}}
<div class="col-lg-4">
<div class="wr-stats-board-tile">
<div class="tile-name">EXTERNAL STORAGE</div>
<div>
<div class="tile-icon"><i class="fw fw-hdd"></i></div>
<div class="tile-stats">{{device.viewModel.external_memory.DeviceCapacityPercentage}}%<span class="tile-stats-free">{{device.viewModel.external_memory.FreeCapacity}} GB Free</span></div>
</div>
</div>
</div>
{{/if}}
</div>
</div>
<!-- /device summary -->
<div class="panel-group" id="accordion" role="tablist" aria-multiselectable="true">
<!-- device location -->
<div class="panel panel-default">
<div class="panel-heading" role="tab" id="headingOne">
<h2 class="sub-title panel-title">
<a data-toggle="collapse" data-parent="#accordion" href="#collapseOne" aria-expanded="true" aria-controls="collapseOne">
<span class="fw-stack">
<i class="fw fw-ring fw-stack-2x"></i>
<i class="fw fw-arrow fw-down-arrow fw-stack-1x"></i>
</span>
Device Location
</a>
</h2>
</div>
<div id="collapseOne" class="panel-collapse collapse in" role="tabpanel" aria-labelledby="headingOne">
<div id="device-location" style="height:400px" class="panel-body">
</div>
</div>
</div>
<!-- /device location -->
<!-- policies -->
<div class="panel panel-default">
<div class="panel-heading" role="tab" id="headingTwo">
<h2 class="sub-title panel-title">
<a class="collapsed" data-toggle="collapse" data-parent="#accordion" href="#collapseTwo" aria-expanded="false" aria-controls="collapseTwo">
<span class="fw-stack">
<i class="fw fw-ring fw-stack-2x"></i>
<i class="fw fw-arrow fw-down-arrow fw-stack-1x"></i>
</span>
Policies
</a>
</h2>
</div>
<div id="collapseTwo" class="panel-collapse collapse" role="tabpanel" aria-labelledby="headingTwo">
<div class="panel-body">
Not available yet
</div>
</div>
</div>
<!-- /policies -->
<!-- installed applications -->
<div class="panel panel-default">
<div class="panel-heading" role="tab" id="headingThree">
<h2 class="sub-title panel-title">
<a class="collapsed" data-toggle="collapse" data-parent="#accordion" href="#collapseThree" aria-expanded="false" aria-controls="collapseThree">
<span class="fw-stack">
<i class="fw fw-ring fw-stack-2x"></i>
<i class="fw fw-arrow fw-down-arrow fw-stack-1x"></i>
</span>
Installed Applications
</a>
</h2>
</div>
<div id="collapseThree" class="panel-collapse collapse" role="tabpanel" aria-labelledby="headingThree">
<div class="panel-body">
Not available yet
</div>
</div>
</div>
<!-- /installed applications -->
<!-- statistics -->
<div class="panel panel-default">
<div class="panel-heading" role="tab" id="headingFour">
<h2 class="sub-title panel-title">
<a class="collapsed" data-toggle="collapse" data-parent="#accordion" href="#collapseFour" aria-expanded="false" aria-controls="collapseFour">
<span class="fw-stack">
<i class="fw fw-ring fw-stack-2x"></i>
<i class="fw fw-arrow fw-down-arrow fw-stack-1x"></i>
</span>
Device Statistics
</a>
</h2>
</div>
<div id="collapseFour" class="panel-collapse collapse" role="tabpanel" aria-labelledby="headingFour">
<div class="panel-body">
<a href="../../devices/analytics?deviceId={{deviceId}}&deviceType={{deviceType}}" ><i class="fw fw-charts"></i> Show Statistics</a>
</div>
</div>
</div>
<!-- /statistics -->
</div>
</div>
<!-- /content -->
</div>
</div>
</div>
</div>
{{/zone}}
{{#zone "bottomJs"}}
<script src="https://maps.googleapis.com/maps/api/js?v=3.exp&signed_in=true"></script>
<script src="{{self.publicURL}}/js/device-detail.js"></script>
{{/zone}}

@ -0,0 +1,59 @@
function onRequest(context) {
var uri = request.getRequestURI();
var uriMatcher = new URIMatcher(String(uri));
var isMatched = uriMatcher.match("/{context}/device/{deviceType}/{+deviceId}");
if (isMatched) {
var matchedElements = uriMatcher.elements();
var deviceType = matchedElements.deviceType;
var deviceId = matchedElements.deviceId;
context.deviceType = deviceType;
context.deviceId = deviceId;
var deviceModule = require("/modules/device.js").deviceModule;
var device = deviceModule.viewDevice(deviceType, deviceId);
if (device){
var viewModel = {};
var deviceInfo = device.properties.DEVICE_INFO;
log.info(deviceInfo);
if (deviceInfo != undefined && String(deviceInfo.toString()).length > 0){
deviceInfo = JSON.parse(deviceInfo);
if (device.type == "ios"){
viewModel.imei = device.properties.IMEI;
viewModel.phoneNumber = deviceInfo.PhoneNumber;
viewModel.udid = deviceInfo.UDID;
viewModel.BatteryLevel = Math.round(deviceInfo.BatteryLevel * 100);
viewModel.DeviceCapacity = Math.round(deviceInfo.DeviceCapacity * 100) / 100;
viewModel.AvailableDeviceCapacity = Math.round(deviceInfo.AvailableDeviceCapacity * 100) / 100;
viewModel.DeviceCapacityUsed = Math.round((viewModel.DeviceCapacity
- viewModel.AvailableDeviceCapacity) * 100) / 100;
viewModel.DeviceCapacityPercentage = Math.round(viewModel.DeviceCapacityUsed
/ viewModel.DeviceCapacity * 10000) /100;
}else if(device.type == "android"){
viewModel.imei = device.properties.IMEI;
viewModel.model = device.properties.DEVICE_MODEL;
viewModel.vendor = device.properties.VENDOR;
viewModel.internal_memory = {};
viewModel.external_memory = {};
viewModel.location = {
latitude: device.properties.LATITUDE,
longitude: device.properties.LONGITUDE
};
viewModel.BatteryLevel = deviceInfo.BATTERY_LEVEL;
viewModel.internal_memory.FreeCapacity = Math.round((deviceInfo.INTERNAL_TOTAL_MEMORY -
deviceInfo.INTERNAL_AVAILABLE_MEMORY) * 100) / 100;
viewModel.internal_memory.DeviceCapacityPercentage = Math.round(deviceInfo.INTERNAL_AVAILABLE_MEMORY
/ deviceInfo.INTERNAL_TOTAL_MEMORY * 10000) / 100;
viewModel.external_memory.FreeCapacity = Math.round((deviceInfo.EXTERNAL_TOTAL_MEMORY -
deviceInfo.EXTERNAL_AVAILABLE_MEMORY) * 100) / 100;
viewModel.external_memory.DeviceCapacityPercentage = Math.round(deviceInfo.EXTERNAL_AVAILABLE_MEMORY
/deviceInfo.EXTERNAL_TOTAL_MEMORY * 10000) /100;
}
device.viewModel = viewModel;
}
}
context.device = device;
} else {
response.sendError(404);
}
return context;
}

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save