evennia.contrib.base_systems.email_login.email_login

Email-based login system

Evennia contrib - Griatch 2012

This is a variant of the login system that requires an email-address instead of a username to login.

This used to be the default Evennia login before replacing it with a more standard username + password system (having to supply an email for some reason caused a lot of confusion when people wanted to expand on it. The email is not strictly needed internally, nor is any confirmation email sent out anyway).

Installation is simple:

To your settings file, add/edit settings as follows:

CMDSET_UNLOGGEDIN = "contrib.base_systems.email_login.email_login.UnloggedinCmdSet"
CONNECTION_SCREEN_MODULE = "contrib.base_systems.email_login.connection_screens"

That’s it. Reload the server and try to log in to see it.

The initial login “graphic” will still not mention email addresses after this change. The login splashscreen is taken from strings in the module given by settings.CONNECTION_SCREEN_MODULE.

class evennia.contrib.base_systems.email_login.email_login.CmdUnconnectedConnect(**kwargs)[source]

Bases: MuxCommand

Connect to the game.

Usage (at login screen):

connect <email> <password>

Use the create command to first create an account before logging in.

key = 'connect'
aliases = ['conn', 'co', 'con']
locks = 'cmd:all()'
func()[source]

Uses the Django admin api. Note that unlogged-in commands have a unique position in that their func() receives a session object instead of a source_object like all other types of logged-in commands (this is because there is no object yet before the account has logged in)

help_category = 'general'
lock_storage = 'cmd:all()'
search_index_entry = {'aliases': 'conn co con', 'category': 'general', 'key': 'connect', 'no_prefix': ' conn co con', 'tags': '', 'text': '\nConnect to the game.\n\nUsage (at login screen):\n    connect <email> <password>\n\nUse the create command to first create an account before logging in.\n'}
class evennia.contrib.base_systems.email_login.email_login.CmdUnconnectedCreate(**kwargs)[source]

Bases: MuxCommand

Create a new account.

Usage (at login screen):

create “accountname” <email> <password>

This creates a new account account.

key = 'create'
aliases = ['cr', 'cre']
locks = 'cmd:all()'
at_pre_cmd()[source]

Verify that account creation is enabled.

parse()[source]

The parser must handle the multiple-word account name enclosed in quotes:

connect “Long name with many words” my@myserv.com mypassw

func()[source]

Do checks and create account

help_category = 'general'
lock_storage = 'cmd:all()'
search_index_entry = {'aliases': 'cr cre', 'category': 'general', 'key': 'create', 'no_prefix': ' cr cre', 'tags': '', 'text': '\nCreate a new account.\n\nUsage (at login screen):\n    create "accountname" <email> <password>\n\nThis creates a new account account.\n\n'}
class evennia.contrib.base_systems.email_login.email_login.CmdUnconnectedQuit(**kwargs)[source]

Bases: MuxCommand

We maintain a different version of the quit command here for unconnected accounts for the sake of simplicity. The logged in version is a bit more complicated.

key = 'quit'
aliases = ['q', 'qu']
locks = 'cmd:all()'
func()[source]

Simply close the connection.

help_category = 'general'
lock_storage = 'cmd:all()'
search_index_entry = {'aliases': 'q qu', 'category': 'general', 'key': 'quit', 'no_prefix': ' q qu', 'tags': '', 'text': '\nWe maintain a different version of the `quit` command\nhere for unconnected accounts for the sake of simplicity. The logged in\nversion is a bit more complicated.\n'}
class evennia.contrib.base_systems.email_login.email_login.CmdUnconnectedLook(**kwargs)[source]

Bases: MuxCommand

This is an unconnected version of the look command for simplicity.

This is called by the server and kicks everything in gear. All it does is display the connect screen.

key = '__unloggedin_look_command'
aliases = ['l', 'look']
locks = 'cmd:all()'
func()[source]

Show the connect screen.

