Patched the batch-processor's interactive mode so it will not abort if it processes an object/script parent that changes the player's state. Also added a variable BATCH_IMPORT_PATH to config so one can keep all batch scripts in one location and don't have to write the full path to get them. Default is the new directory game/gamesrc/world.

Added the permission genperms.admin_nostate so that builders can avoid entering a state when working on a room with a state-changing parent. Superusers have to set the flag ADMIN_NOSTATE on themselves to achieve the same effect (this is necessary since superusers always have all permissions, so they would otherwise never be able to enter states).
/Griatch
This commit is contained in:
Griatch 2009-10-20 22:21:01 +00:00
parent c4114938cc
commit a6ae6e936a
4 changed files with 63 additions and 16 deletions

View file

@ -48,6 +48,7 @@ An example batch file is found in game/gamesrc/commands/examples.
""" """
import os import os
import re import re
from django.conf import settings
from src import logger from src import logger
from src import defines_global from src import defines_global
from src.cmdtable import GLOBAL_CMD_TABLE from src.cmdtable import GLOBAL_CMD_TABLE
@ -55,7 +56,7 @@ from src.statetable import GLOBAL_STATE_TABLE
#global defines for storage #global defines for storage
STATENAME="interactive batch processor" STATENAME="_interactive batch processor"
CMDSTACKS={} # user:cmdstack pairs (for interactive) CMDSTACKS={} # user:cmdstack pairs (for interactive)
STACKPTRS={} # user:stackpointer pairs (for interactive) STACKPTRS={} # user:stackpointer pairs (for interactive)
FILENAMES={} # user:filename pairs (for interactive/reload) FILENAMES={} # user:filename pairs (for interactive/reload)
@ -69,8 +70,10 @@ cnorm = r"%cn"
def read_batchbuild_file(filename): def read_batchbuild_file(filename):
""" """
This reads the contents of batchfile. This reads the contents of batchfile.
Filename is considered to be the name of the batch file
relative the directory specified in settings.py
""" """
filename = os.path.abspath(filename) filename = os.path.abspath("%s/%s" % (settings.BATCH_IMPORT_PATH, filename))
try: try:
f = open(filename) f = open(filename)
except IOError: except IOError:
@ -191,12 +194,15 @@ def cmd_batchprocess(command):
#parse indata file #parse indata file
commands = parse_batchbuild_file(filename) commands = parse_batchbuild_file(filename)
if not commands: if not commands:
source_object.emit_to("'%s'\ncould not be found. Remember that you have to supply the absolute path to the file." % filename) source_object.emit_to("'%s' not found.\nYou have to supply the real path to the file relative to \nyour batch-file directory (e.g. game/gamesrc/world)." % filename)
return return
switches = command.command_switches switches = command.command_switches
if switches and switches[0] in ['inter','interactive']: if switches and switches[0] in ['inter','interactive']:
#allow more control over how batch file is executed # allow more control over how batch file is executed
source_object.set_state(STATENAME) if not source_object.set_state(STATENAME):
source_object.emit_to("You cannot use the interactive mode while you have the flag ADMIN_NOSTATE set.")
return
CMDSTACKS[source_object] = commands CMDSTACKS[source_object] = commands
STACKPTRS[source_object] = 0 STACKPTRS[source_object] = 0
FILENAMES[source_object] = filename FILENAMES[source_object] = filename
@ -288,7 +294,10 @@ def exit_state(source_object):
del FILENAMES[source_object] del FILENAMES[source_object]
except KeyError: except KeyError:
logger.log_errmsg("Batchprocessor quit error: all state vars could not be deleted.") logger.log_errmsg("Batchprocessor quit error: all state vars could not be deleted.")
source_object.clear_state() # since clear_state() is protected against exiting the interactive mode
# (to avoid accidental drop-outs by rooms clearing a player's state),
# we have to clear the state directly here.
source_object.state = None
def cmd_state_ll(command): def cmd_state_ll(command):
""" """
@ -517,7 +526,7 @@ def cmd_state_hh(command):
#create the state; we want it as open as possible so we can do everything #create the state; we want it as open as possible so we can do everything
# in our batch processing. # in our batch processing.
GLOBAL_STATE_TABLE.add_state(STATENAME,global_cmds='all', GLOBAL_STATE_TABLE.add_state(STATENAME,global_cmds='all',
allow_exits=True,allow_obj_cmds=True) allow_exits=True,allow_obj_cmds=True,exit_command=True)
#add state commands #add state commands
GLOBAL_STATE_TABLE.add_command(STATENAME,"nn",cmd_state_nn) GLOBAL_STATE_TABLE.add_command(STATENAME,"nn",cmd_state_nn)
GLOBAL_STATE_TABLE.add_command(STATENAME,"nl",cmd_state_nl) GLOBAL_STATE_TABLE.add_command(STATENAME,"nl",cmd_state_nl)

