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_ni": ({ "_request_nick_local", 0, "_nick_local", "_INTERNAL_stuss" }),
"_request_public": ({ "_request_public", 0, "_flag_public" }), "_request_public": ({ "_request_public", 0, "_flag_public" }),
"_request_pub": ({ "_request_public", 0, "_flag_public" }), "_request_pub": ({ "_request_public", 0, "_flag_public" }),
// threads
"_request_entries": ({ "_request_entries", 0, "_num" }), "_request_entries": ({ "_request_entries", 0, "_num" }),
"_request_ents": ({ "_request_entries", 0, "_num" }), "_request_ents": ({ "_request_entries", 0, "_num" }),
"_request_entry": ({ "_request_entry", 0, "_id" }), "_request_entry": ({ "_request_entry", 0, "_id" }),
"_request_ent": ({ "_request_entry", 0, "_id" }), "_request_ent": ({ "_request_entry", 0, "_id" }),
"_request_comment": ({ "_request_comment", 0, "_id", "_text" }), "_request_entry_reply": ({ "_request_entry_reply", 0, "_parent", "_text" }),
"_request_com": ({ "_request_comment", 0, "_id", "_text" }), "_request_comment": ({ "_request_entry_reply", 0, "_parent", "_text" }),
"_request_title": ({ "_request_title", 0, "_id", "_title" }), "_request_com": ({ "_request_entry_reply", 0, "_parent", "_text" }),
"_request_addentry": ({ "_request_addentry", 0, "_text" }), "_request_entry_add": ({ "_request_entry_add", 0, "_text" }),
"_request_addent": ({ "_request_addentry", 0, "_text" }), "_request_addentry": ({ "_request_entry_add", 0, "_text" }),
"_request_submit": ({ "_request_addentry", 0, "_text" }), "_request_addent": ({ "_request_entry_add", 0, "_text" }),
"_request_blog": ({ "_request_addentry", 0, "_text" }), "_request_submit": ({ "_request_entry_add", 0, "_text" }),
"_request_delentry": ({ "_request_delentry", 0, "_id" }), "_request_blog": ({ "_request_entry_add", 0, "_text" }),
"_request_delent": ({ "_request_delentry", 0, "_id" }), "_request_entry_del": ({ "_request_entry_del", 0, "_id" }),
"_request_unsubmit": ({ "_request_delentry", 0, "_id" }), "_request_delentry": ({ "_request_entry_del", 0, "_id" }),
"_request_unblog": ({ "_request_delentry", 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 #ifdef _flag_enable_module_microblogging
"_request_add": ({ "_request_add", 0, "_person" }), "_request_add": ({ "_request_add", 0, "_person" }),
"_request_remove": ({ "_request_remove", 0, "_person" }), "_request_remove": ({ "_request_remove", 0, "_person" }),
"_request_set_priv": ({ "_request_set_privacy", 0, "_value" }), "_request_set_priv": ({ "_request_set_privacy", 0, "_value" }),
"_request_set_privacy": ({ "_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_tw": ({ "_request_set_twitter", 0, "_value" }),
"_request_set_twitter": ({ "_request_set_twitter", 0, "_value" }), "_request_set_twitter": ({ "_request_set_twitter", 0, "_value" }),
#endif # endif
#ifdef IDENTICA # ifdef IDENTICA
"_request_set_ica": ({ "_request_set_identica", 0, "_value" }), "_request_set_ica": ({ "_request_set_identica", 0, "_value" }),
"_request_set_identica":({ "_request_set_identica", 0, "_value" }), "_request_set_identica":({ "_request_set_identica", 0, "_value" }),
#endif # endif
#endif #endif
#ifdef EXPERIMENTAL #ifdef EXPERIMENTAL
// stuff to play around with // stuff to play around with

View File

@ -216,14 +216,6 @@ int qSaveImmediately() {
#endif #endif
} }
int qHistoryPersistentLimit() {
return _limit_amount_history_persistent;
}
int qHistoryExportLimit() {
return _limit_amount_history_export;
}
// to be overloaded by place.gen // to be overloaded by place.gen
qNewsfeed() { return 0; } qNewsfeed() { return 0; }
// _request_list_feature uses this in *all* place objects, dont ifdef // _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"); } 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) { histClear(a, b, source, vars) {
int l = logSize(); int l = logSize();
@ -463,6 +457,7 @@ showTopic(rcpt, verbose, mc) {
return 1; return 1;
} }
# ifdef SIGS
_request_set_topic(source, mc, data, vars, b) { _request_set_topic(source, mc, data, vars, b) {
string value = vars["_value"] || vars["_topic"]; string value = vars["_value"] || vars["_topic"];
if (strlen(value)) { if (strlen(value)) {
@ -473,7 +468,7 @@ _request_set_topic(source, mc, data, vars, b) {
} }
return 1; return 1;
} }
# endif
#endif #endif
#if HAS_PORT(HTTP_PORT, HTTP_PATH) || HAS_PORT(HTTPS_PORT, HTTP_PATH) #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; 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 #ifdef PLACE_OWNED
_request_owners(source, mc, data, vars, b) { _request_owners(source, mc, data, vars, b) {
mixed t; mixed t;

View File

@ -15,24 +15,22 @@
inherit NET_PATH "place/owned"; inherit NET_PATH "place/owned";
qHistoryPersistentLimit() { int qHistoryPersistentLimit() {
return 0; return 0;
} }
canPost(snicker) { canPost(snicker) { return qAide(snicker); }
return qAide(snicker); canReply(snicker) { return qAide(snicker); }
} canEditOwn(snicker) { return qAide(snicker); }
canEditAll(snicker) { return qOwner(snicker); }
canDeleteOwn(snicker) { canDeleteOwn(snicker) { return qAide(snicker); }
return qAide(snicker); canDeleteAll(snicker) { return qOwner(snicker); }
}
canDeleteEverything(snicker) {
return qOwner(snicker);
}
int mayLog(string mc) { 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() { int showWebLog() {
@ -51,6 +49,17 @@ create() {
logSet(0, ({0, 0, 0, 0})); 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) { varargs array(mixed) entries(int limit, int offset, int reverse, int parent, int id) {
P3((">> entries(%O, %O, %O)\n", limit, offset, parent)) P3((">> entries(%O, %O, %O)\n", limit, offset, parent))
array(mixed) entries = ({}), entry, children, child; array(mixed) entries = ({}), entry, children, child;
@ -90,54 +99,69 @@ varargs array(mixed) entry(int id) {
return entries(0, 0, 0, 0, id); return entries(0, 0, 0, 0, id);
} }
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) {
P3((">> addEntry(%O, %O, %O, %O, %O)\n", source, snicker, text, title, parent_id)) P3((">> addEntry(%O, %O, %O, %O)\n", source, vars, _data, _mc))
int id = logSize();
string mc = "_notice_thread_entry"; string mc = "_notice_thread_entry";
string data = "[_nick] [_action]: "; 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 = ([ if (vars["_parent"]) {
"_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))
array(mixed) parent; array(mixed) parent;
unless (parent = logPick(parent_id)) return 0; vars["_parent"] = to_int(vars["_parent"]);
P3((">>> parent: %O\n", parent)) unless (parent = logPick(vars["_parent"])) return 0;
PT((">>> parent: %O\n", parent))
unless (parent[LOG_VARS]["_children"]) parent[LOG_VARS]["_children"] = ({ }); unless (parent[LOG_VARS]["_children"]) parent[LOG_VARS]["_children"] = ({ });
parent[LOG_VARS]["_children"] += ({ id }); parent[LOG_VARS]["_children"] += ({ vars["_id"] });
save();
mc += "_reply"; mc += "_reply";
data = member(parent[LOG_VARS], "_title") ? data = member(parent[LOG_VARS], "_title") ?
"[_nick] [_action] in reply to #[_parent] ([_parent_title]): " : "[_nick] [_action] in reply to #[_parent] ([_parent_title]): " :
"[_nick] [_action] in reply to #[_parent]: ", "[_nick] [_action] in reply to #[_parent]: ";
vars += ([ "_parent": parent_id ]);
} }
if (title && strlen(title)) { if (strlen(vars["_title"])) {
vars += ([ "_title": title ]);
data += "[_title]\n[_text]"; data += "[_title]\n[_text]";
} else { } else {
data += "[_text]"; data += "[_text]";
} }
data += " (#[_id] in [_nick_place])"; data += " (#[_id] in [_nick_place])";
if (_mc) mc += _mc;
if (_data) data = _data;
castmsg(source, mc, data, vars); castmsg(source, mc, data, vars);
return 1; 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) { int delEntry(int id, mixed source, mapping vars) {
array(mixed) entry; array(mixed) entry;
unless (entry = logPick(id)) return 0; unless (entry = logPick(id)) return 0;
string unick; string unick;
unless (canDeleteEverything(SNICKER)) unless (canDeleteAll(SNICKER))
unless (canDeleteOwn(SNICKER) && lower_case(psyc_name(source)) == lower_case(entry[LOG_SOURCE][LOG_SOURCE_UNI])) unless (canDeleteOwn(SNICKER) && lower_case(psyc_name(source)) == lower_case(entry[LOG_SOURCE][LOG_SOURCE_UNI]))
return 0; return 0;
@ -155,8 +179,8 @@ sendEntries(mixed source, array(mixed) entries, int level) {
PT(("entry: %O\n", entry)) PT(("entry: %O\n", entry))
vars = entry[LOG_VARS]; vars = entry[LOG_VARS];
sendmsg(source, regreplace(entry[LOG_MC], "^_notice", "_list", 1), sendmsg(source, regreplace(entry[LOG_MC], "^_notice", "_list", 1),
"[_indent][_nick]: " + (vars["_title"] ? "[_title]\n" : "") + "[_text] (#[_id])", "[_indent][_nick]: "+ (vars["_title"] ? "[_title]\n" : "") +"[_text] (#[_id])",
vars + ([ "_level": level, "_indent": x(" ", level) ])); vars + ([ "_level": level, "_indent": x(" ", level), "_postfix_time_log": 1 ]));
if (sizeof(entry) >= LOG_CHILDREN + 1) sendEntries(source, entry[LOG_CHILDREN], level + 1); if (sizeof(entry) >= LOG_CHILDREN + 1) sendEntries(source, entry[LOG_CHILDREN], level + 1);
n++; n++;
} }
@ -181,46 +205,58 @@ _request_entry(source, mc, data, vars, b) {
sendmsg(source, "_error_thread_invalid_entry", sendmsg(source, "_error_thread_invalid_entry",
"#[_id]: no such entry", (["_id": id])); "#[_id]: no such entry", (["_id": id]));
} }
return 1; 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)) P3((">> _request_addentry(%O, %O, %O, %O, %O)\n", source, mc, data, vars, b))
unless (canPost(SNICKER)) return 0; unless (canPost(SNICKER)) return 0;
unless (vars["_text"] && strlen(vars["_text"])) { unless (vars["_text"] && strlen(vars["_text"])) {
sendmsg(source, "_warning_usage_addentry", sendmsg(source, "_warning_usage_entry_add",
"Usage: /addentry <text>", ([ ])); "Usage: /addentry <text>", ([ ]));
return 1; return 1;
} }
addEntry(source, SNICKER, vars["_text"], vars["_title"]); addEntry(source, vars, data);
return 1; return 1;
} }
_request_comment(source, mc, data, vars, b) { _request_entry_reply(source, mc, data, vars, b) {
P3((">> _request_comment(%O, %O, %O, %O, %O)\n", source, mc, data, vars, b)) P3((">> _request_entry_reply(%O, %O, %O, %O, %O)\n", source, mc, data, vars, b))
unless (vars["_id"] && strlen(vars["_id"]) && unless (canReply(SNICKER)) return 0;
vars["_text"] && strlen(vars["_text"])) { unless (vars["_parent"] && strlen(vars["_text"])) {
sendmsg(source, "_warning_usage_reply", sendmsg(source, "_warning_usage_entry_reply",
"Usage: /comment <id> <text>", ([ ])); "Usage: /comment <id> <text>", ([ ]));
return 1; return 1;
} }
int id = to_int(vars["_id"]); unless (addEntry(source, vars))
string snicker = SNICKER;
P3((">>> id: %O, vars: %O\n", id, vars));
unless (addEntry(source, snicker, vars["_text"], vars["_title"], id))
sendmsg(source, "_error_thread_invalid_entry", sendmsg(source, "_error_thread_invalid_entry",
"#[_id]: no such entry", (["_id": id])); "#[_id]: no such entry", (["_id": vars["_id"]]));
return 1; return 1;
} }
_request_delentry(source, mc, data, vars, b) { _request_entry_edit(source, mc, data, vars, b) {
P3((">> _request_delentry(%O, %O, %O, %O, %O)\n", source, mc, data, vars, b)) P3((">> _request_title(%O, %O, %O, %O, %O)\n", source, mc, data, vars, b))
unless (canPost(SNICKER)) return 0; unless (canEditOwn(SNICKER)) return 0;
unless (vars["_id"] && strlen(vars["_id"])) { 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>", ([ ])); "Usage: /delentry <id>", ([ ]));
return 1; return 1;
} }
@ -236,23 +272,21 @@ _request_delentry(source, mc, data, vars, b) {
return 1; return 1;
} }
#if 0 _request_set_addaction(source, mc, data, vars, b) {
_request_title(source, mc, data, vars, b) { return _request_set_default_text(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", _request_set_editaction(source, mc, data, vars, b) {
"Usage: /title <id> <title>", ([ ])); return _request_set_default_text(source, mc, data, vars, b);
return 1; }
}
_request_set_showcomments(source, mc, data, vars, b) {
int id = to_int(vars["_id"]); return _request_set_default_bool(source, mc, data, vars, b);
unless (setTitle(id, vars["_title"])) }
sendmsg(source, "_error_thread_invalid_entry",
"#[_id]: no such entry", (["_id": id])); _request_set_showform(source, mc, data, vars, b) {
return _request_set_default_bool(source, mc, data, vars, b);
return 1;
} }
#endif
msg(source, mc, data, vars){ msg(source, mc, data, vars){
P3(("thread:msg(%O, %O, %O, %O)", 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); 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; mapping entry, vars;
string ht = "", style; string ht = "", style;
foreach(entry : entries) { foreach(entry : entries) {
vars = entry[LOG_VARS]; vars = entry[LOG_VARS];
style = level ? "style='padding-left: " + level + "em'" : ""; 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"; 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";
if (sizeof(entry) >= LOG_CHILDREN + 1) ht += htmlComments(entry[LOG_CHILDREN], level + 1); 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) { 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)\n", entries, nojs, chan, submit, url_prefix)) P3((">> threads:htmlentries(%O, %O, %O, %O, %O, %O)\n", entries, submit, nojs, chan, submit_target, url_prefix))
string text, ht = ""; string text, ht = "";
string id_prefix = chan ? chan + "-" : ""; string id_prefix = chan ? chan +"-" : "";
unless (url_prefix) url_prefix = ""; unless (url_prefix) url_prefix = "";
unless (nojs) ht += unless (nojs) ht +=
"<script type='text/javascript'>\n" "<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"; "</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; mapping entry, vars;
foreach (entry : entries) { foreach (entry : entries) {
P3((">>> entry: %O\n", entry)) 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); text = htquote(vars["_text"], 1);
string comments = ""; array(mixed) comments = ({ "", 0 });
if (sizeof(entry) >= LOG_CHILDREN + 1) comments = htmlComments(entry[LOG_CHILDREN]); if (sizeof(entry) >= LOG_CHILDREN + 1) comments = htmlComments(entry[LOG_CHILDREN], submit);
ht += ht +=
"<div class='entry'>\n" "<div class='entry'>\n"
"<div class='header'>\n" "<div class='header'>\n"
"<a href=\"" + url_prefix + "?id=" + vars["_id"] + "\">" "<a href=\""+ url_prefix +"?id="+ vars["_id"] +"\">"
"<span class='id'>#" + vars["_id"] + "</span> - \n" "<span class='id'>#"+ vars["_id"] +"</span> - \n"
"<span class='author'>" + vars["_nick"] + "</span>\n" "<span class='author'>"+ vars["_nick"] +"</span>\n"
+ (vars["_title"] && strlen(vars["_title"]) ? " - " : "") + + (vars["_title"] && strlen(vars["_title"]) ? " - " : "") +
"<span class='title'>" + htquote(vars["_title"] || "") + "</span>\n" "<span class='title'>"+ htquote(vars["_title"] || "") +"</span>\n"
"</a>" "</a>"
"</div>\n" "</div>\n"
"<div class='body'>\n" "<div class='body'>\n"
"<div class='text'>" + text + "</div>\n" "<div class='text'>"+ text +"</div>\n"+
"<div id='comments-" + id_prefix + vars["_id"] + "' class='comments'>" + comments + (show_comments ?
(submit && strlen(submit) ? "<div id='comments-"+ id_prefix + vars["_id"] +"' class='comments'>"+ comments[0] +
"<a onclick=\"toggle(this.nextSibling)\">&raquo; reply</a>" (submit ? "<a onclick=\"toggleForm(this, "+ vars["_id"] +")\">&raquo; reply</a>" : "") +
"<div class='comment-submit hidden'>" "</div>\n" : "") +
"<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>\n" "</div>\n"
"<div class='footer'>\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'>" "<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" "</span>\n"
"</div>\n" "</div>\n"
"</div>\n"; "</div>\n";
} }
P3((">>> ht: %O\n", ht)) 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) // TODO: fix markup, not displayed correctly (in firefox at least)
@ -354,10 +432,10 @@ string rssEntries(array(mixed) entries) {
rss += rss +=
"\n<item>\n" "\n<item>\n"
"\t<title>"+ (vars["_title"] || "no title") +"</title>\n" "\t<title>"+ (vars["_title"] || "no title") +"</title>\n"
"\t<link>http://" + HTTP_OR_HTTPS_URL + "/" + pathName() + "?id=" + vars["_id"] + "</link>\n" "\t<link>http://"+ HTTP_OR_HTTPS_URL +"/"+ pathName() + "?id="+ vars["_id"] +"</link>\n"
"\t<description>" + vars["_text"] + "</description>\n" "\t<description>"+ vars["_text"] +"</description>\n"
"\t<dc:date>" + isotime(ctime(vars["_time_place"]), 1) + "</dc:date>\n" "\t<dc:date>"+ isotime(ctime(vars["_time_place"]), 1) +"</dc:date>\n"
"\t<dc:creator>" + vars["_nick"] + "</dc:creator>\n" "\t<dc:creator>"+ vars["_nick"] +"</dc:creator>\n"
"</item>\n"; "</item>\n";
} }
@ -379,14 +457,14 @@ string jsEntries(array(mixed) entries) {
mapping entry, vars; mapping entry, vars;
foreach (entry : entries) { foreach (entry : entries) {
vars = entry[LOG_VARS]; vars = entry[LOG_VARS];
js += "new Entry(" + vars["_id"] + "," js += "new Entry("+ vars["_id"] +","
"\"" + vars["_title"] + "\"," "\""+ vars["_title"] +"\","
"\"" + vars["_nick"] + "\"," "\""+ vars["_nick"] +"\","
+ isotime(ctime(vars["_time_place"]), 1) + "," + isotime(ctime(vars["_time_place"]), 1) +","
"\"" + vars["_text"] + "\"),\n"; "\""+ vars["_text"] +"\"),\n";
} }
return js[..<3] + ");"; return js[..<3] +");";
} }
varargs string jsonEntries(int limit, int offset) { varargs string jsonEntries(int limit, int offset) {
@ -405,20 +483,24 @@ varargs void rssExport(int limit, int offset) {
write(rssEntries(entries(limit, offset, 1))); write(rssEntries(entries(limit, offset, 1)));
} }
varargs string htMain(int limit, int offset, string chan) { varargs string htMain(int limit, int offset, int submit, string chan) {
return htmlEntries(entries(limit, offset, 1), 0, chan); return htmlEntries(entries(limit, offset, 1), submit, v("showcomments"), 0, chan);
} }
varargs void displayMain(int limit, int offset) { varargs void displayMain(int limit, int offset, int submit) {
write(htMain(limit, offset)); write(htMain(limit, offset, submit));
} }
string htEntry(int id) { void displayForm(int link, int title) {
return htmlEntries(entry(id)); write(htmlForm(link, title));
} }
void displayEntry(int id) { string htEntry(int id, int submit) {
write(htEntry(id) || "No such entry."); 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 // 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 // halten. womöglich kann man auch nachträglich plan A in plan B
// umwandeln..... hmmm -lynX // umwandeln..... hmmm -lynX
// //
void displayHeader() { void displayHeader(string class) {
w("_HTML_head_threads", w("_HTML_head_threads",
"<html><head><link rel='stylesheet' type='text/css' href='"+ STYLESHEET +"'></head>\n"+ "<html><head>"
"<body class='threads'>\n\n"); "<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() { void displayFooter() {
w("_HTML_tail_threads", "</body></html>"); w("_HTML_tail_threads", "</body></html>");
@ -443,6 +529,7 @@ htget(prot, query, headers, qs, data) {
mapping entrymap; mapping entrymap;
mixed target; mixed target;
string nick; string nick;
object user;
int a; int a;
int limit = to_int(query["limit"]) || DEFAULT_BACKLOG; int limit = to_int(query["limit"]) || DEFAULT_BACKLOG;
int offset = to_int(query["offset"]); int offset = to_int(query["offset"]);
@ -454,14 +541,14 @@ htget(prot, query, headers, qs, data) {
if (query["id"]) { if (query["id"]) {
htok(prot); htok(prot);
// kommentare + urspruengliche Nachricht anzeigen // kommentare + urspruengliche Nachricht anzeigen
displayHeader(); displayHeader("entry");
displayEntry(to_int(query["id"])); displayEntry(to_int(query["id"]), checkToken(query) ? 1 : 0);
#if 0 #if 0
// eingabeformular ohne betreff // 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" "<input type='hidden' name='request' value='post'>\n"
"PSYC Uni: <input type='text' name='uni'><br>\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" "<textarea name='text' rows='14' cols='80'>Enter your text here</textarea><br>\n"
"<input type='submit' value='submit'>\n" "<input type='submit' value='submit'>\n"
"</form>\n"); "</form>\n");
@ -472,61 +559,32 @@ htget(prot, query, headers, qs, data) {
return 1; return 1;
} }
// formularbehandlung if (query["request"] == "post") {
if (query["request"] == "post" && query["uni"]) {
htok(prot); htok(prot);
/*
sendmsg uni -> _request_authentication mit thread und text drin // TODO: remote user auth
dann auf die antwort warten die nen vars mapping mit thread + text hat wieder unless (user = checkToken(query)) {
*/ write("Not authenticated!\n");
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;
}
#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 {
write("You are not owner or aide of this place.\n");
}
#endif
return 1; return 1;
} }
unless (canPost(query["user"])) {
write("You are not owner or aide of this place.\n");
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 // neuen Eintrag verfassen
if (query["request"] == "form") { if (query["request"] == "form") {
htok(prot); htok(prot);
displayHeader(); displayHeader("entry-add");
write("<form action='" + webact + "' method='GET'>\n" displayForm(0, 1);
"<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");
displayFooter(); displayFooter();
return 1; return 1;
} }
@ -553,11 +611,12 @@ htget(prot, query, headers, qs, data) {
// normaler Export // normaler Export
//P2(("all entries: %O\n", _thread)) //P2(("all entries: %O\n", _thread))
htok3(prot, "text/html", "Cache-Control: no-cache\n"); htok3(prot, "text/html", "Cache-Control: no-cache\n");
displayHeader(); displayHeader("entries");
if ((user = checkToken(query)) && canPost(user->qName()))
displayForm(!v("showform"));
// display the blog // display the blog
displayMain(limit, offset); displayMain(limit, offset, checkToken(query) ? 1 : 0);
// display the chatlog // display the chatlog
if (showWebLog()) logView(a < 24 ? a : 12, "html", 15); if (showWebLog()) logView(a < 24 ? a : 12, "html", 15);
displayFooter(); displayFooter();
} }

View File

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

View File

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

View File

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

View File

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