Mercurial > prosody-modules
comparison mod_invites_page/mod_invites_page.lua @ 4094:dd00a2b9927c
mod_invites_page: New module to generate landing page for invites
| author | Matthew Wild <mwild1@gmail.com> |
|---|---|
| date | Fri, 11 Sep 2020 13:52:32 +0100 |
| parents | |
| children | 798f284717e7 |
comparison
equal
deleted
inserted
replaced
| 4093:a2116f5a7c8f | 4094:dd00a2b9927c |
|---|---|
| 1 local st = require "util.stanza"; | |
| 2 local url_escape = require "util.http".urlencode; | |
| 3 | |
| 4 module:depends("http"); | |
| 5 local base_url = module.http_url and module:http_url(); | |
| 6 | |
| 7 local render_html_template = require"util.interpolation".new("%b{}", st.xml_escape, { | |
| 8 urlescape = url_escape; | |
| 9 lower = string.lower; | |
| 10 classname = function (s) return (s:gsub("%W+", "-")); end; | |
| 11 relurl = function (s) | |
| 12 if s:match("^%w+://") then | |
| 13 return s; | |
| 14 end | |
| 15 return base_url.."/"..s; | |
| 16 end; | |
| 17 }); | |
| 18 local render_url = require "util.interpolation".new("%b{}", url_escape, { | |
| 19 urlescape = url_escape; | |
| 20 noscheme = function (url) | |
| 21 return (url:gsub("^[^:]+:", "")); | |
| 22 end; | |
| 23 }); | |
| 24 | |
| 25 module:depends("register_apps"); | |
| 26 module:depends("invites_register_web"); | |
| 27 | |
| 28 local site_name = module:get_option_string("site_name", module.host); | |
| 29 local site_apps = module:shared("register_apps/apps"); | |
| 30 | |
| 31 local http_files; | |
| 32 | |
| 33 if prosody.shutdown then | |
| 34 module:depends("http"); | |
| 35 http_files = module:depends("http_files"); | |
| 36 end | |
| 37 local invites = module:depends("invites"); | |
| 38 | |
| 39 -- Point at eg https://github.com/ge0rg/easy-xmpp-invitation | |
| 40 -- This URL must always be absolute, as it is shared standalone | |
| 41 local invite_url_template = module:get_option_string("invites_page", base_url and (base_url.."?{invite.token}") or nil); | |
| 42 -- This URL is relative to the invite page, or can be absolute | |
| 43 local register_url_template = module:get_option_string("invites_registration_page", "register?t={invite.token}&c={app.id}"); | |
| 44 | |
| 45 local function add_landing_url(invite) | |
| 46 if not invite_url_template then return; end | |
| 47 -- TODO: we don't currently have a landing page for subscription-only invites, | |
| 48 -- so the user will only receive a URI. The client should be able to handle this | |
| 49 -- by automatically falling back to a client-specific landing page, per XEP-0401. | |
| 50 if not invite.allow_registration then return; end | |
| 51 invite.landing_page = render_url(invite_url_template, { host = module.host, invite = invite }); | |
| 52 end | |
| 53 | |
| 54 module:hook("invite-created", add_landing_url); | |
| 55 | |
| 56 local function render_app_urls(apps, invite_vars) | |
| 57 local rendered_apps = {}; | |
| 58 for _, unrendered_app in ipairs(apps) do | |
| 59 local app = setmetatable({}, { __index = unrendered_app }); | |
| 60 local template_vars = { app = app, invite = invite_vars, base_url = base_url }; | |
| 61 if app.magic_link_format then | |
| 62 -- Magic link generally links directly to third-party | |
| 63 app.proceed_url = render_url(app.magic_link_format or app.link or "#", template_vars); | |
| 64 elseif app.supports_preauth_uri then | |
| 65 -- Proceed to a page that guides the user to download, and then | |
| 66 -- click the URI button | |
| 67 app.proceed_url = render_url("{base_url!}/setup/{app.id}?{invite.token}", template_vars); | |
| 68 else | |
| 69 -- Manual means proceed to web registration, but include app id | |
| 70 -- so it can show post-registration instructions | |
| 71 app.proceed_url = render_url(register_url_template, template_vars); | |
| 72 end | |
| 73 table.insert(rendered_apps, app); | |
| 74 end | |
| 75 return rendered_apps; | |
| 76 end | |
| 77 | |
| 78 function serve_invite_page(event) | |
| 79 local invite_page_template = assert(module:load_resource("html/invite.html")):read("*a"); | |
| 80 local invalid_invite_page_template = assert(module:load_resource("html/invite_invalid.html")):read("*a"); | |
| 81 | |
| 82 local invite = invites.get(event.request.url.query); | |
| 83 if not invite then | |
| 84 return render_html_template(invalid_invite_page_template, { | |
| 85 site_name = site_name; | |
| 86 static = base_url.."/static"; | |
| 87 }); | |
| 88 end | |
| 89 | |
| 90 local template_vars = { | |
| 91 site_name = site_name; | |
| 92 token = invite.token; | |
| 93 uri = invite.uri; | |
| 94 type = invite.type; | |
| 95 jid = invite.jid; | |
| 96 inviter = invite.inviter; | |
| 97 static = base_url.."/static"; | |
| 98 }; | |
| 99 template_vars.apps = render_app_urls(site_apps, template_vars); | |
| 100 | |
| 101 local invite_page = render_html_template(invite_page_template, template_vars); | |
| 102 return invite_page; | |
| 103 end | |
| 104 | |
| 105 function serve_setup_page(event, app_id) | |
| 106 local invite_page_template = assert(module:load_resource("html/client.html")):read("*a"); | |
| 107 local invalid_invite_page_template = assert(module:load_resource("html/invite_invalid.html")):read("*a"); | |
| 108 | |
| 109 local invite = invites.get(event.request.url.query); | |
| 110 if not invite then | |
| 111 return render_html_template(invalid_invite_page_template, { | |
| 112 site_name = site_name; | |
| 113 static = base_url.."/static"; | |
| 114 }); | |
| 115 end | |
| 116 | |
| 117 local template_vars = { | |
| 118 site_name = site_name; | |
| 119 apps = site_apps; | |
| 120 token = invite.token; | |
| 121 uri = invite.uri; | |
| 122 type = invite.type; | |
| 123 jid = invite.jid; | |
| 124 static = base_url.."/static"; | |
| 125 }; | |
| 126 template_vars.app = render_app_urls({ site_apps[app_id] }, template_vars)[1]; | |
| 127 | |
| 128 local invite_page = render_html_template(invite_page_template, template_vars); | |
| 129 return invite_page; | |
| 130 end | |
| 131 | |
| 132 local mime_map = { | |
| 133 png = "image/png"; | |
| 134 svg = "image/svg+xml"; | |
| 135 js = "application/javascript"; | |
| 136 }; | |
| 137 | |
| 138 module:provides("http", { | |
| 139 route = { | |
| 140 ["GET"] = serve_invite_page; | |
| 141 ["GET /setup/*"] = serve_setup_page; | |
| 142 ["GET /static/*"] = http_files and http_files.serve({ path = module:get_directory().."/static", mime_map = mime_map }); | |
| 143 }; | |
| 144 }); |
