evennia/src/commands/comsys.py
Griatch 7f7306a6e4 - Implemented permission system management inside the game
- changed @chperm to @setperm to avoid confusion with channel commands
- added @setgroup command for adding user group permissions
- Moved permissions/group setup into settings file to allow admins to tweak without going into evennia engine.
- Add all new players to default permission group (defined in settings)
- Defined a basic group hierarchy, removed permission 'genperms.builder' in favour of a group named builders instead, containing all relevant permissions.
- Filtered out all django's automatic permissions in @setperm/list to make permission system more controlled by admin.
- Probably fixed bug that caused new users to not be signed up to channels (more testing needed)
- Added Exception handler in unloggedin method create, this was killing tracebacks upon user creation.
/Griatch
2009-10-03 14:40:34 +00:00

538 lines
18 KiB
Python

"""
Comsys command module.
"""
import time
from django.conf import settings
from src import comsys
from src.channels.models import CommChannelMembership, CommChannel
from src import defines_global
from src import ansi
from src.util import functions_general
from src.objects.models import Object
from src.cmdtable import GLOBAL_CMD_TABLE
def cmd_addcom(command):
"""
addcom
Usage:
addcom [alias=] <channel>
Joins a channel. Allows adding an alias for it to make it
easier and faster to use. Subsequent calls of this command
can be used to add multiple aliases.
"""
source_object = command.source_object
command_argument = command.command_argument
if not command_argument:
source_object.emit_to("Usage: addcom [alias=]channelname.")
return
if '=' in command_argument:
chan_alias, chan_name = command.command_argument.split('=', 1)
chan_alias, chan_name = chan_alias.strip(), chan_name.strip()
else:
chan_name = command_argument.strip()
chan_alias = chan_name
membership = source_object.channel_membership_set.filter(channel__name__iexact=chan_name)
try:
chan = CommChannel.objects.get(name__iexact=chan_name)
s = ""
#if we happened to have this alias already defined on another channel, make
#sure to tell us.
aliasmatch = [cmatch.channel.name for cmatch in
source_object.channel_membership_set.filter(user_alias=chan_alias)
if cmatch.channel.name != chan_name]
if aliasmatch:
s = "The alias '%s' is already in use (for channel '%s')." % (chan_alias, aliasmatch[0])
source_object.emit_to(s)
return
if membership:
#we are already members of this channel. Set a different alias.
# Note: To this without requiring a the user to logout then login again,
# we need to delete, then rejoin the channel. Is this due to the lazy
# loading? /Griatch
prev_alias = membership[0].user_alias
if chan_alias == prev_alias:
s += "Alias unchanged."
else:
comsys.plr_del_channel(source_object, prev_alias)
comsys.plr_add_channel(source_object, chan_alias, chan)
s += "Channel '%s' alias changed from '%s' to '%s'." % (chan_name,prev_alias,
chan_alias)
else:
# This adds a CommChannelMembership object and a matching dict entry
# on the session's cdict.
comsys.plr_add_channel(source_object, chan_alias, chan)
# Let the player know everything went well.
s += "You join %s, with an alias of %s." % \
(chan.get_name(), chan_alias)
# Announce the user's joining.
join_msg = "%s has joined the channel." % \
(source_object.get_name(show_dbref=False),)
comsys.send_cmessage(chan, join_msg)
source_object.emit_to(s)
except CommChannel.DoesNotExist:
# Failed to match iexact on channel's 'name' attribute.
source_object.emit_to("Could not find channel %s." % chan_name)
GLOBAL_CMD_TABLE.add_command("addcom", cmd_addcom)
def cmd_delcom(command):
"""
delcom
Usage:
delcom <alias>
Removes the specified alias to a channel. If this is the last alias,
the user is effectively removed from the channel.
"""
source_object = command.source_object
if not command.command_argument:
source_object.emit_to("Usage: delcom <alias>")
return
try:
membership = source_object.channel_membership_set.get(user_alias__iexact=command.command_argument)
except CommChannelMembership.DoesNotExist:
source_object.emit_to("You are not on that channel.")
return
chan_name = membership.channel.get_name()
source_object.emit_to("You have left %s." % chan_name)
comsys.plr_del_channel(source_object, command.command_argument)
# Announce the user's leaving.
leave_msg = "%s has left the channel." % \
(source_object.get_name(show_dbref=False),)
comsys.send_cmessage(chan_name, leave_msg)
GLOBAL_CMD_TABLE.add_command("delcom", cmd_delcom),
def cmd_comlist(command):
"""
Lists the channels a user is subscribed to.
"""
source_object = command.source_object
session = command.session
s = "Your subscibed channels (use @clist for full chan list)\n"
s += "** Alias Channel Status\n"
channels = source_object.channel_membership_set.all()
if not channels:
s += " (No subscriptions) "
for membership in channels:
chan = membership.channel
if membership.is_listening:
chan_on = "On"
else:
chan_on = "Off"
s += " %s%s %-15.14s%-22.15s%s\n" % ('-','-',membership.user_alias,
chan.get_name(), chan_on)
s = s[:-1]
source_object.emit_to(s)
GLOBAL_CMD_TABLE.add_command("comlist", cmd_comlist)
def cmd_allcom(command):
"""
allcom [on|off|who|clear]
Allows the user to universally turn off or on all channels they are on,
as well as perform a 'who' for all channels they are on. Clear deletes
all channels.
Without argument, works like comlist.
"""
source_object = command.source_object
arg = command.command_argument
if not arg:
cmd_comlist(command)
source_object.emit_to("(allcom arguments: 'on', 'off', 'who' and 'clear'.)")
return
arg = arg.strip()
if arg == 'clear':
cmd_clearcom(command)
return
#get names and alias of all subscribed channels
chandict = comsys.plr_get_cdict(command.session)
aliaslist = chandict.keys()
aliaslist.sort()
if arg == "on":
for alias in aliaslist:
comsys.plr_chan_on(command.session, alias)
elif arg == "off":
for alias in aliaslist:
comsys.plr_chan_off(command.session, alias)
elif arg == "who":
s = ""
if not aliaslist:
s += " (No channels) "
for alias in aliaslist:
s += "-- %s (alias: %s)\n" % (chandict[alias][0],alias)
sess_list = comsys.get_cwho_list(chandict[alias][0])
objlist = [sess.get_pobject() for sess in sess_list]
plist = [p.get_name(show_dbref=source_object.sees_dbrefs())
for p in filter(lambda o: o.is_player(), objlist)]
olist = [o.get_name(show_dbref=source_object.sees_dbrefs())
for o in filter(lambda o: not o.is_player(), objlist)]
plist.sort()
olist.sort()
if plist:
s += " Players:\n "
for pname in plist:
s += "%s, " % pname
s = s[:-2] + "\n"
if olist:
s += " Objects:\n "
for oname in olist:
s += "%s, " % oname
s = s[:-2] + "\n"
s = s[:-1]
source_object.emit_to(s)
GLOBAL_CMD_TABLE.add_command("allcom", cmd_allcom)
def cmd_clearcom(command):
"""
clearcom
Effectively runs delcom on all channels the user is on. It will remove their aliases,
remove them from the channel, and clear any titles they have set.
"""
source_object = command.source_object
#get aall subscribed channel memberships
memberships = source_object.channel_membership_set.all()
if not memberships:
s = "No channels to delete. "
else:
s = "Deleting all channels in your subscriptions ...\n"
for membership in memberships:
chan_name = membership.channel.get_name()
s += "You have left %s.\n" % chan_name
comsys.plr_del_channel(source_object, membership.user_alias)
comsys.send_cmessage(chan_name, "%s has left the channel." % source_object.get_name(show_dbref=False))
s = s[:-1]
source_object.emit_to(s)
GLOBAL_CMD_TABLE.add_command("clearcom", cmd_clearcom)
def cmd_clist(command):
"""
@clist
Lists all available channels on the game.
"""
session = command.session
source_object = command.source_object
s = "All channels (use comlist or allcom to see your subscriptions)\n"
s += "** Channel Owner Description\n"
channels = comsys.get_all_channels()
if not channels:
s += "(No channels) "
for chan in channels:
s += " %s%s %-15.14s%-22.15s%s\n" % \
('-',
'-',
chan.get_name(),
chan.get_owner().get_name(show_dbref=False),
chan.description)
s = s[:-1]
#s += "** End of Channel List **"
source_object.emit_to(s)
GLOBAL_CMD_TABLE.add_command("@clist", cmd_clist),
def cmd_cdestroy(command):
"""
@cdestroy
Destroys a channel.
"""
source_object = command.source_object
cname = command.command_argument
if not cname:
source_object.emit_to("Usage: @cdestroy <channelname>")
return
name_matches = comsys.cname_search(cname, exact=True)
if not name_matches:
source_object.emit_to("Could not find channel %s." % (cname,))
else:
is_controlled_by_plr = name_matches[0].controlled_by(source_object)
if is_controlled_by_plr or source_object.has_perm("channels.channel_admin"):
source_object.emit_to("Channel %s destroyed." % (name_matches[0],))
name_matches.delete()
else:
source_object.emit_to("Permission denied.")
return
GLOBAL_CMD_TABLE.add_command("@cdestroy", cmd_cdestroy)
def cmd_cset(command):
"""
@cset
Sets various flags on a channel.
"""
# TODO: Implement cmd_cset
pass
def cmd_ccharge(command):
"""
@ccharge
Sets the cost to transmit over a channel. Default is free.
"""
# TODO: Implement cmd_ccharge
pass
def cmd_cboot(command):
"""
@cboot[/quiet] <channel>=<object>
Kicks a player or object from the channel
"""
source_object = command.source_object
args = command.command_argument
switches = command.command_switches
if not args or not "=" in args:
source_object.emit_to("Usage: @cboot[/quiet] <channel> = <object>")
return
cname, objname = args.split("=",1)
cname, objname = cname.strip(), objname.strip()
if not cname or not objname:
source_object.emit_to("You must supply both channel and object.")
return
try:
channel = CommChannel.objects.get(name__iexact=cname)
except CommChannel.DoesNotExist:
source_object.emit_to("Could not find channel %s." % cname)
return
#do we have power over this channel?
if not channel.controlled_by(source_object) or source_object.has_perm("channels.channel_admin"):
source_object.emit_to("You don't have that power in channel '%s'." % cname)
return
#mux specification requires an * before player objects.
player_boot = False
if objname[0] == '*':
player_boot = True
objname = objname[1:]
bootobj = Object.objects.player_name_search(objname)
if not bootobj:
source_object.emit_to("Object '%s' not found." % objname)
return
if bootobj.is_player() and not player_boot:
source_object.emit_to("To boot players you need to start their name with an '*'. ")
return
#check so that this object really is on the channel in the first place
membership = bootobj.channel_membership_set.filter(channel__name__iexact=cname)
if not membership:
source_object.emit_to("'%s' is not on channel '%s'." % (objname,cname))
return
#announce to channel
if not 'quiet' in switches:
comsys.send_cmessage(cname, "%s boots %s from channel." % \
(source_object.get_name(show_dbref=False), objname))
#all is set, boot the object by removing all its aliases from the channel.
for mship in membership:
comsys.plr_del_channel(bootobj, mship.user_alias)
GLOBAL_CMD_TABLE.add_command("@cboot", cmd_cboot)
def cmd_cemit(command):
"""
@cemit <channel>=<message>
@cemit/noheader <channel>=<message>
@cemit/sendername <channel>=<message>
Allows the user to send a message over a channel as long as
they own or control it. It does not show the user's name unless they
provide the /sendername switch.
"""
source_object = command.source_object
if not command.command_argument:
source_object.emit_to("@cemit[/switches] <channel> = <message>")
return
eq_args = command.command_argument.split('=', 1)
if len(eq_args) != 2:
source_object.emit_to("You must provide a channel name and a message to emit.")
return
cname = eq_args[0].strip()
cmessage = eq_args[1].strip()
final_cmessage = cmessage
if len(cname) == 0:
source_object.emit_to("You must provide a channel name to emit to.")
return
if len(cmessage) == 0:
source_object.emit_to("You must provide a message to emit.")
return
name_matches = comsys.cname_search(cname, exact=True)
if name_matches:
cname_parsed = name_matches[0].get_name()
else:
source_object.emit_to("Could not find channel %s." % (cname,))
return
# If this is False, don't show the channel header before
# the message. For example: [Public] Woohoo!
show_channel_header = True
if "noheader" in command.command_switches:
if not source_object.has_perm("objects.emit_commchannel"):
source_object.emit_to(defines_global.NOPERMS_MSG)
return
final_cmessage = cmessage
show_channel_header = False
else:
if "sendername" in command.command_switches:
if not comsys.plr_has_channel(command.session, cname_parsed,
return_muted=False):
source_object.emit_to("You must be on %s to do that." % (cname_parsed,))
return
final_cmessage = "%s: %s" % (source_object.get_name(show_dbref=False),
cmessage)
else:
if not source_object.has_perm("objects.emit_commchannel"):
source_object.emit_to(defines_global.NOPERMS_MSG)
return
final_cmessage = cmessage
if not "quiet" in command.command_switches:
source_object.emit_to("Sent - %s" % (name_matches[0],))
comsys.send_cmessage(cname_parsed, final_cmessage,
show_header=show_channel_header)
#pipe to external channels (IRC, IMC) eventually mapped to this channel
comsys.send_cexternal(cname_parsed, cmessage, caller=source_object)
GLOBAL_CMD_TABLE.add_command("@cemit", cmd_cemit,priv_tuple=("channels.emit_commchannel",))
def cmd_cwho(command):
"""
@cwho
list
Usage:
@cwho channel[/all]
Displays the name, status and object type for a given channel.
Adding /all after the channel name will list disconnected players
as well.
"""
session = command.session
source_object = command.source_object
if not command.command_argument:
cmd_clist(command)
source_object.emit_to("Usage: @cwho <channel>[/all]")
return
channel_name = command.command_argument
if channel_name.strip() == '':
source_object.emit_to("You must specify a channel name.")
return
name_matches = comsys.cname_search(channel_name, exact=True)
if name_matches:
# Check to make sure the user has permission to use @cwho.
is_channel_admin = source_object.has_perm("objects.channel_admin")
is_controlled_by_plr = name_matches[0].controlled_by(source_object)
if is_controlled_by_plr or is_channel_admin:
comsys.msg_cwho(source_object, channel_name)
else:
source_object.emit_to("Permission denied.")
return
else:
source_object.emit_to("No channel with that name was found.")
return
GLOBAL_CMD_TABLE.add_command("@cwho", cmd_cwho),
def cmd_ccreate(command):
"""
@ccreate
Creates a new channel with the invoker being the default owner.
"""
# TODO: Implement cmd_ccreate
source_object = command.source_object
cname = command.command_argument
if not cname:
source_object.emit_to("Usage @ccreate <channelname>")
return
if not source_object.has_perm("objects.channel_admin"):
source_object.emit_to("Permission denied.")
return
name_matches = comsys.cname_search(cname, exact=True)
if name_matches:
source_object.emit_to("A channel with that name already exists.")
else:
# Create and set the object up.
new_chan = comsys.create_channel(cname, source_object)
source_object.emit_to("Channel %s created." % (new_chan.get_name(),))
GLOBAL_CMD_TABLE.add_command("@ccreate", cmd_ccreate)
def cmd_cchown(command):
"""
@cchown <channel>=<player>
Changes the owner of a channel.
"""
source_object = command.source_object
args = command.command_argument
if not args or "=" not in args:
source_object.emit_to("Usage: @cchown <channel> = <player>")
return
cname, pname = args.split("=",1)
cname, pname = cname.strip(), pname.strip()
#locate channel
try:
channel = CommChannel.objects.get(name__iexact=cname)
except CommChannel.DoesNotExist:
source_object.emit_to("Channel '%s' not found." % cname)
return
#check so we have ownership to give away.
if not channel.controlled_by(source_object) and not source_object.has_perm("channels.channel_admin"):
source_object.emit_to("You don't control this channel.")
return
#find the new owner
new_owner = Object.objects.player_name_search(pname)
if not new_owner:
source_object.emit_to("New owner '%s' not found." % pname)
return
old_owner = channel.get_owner()
old_pname = old_owner.get_name(show_dbref=False)
if old_owner == new_owner:
source_object.emit_to("Owner unchanged.")
return
#all is set, change owner
channel.set_owner(new_owner)
source_object.emit_to("Owner of %s changed from %s to %s." % (cname, old_pname, pname))
new_owner.emit_to("%s transfered ownership of channel '%s' to you." % (old_pname, cname))
GLOBAL_CMD_TABLE.add_command("@cchown", cmd_cchown)