Browse Source

a few code style fixes

Natenom/support-murmur-13-1446181288462
Michael Ziegler 14 years ago
parent
commit
5a6747c83a
  1. 295
      muco.py
  2. 2
      mumble-django.wsgi
  3. 23
      munin.py
  4. 2
      pyweb/manage.py
  5. 1
      pyweb/mucli.py
  6. 133
      pyweb/mumble/MumbleCtlDbus.py
  7. 181
      pyweb/mumble/MumbleCtlIce.py
  8. 1
      pyweb/mumble/__init__.py
  9. 51
      pyweb/mumble/admin.py
  10. 111
      pyweb/mumble/forms.py
  11. 5
      pyweb/mumble/management/__init__.py
  12. 1
      pyweb/mumble/management/commands/__init__.py
  13. 77
      pyweb/mumble/management/commands/checkenv.py
  14. 1
      pyweb/mumble/management/commands/getslice.py
  15. 1
      pyweb/mumble/management/commands/mmrunserver.py
  16. 1
      pyweb/mumble/management/commands/mmshell.py
  17. 1
      pyweb/mumble/management/commands/mmsyncdb.py
  18. 77
      pyweb/mumble/management/server_detect.py
  19. 5
      pyweb/mumble/management/update_schema.py
  20. 13
      pyweb/mumble/mctl.py
  21. 183
      pyweb/mumble/mmobjects.py
  22. 323
      pyweb/mumble/models.py
  23. 115
      pyweb/mumble/murmurenvutils.py
  24. 15
      pyweb/mumble/templatetags/mumble_extras.py
  25. 55
      pyweb/mumble/testrunner.py
  26. 173
      pyweb/mumble/tests.py
  27. 1
      pyweb/mumble/urls.py
  28. 13
      pyweb/mumble/utils.py
  29. 208
      pyweb/mumble/views.py
  30. 1
      pyweb/processors.py
  31. 13
      pyweb/settings.py
  32. 1
      pyweb/urls.py
  33. 7
      pyweb/views.py

295
muco.py

@ -1,5 +1,6 @@
#!/usr/bin/python
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# kate: space-indent on; indent-width 4; replace-tabs on;
"""
* Copyright (C) 2009, Michael "Svedrin" Ziegler <diese-addy@funzt-halt.net>
@ -16,7 +17,7 @@
"""
# Set this to the same path you used in settings.py, or None for auto-detection.
MUMBLE_DJANGO_ROOT = None;
MUMBLE_DJANGO_ROOT = None
### DO NOT CHANGE ANYTHING BELOW THIS LINE ###
@ -25,7 +26,7 @@ from os.path import join, dirname, abspath, exists
# Path auto-detection
if not MUMBLE_DJANGO_ROOT or not exists( MUMBLE_DJANGO_ROOT ):
MUMBLE_DJANGO_ROOT = dirname(abspath(__file__));
MUMBLE_DJANGO_ROOT = dirname(abspath(__file__))
# environment variables
sys.path.append( MUMBLE_DJANGO_ROOT )
@ -54,314 +55,298 @@ locale.setlocale(locale.LC_ALL, '')
class BaseWindow( object ):
tabName = "tehBasez";
tabName = "tehBasez"
def __init__( self, parentwin, mumble, pos_x, pos_y ):
self.pos = ( pos_x, pos_y );
self.win = parentwin.subwin( pos_y, pos_x );
self.mm = mumble;
self.pos = ( pos_x, pos_y )
self.win = parentwin.subwin( pos_y, pos_x )
self.mm = mumble
self.win.keypad(1);
self.win.keypad(1)
def draw( self ):
self.win.addstr( 1, 1, self.tabName );
self.win.addstr( 1, 1, self.tabName )
def border( self ):
self.win.border();
self.win.border()
def enter( self ):
while( True ):
key = self.win.getch();
key = self.win.getch()
if key == curses.KEY_UP:
return;
return
class WndChannels( BaseWindow ):
tabName = 'Channels';
tabName = 'Channels'
def printItem( self, item, level ):
namestr = "";
namestr = ""
if item.is_server or item.is_channel:
namestr = "%s (Channel)" % item.name;
namestr = "%s (Channel)" % item.name
else:
namestr = "%s (Player)" % item.name
self.win.addstr( self.curr_y, 4*level+1, namestr.encode(locale.getpreferredencoding()) )
self.curr_y += 1;
self.curr_y += 1
def draw( self ):
self.curr_y = 1;
self.mm.rootchan.visit( self.printItem );
self.curr_y = 1
self.mm.rootchan.visit( self.printItem )
class WndSettings( BaseWindow ):
tabName = 'Server settings';
tabName = 'Server settings'
blacklist = ( 'id', 'sslkey', 'sslcrt' );
blacklist = ( 'id', 'sslkey', 'sslcrt' )
def __init__( self, parentwin, mumble, pos_x, pos_y ):
BaseWindow.__init__( self, parentwin, mumble, pos_x, pos_y );
self.form = MumbleAdminForm( instance=mumble );
BaseWindow.__init__( self, parentwin, mumble, pos_x, pos_y )
self.form = MumbleAdminForm( instance=mumble )
self.editors = {};
self.fields = [ mf for mf in mumble._meta.fields if mf.name not in self.blacklist ];
self.editors = {}
self.fields = [ mf for mf in mumble._meta.fields if mf.name not in self.blacklist ]
def getFieldHeight( self, field ):
if isinstance( field, models.TextField ):
return 10;
return 1;
return 10
return 1
def getFieldYPos( self, field ):
ypos = 3;
ypos = 3
for curr_field in self.fields:
if curr_field is field:
return ypos;
ypos += self.getFieldHeight( curr_field );
raise ReferenceError( "Field not found!" );
return ypos
ypos += self.getFieldHeight( curr_field )
raise ReferenceError( "Field not found!" )
def draw( self ):
curr_y = 3;
curr_y = 3
for field in self.fields:
value = unicode( getattr( self.mm, field.name ) );
value = unicode( getattr( self.mm, field.name ) )
self.win.addstr( curr_y, 1, field.verbose_name.encode(locale.getpreferredencoding()) );
self.win.addstr( curr_y, 1, field.verbose_name.encode(locale.getpreferredencoding()) )
height = self.getFieldHeight( field );
winsize = self.win.getmaxyx();
height = self.getFieldHeight( field )
winsize = self.win.getmaxyx()
editwin = self.win.subwin( height, winsize[1]-31, self.pos[1] + curr_y, self.pos[0] + 30 );
editwin.keypad(1);
editwin.addstr( value.encode(locale.getpreferredencoding()) );
editbox = Textbox( editwin );
editwin = self.win.subwin( height, winsize[1]-31, self.pos[1] + curr_y, self.pos[0] + 30 )
editwin.keypad(1)
editwin.addstr( value.encode(locale.getpreferredencoding()) )
editbox = Textbox( editwin )
self.editors[field.name] = ( editwin, editbox );
self.editors[field.name] = ( editwin, editbox )
curr_y += height;
curr_y += height
def enter( self ):
self.selIdx = 0;
self.selMax = len( self.fields ) - 1;
self.selIdx = 0
self.selMax = len( self.fields ) - 1
while( True ):
# Highlight selected field label
field = self.fields[self.selIdx];
field = self.fields[self.selIdx]
self.win.addstr(
self.getFieldYPos(field), 1,
field.verbose_name.encode(locale.getpreferredencoding()),
curses.A_STANDOUT
);
self.win.refresh();
)
self.win.refresh()
key = self.win.getch();
key = self.win.getch()
if key == curses.KEY_UP:
if self.selIdx > 0:
self.selIdx -= 1;
self.selIdx -= 1
else:
return;
return
elif key == curses.KEY_DOWN and self.selIdx < self.selMax:
self.selIdx += 1;
self.selIdx += 1
elif key in ( ord('q'), ord('Q') ):
return;
return
elif key in ( ord('s'), ord('S') ):
try:
self.mm.save();
self.mm.save()
except Exception, instance:
msg = unicode( instance );
msg = unicode( instance )
else:
msg = "Your settings have been saved.";
self.win.addstr( 1, 5, msg.encode(locale.getpreferredencoding()) );
msg = "Your settings have been saved."
self.win.addstr( 1, 5, msg.encode(locale.getpreferredencoding()) )
elif key in ( curses.KEY_RIGHT, curses.KEY_ENTER, ord('\n') ):
valid = False;
valid = False
while not valid:
self.editors[field.name][1].edit();
self.editors[field.name][1].edit()
try:
setattr( self.mm, field.name,
field.to_python( self.editors[field.name][1].gather().strip() )
);
)
except ValidationError, instance:
msg = unicode( instance );
self.win.addstr( 1, 5, msg.encode(locale.getpreferredencoding()), curses.A_STANDOUT );
self.win.refresh();
msg = unicode( instance )
self.win.addstr( 1, 5, msg.encode(locale.getpreferredencoding()), curses.A_STANDOUT )
self.win.refresh()
else:
valid = True;
self.win.move( 1, 5 );
self.win.clrtoeol();
valid = True
self.win.move( 1, 5 )
self.win.clrtoeol()
self.editors[field.name][0].refresh();
self.editors[field.name][0].refresh()
self.win.addstr(
self.getFieldYPos(field), 1,
field.verbose_name.encode(locale.getpreferredencoding())
);
)
class WndUsers( BaseWindow ):
tabName = 'Registered users';
tabName = 'Registered users'
def draw( self ):
curr_y = 3;
curr_y = 3
for acc in self.mm.mumbleuser_set.all():
self.win.addstr( curr_y, 1, acc.name.encode(locale.getpreferredencoding()) );
curr_y += 1;
self.win.addstr( curr_y, 1, acc.name.encode(locale.getpreferredencoding()) )
curr_y += 1
class MumbleForm( object ):
def __init__( self, parentwin, mumble, pos_x, pos_y ):
self.pos = ( pos_x, pos_y );
self.win = parentwin.subwin( pos_y, pos_x );
self.mm = mumble;
self.pos = ( pos_x, pos_y )
self.win = parentwin.subwin( pos_y, pos_x )
self.mm = mumble
self.win.keypad(1);
self.win.keypad(1)
self.windows = (
WndChannels( self.win, mumble, pos_x + 2, pos_y + 2 ),
WndSettings( self.win, mumble, pos_x + 2, pos_y + 2 ),
WndUsers( self.win, mumble, pos_x + 2, pos_y + 2 ),
);
)
self.curridx = 0;
self.currmax = len( self.windows ) - 1;
self.curridx = 0
self.currmax = len( self.windows ) - 1
currwin = property( lambda self: self.windows[self.curridx], None );
currwin = property( lambda self: self.windows[self.curridx], None )
def mvwin( self, pos_x, pos_y ):
self.win.mvwin( pos_y, pos_x );
self.win.mvwin( pos_y, pos_x )
def mvdefault( self ):
self.win.mvwin( self.pos[1], self.pos[0] );
self.win.mvwin( self.pos[1], self.pos[0] )
def draw( self ):
self.win.addstr( 0, 0, self.mm.name.encode(locale.getpreferredencoding()) );
self.win.addstr( 0, 0, self.mm.name.encode(locale.getpreferredencoding()) )
def drawTabs( self ):
first = True;
first = True
for subwin in self.windows:
flags = 0;
if subwin is self.currwin: flags |= curses.A_STANDOUT;
flags = 0
if subwin is self.currwin: flags |= curses.A_STANDOUT
if first:
self.win.addstr( 1, 2, "%-20s" % subwin.tabName, flags );
first = False;
self.win.addstr( 1, 2, "%-20s" % subwin.tabName, flags )
first = False
else:
self.win.addstr( "%-20s" % subwin.tabName, flags );
self.win.addstr( "%-20s" % subwin.tabName, flags )
def enter( self ):
self.drawTabs();
self.currwin.draw();
self.currwin.border();
self.drawTabs()
self.currwin.draw()
self.currwin.border()
while( True ):
key = self.win.getch();
key = self.win.getch()
if key == curses.KEY_LEFT and self.curridx > 0:
self.curridx -= 1;
self.curridx -= 1
elif key == curses.KEY_RIGHT and self.curridx < self.currmax:
self.curridx += 1;
self.curridx += 1
elif key in ( ord('q'), ord('Q'), curses.KEY_UP ):
return;
return
elif key in ( curses.KEY_ENTER, curses.KEY_DOWN, ord('\n') ):
self.currwin.enter();
self.currwin.enter()
self.win.clear();
self.draw();
self.drawTabs();
self.currwin.draw();
self.currwin.border();
self.win.refresh();
self.win.clear()
self.draw()
self.drawTabs()
self.currwin.draw()
self.currwin.border()
self.win.refresh()
def main( stdscr ):
first_y = 3;
curr_y = first_y;
first_y = 3
curr_y = first_y
mumbles = list();
mumbles = list()
for mm in Mumble.objects.all().order_by( "name", "id" ):
mwin = MumbleForm( stdscr, mm, pos_x=5, pos_y=curr_y );
mumbles.append( mwin );
mwin.draw();
curr_y += 1;
mwin = MumbleForm( stdscr, mm, pos_x=5, pos_y=curr_y )
mumbles.append( mwin )
mwin.draw()
curr_y += 1
selectedIdx = 0;
selectedMax = len(mumbles) - 1;
selectedIdx = 0
selectedMax = len(mumbles) - 1
myname = "Mumble Commander";
myname = "Mumble Commander"
while( True ):
selectedObj = mumbles[selectedIdx];
selectedObj = mumbles[selectedIdx]
maxyx = stdscr.getmaxyx();
stdscr.addstr( 0, maxyx[1] / 2 - len(myname)/2, myname, curses.A_UNDERLINE );
maxyx = stdscr.getmaxyx()
stdscr.addstr( 0, maxyx[1] / 2 - len(myname)/2, myname, curses.A_UNDERLINE )
# Draw selection marker
stdscr.addstr( first_y + selectedIdx, 3, '*' );
stdscr.refresh();
stdscr.addstr( first_y + selectedIdx, 3, '*' )
stdscr.refresh()
key = stdscr.getch();
key = stdscr.getch()
if key == curses.KEY_UP:
stdscr.addstr( first_y + selectedIdx, 3, ' ' );
selectedIdx -= 1;
stdscr.addstr( first_y + selectedIdx, 3, ' ' )
selectedIdx -= 1
elif key == curses.KEY_DOWN:
stdscr.addstr( first_y + selectedIdx, 3, ' ' );
selectedIdx += 1;
stdscr.addstr( first_y + selectedIdx, 3, ' ' )
selectedIdx += 1
elif key in ( curses.KEY_RIGHT, curses.KEY_ENTER, ord('\n') ):
stdscr.clear();
stdscr.addstr( 0, maxyx[1] / 2 - len(myname)/2, myname, curses.A_UNDERLINE );
selectedObj.mvwin( 5, first_y );
selectedObj.draw();
stdscr.refresh();
stdscr.clear()
stdscr.addstr( 0, maxyx[1] / 2 - len(myname)/2, myname, curses.A_UNDERLINE )
selectedObj.mvwin( 5, first_y )
selectedObj.draw()
stdscr.refresh()
selectedObj.enter();
selectedObj.enter()
stdscr.clear();
selectedObj.mvdefault();
stdscr.clear()
selectedObj.mvdefault()
for mwin in mumbles:
mwin.draw();
mwin.draw()
elif key in ( ord('q'), ord('Q') ):
return;
if selectedIdx < 0: selectedIdx = 0;
elif selectedIdx > selectedMax: selectedIdx = selectedMax;
return
if selectedIdx < 0: selectedIdx = 0
elif selectedIdx > selectedMax: selectedIdx = selectedMax
if __name__ == '__main__':
#parser = OptionParser();
#parser.add_option( "-v", "--verbose", help="verbose output messages", default=False, action="store_true" );
#parser.add_option( "-n", "--num", help="size of the Matrix", default=4, type = 'int' );
#parser.add_option( "-s", "--sure", help="don't prompt if num >= 10", default=False, action="store_true" );
#options, args = parser.parse_args();
curses.wrapper( main );
#parser = OptionParser()
#parser.add_option( "-v", "--verbose", help="verbose output messages", default=False, action="store_true" )
#parser.add_option( "-n", "--num", help="size of the Matrix", default=4, type = 'int' )
#parser.add_option( "-s", "--sure", help="don't prompt if num >= 10", default=False, action="store_true" )
#options, args = parser.parse_args()
curses.wrapper( main )