help_category = 'general'
lock_storage = 'cmd:all()'
search_index_entry = {'aliases': 'l look', 'category': 'general', 'key': '__unloggedin_look_command', 'no_prefix': ' l look', 'tags': '', 'text': '\nThis is an unconnected version of the `look` command for simplicity.\n\nThis is called by the server and kicks everything in gear.\nAll it does is display the connect screen.\n'}
class evennia.contrib.base_systems.email_login.email_login.CmdUnconnectedHelp(**kwargs)[source]

Bases: MuxCommand

This is an unconnected version of the help command, for simplicity. It shows a pane of info.

key = 'help'
aliases = ['?', 'h']
locks = 'cmd:all()'
func()[source]

Shows help

help_category = 'general'
lock_storage = 'cmd:all()'
search_index_entry = {'aliases': '? h', 'category': 'general', 'key': 'help', 'no_prefix': ' ? h', 'tags': '', 'text': '\nThis is an unconnected version of the help command,\nfor simplicity. It shows a pane of info.\n'}
class evennia.contrib.base_systems.email_login.email_login.AccountDB(*args, **kwargs)[source]

Bases: TypedObject, AbstractUser

This is a special model using Django’s ‘profile’ functionality and extends the default Django User model. It is defined as such by use of the variable AUTH_PROFILE_MODULE in the settings. One accesses the fields/methods. We try use this model as much as possible rather than User, since we can customize this to our liking.

The TypedObject supplies the following (inherited) properties:

  • key - main name

  • typeclass_path - the path to the decorating typeclass

  • typeclass - auto-linked typeclass

  • date_created - time stamp of object creation

  • permissions - perm strings

  • dbref - #id of object

  • db - persistent attribute storage

  • ndb - non-persistent attribute storage

The AccountDB adds the following properties:

  • is_connected - If any Session is currently connected to this Account

  • name - alias for user.username

  • sessions - sessions connected to this account

  • is_superuser - bool if this account is a superuser

  • is_bot - bool if this account is a bot and not a real account

exception DoesNotExist

Bases: ObjectDoesNotExist

exception MultipleObjectsReturned

Bases: MultipleObjectsReturned

account_subscription_set

Accessor to the related objects manager on the forward and reverse sides of a many-to-many relation.

In the example:

class Pizza(Model):
    toppings = ManyToManyField(Topping, related_name='pizzas')

**Pizza.toppings** and **Topping.pizzas** are **ManyToManyDescriptor** instances.

Most of the implementation is delegated to a dynamically defined manager class built by **create_forward_many_to_many_manager()** defined below.

property cmdset_storage

Getter. Allows for value = self.name. Returns a list of cmdset_storage.

date_joined

A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.

db_attributes

Accessor to the related objects manager on the forward and reverse sides of a many-to-many relation.

In the example:

class Pizza(Model):
    toppings = ManyToManyField(Topping, related_name='pizzas')

**Pizza.toppings** and **Topping.pizzas** are **ManyToManyDescriptor** instances.

Most of the implementation is delegated to a dynamically defined manager class built by **create_forward_many_to_many_manager()** defined below.

db_cmdset_storage

A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.

db_date_created

A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.

db_is_bot

A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.

db_is_connected

A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.

db_key

A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.

db_lock_storage

A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.

db_tags

Accessor to the related objects manager on the forward and reverse sides of a many-to-many relation.

In the example:

class Pizza(Model):
    toppings = ManyToManyField(Topping, related_name='pizzas')

**Pizza.toppings** and **Topping.pizzas** are **ManyToManyDescriptor** instances.

Most of the implementation is delegated to a dynamically defined manager class built by **create_forward_many_to_many_manager()** defined below.

db_typeclass_path

A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.

email

A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.

first_name

A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.

get_next_by_date_joined(*, field=<django.db.models.fields.DateTimeField: date_joined>, is_next=True, **kwargs)
get_next_by_db_date_created(*, field=<django.db.models.fields.DateTimeField: db_date_created>, is_next=True, **kwargs)
get_previous_by_date_joined(*, field=<django.db.models.fields.DateTimeField: date_joined>, is_next=False, **kwargs)
get_previous_by_db_date_created(*, field=<django.db.models.fields.DateTimeField: db_date_created>, is_next=False, **kwargs)
groups