View file

@ -44,7 +44,7 @@ SRC_DIR = os.path.join(BASE_PATH, 'src')
# Example: "/home/media/media.lawrence.com" # Example: "/home/media/media.lawrence.com"
MEDIA_ROOT = os.path.join(GAME_DIR, 'web', 'media') MEDIA_ROOT = os.path.join(GAME_DIR, 'web', 'media')
# Import style path to the script parent module. Must be in the import path. # Import style path to the directory holding script parents. Must be in the import path.
SCRIPT_IMPORT_PATH = 'game.gamesrc.parents' SCRIPT_IMPORT_PATH = 'game.gamesrc.parents'
# Default parent associated with non-player objects. This starts from where # Default parent associated with non-player objects. This starts from where
# the SCRIPT_IMPORT_PATH left off. # the SCRIPT_IMPORT_PATH left off.
@ -52,6 +52,10 @@ SCRIPT_DEFAULT_OBJECT = 'base.basicobject'
# Default parent associated with player objects. This starts from where # Default parent associated with player objects. This starts from where
# the SCRIPT_IMPORT_PATH left off. # the SCRIPT_IMPORT_PATH left off.
SCRIPT_DEFAULT_PLAYER = 'base.basicplayer' SCRIPT_DEFAULT_PLAYER = 'base.basicplayer'
# Real path to a directory to be searched for batch scripts for the
# batch processor. Specify relative evennia's 'game' directory.
BATCH_IMPORT_PATH = 'gamesrc/world'
# 'postgresql_psycopg2', 'postgresql', 'mysql', 'sqlite3', and 'oracle'. # 'postgresql_psycopg2', 'postgresql', 'mysql', 'sqlite3', and 'oracle'.
DATABASE_ENGINE = 'sqlite3' DATABASE_ENGINE = 'sqlite3'
@ -125,9 +129,10 @@ PERM_GENPERMS = (
("announce", "May make announcements to everyone."), ("announce", "May make announcements to everyone."),
("admin_perm", "Can modify individual permissions."), ("admin_perm", "Can modify individual permissions."),
("admin_group", "Can manage membership in groups."), ("admin_group", "Can manage membership in groups."),
("process_control", "May shutdown/restart/reload the game"), ("process_control", "May shutdown/restart/reload the game."),
("manage_players", "Can change passwords, siteban, etc."), ("manage_players", "Can change passwords, siteban, etc."),
("game_info", "Can review game metadata"),) ("game_info", "Can review game metadata."),
("admin_nostate", "Do not enter states (should be set only temporarily)."),)
## These permissions are not yet used in the default engine. ## These permissions are not yet used in the default engine.
## ("boot", "May use @boot to kick players"), ## ("boot", "May use @boot to kick players"),

View file

@ -1090,12 +1090,45 @@ class Object(models.Model):
""" """
Only allow setting a state on a player object, otherwise Only allow setting a state on a player object, otherwise
fail silently. fail silently.
This command safeguards the batch processor against dropping
out of interactive mode; it also allows builders to
sidestep room-based states when building (the genperm.admin_nostate
permission is not set on anyone by default, set it temporarily
when building a state-based room).
""" """
if self.is_player(): if not self.is_player():
return False
if self.is_superuser():
# we have to deal with superusers separately since
# they would always appear to have the genperm.admin_nostate
# permission. Instead we expect them to set the flag
# ADMIN_NOSTATE on themselves if they don't want to
# enter states.
nostate = self.has_flag("admin_nostate")
else:
# for other users we request the permission as normal.
nostate = self.has_perm("genperms.admin_nostate")
# we never enter other states if we are in the interactive batch processor.
nostate = nostate or self.state == "_interactive batch processor"
if nostate:
return False
self.state = state_name self.state = state_name
return True
def clear_state(self): def clear_state(self):
"Set to no state (return to normal operation)" """
Set to no state (return to normal operation)
This safeguards the batch processor from exiting its
interactive mode when entering a room cancelling states.
(batch processor clears the state directly instead)
"""
if not self.state == "_interactive batch processor":
self.state = None self.state = None
def purge_object(self): def purge_object(self):