2
mumble-django.wsgi

@ -9,7 +9,7 @@ from os.path import join, dirname, abspath, exists
# Path auto-detection
if not MUMBLE_DJANGO_ROOT or not exists( MUMBLE_DJANGO_ROOT ):
MUMBLE_DJANGO_ROOT = dirname(abspath(__file__));
MUMBLE_DJANGO_ROOT = dirname(abspath(__file__))
# environment variables
sys.path.append( MUMBLE_DJANGO_ROOT )

23
munin.py

@ -1,5 +1,6 @@
#!/usr/bin/python
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# kate: space-indent on; indent-width 4; replace-tabs on;
"""
* Copyright (C) 2009, Michael "Svedrin" Ziegler <diese-addy@funzt-halt.net>
@ -16,7 +17,7 @@
"""
# Set this to the same path you used in settings.py, or None for auto-detection.
MUMBLE_DJANGO_ROOT = None;
MUMBLE_DJANGO_ROOT = None
### DO NOT CHANGE ANYTHING BELOW THIS LINE ###
@ -25,7 +26,7 @@ from os.path import join, dirname, abspath, exists
# Path auto-detection
if not MUMBLE_DJANGO_ROOT or not exists( MUMBLE_DJANGO_ROOT ):
MUMBLE_DJANGO_ROOT = dirname(abspath(__file__));
MUMBLE_DJANGO_ROOT = dirname(abspath(__file__))
# environment variables
sys.path.append( MUMBLE_DJANGO_ROOT )
@ -67,29 +68,29 @@ if sys.argv[-1] == 'config':
print "graph_category", categ
for mumble in get_running_instances():
print "srv%d.label %s" % ( mumble.id, mumble.name.replace('#', '').encode(prefenc, "replace") );
print "srv%d.label %s" % ( mumble.id, mumble.name.replace('#', '').encode(prefenc, "replace") )
if mumble.connecturl:
print "srv%d.info %s" % ( mumble.id, mumble.connecturl );
print "srv%d.info %s" % ( mumble.id, mumble.connecturl )
if mumble.users:
print "srv%d.warning %d" % ( mumble.id, int( mumble.users * warn ) );
print "srv%d.critical %d" % ( mumble.id, int( mumble.users * crit ) );
print "srv%d.warning %d" % ( mumble.id, int( mumble.users * warn ) )
print "srv%d.critical %d" % ( mumble.id, int( mumble.users * crit ) )
elif sys.argv[-1] == 'autoconf':
if Mumble.objects.count() == 0:
print "no (no servers configured)";
print "no (no servers configured)"
else:
# check if connecting works
try:
for mumble in get_running_instances():
mumble.ctl
except Exception, instance:
print "no (can't connect to server %s: %s)" % ( mumble.name, instance );
print "no (can't connect to server %s: %s)" % ( mumble.name, instance )
else:
print "yes";
print "yes"
else:
for mumble in get_running_instances():
print "srv%d.value %d" % ( mumble.id, len( mumble.ctl.getPlayers( mumble.srvid ) ) );
print "srv%d.value %d" % ( mumble.id, len( mumble.ctl.getPlayers( mumble.srvid ) ) )

2
pyweb/manage.py

@ -1,4 +1,4 @@
#!/usr/bin/python
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""

1
pyweb/mucli.py

