place/threads: web posting & commenting, entry edit, new settings; place/archetype.gen: _request_set_default_(text|list|bool)

place/threads new features:
 - add/comment forms after /login @ place url (cookie auth)
 - new settings: /place showform|showcomments|addaction|editaction
This commit is contained in:
Gabor Adam Toth 2010-03-01 03:50:58 +01:00
parent 5f15785e9e
commit 7ffe715010
7 changed files with 389 additions and 237 deletions

View File

@ -80,35 +80,47 @@ private volatile mapping _sigs = ([
"_request_ni": ({ "_request_nick_local", 0, "_nick_local", "_INTERNAL_stuss" }),
"_request_public": ({ "_request_public", 0, "_flag_public" }),
"_request_pub": ({ "_request_public", 0, "_flag_public" }),
// threads
"_request_entries": ({ "_request_entries", 0, "_num" }),
"_request_ents": ({ "_request_entries", 0, "_num" }),
"_request_entry": ({ "_request_entry", 0, "_id" }),
"_request_ent": ({ "_request_entry", 0, "_id" }),
"_request_comment": ({ "_request_comment", 0, "_id", "_text" }),
"_request_com": ({ "_request_comment", 0, "_id", "_text" }),
"_request_title": ({ "_request_title", 0, "_id", "_title" }),
"_request_addentry": ({ "_request_addentry", 0, "_text" }),
"_request_addent": ({ "_request_addentry", 0, "_text" }),
"_request_submit": ({ "_request_addentry", 0, "_text" }),
"_request_blog": ({ "_request_addentry", 0, "_text" }),
"_request_delentry": ({ "_request_delentry", 0, "_id" }),
"_request_delent": ({ "_request_delentry", 0, "_id" }),
"_request_unsubmit": ({ "_request_delentry", 0, "_id" }),
"_request_unblog": ({ "_request_delentry", 0, "_id" }),
"_request_entry_reply": ({ "_request_entry_reply", 0, "_parent", "_text" }),
"_request_comment": ({ "_request_entry_reply", 0, "_parent", "_text" }),
"_request_com": ({ "_request_entry_reply", 0, "_parent", "_text" }),
"_request_entry_add": ({ "_request_entry_add", 0, "_text" }),
"_request_addentry": ({ "_request_entry_add", 0, "_text" }),
"_request_addent": ({ "_request_entry_add", 0, "_text" }),
"_request_submit": ({ "_request_entry_add", 0, "_text" }),
"_request_blog": ({ "_request_entry_add", 0, "_text" }),
"_request_entry_del": ({ "_request_entry_del", 0, "_id" }),
"_request_delentry": ({ "_request_entry_del", 0, "_id" }),
"_request_delent": ({ "_request_entry_del", 0, "_id" }),
"_request_unsubmit": ({ "_request_entry_del", 0, "_id" }),
"_request_unblog": ({ "_request_entry_del", 0, "_id" }),
"_request_entry_edit": ({ "_request_entry_edit", 0, "_id", "_text" }),
"_request_editentry": ({ "_request_entry_edit", 0, "_id", "_text" }),
"_request_edentry": ({ "_request_entry_edit", 0, "_id", "_text" }),
"_request_edent": ({ "_request_entry_edit", 0, "_id", "_text" }),
"_request_set_addact": ({ "_request_set_addaction", 0, "_value" }),
"_request_set_addaction":({ "_request_set_addaction", 0, "_value" }),
"_request_set_editact": ({ "_request_set_editaction", 0, "_value" }),
"_request_set_editaction":({ "_request_set_editaction", 0, "_value" }),
"_request_set_showform":({ "_request_set_showform", 0, "_value" }),
"_request_set_showcomments":({ "_request_set_showcomments", 0, "_value" }),
#ifdef _flag_enable_module_microblogging
"_request_add": ({ "_request_add", 0, "_person" }),
"_request_remove": ({ "_request_remove", 0, "_person" }),
"_request_set_priv": ({ "_request_set_privacy", 0, "_value" }),
"_request_set_privacy": ({ "_request_set_privacy", 0, "_value" }),
#ifdef TWITTER
# ifdef TWITTER
"_request_set_tw": ({ "_request_set_twitter", 0, "_value" }),
"_request_set_twitter": ({ "_request_set_twitter", 0, "_value" }),
#endif
#ifdef IDENTICA
# endif
# ifdef IDENTICA
"_request_set_ica": ({ "_request_set_identica", 0, "_value" }),
"_request_set_identica":({ "_request_set_identica", 0, "_value" }),
#endif
# endif
#endif
#ifdef EXPERIMENTAL
// stuff to play around with

View File

@ -216,14 +216,6 @@ int qSaveImmediately() {
#endif
}
int qHistoryPersistentLimit() {
return _limit_amount_history_persistent;
}
int qHistoryExportLimit() {
return _limit_amount_history_export;
}
// to be overloaded by place.gen
qNewsfeed() { return 0; }
// _request_list_feature uses this in *all* place objects, dont ifdef
@ -233,7 +225,9 @@ mayLog(mc) { return abbrev("_message", mc); }
qHistory() { return v("log"); }
qHistoryGlimpse() { return DEFAULT_GLIMPSE; }
int qHistoryGlimpse() { return DEFAULT_GLIMPSE; }
int qHistoryPersistentLimit() { return _limit_amount_history_persistent; }
int qHistoryExportLimit() { return _limit_amount_history_export; }
histClear(a, b, source, vars) {
int l = logSize();
@ -463,6 +457,7 @@ showTopic(rcpt, verbose, mc) {
return 1;
}
# ifdef SIGS
_request_set_topic(source, mc, data, vars, b) {
string value = vars["_value"] || vars["_topic"];
if (strlen(value)) {
@ -473,7 +468,7 @@ _request_set_topic(source, mc, data, vars, b) {
}
return 1;
}
# endif
#endif
#if HAS_PORT(HTTP_PORT, HTTP_PATH) || HAS_PORT(HTTPS_PORT, HTTP_PATH)
@ -2254,6 +2249,64 @@ _request_set(source, mc, data, vars, b) {
return 1;
}
_request_set_default_text(source, mc, data, vars, b) {
unless (qOwner(SNICKER)) return 0;
string key = vars["_key"];
string value = vars["_value"];
if (strlen(value)) {
vSet(key, value);
save();
}
sendmsg(source, "_info_set_place_" + key, "Setting \"[_key_set]\" is \"[_value]\".", (["_key_set": key, "_value": v(key)]));
return 1;
}
_request_set_default_list(source, mc, data, vars, b, list) {
unless (qOwner(SNICKER)) return 0;
string key = vars["_key"];
string value;
foreach (string item : list) {
if (item == vars["_value"]) {
value = vars["_value"];
break;
}
}
if (strlen(value)) {
vSet(key, value);
save();
} else if (strlen(vars["_value"])) {
sendmsg(source, "_error_invalid_setting_value",
"Sorry, that is not a valid value for the [_key_set] setting. Valid values are: [_values].",
([ "_key_set": key, "_values": implode(list, ", ") ]) );
return 1;
}
sendmsg(source, "_info_set_place_" + key, "Setting \"[_key_set]\" is \"[_value]\".", (["_key_set": key, "_value": v(key)]));
return 1;
}
_request_set_default_bool(source, mc, data, vars, b) {
unless (qOwner(SNICKER)) return 0;
string key = vars["_key"];
string value = vars["_value"];
if (is_true(value)) {
vSet(key, 1);
save();
} else if (is_false(value)) {
vSet(key, 0);
save();
}
sendmsg(source, "_info_set_place_" + key, "Setting \"[_key_set]\" is [_value].", (["_key_set": key, "_value": v(key) ? "on" : "off"]));
return 1;
}
#ifdef PLACE_OWNED
_request_owners(source, mc, data, vars, b) {
mixed t;

View File

@ -15,24 +15,22 @@
inherit NET_PATH "place/owned";
qHistoryPersistentLimit() {
int qHistoryPersistentLimit() {
return 0;
}
canPost(snicker) {
return qAide(snicker);
}
canDeleteOwn(snicker) {
return qAide(snicker);
}
canDeleteEverything(snicker) {
return qOwner(snicker);
}
canPost(snicker) { return qAide(snicker); }
canReply(snicker) { return qAide(snicker); }
canEditOwn(snicker) { return qAide(snicker); }
canEditAll(snicker) { return qOwner(snicker); }
canDeleteOwn(snicker) { return qAide(snicker); }
canDeleteAll(snicker) { return qOwner(snicker); }
int mayLog(string mc) {
return abbrev("_notice_thread", mc) || abbrev("_message", mc);
if (abbrev("_notice_thread", mc))
return regmatch(mc, "_edit\\b") ? 0 : 1;
return abbrev("_message", mc);
}
int showWebLog() {
@ -51,6 +49,17 @@ create() {
logSet(0, ({0, 0, 0, 0}));
}
load(name, keep) {
int ret = ::load(name, keep);
unless (v("addaction")) vSet("addaction", "adds");
unless (v("editaction")) vSet("editaction", "edits");
unless (vExist("showform")) vSet("showform", 1);
unless (vExist("showcomments")) vSet("showcomments", 1);
return ret;
}
varargs array(mixed) entries(int limit, int offset, int reverse, int parent, int id) {
P3((">> entries(%O, %O, %O)\n", limit, offset, parent))
array(mixed) entries = ({}), entry, children, child;
@ -90,54 +99,69 @@ varargs array(mixed) entry(int id) {
return entries(0, 0, 0, 0, id);
}
varargs int addEntry(mixed source, string snicker, string text, string title, int parent_id) {
P3((">> addEntry(%O, %O, %O, %O, %O)\n", source, snicker, text, title, parent_id))
int id = logSize();
varargs int addEntry(mixed source, mapping vars, string _data, string _mc) {
P3((">> addEntry(%O, %O, %O, %O)\n", source, vars, _data, _mc))
string mc = "_notice_thread_entry";
string data = "[_nick] [_action]: ";
vars["_id"] = logSize();
vars["_action"] ||= v("addaction");
// this should only be set after a reply
m_delete(vars, "_children");
mapping vars = ([
"_id": id,
"_text": text,
"_nick": snicker,
"_action": "adds", //TODO: add a /set'ting for it, or find a better name
]);
if (parent_id) {
P3((">>> parent_id: %O\n", parent_id))
if (vars["_parent"]) {
array(mixed) parent;
unless (parent = logPick(parent_id)) return 0;
P3((">>> parent: %O\n", parent))
vars["_parent"] = to_int(vars["_parent"]);
unless (parent = logPick(vars["_parent"])) return 0;
PT((">>> parent: %O\n", parent))
unless (parent[LOG_VARS]["_children"]) parent[LOG_VARS]["_children"] = ({ });
parent[LOG_VARS]["_children"] += ({ id });
save();
parent[LOG_VARS]["_children"] += ({ vars["_id"] });
mc += "_reply";
data = member(parent[LOG_VARS], "_title") ?
"[_nick] [_action] in reply to #[_parent] ([_parent_title]): " :
"[_nick] [_action] in reply to #[_parent]: ",
vars += ([ "_parent": parent_id ]);
"[_nick] [_action] in reply to #[_parent]: ";
}
if (title && strlen(title)) {
vars += ([ "_title": title ]);
if (strlen(vars["_title"])) {
data += "[_title]\n[_text]";
} else {
data += "[_text]";
}
data += " (#[_id] in [_nick_place])";
if (_mc) mc += _mc;
if (_data) data = _data;
castmsg(source, mc, data, vars);
return 1;
}
int editEntry(mixed source, mapping vars, string data) {
P3((">> editEntry(%O, %O, %O)\n", source, vars, data))
array(mixed) entry;
vars["_id"] = to_int(vars["_id"]);
unless (entry = logPick(vars["_id"])) return 0;
string unick;
unless (canEditAll(SNICKER))
unless (canEditOwn(SNICKER) && lower_case(psyc_name(source)) == lower_case(entry[LOG_SOURCE][LOG_SOURCE_UNI]))
return 0;
if (strlen(data)) entry[LOG_DATA] = data;
foreach (string key : vars)
if (key != "_children") entry[LOG_VARS][key] = vars[key];
save();
castmsg(source, entry[LOG_MC] + "_edit", entry[LOG_DATA], vars + ([ "_action": v("editaction") ]));
return 1;
}
int delEntry(int id, mixed source, mapping vars) {
array(mixed) entry;
unless (entry = logPick(id)) return 0;
string unick;
unless (canDeleteEverything(SNICKER))
unless (canDeleteAll(SNICKER))
unless (canDeleteOwn(SNICKER) && lower_case(psyc_name(source)) == lower_case(entry[LOG_SOURCE][LOG_SOURCE_UNI]))
return 0;
@ -155,8 +179,8 @@ sendEntries(mixed source, array(mixed) entries, int level) {
PT(("entry: %O\n", entry))
vars = entry[LOG_VARS];
sendmsg(source, regreplace(entry[LOG_MC], "^_notice", "_list", 1),
"[_indent][_nick]: " + (vars["_title"] ? "[_title]\n" : "") + "[_text] (#[_id])",
vars + ([ "_level": level, "_indent": x(" ", level) ]));
"[_indent][_nick]: "+ (vars["_title"] ? "[_title]\n" : "") +"[_text] (#[_id])",
vars + ([ "_level": level, "_indent": x(" ", level), "_postfix_time_log": 1 ]));
if (sizeof(entry) >= LOG_CHILDREN + 1) sendEntries(source, entry[LOG_CHILDREN], level + 1);
n++;
}
@ -181,46 +205,58 @@ _request_entry(source, mc, data, vars, b) {
sendmsg(source, "_error_thread_invalid_entry",
"#[_id]: no such entry", (["_id": id]));
}
return 1;
}
_request_addentry(source, mc, data, vars, b) {
_request_entry_add(source, mc, data, vars, b) {
P3((">> _request_addentry(%O, %O, %O, %O, %O)\n", source, mc, data, vars, b))
unless (canPost(SNICKER)) return 0;
unless (vars["_text"] && strlen(vars["_text"])) {
sendmsg(source, "_warning_usage_addentry",
sendmsg(source, "_warning_usage_entry_add",
"Usage: /addentry <text>", ([ ]));
return 1;
}
addEntry(source, SNICKER, vars["_text"], vars["_title"]);
addEntry(source, vars, data);
return 1;
}
_request_comment(source, mc, data, vars, b) {
P3((">> _request_comment(%O, %O, %O, %O, %O)\n", source, mc, data, vars, b))
unless (vars["_id"] && strlen(vars["_id"]) &&
vars["_text"] && strlen(vars["_text"])) {
sendmsg(source, "_warning_usage_reply",
_request_entry_reply(source, mc, data, vars, b) {
P3((">> _request_entry_reply(%O, %O, %O, %O, %O)\n", source, mc, data, vars, b))
unless (canReply(SNICKER)) return 0;
unless (vars["_parent"] && strlen(vars["_text"])) {
sendmsg(source, "_warning_usage_entry_reply",
"Usage: /comment <id> <text>", ([ ]));
return 1;
}
int id = to_int(vars["_id"]);
string snicker = SNICKER;
P3((">>> id: %O, vars: %O\n", id, vars));
unless (addEntry(source, snicker, vars["_text"], vars["_title"], id))
unless (addEntry(source, vars))
sendmsg(source, "_error_thread_invalid_entry",
"#[_id]: no such entry", (["_id": id]));
"#[_id]: no such entry", (["_id": vars["_id"]]));
return 1;
}
_request_delentry(source, mc, data, vars, b) {
P3((">> _request_delentry(%O, %O, %O, %O, %O)\n", source, mc, data, vars, b))
unless (canPost(SNICKER)) return 0;
_request_entry_edit(source, mc, data, vars, b) {
P3((">> _request_title(%O, %O, %O, %O, %O)\n", source, mc, data, vars, b))
unless (canEditOwn(SNICKER)) return 0;
unless (vars["_id"] && strlen(vars["_id"])) {
sendmsg(source, "_warning_usage_delentry",
sendmsg(source, "_warning_usage_entry_edit",
"Usage: /editentry <id> <text>", ([ ]));
return 1;
}
unless (editEntry(source, vars))
sendmsg(source, "_error_thread_invalid_entry",
"#[_id]: no such entry", (["_id": vars["_id"]]));
return 1;
}
_request_entry_del(source, mc, data, vars, b) {
P3((">> _request_entry_del(%O, %O, %O, %O, %O)\n", source, mc, data, vars, b))
unless (canPost(SNICKER)) return 0;
unless (vars["_id"]) {
sendmsg(source, "_warning_usage_entry_del",
"Usage: /delentry <id>", ([ ]));
return 1;
}
@ -236,23 +272,21 @@ _request_delentry(source, mc, data, vars, b) {
return 1;
}
#if 0
_request_title(source, mc, data, vars, b) {
P3((">> _request_title(%O, %O, %O, %O, %O)\n", source, mc, data, vars, b))
unless (vars["_id"] && strlen(vars["_id"])) {
sendmsg(source, "_warning_usage_title",
"Usage: /title <id> <title>", ([ ]));
return 1;
}
int id = to_int(vars["_id"]);
unless (setTitle(id, vars["_title"]))
sendmsg(source, "_error_thread_invalid_entry",
"#[_id]: no such entry", (["_id": id]));
return 1;
_request_set_addaction(source, mc, data, vars, b) {
return _request_set_default_text(source, mc, data, vars, b);
}
_request_set_editaction(source, mc, data, vars, b) {
return _request_set_default_text(source, mc, data, vars, b);
}
_request_set_showcomments(source, mc, data, vars, b) {
return _request_set_default_bool(source, mc, data, vars, b);
}
_request_set_showform(source, mc, data, vars, b) {
return _request_set_default_bool(source, mc, data, vars, b);
}
#endif
msg(source, mc, data, vars){
P3(("thread:msg(%O, %O, %O, %O)", source, mc, data, vars))
@ -269,28 +303,49 @@ msg(source, mc, data, vars){
return ::msg(source, mc, data, vars);
}
varargs string htmlComments(array(mixed) entries, int level) {
varargs array(mixed) htmlComments(array(mixed) entries, int submit, int level, int n) {
array(mixed) ret;
mapping entry, vars;
string ht = "", style;
foreach(entry : entries) {
vars = entry[LOG_VARS];
style = level ? "style='padding-left: " + level + "em'" : "";
ht += "<div class='comment' title='" + isotime(ctime(vars["_time_place"]), 1) + "' " + style + "><span class='comment-author'>" + vars["_nick"] + "</span>: <span class='comment-text'>" + htquote(vars["_text"], 1) + "</span></div>\n";
if (sizeof(entry) >= LOG_CHILDREN + 1) ht += htmlComments(entry[LOG_CHILDREN], level + 1);
style = level ? "style='padding-left: "+ level +"em'" : "";
ht += "<div class='comment' title='"+ isotime(ctime(vars["_time_place"]), 1) +"' "+ style +"><span class='comment-author'>"+ vars["_nick"] +"</span>: <span class='comment-text'>" + (submit ? "<a class='comment-form-toggle' onclick='toggleForm(this.parentNode, "+ vars["_id"] +")'>&raquo;</a>" : "")+ htquote(vars["_text"], 1) +"</span></div>\n";
n++;
if (sizeof(entry) >= LOG_CHILDREN + 1) {
ret = htmlComments(entry[LOG_CHILDREN], submit, level + 1, n);
ht += ret[0];
n = ret[1];
}
}
return ht;
return ({ ht, n });
}
varargs string htmlEntries(array(mixed) entries, int nojs, string chan, string submit, string url_prefix) {
P3((">> threads:htmlentries(%O, %O, %O, %O, %O)\n", entries, nojs, chan, submit, url_prefix))
varargs string htmlEntries(array(mixed) entries, int submit, int show_comments, int nojs, string chan, string submit_target, string url_prefix) {
P3((">> threads:htmlentries(%O, %O, %O, %O, %O, %O)\n", entries, submit, nojs, chan, submit_target, url_prefix))
string text, ht = "";
string id_prefix = chan ? chan + "-" : "";
string id_prefix = chan ? chan +"-" : "";
unless (url_prefix) url_prefix = "";
unless (nojs) ht +=
"<script type='text/javascript'>\n"
"function toggle(e) { if (typeof e == 'string') e = document.getElementById(e); e.className = e.className.match('hidden') ? e.className.replace(/ *hidden/, '') : e.className + ' hidden'; }\n"
"function $(id) { return document.getElementById(id); }"
"function toggle(e) { if (!e) return 0; if (typeof e == 'string') e = $(e); e.className = e.className.match('hidden') ? e.className.replace(/ *hidden/, '') : e.className + ' hidden'; return 1; }\n"
"function toggleForm(e, id) { toggle(e.nextSibling) || e.parentNode.appendChild($('entry-form')) && ($('entry-form').className=''); $('form-parent').value = id }"
"</script>\n";
if (submit) ht +=
"<form id='entry-form' class='hidden' action='"+ url_prefix +"'"+
(0 && submit_target
//FIXME: cmd is executed twice, because after a set-cookie it's parsed again
? "onsubmit=\"cmd('comment '+ $('form-parent').value +' '+ this.previousSibling.value, '"+ submit_target +"')\""
: "method='post'") +
">"
"<input type='hidden' name='request' value='post' />"
"<input type='hidden' id='form-parent' name='_parent' value='' />"
"<textarea name='_text' autocomplete='off'></textarea>"
"<input type='submit' value='Send'>"
"</form>";
mapping entry, vars;
foreach (entry : entries) {
P3((">>> entry: %O\n", entry))
@ -298,41 +353,64 @@ varargs string htmlEntries(array(mixed) entries, int nojs, string chan, string s
text = htquote(vars["_text"], 1);
string comments = "";
if (sizeof(entry) >= LOG_CHILDREN + 1) comments = htmlComments(entry[LOG_CHILDREN]);
array(mixed) comments = ({ "", 0 });
if (sizeof(entry) >= LOG_CHILDREN + 1) comments = htmlComments(entry[LOG_CHILDREN], submit);
ht +=
"<div class='entry'>\n"
"<div class='header'>\n"
"<a href=\"" + url_prefix + "?id=" + vars["_id"] + "\">"
"<span class='id'>#" + vars["_id"] + "</span> - \n"
"<span class='author'>" + vars["_nick"] + "</span>\n"
"<a href=\""+ url_prefix +"?id="+ vars["_id"] +"\">"
"<span class='id'>#"+ vars["_id"] +"</span> - \n"
"<span class='author'>"+ vars["_nick"] +"</span>\n"
+ (vars["_title"] && strlen(vars["_title"]) ? " - " : "") +
"<span class='title'>" + htquote(vars["_title"] || "") + "</span>\n"
"<span class='title'>"+ htquote(vars["_title"] || "") +"</span>\n"
"</a>"
"</div>\n"
"<div class='body'>\n"
"<div class='text'>" + text + "</div>\n"
"<div id='comments-" + id_prefix + vars["_id"] + "' class='comments'>" + comments +
(submit && strlen(submit) ?
"<a onclick=\"toggle(this.nextSibling)\">&raquo; reply</a>"
"<div class='comment-submit hidden'>"
"<textarea autocomplete='off'></textarea>"
//FIXME: cmd is executed twice, because after a set-cookie it's parsed again
"<input type='button' value='Send' onclick=\"cmd('comment " + vars["_id"] + " '+ this.previousSibling.value, '" + submit + "')\">"
"</div>" : "") +
"</div>\n"
"<div class='text'>"+ text +"</div>\n"+
(show_comments ?
"<div id='comments-"+ id_prefix + vars["_id"] +"' class='comments'>"+ comments[0] +
(submit ? "<a onclick=\"toggleForm(this, "+ vars["_id"] +")\">&raquo; reply</a>" : "") +
"</div>\n" : "") +
"</div>\n"
"<div class='footer'>\n"
"<span class='date'>" + isotime(ctime(vars["_time_place"]), 1) + "</span>\n"
"<span class='date'>"+ isotime(ctime(vars["_time_place"]), 1) +"</span>\n"
"<span class='comments-link'>"
"<a onclick=\"toggle('comments-" + id_prefix + vars["_id"] + "')\">" + sizeof(vars["_children"]) + " comments</a>"
"<a " +
(show_comments
? "onclick=\"toggle('comments-"+ id_prefix + vars["_id"] +"')\""
: "href='"+ url_prefix +"?id="+ vars["_id"] +"''") +
">"+ comments[1] +" comments</a>"
"</span>\n"
"</div>\n"
"</div>\n";
}
P3((">>> ht: %O\n", ht))
return "<div class='threads'>" + ht + "</div>";
return "<div class='threads'>"+ ht +"</div>";
}
string htmlForm(int link, int title) {
if (link)
return
"<div class='threads'><a class='add-entry' href='?request=form'>Add entry</a></div>\n";
return
"<div class='threads'>"
"<div class='entry entry-form'>\n"
"<div class='header'>Add entry</div>\n"
"<div class='body'>\n"
"<form method='post'>\n"
"<input type='hidden' name='request' value='post' />\n" +
(title ?
"Title:<br><input type='text' name='_title'><br>\n"
"Text:<br/>" : "") +
"<textarea name='_text'></textarea>\n"
"<input type='submit' value='Send' />\n"
"</form>\n"
"</div>\n"
"<div class='footer'>\n"
"</div>\n"
"</div>\n"
"</div>\n";
}
// TODO: fix markup, not displayed correctly (in firefox at least)
@ -354,10 +432,10 @@ string rssEntries(array(mixed) entries) {
rss +=
"\n<item>\n"
"\t<title>"+ (vars["_title"] || "no title") +"</title>\n"
"\t<link>http://" + HTTP_OR_HTTPS_URL + "/" + pathName() + "?id=" + vars["_id"] + "</link>\n"
"\t<description>" + vars["_text"] + "</description>\n"
"\t<dc:date>" + isotime(ctime(vars["_time_place"]), 1) + "</dc:date>\n"
"\t<dc:creator>" + vars["_nick"] + "</dc:creator>\n"
"\t<link>http://"+ HTTP_OR_HTTPS_URL +"/"+ pathName() + "?id="+ vars["_id"] +"</link>\n"
"\t<description>"+ vars["_text"] +"</description>\n"
"\t<dc:date>"+ isotime(ctime(vars["_time_place"]), 1) +"</dc:date>\n"
"\t<dc:creator>"+ vars["_nick"] +"</dc:creator>\n"
"</item>\n";
}
@ -379,14 +457,14 @@ string jsEntries(array(mixed) entries) {
mapping entry, vars;
foreach (entry : entries) {
vars = entry[LOG_VARS];
js += "new Entry(" + vars["_id"] + ","
"\"" + vars["_title"] + "\","
"\"" + vars["_nick"] + "\","
+ isotime(ctime(vars["_time_place"]), 1) + ","
"\"" + vars["_text"] + "\"),\n";
js += "new Entry("+ vars["_id"] +","
"\""+ vars["_title"] +"\","
"\""+ vars["_nick"] +"\","
+ isotime(ctime(vars["_time_place"]), 1) +","
"\""+ vars["_text"] +"\"),\n";
}
return js[..<3] + ");";
return js[..<3] +");";
}
varargs string jsonEntries(int limit, int offset) {
@ -405,20 +483,24 @@ varargs void rssExport(int limit, int offset) {
write(rssEntries(entries(limit, offset, 1)));
}
varargs string htMain(int limit, int offset, string chan) {
return htmlEntries(entries(limit, offset, 1), 0, chan);
varargs string htMain(int limit, int offset, int submit, string chan) {
return htmlEntries(entries(limit, offset, 1), submit, v("showcomments"), 0, chan);
}
varargs void displayMain(int limit, int offset) {
write(htMain(limit, offset));
varargs void displayMain(int limit, int offset, int submit) {
write(htMain(limit, offset, submit));
}
string htEntry(int id) {
return htmlEntries(entry(id));
void displayForm(int link, int title) {
write(htmlForm(link, title));
}
void displayEntry(int id) {
write(htEntry(id) || "No such entry.");
string htEntry(int id, int submit) {
return htmlEntries(entry(id), submit, 1);
}
void displayEntry(int id, int submit) {
write(htEntry(id, submit) || "No such entry.");
}
// wir können zwei strategien fahren.. die technisch einfachere ist es
@ -430,10 +512,14 @@ void displayEntry(int id) {
// halten. womöglich kann man auch nachträglich plan A in plan B
// umwandeln..... hmmm -lynX
//
void displayHeader() {
void displayHeader(string class) {
w("_HTML_head_threads",
"<html><head><link rel='stylesheet' type='text/css' href='"+ STYLESHEET +"'></head>\n"+
"<body class='threads'>\n\n");
"<html><head>"
"<link rel='stylesheet' type='text/css' href='"+ STYLESHEET +"'>"
"<title>"+ MYNICK +"</title>"
"</head>\n"+
"<body class='threads "+ class +"'>\n"
"<h1><a href='/"+ pathName() +"'>"+ MYNICK +"</h1>\n");
}
void displayFooter() {
w("_HTML_tail_threads", "</body></html>");
@ -443,6 +529,7 @@ htget(prot, query, headers, qs, data) {
mapping entrymap;
mixed target;
string nick;
object user;
int a;
int limit = to_int(query["limit"]) || DEFAULT_BACKLOG;
int offset = to_int(query["offset"]);
@ -454,14 +541,14 @@ htget(prot, query, headers, qs, data) {
if (query["id"]) {
htok(prot);
// kommentare + urspruengliche Nachricht anzeigen
displayHeader();
displayEntry(to_int(query["id"]));
displayHeader("entry");
displayEntry(to_int(query["id"]), checkToken(query) ? 1 : 0);
#if 0
// eingabeformular ohne betreff
write("<form action='" + webact + "' method='GET'>\n"
write("<form action='"+ webact +"' method='GET'>\n"
"<input type='hidden' name='request' value='post'>\n"
"PSYC Uni: <input type='text' name='uni'><br>\n"
"<input type='hidden' name='reply' value='" + query["comments"] +"'>\n"
"<input type='hidden' name='reply' value='"+ query["comments"] +"'>\n"
"<textarea name='text' rows='14' cols='80'>Enter your text here</textarea><br>\n"
"<input type='submit' value='submit'>\n"
"</form>\n");
@ -472,61 +559,32 @@ htget(prot, query, headers, qs, data) {
return 1;
}
// formularbehandlung
if (query["request"] == "post" && query["uni"]) {
if (query["request"] == "post") {
htok(prot);
/*
sendmsg uni -> _request_authentication mit thread und text drin
dann auf die antwort warten die nen vars mapping mit thread + text hat wieder
*/
if (nick = legal_name(target = query["uni"])) {
target = summon_person(nick);
nick = target->qNick();
} else {
nick = target;
// write("Hello " + query["uni"] + "<br>\n");
// write("Remote auth doesn't work yet. TODO!!!\n");
// return 1;
// TODO: remote user auth
unless (user = checkToken(query)) {
write("Not authenticated!\n");
return 1;
}
#ifdef OWNED
if (canPost(nick)) {
#endif
#if 0
sendmsg(target, "_request_authentication", "please auth me!",
(["_host_IP" : query_ip_number(),
"_blog_thread" : query["thread"],
"_blog_text" : query["text"] ]));
write("your submit is avaiting authentication by " + query["uni"] + "<br>\n");
#endif // 0
if (target->checkAuthentication(ME, ([ "_host_IP" : query_ip_number() ]) ) > 0) {
// check ob reply auf irgendwas ist...
if (query["reply"]) {
addComment(query["text"], query["uni"], to_int(query["reply"]));
} else {
addEntry(query["text"], query["uni"], query["thread"]);
}
write("authentication successful!\n");
} else {
write("not authenticated!\n");
}
#ifdef OWNED
} else {
unless (canPost(query["user"])) {
write("You are not owner or aide of this place.\n");
return 1;
}
#endif
return 1;
object vars = ([]);
// add query params beginning with _ as vars
foreach (string key, string value : query)
if (abbrev("_", key)) vars[key] = value;
vars["_nick"] = user->qName();
addEntry(user, vars);
}
// neuen Eintrag verfassen
if (query["request"] == "form") {
htok(prot);
displayHeader();
write("<form action='" + webact + "' method='GET'>\n"
"<input type='hidden' name='request' value='post'>\n"
"PSYC Identity:<br><input type='text' name='uni' size=60><br>\n"
"Thread:<br><input type='text' name='thread' size=60><br>\n"
"Text:<br>\n<textarea name='text' rows='14' cols='64'></textarea><br>\n"
"<input type='submit' value='CREATE MESSAGE'>\n"
"</form>\n");
displayHeader("entry-add");
displayForm(0, 1);
displayFooter();
return 1;
}
@ -552,12 +610,13 @@ htget(prot, query, headers, qs, data) {
} else {
// normaler Export
//P2(("all entries: %O\n", _thread))
htok3(prot, "text/html", "Cache-Control: no-cache\n");
displayHeader();
htok3(prot, "text/html", "Cache-Control: no-cache\n");
displayHeader("entries");
if ((user = checkToken(query)) && canPost(user->qName()))
displayForm(!v("showform"));
// display the blog
displayMain(limit, offset);
displayMain(limit, offset, checkToken(query) ? 1 : 0);
// display the chatlog
if (showWebLog()) logView(a < 24 ? a : 12, "html", 15);
displayFooter();
}

View File

@ -24,17 +24,19 @@ volatile object identica;
load(name, keep) {
P3((">> userthreads:load(%O, %O)\n", name, keep))
int ret = ::load(name, keep);
sscanf(name, "~%s#%s", owner, channel);
vSet("owners", ([ lower_case(owner) ]));
vSet("privacy", "private");
vSet("twitter", 0);
vSet("identica", 0);
unless (v("owners")) vSet("owners", ([ lower_case(owner) ]));
unless (v("privacy")) vSet("privacy", "private");
unless (vExist("twitter")) vSet("twitter", 0);
unless (vExist("identica")) vSet("identica", 0);
vSet("_restrict_invitation", BLAME);
vSet("_filter_conversation", BLAME);
return ::load(name, keep);
return ret;
}
enter(source, mc, data, vars) {
@ -127,19 +129,13 @@ _request_remove(source, mc, data, vars, b) {
// set privacy: private or public
// - private: only friends & invited people can enter (default)
// - public: anyone can enter
_request_privacy(source, mc, data, vars, b) {
P3((">> userthreads:_request_privace(%O, %O, %O, %O, %O)\n", source, mc, data, vars, b))
string value = vars["_value"];
if (value == "public" || value == "private") {
vSet("privacy", value);
save();
}
sendmsg(source, "_info_set_place_privacy", "Privacy is: [_value].", (["_value": v("privacy")]));
return 1;
_request_set_privacy(source, mc, data, vars, b) {
return _request_set_default_list(source, mc, data, vars, b, ({"public", "private"}));
}
#ifdef TWITTER
_request_set_twitter(source, mc, data, vars, b) {
unless (qOwner(SNICKER)) return 0;
string value = vars["_value"];
if (is_true(value)) {
unless (twitter) twitter = clone_object(NET_PATH "twitter/client")->load(source);
@ -158,6 +154,7 @@ _request_set_twitter(source, mc, data, vars, b) {
#ifdef IDENTICA
_request_set_identica(source, mc, data, vars, b) {
unless (qOwner(SNICKER)) return 0;
string value = vars["_value"];
if (is_true(value)) {
unless (identica) identica = clone_object(NET_PATH "identica/client")->load(source);
@ -174,21 +171,21 @@ _request_set_identica(source, mc, data, vars, b) {
}
#endif
varargs int addEntry(mixed source, string snicker, string text, string title, int parent_id) {
varargs int addEntry(mixed source, mapping vars, string _data, string _mc) {
int ret;
if (ret = ::addEntry(source, snicker, text, title, parent_id)) {
if (ret = ::addEntry(source, vars, _data, _mc)) {
#ifdef TWITTER
if (v("twitter") && twitter) twitter->status_update(text);
if (v("twitter") && twitter) twitter->status_update(vars["_text"]);
#endif
#ifdef IDENTICA
if (v("identica") && identica) identica->status_update(text);
if (v("identica") && identica) identica->status_update(vars["_text"]);
#endif
}
return ret;
}
htMain(int limit, int offset) {
return ::htMain(limit, offset, channel);
htMain(int limit, int offset, int submit) {
return ::htMain(limit, offset, submit, channel);
}
canPost(snicker) {
@ -207,7 +204,7 @@ qChannel() {
return channel;
}
qHistoryGlimpse() {
int qHistoryGlimpse() {
return HISTORY_GLIMPSE;
}

View File

@ -68,6 +68,10 @@ vInc(k, howmuch) {
}
// vDec(k) { _v[k]--; }
vExist(k) {
return member(_v, k);
}
vEmpty() { return sizeof(_v) == 0; }
vSize() { return sizeof(_v); }

View File

@ -319,7 +319,7 @@ htDescription(anonymous, query, headers, qs, variant, vars) {
+ (first ? "class='selected'" : "") + ">#" + channel + "</a>\n";
contents +=
"<div id='tab-contents-" + channel + "' "
+ (first ? "class='selected'" : "") + ">" + threads->htmlEntries(entries, !first, channel, anonymous ? "" : vars["_identification"] + "#" + channel, vars["_profile_url"] + "/" + channel) + "</div>\n";
+ (first ? "class='selected'" : "") + ">" + threads->htmlEntries(entries, 1, 1, !first, channel, anonymous ? "" : vars["_identification"] + "#" + channel, vars["_profile_url"] + "/" + channel) + "</div>\n";
first = 0;
}
@ -1322,7 +1322,7 @@ w(string mc, string data, mapping vars, mixed source, int showingLog) {
else t = vars["_time_log"] || vars["_time_place"];
// would be nicer to have _time_log in /log rather than showingLog
if (!t && showingLog) t = vars["_time_INTERNAL"];
if (t && intp(t)) di["_prefix"] = time_or_date(t) +" ";
if (t && intp(t)) di["_prefix"] = time_or_date(t);
#if 0
template = T(di["_method"] || mc, 0);
#else
@ -1448,7 +1448,12 @@ w(string mc, string data, mapping vars, mixed source, int showingLog) {
// who is that output for anyway?
output = psyctext(template, vars, data, source);
if (di["_prefix"]) output = di["_prefix"]+output;
if (di["_prefix"]) {
if (vars["_postfix_time_log"])
output += " " + di["_prefix"];
else
output = di["_prefix"] +" "+ output;
}
if (output) {
if (template == "") {

View File

@ -19,7 +19,7 @@ body.threads,
padding: 4;
border: 1px solid #f33;
}
.comment-submit textarea, .comment-submit input,
.entry textarea, .entry input,
.Pe form input,select,textarea {
background: black;
color: #f33;
@ -74,6 +74,7 @@ body.threads,
width: 400;
}
a.add-entry,
.entry {
margin: 22px 44px;
}
@ -102,33 +103,54 @@ body.threads,
margin: 0 1em;
}
.entry .body .comment-submit input,
.entry .body .comment-submit textarea {
.entry .body .comment-form-toggle {
float: right;
}
.entry input,
.entry textarea {
font-size: 12px;
}
.entry .body .comment-submit textarea {
.entry input[type=text],
.entry textarea {
width: 100%;
}
body.entry-add textarea {
height: 40em;
}
.entry form {
margin: 0.2em 0;
padding: 0;
}
h1 a,
.entry a {
cursor: pointer;
text-decoration: none;
}
.entry a:hover {
text-decoration: underline;
}
.entry .header a {
color: black;
}
.entry .header .author {}
.entry .header .title {}
.entry .body a {
color: #f33;
}
h1 a,
a.add-entry,
.entry .footer a,
.entry .footer a:visited {
color: white;
}
.entry a {
cursor: pointer;
text-decoration: none;
}
.entry a:hover {
text-decoration: underline;
}
.entry .footer .comments-link {
float: right;
}