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 -*- # -*- coding: utf-8 -*-
# kate: space-indent on; indent-width 4; replace-tabs on;
""" """
* Copyright (C) 2009, Michael "Svedrin" Ziegler <diese-addy@funzt-halt.net> * 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. # 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 ### ### DO NOT CHANGE ANYTHING BELOW THIS LINE ###
@ -25,7 +26,7 @@ from os.path import join, dirname, abspath, exists
# Path auto-detection # Path auto-detection
if not MUMBLE_DJANGO_ROOT or not exists( MUMBLE_DJANGO_ROOT ): 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 # environment variables
sys.path.append( MUMBLE_DJANGO_ROOT ) sys.path.append( MUMBLE_DJANGO_ROOT )
@ -54,314 +55,298 @@ locale.setlocale(locale.LC_ALL, '')
class BaseWindow( object ): class BaseWindow( object ):
tabName = "tehBasez";
tabName = "tehBasez"
def __init__( self, parentwin, mumble, pos_x, pos_y ): 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 ): def draw( self ):
self.win.addstr( 1, 1, self.tabName );
self.win.addstr( 1, 1, self.tabName )
def border( self ): def border( self ):
self.win.border();
self.win.border()
def enter( self ): def enter( self ):
while( True ): while( True ):
key = self.win.getch();
key = self.win.getch()
if key == curses.KEY_UP: if key == curses.KEY_UP:
return;
return
class WndChannels( BaseWindow ): class WndChannels( BaseWindow ):
tabName = 'Channels';
tabName = 'Channels'
def printItem( self, item, level ): def printItem( self, item, level ):
namestr = "";
namestr = ""
if item.is_server or item.is_channel: if item.is_server or item.is_channel:
namestr = "%s (Channel)" % item.name;
namestr = "%s (Channel)" % item.name
else: else:
namestr = "%s (Player)" % item.name namestr = "%s (Player)" % item.name
self.win.addstr( self.curr_y, 4*level+1, namestr.encode(locale.getpreferredencoding()) ) self.win.addstr( self.curr_y, 4*level+1, namestr.encode(locale.getpreferredencoding()) )
self.curr_y += 1;
self.curr_y += 1
def draw( self ): 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 ): 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 ): 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 ): def getFieldHeight( self, field ):
if isinstance( field, models.TextField ): if isinstance( field, models.TextField ):
return 10;
return 1;
return 10
return 1
def getFieldYPos( self, field ): def getFieldYPos( self, field ):
ypos = 3;
ypos = 3
for curr_field in self.fields: for curr_field in self.fields:
if curr_field is field: 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 ): def draw( self ):
curr_y = 3;
curr_y = 3
for field in self.fields: 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 ): def enter( self ):
self.selIdx = 0;
self.selMax = len( self.fields ) - 1;
self.selIdx = 0
self.selMax = len( self.fields ) - 1
while( True ): while( True ):
# Highlight selected field label # Highlight selected field label
field = self.fields[self.selIdx];
field = self.fields[self.selIdx]
self.win.addstr( self.win.addstr(
self.getFieldYPos(field), 1, self.getFieldYPos(field), 1,
field.verbose_name.encode(locale.getpreferredencoding()), field.verbose_name.encode(locale.getpreferredencoding()),
curses.A_STANDOUT curses.A_STANDOUT
);
self.win.refresh();
)
self.win.refresh()
key = self.win.getch();
key = self.win.getch()
if key == curses.KEY_UP: if key == curses.KEY_UP:
if self.selIdx > 0: if self.selIdx > 0:
self.selIdx -= 1;
self.selIdx -= 1
else: else:
return;
return
elif key == curses.KEY_DOWN and self.selIdx < self.selMax: elif key == curses.KEY_DOWN and self.selIdx < self.selMax:
self.selIdx += 1;
self.selIdx += 1
elif key in ( ord('q'), ord('Q') ): elif key in ( ord('q'), ord('Q') ):
return;
return
elif key in ( ord('s'), ord('S') ): elif key in ( ord('s'), ord('S') ):
try: try:
self.mm.save();
self.mm.save()
except Exception, instance: except Exception, instance:
msg = unicode( instance );
msg = unicode( instance )
else: 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') ): elif key in ( curses.KEY_RIGHT, curses.KEY_ENTER, ord('\n') ):
valid = False;
valid = False
while not valid: while not valid:
self.editors[field.name][1].edit();
self.editors[field.name][1].edit()
try: try:
setattr( self.mm, field.name, setattr( self.mm, field.name,
field.to_python( self.editors[field.name][1].gather().strip() ) field.to_python( self.editors[field.name][1].gather().strip() )
);
)
except ValidationError, instance: 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: 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.win.addstr(
self.getFieldYPos(field), 1, self.getFieldYPos(field), 1,
field.verbose_name.encode(locale.getpreferredencoding()) field.verbose_name.encode(locale.getpreferredencoding())
);
)
class WndUsers( BaseWindow ): class WndUsers( BaseWindow ):
tabName = 'Registered users';
tabName = 'Registered users'
def draw( self ): def draw( self ):
curr_y = 3;
curr_y = 3
for acc in self.mm.mumbleuser_set.all(): 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 ): class MumbleForm( object ):
def __init__( self, parentwin, mumble, pos_x, pos_y ): 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 = ( self.windows = (
WndChannels( self.win, mumble, pos_x + 2, pos_y + 2 ), WndChannels( self.win, mumble, pos_x + 2, pos_y + 2 ),
WndSettings( 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 ), 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 ): def mvwin( self, pos_x, pos_y ):
self.win.mvwin( pos_y, pos_x );
self.win.mvwin( pos_y, pos_x )
def mvdefault( self ): def mvdefault( self ):
self.win.mvwin( self.pos[1], self.pos[0] );
self.win.mvwin( self.pos[1], self.pos[0] )
def draw( self ): 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 ): def drawTabs( self ):
first = True;
first = True
for subwin in self.windows: 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: 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: else:
self.win.addstr( "%-20s" % subwin.tabName, flags );
self.win.addstr( "%-20s" % subwin.tabName, flags )
def enter( self ): def enter( self ):
self.drawTabs();
self.currwin.draw();
self.currwin.border();
self.drawTabs()
self.currwin.draw()
self.currwin.border()
while( True ): while( True ):
key = self.win.getch();
key = self.win.getch()
if key == curses.KEY_LEFT and self.curridx > 0: 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: 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 ): elif key in ( ord('q'), ord('Q'), curses.KEY_UP ):
return;
return
elif key in ( curses.KEY_ENTER, curses.KEY_DOWN, ord('\n') ): 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 ): 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" ): 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 ): 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 # 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: 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: 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') ): 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: for mwin in mumbles:
mwin.draw();
mwin.draw()
elif key in ( ord('q'), ord('Q') ): 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__': 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 # Path auto-detection
if not MUMBLE_DJANGO_ROOT or not exists( MUMBLE_DJANGO_ROOT ): 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 # environment variables
sys.path.append( MUMBLE_DJANGO_ROOT ) sys.path.append( MUMBLE_DJANGO_ROOT )

23
munin.py

@ -1,5 +1,6 @@
#!/usr/bin/python
#!/usr/bin/env python
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# kate: space-indent on; indent-width 4; replace-tabs on;
""" """
* Copyright (C) 2009, Michael "Svedrin" Ziegler <diese-addy@funzt-halt.net> * 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. # 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 ### ### DO NOT CHANGE ANYTHING BELOW THIS LINE ###
@ -25,7 +26,7 @@ from os.path import join, dirname, abspath, exists
# Path auto-detection # Path auto-detection
if not MUMBLE_DJANGO_ROOT or not exists( MUMBLE_DJANGO_ROOT ): 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 # environment variables
sys.path.append( MUMBLE_DJANGO_ROOT ) sys.path.append( MUMBLE_DJANGO_ROOT )
@ -67,29 +68,29 @@ if sys.argv[-1] == 'config':
print "graph_category", categ print "graph_category", categ
for mumble in get_running_instances(): 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: if mumble.connecturl:
print "srv%d.info %s" % ( mumble.id, mumble.connecturl );
print "srv%d.info %s" % ( mumble.id, mumble.connecturl )
if mumble.users: 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': elif sys.argv[-1] == 'autoconf':
if Mumble.objects.count() == 0: if Mumble.objects.count() == 0:
print "no (no servers configured)";
print "no (no servers configured)"
else: else:
# check if connecting works # check if connecting works
try: try:
for mumble in get_running_instances(): for mumble in get_running_instances():
mumble.ctl mumble.ctl
except Exception, instance: 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: else:
print "yes";
print "yes"
else: else:
for mumble in get_running_instances(): 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 -*- # -*- coding: utf-8 -*-
""" """