@ -1,5 +1,6 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# kate: space-indent on; indent-width 4; replace-tabs on;
"""
* Copyright (C) 2010, Michael "Svedrin" Ziegler <diese-addy@funzt-halt.net>

133
pyweb/mumble/MumbleCtlDbus.py

@ -1,4 +1,5 @@
# -*- coding: utf-8 -*-
# kate: space-indent on; indent-width 4; replace-tabs on;
"""
* Copyright © 2009, withgod <withgod@sourceforge.net>
@ -29,77 +30,77 @@ from dbus.exceptions import DBusException
def MumbleCtlDbus( connstring ):
""" Choose the correct DBus handler (1.1.8 or legacy) to use. """
meta = dbus.Interface( dbus.SystemBus().get_object( connstring, '/' ), 'net.sourceforge.mumble.Meta' );
meta = dbus.Interface( dbus.SystemBus().get_object( connstring, '/' ), 'net.sourceforge.mumble.Meta' )
try:
meta.getVersion();
meta.getVersion()
except DBusException:
return MumbleCtlDbus_Legacy( connstring, meta );
return MumbleCtlDbus_Legacy( connstring, meta )
else:
return MumbleCtlDbus_118( connstring, meta );
return MumbleCtlDbus_118( connstring, meta )
class MumbleCtlDbus_118(MumbleCtlBase):
method = "DBus";
method = "DBus"
def __init__( self, connstring, meta ):
self.dbus_base = connstring;
self.meta = meta;
self.dbus_base = connstring
self.meta = meta
def _getDbusMeta( self ):
return self.meta;
return self.meta
def _getDbusServerObject( self, srvid):
if srvid not in self.getBootedServers():
raise SystemError, 'No murmur process with the given server ID (%d) is running and attached to system dbus under %s.' % ( srvid, self.meta );
raise SystemError, 'No murmur process with the given server ID (%d) is running and attached to system dbus under %s.' % ( srvid, self.meta )
return dbus.Interface( dbus.SystemBus().get_object( self.dbus_base, '/%d' % srvid ), 'net.sourceforge.mumble.Murmur' );
return dbus.Interface( dbus.SystemBus().get_object( self.dbus_base, '/%d' % srvid ), 'net.sourceforge.mumble.Murmur' )
def getVersion( self ):
return MumbleCtlDbus_118.convertDbusTypeToNative( self.meta.getVersion() );
return MumbleCtlDbus_118.convertDbusTypeToNative( self.meta.getVersion() )
def getAllConf(self, srvid):
conf = self.meta.getAllConf(dbus.Int32(srvid))
info = {};
info = {}
for key in conf:
if key == "playername":
info['username'] = conf[key];
info['username'] = conf[key]
else:
info[str(key)] = conf[key];
return info;
info[str(key)] = conf[key]
return info
def getConf(self, srvid, key):
if key == "username":
key = "playername";
key = "playername"
return self.meta.getConf(dbus.Int32( srvid ), key)
def setConf(self, srvid, key, value):
if key == "username":
key = "playername";
key = "playername"
self.meta.setConf(dbus.Int32( srvid ), key, value)
def getDefaultConf(self):
conf = self.meta.getDefaultConf()
info = {};
info = {}
for key in conf:
if key == "playername":
info['username'] = conf[key];
info['username'] = conf[key]
else:
info[str(key)] = conf[key];
return info;
info[str(key)] = conf[key]
return info
def start( self, srvid ):
self.meta.start( srvid );
self.meta.start( srvid )
def stop( self, srvid ):
self.meta.stop( srvid );
self.meta.stop( srvid )
def isBooted( self, srvid ):
return bool( self.meta.isBooted( srvid ) );
return bool( self.meta.isBooted( srvid ) )
def deleteServer( self, srvid ):
srvid = dbus.Int32( srvid )
@ -112,9 +113,9 @@ class MumbleCtlDbus_118(MumbleCtlBase):
return self.meta.newServer()
def registerPlayer(self, srvid, name, email, password):
mumbleid = int( self._getDbusServerObject(srvid).registerPlayer(name) );
self.setRegistration( srvid, mumbleid, name, email, password );
return mumbleid;
mumbleid = int( self._getDbusServerObject(srvid).registerPlayer(name) )
self.setRegistration( srvid, mumbleid, name, email, password )
return mumbleid
def unregisterPlayer(self, srvid, mumbleid):
self._getDbusServerObject(srvid).unregisterPlayer(dbus.Int32( mumbleid ))
@ -122,23 +123,23 @@ class MumbleCtlDbus_118(MumbleCtlBase):
def getChannels(self, srvid):
chans = self._getDbusServerObject(srvid).getChannels()
ret = {};
ret = {}
for channel in chans:
print channel;
print channel
ret[ channel[0] ] = ObjectInfo(
id = int(channel[0]),
name = unicode(channel[1]),
parent = int(channel[2]),
links = [ int(lnk) for lnk in channel[3] ],
);
)
return ret;
return ret
def getPlayers(self, srvid):
players = self._getDbusServerObject(srvid).getPlayers();
players = self._getDbusServerObject(srvid).getPlayers()
ret = {};
ret = {}
for playerObj in players:
ret[ int(playerObj[0]) ] = ObjectInfo(
@ -153,13 +154,13 @@ class MumbleCtlDbus_118(MumbleCtlBase):
name = unicode( playerObj[8] ),
onlinesecs = int( playerObj[9] ),
bytespersec = int( playerObj[10] )
);
)
return ret;
return ret
def getRegisteredPlayers(self, srvid, filter = ''):
users = self._getDbusServerObject(srvid).getRegisteredPlayers( filter );
ret = {};
users = self._getDbusServerObject(srvid).getRegisteredPlayers( filter )
ret = {}
for user in users:
ret[int(user[0])] = ObjectInfo(
@ -167,7 +168,7 @@ class MumbleCtlDbus_118(MumbleCtlBase):
name = unicode( user[1] ),
email = unicode( user[2] ),
pw = unicode( user[3] )
);
)
return ret
@ -184,7 +185,7 @@ class MumbleCtlDbus_118(MumbleCtlBase):
deny = int(rule[6]),
)
for rule in raw_acls
];
]
groups = [ ObjectInfo(
name = unicode(group[0]),
@ -196,23 +197,23 @@ class MumbleCtlDbus_118(MumbleCtlBase):
members = [ int(usrid) for usrid in group[6] ],
)
for group in raw_groups
];
]
return acls, groups, bool(raw_inherit);
return acls, groups, bool(raw_inherit)
def setACL(self, srvid, channelid, acls, groups, inherit):
# Pack acl ObjectInfo into a tuple and send that over dbus
dbus_acls = [
( rule.applyHere, rule.applySubs, rule.inherited, rule.userid, rule.group, rule.allow, rule.deny )
for rule in acls
];
]
dbus_groups = [
( group.name, group.inherited, group.inherit, group.inheritable, group.add, group.remove, group.members )
for group in groups
];
]
return self._getDbusServerObject(srvid).setACL( channelid, dbus_acls, dbus_groups, inherit );
return self._getDbusServerObject(srvid).setACL( channelid, dbus_acls, dbus_groups, inherit )
def getBootedServers(self):
return MumbleCtlDbus_118.convertDbusTypeToNative(self.meta.getBootedServers())
@ -230,7 +231,7 @@ class MumbleCtlDbus_118(MumbleCtlBase):
name = unicode(user[1]),
email = unicode(user[2]),
pw = '',
);
)
def setRegistration(self, srvid, mumbleid, name, email, password):
return MumbleCtlDbus_118.convertDbusTypeToNative(
@ -238,58 +239,58 @@ class MumbleCtlDbus_118(MumbleCtlBase):
)
def getTexture(self, srvid, mumbleid):
texture = self._getDbusServerObject(srvid).getTexture(dbus.Int32(mumbleid));
texture = self._getDbusServerObject(srvid).getTexture(dbus.Int32(mumbleid))
if len(texture) == 0:
raise ValueError( "No Texture has been set." );
raise ValueError( "No Texture has been set." )
# this returns a list of bytes.
# first 4 bytes: Length of uncompressed string, rest: compressed data
orig_len = ( texture[0] << 24 ) | ( texture[1] << 16 ) | ( texture[2] << 8 ) | ( texture[3] );
orig_len = ( texture[0] << 24 ) | ( texture[1] << 16 ) | ( texture[2] << 8 ) | ( texture[3] )
# convert rest to string and run decompress
bytestr = "";
bytestr = ""
for byte in texture[4:]:
bytestr += pack( "B", int(byte) );
decompressed = decompress( bytestr );
bytestr += pack( "B", int(byte) )
decompressed = decompress( bytestr )
# iterate over 4 byte chunks of the string
imgdata = "";
imgdata = ""
for idx in range( 0, orig_len, 4 ):
# read 4 bytes = BGRA and convert to RGBA
bgra = unpack( "4B", decompressed[idx:idx+4] );
imgdata += pack( "4B", bgra[2], bgra[1], bgra[0], bgra[3] );
bgra = unpack( "4B", decompressed[idx:idx+4] )
imgdata += pack( "4B", bgra[2], bgra[1], bgra[0], bgra[3] )
# return an 600x60 RGBA image object created from the data
return Image.fromstring( "RGBA", ( 600, 60 ), imgdata);
return Image.fromstring( "RGBA", ( 600, 60 ), imgdata)
def setTexture(self, srvid, mumbleid, infile):
# open image, convert to RGBA, and resize to 600x60
img = infile.convert( "RGBA" ).transform( ( 600, 60 ), Image.EXTENT, ( 0, 0, 600, 60 ) );
img = infile.convert( "RGBA" ).transform( ( 600, 60 ), Image.EXTENT, ( 0, 0, 600, 60 ) )
# iterate over the list and pack everything into a string
bgrastring = "";
bgrastring = ""
for ent in list( img.getdata() ):
# ent is in RGBA format, but Murmur wants BGRA (ARGB inverse), so stuff needs
# to be reordered when passed to pack()
bgrastring += pack( "4B", ent[2], ent[1], ent[0], ent[3] );
bgrastring += pack( "4B", ent[2], ent[1], ent[0], ent[3] )
# compress using zlib
compressed = compress( bgrastring );
compressed = compress( bgrastring )
# pack the original length in 4 byte big endian, and concat the compressed
# data to it to emulate qCompress().
texture = pack( ">L", len(bgrastring) ) + compressed;
texture = pack( ">L", len(bgrastring) ) + compressed
# finally call murmur and set the texture
self._getDbusServerObject(srvid).setTexture(dbus.Int32( mumbleid ), texture)
def verifyPassword( self, srvid, username, password ):
player = self.getRegisteredPlayers( srvid, username );
player = self.getRegisteredPlayers( srvid, username )
if not player:
return -2;
return -2
ok = MumbleCtlDbus_118.convertDbusTypeToNative(
self._getDbusServerObject(srvid).verifyPassword( dbus.Int32( player[0].userid ), password )
);
)
if ok:
return player[0].userid;
return player[0].userid
else:
return -1;
return -1
@staticmethod
def convertDbusTypeToNative(data):
@ -319,7 +320,7 @@ class MumbleCtlDbus_118(MumbleCtlBase):
class MumbleCtlDbus_Legacy( MumbleCtlDbus_118 ):
def getVersion( self ):
return ( 1, 1, 4, u"1.1.4" );
return ( 1, 1, 4, u"1.1.4" )
def setRegistration(self, srvid, mumbleid, name, email, password):
return MumbleCtlDbus_118.convertDbusTypeToNative(

181
pyweb/mumble/MumbleCtlIce.py

@ -1,4 +1,5 @@
# -*- coding: utf-8 -*-
# kate: space-indent on; indent-width 4; replace-tabs on;
"""
* Copyright © 2009, withgod <withgod@sourceforge.net>
@ -54,12 +55,12 @@ def protectDjangoErrPage( func ):
def protection_wrapper( self, *args, **kwargs ):
""" Call the original function and catch Ice exceptions. """
try:
return func( self, *args, **kwargs );
return func( self, *args, **kwargs )
except Ice.Exception, err:
raise err;
raise err
protection_wrapper.innerfunc = func
return protection_wrapper;
return protection_wrapper
@protectDjangoErrPage
@ -152,31 +153,31 @@ def MumbleCtlIce( connstring, slicefile=None, icesecret=None ):
murmurversion = meta.getVersion()[:3]
if murmurversion == (1, 1, 8):
return MumbleCtlIce_118( connstring, meta );
return MumbleCtlIce_118( connstring, meta )
elif murmurversion[:2] == (1, 2):
if murmurversion[2] < 2:
return MumbleCtlIce_120( connstring, meta );
return MumbleCtlIce_120( connstring, meta )
elif murmurversion[2] == 2:
return MumbleCtlIce_122( connstring, meta );
return MumbleCtlIce_122( connstring, meta )
elif murmurversion[2] == 3:
return MumbleCtlIce_123( connstring, meta );
return MumbleCtlIce_123( connstring, meta )
raise NotImplementedError( "No ctl object available for Murmur version %d.%d.%d" % tuple(murmurversion) )
class MumbleCtlIce_118(MumbleCtlBase):
method = "ICE";
method = "ICE"
def __init__( self, connstring, meta ):
self.proxy = connstring;
self.meta = meta;
self.proxy = connstring
self.meta = meta
@protectDjangoErrPage
def _getIceServerObject(self, srvid):
return self.meta.getServer(srvid);
return self.meta.getServer(srvid)
@protectDjangoErrPage
def getBootedServers(self):
@ -187,7 +188,7 @@ class MumbleCtlIce_118(MumbleCtlBase):
@protectDjangoErrPage
def getVersion( self ):
return self.meta.getVersion();
return self.meta.getVersion()
@protectDjangoErrPage
def getAllServers(self):
@ -199,7 +200,7 @@ class MumbleCtlIce_118(MumbleCtlBase):
@protectDjangoErrPage
def getRegisteredPlayers(self, srvid, filter = ''):
users = self._getIceServerObject(srvid).getRegisteredPlayers( filter.encode( "UTF-8" ) )
ret = {};
ret = {}
for user in users:
ret[user.playerid] = ObjectInfo(
@ -207,22 +208,22 @@ class MumbleCtlIce_118(MumbleCtlBase):
name = unicode( user.name, "utf8" ),
email = unicode( user.email, "utf8" ),
pw = unicode( user.pw, "utf8" )
);
)
return ret
@protectDjangoErrPage
def getChannels(self, srvid):
return self._getIceServerObject(srvid).getChannels();
return self._getIceServerObject(srvid).getChannels()
@protectDjangoErrPage
def getPlayers(self, srvid):
users = self._getIceServerObject(srvid).getPlayers()
ret = {};
ret = {}
for useridx in users:
user = users[useridx];
user = users[useridx]
ret[ user.session ] = ObjectInfo(
session = user.session,
userid = user.playerid,
@ -235,9 +236,9 @@ class MumbleCtlIce_118(MumbleCtlBase):
name = user.name,
onlinesecs = user.onlinesecs,
bytespersec = user.bytespersec
);
)
return ret;
return ret
@protectDjangoErrPage
def getDefaultConf(self):
@ -247,13 +248,13 @@ class MumbleCtlIce_118(MumbleCtlBase):
def getAllConf(self, srvid):
conf = self.setUnicodeFlag(self._getIceServerObject(srvid).getAllConf())
info = {};
info = {}
for key in conf:
if key == "playername":
info['username'] = conf[key];
info['username'] = conf[key]
else:
info[str(key)] = conf[key];
return info;
info[str(key)] = conf[key]
return info
@protectDjangoErrPage
def newServer(self):
@ -261,15 +262,15 @@ class MumbleCtlIce_118(MumbleCtlBase):
@protectDjangoErrPage
def isBooted( self, srvid ):
return bool( self._getIceServerObject(srvid).isRunning() );
return bool( self._getIceServerObject(srvid).isRunning() )
@protectDjangoErrPage
def start( self, srvid ):
self._getIceServerObject(srvid).start();
self._getIceServerObject(srvid).start()
@protectDjangoErrPage
def stop( self, srvid ):
self._getIceServerObject(srvid).stop();
self._getIceServerObject(srvid).stop()
@protectDjangoErrPage
def deleteServer( self, srvid ):
@ -284,14 +285,14 @@ class MumbleCtlIce_118(MumbleCtlBase):
@protectDjangoErrPage
def getConf(self, srvid, key):
if key == "username":
key = "playername";
key = "playername"
return self._getIceServerObject(srvid).getConf( key )
@protectDjangoErrPage
def setConf(self, srvid, key, value):
if key == "username":
key = "playername";
key = "playername"
if value is None:
value = ''
self._getIceServerObject(srvid).setConf( key, value.encode( "UTF-8" ) )
@ -299,8 +300,8 @@ class MumbleCtlIce_118(MumbleCtlBase):
@protectDjangoErrPage
def registerPlayer(self, srvid, name, email, password):
mumbleid = self._getIceServerObject(srvid).registerPlayer( name.encode( "UTF-8" ) )
self.setRegistration( srvid, mumbleid, name, email, password );
return mumbleid;
self.setRegistration( srvid, mumbleid, name, email, password )
return mumbleid
@protectDjangoErrPage
def unregisterPlayer(self, srvid, mumbleid):
@ -314,13 +315,13 @@ class MumbleCtlIce_118(MumbleCtlBase):
name = user.name,
email = user.email,
pw = '',
);
)
@protectDjangoErrPage
def setRegistration(self, srvid, mumbleid, name, email, password):
import Murmur
user = Murmur.Player()
user.playerid = mumbleid;
user.playerid = mumbleid
user.name = name.encode( "UTF-8" )
user.email = email.encode( "UTF-8" )
user.pw = password.encode( "UTF-8" )
@ -342,73 +343,73 @@ class MumbleCtlIce_118(MumbleCtlBase):
deny = rule.deny,
)
for rule in raw_acls
];
]
return acls, raw_groups, raw_inherit;
return acls, raw_groups, raw_inherit
@protectDjangoErrPage
def setACL(self, srvid, channelid, acls, groups, inherit):
import Murmur
ice_acls = [];
ice_acls = []
for rule in acls:
ice_rule = Murmur.ACL();
ice_rule.applyHere = rule.applyHere;
ice_rule.applySubs = rule.applySubs;
ice_rule.inherited = rule.inherited;
ice_rule.playerid = rule.userid;
ice_rule.group = rule.group;
ice_rule.allow = rule.allow;
ice_rule.deny = rule.deny;
ice_acls.append(ice_rule);
ice_rule = Murmur.ACL()
ice_rule.applyHere = rule.applyHere
ice_rule.applySubs = rule.applySubs
ice_rule.inherited = rule.inherited
ice_rule.playerid = rule.userid
ice_rule.group = rule.group
ice_rule.allow = rule.allow
ice_rule.deny = rule.deny
ice_acls.append(ice_rule)
return self._getIceServerObject(srvid).setACL( channelid, ice_acls, groups, inherit );
return self._getIceServerObject(srvid).setACL( channelid, ice_acls, groups, inherit )
@protectDjangoErrPage
def getTexture(self, srvid, mumbleid):
texture = self._getIceServerObject(srvid).getTexture(mumbleid)
if len(texture) == 0:
raise ValueError( "No Texture has been set." );
raise ValueError( "No Texture has been set." )
# this returns a list of bytes.
try:
decompressed = decompress( texture );
decompressed = decompress( texture )
except error, err:
raise ValueError( err )
# iterate over 4 byte chunks of the string
imgdata = "";
imgdata = ""
for idx in range( 0, len(decompressed), 4 ):
# read 4 bytes = BGRA and convert to RGBA
# manual wrote getTexture returns "Textures are stored as zlib compress()ed 600x60 32-bit RGBA data."
# http://mumble.sourceforge.net/slice/Murmur/Server.html#getTexture
# but return values BGRA X(
bgra = unpack( "4B", decompressed[idx:idx+4] );
imgdata += pack( "4B", bgra[2], bgra[1], bgra[0], bgra[3] );
bgra = unpack( "4B", decompressed[idx:idx+4] )
imgdata += pack( "4B", bgra[2], bgra[1], bgra[0], bgra[3] )
# return an 600x60 RGBA image object created from the data
return Image.fromstring( "RGBA", ( 600, 60 ), imgdata );
return Image.fromstring( "RGBA", ( 600, 60 ), imgdata )
@protectDjangoErrPage
def setTexture(self, srvid, mumbleid, infile):
# open image, convert to RGBA, and resize to 600x60
img = infile.convert( "RGBA" ).transform( ( 600, 60 ), Image.EXTENT, ( 0, 0, 600, 60 ) );
img = infile.convert( "RGBA" ).transform( ( 600, 60 ), Image.EXTENT, ( 0, 0, 600, 60 ) )
# iterate over the list and pack everything into a string
bgrastring = "";
bgrastring = ""
for ent in list( img.getdata() ):
# ent is in RGBA format, but Murmur wants BGRA (ARGB inverse), so stuff needs
# to be reordered when passed to pack()
bgrastring += pack( "4B", ent[2], ent[1], ent[0], ent[3] );
bgrastring += pack( "4B", ent[2], ent[1], ent[0], ent[3] )
# compress using zlib
compressed = compress( bgrastring );
compressed = compress( bgrastring )
# pack the original length in 4 byte big endian, and concat the compressed
# data to it to emulate qCompress().
texture = pack( ">L", len(bgrastring) ) + compressed;
texture = pack( ">L", len(bgrastring) ) + compressed
# finally call murmur and set the texture
self._getIceServerObject(srvid).setTexture(mumbleid, texture)
@protectDjangoErrPage
def verifyPassword(self, srvid, username, password):
return self._getIceServerObject(srvid).verifyPassword(username, password);
return self._getIceServerObject(srvid).verifyPassword(username, password)
@staticmethod
def setUnicodeFlag(data):
@ -429,7 +430,7 @@ class MumbleCtlIce_120(MumbleCtlIce_118):
@protectDjangoErrPage
def getRegisteredPlayers(self, srvid, filter = ''):
users = self._getIceServerObject( srvid ).getRegisteredUsers( filter.encode( "UTF-8" ) )
ret = {};
ret = {}
for id in users:
ret[id] = ObjectInfo(
@ -437,13 +438,13 @@ class MumbleCtlIce_120(MumbleCtlIce_118):
name = unicode( users[id], "utf8" ),
email = '',
pw = ''
);
)
return ret
@protectDjangoErrPage
def getPlayers(self, srvid):
userdata = self._getIceServerObject(srvid).getUsers();
userdata = self._getIceServerObject(srvid).getUsers()
for key in userdata:
if isinstance( userdata[key], str ):
userdata[key] = userdata[key].decode( "UTF-8" )
@ -451,7 +452,7 @@ class MumbleCtlIce_120(MumbleCtlIce_118):
@protectDjangoErrPage
def getState(self, srvid, sessionid):
userdata = self._getIceServerObject(srvid).getState(sessionid);
userdata = self._getIceServerObject(srvid).getState(sessionid)
for key in userdata.__dict__:
attr = getattr( userdata, key )
if isinstance( attr, str ):
@ -467,8 +468,8 @@ class MumbleCtlIce_120(MumbleCtlIce_118):
Murmur.UserInfo.UserName: name.encode( "UTF-8" ),
Murmur.UserInfo.UserEmail: email.encode( "UTF-8" ),
Murmur.UserInfo.UserPassword: password.encode( "UTF-8" ),
};
return self._getIceServerObject(srvid).registerUser( user );
}
return self._getIceServerObject(srvid).registerUser( user )
@protectDjangoErrPage
def unregisterPlayer(self, srvid, mumbleid):
@ -477,13 +478,13 @@ class MumbleCtlIce_120(MumbleCtlIce_118):
@protectDjangoErrPage
def getRegistration(self, srvid, mumbleid):
reg = self._getIceServerObject( srvid ).getRegistration( mumbleid )
user = ObjectInfo( userid=mumbleid, name="", email="", comment="", hash="", pw="" );
user = ObjectInfo( userid=mumbleid, name="", email="", comment="", hash="", pw="" )
import Murmur
if Murmur.UserInfo.UserName in reg: user.name = reg[Murmur.UserInfo.UserName];
if Murmur.UserInfo.UserEmail in reg: user.email = reg[Murmur.UserInfo.UserEmail];
if Murmur.UserInfo.UserComment in reg: user.comment = reg[Murmur.UserInfo.UserComment];
if Murmur.UserInfo.UserHash in reg: user.hash = reg[Murmur.UserInfo.UserHash];
return user;
if Murmur.UserInfo.UserName in reg: user.name = reg[Murmur.UserInfo.UserName]
if Murmur.UserInfo.UserEmail in reg: user.email = reg[Murmur.UserInfo.UserEmail]
if Murmur.UserInfo.UserComment in reg: user.comment = reg[Murmur.UserInfo.UserComment]
if Murmur.UserInfo.UserHash in reg: user.hash = reg[Murmur.UserInfo.UserHash]
return user
@protectDjangoErrPage
def setRegistration(self, srvid, mumbleid, name, email, password):
@ -492,25 +493,25 @@ class MumbleCtlIce_120(MumbleCtlIce_118):
Murmur.UserInfo.UserName: name.encode( "UTF-8" ),
Murmur.UserInfo.UserEmail: email.encode( "UTF-8" ),
Murmur.UserInfo.UserPassword: password.encode( "UTF-8" ),
};
}
return self._getIceServerObject( srvid ).updateRegistration( mumbleid, user )
@protectDjangoErrPage
def getAllConf(self, srvid):
conf = self.setUnicodeFlag(self._getIceServerObject(srvid).getAllConf())
info = {};
info = {}
for key in conf:
if key == "playername" and conf[key]:
# Buggy database transition from 1.1.8 -> 1.2.0
# Store username as "username" field and set playername field to empty
info['username'] = conf[key];
self.setConf( srvid, "playername", "" );
self.setConf( srvid, "username", conf[key] );
info['username'] = conf[key]
self.setConf( srvid, "playername", "" )
self.setConf( srvid, "username", conf[key] )
else:
info[str(key)] = conf[key];
info[str(key)] = conf[key]
return info;
return info
@protectDjangoErrPage
def getConf(self, srvid, key):
@ -528,26 +529,26 @@ class MumbleCtlIce_120(MumbleCtlIce_118):
@protectDjangoErrPage
def setACL(self, srvid, channelid, acls, groups, inherit):
return self._getIceServerObject(srvid).setACL( channelid, acls, groups, inherit );
return self._getIceServerObject(srvid).setACL( channelid, acls, groups, inherit )
@protectDjangoErrPage
def getBans(self, srvid):
return self._getIceServerObject(srvid).getBans();
return self._getIceServerObject(srvid).getBans()
@protectDjangoErrPage
def setBans(self, srvid, bans):
return self._getIceServerObject(srvid).setBans(bans);
return self._getIceServerObject(srvid).setBans(bans)
@protectDjangoErrPage
def addBanForSession(self, srvid, sessionid, **kwargs):
session = self.getState(srvid, sessionid);
session = self.getState(srvid, sessionid)
if "bits" not in kwargs:
kwargs["bits"] = 128;
kwargs["bits"] = 128
if "start" not in kwargs:
kwargs["start"] = int(time());
kwargs["start"] = int(time())
if "duration" not in kwargs:
kwargs["duration"] = 3600;
return self.addBan(srvid, address=session.address, **kwargs);
kwargs["duration"] = 3600
return self.addBan(srvid, address=session.address, **kwargs)
@protectDjangoErrPage
def addBan(self, srvid, **kwargs):
@ -556,19 +557,19 @@ class MumbleCtlIce_120(MumbleCtlIce_118):
kwargs[key] = kwargs[key].encode("UTF-8")
from Murmur import Ban
srvbans = self.getBans(srvid);
srvbans.append( Ban( **kwargs ) );
return self.setBans(srvid, srvbans);
srvbans = self.getBans(srvid)
srvbans.append( Ban( **kwargs ) )
return self.setBans(srvid, srvbans)
@protectDjangoErrPage
def kickUser(self, srvid, userid, reason=""):
return self._getIceServerObject(srvid).kickUser( userid, reason.encode("UTF-8") );
return self._getIceServerObject(srvid).kickUser( userid, reason.encode("UTF-8") )
class MumbleCtlIce_122(MumbleCtlIce_120):
@protectDjangoErrPage
def getTexture(self, srvid, mumbleid):
raise ValueError( "This method is buggy in 1.2.2, sorry dude." );
raise ValueError( "This method is buggy in 1.2.2, sorry dude." )
@protectDjangoErrPage
def setTexture(self, srvid, mumbleid, infile):
@ -588,7 +589,7 @@ class MumbleCtlIce_123(MumbleCtlIce_120):
def getTexture(self, srvid, mumbleid):
texture = self.getRawTexture(srvid, mumbleid)
if len(texture) == 0:
raise ValueError( "No Texture has been set." );
raise ValueError( "No Texture has been set." )
from StringIO import StringIO
try:
return Image.open( StringIO( texture ) )

1
pyweb/mumble/__init__.py

@ -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>
*

51
pyweb/mumble/admin.py

@ -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>
@ -46,11 +47,11 @@ class MumbleAdmin(admin.ModelAdmin):
""" Specification for the "Server administration" admin section. """
list_display = [ 'name', 'srvid', 'get_addr', 'get_port', 'get_murmur_online', 'get_booted',
'get_is_public', 'get_users_regged', 'get_users_online', 'get_channel_count' ];
list_filter = [ 'addr', 'server' ];
search_fields = [ 'name', 'addr', 'port' ];
ordering = [ 'name' ];
form = MumbleAdminForm;
'get_is_public', 'get_users_regged', 'get_users_online', 'get_channel_count' ]
list_filter = [ 'addr', 'server' ]
search_fields = [ 'name', 'addr', 'port' ]
ordering = [ 'name' ]
form = MumbleAdminForm
def get_murmur_online( self, obj ):
return obj.server.online
@ -81,53 +82,53 @@ class MumbleAdmin(admin.ModelAdmin):
def get_users_regged( self, obj ):
""" Populates the "Registered users" column. """
if obj.booted:
return obj.users_regged;
return obj.users_regged
else:
return '-';
return '-'
get_users_regged.short_description = _( 'Registered users' );
get_users_regged.short_description = _( 'Registered users' )
def get_users_online( self, obj ):
""" Populates the "Online users" column. """
if obj.booted:
return obj.users_online;
return obj.users_online
else:
return '-';
return '-'
get_users_online.short_description = _( 'Online users' );
get_users_online.short_description = _( 'Online users' )
def get_channel_count( self, obj ):
""" Populates the "Channel Count" column. """
if obj.booted:
return obj.channel_cnt;
return obj.channel_cnt
else:
return '-';
return '-'
get_channel_count.short_description = _( 'Channel count' );
get_channel_count.short_description = _( 'Channel count' )
def get_is_public( self, obj ):
""" Populates the "Public" column. """
if obj.booted:
if obj.is_public:
return _( 'Yes' );
return _( 'Yes' )
else:
return _( 'No' );
return _( 'No' )
else:
return '-';
return '-'
get_is_public.short_description = _( 'Public' );
get_is_public.short_description = _( 'Public' )
class MumbleUserAdmin(admin.ModelAdmin):
""" Specification for the "Registered users" admin section. """
list_display = [ 'owner', 'server', 'name', 'mumbleid', 'get_acl_admin' ];
list_filter = [ 'server' ];
search_fields = [ 'owner__username', 'name' ];
ordering = [ 'owner__username' ];
list_display = [ 'owner', 'server', 'name', 'mumbleid', 'get_acl_admin' ]
list_filter = [ 'server' ]
search_fields = [ 'owner__username', 'name' ]
ordering = [ 'owner__username' ]
form = MumbleUserAdminForm
@ -140,6 +141,6 @@ class MumbleUserAdmin(admin.ModelAdmin):
get_acl_admin.boolean = True
admin.site.register( MumbleServer, MumbleServerAdmin );
admin.site.register( Mumble, MumbleAdmin );
admin.site.register( MumbleUser, MumbleUserAdmin );
admin.site.register( MumbleServer, MumbleServerAdmin )
admin.site.register( Mumble, MumbleAdmin )
admin.site.register( MumbleUser, MumbleUserAdmin )

111
pyweb/mumble/forms.py

@ -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>
@ -32,7 +33,7 @@ class PropertyModelForm( ModelForm ):
"""
def __init__( self, *args, **kwargs ):
ModelForm.__init__( self, *args, **kwargs );
ModelForm.__init__( self, *args, **kwargs )
if self.instance:
instfields = self.instance._meta.get_all_field_names()
@ -112,8 +113,8 @@ class MumbleForm( PropertyModelForm ):
self.fields['defchan'].choices = choices
class Meta:
model = Mumble;
fields = ['name'];
model = Mumble
fields = ['name']
class MumbleAdminForm( MumbleForm ):
@ -134,7 +135,7 @@ class MumbleAdminForm( MumbleForm ):
def clean_port( self ):
""" Check if the port number is valid. """
port = self.cleaned_data['port'];
port = self.cleaned_data['port']
if port is not None and port != '':
if port < 1 or port >= 2**16:
@ -143,8 +144,8 @@ class MumbleAdminForm( MumbleForm ):
'portno': port,
'minrange': 1,
'maxrange': 2**16,
});
return port;
})
return port
return None
@ -174,36 +175,36 @@ class MumbleUserForm( ModelForm ):
password = forms.CharField( widget=forms.PasswordInput, required=False )
def __init__( self, *args, **kwargs ):
ModelForm.__init__( self, *args, **kwargs );
self.server = None;
ModelForm.__init__( self, *args, **kwargs )
self.server = None
def clean_name( self ):
""" Check if the desired name is forbidden or taken. """
name = self.cleaned_data['name'];
name = self.cleaned_data['name']
if self.server is None:
raise AttributeError( "You need to set the form's server attribute to the server instance "
"for validation to work." );
"for validation to work." )
if self.server.player and re.compile( self.server.player ).match( name ) is None:
raise forms.ValidationError( _( "That name is forbidden by the server." ) );
raise forms.ValidationError( _( "That name is forbidden by the server." ) )
if not self.instance.id and len( self.server.ctl.getRegisteredPlayers( self.server.srvid, name ) ) > 0:
raise forms.ValidationError( _( "Another player already registered that name." ) );
raise forms.ValidationError( _( "Another player already registered that name." ) )
return name;
return name
def clean_password( self ):
""" Verify a password has been given. """
passwd = self.cleaned_data['password'];
passwd = self.cleaned_data['password']
if not passwd and ( not self.instance or self.instance.mumbleid == -1 ):
raise forms.ValidationError( _( "Cannot register player without a password!" ) );
return passwd;
raise forms.ValidationError( _( "Cannot register player without a password!" ) )
return passwd
class Meta:
model = MumbleUser;
fields = ( 'name', 'password' );
model = MumbleUser
fields = ( 'name', 'password' )
class MumbleUserPasswordForm( MumbleUserForm ):
@ -213,21 +214,21 @@ class MumbleUserPasswordForm( MumbleUserForm ):
label=_('Server Password'),
help_text=_('This server is private and protected mode is active. Please enter the server password.'),
widget=forms.PasswordInput(render_value=False)
);
)
def clean_serverpw( self ):
""" Validate the password """
serverpw = self.cleaned_data['serverpw'];
serverpw = self.cleaned_data['serverpw']
if self.server.passwd != serverpw:
raise forms.ValidationError( _( "The password you entered is incorrect." ) );
return serverpw;
raise forms.ValidationError( _( "The password you entered is incorrect." ) )
return serverpw
def clean( self ):
""" prevent save() from trying to store the password in the Model instance. """
# clean() will be called after clean_serverpw(), so it has already been validated here.
if 'serverpw' in self.cleaned_data:
del( self.cleaned_data['serverpw'] );
return self.cleaned_data;
del( self.cleaned_data['serverpw'] )
return self.cleaned_data
class MumbleUserLinkForm( MumbleUserForm ):
@ -237,89 +238,89 @@ class MumbleUserLinkForm( MumbleUserForm ):
label=_('Link account'),
help_text=_('The account already exists and belongs to me, just link it instead of creating.'),
required=False,
);
)
def __init__( self, *args, **kwargs ):
MumbleUserForm.__init__( self, *args, **kwargs );
self.mumbleid = None;
MumbleUserForm.__init__( self, *args, **kwargs )
self.mumbleid = None
def clean_name( self ):
""" Check if the target account exists in Murmur. """
if 'linkacc' not in self.data:
return MumbleUserForm.clean_name( self );
return MumbleUserForm.clean_name( self )
# Check if user exists
name = self.cleaned_data['name'];
name = self.cleaned_data['name']
if len( self.server.ctl.getRegisteredPlayers( self.server.srvid, name ) ) != 1:
raise forms.ValidationError( _( "No such user found." ) );
raise forms.ValidationError( _( "No such user found." ) )
return name;
return name
def clean_password( self ):
""" Verify that the password is correct. """
if 'linkacc' not in self.data:
return MumbleUserForm.clean_password( self );
return MumbleUserForm.clean_password( self )
if 'name' not in self.cleaned_data:
# keep clean() from trying to find a user that CAN'T exist
self.mumbleid = -10;
return '';
self.mumbleid = -10
return ''
# Validate password with Murmur
passwd = self.cleaned_data['password'];
passwd = self.cleaned_data['password']
self.mumbleid = self.server.ctl.verifyPassword( self.server.srvid, self.cleaned_data['name'], passwd )
if self.mumbleid <= 0:
raise forms.ValidationError( _( "The password you entered is incorrect." ) );
raise forms.ValidationError( _( "The password you entered is incorrect." ) )
return passwd;
return passwd
def clean( self ):
""" Create the MumbleUser instance to save in. """
if 'linkacc' not in self.data or self.mumbleid <= 0:
return self.cleaned_data;
return self.cleaned_data
try:
m_user = MumbleUser.objects.get( server=self.server, mumbleid=self.mumbleid );
m_user = MumbleUser.objects.get( server=self.server, mumbleid=self.mumbleid )
except MumbleUser.DoesNotExist:
m_user = MumbleUser( server=self.server, name=self.cleaned_data['name'], mumbleid=self.mumbleid );
m_user.save( dontConfigureMurmur=True );
m_user = MumbleUser( server=self.server, name=self.cleaned_data['name'], mumbleid=self.mumbleid )
m_user.save( dontConfigureMurmur=True )
else:
if m_user.owner is not None:
raise forms.ValidationError( _( "That account belongs to someone else." ) );
raise forms.ValidationError( _( "That account belongs to someone else." ) )
if m_user.getAdmin() and not settings.ALLOW_ACCOUNT_LINKING_ADMINS:
raise forms.ValidationError( _( "Linking Admin accounts is not allowed." ) );
self.instance = m_user;
raise forms.ValidationError( _( "Linking Admin accounts is not allowed." ) )
self.instance = m_user
return self.cleaned_data;
return self.cleaned_data
class MumbleUserAdminForm( PropertyModelForm ):
aclAdmin = forms.BooleanField( required=False );
aclAdmin = forms.BooleanField( required=False )
password = forms.CharField( widget=forms.PasswordInput, required=False )
def clean_password( self ):
""" Verify a password has been given. """
passwd = self.cleaned_data['password'];
passwd = self.cleaned_data['password']
if not passwd and ( not self.instance or self.instance.mumbleid == -1 ):
raise forms.ValidationError( _( "Cannot register player without a password!" ) );
return passwd;
raise forms.ValidationError( _( "Cannot register player without a password!" ) )
return passwd
class Meta:
model = Mumble;
model = Mumble
class MumbleKickForm( Form ):
session = forms.IntegerField();
ban = forms.BooleanField( required=False );
reason = forms.CharField( required=False );
session = forms.IntegerField()
ban = forms.BooleanField( required=False )
reason = forms.CharField( required=False )
class MumbleTextureForm( Form ):
""" The form used to upload a new image to be set as texture. """
usegravatar = forms.BooleanField( required=False, label=_("Use my Gravatar as my Texture") );
texturefile = forms.ImageField( required=False, label=_("User Texture") );
usegravatar = forms.BooleanField( required=False, label=_("Use my Gravatar as my Texture") )
texturefile = forms.ImageField( required=False, label=_("User Texture") )