Accessor to the related objects manager on the forward and reverse sides of a many-to-many relation.

In the example:

class Pizza(Model):
    toppings = ManyToManyField(Topping, related_name='pizzas')

**Pizza.toppings** and **Topping.pizzas** are **ManyToManyDescriptor** instances.

Most of the implementation is delegated to a dynamically defined manager class built by **create_forward_many_to_many_manager()** defined below.

hide_from_accounts_set

Accessor to the related objects manager on the forward and reverse sides of a many-to-many relation.

In the example:

class Pizza(Model):
    toppings = ManyToManyField(Topping, related_name='pizzas')

**Pizza.toppings** and **Topping.pizzas** are **ManyToManyDescriptor** instances.

Most of the implementation is delegated to a dynamically defined manager class built by **create_forward_many_to_many_manager()** defined below.

id

A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.

is_active

A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.

property is_bot

A wrapper for getting database field db_is_bot.

property is_connected

A wrapper for getting database field db_is_connected.

is_staff

A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.

is_superuser

A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.

property key
last_login

A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.

last_name

A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.

logentry_set

Accessor to the related objects manager on the reverse side of a many-to-one relation.

In the example:

class Child(Model):
    parent = ForeignKey(Parent, related_name='children')

**Parent.children** is a **ReverseManyToOneDescriptor** instance.

Most of the implementation is delegated to a dynamically defined manager class built by **create_forward_many_to_many_manager()** defined below.

property name
objectdb_set

Accessor to the related objects manager on the reverse side of a many-to-one relation.

In the example:

class Child(Model):
    parent = ForeignKey(Parent, related_name='children')

**Parent.children** is a **ReverseManyToOneDescriptor** instance.

Most of the implementation is delegated to a dynamically defined manager class built by **create_forward_many_to_many_manager()** defined below.

objects = <evennia.accounts.manager.AccountDBManager object>
password

A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.

path = 'evennia.accounts.models.AccountDB'
receiver_account_set

Accessor to the related objects manager on the forward and reverse sides of a many-to-many relation.

In the example:

class Pizza(Model):
    toppings = ManyToManyField(Topping, related_name='pizzas')

**Pizza.toppings** and **Topping.pizzas** are **ManyToManyDescriptor** instances.

Most of the implementation is delegated to a dynamically defined manager class built by **create_forward_many_to_many_manager()** defined below.

scriptdb_set

Accessor to the related objects manager on the reverse side of a many-to-one relation.

In the example:

class Child(Model):
    parent = ForeignKey(Parent, related_name='children')

**Parent.children** is a **ReverseManyToOneDescriptor** instance.

Most of the implementation is delegated to a dynamically defined manager class built by **create_forward_many_to_many_manager()** defined below.

sender_account_set

Accessor to the related objects manager on the forward and reverse sides of a many-to-many relation.

In the example:

class Pizza(Model):
    toppings = ManyToManyField(Topping, related_name='pizzas')

**Pizza.toppings** and **Topping.pizzas** are **ManyToManyDescriptor** instances.

Most of the implementation is delegated to a dynamically defined manager class built by **create_forward_many_to_many_manager()** defined below.

typename = 'SharedMemoryModelBase'
property uid

Getter. Retrieves the user id

user_permissions

Accessor to the related objects manager on the forward and reverse sides of a many-to-many relation.

In the example:

class Pizza(Model):
    toppings = ManyToManyField(Topping, related_name='pizzas')

**Pizza.toppings** and **Topping.pizzas** are **ManyToManyDescriptor** instances.

Most of the implementation is delegated to a dynamically defined manager class built by **create_forward_many_to_many_manager()** defined below.

username

A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.

class evennia.contrib.base_systems.email_login.email_login.CmdSet(cmdsetobj=None, key=None)[source]

Bases: object

This class describes a unique cmdset that understands priorities. CmdSets can be merged and made to perform various set operations on each other. CmdSets have priorities that affect which of their ingoing commands gets used.