1
pyweb/mucli.py

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

133
pyweb/mumble/MumbleCtlDbus.py

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

181
pyweb/mumble/MumbleCtlIce.py

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

1
pyweb/mumble/__init__.py

@ -1,4 +1,5 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# kate: space-indent on; indent-width 4; replace-tabs on;
""" """
* Copyright © 2009-2010, Michael "Svedrin" Ziegler <diese-addy@funzt-halt.net> * Copyright © 2009-2010, Michael "Svedrin" Ziegler <diese-addy@funzt-halt.net>
* *

51
pyweb/mumble/admin.py

@ -1,4 +1,5 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# kate: space-indent on; indent-width 4; replace-tabs on;
""" """
* Copyright © 2009-2010, Michael "Svedrin" Ziegler <diese-addy@funzt-halt.net> * 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. """ """ Specification for the "Server administration" admin section. """
list_display = [ 'name', 'srvid', 'get_addr', 'get_port', 'get_murmur_online', 'get_booted', 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 ): def get_murmur_online( self, obj ):
return obj.server.online return obj.server.online
@ -81,53 +82,53 @@ class MumbleAdmin(admin.ModelAdmin):
def get_users_regged( self, obj ): def get_users_regged( self, obj ):
""" Populates the "Registered users" column. """ """ Populates the "Registered users" column. """
if obj.booted: if obj.booted:
return obj.users_regged;
return obj.users_regged
else: else:
return '-';
return '-'
get_users_regged.short_description = _( 'Registered users' );
get_users_regged.short_description = _( 'Registered users' )
def get_users_online( self, obj ): def get_users_online( self, obj ):
""" Populates the "Online users" column. """ """ Populates the "Online users" column. """
if obj.booted: if obj.booted:
return obj.users_online;
return obj.users_online
else: else:
return '-';
return '-'
get_users_online.short_description = _( 'Online users' );
get_users_online.short_description = _( 'Online users' )
def get_channel_count( self, obj ): def get_channel_count( self, obj ):
""" Populates the "Channel Count" column. """ """ Populates the "Channel Count" column. """
if obj.booted: if obj.booted:
return obj.channel_cnt;
return obj.channel_cnt
else: else:
return '-';
return '-'
get_channel_count.short_description = _( 'Channel count' );
get_channel_count.short_description = _( 'Channel count' )
def get_is_public( self, obj ): def get_is_public( self, obj ):
""" Populates the "Public" column. """ """ Populates the "Public" column. """
if obj.booted: if obj.booted:
if obj.is_public: if obj.is_public:
return _( 'Yes' );
return _( 'Yes' )
else: else:
return _( 'No' );
return _( 'No' )
else: else:
return '-';
return '-'
get_is_public.short_description = _( 'Public' );
get_is_public.short_description = _( 'Public' )
class MumbleUserAdmin(admin.ModelAdmin): class MumbleUserAdmin(admin.ModelAdmin):
""" Specification for the "Registered users" admin section. """ """ 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 form = MumbleUserAdminForm
@ -140,6 +141,6 @@ class MumbleUserAdmin(admin.ModelAdmin):
get_acl_admin.boolean = True 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 -*- # -*- coding: utf-8 -*-
# kate: space-indent on; indent-width 4; replace-tabs on;
""" """
* Copyright © 2009-2010, Michael "Svedrin" Ziegler <diese-addy@funzt-halt.net> * Copyright © 2009-2010, Michael "Svedrin" Ziegler <diese-addy@funzt-halt.net>
@ -32,7 +33,7 @@ class PropertyModelForm( ModelForm ):
""" """
def __init__( self, *args, **kwargs ): def __init__( self, *args, **kwargs ):
ModelForm.__init__( self, *args, **kwargs );
ModelForm.__init__( self, *args, **kwargs )
if self.instance: if self.instance:
instfields = self.instance._meta.get_all_field_names() instfields = self.instance._meta.get_all_field_names()
@ -112,8 +113,8 @@ class MumbleForm( PropertyModelForm ):
self.fields['defchan'].choices = choices self.fields['defchan'].choices = choices
class Meta: class Meta:
model = Mumble;
fields = ['name'];
model = Mumble
fields = ['name']
class MumbleAdminForm( MumbleForm ): class MumbleAdminForm( MumbleForm ):
@ -134,7 +135,7 @@ class MumbleAdminForm( MumbleForm ):
def clean_port( self ): def clean_port( self ):
""" Check if the port number is valid. """ """ 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 is not None and port != '':
if port < 1 or port >= 2**16: if port < 1 or port >= 2**16:
@ -143,8 +144,8 @@ class MumbleAdminForm( MumbleForm ):
'portno': port, 'portno': port,
'minrange': 1, 'minrange': 1,
'maxrange': 2**16, 'maxrange': 2**16,
});
return port;
})
return port
return None return None
@ -174,36 +175,36 @@ class MumbleUserForm( ModelForm ):
password = forms.CharField( widget=forms.PasswordInput, required=False ) password = forms.CharField( widget=forms.PasswordInput, required=False )
def __init__( self, *args, **kwargs ): 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 ): def clean_name( self ):
""" Check if the desired name is forbidden or taken. """ """ Check if the desired name is forbidden or taken. """
name = self.cleaned_data['name'];
name = self.cleaned_data['name']
if self.server is None: if self.server is None:
raise AttributeError( "You need to set the form's server attribute to the server instance " 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: 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: 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 ): def clean_password( self ):
""" Verify a password has been given. """ """ 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 ): 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: class Meta:
model = MumbleUser;
fields = ( 'name', 'password' );
model = MumbleUser
fields = ( 'name', 'password' )
class MumbleUserPasswordForm( MumbleUserForm ): class MumbleUserPasswordForm( MumbleUserForm ):
@ -213,21 +214,21 @@ class MumbleUserPasswordForm( MumbleUserForm ):
label=_('Server Password'), label=_('Server Password'),
help_text=_('This server is private and protected mode is active. Please enter the server password.'), help_text=_('This server is private and protected mode is active. Please enter the server password.'),
widget=forms.PasswordInput(render_value=False) widget=forms.PasswordInput(render_value=False)
);
)
def clean_serverpw( self ): def clean_serverpw( self ):
""" Validate the password """ """ Validate the password """
serverpw = self.cleaned_data['serverpw'];
serverpw = self.cleaned_data['serverpw']
if self.server.passwd != 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 ): def clean( self ):
""" prevent save() from trying to store the password in the Model instance. """ """ 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. # clean() will be called after clean_serverpw(), so it has already been validated here.
if 'serverpw' in self.cleaned_data: 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 ): class MumbleUserLinkForm( MumbleUserForm ):
@ -237,89 +238,89 @@ class MumbleUserLinkForm( MumbleUserForm ):
label=_('Link account'), label=_('Link account'),
help_text=_('The account already exists and belongs to me, just link it instead of creating.'), help_text=_('The account already exists and belongs to me, just link it instead of creating.'),
required=False, required=False,
);
)
def __init__( self, *args, **kwargs ): 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 ): def clean_name( self ):
""" Check if the target account exists in Murmur. """ """ Check if the target account exists in Murmur. """
if 'linkacc' not in self.data: if 'linkacc' not in self.data:
return MumbleUserForm.clean_name( self );
return MumbleUserForm.clean_name( self )
# Check if user exists # 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: 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 ): def clean_password( self ):
""" Verify that the password is correct. """ """ Verify that the password is correct. """
if 'linkacc' not in self.data: if 'linkacc' not in self.data:
return MumbleUserForm.clean_password( self );
return MumbleUserForm.clean_password( self )
if 'name' not in self.cleaned_data: if 'name' not in self.cleaned_data:
# keep clean() from trying to find a user that CAN'T exist # keep clean() from trying to find a user that CAN'T exist
self.mumbleid = -10;
return '';
self.mumbleid = -10
return ''
# Validate password with Murmur # 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 ) self.mumbleid = self.server.ctl.verifyPassword( self.server.srvid, self.cleaned_data['name'], passwd )
if self.mumbleid <= 0: 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 ): def clean( self ):
""" Create the MumbleUser instance to save in. """ """ Create the MumbleUser instance to save in. """
if 'linkacc' not in self.data or self.mumbleid <= 0: if 'linkacc' not in self.data or self.mumbleid <= 0:
return self.cleaned_data;
return self.cleaned_data
try: 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: 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: else:
if m_user.owner is not None: 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: 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 ): class MumbleUserAdminForm( PropertyModelForm ):
aclAdmin = forms.BooleanField( required=False );
aclAdmin = forms.BooleanField( required=False )
password = forms.CharField( widget=forms.PasswordInput, required=False ) password = forms.CharField( widget=forms.PasswordInput, required=False )
def clean_password( self ): def clean_password( self ):
""" Verify a password has been given. """ """ 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 ): 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: class Meta:
model = Mumble;
model = Mumble
class MumbleKickForm( Form ): 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 ): class MumbleTextureForm( Form ):
""" The form used to upload a new image to be set as texture. """ """ 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 -*- # -*- coding: utf-8 -*-
# kate: space-indent on; indent-width 4; replace-tabs on;
""" """
* Copyright © 2009-2010, Michael "Svedrin" Ziegler <diese-addy@funzt-halt.net> * Copyright © 2009-2010, Michael "Svedrin" Ziegler <diese-addy@funzt-halt.net>
@ -49,8 +50,8 @@ if not uptodate:
if settings.DATABASE_ENGINE == "sqlite3": if settings.DATABASE_ENGINE == "sqlite3":
# backup the db before the conversion. # backup the db before the conversion.
copy( settings.DATABASE_NAME, settings.DATABASE_NAME+".bak" ) 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: 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 -*- # -*- coding: utf-8 -*-
# kate: space-indent on; indent-width 4; replace-tabs on;
""" """
* Copyright © 2009-2010, Michael "Svedrin" Ziegler <diese-addy@funzt-halt.net> * 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 -*- # -*- coding: utf-8 -*-
# kate: space-indent on; indent-width 4; replace-tabs on;
""" """
* Copyright © 2009-2010, Michael "Svedrin" Ziegler <diese-addy@funzt-halt.net> * Copyright © 2009-2010, Michael "Svedrin" Ziegler <diese-addy@funzt-halt.net>
@ -25,7 +26,7 @@ from mumble.models import Mumble
class TestFailed( Exception ): class TestFailed( Exception ):
pass;
pass
class Command( BaseCommand ): class Command( BaseCommand ):
help = "Run a few tests on Mumble-Django's setup." help = "Run a few tests on Mumble-Django's setup."
@ -36,14 +37,14 @@ class Command( BaseCommand ):
except ImportError: except ImportError:
pass pass
else: 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 ): def check_slice( self ):
print "Checking slice file...", print "Checking slice file...",
@ -71,56 +72,56 @@ class Command( BaseCommand ):
def check_rootdir( self ): def check_rootdir( self ):
print "Checking root directory access...", print "Checking root directory access...",
if not os.path.exists( settings.MUMBLE_DJANGO_ROOT ): 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": elif settings.DATABASE_ENGINE != "sqlite3":
print "not using sqlite [ OK ]" print "not using sqlite [ OK ]"
else: else:
statinfo = os.stat( settings.MUMBLE_DJANGO_ROOT );
statinfo = os.stat( settings.MUMBLE_DJANGO_ROOT )
if statinfo.st_uid == 0: if statinfo.st_uid == 0:
raise TestFailed( raise TestFailed(
"The mumble-django root directory belongs to user root. This is " "The mumble-django root directory belongs to user root. This is "
"most certainly not what you want because it will prevent your " "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 ): 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: else:
print "[ OK ]";
print "[ OK ]"
def check_dbase( self ): def check_dbase( self ):
print "Checking database access...", print "Checking database access...",
if settings.DATABASE_ENGINE == "sqlite3": if settings.DATABASE_ENGINE == "sqlite3":
if not os.path.exists( settings.DATABASE_NAME ): 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: else:
statinfo = os.stat( settings.DATABASE_NAME );
statinfo = os.stat( settings.DATABASE_NAME )
if statinfo.st_uid == 0: if statinfo.st_uid == 0:
raise TestFailed( raise TestFailed(
"the database file belongs to root. This is most certainly not what " "the database file belongs to root. This is most certainly not what "
"you want because it will prevent your web server from being able " "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 ): 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: else:
print "[ OK ]";
print "[ OK ]"
else: else:
print "not using sqlite, so I can't check.";
print "not using sqlite, so I can't check."
def check_sites( self ): def check_sites( self ):
print "Checking URL configuration...", print "Checking URL configuration...",
try: try:
site = Site.objects.get_current();
site = Site.objects.get_current()
except Site.DoesNotExist: except Site.DoesNotExist:
try: try:
@ -132,20 +133,20 @@ class Command( BaseCommand ):
"setting. Create a site in your database and rerun this command to fix this error.") "setting. Create a site in your database and rerun this command to fix this error.")
else: else:
print( "none set.\n" 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': if site.domain == 'example.com':
print( "still the default.\n" print( "still the default.\n"
"The domain is configured as example.com, which is the default but does not make sense. " "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 ): def check_admins( self ):
@ -153,23 +154,23 @@ class Command( BaseCommand ):
for user in User.objects.all(): for user in User.objects.all():
if user.is_superuser: if user.is_superuser:
print "[ OK ]";
return;
print "[ OK ]"
return
raise TestFailed( "" raise TestFailed( ""
"No admin user exists, so you won't be able to log in to the admin system. You " "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 ): def check_mumbles( self ):
print "Checking Murmur instances...", print "Checking Murmur instances...",
mm = Mumble.objects.all();
mm = Mumble.objects.all()
if mm.count() == 0: if mm.count() == 0:
raise TestFailed( raise TestFailed(
"no Mumble servers are configured, you might want to run " "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: else:
for mumble in mm: for mumble in mm:
@ -178,22 +179,22 @@ class Command( BaseCommand ):
except Exception, err: except Exception, err:
raise TestFailed( raise TestFailed(
"Connecting to Murmur `%s` (%s) failed: %s" % ( mumble.name, mumble.server, err ) "Connecting to Murmur `%s` (%s) failed: %s" % ( mumble.name, mumble.server, err )
);
print "[ OK ]";
)
print "[ OK ]"
def check_secret_key( self ): def check_secret_key( self ):
print "Checking SECRET_KEY...", 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: if settings.SECRET_KEY in blacklist:
raise TestFailed( raise TestFailed(
"Your SECRET_KEY setting matches one of the keys that were put in the settings.py " "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. " "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." "You should change the setting, or run gen_secret_key.sh to do it for you."
);
)
else: else:
print "[ OK ]";
print "[ OK ]"

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

@ -1,4 +1,5 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# kate: space-indent on; indent-width 4; replace-tabs on;
""" """
* Copyright © 2009-2010, Michael "Svedrin" Ziegler <diese-addy@funzt-halt.net> * 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 -*- # -*- coding: utf-8 -*-
# kate: space-indent on; indent-width 4; replace-tabs on;
""" """
* Copyright © 2009-2010, Michael "Svedrin" Ziegler <diese-addy@funzt-halt.net> * 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 -*- # -*- coding: utf-8 -*-
# kate: space-indent on; indent-width 4; replace-tabs on;
""" """
* Copyright © 2009-2010, Michael "Svedrin" Ziegler <diese-addy@funzt-halt.net> * 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 -*- # -*- coding: utf-8 -*-
# kate: space-indent on; indent-width 4; replace-tabs on;
""" """
* Copyright © 2009-2010, Michael "Svedrin" Ziegler <diese-addy@funzt-halt.net> * 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 -*- # -*- coding: utf-8 -*-
# kate: space-indent on; indent-width 4; replace-tabs on;
""" """
* Copyright © 2009-2010, Michael "Svedrin" Ziegler <diese-addy@funzt-halt.net> * 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 ): def find_in_dicts( keys, conf, default, valueIfNotFound=None ):
if not isinstance( keys, tuple ): if not isinstance( keys, tuple ):
keys = ( keys, );
keys = ( keys, )
for keyword in keys: for keyword in keys:
if keyword in conf: if keyword in conf:
return conf[keyword];
return conf[keyword]
for keyword in keys: for keyword in keys:
keyword = keyword.lower();
keyword = keyword.lower()
if keyword in default: if keyword in default:
return default[keyword];
return default[keyword]
return valueIfNotFound;
return valueIfNotFound
def find_existing_instances( **kwargs ): def find_existing_instances( **kwargs ):
if "verbosity" in kwargs: if "verbosity" in kwargs:
v = kwargs['verbosity'];
v = kwargs['verbosity']
else: else:
v = 1;
v = 1
if 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: while not online:
if not triedEnviron and 'MURMUR_CONNSTR' in os.environ: 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: if v > 1:
print "Trying environment setting", dbusName;
print "Trying environment setting", dbusName
else: else:
print "--- Murmur connection info ---" print "--- Murmur connection info ---"
print " 1) DBus -- net.sourceforge.mumble.murmur" print " 1) DBus -- net.sourceforge.mumble.murmur"
@ -66,49 +67,49 @@ def find_existing_instances( **kwargs ):
print "string's format." print "string's format."
print print
dbusName = raw_input( "Service string: " ).strip();
dbusName = raw_input( "Service string: " ).strip()
if not dbusName: if not dbusName:
if v: if v:
print 'Be sure to run "python manage.py syncdb" with Murmur running before' 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 "trying to use this app! Otherwise, existing Murmur servers won't be"
print 'configurable!';
return False;
print 'configurable!'
return False
elif dbusName == "1": elif dbusName == "1":
dbusName = "net.sourceforge.mumble.murmur";
dbusName = "net.sourceforge.mumble.murmur"
elif dbusName == "2": 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: try:
ctl = MumbleCtlBase.newInstance( dbusName, settings.SLICE, icesecret );
ctl = MumbleCtlBase.newInstance( dbusName, settings.SLICE, icesecret )
except Exception, instance: except Exception, instance:
if v: 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 print
else: else:
online = True;
online = True
if v > 1: 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: try:
meta = MumbleServer.objects.get( dbus=dbusName );
meta = MumbleServer.objects.get( dbus=dbusName )
except MumbleServer.DoesNotExist: except MumbleServer.DoesNotExist:
meta = MumbleServer( dbus=dbusName );
meta = MumbleServer( dbus=dbusName )
finally: finally:
meta.secret = icesecret;
meta.save();
meta.secret = icesecret
meta.save()
for id in servIDs: for id in servIDs:
if v > 1: 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 # first check that the server has not yet been inserted into the DB
try: try:
instance = Mumble.objects.get( server=meta, srvid=id );
instance = Mumble.objects.get( server=meta, srvid=id )
except Mumble.DoesNotExist: except Mumble.DoesNotExist:
values = { values = {
"server": meta, "server": meta,
@ -119,13 +120,13 @@ def find_existing_instances( **kwargs ):
print "Found new Murmur instance %d on bus '%s'... " % ( id, dbusName ) print "Found new Murmur instance %d on bus '%s'... " % ( id, dbusName )
# now create a model for the record set. # now create a model for the record set.
instance = Mumble( **values );
instance = Mumble( **values )
else: else:
if v: if v:
print "Syncing Murmur instance %d: '%s'... " % ( instance.id, instance.name ) print "Syncing Murmur instance %d: '%s'... " % ( instance.id, instance.name )
try: try:
instance.configureFromMurmur();
instance.configureFromMurmur()
except DatabaseError, err: except DatabaseError, err:
try: try:
# Find instances with the same address/port # 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 # Now search for players on this server that have not yet been registered
if instance.booted: if instance.booted:
if v > 1: 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: 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: 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 -*- # -*- coding: utf-8 -*-
# kate: space-indent on; indent-width 4; replace-tabs on;
""" """
* Copyright © 2010, Michael "Svedrin" Ziegler <diese-addy@funzt-halt.net> * 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 ): def update_schema( **kwargs ):
if "verbosity" in kwargs: if "verbosity" in kwargs:
v = kwargs['verbosity'];
v = kwargs['verbosity']
else: else:
v = 1;
v = 1
if v: if v:
print "Migrating Database schema for Mumble-Django 2.0 now." print "Migrating Database schema for Mumble-Django 2.0 now."

13
pyweb/mumble/mctl.py

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

183
pyweb/mumble/mmobjects.py

@ -1,4 +1,5 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# kate: space-indent on; indent-width 4; replace-tabs on;
""" """
* Copyright © 2009-2010, Michael "Svedrin" Ziegler <diese-addy@funzt-halt.net> * 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 ): def cmp_channels( left, rite ):
""" Compare two channels, first by position, and if that equals, by name. """ """ Compare two channels, first by position, and if that equals, by name. """
if hasattr( left, "position" ) and hasattr( rite, "position" ): if hasattr( left, "position" ) and hasattr( rite, "position" ):
byorder = cmp( left.position, rite.position );
byorder = cmp( left.position, rite.position )
if byorder != 0: if byorder != 0:
return byorder;
return cmp_names( left, rite );
return byorder
return cmp_names( left, rite )
def cmp_names( left, rite ): def cmp_names( left, rite ):
""" Compare two objects by their name property. """ """ Compare two objects by their name property. """
return cmp( left.name, rite.name );
return cmp( left.name, rite.name )
class mmChannel( object ): class mmChannel( object ):
""" Represents a channel in Murmur. """ """ Represents a channel in Murmur. """
def __init__( self, server, channel_obj, parent_chan = None ): 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: 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 # Lookup unknown attributes in self.channel_obj to automatically include Murmur's fields
def __getattr__( self, key ): def __getattr__( self, key ):
if hasattr( self.channel_obj, key ): if hasattr( self.channel_obj, key ):
return getattr( self.channel_obj, key );
return getattr( self.channel_obj, key )
else: 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 ): def parent_channels( self ):
""" Return the names of this channel's parents in the channel tree. """ """ 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: 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 ): def getACL( self ):
""" Retrieve the ACL for this channel. """ """ Retrieve the ACL for this channel. """
if not self._acl: 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( playerCount = property(
lambda self: len( self.players ) + sum( [ chan.playerCount for chan in self.subchans ] ), lambda self: len( self.players ) + sum( [ chan.playerCount for chan in self.subchans ] ),
doc="The number of players in this channel." doc="The number of players in this channel."
);
)
id = property( id = property(
lambda self: "channel_%d"%self.chanid, lambda self: "channel_%d"%self.chanid,
doc="A string ready to be used in an id property of an HTML tag." doc="A string ready to be used in an id property of an HTML tag."
);
)
top_or_not_empty = property( top_or_not_empty = property(
lambda self: self.parent is None or self.parent.chanid == 0 or self.playerCount > 0, 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." 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 ): def __str__( self ):
return '<Channel "%s" (%d)>' % ( self.name, self.chanid );
return '<Channel "%s" (%d)>' % ( self.name, self.chanid )
def sort( self ): def sort( self ):
""" Sort my subchannels and players, and then iterate over them and sort them recursively. """ """ 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: for subc in self.subchans:
subc.sort();
subc.sort()
def visit( self, callback, lvl = 0 ): def visit( self, callback, lvl = 0 ):
""" Call callback on myself, then visit my subchans, then my players. """ """ Call callback on myself, then visit my subchans, then my players. """
callback( self, lvl );
callback( self, lvl )
for subc in self.subchans: for subc in self.subchans:
subc.visit( callback, lvl + 1 );
subc.visit( callback, lvl + 1 )
for plr in self.players: for plr in self.players:
plr.visit( callback, lvl + 1 );
plr.visit( callback, lvl + 1 )
def getURL( self, for_user = None ): def getURL( self, for_user = None ):
@ -124,38 +125,38 @@ class mmChannel( object ):
mumble://username@host:port/parentchans/self.name mumble://username@host:port/parentchans/self.name
""" """
from urlparse import urlunsplit from urlparse import urlunsplit
versionstr = "version=%s" % self.server.prettyversion;
versionstr = "version=%s" % self.server.prettyversion
if self.parent is not None: 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: else:
urlpath = "";
urlpath = ""
if for_user is not None: 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, "" )) return urlunsplit(( "mumble", netloc, urlpath, versionstr, "" ))
else: else:
return urlunsplit(( "mumble", self.server.netloc, urlpath, versionstr, "" )) return urlunsplit(( "mumble", self.server.netloc, urlpath, versionstr, "" ))
connecturl = property( getURL );
connecturl = property( getURL )
def setDefault( self ): def setDefault( self ):
""" Make this the server's default channel. """ """ 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( is_default = property(
lambda self: self.server.defchan == self.chanid, lambda self: self.server.defchan == self.chanid,
doc="True if this channel is the server's default channel." doc="True if this channel is the server's default channel."
);
)
def asDict( self ): 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 ): def asMvXml( self, parentnode ):
""" Return an XML tree for this channel suitable for MumbleViewer-ng. """ """ Return an XML tree for this channel suitable for MumbleViewer-ng. """
@ -190,85 +191,85 @@ class mmPlayer( object ):
""" Represents a Player in Murmur. """ """ Represents a Player in Murmur. """
def __init__( self, server, player_obj, player_chan ): 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: if self.isAuthed:
from mumble.models import MumbleUser from mumble.models import MumbleUser
try: try:
self.mumbleuser = MumbleUser.objects.get( mumbleid=self.userid, server=server );
self.mumbleuser = MumbleUser.objects.get( mumbleid=self.userid, server=server )
except MumbleUser.DoesNotExist: except MumbleUser.DoesNotExist:
self.mumbleuser = None;
self.mumbleuser = None
else: else:
self.mumbleuser = None;
self.mumbleuser = None
# Lookup unknown attributes in self.player_obj to automatically include Murmur's fields # Lookup unknown attributes in self.player_obj to automatically include Murmur's fields
def __getattr__( self, key ): def __getattr__( self, key ):
if hasattr( self.player_obj, key ): if hasattr( self.player_obj, key ):
return getattr( self.player_obj, key );
return getattr( self.player_obj, key )
else: 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 ): 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( hasComment = property(
lambda self: hasattr( self.player_obj, "comment" ) and bool(self.player_obj.comment), lambda self: hasattr( self.player_obj, "comment" ) and bool(self.player_obj.comment),
doc="True if this player has a comment set." doc="True if this player has a comment set."
);
)
isAuthed = property( isAuthed = property(
lambda self: self.userid != -1, lambda self: self.userid != -1,
doc="True if this player is authenticated (+A)." doc="True if this player is authenticated (+A)."
);
)
isAdmin = property( isAdmin = property(
lambda self: self.mumbleuser and self.mumbleuser.getAdmin(), lambda self: self.mumbleuser and self.mumbleuser.getAdmin(),
doc="True if this player is in the Admin group in the ACL." 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 ): def getIpAsString( self ):
""" Get the client's IPv4 or IPv6 address, in a pretty format. """ """ 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): 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])] ip6addr = [(hi << 8 | lo) for (hi, lo) in zip(addr[0::2], addr[1::2])]
# colon-separated string: # colon-separated string:
ipstr = ':'.join([ ("%x" % part) for part in ip6addr ]);
ipstr = ':'.join([ ("%x" % part) for part in ip6addr ])
# 0:0:0 -> :: # 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 ), 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) # 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( id = property(
lambda self: "player_%d"%self.session, lambda self: "player_%d"%self.session,
doc="A string ready to be used in an id property of an HTML tag." doc="A string ready to be used in an id property of an HTML tag."
);
)
def visit( self, callback, lvl = 0 ): def visit( self, callback, lvl = 0 ):
""" Call callback on myself. """ """ Call callback on myself. """
callback( self, lvl );
callback( self, lvl )
def asDict( self ): def asDict( self ):
pldata = self.player_obj.__dict__.copy();
pldata = self.player_obj.__dict__.copy()
if self.mumbleuser: if self.mumbleuser:
if self.mumbleuser.hasTexture(): if self.mumbleuser.hasTexture():
pldata['texture'] = self.mumbleuser.textureUrl;
pldata['texture'] = self.mumbleuser.textureUrl
return pldata;
return pldata
def asMvXml( self, parentnode ): def asMvXml( self, parentnode ):
""" Return an XML node for this player suitable for MumbleViewer-ng. """ """ 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. """ """ Represents an ACL for a certain channel. """
def __init__( self, channel, acl_obj ): 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: for group in self.groups:
self.groups_dict[ group.name ] = group;
self.groups_dict[ group.name ] = group
def group_has_member( self, name, userid ): def group_has_member( self, name, userid ):
""" Checks if the given userid is a member of the given group in this channel. """ """ Checks if the given userid is a member of the given group in this channel. """
if name not in self.groups_dict: 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 ): def group_add_member( self, name, userid ):
""" Make sure this userid is a member of the group in this channel (and subs). """ """ Make sure this userid is a member of the group in this channel (and subs). """
if name not in self.groups_dict: 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 neither inherited nor to be added, add
if userid not in group.members and userid not in group.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 to be removed, unremove
if userid in group.remove: if userid in group.remove:
group.remove.remove( userid );
group.remove.remove( userid )
def group_remove_member( self, name, userid ): def group_remove_member( self, name, userid ):
""" Make sure this userid is NOT a member of the group in this channel (and subs). """ """ Make sure this userid is NOT a member of the group in this channel (and subs). """
if name not in self.groups_dict: 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 added here, unadd
if userid in group.add: if userid in group.add:
group.add.remove( userid );
group.add.remove( userid )
# if member and not in remove, add to remove # if member and not in remove, add to remove
elif userid in group.members and userid not in group.remove: elif userid in group.members and userid not in group.remove:
group.remove.append( userid );
group.remove.append( userid )
def save( self ): def save( self ):
""" Send this ACL to Murmur. """ """ Send this ACL to Murmur. """
@ -344,7 +345,7 @@ class mmACL( object ):
self.channel.server.srvid, self.channel.server.srvid,
self.channel.chanid, self.channel.chanid,
self.acls, self.groups, self.inherit self.acls, self.groups, self.inherit
);
)

323
pyweb/mumble/models.py

@ -1,4 +1,5 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# kate: space-indent on; indent-width 4; replace-tabs on;
""" """
* Copyright © 2009-2010, Michael "Svedrin" Ziegler <diese-addy@funzt-halt.net> * 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 ): def get_field( self ):
if self.id is not None: if self.id is not None:
val = self.getConf( field );
val = self.getConf( field )
if val is None or val == '': if val is None or val == '':
return get_none return get_none
if callable(get_coerce): if callable(get_coerce):
@ -74,28 +75,28 @@ def mk_config_bool_property( field, doc="" ):
return mk_config_property( field, doc=doc, return mk_config_property( field, doc=doc,
get_coerce = lambda value: value == "true", get_coerce = lambda value: value == "true",
set_coerce = lambda value: str(value).lower() set_coerce = lambda value: str(value).lower()
);
)
class MumbleServer( models.Model ): class MumbleServer( models.Model ):
""" Represents a Murmur server installation. """ """ Represents a Murmur server installation. """
dbus = models.CharField( _('DBus or ICE base'), max_length=200, unique=True, default=settings.DEFAULT_CONN, help_text=_( 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: 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 ): 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 ): def __unicode__( self ):
return self.dbus;
return self.dbus
# Ctl instantiation # Ctl instantiation
def getCtl( self ): def getCtl( self ):
@ -104,14 +105,14 @@ class MumbleServer( models.Model ):
Only one instance will be created, and reused on subsequent calls. Only one instance will be created, and reused on subsequent calls.
""" """
if not self._ctl: 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): def isMethodDbus(self):
""" Return true if this instance uses DBus. """ """ 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)) return bool(rd.match(self.dbus))
method_dbus = property( isMethodDbus ) method_dbus = property( isMethodDbus )
@ -197,18 +198,18 @@ class Mumble( models.Model ):
deleted as well. 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=_( 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 " "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 = 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=_( 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 " "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 " "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: '', supw = property( lambda self: '',
lambda self, value: ( value and self.ctl.setSuperUserPassword( self.srvid, value ) ) or None, 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 ): def setBooted( self, value ):
if value != self.getBooted(): if value != self.getBooted():
if value: if value:
self.ctl.start( self.srvid );
self.ctl.start( self.srvid )
else: else:
self.ctl.stop( self.srvid );
self.ctl.stop( self.srvid )
booted = property( getBooted, setBooted, doc=ugettext_noop("Boot Server") ) booted = property( getBooted, setBooted, doc=ugettext_noop("Boot Server") )
online = property( getBooted, setBooted, doc=ugettext_noop("Boot Server") ) online = property( getBooted, setBooted, doc=ugettext_noop("Boot Server") )
class Meta: 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 ): def __unicode__( self ):
if not self.id: 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 ): def save( self, dontConfigureMurmur=False ):
""" Save the options configured in this model instance not only to Django's database, """ Save the options configured in this model instance not only to Django's database,
but to Murmur as well. but to Murmur as well.
""" """
if dontConfigureMurmur: if dontConfigureMurmur:
return models.Model.save( self );
return models.Model.save( self )
if self.id is None: 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 self.addr:
if " " in self.addr: if " " in self.addr:
# user gave multiple addresses, don't mess with that # 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: 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: 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: 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: else:
self.ctl.setConf( self.srvid, 'port', '' );
self.ctl.setConf( self.srvid, 'port', '' )
if self.netloc: if self.netloc:
self.ctl.setConf( self.srvid, 'registerhostname', self.netloc );
self.ctl.setConf( self.srvid, 'registerhostname', self.netloc )
else: 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 ): 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, 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 ): def getConf( self, field ):
return self.ctl.getConf( self.srvid, field ) return self.ctl.getConf( self.srvid, field )
@ -323,12 +324,12 @@ class Mumble( models.Model ):
return self.ctl.setConf( self.srvid, field, value ) return self.ctl.setConf( self.srvid, field, value )
def configureFromMurmur( self ): def configureFromMurmur( self ):
conf = self.ctl.getAllConf( self.srvid );
conf = self.ctl.getAllConf( self.srvid )
if "registername" not in conf or not conf["registername"]: if "registername" not in conf or not conf["registername"]:
self.name = "noname";
self.name = "noname"
else: else:
self.name = conf["registername"];
self.name = conf["registername"]
if "registerhostname" in conf and conf["registerhostname"]: if "registerhostname" in conf and conf["registerhostname"]:
if ':' in conf["registerhostname"]: if ':' in conf["registerhostname"]:
@ -372,29 +373,29 @@ class Mumble( models.Model ):
self.display = '' self.display = ''
self.addr = '' self.addr = ''
self.save( dontConfigureMurmur=True );
self.save( dontConfigureMurmur=True )
def readUsersFromMurmur( self, verbose=0 ): def readUsersFromMurmur( self, verbose=0 ):
if not self.booted: 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"] known_ids = [rec["mumbleid"]
for rec in MumbleUser.objects.filter( server=self ).values( "mumbleid" ) for rec in MumbleUser.objects.filter( server=self ).values( "mumbleid" )
] ]
for idx in players: for idx in players:
playerdata = players[idx];
playerdata = players[idx]
if playerdata.userid == 0: # Skip SuperUsers if playerdata.userid == 0: # Skip SuperUsers
continue;
continue
if verbose > 1: 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 playerdata.userid not in known_ids:
if verbose: if verbose:
print 'Found new Player "%s".' % playerdata.name;
print 'Found new Player "%s".' % playerdata.name
playerinstance = MumbleUser( playerinstance = MumbleUser(
mumbleid = playerdata.userid, mumbleid = playerdata.userid,
@ -402,27 +403,27 @@ class Mumble( models.Model ):
password = '', password = '',
server = self, server = self,
owner = None owner = None
);
)
else: else:
if verbose > 1: 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 ): def isUserAdmin( self, user ):
""" Determine if the given user is an admin on this server. """ """ Determine if the given user is an admin on this server. """
if user.is_authenticated(): if user.is_authenticated():
if user.is_superuser: if user.is_superuser:
return True;
return True
try: try:
return self.mumbleuser_set.get( owner=user ).getAdmin();
return self.mumbleuser_set.get( owner=user ).getAdmin()
except MumbleUser.DoesNotExist: except MumbleUser.DoesNotExist:
return False;
return False;
return False
return False
# Deletion handler # Deletion handler
@ -432,7 +433,7 @@ class Mumble( models.Model ):
@staticmethod @staticmethod
def pre_delete_listener( **kwargs ): def pre_delete_listener( **kwargs ):
kwargs['instance'].deleteServer();
kwargs['instance'].deleteServer()
# Channel list # Channel list
@ -443,58 +444,58 @@ class Mumble( models.Model ):
calls will simply return the list created last time. calls will simply return the list created last time.
""" """
if self._channels is None: 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. # sometimes, ICE seems to return the Channel list in a weird order.
# itercount prevents infinite loops. # itercount prevents infinite loops.
itercount = 0;
maxiter = len(chanlist) * 3;
itercount = 0
maxiter = len(chanlist) * 3
while len(chanlist) and itercount < maxiter: while len(chanlist) and itercount < maxiter:
itercount += 1;
itercount += 1
for theChan in chanlist: for theChan in chanlist:
# Channels - Fields: 0 = ID, 1 = Name, 2 = Parent-ID, 3 = Links # Channels - Fields: 0 = ID, 1 = Name, 2 = Parent-ID, 3 = Links
if( theChan.parent == -1 ): if( theChan.parent == -1 ):
# No parent # No parent
self._channels[theChan.id] = mmChannel( self, theChan );
self._channels[theChan.id] = mmChannel( self, theChan )
elif theChan.parent in self.channels: elif theChan.parent in self.channels:
# parent already known # 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: 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 # process links - if the linked channels are known, link; else save their ids to link later
for linked in theChan.links: for linked in theChan.links:
if linked in self._channels: if linked in self._channels:
self._channels[theChan.id].linked.append( self._channels[linked] );
self._channels[theChan.id].linked.append( self._channels[linked] )
else: else:
if linked not in links: 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 # check if earlier round trips saved channel ids to be linked to the current channel
if theChan.id in links: if theChan.id in links:
for targetChan in links[theChan.id]: 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(): for thePlayer in self.ctl.getPlayers(self.srvid).values():
# Players - Fields: 0 = UserID, 6 = ChannelID # 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 ): def getNetloc( self ):
""" Return the address from the Display field (if any), or the server address. """ 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 self.display:
if ":" in self.display: if ":" in self.display:
return self.display;
return self.display
else: else:
daddr = self.display;
daddr = self.display
elif " " in self.addr: elif " " in self.addr:
daddr = self.addr.split(" ")[0];
daddr = self.addr.split(" ")[0]
else: else:
daddr = self.addr;
daddr = self.addr
if self.port and self.port != settings.MUMBLE_DEFAULT_PORT: if self.port and self.port != settings.MUMBLE_DEFAULT_PORT:
return "%s:%d" % (daddr, self.port);
return "%s:%d" % (daddr, self.port)
else: else:
return daddr;
return daddr
netloc = property( getNetloc );
netloc = property( getNetloc )
def getURL( self, forUser = None ): def getURL( self, forUser = None ):
""" Create an URL of the form mumble://username@host:port/ for this server. """ """ Create an URL of the form mumble://username@host:port/ for this server. """
if not self.netloc: if not self.netloc:
return None return None
from urlparse import urlunsplit from urlparse import urlunsplit
versionstr = "version=%s" % self.prettyversion;
versionstr = "version=%s" % self.prettyversion
if forUser is not None: if forUser is not None:
netloc = "%s@%s" % ( forUser.name, self.netloc );
netloc = "%s@%s" % ( forUser.name, self.netloc )
return urlunsplit(( "mumble", netloc, "", versionstr, "" )) return urlunsplit(( "mumble", netloc, "", versionstr, "" ))
else: else:
return urlunsplit(( "mumble", self.netloc, "", versionstr, "" )) 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 ): def asDict( self ):
return { 'name': self.name, return { 'name': self.name,
'id': self.id, 'id': self.id,
'root': self.rootchan.asDict() 'root': self.rootchan.asDict()
};
}
def asMvXml( self ): def asMvXml( self ):
""" Return an XML tree for this server suitable for MumbleViewer-ng. """ """ Return an XML tree for this server suitable for MumbleViewer-ng. """
@ -556,15 +557,15 @@ class Mumble( models.Model ):
def __setattr__( self, name, value ): def __setattr__( self, name, value ):
if name == 'server': if name == 'server':
if self.id is not None and self.server != value: 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="" ): 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="" ): 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 ): def get_field( self ):
if field in self.registration: if field in self.registration:
return self.registration[field];
return self.registration[field]
else: else:
return None;
return None
return property( get_field, doc=doc ) 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. 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 ) ) gravatar256 = property( lambda self: self.gravatarUrl( size=256 ) )
gravatar128 = property( lambda self: self.gravatarUrl( size=128 ) ) gravatar128 = property( lambda self: self.gravatarUrl( size=128 ) )
@ -608,41 +609,41 @@ class MumbleUser( models.Model ):
gravatar = property( lambda self: self.gravatarUrl() ) gravatar = property( lambda self: self.gravatarUrl() )
class Meta: 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 ): def __unicode__( self ):
return _("Mumble user %(mu)s on %(srv)s owned by Django user %(du)s") % { return _("Mumble user %(mu)s on %(srv)s owned by Django user %(du)s") % {
'mu': self.name, 'mu': self.name,
'srv': self.server, 'srv': self.server,
'du': self.owner 'du': self.owner
};
}
def save( self, dontConfigureMurmur=False ): def save( self, dontConfigureMurmur=False ):
""" Save the settings in this model to Murmur. """ """ Save the settings in this model to Murmur. """
if dontConfigureMurmur: if dontConfigureMurmur:
return models.Model.save( self );
return models.Model.save( self )
ctl = self.server.ctl;
ctl = self.server.ctl
if self.owner: if self.owner:
email = self.owner.email;
email = self.owner.email
else: else:
email = settings.DEFAULT_FROM_EMAIL;
email = settings.DEFAULT_FROM_EMAIL
if self.id is None: if self.id is None:
# This is a new user record, so Murmur doesn't know about it yet # This is a new user record, so Murmur doesn't know about it yet
if len( ctl.getRegisteredPlayers( self.server.srvid, self.name ) ) > 0: 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: 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 # Update user's registration
elif self.password: elif self.password:
@ -652,56 +653,56 @@ class MumbleUser( models.Model ):
self.name, self.name,
email, email,
self.password self.password
);
)
# Don't save the users' passwords, we don't need them anyway # 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 enabled (and possible), set Gravatar as default Avatar
if settings.USE_GRAVATAR and self.gravatar: if settings.USE_GRAVATAR and self.gravatar:
self.setTextureFromUrl( self.gravatar ) self.setTextureFromUrl( self.gravatar )
return models.Model.save( self );
return models.Model.save( self )
def __init__( self, *args, **kwargs ): 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 # Admin handlers
def getAdmin( self ): def getAdmin( self ):
""" Get ACL of root Channel, get the admin group and see if this user is in it. """ """ Get ACL of root Channel, get the admin group and see if this user is in it. """
if self.mumbleid == -1: if self.mumbleid == -1:
return False;
return False
else: 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 ): def setAdmin( self, value ):
""" Set or revoke this user's membership in the admin group on the root channel. """ """ Set or revoke this user's membership in the admin group on the root channel. """
if self.mumbleid == -1: if self.mumbleid == -1:
return False;
return False
if value: if value:
self.server.rootchan.acl.group_add_member( "admin", self.mumbleid );
self.server.rootchan.acl.group_add_member( "admin", self.mumbleid )
else: 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 # Registration fetching
def getRegistration( self ): def getRegistration( self ):
""" Retrieve a user's registration from Murmur as a dict. """ """ Retrieve a user's registration from Murmur as a dict. """
if not self._registration: 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 # Texture handlers
def getTexture( self ): def getTexture( self ):
""" Get the user texture as a PIL Image. """ """ 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 ): def setTexture( self, image ):
""" Install the given image as the user's texture. """ """ Install the given image as the user's texture. """
@ -714,16 +715,16 @@ class MumbleUser( models.Model ):
texture = property( getTexture, setTexture, texture = property( getTexture, setTexture,
doc="Get the texture as a PIL Image or set the Image as the texture." doc="Get the texture as a PIL Image or set the Image as the texture."
);
)
def hasTexture( self ): def hasTexture( self ):
""" Check if this user has a texture set. """ """ Check if this user has a texture set. """
try: try:
self.getTexture();
self.getTexture()
except ValueError: except ValueError:
return False;
return False
else: else:
return True;
return True
def gravatarUrl( self, size=80 ): def gravatarUrl( self, size=80 ):
""" Get a Gravatar URL for my owner's email adress (if any), or using the User's cert hash. """ 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. """ """ Get a URL under which the texture can be retrieved. """
from views import showTexture from views import showTexture
from django.core.urlresolvers import reverse 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 # Deletion handler
@staticmethod @staticmethod
def pre_delete_listener( **kwargs ): def pre_delete_listener( **kwargs ):
kwargs['instance'].unregister();
kwargs['instance'].unregister()
def unregister( self ): def unregister( self ):
""" Delete this user account from Murmur. """ """ Delete this user account from Murmur. """
if self.getAdmin(): if self.getAdmin():
self.setAdmin( False );
self.setAdmin( False )
self.server.ctl.unregisterPlayer(self.server.srvid, self.mumbleid) self.server.ctl.unregisterPlayer(self.server.srvid, self.mumbleid)
@ -762,15 +763,15 @@ class MumbleUser( models.Model ):
def __setattr__( self, name, value ): def __setattr__( self, name, value ):
if name == 'server': if name == 'server':
if self.id is not None and self.server != value: 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 -*- # -*- coding: utf-8 -*-
# kate: space-indent on; indent-width 4; replace-tabs on;
""" """
* Copyright © 2009-2010, Michael "Svedrin" Ziegler <diese-addy@funzt-halt.net> * Copyright © 2009-2010, Michael "Svedrin" Ziegler <diese-addy@funzt-halt.net>
@ -25,9 +26,9 @@ from utils import ObjectInfo
def get_available_versions(): def get_available_versions():
""" Return murmur versions installed inside the LAB_DIR. """ """ 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 ): def run_callback( version, callback, *args, **kwargs ):
@ -56,42 +57,42 @@ def run_callback( version, callback, *args, **kwargs ):
into the first parameter. 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 ): 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: try:
result = callback( process, *args, **kwargs );
result = callback( process, *args, **kwargs )
if type(result) == tuple: if type(result) == tuple:
if result[1]: if result[1]:
update_dbase( version );
return result[0];
update_dbase( version )
return result[0]
else: else:
return result;
return result
finally: finally:
kill_murmur( process );
kill_murmur( process )
def init_dbase( version ): def init_dbase( version ):
""" Initialize Murmur's database by copying the one from FILES_DIR. """ """ 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 ): 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 ): def update_dbase( version ):
""" Copy Murmur's database to FILES_DIR (the inverse of init_dbase). """ """ 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 ): 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 ): def run_murmur( version ):
@ -100,11 +101,11 @@ def run_murmur( version ):
Either returns a Popen object or raises an EnvironmentError. 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 ): 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: for binname in binary_candidates:
if exists( join( murmur_root, binname ) ): if exists( join( murmur_root, binname ) ):
@ -112,34 +113,34 @@ def run_murmur( version ):
( join( murmur_root, binname ), '-fg' ), ( join( murmur_root, binname ), '-fg' ),
stdin=None, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, stdin=None, stdout=subprocess.PIPE, stderr=subprocess.STDOUT,
cwd=murmur_root cwd=murmur_root
);
)
# Check capabilities by waiting for certain lines to show up. # 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 ): 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) setattr(subprocess.Popen, 'canRead', canRead)
while process.canRead(0.5): while process.canRead(0.5):
line = process.stdout.readline();
line = process.stdout.readline()
#print "read line:", line #print "read line:", line
if line == 'DBus registration succeeded\n': 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': 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': 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: 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 ): def wait_for_user( process, timeout=1 ):
@ -155,16 +156,16 @@ def wait_for_user( process, timeout=1 ):
False otherwise. False otherwise.
""" """
while process.canRead( timeout ): while process.canRead( timeout ):
line = process.stdout.readline();
line = process.stdout.readline()
if "> Authenticated\n" in line: 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 ): def kill_murmur( process ):
""" Send a sigterm to the given 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 ): class MumbleCommandWrapper_noargs( object ):
@ -185,23 +186,23 @@ class MumbleCommandWrapper_noargs( object ):
""" """
def _choose_version( self ): def _choose_version( self ):
print "Choose version:";
print "Choose version:"
vv = get_available_versions();
vv = get_available_versions()
for idx in range(len(vv)): 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 ): 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 ): def runOrig( self, proc ):
super( MumbleCommandWrapper_noargs, self ).handle_noargs( **self.origOpts );
super( MumbleCommandWrapper_noargs, self ).handle_noargs( **self.origOpts )
class MumbleCommandWrapper( object ): class MumbleCommandWrapper( object ):
@ -222,23 +223,23 @@ class MumbleCommandWrapper( object ):
""" """
def _choose_version( self ): def _choose_version( self ):
print "Choose version:";
print "Choose version:"
vv = get_available_versions();
vv = get_available_versions()
for idx in range(len(vv)): 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 ): 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 ): 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 -*- # -*- coding: utf-8 -*-
# kate: space-indent on; indent-width 4; replace-tabs on;
""" """
* Copyright © 2009-2010, Michael "Svedrin" Ziegler <diese-addy@funzt-halt.net> * 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 from django.conf import settings
register = template.Library();
register = template.Library()
@register.filter @register.filter
def trunc( string, maxlen = 50 ): def trunc( string, maxlen = 50 ):
""" converts "a very very extaordinary long text" to "a very very extra... """ """ converts "a very very extaordinary long text" to "a very very extra... """
if len(string) < maxlen: if len(string) < maxlen:
return string;
return string[:(maxlen - 3)] + "";
return string
return string[:(maxlen - 3)] + ""
@register.filter @register.filter
def chanview( obj, user = None ): def chanview( obj, user = None ):
""" renders an mmChannel / mmPlayer object with the correct template """ """ renders an mmChannel / mmPlayer object with the correct template """
if obj.is_server: 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: 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: 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 @register.filter
def chanurl( obj, user ): def chanurl( obj, user ):
""" create a connection URL and takes the user's login into account """ """ create a connection URL and takes the user's login into account """
return obj.getURL( user );
return obj.getURL( user )
@register.filter @register.filter
def mmversion_lt( obj, version ): def mmversion_lt( obj, version ):