5
pyweb/mumble/management/__init__.py

@ -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>
@ -49,8 +50,8 @@ if not uptodate:
if settings.DATABASE_ENGINE == "sqlite3":
# backup the db before the conversion.
copy( settings.DATABASE_NAME, settings.DATABASE_NAME+".bak" )
signals.post_syncdb.connect( update_schema, sender=models );
signals.post_syncdb.connect( update_schema, sender=models )
else:
signals.post_syncdb.connect( find_existing_instances, sender=models );
signals.post_syncdb.connect( find_existing_instances, sender=models )

1
pyweb/mumble/management/commands/__init__.py

@ -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>

77
pyweb/mumble/management/commands/checkenv.py

@ -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>
@ -25,7 +26,7 @@ from mumble.models import Mumble
class TestFailed( Exception ):
pass;
pass
class Command( BaseCommand ):
help = "Run a few tests on Mumble-Django's setup."
@ -36,14 +37,14 @@ class Command( BaseCommand ):
except ImportError:
pass
else:
self.check_slice();
self.check_slice()
self.check_rootdir();
self.check_dbase();
self.check_sites();
self.check_mumbles();
self.check_admins();
self.check_secret_key();
self.check_rootdir()
self.check_dbase()
self.check_sites()
self.check_mumbles()
self.check_admins()
self.check_secret_key()
def check_slice( self ):
print "Checking slice file...",
@ -71,56 +72,56 @@ class Command( BaseCommand ):
def check_rootdir( self ):
print "Checking root directory access...",
if not os.path.exists( settings.MUMBLE_DJANGO_ROOT ):
raise TestFailed( "The mumble-django root directory does not exist." );
raise TestFailed( "The mumble-django root directory does not exist." )
elif settings.DATABASE_ENGINE != "sqlite3":
print "not using sqlite [ OK ]"
else:
statinfo = os.stat( settings.MUMBLE_DJANGO_ROOT );
statinfo = os.stat( settings.MUMBLE_DJANGO_ROOT )
if statinfo.st_uid == 0:
raise TestFailed(
"The mumble-django root directory belongs to user root. This is "
"most certainly not what you want because it will prevent your "
"web server from being able to write to the database. Please check." );
"web server from being able to write to the database. Please check." )
elif not os.access( settings.MUMBLE_DJANGO_ROOT, os.W_OK ):
raise TestFailed( "The mumble-django root directory is not writable." );
raise TestFailed( "The mumble-django root directory is not writable." )
else:
print "[ OK ]";
print "[ OK ]"
def check_dbase( self ):
print "Checking database access...",
if settings.DATABASE_ENGINE == "sqlite3":
if not os.path.exists( settings.DATABASE_NAME ):
raise TestFailed( "database does not exist. Have you run syncdb yet?" );
raise TestFailed( "database does not exist. Have you run syncdb yet?" )
else:
statinfo = os.stat( settings.DATABASE_NAME );
statinfo = os.stat( settings.DATABASE_NAME )
if statinfo.st_uid == 0:
raise TestFailed(
"the database file belongs to root. This is most certainly not what "
"you want because it will prevent your web server from being able "
"to write to it. Please check." );
"to write to it. Please check." )
elif not os.access( settings.DATABASE_NAME, os.W_OK ):
raise TestFailed( "database file is not writable." );
raise TestFailed( "database file is not writable." )
else:
print "[ OK ]";
print "[ OK ]"
else:
print "not using sqlite, so I can't check.";
print "not using sqlite, so I can't check."
def check_sites( self ):
print "Checking URL configuration...",
try:
site = Site.objects.get_current();
site = Site.objects.get_current()
except Site.DoesNotExist:
try:
@ -132,20 +133,20 @@ class Command( BaseCommand ):
"setting. Create a site in your database and rerun this command to fix this error.")
else:
print( "none set.\n"
"Please enter the domain where Mumble-Django is reachable." );
dom = raw_input( "> " ).strip();
site = Site( id=sid, name=dom, domain=dom );
site.save();
"Please enter the domain where Mumble-Django is reachable." )
dom = raw_input( "> " ).strip()
site = Site( id=sid, name=dom, domain=dom )
site.save()
if site.domain == 'example.com':
print( "still the default.\n"
"The domain is configured as example.com, which is the default but does not make sense. "
"Please enter the domain where Mumble-Django is reachable." );
"Please enter the domain where Mumble-Django is reachable." )
site.domain = raw_input( "> " ).strip();
site.save();
site.domain = raw_input( "> " ).strip()
site.save()
print site.domain, "[ OK ]";
print site.domain, "[ OK ]"
def check_admins( self ):
@ -153,23 +154,23 @@ class Command( BaseCommand ):
for user in User.objects.all():
if user.is_superuser:
print "[ OK ]";
return;
print "[ OK ]"
return
raise TestFailed( ""
"No admin user exists, so you won't be able to log in to the admin system. You "
"should run `./manage.py createsuperuser` to create one." );
"should run `./manage.py createsuperuser` to create one." )
def check_mumbles( self ):
print "Checking Murmur instances...",
mm = Mumble.objects.all();
mm = Mumble.objects.all()
if mm.count() == 0:
raise TestFailed(
"no Mumble servers are configured, you might want to run "
"`./manage.py syncdb` to run an auto detection." );
"`./manage.py syncdb` to run an auto detection." )
else:
for mumble in mm:
@ -178,22 +179,22 @@ class Command( BaseCommand ):
except Exception, err:
raise TestFailed(
"Connecting to Murmur `%s` (%s) failed: %s" % ( mumble.name, mumble.server, err )
);
print "[ OK ]";
)
print "[ OK ]"
def check_secret_key( self ):
print "Checking SECRET_KEY...",
blacklist = ( 'u-mp185msk#z4%s(do2^5405)y5d!9adbn92)apu_p^qvqh10v', );
blacklist = ( 'u-mp185msk#z4%s(do2^5405)y5d!9adbn92)apu_p^qvqh10v', )
if settings.SECRET_KEY in blacklist:
raise TestFailed(
"Your SECRET_KEY setting matches one of the keys that were put in the settings.py "
"file shipped with Mumble-Django, which means your SECRET_KEY is all but secret. "
"You should change the setting, or run gen_secret_key.sh to do it for you."
);
)
else:
print "[ OK ]";
print "[ OK ]"

