Add Msg.db_receiver_external field. Resolve #2193.

This commit is contained in:
Griatch 2021-05-15 09:12:42 +02:00
parent e38604ab02
commit ac459572f5
4 changed files with 35 additions and 23 deletions

View file

@ -53,6 +53,7 @@
list `PROTOTYPE_LIST` of dicts before loading all dicts in the module as prototypes. list `PROTOTYPE_LIST` of dicts before loading all dicts in the module as prototypes.
- New Channel-System using the `channel` command and nicks. Removed the `ChannelHandler` and the - New Channel-System using the `channel` command and nicks. Removed the `ChannelHandler` and the
concept of a dynamically created `ChannelCmdSet`. concept of a dynamically created `ChannelCmdSet`.
- Add `Msg.db_receiver_external` field to allowe external, string-id message-receivers.
### Evennia 0.9.5 (2019-2020) ### Evennia 0.9.5 (2019-2020)

View file

@ -1,4 +1,4 @@
# Msg # Msg
The [Msg](api:evennia.comms.models.Msg) object represents a database-saved The [Msg](api:evennia.comms.models.Msg) object represents a database-saved
piece of communication. Think of it as a discrete piece of email - it contains piece of communication. Think of it as a discrete piece of email - it contains
@ -29,10 +29,10 @@ good uses for `Msg` objects:
Channels dropped Msg-support. Now only used in `page` command by default. Channels dropped Msg-support. Now only used in `page` command by default.
``` ```
## Msg in code ## Msg in code
The Msg is intended to be used exclusively in code, to build other game systems. It is _not_ The Msg is intended to be used exclusively in code, to build other game systems. It is _not_
a [Typeclassed](./Typeclasses) entity, which means it cannot (easily) be overridden. It a [Typeclassed](./Typeclasses) entity, which means it cannot (easily) be overridden. It
doesn't support Attributes (but it _does_ support [Tags](./Tags)). It tries to be lean doesn't support Attributes (but it _does_ support [Tags](./Tags)). It tries to be lean
and small since a new one is created for every message. and small since a new one is created for every message.
@ -40,7 +40,7 @@ You create a new message with `evennia.create_message`:
```python ```python
from evennia import create_message from evennia import create_message
message = create_message(senders, message, receivers, message = create_message(senders, message, receivers,
locks=..., tags=..., header=...) locks=..., tags=..., header=...)
``` ```
@ -61,22 +61,26 @@ You can search for `Msg` objects in various ways:
### Properties on Msg ### Properties on Msg
- `senders` - there must always be at least one sender. This is one of [Account](./Accounts), [Object](./Objects), [Script](./Scripts) - `senders` - there must always be at least one sender. This is a set of
or _external_ - which is a string uniquely identifying the sender. The latter can be used by - [Account](./Accounts), [Object](./Objects), [Script](./Scripts)
a sender-system that doesn't fit into Evennia's normal typeclass-system. or `str` in any combination (but usually a message only targets one type).
While most systems expect a single sender, it's possible to have any number of them. Using a `str` for a sender indicates it's an 'external' sender and
- `receivers` - these are the ones to see the Msg. These are again one of and can be used to point to a sender that is not a typeclassed entity. This is not used by default
[Account](./Accounts), [Object](./Objects) or [Script](./Scripts). It's in principle possible to have and what this would be depends on the system (it could be a unique id or a
zero receivers but most usages of Msg expects one or more. python-path, for example). While most systems expect a single sender, it's
- `header` - this is an optional text field that can contain meta-information about the message. For possible to have any number of them.
an email-like system it would be the subject line. This can be independently searched, making - `receivers` - these are the ones to see the Msg. These are again any combination of
[Account](./Accounts), [Object](./Objects) or [Script](./Scripts) or `str` (an 'external' receiver).
It's in principle possible to have zero receivers but most usages of Msg expects one or more.
- `header` - this is an optional text field that can contain meta-information about the message. For
an email-like system it would be the subject line. This can be independently searched, making
this a powerful place for quickly finding messages. this a powerful place for quickly finding messages.
- `message` - the actual text being sent. - `message` - the actual text being sent.
- `date_sent` - this is auto-set to the time the Msg was created (and thus presumably sent). - `date_sent` - this is auto-set to the time the Msg was created (and thus presumably sent).
- `locks` - the Evennia [lock handler](./Locks). Use with `locks.add()` etc and check locks with `msg.access()` - `locks` - the Evennia [lock handler](./Locks). Use with `locks.add()` etc and check locks with `msg.access()`
like for all other lockable entities. This can be used to limit access to the contents like for all other lockable entities. This can be used to limit access to the contents
of the Msg. The default lock-type to check is `'read'`. of the Msg. The default lock-type to check is `'read'`.
- `hide_from` - this is an optional list of [Accounts](./Accounts) or [Objects](./Objects) that - `hide_from` - this is an optional list of [Accounts](./Accounts) or [Objects](./Objects) that
will not see this Msg. This relationship is available mainly for optimization will not see this Msg. This relationship is available mainly for optimization
reasons since it allows quick filtering of messages not intended for a given reasons since it allows quick filtering of messages not intended for a given
target. target.

