Merge remote-tracking branch 'manage/master' into subtree

this merges master branch of https://github.com/helma-org/apps-manage-mirror into helma
This commit is contained in:
Simon Oberhammer 2012-03-27 11:47:36 +02:00
commit ca2b08a5df
58 changed files with 2678 additions and 0 deletions

View file

@ -0,0 +1,67 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN">
<html>
<head>
<title></title>
<style type="text/css">
body, p, td, th, li {
font-family: verdana, sans-serif;
font-size: 10pt;
}
big.top {
font-size: 18pt;
font-weight: bold;
}
big {
font-size: 13pt;
font-weight: bold;
}
a {
font-weight:bold;
color: #cc3333;
text-decoration:none;
}
a:hover {
text-decoration:underline;
}
.navig {
font-size: 9px;
text-decoration: none;
font-weight:normal;
}
li {
padding-bottom: 5px;
}
.mainbox {
border-color:#999999;
padding-top:5px;
padding-bottom:5px;
border-bottom-width:1px;
border-bottom-style:dotted;
}
.headline {
font-weight:bold;
background:#dfdfdf;
border-color:#999999;
padding-top:5px;
padding-bottom:5px;
}
</style>
</head>
<body>
<% response.body %>
</body>
</html>

View file

@ -0,0 +1,5 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd">
<html>
<% response.head %>
<% response.body %>
</html>

View file

