login.py 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203
  1. from django.conf import settings
  2. from evennia.utils import utils
  3. from evennia.utils.evmenu import EvMenu
  4. CONNECTION_SCREEN_MODULE = settings.CONNECTION_SCREEN_MODULE
  5. _GUEST_ENABLED = settings.GUEST_ENABLED
  6. _ACCOUNT = utils.class_from_module(settings.BASE_ACCOUNT_TYPECLASS)
  7. _GUEST = utils.class_from_module(settings.BASE_GUEST_TYPECLASS)
  8. _ACCOUNT_HELP = (
  9. "Enter the name you used to log into the game before, " "or a new account-name if you are new."
  10. )
  11. _PASSWORD_HELP = (
  12. "Password should be a minimum of 8 characters (preferably longer) and "
  13. "can contain a mix of letters, spaces, digits and @/./+/-/_/'/, only."
  14. )
  15. def _show_help(caller, raw_string, **kwargs):
  16. """Echo help message, then re-run node that triggered it"""
  17. help_entry = kwargs["help_entry"]
  18. caller.msg(help_entry)
  19. return None # re-run calling node
  20. def node_enter_username(caller, raw_text, **kwargs):
  21. """
  22. Start node of menu
  23. Start login by displaying the connection screen and ask for a user name.
  24. """
  25. def _check_input(caller, username, **kwargs):
  26. """
  27. 'Goto-callable', set up to be called from the _default option below.
  28. Called when user enters a username string. Check if this username already exists and set the flag
  29. 'new_user' if not. Will also directly login if the username is 'guest'
  30. and GUEST_ENABLED is True.
  31. The return from this goto-callable determines which node we go to next
  32. and what kwarg it will be called with.
  33. """
  34. username = username.rstrip("\n")
  35. if username == "guest" and _GUEST_ENABLED:
  36. # do an immediate guest login
  37. session = caller
  38. address = session.address
  39. account, errors = _GUEST.authenticate(ip=address)
  40. if account:
  41. return "node_quit_or_login", {"login": True, "account": account}
  42. else:
  43. session.msg("|R{}|n".format("\n".join(errors)))
  44. return None # re-run the username node
  45. try:
  46. _ACCOUNT.objects.get(username__iexact=username)
  47. except _ACCOUNT.DoesNotExist:
  48. new_user = True
  49. else:
  50. new_user = False
  51. # pass username/new_user into next node as kwargs
  52. return "node_enter_password", {"new_user": new_user, "username": username}
  53. """Show the connect screen."""
  54. callables = utils.callables_from_module(CONNECTION_SCREEN_MODULE)
  55. if "connection_screen" in callables:
  56. connection_screen = callables["connection_screen"]()
  57. else:
  58. connection_screen = utils.random_string_from_module(CONNECTION_SCREEN_MODULE)
  59. if not connection_screen:
  60. connection_screen = "No connection screen found. Please contact an admin."
  61. if _GUEST_ENABLED:
  62. text = "Enter a new or existing user name to login (write 'guest' for a guest login):"
  63. else:
  64. text = "Enter a new or existing user name to login:"
  65. text = "{}\n\n{}".format(connection_screen, text)
  66. options = (
  67. {"key": "", "goto": "node_enter_username"},
  68. {"key": ("quit", "q"), "goto": "node_quit_or_login"},
  69. {"key": ("help", "h"), "goto": (_show_help, {"help_entry": _ACCOUNT_HELP, **kwargs})},
  70. {"key": "_default", "goto": _check_input},
  71. )
  72. return text, options
  73. def node_enter_password(caller, raw_string, **kwargs):
  74. """
  75. Handle password input.
  76. """
  77. def _check_input(caller, password, **kwargs):
  78. """
  79. 'Goto-callable', set up to be called from the _default option below.
  80. Called when user enters a password string. Check username + password
  81. viability. If it passes, the account will have been created and login
  82. will be initiated.
  83. The return from this goto-callable determines which node we go to next
  84. and what kwarg it will be called with.
  85. """
  86. # these flags were set by the goto-callable
  87. username = kwargs["username"]
  88. new_user = kwargs["new_user"]
  89. password = password.rstrip("\n")
  90. session = caller
  91. address = session.address
  92. if new_user:
  93. # create a new account
  94. account, errors = _ACCOUNT.create(
  95. username=username, password=password, ip=address, session=session
  96. )
  97. else:
  98. # check password against existing account
  99. account, errors = _ACCOUNT.authenticate(
  100. username=username, password=password, ip=address, session=session
  101. )
  102. if account:
  103. if new_user:
  104. session.msg("|gA new account |c{}|g was created. Welcome!|n".format(username))
  105. # pass login info to login node
  106. return "node_quit_or_login", {"login": True, "account": account}
  107. else:
  108. # restart due to errors
  109. session.msg("|R{}".format("\n".join(errors)))
  110. kwargs["retry_password"] = True
  111. return "node_enter_password", kwargs
  112. def _restart_login(caller, *args, **kwargs):
  113. caller.msg("|yCancelled login.|n")
  114. return "node_enter_username"
  115. username = kwargs["username"]
  116. if kwargs["new_user"]:
  117. if kwargs.get("retry_password"):
  118. # Attempting to fix password
  119. text = "Enter a new password:"
  120. else:
  121. text = "Creating a new account |c{}|n. " "Enter a password (empty to abort):".format(username)
  122. else:
  123. text = "Enter the password for account |c{}|n (empty to abort):".format(username)
  124. options = (
  125. {"key": "", "goto": _restart_login},
  126. {"key": ("quit", "q"), "goto": "node_quit_or_login"},
  127. {"key": ("help", "h"), "goto": (_show_help, {"help_entry": _PASSWORD_HELP, **kwargs})},
  128. {"key": "_default", "goto": (_check_input, kwargs)},
  129. )
  130. return text, options
  131. def node_quit_or_login(caller, raw_text, **kwargs):
  132. """
  133. Exit menu, either by disconnecting or logging in.
  134. """
  135. session = caller
  136. if kwargs.get("login"):
  137. account = kwargs.get("account")
  138. # TODO
  139. # session.msg("|gLogging in ...|n")
  140. # session.sessionhandler.login(session, account)
  141. # # go OOC
  142. # account.unpuppet_object(session)
  143. EvMenu(
  144. caller,
  145. "menus.char_manager",
  146. startnode="node_enter_char_management",
  147. auto_look=False,
  148. auto_quit=False,
  149. cmd_on_exit=None,
  150. node_formatter=plain_node_formatter,
  151. account=account,
  152. )
  153. else:
  154. session.sessionhandler.disconnect(session, "Goodbye! Logging off.")
  155. return "", {}
  156. def plain_node_formatter(nodetext, optionstext, caller=None):
  157. """Do not display the options, only the text.
  158. This function is used by EvMenu to format the text of nodes. The menu login
  159. is just a series of prompts, so we disable all automatic display decoration
  160. and let the nodes handle everything on their own.
  161. """
  162. return nodetext