1
pyweb/mumble/management/commands/getslice.py

@ -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>

1
pyweb/mumble/management/commands/mmrunserver.py

@ -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>

1
pyweb/mumble/management/commands/mmshell.py

@ -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>

1
pyweb/mumble/management/commands/mmsyncdb.py

@ -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>

77
pyweb/mumble/management/server_detect.py

@ -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>
@ -25,37 +26,37 @@ from mumble.mctl import MumbleCtlBase
def find_in_dicts( keys, conf, default, valueIfNotFound=None ):
if not isinstance( keys, tuple ):
keys = ( keys, );
keys = ( keys, )
for keyword in keys:
if keyword in conf:
return conf[keyword];
return conf[keyword]
for keyword in keys:
keyword = keyword.lower();
keyword = keyword.lower()
if keyword in default:
return default[keyword];
return default[keyword]
return valueIfNotFound;
return valueIfNotFound
def find_existing_instances( **kwargs ):
if "verbosity" in kwargs:
v = kwargs['verbosity'];
v = kwargs['verbosity']
else:
v = 1;
v = 1
if v > 1:
print "Starting Mumble servers and players detection now.";
print "Starting Mumble servers and players detection now."
triedEnviron = False;
online = False;
triedEnviron = False
online = False
while not online:
if not triedEnviron and 'MURMUR_CONNSTR' in os.environ:
dbusName = os.environ['MURMUR_CONNSTR'];
triedEnviron = True;
dbusName = os.environ['MURMUR_CONNSTR']
triedEnviron = True
if v > 1:
print "Trying environment setting", dbusName;
print "Trying environment setting", dbusName
else:
print "--- Murmur connection info ---"
print " 1) DBus -- net.sourceforge.mumble.murmur"
@ -66,49 +67,49 @@ def find_existing_instances( **kwargs ):
print "string's format."
print
dbusName = raw_input( "Service string: " ).strip();
dbusName = raw_input( "Service string: " ).strip()
if not dbusName:
if v:
print 'Be sure to run "python manage.py syncdb" with Murmur running before'
print "trying to use this app! Otherwise, existing Murmur servers won't be"
print 'configurable!';
return False;
print 'configurable!'
return False
elif dbusName == "1":
dbusName = "net.sourceforge.mumble.murmur";
dbusName = "net.sourceforge.mumble.murmur"
elif dbusName == "2":
dbusName = "Meta:tcp -h 127.0.0.1 -p 6502";
dbusName = "Meta:tcp -h 127.0.0.1 -p 6502"
icesecret = getpass.getpass("Please enter the Ice secret (if any): ");
icesecret = getpass.getpass("Please enter the Ice secret (if any): ")
try:
ctl = MumbleCtlBase.newInstance( dbusName, settings.SLICE, icesecret );
ctl = MumbleCtlBase.newInstance( dbusName, settings.SLICE, icesecret )
except Exception, instance:
if v:
print "Unable to connect using name %s. The error was:" % dbusName;
print instance;
print "Unable to connect using name %s. The error was:" % dbusName
print instance
print
else:
online = True;
online = True
if v > 1:
print "Successfully connected to Murmur via connection string %s, using %s." % ( dbusName, ctl.method );
print "Successfully connected to Murmur via connection string %s, using %s." % ( dbusName, ctl.method )
servIDs = ctl.getAllServers();
servIDs = ctl.getAllServers()
try:
meta = MumbleServer.objects.get( dbus=dbusName );
meta = MumbleServer.objects.get( dbus=dbusName )
except MumbleServer.DoesNotExist:
meta = MumbleServer( dbus=dbusName );
meta = MumbleServer( dbus=dbusName )
finally:
meta.secret = icesecret;
meta.save();
meta.secret = icesecret
meta.save()
for id in servIDs:
if v > 1:
print "Checking Murmur instance with id %d." % id;
print "Checking Murmur instance with id %d." % id
# first check that the server has not yet been inserted into the DB
try:
instance = Mumble.objects.get( server=meta, srvid=id );
instance = Mumble.objects.get( server=meta, srvid=id )
except Mumble.DoesNotExist:
values = {
"server": meta,
@ -119,13 +120,13 @@ def find_existing_instances( **kwargs ):
print "Found new Murmur instance %d on bus '%s'... " % ( id, dbusName )
# now create a model for the record set.
instance = Mumble( **values );
instance = Mumble( **values )
else:
if v:
print "Syncing Murmur instance %d: '%s'... " % ( instance.id, instance.name )
try:
instance.configureFromMurmur();
instance.configureFromMurmur()
except DatabaseError, err:
try:
# Find instances with the same address/port
@ -157,13 +158,13 @@ def find_existing_instances( **kwargs ):
# Now search for players on this server that have not yet been registered
if instance.booted:
if v > 1:
print "Looking for registered Players on Server id %d." % id;
instance.readUsersFromMurmur( verbose=v );
print "Looking for registered Players on Server id %d." % id
instance.readUsersFromMurmur( verbose=v )
elif v:
print "This server is not running, can't sync players.";
print "This server is not running, can't sync players."
if v > 1:
print "Successfully finished Servers and Players detection.";
return True;
print "Successfully finished Servers and Players detection."
return True

5
pyweb/mumble/management/update_schema.py

@ -1,4 +1,5 @@
# -*- coding: utf-8 -*-
# kate: space-indent on; indent-width 4; replace-tabs on;
"""
* Copyright © 2010, Michael "Svedrin" Ziegler <diese-addy@funzt-halt.net>
@ -27,9 +28,9 @@ from mumble.management.server_detect import find_existing_instances
def update_schema( **kwargs ):
if "verbosity" in kwargs:
v = kwargs['verbosity'];
v = kwargs['verbosity']
else:
v = 1;
v = 1
if v:
print "Migrating Database schema for Mumble-Django 2.0 now."

13
pyweb/mumble/mctl.py

@ -1,4 +1,5 @@
# -*- coding: utf-8 -*-
# kate: space-indent on; indent-width 4; replace-tabs on;
"""
* Copyright © 2009, withgod <withgod@sourceforge.net>
@ -20,7 +21,7 @@ import re
class MumbleCtlBase(object):
""" This class defines the base interface that the Mumble model expects. """
cache = {};
cache = {}
@staticmethod
def newInstance( connstring, slicefile=None, icesecret=None ):
@ -36,12 +37,12 @@ class MumbleCtlBase(object):
# check cache
if connstring in MumbleCtlBase.cache:
return MumbleCtlBase.cache[connstring];
return MumbleCtlBase.cache[connstring]
# connstring defines whether to connect via ICE or DBus.
# Dbus service names: some.words.divided.by.periods
# ICE specs are WAY more complex, so if DBus doesn't match, use ICE.
rd = re.compile( r'^(\w+\.)*\w+$' );
rd = re.compile( r'^(\w+\.)*\w+$' )
if rd.match( connstring ):
from MumbleCtlDbus import MumbleCtlDbus
@ -50,9 +51,9 @@ class MumbleCtlBase(object):
from MumbleCtlIce import MumbleCtlIce
ctl = MumbleCtlIce( connstring, slicefile, icesecret )
MumbleCtlBase.cache[connstring] = ctl;
return ctl;
MumbleCtlBase.cache[connstring] = ctl
return ctl
@staticmethod
def clearCache():
MumbleCtlBase.cache = {};
MumbleCtlBase.cache = {}

183
pyweb/mumble/mmobjects.py

@ -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>
@ -26,97 +27,97 @@ from django.conf import settings
def cmp_channels( left, rite ):
""" Compare two channels, first by position, and if that equals, by name. """
if hasattr( left, "position" ) and hasattr( rite, "position" ):
byorder = cmp( left.position, rite.position );
byorder = cmp( left.position, rite.position )
if byorder != 0:
return byorder;
return cmp_names( left, rite );
return byorder
return cmp_names( left, rite )
def cmp_names( left, rite ):
""" Compare two objects by their name property. """
return cmp( left.name, rite.name );
return cmp( left.name, rite.name )
class mmChannel( object ):
""" Represents a channel in Murmur. """
def __init__( self, server, channel_obj, parent_chan = None ):
self.server = server;
self.players = list();
self.subchans = list();
self.linked = list();
self.server = server
self.players = list()
self.subchans = list()
self.linked = list()
self.channel_obj = channel_obj;
self.chanid = channel_obj.id;
self.channel_obj = channel_obj
self.chanid = channel_obj.id
self.parent = parent_chan;
self.parent = parent_chan
if self.parent is not None:
self.parent.subchans.append( self );
self.parent.subchans.append( self )
self._acl = None;
self._acl = None
# Lookup unknown attributes in self.channel_obj to automatically include Murmur's fields
def __getattr__( self, key ):
if hasattr( self.channel_obj, key ):
return getattr( self.channel_obj, key );
return getattr( self.channel_obj, key )
else:
raise AttributeError( "'%s' object has no attribute '%s'" % ( self.__class__.__name__, key ) );
raise AttributeError( "'%s' object has no attribute '%s'" % ( self.__class__.__name__, key ) )
def parent_channels( self ):
""" Return the names of this channel's parents in the channel tree. """
if self.parent is None or self.parent.is_server or self.parent.chanid == 0:
return [];
return self.parent.parent_channels() + [self.parent.name];
return []
return self.parent.parent_channels() + [self.parent.name]
def getACL( self ):
""" Retrieve the ACL for this channel. """
if not self._acl:
self._acl = mmACL( self, self.server.ctl.getACL( self.server.srvid, self.chanid ) );
self._acl = mmACL( self, self.server.ctl.getACL( self.server.srvid, self.chanid ) )
return self._acl;
return self._acl
acl = property( getACL );
acl = property( getACL )
is_server = False;
is_channel = True;
is_player = False;
is_server = False
is_channel = True
is_player = False
playerCount = property(
lambda self: len( self.players ) + sum( [ chan.playerCount for chan in self.subchans ] ),
doc="The number of players in this channel."
);
)
id = property(
lambda self: "channel_%d"%self.chanid,
doc="A string ready to be used in an id property of an HTML tag."
);
)
top_or_not_empty = property(
lambda self: self.parent is None or self.parent.chanid == 0 or self.playerCount > 0,
doc="True if this channel needs to be shown because it is root, a child of root, or has players."
);
)
show = property( lambda self: settings.SHOW_EMPTY_SUBCHANS or self.top_or_not_empty );
show = property( lambda self: settings.SHOW_EMPTY_SUBCHANS or self.top_or_not_empty )
def __str__( self ):
return '<Channel "%s" (%d)>' % ( self.name, self.chanid );
return '<Channel "%s" (%d)>' % ( self.name, self.chanid )
def sort( self ):
""" Sort my subchannels and players, and then iterate over them and sort them recursively. """
self.subchans.sort( cmp_channels );
self.players.sort( cmp_names );
self.subchans.sort( cmp_channels )
self.players.sort( cmp_names )
for subc in self.subchans:
subc.sort();
subc.sort()
def visit( self, callback, lvl = 0 ):
""" Call callback on myself, then visit my subchans, then my players. """
callback( self, lvl );
callback( self, lvl )
for subc in self.subchans:
subc.visit( callback, lvl + 1 );
subc.visit( callback, lvl + 1 )
for plr in self.players:
plr.visit( callback, lvl + 1 );
plr.visit( callback, lvl + 1 )
def getURL( self, for_user = None ):
@ -124,38 +125,38 @@ class mmChannel( object ):
mumble://username@host:port/parentchans/self.name
"""
from urlparse import urlunsplit
versionstr = "version=%s" % self.server.prettyversion;
versionstr = "version=%s" % self.server.prettyversion
if self.parent is not None:
chanlist = self.parent_channels() + [self.name];
chanlist = [ urlquote( chan ) for chan in chanlist ];
urlpath = "/".join( chanlist );
chanlist = self.parent_channels() + [self.name]
chanlist = [ urlquote( chan ) for chan in chanlist ]
urlpath = "/".join( chanlist )
else:
urlpath = "";
urlpath = ""
if for_user is not None:
netloc = "%s@%s" % ( for_user.name, self.server.netloc );
netloc = "%s@%s" % ( for_user.name, self.server.netloc )
return urlunsplit(( "mumble", netloc, urlpath, versionstr, "" ))
else:
return urlunsplit(( "mumble", self.server.netloc, urlpath, versionstr, "" ))
connecturl = property( getURL );
connecturl = property( getURL )
def setDefault( self ):
""" Make this the server's default channel. """
self.server.defchan = self.chanid;
self.server.save();
self.server.defchan = self.chanid
self.server.save()
is_default = property(
lambda self: self.server.defchan == self.chanid,
doc="True if this channel is the server's default channel."
);
)
def asDict( self ):
chandata = self.channel_obj.__dict__.copy();
chandata['players'] = [ pl.asDict() for pl in self.players ];
chandata['subchans'] = [ sc.asDict() for sc in self.subchans ];
return chandata;
chandata = self.channel_obj.__dict__.copy()
chandata['players'] = [ pl.asDict() for pl in self.players ]
chandata['subchans'] = [ sc.asDict() for sc in self.subchans ]
return chandata
def asMvXml( self, parentnode ):
""" Return an XML tree for this channel suitable for MumbleViewer-ng. """
@ -190,85 +191,85 @@ class mmPlayer( object ):
""" Represents a Player in Murmur. """
def __init__( self, server, player_obj, player_chan ):
self.player_obj = player_obj;
self.player_obj = player_obj
self.onlinesince = datetime.datetime.fromtimestamp( float( time() - player_obj.onlinesecs ) );
self.channel = player_chan;
self.channel.players.append( self );
self.onlinesince = datetime.datetime.fromtimestamp( float( time() - player_obj.onlinesecs ) )
self.channel = player_chan
self.channel.players.append( self )
if self.isAuthed:
from mumble.models import MumbleUser
try:
self.mumbleuser = MumbleUser.objects.get( mumbleid=self.userid, server=server );
self.mumbleuser = MumbleUser.objects.get( mumbleid=self.userid, server=server )
except MumbleUser.DoesNotExist:
self.mumbleuser = None;
self.mumbleuser = None
else:
self.mumbleuser = None;
self.mumbleuser = None
# Lookup unknown attributes in self.player_obj to automatically include Murmur's fields
def __getattr__( self, key ):
if hasattr( self.player_obj, key ):
return getattr( self.player_obj, key );
return getattr( self.player_obj, key )
else:
raise AttributeError( "'%s' object has no attribute '%s'" % ( self.__class__.__name__, key ) );
raise AttributeError( "'%s' object has no attribute '%s'" % ( self.__class__.__name__, key ) )
def __str__( self ):
return '<Player "%s" (%d, %d)>' % ( self.name, self.session, self.userid );
return '<Player "%s" (%d, %d)>' % ( self.name, self.session, self.userid )
hasComment = property(
lambda self: hasattr( self.player_obj, "comment" ) and bool(self.player_obj.comment),
doc="True if this player has a comment set."
);
)
isAuthed = property(
lambda self: self.userid != -1,
doc="True if this player is authenticated (+A)."
);
)
isAdmin = property(
lambda self: self.mumbleuser and self.mumbleuser.getAdmin(),
doc="True if this player is in the Admin group in the ACL."
);
)
is_server = False;
is_channel = False;
is_player = True;
is_server = False
is_channel = False
is_player = True
def getIpAsString( self ):
""" Get the client's IPv4 or IPv6 address, in a pretty format. """
addr = self.player_obj.address;
addr = self.player_obj.address
if max( addr[:10] ) == 0 and addr[10:12] == (255, 255):
return "%d.%d.%d.%d" % tuple( addr[12:] );
return "%d.%d.%d.%d" % tuple( addr[12:] )
ip6addr = [(hi << 8 | lo) for (hi, lo) in zip(addr[0::2], addr[1::2])]
# colon-separated string:
ipstr = ':'.join([ ("%x" % part) for part in ip6addr ]);
ipstr = ':'.join([ ("%x" % part) for part in ip6addr ])
# 0:0:0 -> ::
return re.sub( "((^|:)(0:){2,})", '::', ipstr, 1 );
return re.sub( "((^|:)(0:){2,})", '::', ipstr, 1 )
ipaddress = property( getIpAsString );
ipaddress = property( getIpAsString )
fqdn = property( lambda self: socket.getfqdn( self.ipaddress ),
doc="The fully qualified domain name of the user's host." );
doc="The fully qualified domain name of the user's host." )
# kept for compatibility to mmChannel (useful for traversal funcs)
playerCount = property( lambda self: -1, doc="Exists only for compatibility to mmChannel." );
playerCount = property( lambda self: -1, doc="Exists only for compatibility to mmChannel." )
id = property(
lambda self: "player_%d"%self.session,
doc="A string ready to be used in an id property of an HTML tag."
);
)
def visit( self, callback, lvl = 0 ):
""" Call callback on myself. """
callback( self, lvl );
callback( self, lvl )
def asDict( self ):
pldata = self.player_obj.__dict__.copy();
pldata = self.player_obj.__dict__.copy()
if self.mumbleuser:
if self.mumbleuser.hasTexture():
pldata['texture'] = self.mumbleuser.textureUrl;
pldata['texture'] = self.mumbleuser.textureUrl
return pldata;
return pldata
def asMvXml( self, parentnode ):
""" Return an XML node for this player suitable for MumbleViewer-ng. """
@ -294,49 +295,49 @@ class mmACL( object ):
""" Represents an ACL for a certain channel. """
def __init__( self, channel, acl_obj ):
self.channel = channel;
self.acls, self.groups, self.inherit = acl_obj;
self.channel = channel
self.acls, self.groups, self.inherit = acl_obj
self.groups_dict = {};
self.groups_dict = {}
for group in self.groups:
self.groups_dict[ group.name ] = group;
self.groups_dict[ group.name ] = group
def group_has_member( self, name, userid ):
""" Checks if the given userid is a member of the given group in this channel. """
if name not in self.groups_dict:
raise ReferenceError( "No such group '%s'" % name );
raise ReferenceError( "No such group '%s'" % name )
return userid in self.groups_dict[name].add or userid in self.groups_dict[name].members;
return userid in self.groups_dict[name].add or userid in self.groups_dict[name].members
def group_add_member( self, name, userid ):
""" Make sure this userid is a member of the group in this channel (and subs). """
if name not in self.groups_dict:
raise ReferenceError( "No such group '%s'" % name );
raise ReferenceError( "No such group '%s'" % name )
group = self.groups_dict[name];
group = self.groups_dict[name]
# if neither inherited nor to be added, add
if userid not in group.members and userid not in group.add:
group.add.append( userid );
group.add.append( userid )
# if to be removed, unremove
if userid in group.remove:
group.remove.remove( userid );
group.remove.remove( userid )
def group_remove_member( self, name, userid ):
""" Make sure this userid is NOT a member of the group in this channel (and subs). """
if name not in self.groups_dict:
raise ReferenceError( "No such group '%s'" % name );
raise ReferenceError( "No such group '%s'" % name )
group = self.groups_dict[name];
group = self.groups_dict[name]
# if added here, unadd
if userid in group.add:
group.add.remove( userid );
group.add.remove( userid )
# if member and not in remove, add to remove
elif userid in group.members and userid not in group.remove:
group.remove.append( userid );
group.remove.append( userid )
def save( self ):
""" Send this ACL to Murmur. """
@ -344,7 +345,7 @@ class mmACL( object ):
self.channel.server.srvid,
self.channel.chanid,
self.acls, self.groups, self.inherit
);
)