@ -0,0 +1,262 @@
/**
* scheduler function, runs global.appStat every minute
*/
function scheduler() {
appStat();
return 60000;
}
/**
* initializes app.data.stat storage on startup,
* creates app.data.addressFilter
*/
function onStart() {
app.data.addressFilter = createAddressFilter();
app.data.addressString = root.getProperty("allowadmin");
}
/**
* initializes addressFilter from app.properties,
* hostnames are converted, wildcards are only allowed in ip-addresses
* (so, no network-names, sorry)
*/
function createAddressFilter() {
var filter = new Packages.helma.util.InetAddressFilter();
var str = root.getProperty("allowadmin");
if (str != null && str != "") {
var arr = str.split(",");
for (var i in arr) {
str = new java.lang.String(arr[i]);
try {
filter.addAddress(str.trim());
} catch (a) {
try {
str = java.net.InetAddress.getByName(str.trim()).getHostAddress();
filter.addAddress(str);
} catch (b) {
app.log("error using address " + arr[i] + ": " + b);
}
}
}
} else {
app.log("no addresses allowed for app manage, all access will be denied");
}
return filter;
}
/**
* updates the stats in app.data.stat every 5 minutes
*/
function appStat() {
if (app.data.stat == null)
app.data.stat = new HopObject ();
if ((new Date() - 300000) < app.data.stat.lastRun)
return;
var arr = root.getApplications();
for (var i = 0; i < arr.length; i++) {
var tmp = app.data.stat[arr[i].getName()];
if (tmp == null) {
tmp = new HopObject();
tmp.lastTotalRequestCount = 0;
tmp.lastTotalErrorCount = 0;
}
tmp.requestCount = arr[i].getRequestCount() - tmp.lastTotalRequestCount;
tmp.lastTotalRequestCount = arr[i].getRequestCount();
tmp.errorCount = arr[i].getErrorCount() - tmp.lastTotalErrorCount;
tmp.lastTotalErrorCount = arr[i].getErrorCount();
app.data.stat[arr[i].getName()] = tmp;
}
app.data.stat.lastRun = new Date();
}
/**
* utility function to sort object-arrays by name
*/
function sortByName(a, b) {
if (a.name > b.name)
return 1;
else if (a.name == b.name)
return 0;
else
return -1;
}
/**
* utility function to sort property-arrays by key
*/
function sortProps(a, b) {
if (a > b)
return 1;
else if (a == b)
return 0;
else
return -1;
}
/**
* check access to an application or the whole server, authenticate against md5-encrypted
* properties of base-app or the particular application. if username or password aren't set
* go into stealth-mode and return a 404. if username|password are wrong, prepare response-
* object for http-auth and return false.
* @arg appObj application object to check against (if adminUsername etc are set in app.properties)
*/
function checkAuth(appObj) {
if (res && res.data.noWeb == true) {
return true;
}
var ok = false;
// check against root
var adminAccess = root.getProperty("adminAccess");
if (adminAccess == null || adminAccess == "") {
res.redirect(root.href("makekey"));
}
var uname = req.username;
var pwd = req.password;
if (uname == null || uname == "" || pwd == null || pwd == "")
return forceAuth();
var md5key = Packages.helma.util.MD5Encoder.encode(uname + "-" + pwd);
if (md5key == adminAccess)
return true;
if (appObj != null && appObj.isActive()) {
// check against application
adminAccess = appObj.getProperty("adminAccess");
if (md5key == adminAccess)
return true;
}
return forceAuth();
}
/**
* check access to the manage-app by ip-addresses
*/
function checkAddress() {
if (res && res.data.noWeb == true) {
return true;
}
// if allowadmin value in server.properties has changed,
// re-construct the addressFilter
if (app.data.addressString != root.getProperty("allowadmin")) {
app.data.addressFilter = createAddressFilter();
app.data.addressString = root.getProperty("allowadmin");
}
if (!app.data.addressFilter.matches(java.net.InetAddress.getByName(req.data.http_remotehost))) {
app.log("denied request from " + req.data.http_remotehost);
// forceStealth seems a bit like overkill here.
// display a message that the ip address must be added to server.properties
res.write("Access from address " + req.data.http_remotehost + " denied.");
return false;
} else {
return true;
}
}
/**
* response is reset to 401 / authorization required
* @arg realm realm for http-auth
*/
function forceAuth(realm) {
res.reset();
res.status = 401;
res.realm = (realm != null) ? realm : "helma";
res.write("Authorization Required. The server could not verify that you are authorized to access the requested page.");
return false;
}
/**
* macro-utility: formatting property lists
*/
function formatProperties(props, par) {
if (props.size() == 0)
return "";
var e = props.keys();
var arr = new Array();
while (e.hasMoreElements()) {
arr[arr.length] = e.nextElement();
}
arr.sort(sortProps);
for (var i in arr) {
// don't print the admin-password
if (arr[i].toLowerCase() == "adminusername" || arr[i].toLowerCase() == "adminpassword") continue;
res.write(par.itemprefix + arr[i] + par.separator + props.getProperty(arr[i]) + par.itemsuffix);
}
}
/**
* macro-utility: formatting an integer value as human readable bytes
*/
function formatBytes(bytes) {
if (bytes > Math.pow(2, 30)) {
res.write(Math.round(100 * bytes / Math.pow(2, 30)) / 100 + "gb");
} else if (bytes > Math.pow(2, 20)) {
res.write(Math.round(100 * bytes / Math.pow(2, 20)) / 100 + "mb");
} else {
res.write(Math.round(100 * bytes / Math.pow(2, 10)) / 100 + "kb");
}
}
/**
* macro-utility: formatting time in millis as human readable age
*/
function formatAge(age) {
var str = "";
var days = Math.floor(age / 86400);
age = age - days * 86400;
var hours = Math.floor(age / 3600);
age = age - hours * 3600;
var minutes = Math.floor(age / 60);
var seconds = Math.floor(age - minutes * 60);
if (days > 0)
str += (days + " days, ");
if (hours > 0)
str += (hours + "h, ");
str += (minutes + "min");
if (days == 0) str += (", " + seconds + "sec");
return(str);
}
/**
* macro-utility: formatting a number-suffix by choosing between singular and plural
* @arg value number to be formatted
* @arg param-object object to get fields
* @param singular string used for value==1
* @param plural string used for value!=1
*/
function formatCount(ct, par) {
if (!par || !par.singular || !par.plural) {
return "";
}
if (ct == 1)
return par.singular;
else
return par.plural;
}
/**
* tries to make out if this server is running linux from java's system properties
*/
function isLinux() {
var str = java.lang.System.getProperty("os.name");
return (str != null && str.toLowerCase().indexOf("linux") != -1);
}

View file

@ -0,0 +1,14 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd">
<html>
<% skin name="head" %>
<body bgcolor="white">
<table width="90%" border="0" cellspacing="1" cellpadding="5" bgcolor="#000000">
<tr>
<td width="30%" align="left" valign="top" bgcolor="#cccc99"><% skin name="navig" %></td>
<td width="70%" align="left" valign="top" bgcolor="#ffffff"><% response.body %></td>
</tr>
</table>
</body>
</html>

