Software / code / prosody
Comparison
plugins/mod_invites.lua @ 13161:9ba11ef91ce4
mod_invites: Refactor argument handling using util.argparse
This makes it so that --admin and --role are no longer mutually
exclusive, they the former is simply treated as another --role.
This was likely a leftover from when only a single role was possible.
It does however become unclear which should be the primary, since the
order is not preserved by argparse.
Bonus: Loading of modules is avoided with only the --help is shown.
| author | Kim Alvefur <zash@zash.se> |
|---|---|
| date | Wed, 12 Jan 2022 10:23:13 +0100 |
| parent | 13096:9638ff8b1c81 |
| child | 13209:c8d949cf6b09 |
comparison
equal
deleted
inserted
replaced
| 13160:4ee9a912ceea | 13161:9ba11ef91ce4 |
|---|---|
| 1 local id = require "prosody.util.id"; | 1 local id = require "prosody.util.id"; |
| 2 local it = require "prosody.util.iterators"; | 2 local it = require "prosody.util.iterators"; |
| 3 local url = require "socket.url"; | 3 local url = require "socket.url"; |
| 4 local jid_node = require "prosody.util.jid".node; | 4 local jid_node = require "prosody.util.jid".node; |
| 5 local jid_split = require "prosody.util.jid".split; | 5 local jid_split = require "prosody.util.jid".split; |
| 6 local argparse = require "prosody.util.argparse"; | |
| 6 | 7 |
| 7 local default_ttl = module:get_option_number("invite_expiry", 86400 * 7); | 8 local default_ttl = module:get_option_number("invite_expiry", 86400 * 7); |
| 8 | 9 |
| 9 local token_storage; | 10 local token_storage; |
| 10 if prosody.process_type == "prosody" or prosody.shutdown then | 11 if prosody.process_type == "prosody" or prosody.shutdown then |
| 228 if not invite then return nil, err; end | 229 if not invite then return nil, err; end |
| 229 return true, invite.landing_page or invite.uri; | 230 return true, invite.landing_page or invite.uri; |
| 230 end | 231 end |
| 231 end | 232 end |
| 232 | 233 |
| 234 local subcommands = {}; | |
| 235 | |
| 233 --- prosodyctl command | 236 --- prosodyctl command |
| 234 function module.command(arg) | 237 function module.command(arg) |
| 235 if #arg < 2 or arg[1] ~= "generate" then | 238 local opts = argparse.parse(arg, { short_params = { h = "help"; ["?"] = "help" } }); |
| 239 local cmd = table.remove(arg, 1); -- pop command | |
| 240 if opts.help or not cmd or not subcommands[cmd] then | |
| 236 print("usage: prosodyctl mod_"..module.name.." generate example.com"); | 241 print("usage: prosodyctl mod_"..module.name.." generate example.com"); |
| 237 return 2; | 242 return 2; |
| 238 end | 243 end |
| 239 table.remove(arg, 1); -- pop command | 244 return subcommands[cmd](arg); |
| 245 end | |
| 246 | |
| 247 function subcommands.generate(arg) | |
| 240 | 248 |
| 241 local sm = require "prosody.core.storagemanager"; | 249 local sm = require "prosody.core.storagemanager"; |
| 242 local mm = require "prosody.core.modulemanager"; | 250 local mm = require "prosody.core.modulemanager"; |
| 243 | 251 |
| 244 local host = arg[1]; | 252 local host = table.remove(arg, 1); -- pop host |
| 245 assert(prosody.hosts[host], "Host "..tostring(host).." does not exist"); | 253 assert(prosody.hosts[host], "Host "..tostring(host).." does not exist"); |
| 246 sm.initialize_host(host); | 254 sm.initialize_host(host); |
| 247 table.remove(arg, 1); -- pop host | |
| 248 module.host = host; --luacheck: ignore 122/module | 255 module.host = host; --luacheck: ignore 122/module |
| 249 token_storage = module:open_store("invite_token", "map"); | 256 token_storage = module:open_store("invite_token", "map"); |
| 257 | |
| 258 local opts = argparse.parse(arg, { | |
| 259 short_params = { h = "help"; ["?"] = "help"; g = "group" }; | |
| 260 value_params = { group = true; reset = true; role = true }; | |
| 261 array_params = { group = true; role = true }; | |
| 262 }); | |
| 263 | |
| 264 | |
| 265 if opts.help then | |
| 266 print("usage: prosodyctl mod_" .. module.name .. " generate DOMAIN --reset USERNAME") | |
| 267 print("usage: prosodyctl mod_" .. module.name .. " generate DOMAIN [--admin] [--role ROLE] [--group GROUPID]...") | |
| 268 print() | |
| 269 print("This command has two modes: password reset and new account.") | |
| 270 print("If --reset is given, the command operates in password reset mode and in new account mode otherwise.") | |
| 271 print() | |
| 272 print("required arguments in password reset mode:") | |
| 273 print() | |
| 274 print(" --reset USERNAME Generate a password reset link for the given USERNAME.") | |
| 275 print() | |
| 276 print("optional arguments in new account mode:") | |
| 277 print() | |
| 278 print(" --admin Make the new user privileged") | |
| 279 print(" Equivalent to --role prosody:admin") | |
| 280 print(" --role ROLE Grant the given ROLE to the new user") | |
| 281 print(" --group GROUPID Add the user to the group with the given ID") | |
| 282 print(" Can be specified multiple times") | |
| 283 print() | |
| 284 print("--group can be specified multiple times; the user will be added to all groups.") | |
| 285 print() | |
| 286 print("--reset and the other options cannot be mixed.") | |
| 287 return 2 | |
| 288 end | |
| 250 | 289 |
| 251 -- Load mod_invites | 290 -- Load mod_invites |
| 252 local invites = module:depends("invites"); | 291 local invites = module:depends("invites"); |
| 253 -- Optional community module that if used, needs to be loaded here | 292 -- Optional community module that if used, needs to be loaded here |
| 254 local invites_page_module = module:get_option_string("invites_page_module", "invites_page"); | 293 local invites_page_module = module:get_option_string("invites_page_module", "invites_page"); |
| 255 if mm.get_modules_for_host(host):contains(invites_page_module) then | 294 if mm.get_modules_for_host(host):contains(invites_page_module) then |
| 256 module:depends(invites_page_module); | 295 module:depends(invites_page_module); |
| 257 end | 296 end |
| 258 | 297 |
| 259 local allow_reset; | 298 local allow_reset; |
| 260 local roles = {}; | 299 |
| 261 local groups = {}; | 300 if opts.reset then |
| 262 | 301 local nodeprep = require "prosody.util.encodings".stringprep.nodeprep; |
| 263 while #arg > 0 do | 302 local username = nodeprep(opts.reset) |
| 264 local value = arg[1]; | 303 if not username then |
| 265 table.remove(arg, 1); | 304 print("Please supply a valid username to generate a reset link for"); |
| 266 if value == "--help" then | 305 return 2; |
| 267 print("usage: prosodyctl mod_"..module.name.." generate DOMAIN --reset USERNAME") | 306 end |
| 268 print("usage: prosodyctl mod_"..module.name.." generate DOMAIN [--admin] [--role ROLE] [--group GROUPID]...") | 307 allow_reset = username; |
| 269 print() | 308 end |
| 270 print("This command has two modes: password reset and new account.") | 309 |
| 271 print("If --reset is given, the command operates in password reset mode and in new account mode otherwise.") | 310 local roles = opts.role or {}; |
| 272 print() | 311 local groups = opts.groups or {}; |
| 273 print("required arguments in password reset mode:") | 312 |
| 274 print() | 313 if opts.admin then |
| 275 print(" --reset USERNAME Generate a password reset link for the given USERNAME.") | 314 -- Insert it first since we don't get order out of argparse |
| 276 print() | 315 table.insert(roles, 1, "prosody:admin"); |
| 277 print("optional arguments in new account mode:") | |
| 278 print() | |
| 279 print(" --admin Make the new user privileged") | |
| 280 print(" Equivalent to --role prosody:admin") | |
| 281 print(" --role ROLE Grant the given ROLE to the new user") | |
| 282 print(" --group GROUPID Add the user to the group with the given ID") | |
| 283 print(" Can be specified multiple times") | |
| 284 print() | |
| 285 print("--role and --admin can be specified multiple times; the first role becomes the primary role, the rest become secondary roles") | |
| 286 print("--group can be specified multiple times; the user will be added to all groups.") | |
| 287 print() | |
| 288 print("--reset and the other options cannot be mixed.") | |
| 289 return 2 | |
| 290 elseif value == "--reset" then | |
| 291 local nodeprep = require "prosody.util.encodings".stringprep.nodeprep; | |
| 292 local username = nodeprep(arg[1]) | |
| 293 table.remove(arg, 1); | |
| 294 if not username then | |
| 295 print("Please supply a valid username to generate a reset link for"); | |
| 296 return 2; | |
| 297 end | |
| 298 allow_reset = username; | |
| 299 elseif value == "--admin" then | |
| 300 table.insert(roles, "prosody:admin"); | |
| 301 elseif value == "--role" then | |
| 302 local rolename = arg[1]; | |
| 303 if not rolename then | |
| 304 print("Please supply a role name"); | |
| 305 return 2; | |
| 306 end | |
| 307 table.insert(roles, rolename); | |
| 308 table.remove(arg, 1); | |
| 309 elseif value == "--group" or value == "-g" then | |
| 310 local groupid = arg[1]; | |
| 311 if not groupid then | |
| 312 print("Please supply a group ID") | |
| 313 return 2; | |
| 314 end | |
| 315 table.insert(groups, groupid); | |
| 316 table.remove(arg, 1); | |
| 317 else | |
| 318 print("unexpected argument: "..value) | |
| 319 end | |
| 320 end | 316 end |
| 321 | 317 |
| 322 local invite; | 318 local invite; |
| 323 if allow_reset then | 319 if allow_reset then |
| 324 if roles[1] then | 320 if roles[1] then |