View file

@ -196,19 +196,21 @@ class Msg(SharedMemoryModel):
list(self.db_sender_accounts.all()) list(self.db_sender_accounts.all())
+ list(self.db_sender_objects.all()) + list(self.db_sender_objects.all())
+ list(self.db_sender_scripts.all()) + list(self.db_sender_scripts.all())
+ [self.db_sender_external] + ([self.db_sender_external] if self.db_sender_external else [])
) )
@senders.setter @senders.setter
def senders(self, senders): def senders(self, senders):
"Setter. Allows for self.sender = value" "Setter. Allows for self.sender = value"
if isinstance(senders, str):
self.db_sender_external = senders
self.save(update_fields=["db_sender_external"])
return
for sender in make_iter(senders): for sender in make_iter(senders):
if not sender: if not sender:
continue continue
if isinstance(sender, str):
self.db_sender_external = sender
self.save(update_fields=["db_sender_external"])
continue
if not hasattr(sender, "__dbclass__"): if not hasattr(sender, "__dbclass__"):
raise ValueError("This is a not a typeclassed object!") raise ValueError("This is a not a typeclassed object!")
clsname = sender.__dbclass__.__name__ clsname = sender.__dbclass__.__name__
@ -267,7 +269,7 @@ class Msg(SharedMemoryModel):
list(self.db_receivers_accounts.all()) list(self.db_receivers_accounts.all())
+ list(self.db_receivers_objects.all()) + list(self.db_receivers_objects.all())
+ list(self.db_receivers_scripts.all()) + list(self.db_receivers_scripts.all())
+ [self.db_receiver_external] + ([self.db_receiver_external] if self.db_receiver_external else [])
) )
@receivers.setter @receivers.setter

View file

@ -139,10 +139,15 @@ class TestCreateMessage(EvenniaTest):
""" """
def test_create_msg__simple(self): def test_create_msg__simple(self):
# from evennia import set_trace;set_trace()
msg = create.create_message(self.char1, self.msgtext, header="TestHeader") msg = create.create_message(self.char1, self.msgtext, header="TestHeader")
msg.senders = "ExternalSender"
msg.receivers = self.char2
msg.receivers = "ExternalReceiver"
self.assertEqual(msg.message, self.msgtext) self.assertEqual(msg.message, self.msgtext)
self.assertEqual(msg.header, "TestHeader") self.assertEqual(msg.header, "TestHeader")
self.assertEqual(msg.senders, [self.char1]) self.assertEqual(msg.senders, [self.char1, "ExternalSender"])
self.assertEqual(msg.receivers, [self.char2, "ExternalReceiver"])
def test_create_msg__custom(self): def test_create_msg__custom(self):
locks = "foo:false();bar:true()" locks = "foo:false();bar:true()"
@ -151,11 +156,11 @@ class TestCreateMessage(EvenniaTest):
self.char1, self.char1,
self.msgtext, self.msgtext,
header="TestHeader", header="TestHeader",
receivers=[self.char1, self.char2], receivers=[self.char1, self.char2, "ExternalReceiver"],
locks=locks, locks=locks,
tags=tags, tags=tags,
) )
self.assertEqual(set(msg.receivers), set([self.char1, self.char2])) self.assertEqual(set(msg.receivers), set([self.char1, self.char2, "ExternalReceiver"]))
self.assertTrue(all(lock in msg.locks.all() for lock in locks.split(";"))) self.assertTrue(all(lock in msg.locks.all() for lock in locks.split(";")))
self.assertEqual(msg.tags.all(), tags) self.assertEqual(msg.tags.all(), tags)