from django.conf import settings from evennia.utils import utils from evennia.utils.evmenu import EvMenu CONNECTION_SCREEN_MODULE = settings.CONNECTION_SCREEN_MODULE _GUEST_ENABLED = settings.GUEST_ENABLED _ACCOUNT = utils.class_from_module(settings.BASE_ACCOUNT_TYPECLASS) _GUEST = utils.class_from_module(settings.BASE_GUEST_TYPECLASS) _ACCOUNT_HELP = ( "Enter the name you used to log into the game before, " "or a new account-name if you are new." ) _PASSWORD_HELP = ( "Password should be a minimum of 8 characters (preferably longer) and " "can contain a mix of letters, spaces, digits and @/./+/-/_/'/, only." ) def _show_help(caller, raw_string, **kwargs): """Echo help message, then re-run node that triggered it""" help_entry = kwargs["help_entry"] caller.msg(help_entry) return None # re-run calling node def node_enter_username(caller, raw_text, **kwargs): """ Start node of menu Start login by displaying the connection screen and ask for a user name. """ def _check_input(caller, username, **kwargs): """ 'Goto-callable', set up to be called from the _default option below. Called when user enters a username string. Check if this username already exists and set the flag 'new_user' if not. Will also directly login if the username is 'guest' and GUEST_ENABLED is True. The return from this goto-callable determines which node we go to next and what kwarg it will be called with. """ username = username.rstrip("\n") if username == "guest" and _GUEST_ENABLED: # do an immediate guest login session = caller address = session.address account, errors = _GUEST.authenticate(ip=address) if account: return "node_quit_or_login", {"login": True, "account": account} else: session.msg("|R{}|n".format("\n".join(errors))) return None # re-run the username node try: _ACCOUNT.objects.get(username__iexact=username) except _ACCOUNT.DoesNotExist: new_user = True else: new_user = False # pass username/new_user into next node as kwargs return "node_enter_password", {"new_user": new_user, "username": username} """Show the connect screen.""" callables = utils.callables_from_module(CONNECTION_SCREEN_MODULE) if "connection_screen" in callables: connection_screen = callables["connection_screen"]() else: connection_screen = utils.random_string_from_module(CONNECTION_SCREEN_MODULE) if not connection_screen: connection_screen = "No connection screen found. Please contact an admin." if _GUEST_ENABLED: text = "Enter a new or existing user name to login (write 'guest' for a guest login):" else: text = "Enter a new or existing user name to login:" text = "{}\n\n{}".format(connection_screen, text) options = ( {"key": "", "goto": "node_enter_username"}, {"key": ("quit", "q"), "goto": "node_quit_or_login"}, {"key": ("help", "h"), "goto": (_show_help, {"help_entry": _ACCOUNT_HELP, **kwargs})}, {"key": "_default", "goto": _check_input}, ) return text, options def node_enter_password(caller, raw_string, **kwargs): """ Handle password input. """ def _check_input(caller, password, **kwargs): """ 'Goto-callable', set up to be called from the _default option below. Called when user enters a password string. Check username + password viability. If it passes, the account will have been created and login will be initiated. The return from this goto-callable determines which node we go to next and what kwarg it will be called with. """ # these flags were set by the goto-callable username = kwargs["username"] new_user = kwargs["new_user"] password = password.rstrip("\n") session = caller address = session.address if new_user: # create a new account account, errors = _ACCOUNT.create( username=username, password=password, ip=address, session=session ) else: # check password against existing account account, errors = _ACCOUNT.authenticate( username=username, password=password, ip=address, session=session ) if account: if new_user: session.msg("|gA new account |c{}|g was created. Welcome!|n".format(username)) # pass login info to login node return "node_quit_or_login", {"login": True, "account": account} else: # restart due to errors session.msg("|R{}".format("\n".join(errors))) kwargs["retry_password"] = True return "node_enter_password", kwargs def _restart_login(caller, *args, **kwargs): caller.msg("|yCancelled login.|n") return "node_enter_username" username = kwargs["username"] if kwargs["new_user"]: if kwargs.get("retry_password"): # Attempting to fix password text = "Enter a new password:" else: text = "Creating a new account |c{}|n. " "Enter a password (empty to abort):".format(username) else: text = "Enter the password for account |c{}|n (empty to abort):".format(username) options = ( {"key": "", "goto": _restart_login}, {"key": ("quit", "q"), "goto": "node_quit_or_login"}, {"key": ("help", "h"), "goto": (_show_help, {"help_entry": _PASSWORD_HELP, **kwargs})}, {"key": "_default", "goto": (_check_input, kwargs)}, ) return text, options def node_quit_or_login(caller, raw_text, **kwargs): """ Exit menu, either by disconnecting or logging in. """ session = caller if kwargs.get("login"): account = kwargs.get("account") # TODO # session.msg("|gLogging in ...|n") # session.sessionhandler.login(session, account) # # go OOC # account.unpuppet_object(session) EvMenu( caller, "menus.char_manager", startnode="node_enter_char_management", auto_look=False, auto_quit=False, cmd_on_exit=None, node_formatter=plain_node_formatter, account=account, ) else: session.sessionhandler.disconnect(session, "Goodbye! Logging off.") return "", {} def plain_node_formatter(nodetext, optionstext, caller=None): """Do not display the options, only the text. This function is used by EvMenu to format the text of nodes. The menu login is just a series of prompts, so we disable all automatic display decoration and let the nodes handle everything on their own. """ return nodetext