In the examples, cmdset A always have higher priority than cmdset B.

key - the name of the cmdset. This can be used on its own for game operations

mergetype (partly from Set theory):

Union - The two command sets are merged so that as many

commands as possible of each cmdset ends up in the merged cmdset. Same-name commands are merged by priority. This is the most common default. Ex: A1,A3 + B1,B2,B4,B5 = A1,B2,A3,B4,B5

Intersect - Only commands found in both cmdsets

(i.e. which have same names) end up in the merged cmdset, with the higher-priority cmdset replacing the lower one. Ex: A1,A3 + B1,B2,B4,B5 = A1

Replace - The commands of this cmdset completely replaces

the lower-priority cmdset’s commands, regardless of if same-name commands exist. Ex: A1,A3 + B1,B2,B4,B5 = A1,A3

Remove - This removes the relevant commands from the

lower-priority cmdset completely. They are not replaced with anything, so this in effects uses the high-priority cmdset as a filter to affect the low-priority cmdset. Ex: A1,A3 + B1,B2,B4,B5 = B2,B4,B5

Note: Commands longer than 2 characters and starting

with double underscrores, like ‘__noinput_command’ are considered ‘system commands’ and are excempt from all merge operations - they are ALWAYS included across mergers and only affected if same-named system commands replace them.

priority- All cmdsets are always merged in pairs of two so that

the higher set’s mergetype is applied to the lower-priority cmdset. Default commands have priority 0, high-priority ones like Exits and Channels have 10 and 9. Priorities can be negative as well to give default commands preference.

duplicates - determines what happens when two sets of equal

priority merge (only). Defaults to None and has the first of them in the merger (i.e. A above) automatically taking precedence. But if duplicates is true, the result will be a merger with more than one of each name match. This will usually lead to the account receiving a multiple-match error higher up the road, but can be good for things like cmdsets on non-account objects in a room, to allow the system to warn that more than one ‘ball’ in the room has the same ‘kick’ command defined on it, so it may offer a chance to select which ball to kick … Allowing duplicates only makes sense for Union and Intersect, the setting is ignored for the other mergetypes. Note that the duplicates flag is not propagated in a cmdset merger. So A + B = C will result in a cmdset with duplicate commands, but C.duplicates will be None. For duplication to apply to a whole cmdset stack merge, _all_ cmdsets in the stack must have .duplicates=True set.

Finally, if a final cmdset has .duplicates=None (the normal unless created alone with another value), the cmdhandler will assume True for object-based cmdsets and False for all other. This is usually the most intuitive outcome.

key_mergetype (dict) - allows the cmdset to define a unique

mergetype for particular cmdsets. Format is {CmdSetkeystring:mergetype}. Priorities still apply. Example: {‘Myevilcmdset’,’Replace’} which would make sure for this set to always use ‘Replace’ on Myevilcmdset no matter what overall mergetype this set has.

no_objs - don’t include any commands from nearby objects

when searching for suitable commands

no_exits - ignore the names of exits when matching against

commands

no_channels - ignore the name of channels when matching against

commands (WARNING- this is dangerous since the account can then not even ask staff for help if something goes wrong)

__init__(cmdsetobj=None, key=None)[source]

Creates a new CmdSet instance.

Parameters:
  • cmdsetobj (Session, Account, Object, optional) – This is the database object to which this particular instance of cmdset is related. It is often a character but may also be a regular object, Account or Session.

  • key (str, optional) – The idenfier for this cmdset. This helps if wanting to selectively remov cmdsets.

add(cmd, allow_duplicates=False)[source]

Add a new command or commands to this CmdSet, a list of commands or a cmdset to this cmdset. Note that this is not a merge operation (that is handled by the + operator).

Parameters:
  • cmd (Command, list, Cmdset) – This allows for adding one or more commands to this Cmdset in one go. If another Cmdset is given, all its commands will be added.

  • allow_duplicates (bool, optional) – If set, will not try to remove duplicate cmds in the set. This is needed during the merge process to avoid wiping commands coming from cmdsets with duplicate=True.

