Repository: evennia/evennia

Issue:
[BUG] Channel command nick doesn't match channel command key
#### Describe the bug
Nicks created by the channel command (e.g. the "pub") nick for the Public channel don't use the right command key: they reference `channel` instead of `@channel`. Normally this doesn't matter, but if you set `CMD_IGNORE_PREFIXES = "/+"` in your settings, this mismatch causes channel nicks to break.

```
> pub test
Command 'channel public = test' is not available. Type "help" for help.
```

#### To Reproduce
Steps to reproduce the behavior:
1. Set CMD_IGNORE_PREFIXES to anything that pays attention to the option @ prefix (like "/+")
2. Run any channel nick-based command.
3. Observe error.

#### Expected behavior
Channel nicks command keys should match the channel command.

#### Environment, Evennia version, OS etc
Evennia 1.2.0

#### Additional context
The issue looks like it's here: 
https://github.com/evennia/evennia/blob/bee281f82d126482f0acb8e3ea4153cba0ad4779/evennia/comms/comms.py#L69
I think this should be `@channel` instead of `channel`. Then it matches the command key and CMD_IGNORE_PREFIXES shouldn't matter anymore.


Discussion:

Resolving patch:
diff --git a/evennia/comms/comms.py b/evennia/comms/comms.py
--- a/evennia/comms/comms.py
+++ b/evennia/comms/comms.py
@@ -7,6 +7,7 @@
 from django.contrib.contenttypes.models import ContentType
 from django.urls import reverse
 from django.utils.text import slugify
+
 from evennia.comms.managers import ChannelManager
 from evennia.comms.models import ChannelDB
 from evennia.typeclasses.models import TypeclassBase
@@ -66,7 +67,7 @@ class DefaultChannel(ChannelDB, metaclass=TypeclassBase):
 
     # default nick-alias replacements (default using the 'channel' command)
     channel_msg_nick_pattern = r"{alias}\s*?|{alias}\s+?(?P<arg1>.+?)"
-    channel_msg_nick_replacement = "channel {channelname} = $1"
+    channel_msg_nick_replacement = "@channel {channelname} = $1"
 
     def at_first_save(self):
         """


Test patch:
diff --git a/evennia/commands/default/tests.py b/evennia/commands/default/tests.py
--- a/evennia/commands/default/tests.py
+++ b/evennia/commands/default/tests.py
@@ -31,14 +31,7 @@
 from evennia.commands import cmdparser
 from evennia.commands.cmdset import CmdSet
 from evennia.commands.command import Command, InterruptCommand
-from evennia.commands.default import (
-    account,
-    admin,
-    batchprocess,
-    building,
-    comms,
-    general,
-)
+from evennia.commands.default import account, admin, batchprocess, building, comms, general
 from evennia.commands.default import help as help_module
 from evennia.commands.default import syscommands, system, unloggedin
 from evennia.commands.default.cmdset_character import CharacterCmdSet
@@ -83,7 +76,9 @@ def test_inventory(self):
     def test_pose(self):
         self.char2.msg = Mock()
         self.call(general.CmdPose(), "looks around", "Char looks around")
-        self.char2.msg.assert_called_with(text=('Char looks around', {'type': 'pose'}), from_obj=self.char1)
+        self.char2.msg.assert_called_with(
+            text=("Char looks around", {"type": "pose"}), from_obj=self.char1
+        )
 
     def test_nick(self):
         self.call(
@@ -173,7 +168,6 @@ def test_access(self):
 
 
 class TestHelp(BaseEvenniaCommandTest):
-
     maxDiff = None
 
     def setUp(self):
@@ -584,7 +578,6 @@ class TestAccount(BaseEvenniaCommandTest):
         ]
     )
     def test_ooc_look(self, multisession_mode, auto_puppet, max_nr_chars, expected_result):
-
         self.account.db._playable_characters = [self.char1]
         self.account.unpuppet_all()
 
@@ -1563,7 +1556,6 @@ def test_script(self):
         )
 
     def test_script_multi_delete(self):
-
         script1 = create.create_script()
         script2 = create.create_script()
         script3 = create.create_script()
@@ -1867,7 +1859,7 @@ def test_channel__sub(self):
         self.call(self.cmdchannel(), "/sub testchannel", "You are now subscribed")
         self.assertTrue(self.char1 in self.channel.subscriptions.all())
         self.assertEqual(
-            self.char1.nicks.nickreplace("testchannel Hello"), "channel testchannel = Hello"
+            self.char1.nicks.nickreplace("testchannel Hello"), "@channel testchannel = Hello"
         )
 
     def test_channel__unsub(self):
@@ -1883,7 +1875,7 @@ def test_channel__alias__unalias(self):
             "/alias testchannel = foo",
             "Added/updated your alias 'foo' for channel testchannel.",
         )
-        self.assertEqual(self.char1.nicks.nickreplace("foo Hello"), "channel testchannel = Hello")
+        self.assertEqual(self.char1.nicks.nickreplace("foo Hello"), "@channel testchannel = Hello")
 
         # use alias
         self.channel.msg = Mock()
@@ -2084,7 +2076,6 @@ def test_batch_commands(self, mock_tutorials, mock_repeat):
 
 
 class CmdInterrupt(Command):
-
     key = "interrupt"
 
     def parse(self):
diff --git a/evennia/comms/tests.py b/evennia/comms/tests.py
--- a/evennia/comms/tests.py
+++ b/evennia/comms/tests.py
@@ -1,8 +1,20 @@
+from django.test import SimpleTestCase
+
 from evennia import DefaultChannel
+from evennia.commands.default.comms import CmdChannel
 from evennia.utils.create import create_message
 from evennia.utils.test_resources import BaseEvenniaTest
 
 
+class TestCommsNickMatchesCommand(SimpleTestCase):
+    def test(self):
+        """
+        Verifies that the nick being set by DefaultChannel matches the channel
+        command key.
+        """
+        self.assertTrue(DefaultChannel.channel_msg_nick_replacement.startswith(CmdChannel.key))
+
+
 class ObjectCreationTest(BaseEvenniaTest):
     def test_channel_create(self):
         description = "A place to talk about coffee."
@@ -18,6 +30,29 @@ def test_message_create(self):
         self.assertEqual(str(msg), "peewee herman->: heh-heh!")
 
 
+class ChannelSubscriptionTests(BaseEvenniaTest):
+    def setUp(self):
+        super().setUp()
+        self.default_channel, _ = DefaultChannel.create(
+            "catlovers", description="A place for feline fanciers."
+        )
+        self.default_channel.connect(self.obj1)
+
+    def test_subscribe_unsubscribe(self):
+        self.default_channel.connect(self.char1)
+        self.assertTrue(self.default_channel.subscriptions.has(self.char1))
+        self.assertEqual(
+            self.char1.nicks.nickreplace("catlovers I love cats!"),
+            "@channel catlovers = I love cats!",
+        )
+        self.default_channel.disconnect(self.char1)
+        self.assertFalse(self.default_channel.subscriptions.has(self.char1))
+        self.assertEqual(
+            self.char1.nicks.nickreplace("catlovers I love cats!"),
+            "catlovers I love cats!",
+        )
+
+
 class ChannelWholistTests(BaseEvenniaTest):
     def setUp(self):
         super().setUp()