55
pyweb/mumble/testrunner.py

@ -1,4 +1,5 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# kate: space-indent on; indent-width 4; replace-tabs on;
""" """
* Copyright © 2009-2010, Michael "Svedrin" Ziegler <diese-addy@funzt-halt.net> * 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: 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 # 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. # The easy way: mumble is not being tested.
if "mumble" not in test_labels: 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 # First run everything apart from mumble. mumble will be tested separately, so Murmur
# can be set up properly first. # can be set up properly first.
failed_tests = 0;
failed_tests = 0
if len(test_labels) > 1: if len(test_labels) > 1:
# only run others if mumble is not the only app to be tested # 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 ): def run_mumble_tests( verbosity=1, interactive=True ):
@ -57,43 +58,43 @@ def run_mumble_tests( verbosity=1, interactive=True ):
connstrings = { connstrings = {
'DBus': 'net.sourceforge.mumble.murmur', 'DBus': 'net.sourceforge.mumble.murmur',
'Ice': 'Meta:tcp -h 127.0.0.1 -p 6502', 'Ice': 'Meta:tcp -h 127.0.0.1 -p 6502',
};
}
def django_run_tests_wrapper( process, version ): def django_run_tests_wrapper( process, version ):
wr_failed_tests = 0;
wr_failed_tests = 0
for method in connstrings: for method in connstrings:
# Check if this server is ready to be used with the current method # Check if this server is ready to be used with the current method
if getattr( process.capabilities, ("has_%s" % method.lower()), False ): 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: if not process.capabilities.has_users:
print "Waiting for user to connect (60 seconds)." 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: 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 from mctl import MumbleCtlBase
for version in get_available_versions(): 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', ''): 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 -*- # -*- coding: utf-8 -*-
# kate: space-indent on; indent-width 4; replace-tabs on;
""" """
* Copyright © 2009-2010, Michael "Svedrin" Ziegler <diese-addy@funzt-halt.net> * 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 # Make sure we always start with a FRESH murmur instance, checking for left-over instances
# and deleting them before creating ours. # and deleting them before creating ours.
try: 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: except Mumble.DoesNotExist:
pass pass
else: else:
self.murmur.delete();
self.murmur.delete()
finally: 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 ): 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 ): def testAddrPortUnique( self ):
try: try:
@ -58,22 +59,22 @@ class InstancesHandling( TestCase ):
name="#another unit testing instance#", name="#another unit testing instance#",
addr=self.murmur.addr, port=self.murmur.port, addr=self.murmur.addr, port=self.murmur.port,
dbus=settings.DEFAULT_CONN dbus=settings.DEFAULT_CONN
);
)
if duplicate.ctl.method == "ICE": if duplicate.ctl.method == "ICE":
import Murmur import Murmur
self.assertRaises( Murmur.ServerFailureException, duplicate.save );
self.assertRaises( Murmur.ServerFailureException, duplicate.save )
elif self.murmur.version[:2] == [ 1, 2 ]: elif self.murmur.version[:2] == [ 1, 2 ]:
from dbus import DBusException from dbus import DBusException
self.assertRaises( DBusException, duplicate.save );
self.assertRaises( DBusException, duplicate.save )
else: else:
from sqlite3 import IntegrityError from sqlite3 import IntegrityError
self.assertRaises( IntegrityError, duplicate.save );
self.assertRaises( IntegrityError, duplicate.save )
finally: finally:
# make sure the duplicate is removed # make sure the duplicate is removed
duplicate.ctl.deleteServer( duplicate.srvid );
duplicate.ctl.deleteServer( duplicate.srvid )
def tearDown( self ): def tearDown( self ):
self.murmur.delete();
self.murmur.delete()
class DataReading( TestCase ): class DataReading( TestCase ):
@ -84,125 +85,125 @@ class DataReading( TestCase ):
# Murmur database like the one I have. # Murmur database like the one I have.
# I definitely need to prepare Murmur somehow before running these tests. # I definitely need to prepare Murmur somehow before running these tests.
# Just don't yet know how. # Just don't yet know how.
self.murmur = Mumble.objects.get(id=1);
self.murmur = Mumble.objects.get(id=1)
def testCtlGetChannels( self ): def testCtlGetChannels( self ):
""" Test getChannels() """ """ Test getChannels() """
channels = self.murmur.ctl.getChannels( self.murmur.srvid );
channels = self.murmur.ctl.getChannels( self.murmur.srvid )
if self.murmur.ctl.method == "ICE": if self.murmur.ctl.method == "ICE":
import Murmur import Murmur
self.assertEquals( type( channels[0] ), Murmur.Channel );
self.assertEquals( type( channels[0] ), Murmur.Channel )
else: 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 ): def testCtlGetPlayers( self ):
""" Test getPlayers() """ """ 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: for plidx in players:
player = players[plidx];
player = players[plidx]
if self.murmur.ctl.method == "ICE" and self.murmur.version[:2] == ( 1, 2 ): if self.murmur.ctl.method == "ICE" and self.murmur.version[:2] == ( 1, 2 ):
import Murmur import Murmur
self.assertEquals( type( player ), Murmur.User );
self.assertEquals( type( player ), Murmur.User )
else: 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 ): def testCtlGetRegisteredPlayers( self ):
""" Test getRegistredPlayers() and getRegistration() """ """ 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: 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 # 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 ): def testCtlGetAcl( self ):
""" Test getACL() for the root channel """ """ 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: for rule in acls:
if self.murmur.ctl.method == "ICE" and self.murmur.version[:2] == ( 1, 2 ): if self.murmur.ctl.method == "ICE" and self.murmur.version[:2] == ( 1, 2 ):
import Murmur import Murmur
self.assertEquals( type( rule ), Murmur.ACL );
self.assertEquals( type( rule ), Murmur.ACL )
else: 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: for grp in groups:
if self.murmur.ctl.method == "ICE": if self.murmur.ctl.method == "ICE":
import Murmur import Murmur
self.assertEquals( type( grp ), Murmur.Group );
self.assertEquals( type( grp ), Murmur.Group )
else: 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 -*- # -*- coding: utf-8 -*-
# kate: space-indent on; indent-width 4; replace-tabs on;
""" """
* Copyright © 2009-2010, Michael "Svedrin" Ziegler <diese-addy@funzt-halt.net> * Copyright © 2009-2010, Michael "Svedrin" Ziegler <diese-addy@funzt-halt.net>

13
pyweb/mumble/utils.py

@ -1,4 +1,5 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# kate: space-indent on; indent-width 4; replace-tabs on;
""" """
* Copyright © 2009-2010, Michael "Svedrin" Ziegler <diese-addy@funzt-halt.net> * 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. """ """ Wraps arbitrary information to be easily accessed. """
def __init__( self, **kwargs ): def __init__( self, **kwargs ):
self.__dict__ = kwargs;
self.__dict__ = kwargs
def __str__( self ): def __str__( self ):
return unicode( self );
return unicode( self )
def __repr__( self ): def __repr__( self ):
return unicode( self );
return unicode( self )
def __unicode__( self ): def __unicode__( self ):
return unicode( self.__dict__ );
return unicode( self.__dict__ )
def __contains__( self, name ): def __contains__( self, name ):
return name in self.__dict__;
return name in self.__dict__
def __getitem__( self, name ): def __getitem__( self, name ):
return self.__dict__[name];
return self.__dict__[name]

