Skip to content

Commit

Permalink
Merge branch 'develop' into smarturls
Browse files Browse the repository at this point in the history
  • Loading branch information
strikaco committed Oct 22, 2018
2 parents a5b759c + 17a2b9f commit cfc8179
Show file tree
Hide file tree
Showing 35 changed files with 485 additions and 190 deletions.
21 changes: 20 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,27 @@
# Changelog

## Evennia 0.9 (2018-2019)

### Commands

- Removed default `@delaccount` command, incorporating as `@account/delete` instead. Added confirmation
question.
- Add new `@force` command to have another object perform a command.
- Add the Portal uptime to the `@time` command.
- Make the `@link` command first make a local search before a global search.

### Utils

- Added more unit tests.


## Evennia 0.8 (2018)

### Requirements

- Up requirements to Django 1.11.x, Twisted 18 and pillow 5.2.0
- Add `inflect` dependency for automatic pluralization of object names.

### Server/Portal

- Removed `evennia_runner`, completely refactor `evennia_launcher.py` (the 'evennia' program)
Expand Down Expand Up @@ -85,7 +105,6 @@

### General

- Up requirements to Django 1.11.x, Twisted 18 and pillow 5.2.0
- Start structuring the `CHANGELOG` to list features in more detail.
- Docker image `evennia/evennia:develop` is now auto-built, tracking the develop branch.
- Inflection and grouping of multiple objects in default room (an box, three boxes)
Expand Down
12 changes: 10 additions & 2 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,22 @@
# Usage:
# cd to a folder where you want your game data to be (or where it already is).
#
# docker run -it -p 4000:4000 -p 4001:4001 -p 4005:4005 -v $PWD:/usr/src/game evennia/evennia
# docker run -it --rm -p 4000:4000 -p 4001:4001 -p 4005:4005 -v $PWD:/usr/src/game evennia/evennia
#
# (If your OS does not support $PWD, replace it with the full path to your current
# folder).
#
# You will end up in a shell where the `evennia` command is available. From here you
# can install and run the game normally. Use Ctrl-D to exit the evennia docker container.
#
# You can also start evennia directly by passing arguments to the folder:
#
# docker run -it --rm -p 4000:4000 -p 4001:4001 -p 4005:4005 -v $PWD:/usr/src/game evennia/evennia evennia start -l
#
# This will start Evennia running as the core process of the container. Note that you *must* use -l
# or one of the foreground modes (like evennia ipstart) since otherwise the container will immediately
# die since no foreground process keeps it up.
#
# The evennia/evennia base image is found on DockerHub and can also be used
# as a base for creating your own custom containerized Evennia game. For more
# info, see https://github.com/evennia/evennia/wiki/Running%20Evennia%20in%20Docker .
Expand Down Expand Up @@ -58,7 +66,7 @@ WORKDIR /usr/src/game
ENV PS1 "evennia|docker \w $ "

# startup a shell when we start the container
ENTRYPOINT bash -c "source /usr/src/evennia/bin/unix/evennia-docker-start.sh"
ENTRYPOINT ["/usr/src/evennia/bin/unix/evennia-docker-start.sh"]

# expose the telnet, webserver and websocket client ports
EXPOSE 4000 4001 4005
16 changes: 12 additions & 4 deletions bin/unix/evennia-docker-start.sh
100644 → 100755
Original file line number Diff line number Diff line change
@@ -1,10 +1,18 @@
#! /bin/bash
#! /bin/sh

# called by the Dockerfile to start the server in docker mode

