Mercurial > prosody-modules
changeset 4184:9127fa98ee1e
mod_welcome_page: New module to provide a friendly entrypoint to invite-based setups
author | Matthew Wild <mwild1@gmail.com> |
---|---|
date | Fri, 09 Oct 2020 12:19:46 +0100 |
parents | ad9ce6750880 |
children | 06a9ac93e2f1 |
files | mod_welcome_page/README.markdown mod_welcome_page/html/index.html mod_welcome_page/mod_welcome_page.lua |
diffstat | 3 files changed, 175 insertions(+), 0 deletions(-) [+] |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mod_welcome_page/README.markdown Fri Oct 09 12:19:46 2020 +0100 @@ -0,0 +1,47 @@ +--- +labels: +- 'Stage-Beta' +summary: 'Serve a welcome page to users' +rockspec: + dependencies: + - mod_invites + build: + copy_directories: + - html +... + +Introduction +============ + +This module serves a welcome page to users, and allows them to create an +account invite via the web on invite-only servers. + +The page template and policy of when to allow account creation are both +possible to override. + +This module is part of the suite of modules that implement invite-based +account registration for Prosody. The other modules are: + +- mod_invites +- mod_invites_adhoc +- mod_invites_page +- mod_invites_register +- mod_invites_register_web +- mod_register_apps + +For details and a full overview, start with the mod_invites documentation. + +Configuration +======= + +`welcome_page_template_path` +: The path to a directory containing the page templates and assets. See + the module source for the example template. + +`welcome_page_variables` +: Optional variables to pass to the template, available as `{var.name}` + +`welcome_page_open_registration` +: Whether to allow account creation in the absence of any other plugin + overriding the policy. Defaults to `false` unless `registration_invite_only` + is set to `false`.
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mod_welcome_page/html/index.html Fri Oct 09 12:19:46 2020 +0100 @@ -0,0 +1,57 @@ +<!DOCTYPE html> +<html> +<head> + <meta charset="utf-8"> + <meta name="viewport" content="width=device-width, initial-scale=1.0"> + <title>{site_name}</title> + <link rel="stylesheet" href="/share/bootstrap4/css/bootstrap.min.css"> + <link rel="apple-touch-icon" sizes="180x180" href="/apple-touch-icon.png"> + <link rel="icon" type="image/png" sizes="32x32" href="/favicon-32x32.png"> + <link rel="icon" type="image/png" sizes="16x16" href="/favicon-16x16.png"> + <link rel="manifest" href="/site.webmanifest"> + <link rel="mask-icon" href="/safari-pinned-tab.svg" color="#5bbad5"> + <meta name="msapplication-TileColor" content="#fbd308"> + <meta name="theme-color" content="#fbd308"> + <style> + #background { + z-index: -1; + display: block; + width: 100%; + height: 100%; + background: -webkit-linear-gradient(to left,#0cd0f3,#dfd18e); + background: linear-gradient(to left,#0cd0f3,#dfd18e); + opacity: 0.8; + } + .jumbotron { + opacity: 0.8; + } + </style> +</head> +<body> + <div id="background" class="fixed-top overflow-hidden"></div> + + <div class="jumbotron m-md-3"> + <h1 class="display-4">{site_name}</h1> + <p class="lead">Welcome to our chat service</p> + <hr class="my-4"> + <p>{site_name} is an XMPP chat service.</p> + + {message&<div class="alert {message.class?alert-info}" role="alert"> + {message.text} + </div>} + + <form method="POST" action="/" class="d-inline"> + <button class="btn btn-primary btn-lg mb-2" type="submit">Create account</button> + </form> + + {var.links&{var.links# + <a class="btn btn-{item.class?secondary} btn-lg mb-2" href="{item.href}" role="button">{item.text}</a> + }} + + {var.webchat&<p class="pt-2">Already have an account here? <a href="{var.webchat}">Log in via the web chat</a></p>} + <div> + + <script src="/share/jquery/jquery.min.js"></script> + <script src="/share/bootstrap4/js/bootstrap.min.js"></script> +</body> +</html>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mod_welcome_page/mod_welcome_page.lua Fri Oct 09 12:19:46 2020 +0100 @@ -0,0 +1,71 @@ +local st = require "util.stanza"; +local url_escape = require "util.http".urlencode; +local render_html_template = require"util.interpolation".new("%b{}", st.xml_escape, { + urlescape = url_escape; +}); + +local template_path = module:get_option_string("welcome_page_template_path", module:get_directory().."/html"); +local user_vars = module:get_option("welcome_page_variables", {}); +local site_name = module:get_option("site_name", module.host); +local invite_only = module:get_option_boolean("registration_invite_only", true); +local open_registration = module:get_option_boolean("welcome_page_open_registration", not invite_only); + +module:depends("http"); +local invites = module:depends("invites"); + +local function load_template(path) + local template_file, err = io.open(path); + if not template_file then + error("Unable to load template file: "..tostring(err)); + end + local template = template_file:read("*a"); + template_file:close(); + return template; +end + +local template = load_template(template_path.."/index.html"); + +local function serve_page(event) + event.response.headers["Content-Type"] = "text/html; charset=utf-8"; + return render_html_template(template, { + site_name = site_name; + request = event.request; + var = user_vars; + }); +end + +local function handle_submit(event) + local submission = { allowed = open_registration, request = event.request }; + module:fire_event("mod_welcome_page/submission", submission); + if not submission.allowed then + event.response.headers["Content-Type"] = "text/html; charset=utf-8"; + return render_html_template(template, { + site_name = site_name; + request = event.request; + var = user_vars; + message = { + class = "alert-danger"; + text = submission.reason or "Account creation is not possible at this time"; + }; + }); + end + + local invite = invites.create_account(nil, { source = module.name }); + if not invite then + return 500; + end + + event.response.headers.Location = invite.landing_page or invite.uri; + + return 303; +end + +local http_files = module:depends("http_files"); + +module:provides("http", { + route = { + ["GET"] = serve_page; + ["GET /*"] = http_files.serve({ path = template_path }); + ["POST"] = handle_submit; + }; +});