|
|
@ -1,4 +1,5 @@ |
|
|
|
# -*- coding: utf-8 -*- |
|
|
|
# kate: space-indent on; indent-width 4; replace-tabs on; |
|
|
|
|
|
|
|
""" |
|
|
|
* Copyright © 2009-2010, Michael "Svedrin" Ziegler <diese-addy@funzt-halt.net> |
|
|
@ -52,7 +53,7 @@ def mk_config_property( field, doc="", get_coerce=None, get_none=None, set_coerc |
|
|
|
|
|
|
|
def get_field( self ): |
|
|
|
if self.id is not None: |
|
|
|
val = self.getConf( field ); |
|
|
|
val = self.getConf( field ) |
|
|
|
if val is None or val == '': |
|
|
|
return get_none |
|
|
|
if callable(get_coerce): |
|
|
@ -74,28 +75,28 @@ def mk_config_bool_property( field, doc="" ): |
|
|
|
return mk_config_property( field, doc=doc, |
|
|
|
get_coerce = lambda value: value == "true", |
|
|
|
set_coerce = lambda value: str(value).lower() |
|
|
|
); |
|
|
|
) |
|
|
|
|
|
|
|
|
|
|
|
class MumbleServer( models.Model ): |
|
|
|
""" Represents a Murmur server installation. """ |
|
|
|
|
|
|
|
dbus = models.CharField( _('DBus or ICE base'), max_length=200, unique=True, default=settings.DEFAULT_CONN, help_text=_( |
|
|
|
"Examples: 'net.sourceforge.mumble.murmur' for DBus or 'Meta:tcp -h 127.0.0.1 -p 6502' for Ice.") ); |
|
|
|
secret = models.CharField( _('Ice Secret'), max_length=200, blank=True ); |
|
|
|
"Examples: 'net.sourceforge.mumble.murmur' for DBus or 'Meta:tcp -h 127.0.0.1 -p 6502' for Ice.") ) |
|
|
|
secret = models.CharField( _('Ice Secret'), max_length=200, blank=True ) |
|
|
|
|
|
|
|
class Meta: |
|
|
|
verbose_name = _('Mumble Server'); |
|
|
|
verbose_name_plural = _('Mumble Servers'); |
|
|
|
verbose_name = _('Mumble Server') |
|
|
|
verbose_name_plural = _('Mumble Servers') |
|
|
|
|
|
|
|
def __init__( self, *args, **kwargs ): |
|
|
|
models.Model.__init__( self, *args, **kwargs ); |
|
|
|
self._ctl = None; |
|
|
|
self._conf = None; |
|
|
|
self._version = None; |
|
|
|
models.Model.__init__( self, *args, **kwargs ) |
|
|
|
self._ctl = None |
|
|
|
self._conf = None |
|
|
|
self._version = None |
|
|
|
|
|
|
|
def __unicode__( self ): |
|
|
|
return self.dbus; |
|
|
|
return self.dbus |
|
|
|
|
|
|
|
# Ctl instantiation |
|
|
|
def getCtl( self ): |
|
|
@ -104,14 +105,14 @@ class MumbleServer( models.Model ): |
|
|
|
Only one instance will be created, and reused on subsequent calls. |
|
|
|
""" |
|
|
|
if not self._ctl: |
|
|
|
self._ctl = MumbleCtlBase.newInstance( self.dbus, settings.SLICE, self.secret ); |
|
|
|
return self._ctl; |
|
|
|
self._ctl = MumbleCtlBase.newInstance( self.dbus, settings.SLICE, self.secret ) |
|
|
|
return self._ctl |
|
|
|
|
|
|
|
ctl = property( getCtl, doc="Get a Control object for this server. The ctl is cached for later reuse." ); |
|
|
|
ctl = property( getCtl, doc="Get a Control object for this server. The ctl is cached for later reuse." ) |
|
|
|
|
|
|
|
def isMethodDbus(self): |
|
|
|
""" Return true if this instance uses DBus. """ |
|
|
|
rd = re.compile( r'^(\w+\.)*\w+$' ); |
|
|
|
rd = re.compile( r'^(\w+\.)*\w+$' ) |
|
|
|
return bool(rd.match(self.dbus)) |
|
|
|
|
|
|
|
method_dbus = property( isMethodDbus ) |
|
|
@ -197,18 +198,18 @@ class Mumble( models.Model ): |
|
|
|
deleted as well. |
|
|
|
""" |
|
|
|
|
|
|
|
server = models.ForeignKey( MumbleServer, verbose_name=_("Mumble Server") ); |
|
|
|
name = models.CharField( _('Server Name'), max_length=200 ); |
|
|
|
srvid = models.IntegerField( _('Server ID'), editable=False ); |
|
|
|
server = models.ForeignKey( MumbleServer, verbose_name=_("Mumble Server") ) |
|
|
|
name = models.CharField( _('Server Name'), max_length=200 ) |
|
|
|
srvid = models.IntegerField( _('Server ID'), editable=False ) |
|
|
|
addr = models.CharField( _('Server Address'), max_length=200, blank=True, help_text=_( |
|
|
|
"Hostname or IP address to bind to. You should use a hostname here, because it will appear on the " |
|
|
|
"global server list.") ); |
|
|
|
"global server list.") ) |
|
|
|
port = models.IntegerField( _('Server Port'), blank=True, null=True, help_text=_( |
|
|
|
"Port number to bind to. Leave empty to auto assign one.") ); |
|
|
|
"Port number to bind to. Leave empty to auto assign one.") ) |
|
|
|
display = models.CharField( _('Server Display Address'), max_length=200, blank=True, help_text=_( |
|
|
|
"This field is only relevant if you are located behind a NAT, and names the Hostname or IP address " |
|
|
|
"to use in the Channel Viewer and for the global server list registration. If not given, the addr " |
|
|
|
"and port fields are used. If display and bind ports are equal, you can omit it here.") ); |
|
|
|
"and port fields are used. If display and bind ports are equal, you can omit it here.") ) |
|
|
|
|
|
|
|
supw = property( lambda self: '', |
|
|
|
lambda self, value: ( value and self.ctl.setSuperUserPassword( self.srvid, value ) ) or None, |
|
|
@ -247,74 +248,74 @@ class Mumble( models.Model ): |
|
|
|
def setBooted( self, value ): |
|
|
|
if value != self.getBooted(): |
|
|
|
if value: |
|
|
|
self.ctl.start( self.srvid ); |
|
|
|
self.ctl.start( self.srvid ) |
|
|
|
else: |
|
|
|
self.ctl.stop( self.srvid ); |
|
|
|
self.ctl.stop( self.srvid ) |
|
|
|
|
|
|
|
booted = property( getBooted, setBooted, doc=ugettext_noop("Boot Server") ) |
|
|
|
online = property( getBooted, setBooted, doc=ugettext_noop("Boot Server") ) |
|
|
|
|
|
|
|
class Meta: |
|
|
|
unique_together = ( ( 'server', 'srvid' ), ); |
|
|
|
verbose_name = _('Server instance'); |
|
|
|
verbose_name_plural = _('Server instances'); |
|
|
|
unique_together = ( ( 'server', 'srvid' ), ) |
|
|
|
verbose_name = _('Server instance') |
|
|
|
verbose_name_plural = _('Server instances') |
|
|
|
|
|
|
|
def __unicode__( self ): |
|
|
|
if not self.id: |
|
|
|
return u'Murmur "%s" (NOT YET CREATED)' % self.name; |
|
|
|
return u'Murmur "%s" (%d)' % ( self.name, self.srvid ); |
|
|
|
return u'Murmur "%s" (NOT YET CREATED)' % self.name |
|
|
|
return u'Murmur "%s" (%d)' % ( self.name, self.srvid ) |
|
|
|
|
|
|
|
def save( self, dontConfigureMurmur=False ): |
|
|
|
""" Save the options configured in this model instance not only to Django's database, |
|
|
|
but to Murmur as well. |
|
|
|
""" |
|
|
|
if dontConfigureMurmur: |
|
|
|
return models.Model.save( self ); |
|
|
|
return models.Model.save( self ) |
|
|
|
|
|
|
|
if self.id is None: |
|
|
|
self.srvid = self.ctl.newServer(); |
|
|
|
self.srvid = self.ctl.newServer() |
|
|
|
|
|
|
|
self.ctl.setConf( self.srvid, 'registername', self.name ); |
|
|
|
self.ctl.setConf( self.srvid, 'registername', self.name ) |
|
|
|
|
|
|
|
if self.addr: |
|
|
|
if " " in self.addr: |
|
|
|
# user gave multiple addresses, don't mess with that |
|
|
|
self.ctl.setConf( self.srvid, 'host', self.addr ); |
|
|
|
self.ctl.setConf( self.srvid, 'host', self.addr ) |
|
|
|
else: |
|
|
|
self.ctl.setConf( self.srvid, 'host', get_ipv46_str_by_name(self.addr) ); |
|
|
|
self.ctl.setConf( self.srvid, 'host', get_ipv46_str_by_name(self.addr) ) |
|
|
|
else: |
|
|
|
self.ctl.setConf( self.srvid, 'host', '' ); |
|
|
|
self.ctl.setConf( self.srvid, 'host', '' ) |
|
|
|
|
|
|
|
if self.port and self.port != self.server.defaultPort + self.srvid - 1: |
|
|
|
self.ctl.setConf( self.srvid, 'port', str(self.port) ); |
|
|
|
self.ctl.setConf( self.srvid, 'port', str(self.port) ) |
|
|
|
else: |
|
|
|
self.ctl.setConf( self.srvid, 'port', '' ); |
|
|
|
self.ctl.setConf( self.srvid, 'port', '' ) |
|
|
|
|
|
|
|
if self.netloc: |
|
|
|
self.ctl.setConf( self.srvid, 'registerhostname', self.netloc ); |
|
|
|
self.ctl.setConf( self.srvid, 'registerhostname', self.netloc ) |
|
|
|
else: |
|
|
|
self.ctl.setConf( self.srvid, 'registerhostname', '' ); |
|
|
|
self.ctl.setConf( self.srvid, 'registerhostname', '' ) |
|
|
|
|
|
|
|
return models.Model.save( self ); |
|
|
|
return models.Model.save( self ) |
|
|
|
|
|
|
|
|
|
|
|
def __init__( self, *args, **kwargs ): |
|
|
|
models.Model.__init__( self, *args, **kwargs ); |
|
|
|
self._channels = None; |
|
|
|
self._rootchan = None; |
|
|
|
models.Model.__init__( self, *args, **kwargs ) |
|
|
|
self._channels = None |
|
|
|
self._rootchan = None |
|
|
|
|
|
|
|
|
|
|
|
users_regged = property( lambda self: self.mumbleuser_set.count(), doc="Number of registered users." ); |
|
|
|
users_online = property( lambda self: len(self.ctl.getPlayers(self.srvid)), doc="Number of online users." ); |
|
|
|
channel_cnt = property( lambda self: len(self.ctl.getChannels(self.srvid)), doc="Number of channels." ); |
|
|
|
users_regged = property( lambda self: self.mumbleuser_set.count(), doc="Number of registered users." ) |
|
|
|
users_online = property( lambda self: len(self.ctl.getPlayers(self.srvid)), doc="Number of online users." ) |
|
|
|
channel_cnt = property( lambda self: len(self.ctl.getChannels(self.srvid)), doc="Number of channels." ) |
|
|
|
is_public = property( lambda self: not self.passwd, |
|
|
|
doc="False if a password is needed to join this server." ); |
|
|
|
doc="False if a password is needed to join this server." ) |
|
|
|
|
|
|
|
is_server = True; |
|
|
|
is_channel = False; |
|
|
|
is_player = False; |
|
|
|
is_server = True |
|
|
|
is_channel = False |
|
|
|
is_player = False |
|
|
|
|
|
|
|
ctl = property( lambda self: self.server.ctl ); |
|
|
|
ctl = property( lambda self: self.server.ctl ) |
|
|
|
|
|
|
|
def getConf( self, field ): |
|
|
|
return self.ctl.getConf( self.srvid, field ) |
|
|
@ -323,12 +324,12 @@ class Mumble( models.Model ): |
|
|
|
return self.ctl.setConf( self.srvid, field, value ) |
|
|
|
|
|
|
|
def configureFromMurmur( self ): |
|
|
|
conf = self.ctl.getAllConf( self.srvid ); |
|
|
|
conf = self.ctl.getAllConf( self.srvid ) |
|
|
|
|
|
|
|
if "registername" not in conf or not conf["registername"]: |
|
|
|
self.name = "noname"; |
|
|
|
self.name = "noname" |
|
|
|
else: |
|
|
|
self.name = conf["registername"]; |
|
|
|
self.name = conf["registername"] |
|
|
|
|
|
|
|
if "registerhostname" in conf and conf["registerhostname"]: |
|
|
|
if ':' in conf["registerhostname"]: |
|
|
@ -372,29 +373,29 @@ class Mumble( models.Model ): |
|
|
|
self.display = '' |
|
|
|
self.addr = '' |
|
|
|
|
|
|
|
self.save( dontConfigureMurmur=True ); |
|
|
|
self.save( dontConfigureMurmur=True ) |
|
|
|
|
|
|
|
|
|
|
|
def readUsersFromMurmur( self, verbose=0 ): |
|
|
|
if not self.booted: |
|
|
|
raise SystemError( "This murmur instance is not currently running, can't sync." ); |
|
|
|
raise SystemError( "This murmur instance is not currently running, can't sync." ) |
|
|
|
|
|
|
|
players = self.ctl.getRegisteredPlayers(self.srvid); |
|
|
|
players = self.ctl.getRegisteredPlayers(self.srvid) |
|
|
|
known_ids = [rec["mumbleid"] |
|
|
|
for rec in MumbleUser.objects.filter( server=self ).values( "mumbleid" ) |
|
|
|
] |
|
|
|
|
|
|
|
for idx in players: |
|
|
|
playerdata = players[idx]; |
|
|
|
playerdata = players[idx] |
|
|
|
|
|
|
|
if playerdata.userid == 0: # Skip SuperUsers |
|
|
|
continue; |
|
|
|
continue |
|
|
|
if verbose > 1: |
|
|
|
print "Checking Player with id %d." % playerdata.userid; |
|
|
|
print "Checking Player with id %d." % playerdata.userid |
|
|
|
|
|
|
|
if playerdata.userid not in known_ids: |
|
|
|
if verbose: |
|
|
|
print 'Found new Player "%s".' % playerdata.name; |
|
|
|
print 'Found new Player "%s".' % playerdata.name |
|
|
|
|
|
|
|
playerinstance = MumbleUser( |
|
|
|
mumbleid = playerdata.userid, |
|
|
@ -402,27 +403,27 @@ class Mumble( models.Model ): |
|
|
|
password = '', |
|
|
|
server = self, |
|
|
|
owner = None |
|
|
|
); |
|
|
|
) |
|
|
|
|
|
|
|
else: |
|
|
|
if verbose > 1: |
|
|
|
print "Player '%s' is already known." % playerdata.name; |
|
|
|
playerinstance = MumbleUser.objects.get( server=self, mumbleid=playerdata.userid ); |
|
|
|
playerinstance.name = playerdata.name; |
|
|
|
print "Player '%s' is already known." % playerdata.name |
|
|
|
playerinstance = MumbleUser.objects.get( server=self, mumbleid=playerdata.userid ) |
|
|
|
playerinstance.name = playerdata.name |
|
|
|
|
|
|
|
playerinstance.save( dontConfigureMurmur=True ); |
|
|
|
playerinstance.save( dontConfigureMurmur=True ) |
|
|
|
|
|
|
|
|
|
|
|
def isUserAdmin( self, user ): |
|
|
|
""" Determine if the given user is an admin on this server. """ |
|
|
|
if user.is_authenticated(): |
|
|
|
if user.is_superuser: |
|
|
|
return True; |
|
|
|
return True |
|
|
|
try: |
|
|
|
return self.mumbleuser_set.get( owner=user ).getAdmin(); |
|
|
|
return self.mumbleuser_set.get( owner=user ).getAdmin() |
|
|
|
except MumbleUser.DoesNotExist: |
|
|
|
return False; |
|
|
|
return False; |
|
|
|
return False |
|
|
|
return False |
|
|
|
|
|
|
|
|
|
|
|
# Deletion handler |
|
|
@ -432,7 +433,7 @@ class Mumble( models.Model ): |
|
|
|
|
|
|
|
@staticmethod |
|
|
|
def pre_delete_listener( **kwargs ): |
|
|
|
kwargs['instance'].deleteServer(); |
|
|
|
kwargs['instance'].deleteServer() |
|
|
|
|
|
|
|
|
|
|
|
# Channel list |
|
|
@ -443,58 +444,58 @@ class Mumble( models.Model ): |
|
|
|
calls will simply return the list created last time. |
|
|
|
""" |
|
|
|
if self._channels is None: |
|
|
|
self._channels = {}; |
|
|
|
chanlist = self.ctl.getChannels(self.srvid).values(); |
|
|
|
links = {}; |
|
|
|
self._channels = {} |
|
|
|
chanlist = self.ctl.getChannels(self.srvid).values() |
|
|
|
links = {} |
|
|
|
|
|
|
|
# sometimes, ICE seems to return the Channel list in a weird order. |
|
|
|
# itercount prevents infinite loops. |
|
|
|
itercount = 0; |
|
|
|
maxiter = len(chanlist) * 3; |
|
|
|
itercount = 0 |
|
|
|
maxiter = len(chanlist) * 3 |
|
|
|
while len(chanlist) and itercount < maxiter: |
|
|
|
itercount += 1; |
|
|
|
itercount += 1 |
|
|
|
for theChan in chanlist: |
|
|
|
# Channels - Fields: 0 = ID, 1 = Name, 2 = Parent-ID, 3 = Links |
|
|
|
if( theChan.parent == -1 ): |
|
|
|
# No parent |
|
|
|
self._channels[theChan.id] = mmChannel( self, theChan ); |
|
|
|
self._channels[theChan.id] = mmChannel( self, theChan ) |
|
|
|
elif theChan.parent in self.channels: |
|
|
|
# parent already known |
|
|
|
self._channels[theChan.id] = mmChannel( self, theChan, self.channels[theChan.parent] ); |
|
|
|
self._channels[theChan.id] = mmChannel( self, theChan, self.channels[theChan.parent] ) |
|
|
|
else: |
|
|
|
continue; |
|
|
|
continue |
|
|
|
|
|
|
|
chanlist.remove( theChan ); |
|
|
|
chanlist.remove( theChan ) |
|
|
|
|
|
|
|
self._channels[theChan.id].serverId = self.id; |
|
|
|
self._channels[theChan.id].serverId = self.id |
|
|
|
|
|
|
|
# process links - if the linked channels are known, link; else save their ids to link later |
|
|
|
for linked in theChan.links: |
|
|
|
if linked in self._channels: |
|
|
|
self._channels[theChan.id].linked.append( self._channels[linked] ); |
|
|
|
self._channels[theChan.id].linked.append( self._channels[linked] ) |
|
|
|
else: |
|
|
|
if linked not in links: |
|
|
|
links[linked] = list(); |
|
|
|
links[linked].append( self._channels[theChan.id] ); |
|
|
|
links[linked] = list() |
|
|
|
links[linked].append( self._channels[theChan.id] ) |
|
|
|
|
|
|
|
# check if earlier round trips saved channel ids to be linked to the current channel |
|
|
|
if theChan.id in links: |
|
|
|
for targetChan in links[theChan.id]: |
|
|
|
targetChan.linked.append( self._channels[theChan.id] ); |
|
|
|
targetChan.linked.append( self._channels[theChan.id] ) |
|
|
|
|
|
|
|
self._channels[0].name = self.name; |
|
|
|
self._channels[0].name = self.name |
|
|
|
|
|
|
|
self.players = {}; |
|
|
|
self.players = {} |
|
|
|
for thePlayer in self.ctl.getPlayers(self.srvid).values(): |
|
|
|
# Players - Fields: 0 = UserID, 6 = ChannelID |
|
|
|
self.players[ thePlayer.session ] = mmPlayer( self, thePlayer, self._channels[ thePlayer.channel ] ); |
|
|
|
self.players[ thePlayer.session ] = mmPlayer( self, thePlayer, self._channels[ thePlayer.channel ] ) |
|
|
|
|
|
|
|
self._channels[0].sort(); |
|
|
|
self._channels[0].sort() |
|
|
|
|
|
|
|
return self._channels; |
|
|
|
return self._channels |
|
|
|
|
|
|
|
channels = property( getChannels, doc="A convenience wrapper for getChannels()." ); |
|
|
|
rootchan = property( lambda self: self.channels[0], doc="A convenience wrapper for getChannels()[0]." ); |
|
|
|
channels = property( getChannels, doc="A convenience wrapper for getChannels()." ) |
|
|
|
rootchan = property( lambda self: self.channels[0], doc="A convenience wrapper for getChannels()[0]." ) |
|
|
|
|
|
|
|
def getNetloc( self ): |
|
|
|
""" Return the address from the Display field (if any), or the server address. |
|
|
@ -503,43 +504,43 @@ class Mumble( models.Model ): |
|
|
|
""" |
|
|
|
if self.display: |
|
|
|
if ":" in self.display: |
|
|
|
return self.display; |
|
|
|
return self.display |
|
|
|
else: |
|
|
|
daddr = self.display; |
|
|
|
daddr = self.display |
|
|
|
elif " " in self.addr: |
|
|
|
daddr = self.addr.split(" ")[0]; |
|
|
|
daddr = self.addr.split(" ")[0] |
|
|
|
else: |
|
|
|
daddr = self.addr; |
|
|
|
daddr = self.addr |
|
|
|
|
|
|
|
if self.port and self.port != settings.MUMBLE_DEFAULT_PORT: |
|
|
|
return "%s:%d" % (daddr, self.port); |
|
|
|
return "%s:%d" % (daddr, self.port) |
|
|
|
else: |
|
|
|
return daddr; |
|
|
|
return daddr |
|
|
|
|
|
|
|
netloc = property( getNetloc ); |
|
|
|
netloc = property( getNetloc ) |
|
|
|
|
|
|
|
def getURL( self, forUser = None ): |
|
|
|
""" Create an URL of the form mumble://username@host:port/ for this server. """ |
|
|
|
if not self.netloc: |
|
|
|
return None |
|
|
|
from urlparse import urlunsplit |
|
|
|
versionstr = "version=%s" % self.prettyversion; |
|
|
|
versionstr = "version=%s" % self.prettyversion |
|
|
|
if forUser is not None: |
|
|
|
netloc = "%s@%s" % ( forUser.name, self.netloc ); |
|
|
|
netloc = "%s@%s" % ( forUser.name, self.netloc ) |
|
|
|
return urlunsplit(( "mumble", netloc, "", versionstr, "" )) |
|
|
|
else: |
|
|
|
return urlunsplit(( "mumble", self.netloc, "", versionstr, "" )) |
|
|
|
|
|
|
|
connecturl = property( getURL ); |
|
|
|
connecturl = property( getURL ) |
|
|
|
|
|
|
|
version = property( lambda self: self.server.version, doc="The version of Murmur." ); |
|
|
|
prettyversion = property( lambda self: self.server.prettyversion ); |
|
|
|
version = property( lambda self: self.server.version, doc="The version of Murmur." ) |
|
|
|
prettyversion = property( lambda self: self.server.prettyversion ) |
|
|
|
|
|
|
|
def asDict( self ): |
|
|
|
return { 'name': self.name, |
|
|
|
'id': self.id, |
|
|
|
'root': self.rootchan.asDict() |
|
|
|
}; |
|
|
|
} |
|
|
|
|
|
|
|
def asMvXml( self ): |
|
|
|
""" Return an XML tree for this server suitable for MumbleViewer-ng. """ |
|
|
@ -556,15 +557,15 @@ class Mumble( models.Model ): |
|
|
|
def __setattr__( self, name, value ): |
|
|
|
if name == 'server': |
|
|
|
if self.id is not None and self.server != value: |
|
|
|
raise AttributeError( _( "This field must not be updated once the record has been saved." ) ); |
|
|
|
raise AttributeError( _( "This field must not be updated once the record has been saved." ) ) |
|
|
|
|
|
|
|
models.Model.__setattr__( self, name, value ); |
|
|
|
models.Model.__setattr__( self, name, value ) |
|
|
|
|
|
|
|
def kickUser( self, sessionid, reason="" ): |
|
|
|
return self.ctl.kickUser( self.srvid, sessionid, reason ); |
|
|
|
return self.ctl.kickUser( self.srvid, sessionid, reason ) |
|
|
|
|
|
|
|
def banUser( self, sessionid, reason="" ): |
|
|
|
return self.ctl.addBanForSession( self.srvid, sessionid, reason=reason ); |
|
|
|
return self.ctl.addBanForSession( self.srvid, sessionid, reason=reason ) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@ -573,9 +574,9 @@ def mk_registration_property( field, doc="" ): |
|
|
|
|
|
|
|
def get_field( self ): |
|
|
|
if field in self.registration: |
|
|
|
return self.registration[field]; |
|
|
|
return self.registration[field] |
|
|
|
else: |
|
|
|
return None; |
|
|
|
return None |
|
|
|
|
|
|
|
return property( get_field, doc=doc ) |
|
|
|
|
|
|
@ -593,14 +594,14 @@ class MumbleUser( models.Model ): |
|
|
|
in Murmur as well, after revoking the user's admin privileges. |
|
|
|
""" |
|
|
|
|
|
|
|
mumbleid = models.IntegerField( _('Mumble player_id'), editable = False, default = -1 ); |
|
|
|
name = models.CharField( _('User name and Login'), max_length = 200 ); |
|
|
|
password = models.CharField( _('Login password'), max_length = 200, blank=True ); |
|
|
|
server = models.ForeignKey( Mumble, verbose_name=_('Server instance'), related_name="mumbleuser_set" ); |
|
|
|
owner = models.ForeignKey( User, verbose_name=_('Account owner'), related_name="mumbleuser_set", null=True, blank=True ); |
|
|
|
mumbleid = models.IntegerField( _('Mumble player_id'), editable = False, default = -1 ) |
|
|
|
name = models.CharField( _('User name and Login'), max_length = 200 ) |
|
|
|
password = models.CharField( _('Login password'), max_length = 200, blank=True ) |
|
|
|
server = models.ForeignKey( Mumble, verbose_name=_('Server instance'), related_name="mumbleuser_set" ) |
|
|
|
owner = models.ForeignKey( User, verbose_name=_('Account owner'), related_name="mumbleuser_set", null=True, blank=True ) |
|
|
|
|
|
|
|
comment = mk_registration_property( "comment", doc=ugettext_noop("The user's comment.") ); |
|
|
|
hash = mk_registration_property( "hash", doc=ugettext_noop("The user's hash.") ); |
|
|
|
comment = mk_registration_property( "comment", doc=ugettext_noop("The user's comment.") ) |
|
|
|
hash = mk_registration_property( "hash", doc=ugettext_noop("The user's hash.") ) |
|
|
|
|
|
|
|
gravatar256 = property( lambda self: self.gravatarUrl( size=256 ) ) |
|
|
|
gravatar128 = property( lambda self: self.gravatarUrl( size=128 ) ) |
|
|
@ -608,41 +609,41 @@ class MumbleUser( models.Model ): |
|
|
|
gravatar = property( lambda self: self.gravatarUrl() ) |
|
|
|
|
|
|
|
class Meta: |
|
|
|
unique_together = ( ( 'server', 'owner' ), ( 'server', 'mumbleid' ) ); |
|
|
|
verbose_name = _( 'User account' ); |
|
|
|
verbose_name_plural = _( 'User accounts' ); |
|
|
|
unique_together = ( ( 'server', 'owner' ), ( 'server', 'mumbleid' ) ) |
|
|
|
verbose_name = _( 'User account' ) |
|
|
|
verbose_name_plural = _( 'User accounts' ) |
|
|
|
|
|
|
|
is_server = False; |
|
|
|
is_channel = False; |
|
|
|
is_player = True; |
|
|
|
is_server = False |
|
|
|
is_channel = False |
|
|
|
is_player = True |
|
|
|
|
|
|
|
def __unicode__( self ): |
|
|
|
return _("Mumble user %(mu)s on %(srv)s owned by Django user %(du)s") % { |
|
|
|
'mu': self.name, |
|
|
|
'srv': self.server, |
|
|
|
'du': self.owner |
|
|
|
}; |
|
|
|
} |
|
|
|
|
|
|
|
def save( self, dontConfigureMurmur=False ): |
|
|
|
""" Save the settings in this model to Murmur. """ |
|
|
|
if dontConfigureMurmur: |
|
|
|
return models.Model.save( self ); |
|
|
|
return models.Model.save( self ) |
|
|
|
|
|
|
|
ctl = self.server.ctl; |
|
|
|
ctl = self.server.ctl |
|
|
|
|
|
|
|
if self.owner: |
|
|
|
email = self.owner.email; |
|
|
|
email = self.owner.email |
|
|
|
else: |
|
|
|
email = settings.DEFAULT_FROM_EMAIL; |
|
|
|
email = settings.DEFAULT_FROM_EMAIL |
|
|
|
|
|
|
|
if self.id is None: |
|
|
|
# This is a new user record, so Murmur doesn't know about it yet |
|
|
|
if len( ctl.getRegisteredPlayers( self.server.srvid, self.name ) ) > 0: |
|
|
|
raise ValueError( _( "Another player already registered that name." ) ); |
|
|
|
raise ValueError( _( "Another player already registered that name." ) ) |
|
|
|
if not self.password: |
|
|
|
raise ValueError( _( "Cannot register player without a password!" ) ); |
|
|
|
raise ValueError( _( "Cannot register player without a password!" ) ) |
|
|
|
|
|
|
|
self.mumbleid = ctl.registerPlayer( self.server.srvid, self.name, email, self.password ); |
|
|
|
self.mumbleid = ctl.registerPlayer( self.server.srvid, self.name, email, self.password ) |
|
|
|
|
|
|
|
# Update user's registration |
|
|
|
elif self.password: |
|
|
@ -652,56 +653,56 @@ class MumbleUser( models.Model ): |
|
|
|
self.name, |
|
|
|
email, |
|
|
|
self.password |
|
|
|
); |
|
|
|
) |
|
|
|
|
|
|
|
# Don't save the users' passwords, we don't need them anyway |
|
|
|
self.password = ''; |
|
|
|
self.password = '' |
|
|
|
|
|
|
|
# If enabled (and possible), set Gravatar as default Avatar |
|
|
|
if settings.USE_GRAVATAR and self.gravatar: |
|
|
|
self.setTextureFromUrl( self.gravatar ) |
|
|
|
|
|
|
|
return models.Model.save( self ); |
|
|
|
return models.Model.save( self ) |
|
|
|
|
|
|
|
def __init__( self, *args, **kwargs ): |
|
|
|
models.Model.__init__( self, *args, **kwargs ); |
|
|
|
self._registration = None; |
|
|
|
models.Model.__init__( self, *args, **kwargs ) |
|
|
|
self._registration = None |
|
|
|
|
|
|
|
# Admin handlers |
|
|
|
def getAdmin( self ): |
|
|
|
""" Get ACL of root Channel, get the admin group and see if this user is in it. """ |
|
|
|
if self.mumbleid == -1: |
|
|
|
return False; |
|
|
|
return False |
|
|
|
else: |
|
|
|
return self.server.rootchan.acl.group_has_member( "admin", self.mumbleid ); |
|
|
|
return self.server.rootchan.acl.group_has_member( "admin", self.mumbleid ) |
|
|
|
|
|
|
|
def setAdmin( self, value ): |
|
|
|
""" Set or revoke this user's membership in the admin group on the root channel. """ |
|
|
|
if self.mumbleid == -1: |
|
|
|
return False; |
|
|
|
return False |
|
|
|
if value: |
|
|
|
self.server.rootchan.acl.group_add_member( "admin", self.mumbleid ); |
|
|
|
self.server.rootchan.acl.group_add_member( "admin", self.mumbleid ) |
|
|
|
else: |
|
|
|
self.server.rootchan.acl.group_remove_member( "admin", self.mumbleid ); |
|
|
|
self.server.rootchan.acl.save(); |
|
|
|
return value; |
|
|
|
self.server.rootchan.acl.group_remove_member( "admin", self.mumbleid ) |
|
|
|
self.server.rootchan.acl.save() |
|
|
|
return value |
|
|
|
|
|
|
|
aclAdmin = property( getAdmin, setAdmin, doc=ugettext_noop('Admin on root channel') ); |
|
|
|
aclAdmin = property( getAdmin, setAdmin, doc=ugettext_noop('Admin on root channel') ) |
|
|
|
|
|
|
|
|
|
|
|
# Registration fetching |
|
|
|
def getRegistration( self ): |
|
|
|
""" Retrieve a user's registration from Murmur as a dict. """ |
|
|
|
if not self._registration: |
|
|
|
self._registration = self.server.ctl.getRegistration( self.server.srvid, self.mumbleid ); |
|
|
|
return self._registration; |
|
|
|
self._registration = self.server.ctl.getRegistration( self.server.srvid, self.mumbleid ) |
|
|
|
return self._registration |
|
|
|
|
|
|
|
registration = property( getRegistration ); |
|
|
|
registration = property( getRegistration ) |
|
|
|
|
|
|
|
# Texture handlers |
|
|
|
def getTexture( self ): |
|
|
|
""" Get the user texture as a PIL Image. """ |
|
|
|
return self.server.ctl.getTexture(self.server.srvid, self.mumbleid); |
|
|
|
return self.server.ctl.getTexture(self.server.srvid, self.mumbleid) |
|
|
|
|
|
|
|
def setTexture( self, image ): |
|
|
|
""" Install the given image as the user's texture. """ |
|
|
@ -714,16 +715,16 @@ class MumbleUser( models.Model ): |
|
|
|
|
|
|
|
texture = property( getTexture, setTexture, |
|
|
|
doc="Get the texture as a PIL Image or set the Image as the texture." |
|
|
|
); |
|
|
|
) |
|
|
|
|
|
|
|
def hasTexture( self ): |
|
|
|
""" Check if this user has a texture set. """ |
|
|
|
try: |
|
|
|
self.getTexture(); |
|
|
|
self.getTexture() |
|
|
|
except ValueError: |
|
|
|
return False; |
|
|
|
return False |
|
|
|
else: |
|
|
|
return True; |
|
|
|
return True |
|
|
|
|
|
|
|
def gravatarUrl( self, size=80 ): |
|
|
|
""" Get a Gravatar URL for my owner's email adress (if any), or using the User's cert hash. |
|
|
@ -741,20 +742,20 @@ class MumbleUser( models.Model ): |
|
|
|
""" Get a URL under which the texture can be retrieved. """ |
|
|
|
from views import showTexture |
|
|
|
from django.core.urlresolvers import reverse |
|
|
|
return reverse( showTexture, kwargs={ 'server': self.server.id, 'userid': self.id } ); |
|
|
|
return reverse( showTexture, kwargs={ 'server': self.server.id, 'userid': self.id } ) |
|
|
|
|
|
|
|
textureUrl = property( getTextureUrl ); |
|
|
|
textureUrl = property( getTextureUrl ) |
|
|
|
|
|
|
|
|
|
|
|
# Deletion handler |
|
|
|
@staticmethod |
|
|
|
def pre_delete_listener( **kwargs ): |
|
|
|
kwargs['instance'].unregister(); |
|
|
|
kwargs['instance'].unregister() |
|
|
|
|
|
|
|
def unregister( self ): |
|
|
|
""" Delete this user account from Murmur. """ |
|
|
|
if self.getAdmin(): |
|
|
|
self.setAdmin( False ); |
|
|
|
self.setAdmin( False ) |
|
|
|
self.server.ctl.unregisterPlayer(self.server.srvid, self.mumbleid) |
|
|
|
|
|
|
|
|
|
|
@ -762,15 +763,15 @@ class MumbleUser( models.Model ): |
|
|
|
def __setattr__( self, name, value ): |
|
|
|
if name == 'server': |
|
|
|
if self.id is not None and self.server != value: |
|
|
|
raise AttributeError( _( "This field must not be updated once the record has been saved." ) ); |
|
|
|
raise AttributeError( _( "This field must not be updated once the record has been saved." ) ) |
|
|
|
|
|
|
|
models.Model.__setattr__( self, name, value ); |
|
|
|
models.Model.__setattr__( self, name, value ) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
signals.pre_delete.connect( Mumble.pre_delete_listener, sender=Mumble ); |
|
|
|
signals.pre_delete.connect( MumbleUser.pre_delete_listener, sender=MumbleUser ); |
|
|
|
signals.pre_delete.connect( Mumble.pre_delete_listener, sender=Mumble ) |
|
|
|
signals.pre_delete.connect( MumbleUser.pre_delete_listener, sender=MumbleUser ) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|