# HG changeset patch # User Trần H. Trung # Date 1688841089 -25200 # Node ID 04f36a470dca77e486f4162980739df2f37b597f # Parent 680fb3344357989e559b55cae99cbbe6f3ddf87d# Parent 59acf7f540c16fe64f0063785754a08e5b15e6b0 Update from upstream diff -r 59acf7f540c1 -r 04f36a470dca mod_invites_register_web/README.markdown --- a/mod_invites_register_web/README.markdown Fri Jul 07 19:45:48 2023 +0200 +++ b/mod_invites_register_web/README.markdown Sun Jul 09 01:31:29 2023 +0700 @@ -34,13 +34,6 @@ validates invite tokens. It also supports guiding the user through client download and configuration via mod_register_apps. -There is no specific configuration for this module (though it uses the -optional `site_name` to override the displayed site name. - -You may also set `webchat_url` to the URL of a web chat that will be linked -to after successful registration. If not specified but mod_conversejs is loaded -on the current host, it will default to the URL of that module. - This module depends on mod_invites_page solely for the case where an invalid invite token is received - it will redirect to mod_invites_page so that an appropriate error can be served to the user. @@ -49,3 +42,41 @@ loaded). As a consequence of this module being loaded, the default password policies will be enforced for all registrations on the server if not explicitly loaded or configured. + +Configuration +============= + +It uses the optional `site_name` to override the displayed site name. + +You can set `webchat_url` to the URL of a web chat that will be linked +to after successful registration. If not specified but mod_conversejs is loaded +on the current host, it will default to the URL of that module. + +You can use your own html templates with `invites_html_template`. Names of the +files MUST match the default. More over, you can offer multiple (human) +languages by adding the `&l=` to the URL. Meaning this module will serve +`register.html` for your default URL: +``` + + https://prosody.example.net/?=aowiefjoaij + +``` + +And if you have a `register.en.html` in the directory you have specified in +your config file, it will be served at: +``` + + https://prosody.example.net/?=aowiefjoaij&l=en + +``` + +So in your `register.html`, you can point to the English version by using an +`` tag like this: +``` + + English + +``` + +You can further customize your URL with [mod_invites_page] too. + diff -r 59acf7f540c1 -r 04f36a470dca mod_invites_register_web/mod_invites_register_web.lua --- a/mod_invites_register_web/mod_invites_register_web.lua Fri Jul 07 19:45:48 2023 +0200 +++ b/mod_invites_register_web/mod_invites_register_web.lua Sun Jul 09 01:31:29 2023 +0700 @@ -34,10 +34,17 @@ local invites = module:depends("invites"); local invites_page = module:depends("invites_page"); +local templatePath = module:get_option_string("invites_html_template", "html"); +function template_get(sTemplate, sLang) + local template = sLang and templatePath.."/"..sTemplate.."."..sLang..".html" + or templatePath.."/"..sTemplate..".html"; + return assert(module:load_resource(template):read("*a")); +end + +local lang = nil; function serve_register_page(event) - local register_page_template = assert(module:load_resource("html/register.html")):read("*a"); - local query_params = event.request.url.query and http_formdecode(event.request.url.query); + lang = query_params and query_params.l; local invite = query_params and invites.get(query_params.t); if not invite then @@ -49,6 +56,7 @@ }; end + local register_page_template = template_get("register", lang); event.response.headers["Content-Type"] = "text/html; charset=utf-8"; local invite_page = render_html_template(register_page_template, { @@ -71,8 +79,8 @@ local user, password, token = form_data["user"], form_data["password"], form_data["token"]; local app_id = form_data["app_id"]; - local register_page_template = assert(module:load_resource("html/register.html")):read("*a"); - local error_template = assert(module:load_resource("html/register_error.html")):read("*a"); + local register_page_template = template_get("register", lang); + local error_template = template_get("register_error", lang); local invite = invites.get(token); if not invite then @@ -163,6 +171,8 @@ module:fire_event("user-registering", registering); if not registering.allowed then + prepped_username = nil; + password = nil; return render_html_template(error_template, { site_name = site_name; msg_class = "alert-danger"; @@ -201,9 +211,9 @@ }; end -- If recognised app, we serve a page that includes setup instructions - success_template = assert(module:load_resource("html/register_success_setup.html")):read("*a"); + success_template = template_get("register_success_setup", lang); else - success_template = assert(module:load_resource("html/register_success.html")):read("*a"); + success_template = template_get("register_success", lang); end -- Due to the credentials being served here, ensure that diff -r 59acf7f540c1 -r 04f36a470dca mod_webpresence/README.markdown --- a/mod_webpresence/README.markdown Fri Jul 07 19:45:48 2023 +0200 +++ b/mod_webpresence/README.markdown Sun Jul 09 01:31:29 2023 +0700 @@ -2,65 +2,80 @@ labels: - 'Stage-Stable' summary: Display your online status in web pages +rockspec: + build: + copy_directories: + - icons ... Introduction ============ Quite often you may want to publish your Jabber status to your blog or -website. mod\_webpresence allows you to do exactly this. - -Details -======= - -This module uses Prosody's built-in HTTP server (it does not depend on -mod\_httpserver). It supplies a status icon representative of a user's -online state. +website. mod\_webpresence allows you to do exactly this via adhoc control. Installation ============ -Simply copy mod\_webpresence.lua to your modules directory, the image -files are embedded within it. Then add "webpresence" to your -modules\_enabled list. +Copy mod\_webpresence.lua to your modules directory then add it to your +modules\_enabled list: + +``` -Usage -===== + modules_enabled = { + "webpresence"; + }; + +``` + +Configuration & Usage +===================== + +There is a set of icons supplied with the module. But you can configure it to +load your own in the config file: -Once loaded you can embed the icon into a page using a simple `` -tag, as follows: +``` + + webpresence_icons = "/path/to/your/icons"; - +``` + +Beware that the icon files must have the same names as the default files. + +This module will always returns offline until you enable it via adhoc. -Alternatively, it can be used to get status name as plaint text, status -message as plain text or html-code for embedding on web-pages. +You can embed the icon into a page using a simple `` tag, as follows: + + -To get status name in plain text you can use something like that link: -`http://prosody.example.com:5280/status/john.smith/text` +Alternatively, it can be used to get status name as plain text, status message +as plain text or html-code for embedding on web-pages. + +To get status name in plain text you can use something like this link: +`http://prosody.example.com:5280/status/john.smith@domain.net/text` To get status message as plain text you can use something like following -link: `http://prosody.example.com:5280/status/john.smith/message` +link: `http://prosody.example.com:5280/status/john.smith@domain.net/message` -To get html code, containig status name, status image and status message -(if set): `http://prosody.example.com:5280/status/john.smith/html` - -All other +To get html code, containing status name, status image and status message +(if set): `http://prosody.example.com:5280/status/john.smith@domain.net/html` Compatibility ============= - ----- ------- - trunk Works - 0.10 Works - 0.9 Works - 0.8 Works - 0.7 Works - 0.6 Works - ----- ------- + ----- ------- + trunk Works + 0.12.3 Works + 0.10 Works + 0.9 Works + 0.8 Works + 0.7 Works + 0.6 Works + ----- ------- Todo ==== - Display PEP information (maybe a new plugin?) -- More (free) iconsets - Internal/external image generator (GD, ImageMagick) +- Display the correct boolean in the first form. diff -r 59acf7f540c1 -r 04f36a470dca mod_webpresence/mod_webpresence.lua --- a/mod_webpresence/mod_webpresence.lua Fri Jul 07 19:45:48 2023 +0200 +++ b/mod_webpresence/mod_webpresence.lua Sun Jul 09 01:31:29 2023 +0700 @@ -1,13 +1,156 @@ +module:depends("adhoc"); module:depends("http"); +local moduleHost = module.host; +local moduleName = module:get_name(); +local jid = require "util.jid"; local jid_split = require "util.jid".prepped_split; +local serialization = require "util.serialization"; + +-- ADHOC +local storage = module:open_store(moduleName, "keyval"); +local utilDataforms = require "util.dataforms"; +local utilAdhoc = require "util.adhoc"; +local adhoc_new = module:require("adhoc").new; + +local function webpresence_set(user, value) + local ok, err = storage:set(user, value); -- value is table. + + if not ok or err then + module:log(error, "Could not write data %s", tostring(user)); + return ok, err; + else + return ok; + end +end +local function webpresence_get(user) + local result = storage:get(user); + if not result then + result = { ["webpresence"] = false }; + webpresence_set(user, result); + end + return result[moduleName]; -- bool +end + +local form = utilDataforms.new { + title = "Web Presence Policy"; + instructions = "Your webpresence shows offline by default"; + { + type = "boolean"; + name = moduleName; + label = "Show"; + value = webpresence_get(); + }; +}; +local formResult = utilDataforms.new { + title = "Web Presence Policy"; + { + type = "boolean"; + name = moduleName; + label = "Show"; + value; + }; + { + type = "text-multi"; + name = "url"; + label = "Check your presence at"; + value = "text-multi\n"; + }; +}; + +local function webpresence_url(jid_bare) + local config, path = module:get_option("http_paths"); + if config then + for k, v in pairs(config) do + if k == moduleName then path = v; + else path = "/status" .. "/"; end + end + else path = "/status" .. "/"; end + + local urlConfig = module:get_option_string("http_external_link"); + local urlBase = urlConfig..path..jid_bare; + local style = { "/text", "/message", "/json", "/html" }; + local urlResult = urlBase.."\n"; + for _, v in ipairs(style) do + urlResult = urlResult..urlBase..v.."\n"; + end + return urlResult; +end + +local adhoc_handler = utilAdhoc.new_simple_form(form, function(fields, state, data) + local jid_bare = jid.bare(data.from); + local user, host = jid_split(jid_bare); + + local oldData, _ = storage:get(user); + oldValue = webpresence_get(user); + form.webpresence = oldValue; + + local urlResult = webpresence_url(jid_bare); + local newValue = { + [moduleName] = fields.webpresence; + }; + + if state then + return { + status = "completed"; + info = "No change for: "..tostring(data.from).." …\n" + .."Old data: "..serialization.serialize(oldData).."\n" + .."New data: "..serialization.serialize(newValue).."\n"; + result = { + layout = formResult; + values = { + webpresence = oldValue; + url = urlResult; + }; + }; + }; + else + local resultSet, resultErr = webpresence_set(user, newValue) + if not resultSet or resultErr then + module:log(error, "Could not set value: %s", errOut); + return { + status = "completed"; + info = "Could not set value: "..tostring(data.from).." …\n" + .."Old data: "..serialization.serialize(oldData).."\n" + .."New data: "..serialization.serialize(newValue).."\n" + .."Error: "..errOut.."\n"; + result = { + layout = formResult; + values = { + webpresence = newValue[moduleName]; + url = urlResult; + }; + }; + }; + else + return { + status = "completed"; + info = "Changing value for: "..tostring(data.from).." …\n" + .."Old data: "..serialization.serialize(oldData).."\n" + .."New data: "..serialization.serialize(newValue).."\n"; + result = { + layout = formResult; + values = { + webpresence = newValue[moduleName]; + url = urlResult; + }; + }; + }; + end + end +end); + +module:provides("adhoc", adhoc_new("Web Presence Policy", moduleName, adhoc_handler, "any")); + +-- HTTP local b64 = require "util.encodings".base64.encode; local sha1 = require "util.hashes".sha1; local stanza = require "util.stanza".stanza; local json = require "util.json".encode_ordered; +local usermanager = require "core.usermanager"; local function require_resource(name) - local icon_path = module:get_option_string("presence_icons", "icons"); + local icon_path = module:get_option_string("webpresence_icons", "icons"); local f, err = module:load_resource(icon_path.."/"..name); if f then return f:read("*a"); @@ -18,101 +161,112 @@ local statuses = { online = {}, away = {}, xa = {}, dnd = {}, chat = {}, offline = {} }; +local function user_list(host) return user:list(host); end + local function handle_request(event, path) - local status, message; - local jid, type = path:match("([^/]+)/?(.*)$"); - if jid then - local user, host = jid_split(jid); - if host and not user then - user, host = host, event.request.headers.host; - if host then host = host:gsub(":%d+$", ""); end - end - if user and host then - local user_sessions = hosts[host] and hosts[host].sessions[user]; - if user_sessions and user_sessions.top_resources then - status = user_sessions.top_resources[1]; - if status and status.presence then - message = status.presence:child_with_name("status"); - status = status.presence:child_with_name("show"); - if not status then - status = "online"; - else - status = status:get_text(); - end - if message then - message = message:get_text(); - end - end - end - end - end - status = status or "offline"; + local status, message; + local jid, type = path:match("([^/]+)/?(.*)$"); + if jid then + local user, host = jid_split(jid); + if host and not user then + user, host = host, event.request.headers.host; + if host then host = host:gsub(":%d+$", ""); end + end + if host ~= moduleHost then + status = "offline"; + else + if user and host and usermanager.user_exists(user, host) then + local user_sessions = hosts[host] and hosts[host].sessions[user]; + local show = webpresence_get(user) + if show == false then + status = "offline"; + else + if user_sessions and user_sessions.top_resources then + status = user_sessions.top_resources[1]; + if status and status.presence then + message = status.presence:child_with_name("status"); + status = status.presence:child_with_name("show"); + if not status then + status = "online"; + else + status = status:get_text(); + end + if message then + message = message:get_text(); + end + end + end + end + end + end + status = status or "offline"; + end - statuses[status].image = function() - return { status_code = 200, headers = { content_type = "image/png" }, - body = require_resource("status_"..status..".png") - }; +statuses[status].image = function() + return { status_code = 200, headers = { content_type = "image/png" }, + body = require_resource("status_"..status..".png") +}; end; statuses[status].html = function() - local jid_hash = sha1(jid, true); - return { status_code = 200, headers = { content_type = "text/html" }, - body = [[]].. - tostring( - stanza("html") - :tag("head") - :tag("title"):text("XMPP Status Page for "..jid):up():up() - :tag("body") - :tag("div", { id = jid_hash.."_status", class = "xmpp_status" }) - :tag("img", { id = jid_hash.."_img", class = "xmpp_status_image xmpp_status_"..status, - src = "data:image/png;base64,"..b64(require_resource("status_"..status..".png")) }):up() - :tag("span", { id = jid_hash.."_status_name", class = "xmpp_status_name" }) - :text("\194\160"..status):up() - :tag("span", { id = jid_hash.."_status_message", class = "xmpp_status_message" }) - :text(message and "\194\160"..message.."" or "") - ) - }; + local jid_hash = sha1(jid, true); + return { status_code = 200, headers = { content_type = "text/html" }, + body = [[]].. + tostring( + stanza("html") + :tag("head") + :tag("title"):text("XMPP Status Page for "..jid):up():up() + :tag("body") + :tag("div", { id = jid_hash.."_status", class = "xmpp_status" }) + :tag("img", { id = jid_hash.."_img", class = "xmpp_status_image xmpp_status_"..status, + src = "data:image/png;base64,"..b64(require_resource("status_"..status..".png")) }):up() + :tag("span", { id = jid_hash.."_status_name", class = "xmpp_status_name" }) + :text("\194\160"..status):up() + :tag("span", { id = jid_hash.."_status_message", class = "xmpp_status_message" }) + :text(message and "\194\160"..message.."" or "") + ) + }; end; statuses[status].text = function() - return { status_code = 200, headers = { content_type = "text/plain" }, - body = status - }; + return { status_code = 200, headers = { content_type = "text/plain" }, + body = status + }; end; statuses[status].message = function() - return { status_code = 200, headers = { content_type = "text/plain" }, - body = (message and message or "") - }; + return { status_code = 200, headers = { content_type = "text/plain" }, + body = (message and message or "") + }; end; statuses[status].json = function() - return { status_code = 200, headers = { content_type = "application/json" }, - body = json({ - jid = jid, - show = status, - status = (message and message or "null") - }) - }; + return { status_code = 200, headers = { content_type = "application/json" }, + body = json({ + jid = jid, + show = status, + status = (message and message or "null") + }) + }; end; statuses[status].xml = function() - return { status_code = 200, headers = { content_type = "application/xml" }, - body = [[]].. - tostring( - stanza("result") - :tag("jid"):text(jid):up() - :tag("show"):text(status):up() - :tag("status"):text(message) - ) - }; + return { status_code = 200, headers = { content_type = "application/xml" }, + body = [[]].. + tostring( + stanza("result") + :tag("jid"):text(jid):up() + :tag("show"):text(status):up() + :tag("status"):text(message) + ) + }; end if ((type == "") or (not statuses[status][type])) then - type = "image" + type = "image" end; return statuses[status][type](); end module:provides("http", { - default_path = "/status"; - route = { - ["GET /*"] = handle_request; - }; + default_path = "/status"; + route = { + ["GET /*"] = handle_request; + }; });