Notes

If cmd already exists in set, it will replace the old one (no priority checking etc happens here). This is very useful when overloading default commands).

If cmd is another cmdset class or -instance, the commands of that command set is added to this one, as if they were part of the original cmdset definition. No merging or priority checks are made, rather later added commands will simply replace existing ones to make a unique set.

at_cmdset_creation()[source]

Hook method - this should be overloaded in the inheriting class, and should take care of populating the cmdset by use of self.add().

count()[source]

Number of commands in set.

Returns:

N (int) – Number of commands in this Cmdset.

duplicates = None
errmessage = ''
get(cmd)[source]

Get a command from the cmdset. This is mostly useful to check if the command is part of this cmdset or not.

Parameters:

cmd (Command or str) – Either the Command object or its key.

Returns:

cmd (Command) – The first matching Command in the set.

get_all_cmd_keys_and_aliases(caller=None)[source]

Collects keys/aliases from commands

Parameters:

caller (Object, optional) – If set, this is used to check access permissions on each command. Only commands that pass are returned.

Returns:

names (list)

A list of all command keys and aliases in this cmdset. If caller

was given, this list will only contain commands to which caller passed the call locktype check.

get_system_cmds()[source]

Get system commands in cmdset

Returns:

sys_cmds (list) – The system commands in the set.

Notes

As far as the Cmdset is concerned, system commands are any commands with a key starting with double underscore __. These are excempt from merge operations.

key = 'Unnamed CmdSet'
key_mergetypes = {}
make_unique(caller)[source]

Remove duplicate command-keys (unsafe)

Parameters:

caller (object) – Commands on this object will get preference in the duplicate removal.

Notes

This is an unsafe command meant to clean out a cmdset of doublet commands after it has been created. It is useful for commands inheriting cmdsets from the cmdhandler where obj-based cmdsets always are added double. Doublets will be weeded out with preference to commands defined on caller, otherwise just by first-come-first-served.

mergetype = 'Union'
no_channels = None
no_exits = None
no_objs = None
path = 'evennia.commands.cmdset.CmdSet'
persistent = False
priority = 0
remove(cmd)[source]

Remove a command instance from the cmdset.

Parameters:

cmd (Command or str) – Either the Command object to remove or the key of such a command.

to_duplicate = ('key', 'cmdsetobj', 'no_exits', 'no_objs', 'no_channels', 'persistent', 'mergetype', 'priority', 'duplicates', 'errmessage')
class evennia.contrib.base_systems.email_login.email_login.MuxCommand(**kwargs)[source]

Bases: Command

This sets up the basis for a MUX command. The idea is that most other Mux-related commands should just inherit from this and don’t have to implement much parsing of their own unless they do something particularly advanced.

Note that the class’s __doc__ string (this text) is used by Evennia to create the automatic help entry for the command, so make sure to document consistently here.

aliases = []
at_post_cmd()[source]

This hook is called after the command has finished executing (after self.func()).

at_pre_cmd()[source]

This hook is called before self.parse() on all commands

func()[source]
This is the hook function that actually does all the work. It is called

by the cmdhandler right after self.parser() finishes, and so has access to all the variables defined therein.

get_command_info()[source]

Update of parent class’s get_command_info() for MuxCommand.

has_perm(srcobj)[source]

This is called by the cmdhandler to determine if srcobj is allowed to execute this command. We just show it here for completeness - we are satisfied using the default check in Command.

help_category = 'general'
key = 'command'
lock_storage = 'cmd:all();'
parse()[source]

This method is called by the cmdhandler once the command name has been identified. It creates a new set of member variables that can be later accessed from self.func() (see below)

The following variables are available for our use when entering this method (from the command definition, and assigned on the fly by the cmdhandler):

self.key - the name of this command (‘look’) self.aliases - the aliases of this cmd (‘l’) self.permissions - permission string for this command self.help_category - overall category of command

self.caller - the object calling this command self.cmdstring - the actual command name used to call this