View file

@ -0,0 +1,59 @@
<head>
<title><% response.title %></title>
<style type="text/css">
<!--
body, p, td, th, li {
font-family: verdana, sans-serif;
font-size: 10pt;
}
.formEl {
border-color:#000000;
border-style:solid;
border-width:1px;
}
.list_apps {
border-color:#ffffff;
padding-top:5px;
padding-bottom:5px;
border-bottom-width:1px;
border-bottom-style:dotted;
}
.list_property {
border-color:#999999;
padding-top:5px;
padding-bottom:5px;
border-bottom-width:1px;
border-bottom-style:dotted;
}
.list_separator {
font-weight:bold;
background:#dfdfdf;
border-color:#999999;
padding-top:5px;
padding-bottom:5px;
border-bottom-width:1px;
border-bottom-style:dotted;
}
big {
font-size: 18pt;
font-weight: bold;
}
a {
font-weight:bold;
color: #cc3333;
text-decoration:none;
}
a:hover {
text-decoration:underline;
}
// -->
</style>
</head>

View file

@ -0,0 +1,18 @@
/**
* macro rendering a skin
* @param name name of skin
*/
function skin_macro(par) {
if (par && par.name) {
renderSkin(par.name);
}
}
/**
* Macro returning the actual date and time.
*/
function now_macro() {
var date = new Date();
return(date.format("dd.MM.yyyy, HH:mm'h' zzz"));
}

View file

@ -0,0 +1,30 @@
<p><a href="<% root.href action="main" %>"><img src="<% root.href action="image" %>" title="helma" border="0" width="174" height="35" align="baseline" style="border-width:3px;border-color:white;"></a>
</p>
<div class="list_apps">
<i><% root.appCount filter="active" singular=" app" plural=" apps"%> on
<a href="<% root.href action="main" %>"><% root.hostname %> (<% root.hostaddress %>)</a></i>
</div>
<% root.appList filter="active" %>
<p></p>
<div class="list_apps">
<i>disabled apps:</i>
</div>
<% root.appList filter="disabled" skin="navig_disabled" %>
<br/><br/>
<p>
Information on <a href="http://helma.org/">helma.org</a>:<br/>
<li><a href="http://helma.org/docs">reference</a><br/>
<li><a href="http://dev.helma.org/Mailing+Lists/">mailinglist</a><br/>
<li><a href="https://dev.helma.org/trac/helma/browser/helma/helma/trunk">svn</a><br/>
<li><a href="http://helma.org/download/">download</a><br/>
</p>
<p>
<li><a href="<% root.href action="makekey" %>">generate server password</a>
</p>

View file

@ -0,0 +1,20 @@
<body bgcolor="white">
<table width="500" border="0" cellspacing="0" cellpadding="5" bgcolor="#000000">
<tr>
<td width="500" align="left" valign="top" bgcolor="#ffffff">
<big>Generated username and password for helma's manager:</big><br>
<p>Please copy/paste this line into the server.properties file of your
helma installation.</p>
<pre><% param.propsString %></pre>
<p>After that proceed to <a href="<% root.href action="main" %>">the manage console</a>,
enter your credentials and you should be allowed in.</p>
</td></tr>
</table>
</body>

View file

@ -0,0 +1,28 @@
<body bgcolor="white">
<table width="500" border="0" cellspacing="0" cellpadding="5" bgcolor="#000000">
<tr>
<td width="500" align="left" valign="top" bgcolor="#ffffff">
<big>Username and password for helma's manager:</big><br>
<p>Please choose an username and password combination to access the
manage application of this server. They will be printed md5-encoded
in a format that you've got to copy/paste into the server.properties
file.</p>
<font color="red"><% param.msg %></font>
<form method="post">
<input class="formEl" name="username" size="25" value="<% param.username %>"> (username)<br>
<input class="formEl" type="password" name="password" size="25"> (password)<br>
<input class="formEl" type="submit" value="md5 encode"><br>
</form>
<p><b>Warning:</b> The used http-authorization transmits username and password
in an unsafe cleartext way. Therefore you're strongly discouraged to
use any given combination that is normally protected through SSH.</p>
</td></tr>
</table>
</body>