208
pyweb/mumble/views.py

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

1
pyweb/processors.py

@ -1,4 +1,5 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# kate: space-indent on; indent-width 4; replace-tabs on;
""" """
* Copyright © 2009-2010, Michael "Svedrin" Ziegler <diese-addy@funzt-halt.net> * Copyright © 2009-2010, Michael "Svedrin" Ziegler <diese-addy@funzt-halt.net>

13
pyweb/settings.py

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

1
pyweb/urls.py

@ -1,4 +1,5 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# kate: space-indent on; indent-width 4; replace-tabs on;
""" """
* Copyright © 2009-2010, Michael "Svedrin" Ziegler <diese-addy@funzt-halt.net> * Copyright © 2009-2010, Michael "Svedrin" Ziegler <diese-addy@funzt-halt.net>

7
pyweb/views.py

@ -1,4 +1,5 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# kate: space-indent on; indent-width 4; replace-tabs on;
""" """
* Copyright © 2009-2010, Michael "Svedrin" Ziegler <diese-addy@funzt-halt.net> * Copyright © 2009-2010, Michael "Svedrin" Ziegler <diese-addy@funzt-halt.net>
@ -25,13 +26,13 @@ def profile( request ):
userdata = { userdata = {
"ProfileActive": True, "ProfileActive": True,
"mumbleaccs": MumbleUser.objects.filter( owner = request.user ), "mumbleaccs": MumbleUser.objects.filter( owner = request.user ),
};
}
return render_to_response( return render_to_response(
'registration/profile.html', 'registration/profile.html',
userdata, userdata,
context_instance = RequestContext(request) context_instance = RequestContext(request)
);
)
def imprint( request ): def imprint( request ):
@ -39,4 +40,4 @@ def imprint( request ):
return render_to_response( return render_to_response(
'registration/imprint.html', 'registration/imprint.html',
{ 'upstreamversion': mumble.getLatestUpstreamVersion() }, { 'upstreamversion': mumble.getLatestUpstreamVersion() },
context_instance = RequestContext(request) );
context_instance = RequestContext(request) )
Loading…
Cancel
Save