323
pyweb/mumble/models.py

@ -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 )

115
pyweb/mumble/murmurenvutils.py

@ -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>
@ -25,9 +26,9 @@ from utils import ObjectInfo
def get_available_versions():
""" Return murmur versions installed inside the LAB_DIR. """
dirs = os.listdir( settings.TEST_MURMUR_LAB_DIR );
dirs.sort();
return dirs;
dirs = os.listdir( settings.TEST_MURMUR_LAB_DIR )
dirs.sort()
return dirs
def run_callback( version, callback, *args, **kwargs ):
@ -56,42 +57,42 @@ def run_callback( version, callback, *args, **kwargs ):
into the first parameter.
"""
murmur_root = join( settings.TEST_MURMUR_LAB_DIR, version );
murmur_root = join( settings.TEST_MURMUR_LAB_DIR, version )
if not exists( murmur_root ):
raise EnvironmentError( "This version could not be found: '%s' does not exist!" % murmur_root );
raise EnvironmentError( "This version could not be found: '%s' does not exist!" % murmur_root )
init_dbase( version );
init_dbase( version )
process = run_murmur( version );
process = run_murmur( version )
try:
result = callback( process, *args, **kwargs );
result = callback( process, *args, **kwargs )
if type(result) == tuple:
if result[1]:
update_dbase( version );
return result[0];
update_dbase( version )
return result[0]
else:
return result;
return result
finally:
kill_murmur( process );
kill_murmur( process )
def init_dbase( version ):
""" Initialize Murmur's database by copying the one from FILES_DIR. """
dbasefile = join( settings.TEST_MURMUR_FILES_DIR, "murmur-%s.db3" % version );
dbasefile = join( settings.TEST_MURMUR_FILES_DIR, "murmur-%s.db3" % version )
if not exists( dbasefile ):
raise EnvironmentError( "This version could not be found: '%s' does not exist!" % dbasefile );
murmurfile = join( settings.TEST_MURMUR_LAB_DIR, version, "murmur.sqlite" );
copyfile( dbasefile, murmurfile );
raise EnvironmentError( "This version could not be found: '%s' does not exist!" % dbasefile )
murmurfile = join( settings.TEST_MURMUR_LAB_DIR, version, "murmur.sqlite" )
copyfile( dbasefile, murmurfile )
def update_dbase( version ):
""" Copy Murmur's database to FILES_DIR (the inverse of init_dbase). """
murmurfile = join( settings.TEST_MURMUR_LAB_DIR, version, "murmur.sqlite" );
murmurfile = join( settings.TEST_MURMUR_LAB_DIR, version, "murmur.sqlite" )
if not exists( murmurfile ):
raise EnvironmentError( "Murmur's database could not be found: '%s' does not exist!" % murmurfile );
dbasefile = join( settings.TEST_MURMUR_FILES_DIR, "murmur-%s.db3" % version );
copyfile( murmurfile, dbasefile );
raise EnvironmentError( "Murmur's database could not be found: '%s' does not exist!" % murmurfile )
dbasefile = join( settings.TEST_MURMUR_FILES_DIR, "murmur-%s.db3" % version )
copyfile( murmurfile, dbasefile )
def run_murmur( version ):
@ -100,11 +101,11 @@ def run_murmur( version ):
Either returns a Popen object or raises an EnvironmentError.
"""
murmur_root = join( settings.TEST_MURMUR_LAB_DIR, version );
murmur_root = join( settings.TEST_MURMUR_LAB_DIR, version )
if not exists( murmur_root ):
raise EnvironmentError( "This version could not be found: '%s' does not exist!" % murmur_root );
raise EnvironmentError( "This version could not be found: '%s' does not exist!" % murmur_root )
binary_candidates = ( 'murmur.64', 'murmur.x86', 'murmurd' );
binary_candidates = ( 'murmur.64', 'murmur.x86', 'murmurd' )
for binname in binary_candidates:
if exists( join( murmur_root, binname ) ):
@ -112,34 +113,34 @@ def run_murmur( version ):
( join( murmur_root, binname ), '-fg' ),
stdin=None, stdout=subprocess.PIPE, stderr=subprocess.STDOUT,
cwd=murmur_root
);
)
# Check capabilities by waiting for certain lines to show up.
capa = ObjectInfo( has_dbus=False, has_ice=False, has_instance=False, has_users=False );
capa = ObjectInfo( has_dbus=False, has_ice=False, has_instance=False, has_users=False )
def canRead( self, timeout=1 ):
rdy_read, rdy_write, rdy_other = select( [self.stdout], [], [], timeout );
return self.stdout in rdy_read;
rdy_read, rdy_write, rdy_other = select( [self.stdout], [], [], timeout )
return self.stdout in rdy_read
setattr(subprocess.Popen, 'canRead', canRead)
while process.canRead(0.5):
line = process.stdout.readline();
line = process.stdout.readline()
#print "read line:", line
if line == 'DBus registration succeeded\n':
capa.has_dbus = True;
capa.has_dbus = True
elif line == 'MurmurIce: Endpoint "tcp -h 127.0.0.1 -p 6502" running\n':
capa.has_ice = True;
capa.has_ice = True
elif line == '1 => Server listening on 0.0.0.0:64738\n':
capa.has_instance = True;
capa.has_instance = True
elif "> Authenticated\n" in line:
capa.has_users = True;
capa.has_users = True
process.capabilities = capa;
process.capabilities = capa
return process;
return process
raise EnvironmentError( "Murmur binary not found. (Tried %s)" % unicode(binary_candidates) );
raise EnvironmentError( "Murmur binary not found. (Tried %s)" % unicode(binary_candidates) )
def wait_for_user( process, timeout=1 ):
@ -155,16 +156,16 @@ def wait_for_user( process, timeout=1 ):
False otherwise.
"""
while process.canRead( timeout ):
line = process.stdout.readline();
line = process.stdout.readline()
if "> Authenticated\n" in line:
process.capabilities.has_users = True;
return True;
return False;
process.capabilities.has_users = True
return True
return False
def kill_murmur( process ):
""" Send a sigterm to the given process. """
return os.kill( process.pid, signal.SIGTERM );
return os.kill( process.pid, signal.SIGTERM )
class MumbleCommandWrapper_noargs( object ):
@ -185,23 +186,23 @@ class MumbleCommandWrapper_noargs( object ):
"""
def _choose_version( self ):
print "Choose version:";
print "Choose version:"
vv = get_available_versions();
vv = get_available_versions()
for idx in range(len(vv)):
print " #%d %s" % ( idx, vv[idx] );
print " #%d %s" % ( idx, vv[idx] )
chosen = int( raw_input("#> ") );
chosen = int( raw_input("#> ") )
return vv[chosen];
return vv[chosen]
def handle_noargs( self, **options ):
self.origOpts = options;
self.origOpts = options
run_callback( self._choose_version(), self.runOrig );
run_callback( self._choose_version(), self.runOrig )
def runOrig( self, proc ):
super( MumbleCommandWrapper_noargs, self ).handle_noargs( **self.origOpts );
super( MumbleCommandWrapper_noargs, self ).handle_noargs( **self.origOpts )
class MumbleCommandWrapper( object ):
@ -222,23 +223,23 @@ class MumbleCommandWrapper( object ):
"""
def _choose_version( self ):
print "Choose version:";
print "Choose version:"
vv = get_available_versions();
vv = get_available_versions()
for idx in range(len(vv)):
print " #%d %s" % ( idx, vv[idx] );
print " #%d %s" % ( idx, vv[idx] )
chosen = int( raw_input("#> ") );
chosen = int( raw_input("#> ") )
return vv[chosen];
return vv[chosen]
def handle( self, *args, **options ):
self.origArgs = args;
self.origOpts = options;
self.origArgs = args
self.origOpts = options
run_callback( self._choose_version(), self.runOrig );
run_callback( self._choose_version(), self.runOrig )
def runOrig( self, proc ):
super( MumbleCommandWrapper, self ).handle( *self.origArgs, **self.origOpts );
super( MumbleCommandWrapper, self ).handle( *self.origArgs, **self.origOpts )

15
pyweb/mumble/templatetags/mumble_extras.py

@ -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>
@ -19,32 +20,32 @@ from django.template.loader import render_to_string
from django.conf import settings
register = template.Library();
register = template.Library()
@register.filter
def trunc( string, maxlen = 50 ):
""" converts "a very very extaordinary long text" to "a very very extra... """
if len(string) < maxlen:
return string;
return string[:(maxlen - 3)] + "";
return string
return string[:(maxlen - 3)] + ""
@register.filter
def chanview( obj, user = None ):
""" renders an mmChannel / mmPlayer object with the correct template """
if obj.is_server:
return render_to_string( 'mumble/server.html', { 'Server': obj, 'MumbleAccount': user, 'MEDIA_URL': settings.MEDIA_URL } );
return render_to_string( 'mumble/server.html', { 'Server': obj, 'MumbleAccount': user, 'MEDIA_URL': settings.MEDIA_URL } )
elif obj.is_channel:
return render_to_string( 'mumble/channel.html', { 'Channel': obj, 'MumbleAccount': user, 'MEDIA_URL': settings.MEDIA_URL } );
return render_to_string( 'mumble/channel.html', { 'Channel': obj, 'MumbleAccount': user, 'MEDIA_URL': settings.MEDIA_URL } )
elif obj.is_player:
return render_to_string( 'mumble/player.html', { 'Player': obj, 'MumbleAccount': user, 'MEDIA_URL': settings.MEDIA_URL } );
return render_to_string( 'mumble/player.html', { 'Player': obj, 'MumbleAccount': user, 'MEDIA_URL': settings.MEDIA_URL } )
@register.filter
def chanurl( obj, user ):
""" create a connection URL and takes the user's login into account """
return obj.getURL( user );
return obj.getURL( user )
@register.filter
def mmversion_lt( obj, version ):

55
pyweb/mumble/testrunner.py

