919 lines
24 KiB
JavaScript
919 lines
24 KiB
JavaScript
// The Antville Project
|
||
// http://code.google.com/p/antville
|
||
//
|
||
// Copyright 2001–2014 by the Workers of Antville.
|
||
//
|
||
// Licensed under the Apache License, Version 2.0 (the ``License'');
|
||
// you may not use this file except in compliance with the License.
|
||
// You may obtain a copy of the License at
|
||
//
|
||
// http://www.apache.org/licenses/LICENSE-2.0
|
||
//
|
||
// Unless required by applicable law or agreed to in writing, software
|
||
// distributed under the License is distributed on an ``AS IS'' BASIS,
|
||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||
// See the License for the specific language governing permissions and
|
||
// limitations under the License.
|
||
|
||
/**
|
||
* @fileOverview Defines the Admin prototype.
|
||
*/
|
||
|
||
markgettext('export');
|
||
markgettext('import');
|
||
markgettext('remove');
|
||
|
||
Admin.MAXBATCHSIZE = 50;
|
||
|
||
/**
|
||
*
|
||
* @param {HopObject} target
|
||
* @param {String} method
|
||
* @param {User} user
|
||
* @constructor
|
||
*/
|
||
Admin.Job = function(target, method, user) {
|
||
if (!user) user = session.user;
|
||
|
||
var file, date;
|
||
|
||
this.__defineGetter__('target', function() {
|
||
return target;
|
||
});
|
||
|
||
this.__defineGetter__('method', function() {
|
||
return method;
|
||
});
|
||
|
||
this.__defineGetter__('user', function() {
|
||
return user;
|
||
});
|
||
|
||
this.__defineGetter__('name', function() {
|
||
return file.getName();
|
||
});
|
||
|
||
this.__defineGetter__('date', function() {
|
||
return date;
|
||
});
|
||
|
||
this.remove = function(isCareless) {
|
||
// isCareless is `true` after a site is completely removed, to prevent NullPointer exception
|
||
if (!isCareless) target.job = null;
|
||
if (file.exists()) file['delete']();
|
||
};
|
||
|
||
if (target && method && user) {
|
||
file = new java.io.File.createTempFile('job-', String.EMPTY, Admin.queue.dir);
|
||
serialize({type: target._prototype, id: target._id, method: method, user: user._id}, file);
|
||
} else if (target) {
|
||
file = new java.io.File(Admin.queue.dir, target);
|
||
if (file.exists()) {
|
||
var data = deserialize(file);
|
||
target = global[data.type].getById(data.id);
|
||
method = data.method;
|
||
user = User.getById(data.user);
|
||
date = new Date(file.lastModified());
|
||
}
|
||
} else {
|
||
throw Error('Insufficient arguments');
|
||
}
|
||
|
||
this.toString = function() {
|
||
return ['[Job: ', method, ' ', target, ' by ', user, ']'].join(String.EMPTY);
|
||
}
|
||
|
||
return this;
|
||
}
|
||
|
||
/**
|
||
* @function
|
||
* @returns {String[]}
|
||
* @see defineConstants
|
||
*/
|
||
Admin.getNotificationScopes = defineConstants(Admin, markgettext('None'), markgettext('Trusted'), markgettext('Regular'));
|
||
|
||
/**
|
||
* @function
|
||
* @return {String[]}
|
||
* @see defineConstants
|
||
*/
|
||
Admin.getPhaseOutModes = defineConstants(Admin, markgettext('Disabled'), markgettext('Restricted'), markgettext('Abandoned'), markgettext('Both'));
|
||
|
||
/**
|
||
* @function
|
||
* @returns {String[]}
|
||
* @see defineConstants
|
||
*/
|
||
Admin.getCreationScopes = defineConstants(Admin, markgettext('Privileged'), markgettext('Trusted'), markgettext('Regular'));
|
||
|
||
/**
|
||
* @function
|
||
* @returns {String[]}
|
||
* @see defineConstants
|
||
*/
|
||
Admin.getLoginScopes = defineConstants(Admin, markgettext('Privileged'), markgettext('Trusted'), markgettext('Regular'), markgettext('None'));
|
||
|
||
/**
|
||
* Convenience method for easily queueing jobs.
|
||
* @param {HopObject} target
|
||
* @param {String} method
|
||
* @param {User} user
|
||
* @returns {String}
|
||
* @see Admin.Job
|
||
*/
|
||
Admin.queue = function(target, method, user) {
|
||
var job = new Admin.Job(target, method, user || session.user);
|
||
return job.name;
|
||
}
|
||
|
||
/**
|
||
*
|
||
*/
|
||
Admin.queue.dir = (new java.io.File(app.dir, '../jobs')).getCanonicalFile();
|
||
Admin.queue.dir.exists() || Admin.queue.dir.mkdirs();
|
||
|
||
/**
|
||
*
|
||
*/
|
||
Admin.dequeue = function() {
|
||
var jobs = Admin.getJobs('desc');
|
||
var max = Math.min(jobs.length, Admin.MAXBATCHSIZE);
|
||
for (let i=0; i<max; i+=1) {
|
||
let job = new Admin.Job(jobs[i].name);
|
||
if (job.target) {
|
||
try {
|
||
app.log('Processing queued job ' + (i + 1) + ' of ' + max);
|
||
switch (job.method) {
|
||
case 'remove':
|
||
if (job.target.constructor === Site) Site.remove.call(job.target);
|
||
if (job.target.constructor === User) User.remove.call(job.target);
|
||
break;
|
||
case 'import':
|
||
Importer.run(job.target, job.user);
|
||
break;
|
||
case 'export':
|
||
Exporter.run(job.target, job.user);
|
||
break;
|
||
}
|
||
job.remove(true);
|
||
} catch (ex) {
|
||
app.log('Failed to process job ' + job + ' due to ' + ex);
|
||
app.debug(ex.rhinoException);
|
||
}
|
||
}
|
||
}
|
||
return;
|
||
}
|
||
|
||
Admin.getJobs = function(sort) {
|
||
if (!sort) sort = 'asc';
|
||
return Admin.queue.dir.listFiles().sort((a, b) => {
|
||
return (a.lastModified() - b.lastModified()) * (sort === 'asc' ? -1 : 1);
|
||
});
|
||
};
|
||
|
||
Admin.purgeAccounts = function() {
|
||
var now = Date.now();
|
||
|
||
root.admin.deletedUsers.forEach(function() {
|
||
if (this.job || this.deleted) return; // already gone
|
||
this.job = Admin.queue(this, 'remove', this);
|
||
});
|
||
};
|
||
|
||
Admin.purgeSites = function() {
|
||
var now = new Date;
|
||
|
||
root.admin.deletedSites.forEach(function() {
|
||
if (this.job) return;
|
||
this.job = Admin.queue(this, 'remove', this.modifier);
|
||
});
|
||
|
||
var notificationPeriod = root.phaseOutNotificationPeriod * Date.ONEDAY;
|
||
var gracePeriod = root.phaseOutGracePeriod * Date.ONEDAY;
|
||
|
||
var phaseOutAbandonedSites = function() {
|
||
root.forEach(function() {
|
||
if (this.status === Site.TRUSTED) {
|
||
return;
|
||
}
|
||
var age = now - (this.stories.size() > 0 ?
|
||
this.stories.get(0).modified : this.modified);
|
||
if (age - notificationPeriod > 0) {
|
||
if (!this.notified) {
|
||
var site = res.handlers.site = this;
|
||
this.members.owners.forEach(function() {
|
||
res.handlers.membership = this;
|
||
sendMail(this.creator.email,
|
||
gettext('[{0}] Warning: Site will be deleted'),
|
||
site.renderSkinAsString('$Site#notify_delete'));
|
||
});
|
||
this.notified = now;
|
||
} else if (now - this.notified > gracePeriod) {
|
||
this.status = Site.DELETED;
|
||
this.deleted = now;
|
||
this.notified = null;
|
||
}
|
||
}
|
||
});
|
||
return;
|
||
}
|
||
|
||
var phaseOutRestrictedSites = function() {
|
||
root.admin.restrictedSites.forEach(function() {
|
||
if (this.status === Site.TRUSTED) {
|
||
return;
|
||
}
|
||
var age = now - this.created;
|
||
if (age - notificationPeriod > 0) {
|
||
if (!this.notified) {
|
||
var site = res.handlers.site = this;
|
||
this.members.owners.forEach(function() {
|
||
res.handlers.membership = this;
|
||
sendMail(this.creator.email,
|
||
gettext('[{0}] Warning: Site will be blocked'),
|
||
site.renderSkinAsString('$Site#notify_block'));
|
||
});
|
||
this.notified = now;
|
||
} else if (now - this.notified > gracePeriod) {
|
||
this.status = Site.BLOCKED;
|
||
this.notified = null;
|
||
}
|
||
}
|
||
});
|
||
return;
|
||
}
|
||
|
||
switch (root.phaseOutMode) {
|
||
case Admin.ABANDONED:
|
||
return phaseOutAbandonedSites();
|
||
case Admin.RESTRICTED:
|
||
return phaseOutRestrictedSites();
|
||
case Admin.BOTH:
|
||
phaseOutAbandonedSites();
|
||
return phaseOutRestrictedSites();
|
||
}
|
||
return;
|
||
}
|
||
|
||
/**
|
||
*
|
||
*/
|
||
Admin.purgeReferrers = function() {
|
||
var sql = new Sql;
|
||
var result = sql.execute(Sql.PURGEREFERRERS);
|
||
return result;
|
||
}
|
||
|
||
/**
|
||
*
|
||
*/
|
||
Admin.commitRequests = function() {
|
||
var requests = app.data.requests;
|
||
app.data.requests = {};
|
||
for each (var item in requests) {
|
||
switch (item.type) {
|
||
case Story:
|
||
var story = Story.getById(item.id);
|
||
story && (story.requests = item.requests);
|
||
break;
|
||
}
|
||
}
|
||
res.commit();
|
||
return;
|
||
}
|
||
|
||
/**
|
||
*
|
||
*/
|
||
Admin.commitEntries = function() {
|
||
var entries = app.data.entries;
|
||
app.data.entries = [];
|
||
var history = [];
|
||
|
||
for each (var item in entries) {
|
||
var referrer = helma.Http.evalUrl(item.referrer);
|
||
if (!referrer) {
|
||
continue;
|
||
}
|
||
|
||
// Only log unique combinations of context, ip and referrer
|
||
referrer = Admin.resolveUrl(referrer);
|
||
var key = item.context._prototype + '-' + item.context._id + ':' +
|
||
item.ip + ':' + referrer;
|
||
if (history.indexOf(key) > -1) {
|
||
continue;
|
||
}
|
||
history.push(key);
|
||
item.referrer = referrer;
|
||
|
||
// Exclude requests coming from the same site
|
||
if (item.site) {
|
||
var href = item.site.href().toLowerCase();
|
||
if (href.startsWith('http') &&
|
||
referrer.toLowerCase().contains(href.substr(0, href.length-1))) {
|
||
continue;
|
||
}
|
||
}
|
||
item.persist();
|
||
}
|
||
|
||
res.commit();
|
||
return;
|
||
}
|
||
|
||
/**
|
||
*
|
||
*/
|
||
Admin.invokeCallbacks = function() {
|
||
var http = helma.Http();
|
||
http.setTimeout(200);
|
||
http.setReadTimeout(300);
|
||
http.setMethod('POST');
|
||
|
||
var ref, site, item;
|
||
while (ref = app.data.callbacks.pop()) {
|
||
site = Site.getById(ref.site);
|
||
item = ref.handler && ref.handler.getById(ref.id);
|
||
if (!site || !item) {
|
||
continue;
|
||
}
|
||
app.log('Invoking callback URL ' + site.callbackUrl + ' for ' + item);
|
||
try {
|
||
http.setContent({
|
||
type: item.constructor.name,
|
||
id: item.name || item._id,
|
||
url: item.href(),
|
||
date: item.modified.valueOf(),
|
||
user: item.modifier.name,
|
||
site: site.title || site.name,
|
||
origin: site.href()
|
||
});
|
||
http.getUrl(site.callbackUrl);
|
||
} catch (ex) {
|
||
app.debug('Invoking callback URL ' + site.callbackUrl + ' failed: ' + ex);
|
||
}
|
||
}
|
||
return;
|
||
}
|
||
|
||
/**
|
||
*
|
||
*/
|
||
Admin.updateHealth = function() {
|
||
var health = Admin.health || {};
|
||
if (!health.modified || new Date - health.modified > 5 * Date.ONEMINUTE) {
|
||
health.modified = new Date;
|
||
health.requestsPerUnit = app.requestCount - (health.currentRequestCount || 0);
|
||
health.currentRequestCount = app.requestCount;
|
||
health.errorsPerUnit = app.errorCount - (health.currentErrorCount || 0);
|
||
health.currentErrorCount = app.errorCount;
|
||
Admin.health = health;
|
||
}
|
||
return;
|
||
}
|
||
|
||
/**
|
||
*
|
||
*/
|
||
Admin.updateDomains = function() {
|
||
res.push();
|
||
for (var key in app.properties) {
|
||
if (key.startsWith('domain.') && !key.endsWith('*')) {
|
||
res.writeln(getProperty(key) + '\t\t' + key.substr(7));
|
||
}
|
||
}
|
||
var map = res.pop();
|
||
var file = new java.io.File(app.dir, 'domains.map');
|
||
var out = new java.io.BufferedWriter(new java.io.OutputStreamWriter(
|
||
new java.io.FileOutputStream(file), 'UTF-8'));
|
||
out.write(map);
|
||
out.close();
|
||
return;
|
||
}
|
||
|
||
Admin.resolveUrl = function(url) {
|
||
var http = new helma.Http();
|
||
http.setMethod('HEAD');
|
||
http.setFollowRedirects(false);
|
||
|
||
var response;
|
||
var location = url;
|
||
|
||
while (location) {
|
||
try {
|
||
response = http.getUrl(location);
|
||
location = response.location;
|
||
} catch (error) {
|
||
location = null;
|
||
}
|
||
};
|
||
|
||
return String(response ? response.url : url);
|
||
};
|
||
|
||
/**
|
||
* The Admin prototype is mounted at root and provides actions needed
|
||
* for system administration. A user needs the User.PRIVILEGED permission
|
||
* to gain access or modify settings.
|
||
* @name Admin
|
||
* @constructor
|
||
* @property {Sites[]} deletedSites Contains sites scheduled for deletion
|
||
* @property {LogEntry[]} entries Contains administrative log entries only
|
||
* @property {Sites[]} restrictedSites Contains sites which are restricted but not blocked
|
||
* @property {Sites[]} sites Contains all available sites
|
||
* @property {Users[]} users Contains all available users
|
||
* @extends HopObject
|
||
*/
|
||
Admin.prototype.constructor = function() {
|
||
this.filterSites();
|
||
this.filterUsers();
|
||
return this;
|
||
}
|
||
|
||
/**
|
||
*
|
||
* @param {Object} action
|
||
* @returns {Boolean}
|
||
*/
|
||
Admin.prototype.getPermission = function(action) {
|
||
return User.require(User.PRIVILEGED);
|
||
}
|
||
|
||
/**
|
||
*
|
||
*/
|
||
Admin.prototype.onRequest = function() {
|
||
HopObject.prototype.onRequest.apply(this);
|
||
if (!session.data.admin) {
|
||
session.data.admin = new Admin();
|
||
}
|
||
return;
|
||
}
|
||
|
||
/**
|
||
*
|
||
* @param {String} name
|
||
*/
|
||
Admin.prototype.onUnhandledMacro = function(name) {
|
||
console.warn('Add ' + name + '_macro to Admin!');
|
||
return null;
|
||
}
|
||
|
||
Admin.prototype.main_action = function() {
|
||
if (req.postParams.save) {
|
||
try {
|
||
this.update(req.postParams);
|
||
this.log(root, 'setup');
|
||
res.message = gettext('Successfully updated the setup.');
|
||
res.redirect(this.href(req.action));
|
||
} catch (ex) {
|
||
res.message = ex;
|
||
app.log(ex);
|
||
}
|
||
}
|
||
|
||
res.data.title = gettext('Setup');
|
||
res.data.action = this.href(req.action);
|
||
res.data.body = this.renderSkinAsString('$Admin#setup');
|
||
root.renderSkin('Site#page');
|
||
return;
|
||
}
|
||
|
||
Admin.prototype.activity_action = function () {
|
||
if (req.isPost()) {
|
||
session.data.display = req.postParams.display;
|
||
session.data.order = req.postParams.order;
|
||
session.data.filter = req.postParams.filter;
|
||
} else if (!req.data.page) {
|
||
session.data.display = session.data.order = session.data.filter = null;
|
||
}
|
||
|
||
var constraints = {order: 'created desc', limit: 1000};
|
||
var sites = Site.getCollection(constraints);
|
||
var stories = Story.getCollection(constraints);
|
||
var comments = Comment.getCollection(constraints);
|
||
var images = Image.getCollection(constraints);
|
||
var files = File.getCollection(constraints);
|
||
var polls = Poll.getCollection(constraints);
|
||
var users = User.getCollection(constraints);
|
||
|
||
var displays = {
|
||
1: [stories, images, files, polls],
|
||
2: [comments],
|
||
3: [stories, comments],
|
||
4: [files],
|
||
5: [images],
|
||
6: [polls],
|
||
7: [sites],
|
||
8: [users]
|
||
};
|
||
|
||
var lists = displays[session.data.display] || [sites, stories, images, files, polls, users];
|
||
lists = lists.map(function (collection) {
|
||
return collection.list();
|
||
});
|
||
|
||
var union = Array.prototype.concat.apply([], lists);
|
||
union.sort(new Number.Sorter('created', Number.Sorter.DESC));
|
||
(session.data.order == 1) && union.reverse();
|
||
|
||
if (session.data.filter) {
|
||
var filter = '^' + session.data.filter.replace(/(\W\D[*])/g, '$1').replace(/\*/g, '.*') + '$';
|
||
var re = new RegExp(filter.toLowerCase());
|
||
union = union.filter(function (item) {
|
||
return re.test((item.creator ? item.creator.name : item.name).toLowerCase());
|
||
});
|
||
}
|
||
|
||
if (session.data.display == 3 /* link activity */) {
|
||
union = union.filter(function (item) {
|
||
return getLinkCount(item) > 0;
|
||
});
|
||
}
|
||
|
||
res.data.count = union.length;
|
||
res.data.list = renderList(union, this.renderActivity, 25, req.queryParams.page);
|
||
res.data.pager = renderPager(union, this.href(req.action), 25, req.queryParams.page);
|
||
res.data.title = gettext('Activity');
|
||
res.data.action = this.href(req.action);
|
||
res.data.body = this.renderSkinAsString('$Admin#activities');
|
||
root.renderSkin('Site#page');
|
||
return;
|
||
}
|
||
|
||
Admin.prototype.jobs_action = function() {
|
||
var files = Admin.getJobs();
|
||
res.data.count = files.length;
|
||
res.data.list = renderList(files, this.renderItem);
|
||
res.data.title = gettext('Jobs');
|
||
res.data.action = this.href(req.action);
|
||
res.data.body = this.renderSkinAsString('$Admin#jobs');
|
||
root.renderSkin('Site#page');
|
||
return;
|
||
};
|
||
|
||
Admin.prototype.job_action = function () {
|
||
if (req.data.name) {
|
||
const job = new Admin.Job(req.data.name);
|
||
job.remove();
|
||
}
|
||
return res.redirect(req.data.http_referer);
|
||
};
|
||
|
||
Admin.prototype.sites_action = function() {
|
||
if (req.isPost()) {
|
||
session.data.display = req.postParams.display;
|
||
session.data.sorting = req.postParams.sorting;
|
||
session.data.order = req.postParams.order;
|
||
session.data.filter = req.postParams.filter;
|
||
} else if (!req.data.page) {
|
||
session.data.display = session.data.sorting = session.data.order = session.data.filter = null;
|
||
}
|
||
session.data.admin.filterSites(session.data);
|
||
res.data.count = session.data.admin.sites.size();
|
||
res.data.list = renderList(session.data.admin.sites, this.renderItem, 25, req.queryParams.page);
|
||
res.data.pager = renderPager(session.data.admin.sites, this.href(req.action), 25, req.data.page);
|
||
res.data.title = gettext('Sites');
|
||
res.data.action = this.href(req.action);
|
||
res.data.body = this.renderSkinAsString('$Admin#sites');
|
||
root.renderSkin('Site#page');
|
||
return;
|
||
}
|
||
|
||
Admin.prototype.users_action = function() {
|
||
if (req.isPost()) {
|
||
session.data.display = req.postParams.display;
|
||
session.data.sorting = req.postParams.sorting;
|
||
session.data.order = req.postParams.order;
|
||
session.data.filter = req.postParams.filter;
|
||
} else if (!req.data.page) {
|
||
session.data.display = session.data.sorting = session.data.order = session.data.filter = null;
|
||
}
|
||
session.data.admin.filterUsers(session.data);
|
||
res.data.count = session.data.admin.users.size();
|
||
res.data.list = renderList(session.data.admin.users, this.renderItem, 25, req.data.page);
|
||
res.data.pager = renderPager(session.data.admin.users, this.href(req.action), 25, req.data.page);
|
||
res.data.title = gettext('Accounts');
|
||
res.data.action = this.href(req.action);
|
||
res.data.body = this.renderSkinAsString('$Admin#users');
|
||
root.renderSkin('Site#page');
|
||
return;
|
||
}
|
||
|
||
/**
|
||
*
|
||
* @param {Object} data
|
||
*/
|
||
Admin.prototype.update = function(data) {
|
||
root.map({
|
||
creationScope: data.creationScope,
|
||
creationDelay: data.creationDelay,
|
||
loginScope: data.loginScope,
|
||
notificationScope: data.notificationScope,
|
||
phaseOutGracePeriod: data.phaseOutGracePeriod,
|
||
phaseOutMode: data.phaseOutMode,
|
||
phaseOutNotificationPeriod: data.phaseOutNotificationPeriod,
|
||
privacyStory: data.privacyStory,
|
||
probationPeriod: data.probationPeriod,
|
||
quota: data.quota,
|
||
replyTo: data.replyTo,
|
||
termsStory: data.termsStory
|
||
});
|
||
return;
|
||
}
|
||
|
||
/**
|
||
*
|
||
* @param {Object} data
|
||
*/
|
||
Admin.prototype.filterSites = function(data) {
|
||
data || (data = {});
|
||
|
||
var displays = {
|
||
1: "status = 'blocked'",
|
||
2: "status = 'deleted'",
|
||
3: "status = 'trusted'",
|
||
4: "mode = 'open'",
|
||
5: "mode = 'restricted'",
|
||
6: "mode = 'public'",
|
||
7: "mode = 'closed'"
|
||
};
|
||
|
||
var sortings = {
|
||
1: 'created',
|
||
2: 'name'
|
||
};
|
||
|
||
var sql = ['where'];
|
||
add(displays[data.display] || true);
|
||
|
||
if (data.filter) {
|
||
var parts = stripTags(data.filter).split(String.SPACE);
|
||
var keyword, like;
|
||
for (var i in parts) {
|
||
keyword = parts[i].replace(/\*/g, '%');
|
||
like = keyword.contains('%') ? 'like' : '=';
|
||
add(i < 1 ? 'and' : 'or', 'name', like, quote(keyword));
|
||
}
|
||
}
|
||
|
||
add('order by', sortings[data.sorting] || 'modified', data.order === '1' ? 'asc' : 'desc');
|
||
this.sites.subnodeRelation = sql.join(String.SPACE);
|
||
|
||
function add() {
|
||
sql.push.apply(sql, arguments);
|
||
}
|
||
}
|
||
|
||
/**
|
||
*
|
||
* @param {Object} data
|
||
*/
|
||
Admin.prototype.filterUsers = function(data) {
|
||
data || (data = {});
|
||
|
||
var displays = {
|
||
1: "status = 'deleted'",
|
||
2: "status = 'blocked'",
|
||
3: "status = 'trusted'",
|
||
4: "status = 'privileged'"
|
||
};
|
||
|
||
var sortings = {
|
||
1: 'modified',
|
||
2: 'name'
|
||
};
|
||
|
||
var sql = ['where'];
|
||
add(displays[data.display] || true);
|
||
|
||
if (data.filter) {
|
||
var parts = stripTags(data.filter).split(String.SPACE);
|
||
var keyword, like;
|
||
for (var i in parts) {
|
||
add(i < 1 ? 'and' : 'or');
|
||
keyword = parts[i].replace(/\*/g, '%');
|
||
like = keyword.contains('%') ? 'like' : '=';
|
||
if (keyword.contains('@')) {
|
||
add('email');
|
||
keyword = keyword.replace(/@/g, '');
|
||
} else {
|
||
add('name');
|
||
}
|
||
add(like, quote(keyword));
|
||
}
|
||
}
|
||
|
||
add('order by', sortings[data.sorting] || 'created', data.order === '1' ? 'asc' : 'desc');
|
||
this.users.subnodeRelation = sql.join(String.SPACE);
|
||
|
||
function add() {
|
||
sql.push.apply(sql, arguments);
|
||
}
|
||
}
|
||
|
||
/**
|
||
*
|
||
* @param {HopObject} item
|
||
*/
|
||
Admin.prototype.renderItem = function(item) {
|
||
res.handlers.item = item;
|
||
var name = item._prototype;
|
||
if (item.getClass && item.getClass() === java.io.File) {
|
||
name = 'Job';
|
||
res.handlers.item = new Admin.Job(item.name);
|
||
} else if (name === 'Root') {
|
||
name = 'Site';
|
||
}
|
||
Admin.prototype.renderSkin('$Admin#' + name.toLowerCase());
|
||
return;
|
||
}
|
||
|
||
Admin.prototype.renderActivity = function (item, skin) {
|
||
if (!skin) skin = '$Admin#activity';
|
||
|
||
var param = {
|
||
item: item,
|
||
icon: getIcon(item),
|
||
date: item.created,
|
||
reference: getReference(item),
|
||
user: item.creator ? item.creator.name : item.name,
|
||
href: item.href(item.constructor === User ? 'edit' : ''),
|
||
linkCount: getLinkCount(item),
|
||
alert: getAlert(item),
|
||
site: (item.parent && item.parent.site || item.parent || item.site || {}).name
|
||
};
|
||
|
||
param.warn = param.linkCount > 2 ? true : false;
|
||
|
||
Admin.prototype.renderSkin(skin, param);
|
||
|
||
function getReference(item) {
|
||
switch (item.constructor) {
|
||
case Root:
|
||
case Site:
|
||
return item.getTitle();
|
||
case Comment:
|
||
case Story:
|
||
return item.getAbstract();
|
||
case File:
|
||
return item.name;
|
||
case User:
|
||
return item.email
|
||
case Image:
|
||
res.push();
|
||
item.thumbnail_macro({'class': 'uk-thumbnail'}, 'thumbnail');
|
||
return res.pop();
|
||
case Poll:
|
||
return item.question;
|
||
}
|
||
}
|
||
|
||
function getIcon(item) {
|
||
var name;
|
||
switch (item.constructor) {
|
||
case Root:
|
||
case Site:
|
||
res.push();
|
||
html.element('i', String.EMPTY, {'class': 'av-ant'});
|
||
return res.pop();
|
||
case Comment:
|
||
name = 'comment-o';
|
||
break;
|
||
case Story:
|
||
name = 'newspaper-o';
|
||
break
|
||
case File:
|
||
name = 'file-o';
|
||
break;
|
||
case Image:
|
||
name = 'image';
|
||
break;
|
||
case User:
|
||
name = 'user';
|
||
break;
|
||
case Poll:
|
||
name = 'bar-chart';
|
||
break;
|
||
}
|
||
return "<i class='uk-icon uk-icon-" + name + "'></i>";
|
||
}
|
||
|
||
function getAlert(item) {
|
||
switch (item.constructor) {
|
||
case User:
|
||
return item.status !== User.BLOCKED && item.status !== User.DELETED && item.created - item.modified < 1;
|
||
case Site:
|
||
return item.status !== Site.DELETED && item.created - item.modified < 1;
|
||
}
|
||
return false;
|
||
}
|
||
};
|
||
|
||
/**
|
||
*
|
||
* @param {HopObject} context
|
||
* @param {String} action
|
||
*/
|
||
Admin.prototype.log = function(context, action) {
|
||
var entry = new LogEntry(context, action);
|
||
this.entries.add(entry);
|
||
return;
|
||
}
|
||
|
||
/**
|
||
*
|
||
* @param {Object} param
|
||
* @param {String} action
|
||
* @param {Number} id
|
||
* @param {String} text
|
||
*/
|
||
|
||
Admin.prototype.href_macro = function (param, action, id) {
|
||
res.write(this.href.call(this, action, id));
|
||
return;
|
||
};
|
||
|
||
Admin.prototype.href = function (action, id) {
|
||
switch (action) {
|
||
case 'main':
|
||
action = '.';
|
||
break;
|
||
}
|
||
return root.href('admin') + '/' + action;
|
||
};
|
||
|
||
/**
|
||
*
|
||
* @param {Object} param
|
||
* @param {String} name
|
||
*/
|
||
Admin.prototype.skin_macro = function(param, name) {
|
||
if (this.getPermission('main')) {
|
||
return HopObject.prototype.skin_macro.apply(this, arguments);
|
||
}
|
||
return;
|
||
}
|
||
|
||
/**
|
||
*
|
||
* @param {Object} param
|
||
* @param {HopObject} object
|
||
* @param {String} name
|
||
*/
|
||
Admin.prototype.items_macro = function(param, object, name) {
|
||
if (!object || !object.size) {
|
||
return;
|
||
}
|
||
var max = Math.min(object.size(), parseInt(param.limit) || 10);
|
||
for (var i=0; i<max; i+=1) {
|
||
html.link({href: object.get(i).href()}, '#' + (object.size()-i) + ' ');
|
||
}
|
||
return;
|
||
}
|
||
|
||
/**
|
||
*
|
||
* @param {Object} param
|
||
*/
|
||
Admin.prototype.dropdown_macro = function(param /*, value1, value2, ... */) {
|
||
if (!param.name || arguments.length < 2) {
|
||
return;
|
||
}
|
||
var values = Array.prototype.slice.call(arguments, 1);
|
||
var options = values.map(function(item, index) {
|
||
return {
|
||
value: index,
|
||
display: gettext(item)
|
||
}
|
||
});
|
||
var selectedIndex = req.postParams[param.name] || session.data[param.name];
|
||
html.dropDown({name: param.name}, options, selectedIndex);
|
||
return;
|
||
}
|
||
|
||
Admin.prototype.link_macro = function (param, action, text, target) {
|
||
if (target) {
|
||
switch (action) {
|
||
case 'block':
|
||
var user = target.creator || target;
|
||
if (user.status !== User.PRIVILEGED && user.status !== User.BLOCKED && user.status !== User.DELETED) {
|
||
var url = user.href('block');
|
||
return renderLink.call(global, param, url, text || String.EMPTY, this);
|
||
}
|
||
break;
|
||
|
||
case 'delete':
|
||
var site = target.constructor === Site ? target : target.site;
|
||
if (site && site.getPermission(action) && site.status !== Site.DELETED) {
|
||
var url = site.href('delete') + '?safemode';
|
||
return renderLink.call(global, param, url, text || String.EMPTY, this);
|
||
}
|
||
break;
|
||
}
|
||
return;
|
||
}
|
||
return HopObject.prototype.link_macro.call(this, param, action, text);
|
||
};
|