(this allows you to know which alias was used,

for example)

self.args - the raw input; everything following self.cmdstring. self.cmdset - the cmdset from which this command was picked. Not

often used (useful for commands like ‘help’ or to list all available commands etc)

self.obj - the object on which this command was defined. It is often

the same as self.caller.

A MUX command has the following possible syntax:

name[ with several words][/switch[/switch..]] arg1[,arg2,…] [[=|,] arg[,..]]

The ‘name[ with several words]’ part is already dealt with by the cmdhandler at this point, and stored in self.cmdname (we don’t use it here). The rest of the command is stored in self.args, which can start with the switch indicator /.

Optional variables to aid in parsing, if set:
self.switch_options - (tuple of valid /switches expected by this

command (without the /))

self.rhs_split - Alternate string delimiter or tuple of strings

to separate left/right hand sides. tuple form gives priority split to first string delimiter.

This parser breaks self.args into its constituents and stores them in the following variables:

self.switches = [list of /switches (without the /)] self.raw = This is the raw argument input, including switches self.args = This is re-defined to be everything except the switches self.lhs = Everything to the left of = (lhs:’left-hand side’). If

no = is found, this is identical to self.args.

self.rhs: Everything to the right of = (rhs:’right-hand side’).

If no ‘=’ is found, this is None.

self.lhslist - [self.lhs split into a list by comma] self.rhslist - [list of self.rhs split into a list by comma] self.arglist = [list of space-separated args (stripped, including ‘=’ if it exists)]

All args and list members are stripped of excess whitespace around the strings, but case is preserved.

search_index_entry = {'aliases': '', 'category': 'general', 'key': 'command', 'no_prefix': ' ', 'tags': '', 'text': "\nThis sets up the basis for a MUX command. The idea\nis that most other Mux-related commands should just\ninherit from this and don't have to implement much\nparsing of their own unless they do something particularly\nadvanced.\n\nNote that the class's __doc__ string (this text) is\nused by Evennia to create the automatic help entry for\nthe command, so make sure to document consistently here.\n"}
class evennia.contrib.base_systems.email_login.email_login.ServerConfig(*args, **kwargs)[source]

Bases: WeakSharedMemoryModel

On-the fly storage of global settings.

Properties defined on ServerConfig:

  • key: Main identifier

  • value: Value stored in key. This is a pickled storage.

exception DoesNotExist

Bases: ObjectDoesNotExist

exception MultipleObjectsReturned

Bases: MultipleObjectsReturned

db_key

A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.

db_value

A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.

id

A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.

property key

Getter. Allows for value = self.key

objects = <evennia.server.manager.ServerConfigManager object>
path = 'evennia.server.models.ServerConfig'
store(key, value)[source]

Wrap the storage.

Parameters:
  • key (str) – The name of this store.

  • value (str) – The data to store with this key.

typename = 'WeakSharedMemoryModelBase'
property value

Getter. Allows for value = self.value

class evennia.contrib.base_systems.email_login.email_login.UnloggedinCmdSet(cmdsetobj=None, key=None)[source]

Bases: CmdSet

Sets up the unlogged cmdset.

key = 'Unloggedin'
path = 'evennia.contrib.base_systems.email_login.email_login.UnloggedinCmdSet'
priority = 0
at_cmdset_creation()[source]

Populate the cmdset

evennia.contrib.base_systems.email_login.email_login.class_from_module(path, defaultpaths=None, fallback=None)[source]

Return a class from a module, given the class’ full python path. This is primarily used to convert db_typeclass_path:s to classes.

Parameters:
  • path (str) – Full Python dot-path to module.

  • defaultpaths (iterable, optional) – If a direct import from path fails, try subsequent imports by prepending those paths to path.

  • fallback (str) – If all other attempts fail, use this path as a fallback. This is intended as a last-resort. In the example of Evennia loading, this would be a path to a default parent class in the evennia repo itself.

Returns:

class (Class) – An uninstantiated class recovered from path.

Raises:

ImportError – If all loading failed.