View file

@ -0,0 +1,153 @@
function renderLink(docEl, param) {
var text = "";
if (docEl.getType() == docEl.APPLICATION || docEl.getType() == docEl.PROTOTYPE) {
text = docEl.getName();
} else if (docEl.getType() == docEl.SKIN) {
text = docEl.getName() + ".skin";
} else if (docEl.getType() == docEl.MACRO) {
if (param.handler != "false" && docEl.getParentElement() && docEl.getParentElement().getName() != "global") {
text = docEl.getParentElement().getName() + ".";
}
var str = docEl.getName();
if (str.indexOf("_macro")) {
text += str.substring(0, str.length - 6);
}
} else if (docEl.getType() == docEl.FUNCTION) {
text = docEl.getName() + "(";
var arr = docEl.listParameters();
for (var i = 0; i < arr.length; i++) {
text += arr[i];
if (i < arr.length - 1)
text += ",&nbsp;";
}
text += ")";
} else {
text = docEl.getName();
}
param.href = docEl.href("main");
if (!param.target) {
param.target = "main";
}
return renderLinkTag(param) + text + '</a>';
}
function renderLinkTag(param) {
var sb = new java.lang.StringBuffer ();
sb.append('<a');
for (var i in param) {
sb.append(' ');
sb.append(i);
sb.append('="');
sb.append(param[i]);
sb.append('"');
}
sb.append('>');
return sb.toString();
}
/**
* renders the name of the location of a doc element.
*/
function renderLocation (docEl, param) {
return docEl.toString();
}
/**
* renders tag list.
* @param param.skin skin to render on found DocTags
* @param param.separator String printed between tags
* @param param.type type string (param|return|author|version|see) to filter tags.
*/
function renderTags(docEl, param) {
var skinname = (param.skin) ? param.skin : "main";
var type = param.type;
if (type == "params")
type = "param";
else if (type == "returns")
type = "return";
else if (type == "arg")
type = "param";
var str = "";
var arr = docEl.listTags();
for (var i = 0; i < arr.length; i++) {
if (arr[i].getType() == type) {
if (type == "see" || type == "overrides") {
param.link = renderReference(arr[i], docEl);
}
str += arr[i].renderSkinAsString(skinname, param);
str += (param.separator) ? param.separator : "";
}
}
return str;
}
/**
* renders a reference to functions in other prototypes, masks
* urls in a see tag
* (see- and overrides-tags)
* @param docTagObj
* @param docEl needed to be able to walk up to application object
*/
function renderReference(docTagObj, docEl) {
// prepare the text:
var text = docTagObj.getText();
text = new java.lang.String (text);
text = text.trim();
if (text.indexOf("http://") == 0) {
// an url is a simple job
return '<a href="' + text + '" target="_new">' + text + '</a>';
} else {
// make sure we only use the first item in the text so that unlinked comments
// can follow, store & split the that
var tok = new java.util.StringTokenizer (text);
var tmp = tok.nextToken();
text = " " + text.substring(tmp.length + 1);
var parts = tmp.split(".");
// try to find the application object
var obj = docEl;
while (obj != null) {
if (obj.getType() == Packages.helma.doc.DocElement.APPLICATION) {
var appObj = obj;
break;
}
obj = obj.getParentElement();
}
var protoObj = appObj.getChildElement("prototype_" + parts[0]);
if (protoObj == null) {
// prototype wasn't found, return the unlinked tag
return tmp + text;
}
if (parts.length == 1) {
// no function specified, return the linked prototype
return '<a href="' + protoObj.href("main") + '">' + format(tmp) + '</a>' + text;
}
// try to find a function object:
var arr = protoObj.listChildren();
for (var i = 0; i < arr.length; i++) {
if (arr[i].getName() == parts [1]) {
return '<a href="' + arr[i].href("main") + '">' + format(tmp) + '</a>' + text;
}
}
// function not found:
return tmp + text;
}
}
/**
* function rendering a comment.
* @param param.length comment is shortened to the given length.
* @returns string
*/
function renderComment(docEl, param) {
var str = docEl.getComment();
if (param.length) {
if (param.length < str.length) {
return str.substring(0, param.length) + " ...";
}
}
return str;
}