@ -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>
@ -28,28 +29,28 @@ def run_tests( test_labels, verbosity=1, interactive=True, extra_tests=[] ):
"""
if not test_labels:
test_labels = [ appname.split('.')[-1] for appname in settings.INSTALLED_APPS ];
test_labels = [ appname.split('.')[-1] for appname in settings.INSTALLED_APPS ]
# No need to sync any murmur servers for the other apps
os.environ['MURMUR_CONNSTR'] = '';
os.environ['MURMUR_CONNSTR'] = ''
# The easy way: mumble is not being tested.
if "mumble" not in test_labels:
return django_run_tests( test_labels, verbosity, interactive, extra_tests );
return django_run_tests( test_labels, verbosity, interactive, extra_tests )
# First run everything apart from mumble. mumble will be tested separately, so Murmur
# can be set up properly first.
failed_tests = 0;
failed_tests = 0
if len(test_labels) > 1:
# only run others if mumble is not the only app to be tested
test_labels = list(test_labels);
test_labels.remove( "mumble" );
failed_tests += django_run_tests( test_labels, verbosity, interactive, extra_tests );
test_labels = list(test_labels)
test_labels.remove( "mumble" )
failed_tests += django_run_tests( test_labels, verbosity, interactive, extra_tests )
failed_tests += run_mumble_tests( verbosity, interactive );
failed_tests += run_mumble_tests( verbosity, interactive )
return failed_tests;
return failed_tests
def run_mumble_tests( verbosity=1, interactive=True ):
@ -57,43 +58,43 @@ def run_mumble_tests( verbosity=1, interactive=True ):
connstrings = {
'DBus': 'net.sourceforge.mumble.murmur',
'Ice': 'Meta:tcp -h 127.0.0.1 -p 6502',
};
}
def django_run_tests_wrapper( process, version ):
wr_failed_tests = 0;
wr_failed_tests = 0
for method in connstrings:
# Check if this server is ready to be used with the current method
if getattr( process.capabilities, ("has_%s" % method.lower()), False ):
print "Testing mumble %s via %s" % ( version, method );
print "Testing mumble %s via %s" % ( version, method )
os.environ['MURMUR_CONNSTR'] = connstrings[method];
settings.DEFAULT_CONN = connstrings[method];
settings.SLICE_VERSION = [ int(dgt) for dgt in version.split('.') ];
os.environ['MURMUR_CONNSTR'] = connstrings[method]
settings.DEFAULT_CONN = connstrings[method]
settings.SLICE_VERSION = [ int(dgt) for dgt in version.split('.') ]
print "MURMUR_CONNSTR:", os.environ['MURMUR_CONNSTR'];
print "DEFAULT_CONN: ", settings.DEFAULT_CONN;
print "SLICE_VERSION: ", settings.SLICE_VERSION;
print "MURMUR_CONNSTR:", os.environ['MURMUR_CONNSTR']
print "DEFAULT_CONN: ", settings.DEFAULT_CONN
print "SLICE_VERSION: ", settings.SLICE_VERSION
if not process.capabilities.has_users:
print "Waiting for user to connect (60 seconds)."
wait_for_user( process, timeout=60 );
wait_for_user( process, timeout=60 )
wr_failed_tests += django_run_tests( ('mumble',), verbosity, interactive, [] );
wr_failed_tests += django_run_tests( ('mumble',), verbosity, interactive, [] )
else:
print "Mumble %s does not support Method %s" % ( version, method );
print "Mumble %s does not support Method %s" % ( version, method )
return wr_failed_tests;
return wr_failed_tests
failed_tests = 0;
failed_tests = 0
from mctl import MumbleCtlBase
for version in get_available_versions():
MumbleCtlBase.clearCache();
MumbleCtlBase.clearCache()
run = raw_input( "Run tests for %s? [Y/n] " % version );
run = raw_input( "Run tests for %s? [Y/n] " % version )
if run in ('Y', 'y', ''):
failed_tests += run_callback( version, django_run_tests_wrapper, version );
failed_tests += run_callback( version, django_run_tests_wrapper, version )
return failed_tests;
return failed_tests

173
pyweb/mumble/tests.py

@ -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>
@ -28,29 +29,29 @@ class InstancesHandling( TestCase ):
# Make sure we always start with a FRESH murmur instance, checking for left-over instances
# and deleting them before creating ours.
try:
self.murmur = Mumble.objects.get( addr="0.0.0.0", port=31337 );
self.murmur = Mumble.objects.get( addr="0.0.0.0", port=31337 )
except Mumble.DoesNotExist:
pass
else:
self.murmur.delete();
self.murmur.delete()
finally:
self.murmur = Mumble( name="#unit testing instance#", addr="0.0.0.0", port=31337 );
self.murmur.save();
self.murmur = Mumble( name="#unit testing instance#", addr="0.0.0.0", port=31337 )
self.murmur.save()
def testDefaultConf( self ):
conf = self.murmur.ctl.getAllConf( self.murmur.srvid );
self.assert_( type(conf) == dict );
self.assert_( "host" in conf );
self.assert_( "port" in conf );
self.assert_( "certificate" in conf );
self.assert_( "key" in conf );
self.assert_( "registerhostname" in conf );
self.assert_( "registername" in conf );
self.assert_( "channelname" in conf );
self.assert_( "username" in conf );
self.assert_( "obfuscate" in conf );
self.assert_( "defaultchannel" in conf );
conf = self.murmur.ctl.getAllConf( self.murmur.srvid )
self.assert_( type(conf) == dict )
self.assert_( "host" in conf )
self.assert_( "port" in conf )
self.assert_( "certificate" in conf )
self.assert_( "key" in conf )
self.assert_( "registerhostname" in conf )
self.assert_( "registername" in conf )
self.assert_( "channelname" in conf )
self.assert_( "username" in conf )
self.assert_( "obfuscate" in conf )
self.assert_( "defaultchannel" in conf )
def testAddrPortUnique( self ):
try:
@ -58,22 +59,22 @@ class InstancesHandling( TestCase ):
name="#another unit testing instance#",
addr=self.murmur.addr, port=self.murmur.port,
dbus=settings.DEFAULT_CONN
);
)
if duplicate.ctl.method == "ICE":
import Murmur
self.assertRaises( Murmur.ServerFailureException, duplicate.save );
self.assertRaises( Murmur.ServerFailureException, duplicate.save )
elif self.murmur.version[:2] == [ 1, 2 ]:
from dbus import DBusException
self.assertRaises( DBusException, duplicate.save );
self.assertRaises( DBusException, duplicate.save )
else:
from sqlite3 import IntegrityError
self.assertRaises( IntegrityError, duplicate.save );
self.assertRaises( IntegrityError, duplicate.save )
finally:
# make sure the duplicate is removed
duplicate.ctl.deleteServer( duplicate.srvid );
duplicate.ctl.deleteServer( duplicate.srvid )
def tearDown( self ):
self.murmur.delete();
self.murmur.delete()
class DataReading( TestCase ):
@ -84,125 +85,125 @@ class DataReading( TestCase ):
# Murmur database like the one I have.
# I definitely need to prepare Murmur somehow before running these tests.
# Just don't yet know how.
self.murmur = Mumble.objects.get(id=1);
self.murmur = Mumble.objects.get(id=1)
def testCtlGetChannels( self ):
""" Test getChannels() """
channels = self.murmur.ctl.getChannels( self.murmur.srvid );
channels = self.murmur.ctl.getChannels( self.murmur.srvid )
if self.murmur.ctl.method == "ICE":
import Murmur
self.assertEquals( type( channels[0] ), Murmur.Channel );
self.assertEquals( type( channels[0] ), Murmur.Channel )
else:
self.assertEquals( type( channels[0] ), ObjectInfo );
self.assertEquals( type( channels[0] ), ObjectInfo )
self.assert_( hasattr( channels[0], "id" ) );
self.assert_( hasattr( channels[0], "name" ) );
self.assert_( hasattr( channels[0], "parent" ) );
self.assert_( hasattr( channels[0], "links" ) );
self.assert_( hasattr( channels[0], "id" ) )
self.assert_( hasattr( channels[0], "name" ) )
self.assert_( hasattr( channels[0], "parent" ) )
self.assert_( hasattr( channels[0], "links" ) )
def testCtlGetPlayers( self ):
""" Test getPlayers() """
players = self.murmur.ctl.getPlayers( self.murmur.srvid );
players = self.murmur.ctl.getPlayers( self.murmur.srvid )
self.assert_( len(players) > 0 );
self.assert_( len(players) > 0 )
self.assertEquals( type(players), dict );
self.assertEquals( type(players), dict )
for plidx in players:
player = players[plidx];
player = players[plidx]
if self.murmur.ctl.method == "ICE" and self.murmur.version[:2] == ( 1, 2 ):
import Murmur
self.assertEquals( type( player ), Murmur.User );
self.assertEquals( type( player ), Murmur.User )
else:
self.assertEquals( type( player ), ObjectInfo );
self.assertEquals( type( player ), ObjectInfo )
self.assert_( hasattr( player, "session" ) );
self.assert_( hasattr( player, "mute" ) );
self.assert_( hasattr( player, "deaf" ) );
self.assert_( hasattr( player, "selfMute" ) );
self.assert_( hasattr( player, "selfDeaf" ) );
self.assert_( hasattr( player, "channel" ) );
self.assert_( hasattr( player, "userid" ) );
self.assert_( hasattr( player, "name" ) );
self.assert_( hasattr( player, "onlinesecs" ) );
self.assert_( hasattr( player, "bytespersec" ) );
self.assert_( hasattr( player, "session" ) )
self.assert_( hasattr( player, "mute" ) )
self.assert_( hasattr( player, "deaf" ) )
self.assert_( hasattr( player, "selfMute" ) )
self.assert_( hasattr( player, "selfDeaf" ) )
self.assert_( hasattr( player, "channel" ) )
self.assert_( hasattr( player, "userid" ) )
self.assert_( hasattr( player, "name" ) )
self.assert_( hasattr( player, "onlinesecs" ) )
self.assert_( hasattr( player, "bytespersec" ) )
def testCtlGetRegisteredPlayers( self ):
""" Test getRegistredPlayers() and getRegistration() """
players = self.murmur.ctl.getRegisteredPlayers( self.murmur.srvid );
players = self.murmur.ctl.getRegisteredPlayers( self.murmur.srvid )
self.assert_( len(players) > 0 );
self.assert_( len(players) > 0 )
self.assertEquals( type(players), dict );
self.assertEquals( type(players), dict )
for plidx in players:
player = players[plidx];
player = players[plidx]
self.assertEquals( type( player ), ObjectInfo );
self.assertEquals( type( player ), ObjectInfo )
self.assert_( hasattr( player, "userid" ) );
self.assert_( hasattr( player, "name" ) );
self.assert_( hasattr( player, "email" ) );
self.assert_( hasattr( player, "pw" ) );
self.assert_( hasattr( player, "userid" ) )
self.assert_( hasattr( player, "name" ) )
self.assert_( hasattr( player, "email" ) )
self.assert_( hasattr( player, "pw" ) )
# compare with getRegistration result
reg = self.murmur.ctl.getRegistration( self.murmur.srvid, player.userid );
reg = self.murmur.ctl.getRegistration( self.murmur.srvid, player.userid )
self.assertEquals( type( reg ), ObjectInfo );
self.assertEquals( type( reg ), ObjectInfo )
self.assert_( hasattr( reg, "userid" ) );
self.assert_( hasattr( reg, "name" ) );
self.assert_( hasattr( reg, "email" ) );
self.assert_( hasattr( reg, "pw" ) );
self.assert_( hasattr( reg, "userid" ) )
self.assert_( hasattr( reg, "name" ) )
self.assert_( hasattr( reg, "email" ) )
self.assert_( hasattr( reg, "pw" ) )
self.assertEquals( player.userid, reg.userid );
self.assertEquals( player.name, reg.name );
self.assertEquals( player.email, reg.email );
self.assertEquals( player.pw, reg.pw );
self.assertEquals( player.userid, reg.userid )
self.assertEquals( player.name, reg.name )
self.assertEquals( player.email, reg.email )
self.assertEquals( player.pw, reg.pw )
def testCtlGetAcl( self ):
""" Test getACL() for the root channel """
acls, groups, inherit = self.murmur.ctl.getACL( self.murmur.srvid, 0 );
acls, groups, inherit = self.murmur.ctl.getACL( self.murmur.srvid, 0 )
for rule in acls:
if self.murmur.ctl.method == "ICE" and self.murmur.version[:2] == ( 1, 2 ):
import Murmur
self.assertEquals( type( rule ), Murmur.ACL );
self.assertEquals( type( rule ), Murmur.ACL )
else:
self.assertEquals( type( rule ), ObjectInfo );
self.assertEquals( type( rule ), ObjectInfo )
self.assert_( hasattr( rule, "applyHere" ) );
self.assert_( hasattr( rule, "applySubs" ) );
self.assert_( hasattr( rule, "inherited" ) );
self.assert_( hasattr( rule, "userid" ) );
self.assert_( hasattr( rule, "group" ) );
self.assert_( hasattr( rule, "allow" ) );
self.assert_( hasattr( rule, "deny" ) );
self.assert_( hasattr( rule, "applyHere" ) )
self.assert_( hasattr( rule, "applySubs" ) )
self.assert_( hasattr( rule, "inherited" ) )
self.assert_( hasattr( rule, "userid" ) )
self.assert_( hasattr( rule, "group" ) )
self.assert_( hasattr( rule, "allow" ) )
self.assert_( hasattr( rule, "deny" ) )
for grp in groups:
if self.murmur.ctl.method == "ICE":
import Murmur
self.assertEquals( type( grp ), Murmur.Group );
self.assertEquals( type( grp ), Murmur.Group )
else:
self.assertEquals( type( grp ), ObjectInfo );
self.assert_( hasattr( grp, "name" ) );
self.assert_( hasattr( grp, "inherited" ) );
self.assert_( hasattr( grp, "inherit" ) );
self.assert_( hasattr( grp, "inheritable" ) );
self.assert_( hasattr( grp, "add" ) );
self.assert_( hasattr( grp, "remove" ) );
self.assert_( hasattr( grp, "members" ) );
self.assertEquals( type( grp ), ObjectInfo )
self.assert_( hasattr( grp, "name" ) )
self.assert_( hasattr( grp, "inherited" ) )
self.assert_( hasattr( grp, "inherit" ) )
self.assert_( hasattr( grp, "inheritable" ) )
self.assert_( hasattr( grp, "add" ) )
self.assert_( hasattr( grp, "remove" ) )
self.assert_( hasattr( grp, "members" ) )

1
pyweb/mumble/urls.py

@ -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>

13
pyweb/mumble/utils.py

@ -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>
@ -18,19 +19,19 @@ class ObjectInfo( object ):
""" Wraps arbitrary information to be easily accessed. """
def __init__( self, **kwargs ):
self.__dict__ = kwargs;
self.__dict__ = kwargs
def __str__( self ):
return unicode( self );
return unicode( self )
def __repr__( self ):
return unicode( self );
return unicode( self )
def __unicode__( self ):
return unicode( self.__dict__ );
return unicode( self.__dict__ )
def __contains__( self, name ):
return name in self.__dict__;
return name in self.__dict__
def __getitem__( self, name ):
return self.__dict__[name];
return self.__dict__[name]

208
pyweb/mumble/views.py

@ -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>
@ -21,12 +22,11 @@ from PIL import Image
from django.shortcuts import render_to_response, get_object_or_404, get_list_or_404
from django.template import RequestContext
from django.http import Http404, HttpResponse, HttpResponseRedirect
from django.conf import settings
from django.contrib.auth.decorators import login_required
from django.contrib.auth.models import User
from django.conf import settings
from django.core.urlresolvers import reverse
from django.contrib.auth import views as auth_views
from django.core.urlresolvers import reverse
from models import Mumble, MumbleUser
from forms import MumbleForm, MumbleUserForm, MumbleUserPasswordForm
@ -55,24 +55,24 @@ def redir( request ):
"IEMobile" in request.META['HTTP_USER_AGENT'] or \
"iPod" in request.META['HTTP_USER_AGENT'] or \
"iPhone" in request.META['HTTP_USER_AGENT']:
return HttpResponseRedirect( reverse( mobile_mumbles ) );
return HttpResponseRedirect( reverse( mobile_mumbles ) )
else:
return HttpResponseRedirect( reverse( mumbles ) );
return HttpResponseRedirect( reverse( mumbles ) )
def mobile_mumbles( request ):
return mumbles( request, mobile=True );
return mumbles( request, mobile=True )
def mumbles( request, mobile=False ):
""" Display a list of all configured Mumble servers, or redirect if only one configured. """
mms = Mumble.objects.all().order_by( "name" );
mms = Mumble.objects.all().order_by( "name" )
if len(mms) == 1:
return HttpResponseRedirect( reverse(
{ False: show, True: mobile_show }[mobile],
kwargs={ 'server': mms[0].id, }
) );
) )
return render_to_response(
'mumble/%s.html' % { False: 'list', True: 'mobile_list' }[mobile],
@ -80,7 +80,7 @@ def mumbles( request, mobile=False ):
'MumbleActive': True,
},
context_instance = RequestContext(request)
);
)
def show( request, server ):
@ -90,116 +90,114 @@ def show( request, server ):
server admin and user texture form as well. The template then uses JavaScript
to display these forms integrated into the Channel viewer.
"""
srv = get_object_or_404( Mumble, id=server );
srv = get_object_or_404( Mumble, id=server )
if not srv.booted:
return render_to_response(
'mumble/offline.html',
{ 'DBaseObject': srv,
'MumbleActive': True,
}, context_instance = RequestContext(request) );
}, context_instance = RequestContext(request) )
isAdmin = srv.isUserAdmin( request.user );
isAdmin = srv.isUserAdmin( request.user )
# The tab to start on.
displayTab = 0;
displayTab = 0
if isAdmin:
if request.method == 'POST' and "mode" in request.POST and request.POST['mode'] == 'admin':
adminform = MumbleForm( request.POST, instance=srv );
adminform = MumbleForm( request.POST, instance=srv )
if adminform.is_valid():
adminform.save();
return HttpResponseRedirect( reverse( show, kwargs={ 'server': int(server), } ) );
adminform.save()
return HttpResponseRedirect( reverse( show, kwargs={ 'server': int(server), } ) )
else:
displayTab = 2;
displayTab = 2
else:
adminform = MumbleForm( instance=srv );
adminform = MumbleForm( instance=srv )
else:
adminform = None;
adminform = None
registered = False;
user = None;
registered = False
user = None
if request.user.is_authenticated():
# Unregistered users may or may not need a password to register.
if settings.PROTECTED_MODE and srv.passwd:
unregged_user_form = MumbleUserPasswordForm;
unregged_user_form = MumbleUserPasswordForm
# Unregistered users may or may not want to link an existing account
elif settings.ALLOW_ACCOUNT_LINKING:
unregged_user_form = MumbleUserLinkForm;
unregged_user_form = MumbleUserLinkForm
else:
unregged_user_form = MumbleUserForm;
unregged_user_form = MumbleUserForm
if request.method == 'POST' and 'mode' in request.POST and request.POST['mode'] == 'reg':
try:
user = MumbleUser.objects.get( server=srv, owner=request.user );
user = MumbleUser.objects.get( server=srv, owner=request.user )
except MumbleUser.DoesNotExist:
regform = unregged_user_form( request.POST );
regform.server = srv;
regform = unregged_user_form( request.POST )
regform.server = srv
if regform.is_valid():
model = regform.save( commit=False );
model.owner = request.user;
model.server = srv;
model = regform.save( commit=False )
model.owner = request.user
model.server = srv
# If we're linking accounts, the change is local only.
model.save( dontConfigureMurmur=( "linkacc" in regform.data ) );
return HttpResponseRedirect( reverse( show, kwargs={ 'server': int(server), } ) );
model.save( dontConfigureMurmur=( "linkacc" in regform.data ) )
return HttpResponseRedirect( reverse( show, kwargs={ 'server': int(server), } ) )
else:
displayTab = 1;
displayTab = 1
else:
regform = MumbleUserForm( request.POST, instance=user );
regform.server = srv;
regform = MumbleUserForm( request.POST, instance=user )
regform.server = srv
if regform.is_valid():
regform.save();
return HttpResponseRedirect( reverse( show, kwargs={ 'server': int(server), } ) );
regform.save()
return HttpResponseRedirect( reverse( show, kwargs={ 'server': int(server), } ) )
else:
displayTab = 1;
displayTab = 1
else:
try:
user = MumbleUser.objects.get( server=srv, owner=request.user );
user = MumbleUser.objects.get( server=srv, owner=request.user )
except MumbleUser.DoesNotExist:
regform = unregged_user_form();
regform = unregged_user_form()
else:
regform = MumbleUserForm( instance=user );
registered = True;
regform = MumbleUserForm( instance=user )
registered = True
if request.method == 'POST' and 'mode' in request.POST and request.POST['mode'] == 'texture' and registered:
textureform = MumbleTextureForm( request.POST, request.FILES );
textureform = MumbleTextureForm( request.POST, request.FILES )
if textureform.is_valid():
if 'usegravatar' in textureform.cleaned_data and textureform.cleaned_data['usegravatar'] and user.gravatar:
user.setTextureFromUrl( user.gravatar );
user.setTextureFromUrl( user.gravatar )
elif 'texturefile' in request.FILES:
user.setTexture( Image.open( request.FILES['texturefile'] ) );
return HttpResponseRedirect( reverse( show, kwargs={ 'server': int(server), } ) );
user.setTexture( Image.open( request.FILES['texturefile'] ) )
return HttpResponseRedirect( reverse( show, kwargs={ 'server': int(server), } ) )
else:
textureform = MumbleTextureForm();
textureform = MumbleTextureForm()
else:
regform = None;
textureform = None;
regform = None
textureform = None
if isAdmin:
if request.method == 'POST' and 'mode' in request.POST:
if request.POST['mode'] == 'kick':
kickform = MumbleKickForm( request.POST );
kickform = MumbleKickForm( request.POST )
if kickform.is_valid():
if kickform.cleaned_data["ban"]:
srv.banUser( kickform.cleaned_data['session'], kickform.cleaned_data['reason'] );
srv.kickUser( kickform.cleaned_data['session'], kickform.cleaned_data['reason'] );
srv.banUser( kickform.cleaned_data['session'], kickform.cleaned_data['reason'] )
srv.kickUser( kickform.cleaned_data['session'], kickform.cleaned_data['reason'] )
# ChannelTable is a somewhat misleading name, as it actually contains channels and players.
channelTable = [];
channelTable = []
for cid in srv.channels:
if cid != 0 and srv.channels[cid].show:
channelTable.append( srv.channels[cid] );
channelTable.append( srv.channels[cid] )
for pid in srv.players:
channelTable.append( srv.players[pid] );
channelTable.append( srv.players[pid] )
show_url = reverse( show, kwargs={ 'server': srv.id } );
login_url = reverse( auth_views.login );
show_url = reverse( show, kwargs={ 'server': srv.id } )
login_url = reverse( auth_views.login )
return render_to_response(
'mumble/mumble.html',
{
return render_to_response( 'mumble/mumble.html', {
'login_url': "%s?next=%s" % ( login_url, show_url ),
'DBaseObject': srv,
'ChannelTable': channelTable,
@ -211,33 +209,25 @@ def show( request, server ):
'DisplayTab': displayTab,
'MumbleActive': True,
'MumbleAccount':user,
},
context_instance = RequestContext(request)
);
}, context_instance = RequestContext(request) )
def mobile_show( request, server ):
""" Display the channel list for the given Server ID. """
srv = get_object_or_404( Mumble, id=server );
srv = get_object_or_404( Mumble, id=server )
user = None;
user = None
if request.user.is_authenticated():
try:
user = MumbleUser.objects.get( server=srv, owner=request.user );
user = MumbleUser.objects.get( server=srv, owner=request.user )
except MumbleUser.DoesNotExist:
pass;
pass
return render_to_response(
'mumble/mobile_mumble.html',
{
return render_to_response( 'mumble/mobile_mumble.html', {
'DBaseObject': srv,
'MumbleActive': True,
'MumbleAccount':user,
},
context_instance = RequestContext(request)
);
}, context_instance = RequestContext(request) )
def showTexture( request, server, userid ):
@ -246,17 +236,17 @@ def showTexture( request, server, userid ):
If userid is none, use the currently logged in User.
"""
srv = get_object_or_404( Mumble, id=int(server) );
user = get_object_or_404( MumbleUser, server=srv, id=int(userid) );
srv = get_object_or_404( Mumble, id=int(server) )
user = get_object_or_404( MumbleUser, server=srv, id=int(userid) )
try:
img = user.getTexture();
img = user.getTexture()
except ValueError:
raise Http404();
raise Http404()
else:
buf = StringIO();
img.save( buf, "PNG" );
return HttpResponse( buf.getvalue(), "image/png" );
buf = StringIO()
img.save( buf, "PNG" )
return HttpResponse( buf.getvalue(), "image/png" )
@login_required
@ -266,40 +256,40 @@ def users( request, server ):
If the request has a "data" field, evaluate that and update the user records.
"""
srv = get_object_or_404( Mumble, id=int(server) );
srv = get_object_or_404( Mumble, id=int(server) )
if "resync" in request.POST and request.POST['resync'] == "true":
srv.readUsersFromMurmur();
srv.readUsersFromMurmur()
if not srv.isUserAdmin( request.user ):
return HttpResponse(
simplejson.dumps({ 'success': False, 'objects': [], 'errormsg': 'Access denied' }),
mimetype='text/javascript'
);
)
if request.method == 'POST':
data = simplejson.loads( request.POST['data'] );
data = simplejson.loads( request.POST['data'] )
for record in data:
if record['id'] == -1:
if record['delete']:
continue;
mu = MumbleUser( server=srv );
continue
mu = MumbleUser( server=srv )
else:
mu = MumbleUser.objects.get( id=record['id'] );
mu = MumbleUser.objects.get( id=record['id'] )
if record['delete']:
mu.delete();
continue;
mu.delete()
continue
mu.name = record['name'];
mu.password = record['password'];
mu.name = record['name']
mu.password = record['password']
if record['owner']:
mu.owner = User.objects.get( id=int(record['owner']) );
mu.save();
mu.aclAdmin = record['admin'];
mu.owner = User.objects.get( id=int(record['owner']) )
mu.save()
mu.aclAdmin = record['admin']
users = [];
users = []
for mu in srv.mumbleuser_set.all():
owner = None;
owner = None
if mu.owner is not None:
owner = mu.owner.id
@ -309,29 +299,29 @@ def users( request, server ):
'password': None,
'owner': owner,
'admin': mu.aclAdmin,
} );
} )
return HttpResponse(
simplejson.dumps( { 'success': True, 'objects': users } ),
mimetype='text/javascript'
);
)
@login_required
def djangousers( request ):
""" Return a list of all Django users' names and IDs. """
users = [ { 'uid': '', 'uname': '------' } ];
users = [ { 'uid': '', 'uname': '------' } ]
for du in User.objects.all().order_by( 'username' ):
users.append( {
'uid': du.id,
'uname': unicode( du ),
} );
} )
return HttpResponse(
simplejson.dumps( { 'success': True, 'objects': users } ),
mimetype='text/javascript'
);
)
def mmng_tree( request, server ):
@ -343,7 +333,7 @@ def mmng_tree( request, server ):
to "http://<mumble-django base URL>/mumble"
"""
srv = get_object_or_404( Mumble, id=int(server) );
srv = get_object_or_404( Mumble, id=int(server) )
chanlist = []
userlist = []
@ -385,21 +375,21 @@ def mmng_tree( request, server ):
return HttpResponse(
prefix + "(" + simplejson.dumps( { 'channels': chanlist, 'users': userlist } ) + ")",
mimetype='text/javascript'
);
)
def mumbleviewer_tree_xml( request, server ):
""" Get the XML tree from the server and serialize it to the client. """
from xml.etree.cElementTree import tostring as xml_to_string
srv = get_object_or_404( Mumble, id=int(server) );
srv = get_object_or_404( Mumble, id=int(server) )
return HttpResponse(
xml_to_string( srv.asMvXml(), encoding='utf-8' ),
mimetype='text/xml'
);
)
def mumbleviewer_tree_json( request, server ):
""" Get the Dict from the server and serialize it as JSON to the client. """
srv = get_object_or_404( Mumble, id=int(server) );
srv = get_object_or_404( Mumble, id=int(server) )
if "jsonp_callback" in request.GET:
prefix = request.GET["jsonp_callback"]
@ -409,4 +399,4 @@ def mumbleviewer_tree_json( request, server ):
return HttpResponse(
prefix + "(" + simplejson.dumps( srv.asMvJson() ) + ")",
mimetype='text/javascript'
);
)

1
pyweb/processors.py

@ -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>

13
pyweb/settings.py

@ -1,4 +1,5 @@
# -*- coding: utf-8 -*-
# kate: space-indent on; indent-width 4; replace-tabs on;
# Django settings for mumble_django project.
"""
@ -56,7 +57,7 @@ MUMBLE_DJANGO_ROOT = None ##
from os.path import join, dirname, abspath, exists
if not MUMBLE_DJANGO_ROOT or not exists( MUMBLE_DJANGO_ROOT ):
MUMBLE_DJANGO_ROOT = dirname(dirname(abspath(__file__)));
MUMBLE_DJANGO_ROOT = dirname(dirname(abspath(__file__)))
# URL Template for constructing Gravatars.
GRAVATAR_URL = 'http://www.gravatar.com/avatar/%(hash)s.jpg?d=monsterid&s=%(size)d'
@ -155,8 +156,8 @@ MEDIA_URL = MUMBLE_DJANGO_URL+'static/'
ADMIN_MEDIA_PREFIX = MUMBLE_DJANGO_URL+'media/'
# URL to the login view
LOGIN_URL = MUMBLE_DJANGO_URL + 'accounts/login';
LOGIN_REDIRECT_URL = MUMBLE_DJANGO_URL + 'accounts/profile';
LOGIN_URL = MUMBLE_DJANGO_URL + 'accounts/login'
LOGIN_REDIRECT_URL = MUMBLE_DJANGO_URL + 'accounts/profile'
# Automatically generate a .secret.txt file containing the SECRET_KEY.
@ -210,10 +211,10 @@ TEMPLATE_CONTEXT_PROCESSORS = (
)
TEST_RUNNER = 'mumble.testrunner.run_tests'
TEST_MURMUR_LAB_DIR = join( dirname(MUMBLE_DJANGO_ROOT), 'murmur' );
TEST_MURMUR_FILES_DIR = join( MUMBLE_DJANGO_ROOT, 'testdata' );
TEST_MURMUR_LAB_DIR = join( dirname(MUMBLE_DJANGO_ROOT), 'murmur' )
TEST_MURMUR_FILES_DIR = join( MUMBLE_DJANGO_ROOT, 'testdata' )
CONVERSIONSQL_ROOT = join( MUMBLE_DJANGO_ROOT, "pyweb", "mumble", "conversionsql" );
CONVERSIONSQL_ROOT = join( MUMBLE_DJANGO_ROOT, "pyweb", "mumble", "conversionsql" )
INSTALLED_APPS = [
'django.contrib.auth',

1
pyweb/urls.py

@ -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>

7
pyweb/views.py

@ -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>
@ -25,13 +26,13 @@ def profile( request ):
userdata = {
"ProfileActive": True,
"mumbleaccs": MumbleUser.objects.filter( owner = request.user ),
};
}
return render_to_response(
'registration/profile.html',
userdata,
context_instance = RequestContext(request)
);
)
def imprint( request ):
@ -39,4 +40,4 @@ def imprint( request ):
return render_to_response(
'registration/imprint.html',
{ 'upstreamversion': mumble.getLatestUpstreamVersion() },
context_instance = RequestContext(request) );
context_instance = RequestContext(request) )
Loading…
Cancel
Save