# remove leftover .pid files (such as from when dropping the container)
rm /usr/src/game/server/*.pid >& /dev/null || true

# start evennia server; log to server.log but also output to stdout so it can
# be viewed with docker-compose logs
exec 3>&1; evennia start -l
PS1="evennia|docker \w $ "

cmd="$@"
output="Docker starting with argument '$cmd' ..."
if test -z $cmd; then
cmd="bash"
output="No argument given, starting shell ..."
fi

echo $output
exec 3>&1; $cmd
5 changes: 4 additions & 1 deletion evennia/accounts/accounts.py
Original file line number Diff line number Diff line change
Expand Up @@ -1001,7 +1001,10 @@ def at_look(self, target=None, session=None, **kwargs):

if target and not is_iter(target):
# single target - just show it
return target.return_appearance(self)
if hasattr(target, "return_appearance"):
return target.return_appearance(self)
else:
return "{} has no in-game appearance.".format(target)
else:
# list of targets - make list to disconnect from db
characters = list(tar for tar in target if tar) if target else []
Expand Down
62 changes: 44 additions & 18 deletions evennia/accounts/tests.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
from mock import Mock
from mock import Mock, MagicMock
from random import randint
from unittest import TestCase

from django.test import override_settings
from evennia.accounts.accounts import AccountSessionHandler
from evennia.accounts.accounts import DefaultAccount
from evennia.server.session import Session
from evennia.utils import create
from evennia.utils.test_resources import EvenniaTest

from django.conf import settings

Expand All @@ -14,34 +16,40 @@ class TestAccountSessionHandler(TestCase):
"Check AccountSessionHandler class"

def setUp(self):
self.account = create.create_account("TestAccount%s" % randint(0, 999999), email="test@test.com", password="testpassword", typeclass=DefaultAccount)
self.account = create.create_account(
"TestAccount%s" % randint(0, 999999), email="test@test.com",
password="testpassword", typeclass=DefaultAccount)
self.handler = AccountSessionHandler(self.account)

def tearDown(self):
if hasattr(self, 'account'):
self.account.delete()

def test_get(self):
"Check get method"
self.assertEqual(self.handler.get(), [])
self.assertEqual(self.handler.get(100), [])

import evennia.server.sessionhandler

s1 = Session()
s1 = MagicMock()
s1.logged_in = True
s1.uid = self.account.uid
evennia.server.sessionhandler.SESSIONS[s1.uid] = s1

s2 = Session()
s2 = MagicMock()
s2.logged_in = True
s2.uid = self.account.uid + 1
evennia.server.sessionhandler.SESSIONS[s2.uid] = s2

s3 = Session()
s3 = MagicMock()
s3.logged_in = False
s3.uid = self.account.uid + 2
evennia.server.sessionhandler.SESSIONS[s3.uid] = s3

self.assertEqual(self.handler.get(), [s1])
self.assertEqual(self.handler.get(self.account.uid), [s1])
self.assertEqual(self.handler.get(self.account.uid + 1), [])
self.assertEqual([s.uid for s in self.handler.get()], [s1.uid])
self.assertEqual([s.uid for s in [self.handler.get(self.account.uid)]], [s1.uid])
self.assertEqual([s.uid for s in self.handler.get(self.account.uid + 1)], [])

def test_all(self):
"Check all method"
Expand All @@ -56,10 +64,10 @@ class TestDefaultAccount(TestCase):
"Check DefaultAccount class"

def setUp(self):
self.s1 = Session()
self.s1 = MagicMock()
self.s1.puppet = None
self.s1.sessid = 0

def test_absolute_url(self):
"Get URL for account detail page on website"
self.account = create.create_account("TestAccount%s" % randint(100000, 999999),
Expand All @@ -84,7 +92,6 @@ def test_password_validation(self):
"Check validators allow sufficiently complex passwords"
for better in ('Mxyzptlk', "j0hn, i'M 0n1y d4nc1nG"):
self.assertTrue(self.account.validate_password(better, account=self.account)[0])
self.account.delete()

def test_password_change(self):
"Check password setting and validation is working as expected"
Expand Down Expand Up @@ -122,7 +129,9 @@ def test_puppet_object_already_puppeting(self):

import evennia.server.sessionhandler

account = create.create_account("TestAccount%s" % randint(0, 999999), email="test@test.com", password="testpassword", typeclass=DefaultAccount)
account = create.create_account(
"TestAccount%s" % randint(0, 999999), email="test@test.com",
password="testpassword", typeclass=DefaultAccount)
self.s1.uid = account.uid
evennia.server.sessionhandler.SESSIONS[self.s1.uid] = self.s1

Expand All @@ -144,10 +153,7 @@ def test_puppet_object_no_permission(self):
self.s1.uid = account.uid
evennia.server.sessionhandler.SESSIONS[self.s1.uid] = self.s1

self.s1.puppet = None
self.s1.logged_in = True
self.s1.data_out = Mock(return_value=None)

self.s1.data_out = MagicMock()
obj = Mock()
obj.access = Mock(return_value=False)

Expand All @@ -156,6 +162,7 @@ def test_puppet_object_no_permission(self):
self.assertTrue(self.s1.data_out.call_args[1]['text'].startswith("You don't have permission to puppet"))
self.assertIsNone(obj.at_post_puppet.call_args)

@override_settings(MULTISESSION_MODE=0)
def test_puppet_object_joining_other_session(self):
"Check puppet_object method called, joining other session"

Expand All @@ -167,15 +174,16 @@ def test_puppet_object_joining_other_session(self):

self.s1.puppet = None
self.s1.logged_in = True
self.s1.data_out = Mock(return_value=None)
self.s1.data_out = MagicMock()

obj = Mock()
obj.access = Mock(return_value=True)
obj.account = account
obj.sessions.all = MagicMock(return_value=[self.s1])

account.puppet_object(self.s1, obj)
# works because django.conf.settings.MULTISESSION_MODE is not in (1, 3)
self.assertTrue(self.s1.data_out.call_args[1]['text'].endswith("from another of your sessions."))
self.assertTrue(self.s1.data_out.call_args[1]['text'].endswith("from another of your sessions.|n"))
self.assertTrue(obj.at_post_puppet.call_args[1] == {})

def test_puppet_object_already_puppeted(self):
Expand All @@ -184,6 +192,7 @@ def test_puppet_object_already_puppeted(self):
import evennia.server.sessionhandler

account = create.create_account("TestAccount%s" % randint(0, 999999), email="test@test.com", password="testpassword", typeclass=DefaultAccount)
self.account = account
self.s1.uid = account.uid
evennia.server.sessionhandler.SESSIONS[self.s1.uid] = self.s1

Expand All @@ -199,3 +208,20 @@ def test_puppet_object_already_puppeted(self):
account.puppet_object(self.s1, obj)
self.assertTrue(self.s1.data_out.call_args[1]['text'].endswith("is already puppeted by another Account."))
self.assertIsNone(obj.at_post_puppet.call_args)


class TestAccountPuppetDeletion(EvenniaTest):

@override_settings(MULTISESSION_MODE=2)
def test_puppet_deletion(self):
# Check for existing chars
self.assertFalse(self.account.db._playable_characters, 'Account should not have any chars by default.')

# Add char1 to account's playable characters
self.account.db._playable_characters.append(self.char1)
self.assertTrue(self.account.db._playable_characters, 'Char was not added to account.')

# See what happens when we delete char1.
self.char1.delete()
# Playable char list should be empty.
self.assertFalse(self.account.db._playable_characters, 'Playable character list is not empty! %s' % self.account.db._playable_characters)
7 changes: 6 additions & 1 deletion evennia/commands/default/account.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
import time
from django.conf import settings
from evennia.server.sessionhandler import SESSIONS
from evennia.utils import utils, create, search, evtable
from evennia.utils import utils, create, logger, search, evtable

COMMAND_DEFAULT_CLASS = utils.class_from_module(settings.COMMAND_DEFAULT_CLASS)

Expand Down Expand Up @@ -171,6 +171,7 @@ def func(self):
new_character.db.desc = "This is a character."
self.msg("Created new character %s. Use |w@ic %s|n to enter the game as this character."
% (new_character.key, new_character.key))
logger.log_sec('Character Created: %s (Caller: %s, IP: %s).' % (new_character, account, self.session.address))


class CmdCharDelete(COMMAND_DEFAULT_CLASS):
Expand Down Expand Up @@ -214,6 +215,7 @@ def _callback(caller, callback_prompt, result):
caller.db._playable_characters = [pc for pc in caller.db._playable_characters if pc != delobj]
delobj.delete()
self.msg("Character '%s' was permanently deleted." % key)
logger.log_sec('Character Deleted: %s (Caller: %s, IP: %s).' % (key, account, self.session.address))
else:
self.msg("Deletion was aborted.")
del caller.ndb._char_to_delete
Expand Down Expand Up @@ -279,8 +281,10 @@ def func(self):
try:
account.puppet_object(session, new_character)
account.db._last_puppet = new_character
logger.log_sec('Puppet Success: (Caller: %s, Target: %s, IP: %s).' % (account, new_character, self.session.address))
except RuntimeError as exc:
self.msg("|rYou cannot become |C%s|n: %s" % (new_character.name, exc))
logger.log_sec('Puppet Failed: %s (Caller: %s, Target: %s, IP: %s).' % (exc, account, new_character, self.session.address))


# note that this is inheriting from MuxAccountLookCommand,
Expand Down Expand Up @@ -641,6 +645,7 @@ def func(self):
account.set_password(newpass)
account.save()
self.msg("Password changed.")
logger.log_sec('Password Changed: %s (Caller: %s, IP: %s).' % (account, account, self.session.address))


class CmdQuit(COMMAND_DEFAULT_CLASS):
Expand Down
Loading

0 comments on commit cfc8179

Please sign in to comment.