478 lines
15 KiB
JavaScript
478 lines
15 KiB
JavaScript
/**
|
|
* constructor function for site objects
|
|
* @param String Title
|
|
* @param String Alias
|
|
* @param Object Creator
|
|
*/
|
|
function constructor(title, alias, creator) {
|
|
this.title = title;
|
|
this.alias = alias;
|
|
this.creator = creator;
|
|
this.createtime = this.lastoffline = new Date();
|
|
this.email = creator.email;
|
|
this.online = 0;
|
|
this.blocked = 0;
|
|
this.trusted = creator.trusted;
|
|
this.enableping = 0;
|
|
|
|
// create initial preferences
|
|
var prefs = new HopObject();
|
|
prefs.tagline = null;
|
|
prefs.discussions = 1;
|
|
prefs.usercontrib = 0;
|
|
prefs.archive = 1;
|
|
prefs.days = 3;
|
|
// retrieve locale-object from root
|
|
var loc = root.getLocale();
|
|
prefs.language = loc.getLanguage();
|
|
prefs.country = loc.getCountry();
|
|
prefs.timezone = root.getTimeZone().getID();
|
|
prefs.longdateformat = "EEEE, dd. MMMM yyyy, h:mm a";
|
|
prefs.shortdateformat = "yyyy.MM.dd, HH:mm";
|
|
this.preferences_xml = Xml.writeToString(prefs);
|
|
return this;
|
|
}
|
|
|
|
/**
|
|
* function saves new properties of site
|
|
* @param Obj Object containing the form values
|
|
* @param Obj User-Object modifying this site
|
|
* @throws Exception
|
|
*/
|
|
|
|
function evalPreferences(param, modifier) {
|
|
if (!evalEmail(param.email))
|
|
throw new Exception("emailInvalid");
|
|
this.title = stripTags(param.title);
|
|
this.email = param.email;
|
|
if (this.online && !param.online)
|
|
this.lastoffline = new Date();
|
|
this.online = param.online ? 1 : 0;
|
|
this.enableping = param.enableping ? 1 : 0;
|
|
|
|
// store new preferences
|
|
var prefs = new HopObject();
|
|
for (var i in param) {
|
|
if (i.startsWith("preferences_"))
|
|
prefs[i.substring(12)] = param[i];
|
|
}
|
|
prefs.days = !isNaN(parseInt(param.preferences_days, 10)) ? parseInt(param.preferences_days, 10) : 3;
|
|
prefs.discussions = param.preferences_discussions ? 1 : 0;
|
|
prefs.usercontrib = param.preferences_usercontrib ? 1 : 0;
|
|
prefs.archive = param.preferences_archive ? 1 : 0;
|
|
// store selected locale
|
|
if (param.locale) {
|
|
var loc = param.locale.split("_");
|
|
prefs.language = loc[0];
|
|
prefs.country = loc.length == 2 ? loc[1] : null;
|
|
}
|
|
prefs.timezone = param.timezone;
|
|
prefs.longdateformat = param.longdateformat;
|
|
prefs.shortdateformat = param.shortdateformat;
|
|
|
|
// layout
|
|
this.layout = param.layout ? this.layouts.get(param.layout) : null;
|
|
|
|
// e-mail notification
|
|
prefs.notify_create = parseInt(param.notify_create, 10) || null;
|
|
prefs.notify_update = parseInt(param.notify_update, 10) || null;
|
|
prefs.notify_upload = parseInt(param.notify_upload, 10) || null;
|
|
|
|
// store preferences
|
|
this.preferences.setAll(prefs);
|
|
// call the evalPreferences method of every module
|
|
for (var i in app.modules)
|
|
this.applyModuleMethod(app.modules[i], "evalPreferences", param);
|
|
|
|
|
|
// reset cached locale, timezone and dateSymbols
|
|
this.cache.locale = null;
|
|
this.cache.timezone = null;
|
|
this.cache.dateSymbols = null;
|
|
|
|
this.modifytime = new Date();
|
|
this.modifier = modifier;
|
|
return new Message("update");
|
|
}
|
|
|
|
|
|
/**
|
|
* function checks if language and country were specified
|
|
* for this site. if so, it returns the specified Locale-object
|
|
* otherwise it calls getLocale() for root
|
|
*/
|
|
|
|
function getLocale() {
|
|
var locale = this.cache.locale;
|
|
if (locale)
|
|
return locale;
|
|
if (this.preferences.getProperty("language")) {
|
|
if (this.preferences.getProperty("country"))
|
|
locale = new java.util.Locale(this.preferences.getProperty("language"),
|
|
this.preferences.getProperty("country"));
|
|
else
|
|
locale = new java.util.Locale(this.preferences.getProperty("language"));
|
|
} else
|
|
locale = root.getLocale();
|
|
this.cache.locale =locale;
|
|
return locale;
|
|
}
|
|
|
|
/**
|
|
* function returns the (already cached) DateFormatSymbols according
|
|
* to the locale defined for a site
|
|
*/
|
|
function getDateSymbols() {
|
|
var symbols = this.cache.dateSymbols;
|
|
if (symbols)
|
|
return symbols;
|
|
this.cache.dateSymbols = new java.text.DateFormatSymbols(this.getLocale());
|
|
return this.cache.dateSymbols;
|
|
}
|
|
|
|
/**
|
|
* function returns the (already cached) TimeZone-Object
|
|
* according to site-preferences
|
|
*/
|
|
function getTimeZone() {
|
|
var tz = this.cache.timezone;
|
|
if (tz)
|
|
return tz;
|
|
if (this.preferences.getProperty("timezone"))
|
|
tz = java.util.TimeZone.getTimeZone(this.preferences.getProperty("timezone"));
|
|
else
|
|
tz = root.getTimeZone();
|
|
this.cache.timezone = tz;
|
|
return tz;
|
|
}
|
|
|
|
/**
|
|
* function deletes all assets of a site (recursive!)
|
|
*/
|
|
function deleteAll() {
|
|
this.images.deleteAll();
|
|
this.files.deleteAll();
|
|
// FIXME: add deleting of all layouts!
|
|
// this.layouts.deleteAll();
|
|
this.stories.deleteAll();
|
|
this.members.deleteAll();
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* send notification to weblogs.com
|
|
* that this site was updated
|
|
* @return Object with properties error and message
|
|
*/
|
|
|
|
function ping() {
|
|
var title = this.title ? this.title : this.alias;
|
|
|
|
// we're doing it the xml-rpc way
|
|
// (specs at http://newhome.weblogs.com/directory/11)
|
|
var xr = new Remote("http://rpc.weblogs.com/RPC2");
|
|
var ping = xr.weblogUpdates.ping(title, this.href());
|
|
if (!ping.result)
|
|
return;
|
|
var result = new Object();
|
|
result.error = ping.result.flerror;
|
|
result.message = ping.result.message;
|
|
|
|
if (result.error)
|
|
app.log("Error when notifying weblogs.com for updated site \"" + this.alias + "\": " + result.message);
|
|
|
|
// lastping is always set to now to prevent blogs
|
|
// hanging in the scheduler if a fatal error occurs
|
|
this.lastping = new Date();
|
|
return result;
|
|
}
|
|
|
|
|
|
/**
|
|
* href URL postprocessor. If a virtual host mapping is defined
|
|
* for this site's alias, use it. Otherwise, use normal site URL.
|
|
*/
|
|
function processHref(href) {
|
|
var vhost = app.properties["vhost." + this.alias];
|
|
if (vhost)
|
|
return vhost + href;
|
|
else
|
|
return app.properties.defaulthost + "/" + this.alias + href;
|
|
}
|
|
|
|
|
|
/**
|
|
* basic check if email notification is enabled for a site
|
|
* @param Obj site object
|
|
* @return Boolean true if notification is enabled, false otherwise
|
|
*/
|
|
function isNotificationEnabled() {
|
|
if (root.sys_allowEmails == 1 || root.sys_allowEmails == 2 && this.trusted)
|
|
return true;
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* send e-mail notification if necessary
|
|
* @param String type of changes (e.g. createStory)
|
|
* @param HopObject the HopObject the changes were applied to
|
|
*/
|
|
function sendNotification(type, obj) {
|
|
var notify = this.preferences.getProperty("notify_" + type);
|
|
if (obj.online === 0 || !notify || notify == 0)
|
|
return;
|
|
var recipients = new Array();
|
|
for (var i=0; i<this.members.size(); i++) {
|
|
var m = this.members.get(i);
|
|
if ((type != "update" && m.user == obj.creator) || (type == "update" && m.user == obj.modifier))
|
|
continue;
|
|
if (notify == 1 && m.level >= CONTENTMANAGER)
|
|
recipients.push(m.user.email);
|
|
else if (notify == 2 && m.level >= CONTRIBUTOR)
|
|
recipients.push(m.user.email);
|
|
}
|
|
if (recipients.length > 0) {
|
|
var param = {
|
|
user: obj.modifier ? obj.modifier.name :
|
|
(obj.creator ? obj.creator.name : null),
|
|
url: obj.href()
|
|
};
|
|
var sender = root.sys_title + "<" + root.sys_email + ">";
|
|
var subject = "[ + root.sys_title + "] " + getMessage("mail.notification");
|
|
var body = this.renderSkinAsString("notificationMail", param);
|
|
sendMail(sender, recipients, subject, body);
|
|
}
|
|
return;
|
|
}
|
|
|
|
/**
|
|
* return the currently enabled layout object
|
|
*/
|
|
function getLayout() {
|
|
if (this.layout)
|
|
return this.layout;
|
|
return root.getLayout();
|
|
}
|
|
|
|
/**
|
|
* render the path to the static directory
|
|
* of this site
|
|
* @param String name of subdirectory (optional)
|
|
*/
|
|
function staticPath(subdir) {
|
|
res.write(app.properties.staticPath);
|
|
res.write(this.alias);
|
|
res.write("/");
|
|
if (subdir)
|
|
res.write(subdir);
|
|
return;
|
|
}
|
|
|
|
/**
|
|
* return the path to the static directory
|
|
* of this site
|
|
* @param String name of subdirectory (optional)
|
|
* @return String path to the static directory
|
|
*/
|
|
function getStaticPath(subdir) {
|
|
res.push();
|
|
this.staticPath(subdir);
|
|
return res.pop();
|
|
}
|
|
|
|
/**
|
|
* render the url of the static directory
|
|
* of this site
|
|
* @param String optional subdirectory
|
|
*/
|
|
function staticUrl(subdir) {
|
|
res.write(app.properties.staticUrl);
|
|
res.write(this.alias);
|
|
res.write("/");
|
|
if (subdir)
|
|
res.write(subdir);
|
|
return;
|
|
}
|
|
|
|
/**
|
|
* return the url of the static directory
|
|
* of this site
|
|
* @param String optional subdirectory
|
|
* @return String static url
|
|
*/
|
|
function getStaticUrl(subdir) {
|
|
res.push();
|
|
this.staticUrl(subdir);
|
|
return res.pop();
|
|
}
|
|
|
|
/**
|
|
* return the directory containing static contents
|
|
* @param String subdirectory (optional)
|
|
* @return Object File object
|
|
*/
|
|
function getStaticDir(subdir) {
|
|
var f = new Helma.File(this.getStaticPath(subdir));
|
|
f.mkdir();
|
|
return f;
|
|
}
|
|
|
|
/**
|
|
* function returns the title of a site
|
|
*/
|
|
function getTitle() {
|
|
if (this.title && this.title.trim())
|
|
return stripTags(this.title);
|
|
else
|
|
return "[" + getMessage("generic.untitled") + "]";
|
|
}
|
|
|
|
|
|
/**
|
|
* function returns the used disk space for this site in Kilobyte
|
|
*/
|
|
function getDiskUsage() {
|
|
if (this.diskusage == null) {
|
|
this.diskusage = 0;
|
|
for (var i=0; i<this.files.count(); i++)
|
|
this.diskusage += this.files.get(i).filesize;
|
|
for (var i=0; i<this.images.count(); i++) {
|
|
if (this.images.get(i).filesize == null)
|
|
this.images.get(i).filesize = this.images.get(i).getFile().getLength();
|
|
this.diskusage += this.images.get(i).filesize;
|
|
}
|
|
}
|
|
return Math.round(this.diskusage / 1024);
|
|
}
|
|
|
|
|
|
/**
|
|
* function returns the disk quota in Kilobyte for this site
|
|
*/
|
|
function getDiskQuota() {
|
|
if (this.trusted || !root.sys_diskQuota)
|
|
return Infinity;
|
|
else
|
|
return root.sys_diskQuota;
|
|
}
|
|
|
|
|
|
/**
|
|
* returns the corresponding Index object for a site
|
|
* for performance reasons the Index object is cached
|
|
*/
|
|
function getIndex(force) {
|
|
if (!this.cache.index || force) {
|
|
var baseDir = new Helma.File(app.properties.indexPath);
|
|
var index, analyzer;
|
|
if (this.getLocale().getLanguage() == java.util.Locale.GERMAN)
|
|
analyzer = Search.getAnalyzer(java.util.Locale.GERMAN);
|
|
else
|
|
analyzer = Search.getAnalyzer();
|
|
// try to mount an existing index, if this fails create a new one
|
|
try {
|
|
index = Search.mountIndex(this.alias, baseDir, analyzer);
|
|
app.log("[" + this.alias + "] mounted index " + index);
|
|
} catch (e) {
|
|
try {
|
|
index = Search.createIndex(this.alias, baseDir, analyzer);
|
|
app.log("[" + this.alias + "] created index " + index);
|
|
} catch (e) {
|
|
throw ("[" + this.alias + "] Error: unable to mount or create index");
|
|
return;
|
|
}
|
|
}
|
|
this.cache.index = index;
|
|
}
|
|
return this.cache.index;
|
|
};
|
|
|
|
|
|
/**
|
|
* re-indexes all stories and comments of a site
|
|
* @param Object instance of Search.Index
|
|
* @return void
|
|
*/
|
|
function rebuildIndex() {
|
|
/**
|
|
* private method for constructing an index document
|
|
* based on the data retrieved via direct db
|
|
*/
|
|
function getIndexDocument() {
|
|
var doc = new Search.Document();
|
|
doc.addField("prototype", rows.getColumnItem("TEXT_PROTOTYPE"));
|
|
switch (rows.getColumnItem("TEXT_PROTOTYPE")) {
|
|
case "Comment":
|
|
doc.addField("story", rows.getColumnItem("TEXT_F_TEXT_STORY"), {store: true, index: true, tokenize: false});
|
|
if (parent = rows.getColumnItem("TEXT_F_TEXT_PARENT"))
|
|
doc.addField("parent", parent, {store: true, index: true, tokenize: false});
|
|
break;
|
|
default:
|
|
doc.addField("day", rows.getColumnItem("TEXT_DAY"), {store: true, index: true, tokenize: false});
|
|
if (topic = rows.getColumnItem("TEXT_TOPIC"))
|
|
doc.addField("topic", topic, {store: true, index: true, tokenize: true});
|
|
break;
|
|
}
|
|
|
|
doc.addField("online", rows.getColumnItem("TEXT_ISONLINE"), {store: true, index: true, tokenize: false});
|
|
doc.addField("site", self._id, {store: true, index: true, tokenize: false});
|
|
doc.addField("id", rows.getColumnItem("TEXT_ID"), {store: true, index: true, tokenize: false});
|
|
var content = Xml.readFromString(rows.getColumnItem("TEXT_CONTENT"));
|
|
for (var propName in content) {
|
|
doc.addField((propName == "title") ? "title" : "text",
|
|
stripTags(content[propName]),
|
|
{store: false, index: true, tokenize: true});
|
|
}
|
|
if (creator = rows.getColumnItem("USER_NAME")) {
|
|
doc.addField("creator", creator, {store: false, index: true, tokenize: false});
|
|
doc.addField("createtime", (new Date(rows.getColumnItem("TEXT_CREATETIME").getTime())).format("yyyyMMdd", locale, timeZone),
|
|
{store: false, index: true, tokenize: false});
|
|
}
|
|
return doc;
|
|
}
|
|
|
|
var parent, topic, title, text, creator;
|
|
// lock the index queue to prevent it
|
|
// from being flushed by the IndexManager
|
|
var queue = app.data.indexManager.getQueue(this);
|
|
queue.lock();
|
|
var index = this.getIndex();
|
|
index.clear();
|
|
|
|
var buf = new java.util.Vector(500, 500);
|
|
var cnt = 0;
|
|
var now = new Date();
|
|
var start = new Date();
|
|
var locale = this.getLocale();
|
|
var timeZone = this.getTimeZone();
|
|
var dbCon = getDBConnection("antville");
|
|
var rows = dbCon.executeRetrieval("select TEXT_ID, TEXT_PROTOTYPE, TEXT_DAY, TEXT_TOPIC, TEXT_ALIAS, TEXT_F_TEXT_STORY, TEXT_F_TEXT_PARENT, TEXT_PROTOTYPE, TEXT_ISONLINE, TEXT_CONTENT, USER_NAME, TEXT_CREATETIME from AV_TEXT, AV_USER where TEXT_F_SITE = " + this._id + " and TEXT_F_USER_CREATOR = USER_ID");
|
|
app.log("[" + this.alias + "] retrieved indexable contents in " + ((new Date()).diff(now)) + " ms");
|
|
if (dbCon.lastError != null) {
|
|
app.log("[" + this.alias + "] unable to retrieve indexable contents, reason: " + dbCon.lastError);
|
|
} else {
|
|
var self = this;
|
|
while (rows.next()) {
|
|
try {
|
|
buf.add(getIndexDocument());
|
|
if (cnt > 0 && cnt % 2000 == 0) {
|
|
index.addDocument(buf);
|
|
buf.clear();
|
|
app.log("[" + this.alias + "] added " + cnt + " documents to index (last 1000 in " + ((new Date()).diff(now)) + " ms)");
|
|
now = new Date();
|
|
}
|
|
} catch (e) {
|
|
app.log("[" + this.alias + "] Error: unable to add document " + cnt + " to index. Reason: " + e.toString());
|
|
}
|
|
cnt++;
|
|
}
|
|
rows.release();
|
|
index.addDocument(buf);
|
|
app.log("[" + this.alias + "] finished adding " + cnt + " documents to index in " + ((new Date()).diff(start)) + " ms");
|
|
index.optimize();
|
|
}
|
|
|
|
// unlock the queue again
|
|
queue.unlock();
|
|
return cnt;
|
|
}
|