Browse Source

a few code style fixes

Natenom/support-murmur-13-1446181288462
Michael Ziegler 15 years ago
parent
commit
5a6747c83a
  1. 563
      muco.py
  2. 2
      mumble-django.wsgi
  3. 73
      munin.py
  4. 2
      pyweb/manage.py
  5. 239
      pyweb/mucli.py
  6. 595
      pyweb/mumble/MumbleCtlDbus.py
  7. 1117
      pyweb/mumble/MumbleCtlIce.py
  8. 39
      pyweb/mumble/__init__.py
  9. 231
      pyweb/mumble/admin.py
  10. 547
      pyweb/mumble/forms.py
  11. 43
      pyweb/mumble/management/__init__.py
  12. 1
      pyweb/mumble/management/commands/__init__.py
  13. 345
      pyweb/mumble/management/commands/checkenv.py
  14. 71
      pyweb/mumble/management/commands/getslice.py
  15. 7
      pyweb/mumble/management/commands/mmrunserver.py
  16. 7
      pyweb/mumble/management/commands/mmshell.py
  17. 7
      pyweb/mumble/management/commands/mmsyncdb.py
  18. 279
      pyweb/mumble/management/server_detect.py
  19. 107
      pyweb/mumble/management/update_schema.py
  20. 77
      pyweb/mumble/mctl.py
  21. 623
      pyweb/mumble/mmobjects.py
  22. 1461
      pyweb/mumble/models.py
  23. 395
      pyweb/mumble/murmurenvutils.py
  24. 41
      pyweb/mumble/templatetags/mumble_extras.py
  25. 149
      pyweb/mumble/testrunner.py
  26. 365
      pyweb/mumble/tests.py
  27. 31
      pyweb/mumble/urls.py
  28. 39
      pyweb/mumble/utils.py
  29. 708
      pyweb/mumble/views.py
  30. 9
      pyweb/processors.py
  31. 103
      pyweb/settings.py
  32. 37
      pyweb/urls.py
  33. 39
      pyweb/views.py

563
muco.py

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

2
mumble-django.wsgi

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

73
munin.py

@ -1,5 +1,6 @@
#!/usr/bin/python
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# kate: space-indent on; indent-width 4; replace-tabs on;
"""
* Copyright (C) 2009, Michael "Svedrin" Ziegler <diese-addy@funzt-halt.net>
@ -16,7 +17,7 @@
"""
# Set this to the same path you used in settings.py, or None for auto-detection.
MUMBLE_DJANGO_ROOT = None;
MUMBLE_DJANGO_ROOT = None
### DO NOT CHANGE ANYTHING BELOW THIS LINE ###
@ -25,7 +26,7 @@ from os.path import join, dirname, abspath, exists
# Path auto-detection
if not MUMBLE_DJANGO_ROOT or not exists( MUMBLE_DJANGO_ROOT ):
MUMBLE_DJANGO_ROOT = dirname(abspath(__file__));
MUMBLE_DJANGO_ROOT = dirname(abspath(__file__))
# environment variables
sys.path.append( MUMBLE_DJANGO_ROOT )
@ -50,46 +51,46 @@ categ = getattr( settings, "MUNIN_CATEGORY", "network" )
def get_running_instances():
for server in MumbleServer.objects.all():
if not server.online:
continue
runinst = server.ctl.getBootedServers()
for inst in server.mumble_set.order_by("srvid").filter( srvid__in=runinst ):
yield inst
for server in MumbleServer.objects.all():
if not server.online:
continue
runinst = server.ctl.getBootedServers()
for inst in server.mumble_set.order_by("srvid").filter( srvid__in=runinst ):
yield inst
if sys.argv[-1] == 'config':
prefenc = locale.getpreferredencoding()
print "graph_vlabel Users"
print "graph_args --base 1000"
print "graph_title", title
print "graph_category", categ
for mumble in get_running_instances():
print "srv%d.label %s" % ( mumble.id, mumble.name.replace('#', '').encode(prefenc, "replace") );
if mumble.connecturl:
print "srv%d.info %s" % ( mumble.id, mumble.connecturl );
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 ) );
prefenc = locale.getpreferredencoding()
print "graph_vlabel Users"
print "graph_args --base 1000"
print "graph_title", title
print "graph_category", categ
for mumble in get_running_instances():
print "srv%d.label %s" % ( mumble.id, mumble.name.replace('#', '').encode(prefenc, "replace") )
if mumble.connecturl:
print "srv%d.info %s" % ( mumble.id, mumble.connecturl )
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 ) )
elif sys.argv[-1] == 'autoconf':
if Mumble.objects.count() == 0:
print "no (no servers configured)";
else:
# check if connecting works
try:
for mumble in get_running_instances():
mumble.ctl
except Exception, instance:
print "no (can't connect to server %s: %s)" % ( mumble.name, instance );
else:
print "yes";
if Mumble.objects.count() == 0:
print "no (no servers configured)"
else:
# check if connecting works
try:
for mumble in get_running_instances():
mumble.ctl
except Exception, instance:
print "no (can't connect to server %s: %s)" % ( mumble.name, instance )
else:
print "yes"
else:
for mumble in get_running_instances():
print "srv%d.value %d" % ( mumble.id, len( mumble.ctl.getPlayers( mumble.srvid ) ) );
for mumble in get_running_instances():
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 -*-
"""

239
pyweb/mucli.py

@ -1,5 +1,6 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# kate: space-indent on; indent-width 4; replace-tabs on;
"""
* Copyright (C) 2010, Michael "Svedrin" Ziegler <diese-addy@funzt-halt.net>
@ -22,8 +23,8 @@ import os, sys
import inspect
import getpass
from optparse import OptionParser
from mumble.mctl import MumbleCtlBase
from optparse import OptionParser
from mumble.mctl import MumbleCtlBase
usage = """Usage: %prog [options] [<method name>] [<method arguments>]
@ -39,153 +40,153 @@ as False.
parser = OptionParser(usage=usage)
parser.add_option( "-d", "--django-settings",
help="if specified, get connstring and slice defaults from the given Django "
"settings module. Default: empty.",
default=None
)
help="if specified, get connstring and slice defaults from the given Django "
"settings module. Default: empty.",
default=None
)
parser.add_option( "-c", "--connstring",
help="connection string to use. Default is '%s'." % DEFAULT_CONNSTRING,
default=None
)
help="connection string to use. Default is '%s'." % DEFAULT_CONNSTRING,
default=None
)
parser.add_option( "-i", "--icesecret",
help="Ice secret to use in the connection. Also see --asksecret.",
default=None
)
help="Ice secret to use in the connection. Also see --asksecret.",
default=None
)
parser.add_option( "-a", "--asksecret",
help="Ask for the Ice secret on the shell instead of taking it from the command line.",
action="store_true", default=False
)
help="Ask for the Ice secret on the shell instead of taking it from the command line.",
action="store_true", default=False
)
parser.add_option( "-s", "--slice",
help="path to the slice file. Default is '%s'." % DEFAULT_SLICEFILE,
default=None
)
help="path to the slice file. Default is '%s'." % DEFAULT_SLICEFILE,
default=None
)
parser.add_option( "-e", "--encoding",
help="Character set arguments are encoded in. Default: Read from LANG env variable with fallback to UTF-8.",
default=None
)
help="Character set arguments are encoded in. Default: Read from LANG env variable with fallback to UTF-8.",
default=None
)
parser.add_option(
"-v", "--verbose",
help="Show verbose messages on stderr",
default=False,
action="store_true"
)
"-v", "--verbose",
help="Show verbose messages on stderr",
default=False,
action="store_true"
)
options, progargs = parser.parse_args()
if options.django_settings is not None:
if options.verbose:
print >> sys.stderr, "Reading settings from module '%s'." % options.django_settings
os.environ['DJANGO_SETTINGS_MODULE'] = options.django_settings
from django.conf import settings
if options.connstring is None:
if options.verbose:
print >> sys.stderr, "Setting connstring from settings module"
options.connstring = settings.DEFAULT_CONN
if options.slice is None:
if options.verbose:
print >> sys.stderr, "Setting slice from settings module"
options.slice = settings.SLICE
if options.verbose:
print >> sys.stderr, "Reading settings from module '%s'." % options.django_settings
os.environ['DJANGO_SETTINGS_MODULE'] = options.django_settings
from django.conf import settings
if options.connstring is None:
if options.verbose:
print >> sys.stderr, "Setting connstring from settings module"
options.connstring = settings.DEFAULT_CONN
if options.slice is None:
if options.verbose:
print >> sys.stderr, "Setting slice from settings module"
options.slice = settings.SLICE
else:
if options.connstring is None:
if options.verbose:
print >> sys.stderr, "Setting default connstring"
options.connstring = DEFAULT_CONNSTRING
if options.slice is None:
if options.verbose:
print >> sys.stderr, "Setting default slice"
options.slice = DEFAULT_SLICEFILE
if options.connstring is None:
if options.verbose:
print >> sys.stderr, "Setting default connstring"
options.connstring = DEFAULT_CONNSTRING
if options.slice is None:
if options.verbose:
print >> sys.stderr, "Setting default slice"
options.slice = DEFAULT_SLICEFILE
if options.encoding is None:
try:
locale = os.environ['LANG']
_, options.encoding = locale.split('.')
except (KeyError, ValueError):
options.encoding = "UTF-8"
try:
locale = os.environ['LANG']
_, options.encoding = locale.split('.')
except (KeyError, ValueError):
options.encoding = "UTF-8"
if options.verbose:
print >> sys.stderr, "Connection info:"
print >> sys.stderr, " Connstring: %s" % options.connstring
print >> sys.stderr, " Slice: %s" % options.slice
print >> sys.stderr, "Encoding: %s" % options.encoding
print >> sys.stderr, "Connection info:"
print >> sys.stderr, " Connstring: %s" % options.connstring
print >> sys.stderr, " Slice: %s" % options.slice
print >> sys.stderr, "Encoding: %s" % options.encoding
if options.asksecret or options.icesecret == '':
options.icesecret = getpass.getpass( "Ice secret: " )
options.icesecret = getpass.getpass( "Ice secret: " )
ctl = MumbleCtlBase.newInstance( options.connstring, options.slice, options.icesecret )
if not progargs:
# Print available methods.
for method in inspect.getmembers( ctl ):
if method[0][0] == '_' or not callable( method[1] ):
continue
if hasattr( method[1], "innerfunc" ):
args = inspect.getargspec( method[1].innerfunc )[0]
else:
args = inspect.getargspec( method[1] )[0]
if len( args ) > 1:
if args[0] == 'self':
print "%s( %s )" % ( method[0], ', '.join( args[1:] ) )
else:
print "%s()" % method[0]
# Print available methods.
for method in inspect.getmembers( ctl ):
if method[0][0] == '_' or not callable( method[1] ):
continue
if hasattr( method[1], "innerfunc" ):
args = inspect.getargspec( method[1].innerfunc )[0]
else:
args = inspect.getargspec( method[1] )[0]
if len( args ) > 1:
if args[0] == 'self':
print "%s( %s )" % ( method[0], ', '.join( args[1:] ) )
else:
print "%s()" % method[0]
else:
# function name given. check if its args matches ours, if yes call it, if not print usage
if options.verbose:
print >> sys.stderr, "Method name: %s" % progargs[0]
method = getattr( ctl, progargs[0] )
if hasattr( method, "innerfunc" ):
method = method.innerfunc
args = inspect.getargspec( method )[0]
if len(progargs) == len(args) and args[0] == 'self':
if len(args) == 1:
print method(ctl)
else:
cleanargs = []
for param in progargs[1:]:
try:
argtype, argval = param.split(':', 1)
except ValueError:
cleanargs.append( param.decode(options.encoding) )
else:
cleanval = {
'bool': lambda val: val in ('True', 'true', '1', 'Yes', 'yes'),
'int': int,
'float': float,
'string': str
}[ argtype ]( argval )
if argtype == 'string':
cleanval = cleanval.decode(options.encoding)
cleanargs.append(cleanval)
if options.verbose:
print >> sys.stderr, "Call arguments: %s" % repr(cleanargs)
print method( ctl, *cleanargs )
elif len(args) == 1:
print >> sys.stderr, "Method '%s' does not take any arguments." % progargs[0]
print >> sys.stderr, "Expected %s()" % progargs[0]
else:
print >> sys.stderr, "Invalid arguments for method '%s': %s" % ( progargs[0], ', '.join( progargs[1:] ) )
print >> sys.stderr, "Expected %s( %s )" % ( progargs[0], ', '.join( args[1:] ) )
# function name given. check if its args matches ours, if yes call it, if not print usage
if options.verbose:
print >> sys.stderr, "Method name: %s" % progargs[0]
method = getattr( ctl, progargs[0] )
if hasattr( method, "innerfunc" ):
method = method.innerfunc
args = inspect.getargspec( method )[0]
if len(progargs) == len(args) and args[0] == 'self':
if len(args) == 1:
print method(ctl)
else:
cleanargs = []
for param in progargs[1:]:
try:
argtype, argval = param.split(':', 1)
except ValueError:
cleanargs.append( param.decode(options.encoding) )
else:
cleanval = {
'bool': lambda val: val in ('True', 'true', '1', 'Yes', 'yes'),
'int': int,
'float': float,
'string': str
}[ argtype ]( argval )
if argtype == 'string':
cleanval = cleanval.decode(options.encoding)
cleanargs.append(cleanval)
if options.verbose:
print >> sys.stderr, "Call arguments: %s" % repr(cleanargs)
print method( ctl, *cleanargs )
elif len(args) == 1:
print >> sys.stderr, "Method '%s' does not take any arguments." % progargs[0]
print >> sys.stderr, "Expected %s()" % progargs[0]
else:
print >> sys.stderr, "Invalid arguments for method '%s': %s" % ( progargs[0], ', '.join( progargs[1:] ) )
print >> sys.stderr, "Expected %s( %s )" % ( progargs[0], ', '.join( args[1:] ) )

595
pyweb/mumble/MumbleCtlDbus.py

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

1117
pyweb/mumble/MumbleCtlIce.py
File diff suppressed because it is too large
View File

39
pyweb/mumble/__init__.py

@ -1,4 +1,5 @@
# -*- coding: utf-8 -*-
# kate: space-indent on; indent-width 4; replace-tabs on;
"""
* Copyright © 2009-2010, Michael "Svedrin" Ziegler <diese-addy@funzt-halt.net>
*
@ -16,29 +17,29 @@
version = { 'major': 2, 'minor': 2, 'beta': None }
if version['beta']:
version_str = "v%(major)d.%(minor)dbeta%(beta)d" % version
version_str = "v%(major)d.%(minor)dbeta%(beta)d" % version
else:
version_str = "v%(major)d.%(minor)d" % version
version_str = "v%(major)d.%(minor)d" % version
def getVersions():
""" Generator that yields all available upstream versions. """
url = 'http://bitbucket.org/Svedrin/mumble-django/raw/tip/.hgtags'
from urllib2 import urlopen
webtags = urlopen(url)
try:
while True:
line = webtags.readline().strip()
if not line:
raise StopIteration
_, version = line.split(' ')
yield version
finally:
webtags.close()
""" Generator that yields all available upstream versions. """
url = 'http://bitbucket.org/Svedrin/mumble-django/raw/tip/.hgtags'
from urllib2 import urlopen
webtags = urlopen(url)
try:
while True:
line = webtags.readline().strip()
if not line:
raise StopIteration
_, version = line.split(' ')
yield version
finally:
webtags.close()
def getLatestUpstreamVersion():
""" Return the latest version available upstream. """
return max(getVersions())
""" Return the latest version available upstream. """
return max(getVersions())
def isUptodate():
""" Check if this version of Mumble-Django is the latest available. """
return version_str >= getLatestUpstreamVersion()
""" Check if this version of Mumble-Django is the latest available. """
return version_str >= getLatestUpstreamVersion()

231
pyweb/mumble/admin.py

@ -1,4 +1,5 @@
# -*- coding: utf-8 -*-
# kate: space-indent on; indent-width 4; replace-tabs on;
"""
* Copyright © 2009-2010, Michael "Svedrin" Ziegler <diese-addy@funzt-halt.net>
@ -22,124 +23,124 @@ from mumble.forms import MumbleServerForm, MumbleAdminForm, MumbleUserAdminForm
from mumble.models import MumbleServer, Mumble, MumbleUser
class MumbleServerAdmin(admin.ModelAdmin):
list_display = [ 'dbus', 'get_murmur_online', 'get_murmur_version' ]
search_fields = [ 'dbus' ]
ordering = [ 'dbus' ]
form = MumbleServerForm
def get_murmur_online( self, obj ):
return obj.online
get_murmur_online.short_description = _('Master is running')
get_murmur_online.boolean = True
def get_murmur_version( self, obj ):
if obj.online:
return obj.prettyversion
return "?"
get_murmur_version.short_description = _("Server version")
list_display = [ 'dbus', 'get_murmur_online', 'get_murmur_version' ]
search_fields = [ 'dbus' ]
ordering = [ 'dbus' ]
form = MumbleServerForm
def get_murmur_online( self, obj ):
return obj.online
get_murmur_online.short_description = _('Master is running')
get_murmur_online.boolean = True
def get_murmur_version( self, obj ):
if obj.online:
return obj.prettyversion
return "?"
get_murmur_version.short_description = _("Server version")
class MumbleAdmin(admin.ModelAdmin):
""" Specification for the "Server administration" admin section. """
list_display = [ 'name', 'srvid', 'get_addr', 'get_port', 'get_murmur_online', 'get_booted',
'get_is_public', 'get_users_regged', 'get_users_online', 'get_channel_count' ];
list_filter = [ 'addr', 'server' ];
search_fields = [ 'name', 'addr', 'port' ];
ordering = [ 'name' ];
form = MumbleAdminForm;
def get_murmur_online( self, obj ):
return obj.server.online
get_murmur_online.short_description = _('Master is running')
get_murmur_online.boolean = True
def get_addr( self, obj ):
if not obj.addr:
return "*"
return obj.addr
get_addr.short_description = _('Server Address')
def get_port( self, obj ):
if not obj.port:
return '< %d >' % (obj.server.defaultPort + obj.srvid - 1)
return obj.port
get_port.short_description = _('Server Port')
def get_booted( self, obj ):
return obj.booted
get_booted.short_description = _('Instance is running')
get_booted.boolean = True
def get_users_regged( self, obj ):
""" Populates the "Registered users" column. """
if obj.booted:
return obj.users_regged;
else:
return '-';
get_users_regged.short_description = _( 'Registered users' );
def get_users_online( self, obj ):
""" Populates the "Online users" column. """
if obj.booted:
return obj.users_online;
else:
return '-';
get_users_online.short_description = _( 'Online users' );
def get_channel_count( self, obj ):
""" Populates the "Channel Count" column. """
if obj.booted:
return obj.channel_cnt;
else:
return '-';
get_channel_count.short_description = _( 'Channel count' );
def get_is_public( self, obj ):
""" Populates the "Public" column. """
if obj.booted:
if obj.is_public:
return _( 'Yes' );
else:
return _( 'No' );
else:
return '-';
get_is_public.short_description = _( 'Public' );
""" Specification for the "Server administration" admin section. """
list_display = [ 'name', 'srvid', 'get_addr', 'get_port', 'get_murmur_online', 'get_booted',
'get_is_public', 'get_users_regged', 'get_users_online', 'get_channel_count' ]
list_filter = [ 'addr', 'server' ]
search_fields = [ 'name', 'addr', 'port' ]
ordering = [ 'name' ]
form = MumbleAdminForm
def get_murmur_online( self, obj ):
return obj.server.online
get_murmur_online.short_description = _('Master is running')
get_murmur_online.boolean = True
def get_addr( self, obj ):
if not obj.addr:
return "*"
return obj.addr
get_addr.short_description = _('Server Address')
def get_port( self, obj ):
if not obj.port:
return '< %d >' % (obj.server.defaultPort + obj.srvid - 1)
return obj.port
get_port.short_description = _('Server Port')
def get_booted( self, obj ):
return obj.booted
get_booted.short_description = _('Instance is running')
get_booted.boolean = True
def get_users_regged( self, obj ):
""" Populates the "Registered users" column. """
if obj.booted:
return obj.users_regged
else:
return '-'
get_users_regged.short_description = _( 'Registered users' )
def get_users_online( self, obj ):
""" Populates the "Online users" column. """
if obj.booted:
return obj.users_online
else:
return '-'
get_users_online.short_description = _( 'Online users' )
def get_channel_count( self, obj ):
""" Populates the "Channel Count" column. """
if obj.booted:
return obj.channel_cnt
else:
return '-'
get_channel_count.short_description = _( 'Channel count' )
def get_is_public( self, obj ):
""" Populates the "Public" column. """
if obj.booted:
if obj.is_public:
return _( 'Yes' )
else:
return _( 'No' )
else:
return '-'
get_is_public.short_description = _( 'Public' )
class MumbleUserAdmin(admin.ModelAdmin):
""" Specification for the "Registered users" admin section. """
list_display = [ 'owner', 'server', 'name', 'mumbleid', 'get_acl_admin' ];
list_filter = [ 'server' ];
search_fields = [ 'owner__username', 'name' ];
ordering = [ 'owner__username' ];
form = MumbleUserAdminForm
def get_acl_admin( self, obj ):
if obj.server.booted:
return obj.aclAdmin
return None
get_acl_admin.short_description = _('Admin on root channel')
get_acl_admin.boolean = True
admin.site.register( MumbleServer, MumbleServerAdmin );
admin.site.register( Mumble, MumbleAdmin );
admin.site.register( MumbleUser, MumbleUserAdmin );
""" 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' ]
form = MumbleUserAdminForm
def get_acl_admin( self, obj ):
if obj.server.booted:
return obj.aclAdmin
return None
get_acl_admin.short_description = _('Admin on root channel')
get_acl_admin.boolean = True
admin.site.register( MumbleServer, MumbleServerAdmin )
admin.site.register( Mumble, MumbleAdmin )
admin.site.register( MumbleUser, MumbleUserAdmin )

547
pyweb/mumble/forms.py

@ -1,4 +1,5 @@
# -*- coding: utf-8 -*-
# kate: space-indent on; indent-width 4; replace-tabs on;
"""
* Copyright © 2009-2010, Michael "Svedrin" Ziegler <diese-addy@funzt-halt.net>
@ -17,309 +18,309 @@
import socket
import re
from django import forms
from django.conf import settings
from django.forms import Form, ModelForm
from django.utils.translation import ugettext_lazy as _
from django import forms
from django.conf import settings
from django.forms import Form, ModelForm
from django.utils.translation import ugettext_lazy as _
from mumble.models import MumbleServer, Mumble, MumbleUser
from mumble.models import MumbleServer, Mumble, MumbleUser
class PropertyModelForm( ModelForm ):
""" ModelForm that gets/sets fields that are not within the model's
fields as model attributes. Necessary to get forms that manipulate
properties.
"""
def __init__( self, *args, **kwargs ):
ModelForm.__init__( self, *args, **kwargs );
if self.instance:
instfields = self.instance._meta.get_all_field_names()
for fldname in self.fields:
if fldname in instfields:
continue
self.fields[fldname].initial = getattr( self.instance, fldname )
prop = getattr( self.instance.__class__, fldname )
if prop.__doc__:
self.fields[fldname].label = _(prop.__doc__)
def save( self, commit=True ):
inst = ModelForm.save( self, commit=commit )
if commit:
self.save_to_model( inst )
else:
# Update when the model has been saved.
from django.db.models import signals
self._update_inst = inst
signals.post_save.connect( self.save_listener, sender=inst.__class__ )
return inst
def save_listener( self, **kwargs ):
if kwargs['instance'] is self._update_inst:
self.save_to_model( self._update_inst )
def save_to_model( self, inst ):
instfields = inst._meta.get_all_field_names()
for fldname in self.fields:
if fldname not in instfields:
setattr( inst, fldname, self.cleaned_data[fldname] )
""" ModelForm that gets/sets fields that are not within the model's
fields as model attributes. Necessary to get forms that manipulate
properties.
"""
def __init__( self, *args, **kwargs ):
ModelForm.__init__( self, *args, **kwargs )
if self.instance:
instfields = self.instance._meta.get_all_field_names()
for fldname in self.fields:
if fldname in instfields:
continue
self.fields[fldname].initial = getattr( self.instance, fldname )
prop = getattr( self.instance.__class__, fldname )
if prop.__doc__:
self.fields[fldname].label = _(prop.__doc__)
def save( self, commit=True ):
inst = ModelForm.save( self, commit=commit )
if commit:
self.save_to_model( inst )
else:
# Update when the model has been saved.
from django.db.models import signals
self._update_inst = inst
signals.post_save.connect( self.save_listener, sender=inst.__class__ )
return inst
def save_listener( self, **kwargs ):
if kwargs['instance'] is self._update_inst:
self.save_to_model( self._update_inst )
def save_to_model( self, inst ):
instfields = inst._meta.get_all_field_names()
for fldname in self.fields:
if fldname not in instfields:
setattr( inst, fldname, self.cleaned_data[fldname] )
class MumbleForm( PropertyModelForm ):
""" The Mumble Server admin form that allows to configure settings which do
not necessarily have to be reserved to the server hoster.
Server hosters are expected to use the Django admin application instead,
where everything can be configured freely.
"""
url = forms.CharField( required=False )
motd = forms.CharField( required=False, widget=forms.Textarea )
passwd = forms.CharField( required=False, help_text=_(
"Password required to join. Leave empty for public servers.") )
supw = forms.CharField( required=False, widget=forms.PasswordInput )
obfsc = forms.BooleanField( required=False, help_text=_(
"If on, IP adresses of the clients are not logged.") )
player = forms.CharField( required=False )
channel = forms.CharField( required=False )
defchan = forms.TypedChoiceField( choices=(), coerce=int, required=False )
timeout = forms.IntegerField( required=False )
certreq = forms.BooleanField( required=False )
textlen = forms.IntegerField( required=False )
html = forms.BooleanField( required=False )
def __init__( self, *args, **kwargs ):
PropertyModelForm.__init__( self, *args, **kwargs )
# Populate the `default channel' field's choices
choices = [ ('', '----------') ]
if self.instance and self.instance.srvid is not None:
if self.instance.booted:
def add_item( item, level ):
if item.is_server or item.is_channel:
choices.append( ( item.chanid, ( "-"*level + " " + item.name ) ) )
self.instance.rootchan.visit(add_item)
else:
current = self.instance.defchan
if current is not None:
choices.append( ( current, "Current value: %d" % current ) )
self.fields['defchan'].choices = choices
class Meta:
model = Mumble;
fields = ['name'];
""" The Mumble Server admin form that allows to configure settings which do
not necessarily have to be reserved to the server hoster.
Server hosters are expected to use the Django admin application instead,
where everything can be configured freely.
"""
url = forms.CharField( required=False )
motd = forms.CharField( required=False, widget=forms.Textarea )
passwd = forms.CharField( required=False, help_text=_(
"Password required to join. Leave empty for public servers.") )
supw = forms.CharField( required=False, widget=forms.PasswordInput )
obfsc = forms.BooleanField( required=False, help_text=_(
"If on, IP adresses of the clients are not logged.") )
player = forms.CharField( required=False )
channel = forms.CharField( required=False )
defchan = forms.TypedChoiceField( choices=(), coerce=int, required=False )
timeout = forms.IntegerField( required=False )
certreq = forms.BooleanField( required=False )
textlen = forms.IntegerField( required=False )
html = forms.BooleanField( required=False )
def __init__( self, *args, **kwargs ):
PropertyModelForm.__init__( self, *args, **kwargs )
# Populate the `default channel' field's choices
choices = [ ('', '----------') ]
if self.instance and self.instance.srvid is not None:
if self.instance.booted:
def add_item( item, level ):
if item.is_server or item.is_channel:
choices.append( ( item.chanid, ( "-"*level + " " + item.name ) ) )
self.instance.rootchan.visit(add_item)
else:
current = self.instance.defchan
if current is not None:
choices.append( ( current, "Current value: %d" % current ) )
self.fields['defchan'].choices = choices
class Meta:
model = Mumble
fields = ['name']
class MumbleAdminForm( MumbleForm ):
""" A Mumble Server admin form intended to be used by the server hoster. """
users = forms.IntegerField( required=False )
bwidth = forms.IntegerField( required=False )
sslcrt = forms.CharField( required=False, widget=forms.Textarea )
sslkey = forms.CharField( required=False, widget=forms.Textarea )
booted = forms.BooleanField( required=False )
autoboot = forms.BooleanField( required=False )
bonjour = forms.BooleanField( required=False )
class Meta:
fields = None
exclude = None
def clean_port( self ):
""" Check if the port number is valid. """
port = self.cleaned_data['port'];
if port is not None and port != '':
if port < 1 or port >= 2**16:
raise forms.ValidationError(
_("Port number %(portno)d is not within the allowed range %(minrange)d - %(maxrange)d") % {
'portno': port,
'minrange': 1,
'maxrange': 2**16,
});
return port;
return None
""" A Mumble Server admin form intended to be used by the server hoster. """
users = forms.IntegerField( required=False )
bwidth = forms.IntegerField( required=False )
sslcrt = forms.CharField( required=False, widget=forms.Textarea )
sslkey = forms.CharField( required=False, widget=forms.Textarea )
booted = forms.BooleanField( required=False )
autoboot = forms.BooleanField( required=False )
bonjour = forms.BooleanField( required=False )
class Meta:
fields = None
exclude = None
def clean_port( self ):
""" Check if the port number is valid. """
port = self.cleaned_data['port']
if port is not None and port != '':
if port < 1 or port >= 2**16:
raise forms.ValidationError(
_("Port number %(portno)d is not within the allowed range %(minrange)d - %(maxrange)d") % {
'portno': port,
'minrange': 1,
'maxrange': 2**16,
})
return port
return None
class MumbleServerForm( ModelForm ):
defaultconf = forms.CharField( label=_("Default config"), required=False, widget=forms.Textarea )
def __init__( self, *args, **kwargs ):
ModelForm.__init__( self, *args, **kwargs )
if self.instance and self.instance.id:
if self.instance.online:
confstr = ""
conf = self.instance.defaultconf
for field in conf:
confstr += "%s: %s\n" % ( field, conf[field] )
self.fields["defaultconf"].initial = confstr
else:
self.fields["defaultconf"].initial = _("This server is currently offline.")
class Meta:
model = MumbleServer
defaultconf = forms.CharField( label=_("Default config"), required=False, widget=forms.Textarea )
def __init__( self, *args, **kwargs ):
ModelForm.__init__( self, *args, **kwargs )
if self.instance and self.instance.id:
if self.instance.online:
confstr = ""
conf = self.instance.defaultconf
for field in conf:
confstr += "%s: %s\n" % ( field, conf[field] )
self.fields["defaultconf"].initial = confstr
else:
self.fields["defaultconf"].initial = _("This server is currently offline.")
class Meta:
model = MumbleServer
class MumbleUserForm( ModelForm ):
""" The user registration form used to register an account. """
password = forms.CharField( widget=forms.PasswordInput, required=False )
def __init__( self, *args, **kwargs ):
ModelForm.__init__( self, *args, **kwargs );
self.server = None;
def clean_name( self ):
""" Check if the desired name is forbidden or taken. """
name = self.cleaned_data['name'];
if self.server is None:
raise AttributeError( "You need to set the form's server attribute to the server instance "
"for validation to work." );
if self.server.player and re.compile( self.server.player ).match( name ) is None:
raise forms.ValidationError( _( "That name is forbidden by the server." ) );
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." ) );
return name;
def clean_password( self ):
""" Verify a password has been given. """
passwd = self.cleaned_data['password'];
if not passwd and ( not self.instance or self.instance.mumbleid == -1 ):
raise forms.ValidationError( _( "Cannot register player without a password!" ) );
return passwd;
class Meta:
model = MumbleUser;
fields = ( 'name', 'password' );
""" The user registration form used to register an account. """
password = forms.CharField( widget=forms.PasswordInput, required=False )
def __init__( self, *args, **kwargs ):
ModelForm.__init__( self, *args, **kwargs )
self.server = None
def clean_name( self ):
""" Check if the desired name is forbidden or taken. """
name = self.cleaned_data['name']
if self.server is None:
raise AttributeError( "You need to set the form's server attribute to the server instance "
"for validation to work." )
if self.server.player and re.compile( self.server.player ).match( name ) is None:
raise forms.ValidationError( _( "That name is forbidden by the server." ) )
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." ) )
return name
def clean_password( self ):
""" Verify a password has been given. """
passwd = self.cleaned_data['password']
if not passwd and ( not self.instance or self.instance.mumbleid == -1 ):
raise forms.ValidationError( _( "Cannot register player without a password!" ) )
return passwd
class Meta:
model = MumbleUser
fields = ( 'name', 'password' )
class MumbleUserPasswordForm( MumbleUserForm ):
""" The user registration form used to register an account on a private server in protected mode. """
serverpw = forms.CharField(
label=_('Server Password'),
help_text=_('This server is private and protected mode is active. Please enter the server password.'),
widget=forms.PasswordInput(render_value=False)
);
def clean_serverpw( self ):
""" Validate the password """
serverpw = self.cleaned_data['serverpw'];
if self.server.passwd != serverpw:
raise forms.ValidationError( _( "The password you entered is incorrect." ) );
return serverpw;
def clean( self ):
""" prevent save() from trying to store the password in the Model instance. """
# clean() will be called after clean_serverpw(), so it has already been validated here.
if 'serverpw' in self.cleaned_data:
del( self.cleaned_data['serverpw'] );
return self.cleaned_data;
""" The user registration form used to register an account on a private server in protected mode. """
serverpw = forms.CharField(
label=_('Server Password'),
help_text=_('This server is private and protected mode is active. Please enter the server password.'),
widget=forms.PasswordInput(render_value=False)
)
def clean_serverpw( self ):
""" Validate the password """
serverpw = self.cleaned_data['serverpw']
if self.server.passwd != serverpw:
raise forms.ValidationError( _( "The password you entered is incorrect." ) )
return serverpw
def clean( self ):
""" prevent save() from trying to store the password in the Model instance. """
# clean() will be called after clean_serverpw(), so it has already been validated here.
if 'serverpw' in self.cleaned_data:
del( self.cleaned_data['serverpw'] )
return self.cleaned_data
class MumbleUserLinkForm( MumbleUserForm ):
""" Special registration form to either register or link an account. """
linkacc = forms.BooleanField(
label=_('Link account'),
help_text=_('The account already exists and belongs to me, just link it instead of creating.'),
required=False,
);
def __init__( self, *args, **kwargs ):
MumbleUserForm.__init__( self, *args, **kwargs );
self.mumbleid = None;
def clean_name( self ):
""" Check if the target account exists in Murmur. """
if 'linkacc' not in self.data:
return MumbleUserForm.clean_name( self );
# Check if user exists
name = self.cleaned_data['name'];
if len( self.server.ctl.getRegisteredPlayers( self.server.srvid, name ) ) != 1:
raise forms.ValidationError( _( "No such user found." ) );
return name;
def clean_password( self ):
""" Verify that the password is correct. """
if 'linkacc' not in self.data:
return MumbleUserForm.clean_password( self );
if 'name' not in self.cleaned_data:
# keep clean() from trying to find a user that CAN'T exist
self.mumbleid = -10;
return '';
# Validate password with Murmur
passwd = self.cleaned_data['password'];
self.mumbleid = self.server.ctl.verifyPassword( self.server.srvid, self.cleaned_data['name'], passwd )
if self.mumbleid <= 0:
raise forms.ValidationError( _( "The password you entered is incorrect." ) );
return passwd;
def clean( self ):
""" Create the MumbleUser instance to save in. """
if 'linkacc' not in self.data or self.mumbleid <= 0:
return self.cleaned_data;
try:
m_user = MumbleUser.objects.get( server=self.server, mumbleid=self.mumbleid );
except MumbleUser.DoesNotExist:
m_user = MumbleUser( server=self.server, name=self.cleaned_data['name'], mumbleid=self.mumbleid );
m_user.save( dontConfigureMurmur=True );
else:
if m_user.owner is not None:
raise forms.ValidationError( _( "That account belongs to someone else." ) );
if m_user.getAdmin() and not settings.ALLOW_ACCOUNT_LINKING_ADMINS:
raise forms.ValidationError( _( "Linking Admin accounts is not allowed." ) );
self.instance = m_user;
return self.cleaned_data;
""" Special registration form to either register or link an account. """
linkacc = forms.BooleanField(
label=_('Link account'),
help_text=_('The account already exists and belongs to me, just link it instead of creating.'),
required=False,
)
def __init__( self, *args, **kwargs ):
MumbleUserForm.__init__( self, *args, **kwargs )
self.mumbleid = None
def clean_name( self ):
""" Check if the target account exists in Murmur. """
if 'linkacc' not in self.data:
return MumbleUserForm.clean_name( self )
# Check if user exists
name = self.cleaned_data['name']
if len( self.server.ctl.getRegisteredPlayers( self.server.srvid, name ) ) != 1:
raise forms.ValidationError( _( "No such user found." ) )
return name
def clean_password( self ):
""" Verify that the password is correct. """
if 'linkacc' not in self.data:
return MumbleUserForm.clean_password( self )
if 'name' not in self.cleaned_data:
# keep clean() from trying to find a user that CAN'T exist
self.mumbleid = -10
return ''
# Validate password with Murmur
passwd = self.cleaned_data['password']
self.mumbleid = self.server.ctl.verifyPassword( self.server.srvid, self.cleaned_data['name'], passwd )
if self.mumbleid <= 0:
raise forms.ValidationError( _( "The password you entered is incorrect." ) )
return passwd
def clean( self ):
""" Create the MumbleUser instance to save in. """
if 'linkacc' not in self.data or self.mumbleid <= 0:
return self.cleaned_data
try:
m_user = MumbleUser.objects.get( server=self.server, mumbleid=self.mumbleid )
except MumbleUser.DoesNotExist:
m_user = MumbleUser( server=self.server, name=self.cleaned_data['name'], mumbleid=self.mumbleid )
m_user.save( dontConfigureMurmur=True )
else:
if m_user.owner is not None:
raise forms.ValidationError( _( "That account belongs to someone else." ) )
if m_user.getAdmin() and not settings.ALLOW_ACCOUNT_LINKING_ADMINS:
raise forms.ValidationError( _( "Linking Admin accounts is not allowed." ) )
self.instance = m_user
return self.cleaned_data
class MumbleUserAdminForm( PropertyModelForm ):
aclAdmin = forms.BooleanField( required=False );
password = forms.CharField( widget=forms.PasswordInput, required=False )
def clean_password( self ):
""" Verify a password has been given. """
passwd = self.cleaned_data['password'];
if not passwd and ( not self.instance or self.instance.mumbleid == -1 ):
raise forms.ValidationError( _( "Cannot register player without a password!" ) );
return passwd;
class Meta:
model = Mumble;
aclAdmin = forms.BooleanField( required=False )
password = forms.CharField( widget=forms.PasswordInput, required=False )
def clean_password( self ):
""" Verify a password has been given. """
passwd = self.cleaned_data['password']
if not passwd and ( not self.instance or self.instance.mumbleid == -1 ):
raise forms.ValidationError( _( "Cannot register player without a password!" ) )
return passwd
class Meta:
model = Mumble
class MumbleKickForm( Form ):
session = forms.IntegerField();
ban = forms.BooleanField( required=False );
reason = forms.CharField( required=False );
session = forms.IntegerField()
ban = forms.BooleanField( required=False )
reason = forms.CharField( required=False )
class MumbleTextureForm( Form ):
""" The form used to upload a new image to be set as texture. """
usegravatar = forms.BooleanField( required=False, label=_("Use my Gravatar as my Texture") );
texturefile = forms.ImageField( required=False, label=_("User Texture") );
""" 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") )

43
pyweb/mumble/management/__init__.py

@ -1,4 +1,5 @@
# -*- coding: utf-8 -*-
# kate: space-indent on; indent-width 4; replace-tabs on;
"""
* Copyright © 2009-2010, Michael "Svedrin" Ziegler <diese-addy@funzt-halt.net>
@ -14,24 +15,24 @@
* GNU General Public License for more details.
"""
from shutil import copy, move
from os.path import exists, join
from shutil import copy, move
from os.path import exists, join
from django.conf import settings
from django.db import connection
from django.db.models import signals
from django.conf import settings
from django.db import connection
from django.db.models import signals
from mumble import models
from mumble import models
from update_schema import update_schema
from server_detect import find_existing_instances
from update_schema import update_schema
from server_detect import find_existing_instances
if settings.DATABASE_ENGINE == "sqlite3":
# Move the DB to the db subdirectory if necessary.
oldpath = join( settings.MUMBLE_DJANGO_ROOT, "mumble-django.db3" )
if not exists( settings.DATABASE_NAME ) and exists( oldpath ):
move( oldpath, settings.DATABASE_NAME )
# Move the DB to the db subdirectory if necessary.
oldpath = join( settings.MUMBLE_DJANGO_ROOT, "mumble-django.db3" )
if not exists( settings.DATABASE_NAME ) and exists( oldpath ):
move( oldpath, settings.DATABASE_NAME )
cursor = connection.cursor()
@ -39,18 +40,18 @@ cursor = connection.cursor()
tablename = models.Mumble._meta.db_table
if tablename in connection.introspection.get_table_list(cursor):
fields = connection.introspection.get_table_description(cursor, tablename)
uptodate = "server_id" in [ entry[0] for entry in fields ]
fields = connection.introspection.get_table_description(cursor, tablename)
uptodate = "server_id" in [ entry[0] for entry in fields ]
else:
# Table doesn't yet exist, so syncdb will create it properly
uptodate = True
# Table doesn't yet exist, so syncdb will create it properly
uptodate = True
if not uptodate:
if settings.DATABASE_ENGINE == "sqlite3":
# backup the db before the conversion.
copy( settings.DATABASE_NAME, settings.DATABASE_NAME+".bak" )
signals.post_syncdb.connect( update_schema, sender=models );
if settings.DATABASE_ENGINE == "sqlite3":
# backup the db before the conversion.
copy( settings.DATABASE_NAME, settings.DATABASE_NAME+".bak" )
signals.post_syncdb.connect( update_schema, sender=models )
else:
signals.post_syncdb.connect( find_existing_instances, sender=models );
signals.post_syncdb.connect( find_existing_instances, sender=models )

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

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

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

@ -1,4 +1,5 @@
# -*- coding: utf-8 -*-
# kate: space-indent on; indent-width 4; replace-tabs on;
"""
* Copyright © 2009-2010, Michael "Svedrin" Ziegler <diese-addy@funzt-halt.net>
@ -16,184 +17,184 @@
import os
from django.core.management.base import BaseCommand
from django.contrib.auth.models import User
from django.contrib.sites.models import Site
from django.conf import settings
from django.core.management.base import BaseCommand
from django.contrib.auth.models import User
from django.contrib.sites.models import Site
from django.conf import settings
from mumble.models import Mumble
from mumble.models import Mumble
class TestFailed( Exception ):
pass;
pass
class Command( BaseCommand ):
help = "Run a few tests on Mumble-Django's setup."
def handle(self, **options):
try:
import Ice
except ImportError:
pass
else:
self.check_slice();
self.check_rootdir();
self.check_dbase();
self.check_sites();
self.check_mumbles();
self.check_admins();
self.check_secret_key();
def check_slice( self ):
print "Checking slice file...",
if settings.SLICE is None:
raise TestFailed( "You don't have set the SLICE variable in settings.py." )
if " " in settings.SLICE:
raise TestFailed( "You have a space char in your Slice path. This will confuse Ice, please check." )
if not settings.SLICE.endswith( ".ice" ):
raise TestFailed( "The slice file name MUST end with '.ice'." )
try:
fd = open( settings.SLICE, "rb" )
slice = fd.read()
fd.close()
except IOError, err:
raise TestFailed( "Failed opening the slice file: %s" % err )
import Ice
Ice.loadSlice( settings.SLICE )
print "[ OK ]"
def check_rootdir( self ):
print "Checking root directory access...",
if not os.path.exists( settings.MUMBLE_DJANGO_ROOT ):
raise TestFailed( "The mumble-django root directory does not exist." );
elif settings.DATABASE_ENGINE != "sqlite3":
print "not using sqlite [ OK ]"
else:
statinfo = os.stat( settings.MUMBLE_DJANGO_ROOT );
if statinfo.st_uid == 0:
raise TestFailed(
"The mumble-django root directory belongs to user root. This is "
"most certainly not what you want because it will prevent your "
"web server from being able to write to the database. Please check." );
elif not os.access( settings.MUMBLE_DJANGO_ROOT, os.W_OK ):
raise TestFailed( "The mumble-django root directory is not writable." );
else:
print "[ OK ]";
def check_dbase( self ):
print "Checking database access...",
if settings.DATABASE_ENGINE == "sqlite3":
if not os.path.exists( settings.DATABASE_NAME ):
raise TestFailed( "database does not exist. Have you run syncdb yet?" );
else:
statinfo = os.stat( settings.DATABASE_NAME );
if statinfo.st_uid == 0:
raise TestFailed(
"the database file belongs to root. This is most certainly not what "
"you want because it will prevent your web server from being able "
"to write to it. Please check." );
elif not os.access( settings.DATABASE_NAME, os.W_OK ):
raise TestFailed( "database file is not writable." );
else:
print "[ OK ]";
else:
print "not using sqlite, so I can't check.";
def check_sites( self ):
print "Checking URL configuration...",
try:
site = Site.objects.get_current();
except Site.DoesNotExist:
try:
sid = settings.SITE_ID
except AttributeError:
from django.core.exceptions import ImproperlyConfigured
raise ImproperlyConfigured(
"You're using the Django \"sites framework\" without having set the SITE_ID "
"setting. Create a site in your database and rerun this command to fix this error.")
else:
print( "none set.\n"
"Please enter the domain where Mumble-Django is reachable." );
dom = raw_input( "> " ).strip();
site = Site( id=sid, name=dom, domain=dom );
site.save();
if site.domain == 'example.com':
print( "still the default.\n"
"The domain is configured as example.com, which is the default but does not make sense. "
"Please enter the domain where Mumble-Django is reachable." );
site.domain = raw_input( "> " ).strip();
site.save();
print site.domain, "[ OK ]";
def check_admins( self ):
print "Checking if an Admin user exists...",
for user in User.objects.all():
if user.is_superuser:
print "[ OK ]";
return;
raise TestFailed( ""
"No admin user exists, so you won't be able to log in to the admin system. You "
"should run `./manage.py createsuperuser` to create one." );
def check_mumbles( self ):
print "Checking Murmur instances...",
mm = Mumble.objects.all();
if mm.count() == 0:
raise TestFailed(
"no Mumble servers are configured, you might want to run "
"`./manage.py syncdb` to run an auto detection." );
else:
for mumble in mm:
try:
mumble.ctl
except Exception, err:
raise TestFailed(
"Connecting to Murmur `%s` (%s) failed: %s" % ( mumble.name, mumble.server, err )
);
print "[ OK ]";
def check_secret_key( self ):
print "Checking SECRET_KEY...",
blacklist = ( 'u-mp185msk#z4%s(do2^5405)y5d!9adbn92)apu_p^qvqh10v', );
if settings.SECRET_KEY in blacklist:
raise TestFailed(
"Your SECRET_KEY setting matches one of the keys that were put in the settings.py "
"file shipped with Mumble-Django, which means your SECRET_KEY is all but secret. "
"You should change the setting, or run gen_secret_key.sh to do it for you."
);
else:
print "[ OK ]";
help = "Run a few tests on Mumble-Django's setup."
def handle(self, **options):
try:
import Ice
except ImportError:
pass
else:
self.check_slice()
self.check_rootdir()
self.check_dbase()
self.check_sites()
self.check_mumbles()
self.check_admins()
self.check_secret_key()
def check_slice( self ):
print "Checking slice file...",
if settings.SLICE is None:
raise TestFailed( "You don't have set the SLICE variable in settings.py." )
if " " in settings.SLICE:
raise TestFailed( "You have a space char in your Slice path. This will confuse Ice, please check." )
if not settings.SLICE.endswith( ".ice" ):
raise TestFailed( "The slice file name MUST end with '.ice'." )
try:
fd = open( settings.SLICE, "rb" )
slice = fd.read()
fd.close()
except IOError, err:
raise TestFailed( "Failed opening the slice file: %s" % err )
import Ice
Ice.loadSlice( settings.SLICE )
print "[ OK ]"
def check_rootdir( self ):
print "Checking root directory access...",
if not os.path.exists( settings.MUMBLE_DJANGO_ROOT ):
raise TestFailed( "The mumble-django root directory does not exist." )
elif settings.DATABASE_ENGINE != "sqlite3":
print "not using sqlite [ OK ]"
else:
statinfo = os.stat( settings.MUMBLE_DJANGO_ROOT )
if statinfo.st_uid == 0:
raise TestFailed(
"The mumble-django root directory belongs to user root. This is "
"most certainly not what you want because it will prevent your "
"web server from being able to write to the database. Please check." )
elif not os.access( settings.MUMBLE_DJANGO_ROOT, os.W_OK ):
raise TestFailed( "The mumble-django root directory is not writable." )
else:
print "[ OK ]"
def check_dbase( self ):
print "Checking database access...",
if settings.DATABASE_ENGINE == "sqlite3":
if not os.path.exists( settings.DATABASE_NAME ):
raise TestFailed( "database does not exist. Have you run syncdb yet?" )
else:
statinfo = os.stat( settings.DATABASE_NAME )
if statinfo.st_uid == 0:
raise TestFailed(
"the database file belongs to root. This is most certainly not what "
"you want because it will prevent your web server from being able "
"to write to it. Please check." )
elif not os.access( settings.DATABASE_NAME, os.W_OK ):
raise TestFailed( "database file is not writable." )
else:
print "[ OK ]"
else:
print "not using sqlite, so I can't check."
def check_sites( self ):
print "Checking URL configuration...",
try:
site = Site.objects.get_current()
except Site.DoesNotExist:
try:
sid = settings.SITE_ID
except AttributeError:
from django.core.exceptions import ImproperlyConfigured
raise ImproperlyConfigured(
"You're using the Django \"sites framework\" without having set the SITE_ID "
"setting. Create a site in your database and rerun this command to fix this error.")
else:
print( "none set.\n"
"Please enter the domain where Mumble-Django is reachable." )
dom = raw_input( "> " ).strip()
site = Site( id=sid, name=dom, domain=dom )
site.save()
if site.domain == 'example.com':
print( "still the default.\n"
"The domain is configured as example.com, which is the default but does not make sense. "
"Please enter the domain where Mumble-Django is reachable." )
site.domain = raw_input( "> " ).strip()
site.save()
print site.domain, "[ OK ]"
def check_admins( self ):
print "Checking if an Admin user exists...",
for user in User.objects.all():
if user.is_superuser:
print "[ OK ]"
return
raise TestFailed( ""
"No admin user exists, so you won't be able to log in to the admin system. You "
"should run `./manage.py createsuperuser` to create one." )
def check_mumbles( self ):
print "Checking Murmur instances...",
mm = Mumble.objects.all()
if mm.count() == 0:
raise TestFailed(
"no Mumble servers are configured, you might want to run "
"`./manage.py syncdb` to run an auto detection." )
else:
for mumble in mm:
try:
mumble.ctl
except Exception, err:
raise TestFailed(
"Connecting to Murmur `%s` (%s) failed: %s" % ( mumble.name, mumble.server, err )
)
print "[ OK ]"
def check_secret_key( self ):
print "Checking SECRET_KEY...",
blacklist = ( 'u-mp185msk#z4%s(do2^5405)y5d!9adbn92)apu_p^qvqh10v', )
if settings.SECRET_KEY in blacklist:
raise TestFailed(
"Your SECRET_KEY setting matches one of the keys that were put in the settings.py "
"file shipped with Mumble-Django, which means your SECRET_KEY is all but secret. "
"You should change the setting, or run gen_secret_key.sh to do it for you."
)
else:
print "[ OK ]"

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

@ -1,4 +1,5 @@
# -*- coding: utf-8 -*-
# kate: space-indent on; indent-width 4; replace-tabs on;
"""
* Copyright © 2009-2010, Michael "Svedrin" Ziegler <diese-addy@funzt-halt.net>
@ -17,41 +18,41 @@
import Ice, IcePy, os, getpass
from sys import stderr
from django.core.management.base import BaseCommand
from django.core.management.base import BaseCommand
from mumble.models import MumbleServer
from mumble.models import MumbleServer
class Command( BaseCommand ):
help = "Check if the known servers support getSlice."
def handle(self, **options):
prop = Ice.createProperties([])
prop.setProperty("Ice.ImplicitContext", "Shared")
idd = Ice.InitializationData()
idd.properties = prop
ice = Ice.initialize(idd)
for serv in MumbleServer.objects.all():
print >>stderr, "Probing server at '%s'..." % serv.dbus
if serv.secret:
ice.getImplicitContext().put( "secret", serv.secret.encode("utf-8") )
prx = ice.stringToProxy( serv.dbus.encode("utf-8") )
# Try loading the Slice from Murmur directly via its getSlice method.
try:
slice = IcePy.Operation( 'getSlice',
Ice.OperationMode.Idempotent, Ice.OperationMode.Idempotent,
True, (), (), (), IcePy._t_string, ()
).invoke(prx, ((), None))
except TypeError, err:
print >>stderr, " Received TypeError:", err
print >>stderr, " It seems your version of IcePy is incompatible."
except Ice.OperationNotExistException:
print >>stderr, " Your version of Murmur does not support getSlice."
else:
print slice
print >>stderr, " Successfully received the slice (length: %d bytes.)" % len(slice)
help = "Check if the known servers support getSlice."
def handle(self, **options):
prop = Ice.createProperties([])
prop.setProperty("Ice.ImplicitContext", "Shared")
idd = Ice.InitializationData()
idd.properties = prop
ice = Ice.initialize(idd)
for serv in MumbleServer.objects.all():
print >>stderr, "Probing server at '%s'..." % serv.dbus
if serv.secret:
ice.getImplicitContext().put( "secret", serv.secret.encode("utf-8") )
prx = ice.stringToProxy( serv.dbus.encode("utf-8") )
# Try loading the Slice from Murmur directly via its getSlice method.
try:
slice = IcePy.Operation( 'getSlice',
Ice.OperationMode.Idempotent, Ice.OperationMode.Idempotent,
True, (), (), (), IcePy._t_string, ()
).invoke(prx, ((), None))
except TypeError, err:
print >>stderr, " Received TypeError:", err
print >>stderr, " It seems your version of IcePy is incompatible."
except Ice.OperationNotExistException:
print >>stderr, " Your version of Murmur does not support getSlice."
else:
print slice
print >>stderr, " Successfully received the slice (length: %d bytes.)" % len(slice)

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

@ -1,4 +1,5 @@
# -*- coding: utf-8 -*-
# kate: space-indent on; indent-width 4; replace-tabs on;
"""
* Copyright © 2009-2010, Michael "Svedrin" Ziegler <diese-addy@funzt-halt.net>
@ -14,8 +15,8 @@
* GNU General Public License for more details.
"""
from django.core.management.commands.runserver import Command as OrigCommand
from mumble.murmurenvutils import MumbleCommandWrapper
from django.core.management.commands.runserver import Command as OrigCommand
from mumble.murmurenvutils import MumbleCommandWrapper
class Command( MumbleCommandWrapper, OrigCommand ):
pass
pass

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

@ -1,4 +1,5 @@
# -*- coding: utf-8 -*-
# kate: space-indent on; indent-width 4; replace-tabs on;
"""
* Copyright © 2009-2010, Michael "Svedrin" Ziegler <diese-addy@funzt-halt.net>
@ -14,8 +15,8 @@
* GNU General Public License for more details.
"""
from django.core.management.commands.shell import Command as OrigCommand
from mumble.murmurenvutils import MumbleCommandWrapper_noargs
from django.core.management.commands.shell import Command as OrigCommand
from mumble.murmurenvutils import MumbleCommandWrapper_noargs
class Command( MumbleCommandWrapper_noargs, OrigCommand ):
pass
pass

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

@ -1,4 +1,5 @@
# -*- coding: utf-8 -*-
# kate: space-indent on; indent-width 4; replace-tabs on;
"""
* Copyright © 2009-2010, Michael "Svedrin" Ziegler <diese-addy@funzt-halt.net>
@ -14,8 +15,8 @@
* GNU General Public License for more details.
"""
from django.core.management.commands.syncdb import Command as OrigCommand
from mumble.murmurenvutils import MumbleCommandWrapper_noargs
from django.core.management.commands.syncdb import Command as OrigCommand
from mumble.murmurenvutils import MumbleCommandWrapper_noargs
class Command( MumbleCommandWrapper_noargs, OrigCommand ):
pass
pass

279
pyweb/mumble/management/server_detect.py

@ -1,4 +1,5 @@
# -*- coding: utf-8 -*-
# kate: space-indent on; indent-width 4; replace-tabs on;
"""
* Copyright © 2009-2010, Michael "Svedrin" Ziegler <diese-addy@funzt-halt.net>
@ -16,154 +17,154 @@
import os, getpass
from django.db import DatabaseError
from django.conf import settings
from django.db import DatabaseError
from django.conf import settings
from mumble.models import MumbleServer, Mumble
from mumble.mctl import MumbleCtlBase
from mumble.models import MumbleServer, Mumble
from mumble.mctl import MumbleCtlBase
def find_in_dicts( keys, conf, default, valueIfNotFound=None ):
if not isinstance( keys, tuple ):
keys = ( keys, );
if not isinstance( keys, tuple ):
keys = ( keys, )
for keyword in keys:
if keyword in conf:
return conf[keyword];
for keyword in keys:
if keyword in conf:
return conf[keyword]
for keyword in keys:
keyword = keyword.lower();
if keyword in default:
return default[keyword];
for keyword in keys:
keyword = keyword.lower()
if keyword in default:
return default[keyword]
return valueIfNotFound;
return valueIfNotFound
def find_existing_instances( **kwargs ):
if "verbosity" in kwargs:
v = kwargs['verbosity'];
else:
v = 1;
if v > 1:
print "Starting Mumble servers and players detection now.";
triedEnviron = False;
online = False;
while not online:
if not triedEnviron and 'MURMUR_CONNSTR' in os.environ:
dbusName = os.environ['MURMUR_CONNSTR'];
triedEnviron = True;
if v > 1:
print "Trying environment setting", dbusName;
else:
print "--- Murmur connection info ---"
print " 1) DBus -- net.sourceforge.mumble.murmur"
print " 2) ICE -- Meta:tcp -h 127.0.0.1 -p 6502"
print "Enter 1 or 2 for the defaults above, nothing to skip Server detection,"
print "and if the defaults do not fit your needs, enter the correct string."
print "Whether to use DBus or Ice will be detected automatically from the"
print "string's format."
print
dbusName = raw_input( "Service string: " ).strip();
if not dbusName:
if v:
print 'Be sure to run "python manage.py syncdb" with Murmur running before'
print "trying to use this app! Otherwise, existing Murmur servers won't be"
print 'configurable!';
return False;
elif dbusName == "1":
dbusName = "net.sourceforge.mumble.murmur";
elif dbusName == "2":
dbusName = "Meta:tcp -h 127.0.0.1 -p 6502";
icesecret = getpass.getpass("Please enter the Ice secret (if any): ");
try:
ctl = MumbleCtlBase.newInstance( dbusName, settings.SLICE, icesecret );
except Exception, instance:
if v:
print "Unable to connect using name %s. The error was:" % dbusName;
print instance;
print
else:
online = True;
if v > 1:
print "Successfully connected to Murmur via connection string %s, using %s." % ( dbusName, ctl.method );
servIDs = ctl.getAllServers();
try:
meta = MumbleServer.objects.get( dbus=dbusName );
except MumbleServer.DoesNotExist:
meta = MumbleServer( dbus=dbusName );
finally:
meta.secret = icesecret;
meta.save();
for id in servIDs:
if v > 1:
print "Checking Murmur instance with id %d." % id;
# first check that the server has not yet been inserted into the DB
try:
instance = Mumble.objects.get( server=meta, srvid=id );
except Mumble.DoesNotExist:
values = {
"server": meta,
"srvid": id,
}
if v:
print "Found new Murmur instance %d on bus '%s'... " % ( id, dbusName )
# now create a model for the record set.
instance = Mumble( **values );
else:
if v:
print "Syncing Murmur instance %d: '%s'... " % ( instance.id, instance.name )
try:
instance.configureFromMurmur();
except DatabaseError, err:
try:
# Find instances with the same address/port
dup = Mumble.objects.get( addr=instance.addr, port=instance.port )
except Mumble.DoesNotExist:
# None exist - this must've been something else.
print "Server ID / Name: %d / %s" % ( instance.srvid, instance.name )
raise err
else:
print "ERROR: There is already another server instance registered"
print " on the same address and port."
print " -------------"
print " New Server ID:", instance.srvid,
print " New Server Name:", instance.name
print " Address:", instance.addr
print " Port:", instance.port
print " Connection string:", instance.server.dbus
print " -------------"
print " Duplicate Server ID:", dup.srvid,
print "Duplicate Server Name:", dup.name
print " Address:", dup.addr
print " Port:", dup.port
print " Connection string:", dup.server.dbus
return False
except Exception, err:
print "Server ID / Name: %d / %s" % ( instance.srvid, instance.name )
raise err
# Now search for players on this server that have not yet been registered
if instance.booted:
if v > 1:
print "Looking for registered Players on Server id %d." % id;
instance.readUsersFromMurmur( verbose=v );
elif v:
print "This server is not running, can't sync players.";
if v > 1:
print "Successfully finished Servers and Players detection.";
return True;
if "verbosity" in kwargs:
v = kwargs['verbosity']
else:
v = 1
if v > 1:
print "Starting Mumble servers and players detection now."
triedEnviron = False
online = False
while not online:
if not triedEnviron and 'MURMUR_CONNSTR' in os.environ:
dbusName = os.environ['MURMUR_CONNSTR']
triedEnviron = True
if v > 1:
print "Trying environment setting", dbusName
else:
print "--- Murmur connection info ---"
print " 1) DBus -- net.sourceforge.mumble.murmur"
print " 2) ICE -- Meta:tcp -h 127.0.0.1 -p 6502"
print "Enter 1 or 2 for the defaults above, nothing to skip Server detection,"
print "and if the defaults do not fit your needs, enter the correct string."
print "Whether to use DBus or Ice will be detected automatically from the"
print "string's format."
print
dbusName = raw_input( "Service string: " ).strip()
if not dbusName:
if v:
print 'Be sure to run "python manage.py syncdb" with Murmur running before'
print "trying to use this app! Otherwise, existing Murmur servers won't be"
print 'configurable!'
return False
elif dbusName == "1":
dbusName = "net.sourceforge.mumble.murmur"
elif dbusName == "2":
dbusName = "Meta:tcp -h 127.0.0.1 -p 6502"
icesecret = getpass.getpass("Please enter the Ice secret (if any): ")
try:
ctl = MumbleCtlBase.newInstance( dbusName, settings.SLICE, icesecret )
except Exception, instance:
if v:
print "Unable to connect using name %s. The error was:" % dbusName
print instance
print
else:
online = True
if v > 1:
print "Successfully connected to Murmur via connection string %s, using %s." % ( dbusName, ctl.method )
servIDs = ctl.getAllServers()
try:
meta = MumbleServer.objects.get( dbus=dbusName )
except MumbleServer.DoesNotExist:
meta = MumbleServer( dbus=dbusName )
finally:
meta.secret = icesecret
meta.save()
for id in servIDs:
if v > 1:
print "Checking Murmur instance with id %d." % id
# first check that the server has not yet been inserted into the DB
try:
instance = Mumble.objects.get( server=meta, srvid=id )
except Mumble.DoesNotExist:
values = {
"server": meta,
"srvid": id,
}
if v:
print "Found new Murmur instance %d on bus '%s'... " % ( id, dbusName )
# now create a model for the record set.
instance = Mumble( **values )
else:
if v:
print "Syncing Murmur instance %d: '%s'... " % ( instance.id, instance.name )
try:
instance.configureFromMurmur()
except DatabaseError, err:
try:
# Find instances with the same address/port
dup = Mumble.objects.get( addr=instance.addr, port=instance.port )
except Mumble.DoesNotExist:
# None exist - this must've been something else.
print "Server ID / Name: %d / %s" % ( instance.srvid, instance.name )
raise err
else:
print "ERROR: There is already another server instance registered"
print " on the same address and port."
print " -------------"
print " New Server ID:", instance.srvid,
print " New Server Name:", instance.name
print " Address:", instance.addr
print " Port:", instance.port
print " Connection string:", instance.server.dbus
print " -------------"
print " Duplicate Server ID:", dup.srvid,
print "Duplicate Server Name:", dup.name
print " Address:", dup.addr
print " Port:", dup.port
print " Connection string:", dup.server.dbus
return False
except Exception, err:
print "Server ID / Name: %d / %s" % ( instance.srvid, instance.name )
raise err
# Now search for players on this server that have not yet been registered
if instance.booted:
if v > 1:
print "Looking for registered Players on Server id %d." % id
instance.readUsersFromMurmur( verbose=v )
elif v:
print "This server is not running, can't sync players."
if v > 1:
print "Successfully finished Servers and Players detection."
return True

107
pyweb/mumble/management/update_schema.py

@ -1,4 +1,5 @@
# -*- coding: utf-8 -*-
# kate: space-indent on; indent-width 4; replace-tabs on;
"""
* Copyright © 2010, Michael "Svedrin" Ziegler <diese-addy@funzt-halt.net>
@ -15,62 +16,62 @@
"""
import os
from os.path import join
from os.path import join
from django.db import connection, transaction
from django.db.models import signals
from django.conf import settings
from django.db import connection, transaction
from django.db.models import signals
from django.conf import settings
from mumble import models
from mumble import models
from mumble.management.server_detect import find_existing_instances
def update_schema( **kwargs ):
if "verbosity" in kwargs:
v = kwargs['verbosity'];
else:
v = 1;
if v:
print "Migrating Database schema for Mumble-Django 2.0 now."
scriptdir = join( settings.CONVERSIONSQL_ROOT, {
'postgresql_psycopg2': 'pgsql',
'postgresql': 'pgsql',
'mysql': 'mysql',
'sqlite3': 'sqlite',
}[settings.DATABASE_ENGINE] )
if v > 1:
print "Reading migration scripts for %s from '%s'" % ( settings.DATABASE_ENGINE, scriptdir )
scripts = [ filename for filename in os.listdir( scriptdir ) if filename.endswith( ".sql" ) ]
scripts.sort()
for filename in scripts:
cursor = connection.cursor()
scriptpath = os.path.join( scriptdir, filename )
scriptfile = open( scriptpath, "r" )
try:
if v > 1:
print "Running migration script '%s'..." % scriptpath
stmt = scriptfile.read()
cursor.execute( stmt )
except IOError, err:
print "Error reading file '%s':" % filename
print err
except cursor.db.connection.Error, err:
print "Error executing file '%s':" % filename
print err
finally:
scriptfile.close()
cursor.close()
if v:
print "Database migration finished successfully."
find_existing_instances( **kwargs )
if "verbosity" in kwargs:
v = kwargs['verbosity']
else:
v = 1
if v:
print "Migrating Database schema for Mumble-Django 2.0 now."
scriptdir = join( settings.CONVERSIONSQL_ROOT, {
'postgresql_psycopg2': 'pgsql',
'postgresql': 'pgsql',
'mysql': 'mysql',
'sqlite3': 'sqlite',
}[settings.DATABASE_ENGINE] )
if v > 1:
print "Reading migration scripts for %s from '%s'" % ( settings.DATABASE_ENGINE, scriptdir )
scripts = [ filename for filename in os.listdir( scriptdir ) if filename.endswith( ".sql" ) ]
scripts.sort()
for filename in scripts:
cursor = connection.cursor()
scriptpath = os.path.join( scriptdir, filename )
scriptfile = open( scriptpath, "r" )
try:
if v > 1:
print "Running migration script '%s'..." % scriptpath
stmt = scriptfile.read()
cursor.execute( stmt )
except IOError, err:
print "Error reading file '%s':" % filename
print err
except cursor.db.connection.Error, err:
print "Error executing file '%s':" % filename
print err
finally:
scriptfile.close()
cursor.close()
if v:
print "Database migration finished successfully."
find_existing_instances( **kwargs )

77
pyweb/mumble/mctl.py

@ -1,4 +1,5 @@
# -*- coding: utf-8 -*-
# kate: space-indent on; indent-width 4; replace-tabs on;
"""
* Copyright © 2009, withgod <withgod@sourceforge.net>
@ -18,41 +19,41 @@
import re
class MumbleCtlBase(object):
""" This class defines the base interface that the Mumble model expects. """
cache = {};
@staticmethod
def newInstance( connstring, slicefile=None, icesecret=None ):
""" Create a new CTL object for the given connstring.
Optional parameters are the path to the slice file and the
Ice secret necessary to authenticate to Murmur.
The path can be omitted only if using DBus or running Murmur
1.2.3 or later, which exports a getSlice method to retrieve
the Slice from.
"""
# check cache
if connstring in MumbleCtlBase.cache:
return MumbleCtlBase.cache[connstring];
# connstring defines whether to connect via ICE or DBus.
# Dbus service names: some.words.divided.by.periods
# ICE specs are WAY more complex, so if DBus doesn't match, use ICE.
rd = re.compile( r'^(\w+\.)*\w+$' );
if rd.match( connstring ):
from MumbleCtlDbus import MumbleCtlDbus
ctl = MumbleCtlDbus( connstring )
else:
from MumbleCtlIce import MumbleCtlIce
ctl = MumbleCtlIce( connstring, slicefile, icesecret )
MumbleCtlBase.cache[connstring] = ctl;
return ctl;
@staticmethod
def clearCache():
MumbleCtlBase.cache = {};
""" This class defines the base interface that the Mumble model expects. """
cache = {}
@staticmethod
def newInstance( connstring, slicefile=None, icesecret=None ):
""" Create a new CTL object for the given connstring.
Optional parameters are the path to the slice file and the
Ice secret necessary to authenticate to Murmur.
The path can be omitted only if using DBus or running Murmur
1.2.3 or later, which exports a getSlice method to retrieve
the Slice from.
"""
# check cache
if connstring in MumbleCtlBase.cache:
return MumbleCtlBase.cache[connstring]
# connstring defines whether to connect via ICE or DBus.
# Dbus service names: some.words.divided.by.periods
# ICE specs are WAY more complex, so if DBus doesn't match, use ICE.
rd = re.compile( r'^(\w+\.)*\w+$' )
if rd.match( connstring ):
from MumbleCtlDbus import MumbleCtlDbus
ctl = MumbleCtlDbus( connstring )
else:
from MumbleCtlIce import MumbleCtlIce
ctl = MumbleCtlIce( connstring, slicefile, icesecret )
MumbleCtlBase.cache[connstring] = ctl
return ctl
@staticmethod
def clearCache():
MumbleCtlBase.cache = {}

623
pyweb/mumble/mmobjects.py

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

1461
pyweb/mumble/models.py
File diff suppressed because it is too large
View File

395
pyweb/mumble/murmurenvutils.py

@ -1,4 +1,5 @@
# -*- coding: utf-8 -*-
# kate: space-indent on; indent-width 4; replace-tabs on;
"""
* Copyright © 2009-2010, Michael "Svedrin" Ziegler <diese-addy@funzt-halt.net>
@ -15,230 +16,230 @@
"""
import os, subprocess, signal
from select import select
from os.path import join, exists
from shutil import copyfile
from select import select
from os.path import join, exists
from shutil import copyfile
from django.conf import settings
from django.conf import settings
from utils import ObjectInfo
from utils import ObjectInfo
def get_available_versions():
""" Return murmur versions installed inside the LAB_DIR. """
dirs = os.listdir( settings.TEST_MURMUR_LAB_DIR );
dirs.sort();
return dirs;
""" Return murmur versions installed inside the LAB_DIR. """
dirs = os.listdir( settings.TEST_MURMUR_LAB_DIR )
dirs.sort()
return dirs
def run_callback( version, callback, *args, **kwargs ):
""" Initialize the database and run murmur, then call the callback.
After the callback has returned, kill murmur.
The callback will be passed the Popen object that wraps murmur,
and any arguments that were passed to run_callback.
If the callback raises an exception, murmur will still be properly
shutdown and the exception will be reraised.
The callback can either return an arbitrary value, or a tuple.
If it returns a tuple, it must be of the form:
( <any> intended_return_value, <bool> call_update_dbase )
That means: If the second value evaluates to True, update_dbase
will be called; the first value will be returned by run_callback.
If the callback returns anything other than a tuple, that value
will be returned directly.
So, If run_callback should return a tuple, you will need to return
the tuple form mentioned above in the callback, and put your tuple
into the first parameter.
"""
murmur_root = join( settings.TEST_MURMUR_LAB_DIR, version );
if not exists( murmur_root ):
raise EnvironmentError( "This version could not be found: '%s' does not exist!" % murmur_root );
init_dbase( version );
process = run_murmur( version );
try:
result = callback( process, *args, **kwargs );
if type(result) == tuple:
if result[1]:
update_dbase( version );
return result[0];
else:
return result;
finally:
kill_murmur( process );
""" Initialize the database and run murmur, then call the callback.
After the callback has returned, kill murmur.
The callback will be passed the Popen object that wraps murmur,
and any arguments that were passed to run_callback.
If the callback raises an exception, murmur will still be properly
shutdown and the exception will be reraised.
The callback can either return an arbitrary value, or a tuple.
If it returns a tuple, it must be of the form:
( <any> intended_return_value, <bool> call_update_dbase )
That means: If the second value evaluates to True, update_dbase
will be called; the first value will be returned by run_callback.
If the callback returns anything other than a tuple, that value
will be returned directly.
So, If run_callback should return a tuple, you will need to return
the tuple form mentioned above in the callback, and put your tuple
into the first parameter.
"""
murmur_root = join( settings.TEST_MURMUR_LAB_DIR, version )
if not exists( murmur_root ):
raise EnvironmentError( "This version could not be found: '%s' does not exist!" % murmur_root )
init_dbase( version )
process = run_murmur( version )
try:
result = callback( process, *args, **kwargs )
if type(result) == tuple:
if result[1]:
update_dbase( version )
return result[0]
else:
return result
finally:
kill_murmur( process )
def init_dbase( version ):
""" Initialize Murmur's database by copying the one from FILES_DIR. """
dbasefile = join( settings.TEST_MURMUR_FILES_DIR, "murmur-%s.db3" % version );
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 );
""" Initialize Murmur's database by copying the one from FILES_DIR. """
dbasefile = join( settings.TEST_MURMUR_FILES_DIR, "murmur-%s.db3" % version )
if not exists( dbasefile ):
raise EnvironmentError( "This version could not be found: '%s' does not exist!" % dbasefile )
murmurfile = join( settings.TEST_MURMUR_LAB_DIR, version, "murmur.sqlite" )
copyfile( dbasefile, murmurfile )
def update_dbase( version ):
""" Copy Murmur's database to FILES_DIR (the inverse of init_dbase). """
murmurfile = join( settings.TEST_MURMUR_LAB_DIR, version, "murmur.sqlite" );
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 );
""" Copy Murmur's database to FILES_DIR (the inverse of init_dbase). """
murmurfile = join( settings.TEST_MURMUR_LAB_DIR, version, "murmur.sqlite" )
if not exists( murmurfile ):
raise EnvironmentError( "Murmur's database could not be found: '%s' does not exist!" % murmurfile )
dbasefile = join( settings.TEST_MURMUR_FILES_DIR, "murmur-%s.db3" % version )
copyfile( murmurfile, dbasefile )
def run_murmur( version ):
""" Run the given Murmur version as a subprocess.
Either returns a Popen object or raises an EnvironmentError.
"""
murmur_root = join( settings.TEST_MURMUR_LAB_DIR, version );
if not exists( murmur_root ):
raise EnvironmentError( "This version could not be found: '%s' does not exist!" % murmur_root );
binary_candidates = ( 'murmur.64', 'murmur.x86', 'murmurd' );
for binname in binary_candidates:
if exists( join( murmur_root, binname ) ):
process = subprocess.Popen(
( join( murmur_root, binname ), '-fg' ),
stdin=None, stdout=subprocess.PIPE, stderr=subprocess.STDOUT,
cwd=murmur_root
);
# Check capabilities by waiting for certain lines to show up.
capa = ObjectInfo( has_dbus=False, has_ice=False, has_instance=False, has_users=False );
def canRead( self, timeout=1 ):
rdy_read, rdy_write, rdy_other = select( [self.stdout], [], [], timeout );
return self.stdout in rdy_read;
setattr(subprocess.Popen, 'canRead', canRead)
while process.canRead(0.5):
line = process.stdout.readline();
#print "read line:", line
if line == 'DBus registration succeeded\n':
capa.has_dbus = True;
elif line == 'MurmurIce: Endpoint "tcp -h 127.0.0.1 -p 6502" running\n':
capa.has_ice = True;
elif line == '1 => Server listening on 0.0.0.0:64738\n':
capa.has_instance = True;
elif "> Authenticated\n" in line:
capa.has_users = True;
process.capabilities = capa;
return process;
raise EnvironmentError( "Murmur binary not found. (Tried %s)" % unicode(binary_candidates) );
""" Run the given Murmur version as a subprocess.
Either returns a Popen object or raises an EnvironmentError.
"""
murmur_root = join( settings.TEST_MURMUR_LAB_DIR, version )
if not exists( murmur_root ):
raise EnvironmentError( "This version could not be found: '%s' does not exist!" % murmur_root )
binary_candidates = ( 'murmur.64', 'murmur.x86', 'murmurd' )
for binname in binary_candidates:
if exists( join( murmur_root, binname ) ):
process = subprocess.Popen(
( join( murmur_root, binname ), '-fg' ),
stdin=None, stdout=subprocess.PIPE, stderr=subprocess.STDOUT,
cwd=murmur_root
)
# Check capabilities by waiting for certain lines to show up.
capa = ObjectInfo( has_dbus=False, has_ice=False, has_instance=False, has_users=False )
def canRead( self, timeout=1 ):
rdy_read, rdy_write, rdy_other = select( [self.stdout], [], [], timeout )
return self.stdout in rdy_read
setattr(subprocess.Popen, 'canRead', canRead)
while process.canRead(0.5):
line = process.stdout.readline()
#print "read line:", line
if line == 'DBus registration succeeded\n':
capa.has_dbus = True
elif line == 'MurmurIce: Endpoint "tcp -h 127.0.0.1 -p 6502" running\n':
capa.has_ice = True
elif line == '1 => Server listening on 0.0.0.0:64738\n':
capa.has_instance = True
elif "> Authenticated\n" in line:
capa.has_users = True
process.capabilities = capa
return process
raise EnvironmentError( "Murmur binary not found. (Tried %s)" % unicode(binary_candidates) )
def wait_for_user( process, timeout=1 ):
""" Wait for a user to connect. This call will consume any output from murmur
until a line indicating a user's attempt to connect has been found.
The timeout parameter specifies how long (in seconds) to wait for input.
It defaults to 1 second. If you set this to 0 it will return at the end
of input (and thereby tell you if a player has already connected). If
you set this to None, the call will block until a player has connected.
Returns True if a user has connected before the timeout has been hit,
False otherwise.
"""
while process.canRead( timeout ):
line = process.stdout.readline();
if "> Authenticated\n" in line:
process.capabilities.has_users = True;
return True;
return False;
""" Wait for a user to connect. This call will consume any output from murmur
until a line indicating a user's attempt to connect has been found.
The timeout parameter specifies how long (in seconds) to wait for input.
It defaults to 1 second. If you set this to 0 it will return at the end
of input (and thereby tell you if a player has already connected). If
you set this to None, the call will block until a player has connected.
Returns True if a user has connected before the timeout has been hit,
False otherwise.
"""
while process.canRead( timeout ):
line = process.stdout.readline()
if "> Authenticated\n" in line:
process.capabilities.has_users = True
return True
return False
def kill_murmur( process ):
""" Send a sigterm to the given process. """
return os.kill( process.pid, signal.SIGTERM );
""" Send a sigterm to the given process. """
return os.kill( process.pid, signal.SIGTERM )
class MumbleCommandWrapper_noargs( object ):
""" Mixin used to run a standard Django command inside MurmurEnvUtils.
To modify a standard Django command for MEU, you will need to create
a new command and derive its Command class from the wrapper, and the
Command class of the original command:
from django.core.management.commands.shell import Command as ShellCommand
from mumble.murmurenvutils import MumbleCommandWrapper
class Command( MumbleCommandWrapper, ShellCommand ):
pass
That will run the original command, after the user has had the chance to
select the version of Murmur to run.
"""
def _choose_version( self ):
print "Choose version:";
vv = get_available_versions();
for idx in range(len(vv)):
print " #%d %s" % ( idx, vv[idx] );
chosen = int( raw_input("#> ") );
return vv[chosen];
def handle_noargs( self, **options ):
self.origOpts = options;
run_callback( self._choose_version(), self.runOrig );
def runOrig( self, proc ):
super( MumbleCommandWrapper_noargs, self ).handle_noargs( **self.origOpts );
""" Mixin used to run a standard Django command inside MurmurEnvUtils.
To modify a standard Django command for MEU, you will need to create
a new command and derive its Command class from the wrapper, and the
Command class of the original command:
from django.core.management.commands.shell import Command as ShellCommand
from mumble.murmurenvutils import MumbleCommandWrapper
class Command( MumbleCommandWrapper, ShellCommand ):
pass
That will run the original command, after the user has had the chance to
select the version of Murmur to run.
"""
def _choose_version( self ):
print "Choose version:"
vv = get_available_versions()
for idx in range(len(vv)):
print " #%d %s" % ( idx, vv[idx] )
chosen = int( raw_input("#> ") )
return vv[chosen]
def handle_noargs( self, **options ):
self.origOpts = options
run_callback( self._choose_version(), self.runOrig )
def runOrig( self, proc ):
super( MumbleCommandWrapper_noargs, self ).handle_noargs( **self.origOpts )
class MumbleCommandWrapper( object ):
""" Mixin used to run a standard Django command inside MurmurEnvUtils.
To modify a standard Django command for MEU, you will need to create
a new command and derive its Command class from the wrapper, and the
Command class of the original command:
from django.core.management.commands.shell import Command as ShellCommand
from mumble.murmurenvutils import MumbleCommandWrapper
class Command( MumbleCommandWrapper, ShellCommand ):
pass
That will run the original command, after the user has had the chance to
select the version of Murmur to run.
"""
def _choose_version( self ):
print "Choose version:";
vv = get_available_versions();
for idx in range(len(vv)):
print " #%d %s" % ( idx, vv[idx] );
chosen = int( raw_input("#> ") );
return vv[chosen];
def handle( self, *args, **options ):
self.origArgs = args;
self.origOpts = options;
run_callback( self._choose_version(), self.runOrig );
def runOrig( self, proc ):
super( MumbleCommandWrapper, self ).handle( *self.origArgs, **self.origOpts );
""" Mixin used to run a standard Django command inside MurmurEnvUtils.
To modify a standard Django command for MEU, you will need to create
a new command and derive its Command class from the wrapper, and the
Command class of the original command:
from django.core.management.commands.shell import Command as ShellCommand
from mumble.murmurenvutils import MumbleCommandWrapper
class Command( MumbleCommandWrapper, ShellCommand ):
pass
That will run the original command, after the user has had the chance to
select the version of Murmur to run.
"""
def _choose_version( self ):
print "Choose version:"
vv = get_available_versions()
for idx in range(len(vv)):
print " #%d %s" % ( idx, vv[idx] )
chosen = int( raw_input("#> ") )
return vv[chosen]
def handle( self, *args, **options ):
self.origArgs = args
self.origOpts = options
run_callback( self._choose_version(), self.runOrig )
def runOrig( self, proc ):
super( MumbleCommandWrapper, self ).handle( *self.origArgs, **self.origOpts )

41
pyweb/mumble/templatetags/mumble_extras.py

@ -1,4 +1,5 @@
# -*- coding: utf-8 -*-
# kate: space-indent on; indent-width 4; replace-tabs on;
"""
* Copyright © 2009-2010, Michael "Svedrin" Ziegler <diese-addy@funzt-halt.net>
@ -19,44 +20,44 @@ from django.template.loader import render_to_string
from django.conf import settings
register = template.Library();
register = template.Library()
@register.filter
def trunc( string, maxlen = 50 ):
""" converts "a very very extaordinary long text" to "a very very extra... """
if len(string) < maxlen:
return string;
return string[:(maxlen - 3)] + "";
""" converts "a very very extaordinary long text" to "a very very extra... """
if len(string) < maxlen:
return string
return string[:(maxlen - 3)] + ""
@register.filter
def chanview( obj, user = None ):
""" renders an mmChannel / mmPlayer object with the correct template """
if obj.is_server:
return render_to_string( 'mumble/server.html', { 'Server': obj, 'MumbleAccount': user, 'MEDIA_URL': settings.MEDIA_URL } );
elif obj.is_channel:
return render_to_string( 'mumble/channel.html', { 'Channel': obj, 'MumbleAccount': user, 'MEDIA_URL': settings.MEDIA_URL } );
elif obj.is_player:
return render_to_string( 'mumble/player.html', { 'Player': obj, 'MumbleAccount': user, 'MEDIA_URL': settings.MEDIA_URL } );
""" renders an mmChannel / mmPlayer object with the correct template """
if obj.is_server:
return render_to_string( 'mumble/server.html', { 'Server': obj, 'MumbleAccount': user, 'MEDIA_URL': settings.MEDIA_URL } )
elif obj.is_channel:
return render_to_string( 'mumble/channel.html', { 'Channel': obj, 'MumbleAccount': user, 'MEDIA_URL': settings.MEDIA_URL } )
elif obj.is_player:
return render_to_string( 'mumble/player.html', { 'Player': obj, 'MumbleAccount': user, 'MEDIA_URL': settings.MEDIA_URL } )
@register.filter
def chanurl( obj, user ):
""" create a connection URL and takes the user's login into account """
return obj.getURL( user );
""" create a connection URL and takes the user's login into account """
return obj.getURL( user )
@register.filter
def mmversion_lt( obj, version ):
""" return True if the given Server's version is less than the given version. """
return tuple(obj.version[:3]) < tuple([int(v) for v in version.split('.')])
""" return True if the given Server's version is less than the given version. """
return tuple(obj.version[:3]) < tuple([int(v) for v in version.split('.')])
@register.filter
def mmversion_eq( obj, version ):
""" return True if the given Server's version equals the given version. """
return tuple(obj.version[:3]) == tuple([int(v) for v in version.split('.')])
""" return True if the given Server's version equals the given version. """
return tuple(obj.version[:3]) == tuple([int(v) for v in version.split('.')])
@register.filter
def mmversion_gt( obj, version ):
""" return True if the given Server's version is greater than the given version. """
return tuple(obj.version[:3]) > tuple([int(v) for v in version.split('.')])
""" return True if the given Server's version is greater than the given version. """
return tuple(obj.version[:3]) > tuple([int(v) for v in version.split('.')])

149
pyweb/mumble/testrunner.py

@ -1,4 +1,5 @@
# -*- coding: utf-8 -*-
# kate: space-indent on; indent-width 4; replace-tabs on;
"""
* Copyright © 2009-2010, Michael "Svedrin" Ziegler <diese-addy@funzt-halt.net>
@ -16,84 +17,84 @@
import os
from django.test.simple import run_tests as django_run_tests
from django.conf import settings
from django.test.simple import run_tests as django_run_tests
from django.conf import settings
from murmurenvutils import get_available_versions, run_callback, wait_for_user
from murmurenvutils import get_available_versions, run_callback, wait_for_user
def run_tests( test_labels, verbosity=1, interactive=True, extra_tests=[] ):
""" Run the Django built in testing framework, but before testing the mumble
app, allow Murmur to be set up correctly.
"""
if not test_labels:
test_labels = [ appname.split('.')[-1] for appname in settings.INSTALLED_APPS ];
# No need to sync any murmur servers for the other apps
os.environ['MURMUR_CONNSTR'] = '';
# The easy way: mumble is not being tested.
if "mumble" not in test_labels:
return django_run_tests( test_labels, verbosity, interactive, extra_tests );
# First run everything apart from mumble. mumble will be tested separately, so Murmur
# can be set up properly first.
failed_tests = 0;
if len(test_labels) > 1:
# only run others if mumble is not the only app to be tested
test_labels = list(test_labels);
test_labels.remove( "mumble" );
failed_tests += django_run_tests( test_labels, verbosity, interactive, extra_tests );
failed_tests += run_mumble_tests( verbosity, interactive );
return failed_tests;
""" Run the Django built in testing framework, but before testing the mumble
app, allow Murmur to be set up correctly.
"""
if not test_labels:
test_labels = [ appname.split('.')[-1] for appname in settings.INSTALLED_APPS ]
# No need to sync any murmur servers for the other apps
os.environ['MURMUR_CONNSTR'] = ''
# The easy way: mumble is not being tested.
if "mumble" not in test_labels:
return django_run_tests( test_labels, verbosity, interactive, extra_tests )
# First run everything apart from mumble. mumble will be tested separately, so Murmur
# can be set up properly first.
failed_tests = 0
if len(test_labels) > 1:
# only run others if mumble is not the only app to be tested
test_labels = list(test_labels)
test_labels.remove( "mumble" )
failed_tests += django_run_tests( test_labels, verbosity, interactive, extra_tests )
failed_tests += run_mumble_tests( verbosity, interactive )
return failed_tests
def run_mumble_tests( verbosity=1, interactive=True ):
connstrings = {
'DBus': 'net.sourceforge.mumble.murmur',
'Ice': 'Meta:tcp -h 127.0.0.1 -p 6502',
};
def django_run_tests_wrapper( process, version ):
wr_failed_tests = 0;
for method in connstrings:
# Check if this server is ready to be used with the current method
if getattr( process.capabilities, ("has_%s" % method.lower()), False ):
print "Testing mumble %s via %s" % ( version, method );
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;
if not process.capabilities.has_users:
print "Waiting for user to connect (60 seconds)."
wait_for_user( process, timeout=60 );
wr_failed_tests += django_run_tests( ('mumble',), verbosity, interactive, [] );
else:
print "Mumble %s does not support Method %s" % ( version, method );
return wr_failed_tests;
failed_tests = 0;
from mctl import MumbleCtlBase
for version in get_available_versions():
MumbleCtlBase.clearCache();
run = raw_input( "Run tests for %s? [Y/n] " % version );
if run in ('Y', 'y', ''):
failed_tests += run_callback( version, django_run_tests_wrapper, version );
return failed_tests;
connstrings = {
'DBus': 'net.sourceforge.mumble.murmur',
'Ice': 'Meta:tcp -h 127.0.0.1 -p 6502',
}
def django_run_tests_wrapper( process, version ):
wr_failed_tests = 0
for method in connstrings:
# Check if this server is ready to be used with the current method
if getattr( process.capabilities, ("has_%s" % method.lower()), False ):
print "Testing mumble %s via %s" % ( version, method )
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
if not process.capabilities.has_users:
print "Waiting for user to connect (60 seconds)."
wait_for_user( process, timeout=60 )
wr_failed_tests += django_run_tests( ('mumble',), verbosity, interactive, [] )
else:
print "Mumble %s does not support Method %s" % ( version, method )
return wr_failed_tests
failed_tests = 0
from mctl import MumbleCtlBase
for version in get_available_versions():
MumbleCtlBase.clearCache()
run = raw_input( "Run tests for %s? [Y/n] " % version )
if run in ('Y', 'y', ''):
failed_tests += run_callback( version, django_run_tests_wrapper, version )
return failed_tests

365
pyweb/mumble/tests.py

@ -1,4 +1,5 @@
# -*- coding: utf-8 -*-
# kate: space-indent on; indent-width 4; replace-tabs on;
"""
* Copyright © 2009-2010, Michael "Svedrin" Ziegler <diese-addy@funzt-halt.net>
@ -14,195 +15,195 @@
* GNU General Public License for more details.
"""
from django.conf import settings
from django.test import TestCase
from django.conf import settings
from django.test import TestCase
from models import Mumble
from utils import ObjectInfo
from models import Mumble
from utils import ObjectInfo
class InstancesHandling( TestCase ):
""" Tests creation, editing and removing of vserver instances. """
def setUp( self ):
# Make sure we always start with a FRESH murmur instance, checking for left-over instances
# and deleting them before creating ours.
try:
self.murmur = Mumble.objects.get( addr="0.0.0.0", port=31337 );
except Mumble.DoesNotExist:
pass
else:
self.murmur.delete();
finally:
self.murmur = Mumble( name="#unit testing instance#", addr="0.0.0.0", port=31337 );
self.murmur.save();
def testDefaultConf( self ):
conf = self.murmur.ctl.getAllConf( self.murmur.srvid );
self.assert_( type(conf) == dict );
self.assert_( "host" in conf );
self.assert_( "port" in conf );
self.assert_( "certificate" in conf );
self.assert_( "key" in conf );
self.assert_( "registerhostname" in conf );
self.assert_( "registername" in conf );
self.assert_( "channelname" in conf );
self.assert_( "username" in conf );
self.assert_( "obfuscate" in conf );
self.assert_( "defaultchannel" in conf );
def testAddrPortUnique( self ):
try:
duplicate = Mumble(
name="#another unit testing instance#",
addr=self.murmur.addr, port=self.murmur.port,
dbus=settings.DEFAULT_CONN
);
if duplicate.ctl.method == "ICE":
import Murmur
self.assertRaises( Murmur.ServerFailureException, duplicate.save );
elif self.murmur.version[:2] == [ 1, 2 ]:
from dbus import DBusException
self.assertRaises( DBusException, duplicate.save );
else:
from sqlite3 import IntegrityError
self.assertRaises( IntegrityError, duplicate.save );
finally:
# make sure the duplicate is removed
duplicate.ctl.deleteServer( duplicate.srvid );
def tearDown( self ):
self.murmur.delete();
""" Tests creation, editing and removing of vserver instances. """
def setUp( self ):
# Make sure we always start with a FRESH murmur instance, checking for left-over instances
# and deleting them before creating ours.
try:
self.murmur = Mumble.objects.get( addr="0.0.0.0", port=31337 )
except Mumble.DoesNotExist:
pass
else:
self.murmur.delete()
finally:
self.murmur = Mumble( name="#unit testing instance#", addr="0.0.0.0", port=31337 )
self.murmur.save()
def testDefaultConf( self ):
conf = self.murmur.ctl.getAllConf( self.murmur.srvid )
self.assert_( type(conf) == dict )
self.assert_( "host" in conf )
self.assert_( "port" in conf )
self.assert_( "certificate" in conf )
self.assert_( "key" in conf )
self.assert_( "registerhostname" in conf )
self.assert_( "registername" in conf )
self.assert_( "channelname" in conf )
self.assert_( "username" in conf )
self.assert_( "obfuscate" in conf )
self.assert_( "defaultchannel" in conf )
def testAddrPortUnique( self ):
try:
duplicate = Mumble(
name="#another unit testing instance#",
addr=self.murmur.addr, port=self.murmur.port,
dbus=settings.DEFAULT_CONN
)
if duplicate.ctl.method == "ICE":
import Murmur
self.assertRaises( Murmur.ServerFailureException, duplicate.save )
elif self.murmur.version[:2] == [ 1, 2 ]:
from dbus import DBusException
self.assertRaises( DBusException, duplicate.save )
else:
from sqlite3 import IntegrityError
self.assertRaises( IntegrityError, duplicate.save )
finally:
# make sure the duplicate is removed
duplicate.ctl.deleteServer( duplicate.srvid )
def tearDown( self ):
self.murmur.delete()
class DataReading( TestCase ):
""" Tests reading data from murmur using the low-level CTL methods. """
def setUp( self ):
# BIG FAT WARNING: This sucks ass, because it assumes the tester has a
# Murmur database like the one I have.
# I definitely need to prepare Murmur somehow before running these tests.
# Just don't yet know how.
self.murmur = Mumble.objects.get(id=1);
def testCtlGetChannels( self ):
""" Test getChannels() """
channels = self.murmur.ctl.getChannels( self.murmur.srvid );
if self.murmur.ctl.method == "ICE":
import Murmur
self.assertEquals( type( channels[0] ), Murmur.Channel );
else:
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" ) );
def testCtlGetPlayers( self ):
""" Test getPlayers() """
players = self.murmur.ctl.getPlayers( self.murmur.srvid );
self.assert_( len(players) > 0 );
self.assertEquals( type(players), dict );
for plidx in players:
player = players[plidx];
if self.murmur.ctl.method == "ICE" and self.murmur.version[:2] == ( 1, 2 ):
import Murmur
self.assertEquals( type( player ), Murmur.User );
else:
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" ) );
def testCtlGetRegisteredPlayers( self ):
""" Test getRegistredPlayers() and getRegistration() """
players = self.murmur.ctl.getRegisteredPlayers( self.murmur.srvid );
self.assert_( len(players) > 0 );
self.assertEquals( type(players), dict );
for plidx in players:
player = players[plidx];
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" ) );
# compare with getRegistration result
reg = self.murmur.ctl.getRegistration( self.murmur.srvid, player.userid );
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.assertEquals( player.userid, reg.userid );
self.assertEquals( player.name, reg.name );
self.assertEquals( player.email, reg.email );
self.assertEquals( player.pw, reg.pw );
def testCtlGetAcl( self ):
""" Test getACL() for the root channel """
acls, groups, inherit = self.murmur.ctl.getACL( self.murmur.srvid, 0 );
for rule in acls:
if self.murmur.ctl.method == "ICE" and self.murmur.version[:2] == ( 1, 2 ):
import Murmur
self.assertEquals( type( rule ), Murmur.ACL );
else:
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" ) );
for grp in groups:
if self.murmur.ctl.method == "ICE":
import Murmur
self.assertEquals( type( grp ), Murmur.Group );
else:
self.assertEquals( type( grp ), ObjectInfo );
self.assert_( hasattr( grp, "name" ) );
self.assert_( hasattr( grp, "inherited" ) );
self.assert_( hasattr( grp, "inherit" ) );
self.assert_( hasattr( grp, "inheritable" ) );
self.assert_( hasattr( grp, "add" ) );
self.assert_( hasattr( grp, "remove" ) );
self.assert_( hasattr( grp, "members" ) );
""" Tests reading data from murmur using the low-level CTL methods. """
def setUp( self ):
# BIG FAT WARNING: This sucks ass, because it assumes the tester has a
# Murmur database like the one I have.
# I definitely need to prepare Murmur somehow before running these tests.
# Just don't yet know how.
self.murmur = Mumble.objects.get(id=1)
def testCtlGetChannels( self ):
""" Test getChannels() """
channels = self.murmur.ctl.getChannels( self.murmur.srvid )
if self.murmur.ctl.method == "ICE":
import Murmur
self.assertEquals( type( channels[0] ), Murmur.Channel )
else:
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" ) )
def testCtlGetPlayers( self ):
""" Test getPlayers() """
players = self.murmur.ctl.getPlayers( self.murmur.srvid )
self.assert_( len(players) > 0 )
self.assertEquals( type(players), dict )
for plidx in players:
player = players[plidx]
if self.murmur.ctl.method == "ICE" and self.murmur.version[:2] == ( 1, 2 ):
import Murmur
self.assertEquals( type( player ), Murmur.User )
else:
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" ) )
def testCtlGetRegisteredPlayers( self ):
""" Test getRegistredPlayers() and getRegistration() """
players = self.murmur.ctl.getRegisteredPlayers( self.murmur.srvid )
self.assert_( len(players) > 0 )
self.assertEquals( type(players), dict )
for plidx in players:
player = players[plidx]
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" ) )
# compare with getRegistration result
reg = self.murmur.ctl.getRegistration( self.murmur.srvid, player.userid )
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.assertEquals( player.userid, reg.userid )
self.assertEquals( player.name, reg.name )
self.assertEquals( player.email, reg.email )
self.assertEquals( player.pw, reg.pw )
def testCtlGetAcl( self ):
""" Test getACL() for the root channel """
acls, groups, inherit = self.murmur.ctl.getACL( self.murmur.srvid, 0 )
for rule in acls:
if self.murmur.ctl.method == "ICE" and self.murmur.version[:2] == ( 1, 2 ):
import Murmur
self.assertEquals( type( rule ), Murmur.ACL )
else:
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" ) )
for grp in groups:
if self.murmur.ctl.method == "ICE":
import Murmur
self.assertEquals( type( grp ), Murmur.Group )
else:
self.assertEquals( type( grp ), ObjectInfo )
self.assert_( hasattr( grp, "name" ) )
self.assert_( hasattr( grp, "inherited" ) )
self.assert_( hasattr( grp, "inherit" ) )
self.assert_( hasattr( grp, "inheritable" ) )
self.assert_( hasattr( grp, "add" ) )
self.assert_( hasattr( grp, "remove" ) )
self.assert_( hasattr( grp, "members" ) )

31
pyweb/mumble/urls.py

@ -1,4 +1,5 @@
# -*- coding: utf-8 -*-
# kate: space-indent on; indent-width 4; replace-tabs on;
"""
* Copyright © 2009-2010, Michael "Svedrin" Ziegler <diese-addy@funzt-halt.net>
@ -17,19 +18,19 @@
from django.conf.urls.defaults import patterns
urlpatterns = patterns(
'mumble.views',
( r'djangousers', 'djangousers' ),
( r'(?P<server>\d+)/users', 'users' ),
( r'(?P<server>\d+)/(?P<userid>\d+)/texture.png', 'showTexture' ),
( r'murmur/tree/(?P<server>\d+)', 'mmng_tree' ),
( r'mumbleviewer/(?P<server>\d+).xml', 'mumbleviewer_tree_xml' ),
( r'mumbleviewer/(?P<server>\d+).json', 'mumbleviewer_tree_json'),
( r'mobile/(?P<server>\d+)', 'mobile_show' ),
( r'mobile/?$', 'mobile_mumbles' ),
( r'(?P<server>\d+)', 'show' ),
( r'$', 'mumbles' ),
'mumble.views',
( r'djangousers', 'djangousers' ),
( r'(?P<server>\d+)/users', 'users' ),
( r'(?P<server>\d+)/(?P<userid>\d+)/texture.png', 'showTexture' ),
( r'murmur/tree/(?P<server>\d+)', 'mmng_tree' ),
( r'mumbleviewer/(?P<server>\d+).xml', 'mumbleviewer_tree_xml' ),
( r'mumbleviewer/(?P<server>\d+).json', 'mumbleviewer_tree_json'),
( r'mobile/(?P<server>\d+)', 'mobile_show' ),
( r'mobile/?$', 'mobile_mumbles' ),
( r'(?P<server>\d+)', 'show' ),
( r'$', 'mumbles' ),
)

39
pyweb/mumble/utils.py

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

708
pyweb/mumble/views.py

@ -1,4 +1,5 @@
# -*- coding: utf-8 -*-
# kate: space-indent on; indent-width 4; replace-tabs on;
"""
* Copyright © 2009-2010, Michael "Svedrin" Ziegler <diese-addy@funzt-halt.net>
@ -15,398 +16,387 @@
"""
import simplejson
from StringIO import StringIO
from PIL import Image
from StringIO import StringIO
from PIL import Image
from django.shortcuts import render_to_response, get_object_or_404, get_list_or_404
from django.template import RequestContext
from django.http import Http404, HttpResponse, HttpResponseRedirect
from django.contrib.auth.decorators import login_required
from django.contrib.auth.models import User
from django.conf import settings
from django.core.urlresolvers import reverse
from django.shortcuts import render_to_response, get_object_or_404, get_list_or_404
from django.template import RequestContext
from django.http import Http404, HttpResponse, HttpResponseRedirect
from django.conf import settings
from django.contrib.auth.decorators import login_required
from django.contrib.auth.models import User
from django.contrib.auth import views as auth_views
from django.core.urlresolvers import reverse
from django.contrib.auth import views as auth_views
from models import Mumble, MumbleUser
from forms import MumbleForm, MumbleUserForm, MumbleUserPasswordForm
from forms import MumbleUserLinkForm, MumbleTextureForm, MumbleKickForm
from models import Mumble, MumbleUser
from forms import MumbleForm, MumbleUserForm, MumbleUserPasswordForm
from forms import MumbleUserLinkForm, MumbleTextureForm, MumbleKickForm
def redir( request ):
""" Redirect to the servers list. """
if request.META['HTTP_USER_AGENT'].startswith( 'BlackBerry' ) or \
"Opera Mobi" in request.META['HTTP_USER_AGENT'] or \
"Opera Mini" in request.META['HTTP_USER_AGENT'] or \
"Windows CE" in request.META['HTTP_USER_AGENT'] or \
"MIDP" in request.META['HTTP_USER_AGENT'] or \
"Palm" in request.META['HTTP_USER_AGENT'] or \
"NetFront" in request.META['HTTP_USER_AGENT'] or \
"Nokia" in request.META['HTTP_USER_AGENT'] or \
"Symbian" in request.META['HTTP_USER_AGENT'] or \
"UP.Browser" in request.META['HTTP_USER_AGENT'] or \
"UP.Link" in request.META['HTTP_USER_AGENT'] or \
"WinWAP" in request.META['HTTP_USER_AGENT'] or \
"Android" in request.META['HTTP_USER_AGENT'] or \
"DoCoMo" in request.META['HTTP_USER_AGENT'] or \
"KDDI-" in request.META['HTTP_USER_AGENT'] or \
"Softbank" in request.META['HTTP_USER_AGENT'] or \
"J-Phone" in request.META['HTTP_USER_AGENT'] or \
"IEMobile" in request.META['HTTP_USER_AGENT'] or \
"iPod" in request.META['HTTP_USER_AGENT'] or \
"iPhone" in request.META['HTTP_USER_AGENT']:
return HttpResponseRedirect( reverse( mobile_mumbles ) );
else:
return HttpResponseRedirect( reverse( mumbles ) );
""" Redirect to the servers list. """
if request.META['HTTP_USER_AGENT'].startswith( 'BlackBerry' ) or \
"Opera Mobi" in request.META['HTTP_USER_AGENT'] or \
"Opera Mini" in request.META['HTTP_USER_AGENT'] or \
"Windows CE" in request.META['HTTP_USER_AGENT'] or \
"MIDP" in request.META['HTTP_USER_AGENT'] or \
"Palm" in request.META['HTTP_USER_AGENT'] or \
"NetFront" in request.META['HTTP_USER_AGENT'] or \
"Nokia" in request.META['HTTP_USER_AGENT'] or \
"Symbian" in request.META['HTTP_USER_AGENT'] or \
"UP.Browser" in request.META['HTTP_USER_AGENT'] or \
"UP.Link" in request.META['HTTP_USER_AGENT'] or \
"WinWAP" in request.META['HTTP_USER_AGENT'] or \
"Android" in request.META['HTTP_USER_AGENT'] or \
"DoCoMo" in request.META['HTTP_USER_AGENT'] or \
"KDDI-" in request.META['HTTP_USER_AGENT'] or \
"Softbank" in request.META['HTTP_USER_AGENT'] or \
"J-Phone" in request.META['HTTP_USER_AGENT'] or \
"IEMobile" in request.META['HTTP_USER_AGENT'] or \
"iPod" in request.META['HTTP_USER_AGENT'] or \
"iPhone" in request.META['HTTP_USER_AGENT']:
return HttpResponseRedirect( reverse( mobile_mumbles ) )
else:
return HttpResponseRedirect( reverse( mumbles ) )
def mobile_mumbles( request ):
return mumbles( request, mobile=True );
return mumbles( request, mobile=True )
def mumbles( request, mobile=False ):
""" Display a list of all configured Mumble servers, or redirect if only one configured. """
mms = Mumble.objects.all().order_by( "name" );
if len(mms) == 1:
return HttpResponseRedirect( reverse(
{ False: show, True: mobile_show }[mobile],
kwargs={ 'server': mms[0].id, }
) );
return render_to_response(
'mumble/%s.html' % { False: 'list', True: 'mobile_list' }[mobile],
{ 'MumbleObjects': mms,
'MumbleActive': True,
},
context_instance = RequestContext(request)
);
""" Display a list of all configured Mumble servers, or redirect if only one configured. """
mms = Mumble.objects.all().order_by( "name" )
if len(mms) == 1:
return HttpResponseRedirect( reverse(
{ False: show, True: mobile_show }[mobile],
kwargs={ 'server': mms[0].id, }
) )
return render_to_response(
'mumble/%s.html' % { False: 'list', True: 'mobile_list' }[mobile],
{ 'MumbleObjects': mms,
'MumbleActive': True,
},
context_instance = RequestContext(request)
)
def show( request, server ):
""" Display the channel list for the given Server ID.
This includes not only the channel list itself, but indeed the user registration,
server admin and user texture form as well. The template then uses JavaScript
to display these forms integrated into the Channel viewer.
"""
srv = get_object_or_404( Mumble, id=server );
if not srv.booted:
return render_to_response(
'mumble/offline.html',
{ 'DBaseObject': srv,
'MumbleActive': True,
}, context_instance = RequestContext(request) );
isAdmin = srv.isUserAdmin( request.user );
# The tab to start on.
displayTab = 0;
if isAdmin:
if request.method == 'POST' and "mode" in request.POST and request.POST['mode'] == 'admin':
adminform = MumbleForm( request.POST, instance=srv );
if adminform.is_valid():
adminform.save();
return HttpResponseRedirect( reverse( show, kwargs={ 'server': int(server), } ) );
else:
displayTab = 2;
else:
adminform = MumbleForm( instance=srv );
else:
adminform = None;
registered = False;
user = None;
if request.user.is_authenticated():
# Unregistered users may or may not need a password to register.
if settings.PROTECTED_MODE and srv.passwd:
unregged_user_form = MumbleUserPasswordForm;
# Unregistered users may or may not want to link an existing account
elif settings.ALLOW_ACCOUNT_LINKING:
unregged_user_form = MumbleUserLinkForm;
else:
unregged_user_form = MumbleUserForm;
if request.method == 'POST' and 'mode' in request.POST and request.POST['mode'] == 'reg':
try:
user = MumbleUser.objects.get( server=srv, owner=request.user );
except MumbleUser.DoesNotExist:
regform = unregged_user_form( request.POST );
regform.server = srv;
if regform.is_valid():
model = regform.save( commit=False );
model.owner = request.user;
model.server = srv;
# 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), } ) );
else:
displayTab = 1;
else:
regform = MumbleUserForm( request.POST, instance=user );
regform.server = srv;
if regform.is_valid():
regform.save();
return HttpResponseRedirect( reverse( show, kwargs={ 'server': int(server), } ) );
else:
displayTab = 1;
else:
try:
user = MumbleUser.objects.get( server=srv, owner=request.user );
except MumbleUser.DoesNotExist:
regform = unregged_user_form();
else:
regform = MumbleUserForm( instance=user );
registered = True;
if request.method == 'POST' and 'mode' in request.POST and request.POST['mode'] == 'texture' and registered:
textureform = MumbleTextureForm( request.POST, request.FILES );
if textureform.is_valid():
if 'usegravatar' in textureform.cleaned_data and textureform.cleaned_data['usegravatar'] and user.gravatar:
user.setTextureFromUrl( user.gravatar );
elif 'texturefile' in request.FILES:
user.setTexture( Image.open( request.FILES['texturefile'] ) );
return HttpResponseRedirect( reverse( show, kwargs={ 'server': int(server), } ) );
else:
textureform = MumbleTextureForm();
else:
regform = None;
textureform = None;
if isAdmin:
if request.method == 'POST' and 'mode' in request.POST:
if request.POST['mode'] == 'kick':
kickform = MumbleKickForm( request.POST );
if kickform.is_valid():
if kickform.cleaned_data["ban"]:
srv.banUser( kickform.cleaned_data['session'], kickform.cleaned_data['reason'] );
srv.kickUser( kickform.cleaned_data['session'], kickform.cleaned_data['reason'] );
# ChannelTable is a somewhat misleading name, as it actually contains channels and players.
channelTable = [];
for cid in srv.channels:
if cid != 0 and srv.channels[cid].show:
channelTable.append( srv.channels[cid] );
for pid in srv.players:
channelTable.append( srv.players[pid] );
show_url = reverse( show, kwargs={ 'server': srv.id } );
login_url = reverse( auth_views.login );
return render_to_response(
'mumble/mumble.html',
{
'login_url': "%s?next=%s" % ( login_url, show_url ),
'DBaseObject': srv,
'ChannelTable': channelTable,
'CurrentUserIsAdmin': isAdmin,
'AdminForm': adminform,
'RegForm': regform,
'TextureForm': textureform,
'Registered': registered,
'DisplayTab': displayTab,
'MumbleActive': True,
'MumbleAccount':user,
},
context_instance = RequestContext(request)
);
""" Display the channel list for the given Server ID.
This includes not only the channel list itself, but indeed the user registration,
server admin and user texture form as well. The template then uses JavaScript
to display these forms integrated into the Channel viewer.
"""
srv = get_object_or_404( Mumble, id=server )
if not srv.booted:
return render_to_response(
'mumble/offline.html',
{ 'DBaseObject': srv,
'MumbleActive': True,
}, context_instance = RequestContext(request) )
isAdmin = srv.isUserAdmin( request.user )
# The tab to start on.
displayTab = 0
if isAdmin:
if request.method == 'POST' and "mode" in request.POST and request.POST['mode'] == 'admin':
adminform = MumbleForm( request.POST, instance=srv )
if adminform.is_valid():
adminform.save()
return HttpResponseRedirect( reverse( show, kwargs={ 'server': int(server), } ) )
else:
displayTab = 2
else:
adminform = MumbleForm( instance=srv )
else:
adminform = None
registered = False
user = None
if request.user.is_authenticated():
# Unregistered users may or may not need a password to register.
if settings.PROTECTED_MODE and srv.passwd:
unregged_user_form = MumbleUserPasswordForm
# Unregistered users may or may not want to link an existing account
elif settings.ALLOW_ACCOUNT_LINKING:
unregged_user_form = MumbleUserLinkForm
else:
unregged_user_form = MumbleUserForm
if request.method == 'POST' and 'mode' in request.POST and request.POST['mode'] == 'reg':
try:
user = MumbleUser.objects.get( server=srv, owner=request.user )
except MumbleUser.DoesNotExist:
regform = unregged_user_form( request.POST )
regform.server = srv
if regform.is_valid():
model = regform.save( commit=False )
model.owner = request.user
model.server = srv
# 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), } ) )
else:
displayTab = 1
else:
regform = MumbleUserForm( request.POST, instance=user )
regform.server = srv
if regform.is_valid():
regform.save()
return HttpResponseRedirect( reverse( show, kwargs={ 'server': int(server), } ) )
else:
displayTab = 1
else:
try:
user = MumbleUser.objects.get( server=srv, owner=request.user )
except MumbleUser.DoesNotExist:
regform = unregged_user_form()
else:
regform = MumbleUserForm( instance=user )
registered = True
if request.method == 'POST' and 'mode' in request.POST and request.POST['mode'] == 'texture' and registered:
textureform = MumbleTextureForm( request.POST, request.FILES )
if textureform.is_valid():
if 'usegravatar' in textureform.cleaned_data and textureform.cleaned_data['usegravatar'] and user.gravatar:
user.setTextureFromUrl( user.gravatar )
elif 'texturefile' in request.FILES:
user.setTexture( Image.open( request.FILES['texturefile'] ) )
return HttpResponseRedirect( reverse( show, kwargs={ 'server': int(server), } ) )
else:
textureform = MumbleTextureForm()
else:
regform = None
textureform = None
if isAdmin:
if request.method == 'POST' and 'mode' in request.POST:
if request.POST['mode'] == 'kick':
kickform = MumbleKickForm( request.POST )
if kickform.is_valid():
if kickform.cleaned_data["ban"]:
srv.banUser( kickform.cleaned_data['session'], kickform.cleaned_data['reason'] )
srv.kickUser( kickform.cleaned_data['session'], kickform.cleaned_data['reason'] )
# ChannelTable is a somewhat misleading name, as it actually contains channels and players.
channelTable = []
for cid in srv.channels:
if cid != 0 and srv.channels[cid].show:
channelTable.append( srv.channels[cid] )
for pid in srv.players:
channelTable.append( srv.players[pid] )
show_url = reverse( show, kwargs={ 'server': srv.id } )
login_url = reverse( auth_views.login )
return render_to_response( 'mumble/mumble.html', {
'login_url': "%s?next=%s" % ( login_url, show_url ),
'DBaseObject': srv,
'ChannelTable': channelTable,
'CurrentUserIsAdmin': isAdmin,
'AdminForm': adminform,
'RegForm': regform,
'TextureForm': textureform,
'Registered': registered,
'DisplayTab': displayTab,
'MumbleActive': True,
'MumbleAccount':user,
}, context_instance = RequestContext(request) )
def mobile_show( request, server ):
""" Display the channel list for the given Server ID. """
srv = get_object_or_404( Mumble, id=server );
user = None;
if request.user.is_authenticated():
try:
user = MumbleUser.objects.get( server=srv, owner=request.user );
except MumbleUser.DoesNotExist:
pass;
return render_to_response(
'mumble/mobile_mumble.html',
{
'DBaseObject': srv,
'MumbleActive': True,
'MumbleAccount':user,
},
context_instance = RequestContext(request)
);
""" Display the channel list for the given Server ID. """
srv = get_object_or_404( Mumble, id=server )
user = None
if request.user.is_authenticated():
try:
user = MumbleUser.objects.get( server=srv, owner=request.user )
except MumbleUser.DoesNotExist:
pass
return render_to_response( 'mumble/mobile_mumble.html', {
'DBaseObject': srv,
'MumbleActive': True,
'MumbleAccount':user,
}, context_instance = RequestContext(request) )
def showTexture( request, server, userid ):
""" Pack the given user's texture into an HttpResponse.
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) );
try:
img = user.getTexture();
except ValueError:
raise Http404();
else:
buf = StringIO();
img.save( buf, "PNG" );
return HttpResponse( buf.getvalue(), "image/png" );
""" Pack the given user's texture into an HttpResponse.
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) )
try:
img = user.getTexture()
except ValueError:
raise Http404()
else:
buf = StringIO()
img.save( buf, "PNG" )
return HttpResponse( buf.getvalue(), "image/png" )
@login_required
def users( request, server ):
""" Create a list of MumbleUsers for a given server serialized as a JSON object.
If the request has a "data" field, evaluate that and update the user records.
"""
srv = get_object_or_404( Mumble, id=int(server) );
if "resync" in request.POST and request.POST['resync'] == "true":
srv.readUsersFromMurmur();
if not srv.isUserAdmin( request.user ):
return HttpResponse(
simplejson.dumps({ 'success': False, 'objects': [], 'errormsg': 'Access denied' }),
mimetype='text/javascript'
);
if request.method == 'POST':
data = simplejson.loads( request.POST['data'] );
for record in data:
if record['id'] == -1:
if record['delete']:
continue;
mu = MumbleUser( server=srv );
else:
mu = MumbleUser.objects.get( id=record['id'] );
if record['delete']:
mu.delete();
continue;
mu.name = record['name'];
mu.password = record['password'];
if record['owner']:
mu.owner = User.objects.get( id=int(record['owner']) );
mu.save();
mu.aclAdmin = record['admin'];
users = [];
for mu in srv.mumbleuser_set.all():
owner = None;
if mu.owner is not None:
owner = mu.owner.id
users.append( {
'id': mu.id,
'name': mu.name,
'password': None,
'owner': owner,
'admin': mu.aclAdmin,
} );
return HttpResponse(
simplejson.dumps( { 'success': True, 'objects': users } ),
mimetype='text/javascript'
);
""" Create a list of MumbleUsers for a given server serialized as a JSON object.
If the request has a "data" field, evaluate that and update the user records.
"""
srv = get_object_or_404( Mumble, id=int(server) )
if "resync" in request.POST and request.POST['resync'] == "true":
srv.readUsersFromMurmur()
if not srv.isUserAdmin( request.user ):
return HttpResponse(
simplejson.dumps({ 'success': False, 'objects': [], 'errormsg': 'Access denied' }),
mimetype='text/javascript'
)
if request.method == 'POST':
data = simplejson.loads( request.POST['data'] )
for record in data:
if record['id'] == -1:
if record['delete']:
continue
mu = MumbleUser( server=srv )
else:
mu = MumbleUser.objects.get( id=record['id'] )
if record['delete']:
mu.delete()
continue
mu.name = record['name']
mu.password = record['password']
if record['owner']:
mu.owner = User.objects.get( id=int(record['owner']) )
mu.save()
mu.aclAdmin = record['admin']
users = []
for mu in srv.mumbleuser_set.all():
owner = None
if mu.owner is not None:
owner = mu.owner.id
users.append( {
'id': mu.id,
'name': mu.name,
'password': None,
'owner': owner,
'admin': mu.aclAdmin,
} )
return HttpResponse(
simplejson.dumps( { 'success': True, 'objects': users } ),
mimetype='text/javascript'
)
@login_required
def djangousers( request ):
""" Return a list of all Django users' names and IDs. """
users = [ { 'uid': '', 'uname': '------' } ];
for du in User.objects.all().order_by( 'username' ):
users.append( {
'uid': du.id,
'uname': unicode( du ),
} );
return HttpResponse(
simplejson.dumps( { 'success': True, 'objects': users } ),
mimetype='text/javascript'
);
""" Return a list of all Django users' names and IDs. """
users = [ { 'uid': '', 'uname': '------' } ]
for du in User.objects.all().order_by( 'username' ):
users.append( {
'uid': du.id,
'uname': unicode( du ),
} )
return HttpResponse(
simplejson.dumps( { 'success': True, 'objects': users } ),
mimetype='text/javascript'
)
def mmng_tree( request, server ):
""" Return a JSON representation of the channel tree suitable for
Murmur Manager:
http://github.com/cheald/murmur-manager/tree/master/widget/
To make the client widget query this view, set the URL attribute
to "http://<mumble-django base URL>/mumble"
"""
srv = get_object_or_404( Mumble, id=int(server) );
chanlist = []
userlist = []
for chanid in srv.channels:
channel = srv.channels[chanid]
if channel.parent is not None:
parent = channel.parent.chanid
else:
parent = -1
chanlist.append({
"type": "channel",
"id": channel.chanid,
"name": channel.name,
"parent": parent,
"position": channel.position,
"state": channel.temporary and "temporary" or "permanent"
})
for sessionid in srv.players:
user = srv.players[sessionid]
userlist.append({
"type": "player",
"name": user.name,
"channel": user.channel.chanid,
"mute": user.mute or user.selfMute or user.suppress,
"deaf": user.deaf or user.selfDeaf,
"online": user.onlinesecs,
"state": "online"
})
if "callback" in request.GET:
prefix = request.GET["callback"]
else:
prefix = ""
return HttpResponse(
prefix + "(" + simplejson.dumps( { 'channels': chanlist, 'users': userlist } ) + ")",
mimetype='text/javascript'
);
""" Return a JSON representation of the channel tree suitable for
Murmur Manager:
http://github.com/cheald/murmur-manager/tree/master/widget/
To make the client widget query this view, set the URL attribute
to "http://<mumble-django base URL>/mumble"
"""
srv = get_object_or_404( Mumble, id=int(server) )
chanlist = []
userlist = []
for chanid in srv.channels:
channel = srv.channels[chanid]
if channel.parent is not None:
parent = channel.parent.chanid
else:
parent = -1
chanlist.append({
"type": "channel",
"id": channel.chanid,
"name": channel.name,
"parent": parent,
"position": channel.position,
"state": channel.temporary and "temporary" or "permanent"
})
for sessionid in srv.players:
user = srv.players[sessionid]
userlist.append({
"type": "player",
"name": user.name,
"channel": user.channel.chanid,
"mute": user.mute or user.selfMute or user.suppress,
"deaf": user.deaf or user.selfDeaf,
"online": user.onlinesecs,
"state": "online"
})
if "callback" in request.GET:
prefix = request.GET["callback"]
else:
prefix = ""
return HttpResponse(
prefix + "(" + simplejson.dumps( { 'channels': chanlist, 'users': userlist } ) + ")",
mimetype='text/javascript'
)
def mumbleviewer_tree_xml( request, server ):
""" Get the XML tree from the server and serialize it to the client. """
from xml.etree.cElementTree import tostring as xml_to_string
srv = get_object_or_404( Mumble, id=int(server) );
return HttpResponse(
xml_to_string( srv.asMvXml(), encoding='utf-8' ),
mimetype='text/xml'
);
""" Get the XML tree from the server and serialize it to the client. """
from xml.etree.cElementTree import tostring as xml_to_string
srv = get_object_or_404( Mumble, id=int(server) )
return HttpResponse(
xml_to_string( srv.asMvXml(), encoding='utf-8' ),
mimetype='text/xml'
)
def mumbleviewer_tree_json( request, server ):
""" Get the Dict from the server and serialize it as JSON to the client. """
srv = get_object_or_404( Mumble, id=int(server) );
if "jsonp_callback" in request.GET:
prefix = request.GET["jsonp_callback"]
else:
prefix = ""
return HttpResponse(
prefix + "(" + simplejson.dumps( srv.asMvJson() ) + ")",
mimetype='text/javascript'
);
""" Get the Dict from the server and serialize it as JSON to the client. """
srv = get_object_or_404( Mumble, id=int(server) )
if "jsonp_callback" in request.GET:
prefix = request.GET["jsonp_callback"]
else:
prefix = ""
return HttpResponse(
prefix + "(" + simplejson.dumps( srv.asMvJson() ) + ")",
mimetype='text/javascript'
)

9
pyweb/processors.py

@ -1,4 +1,5 @@
# -*- coding: utf-8 -*-
# kate: space-indent on; indent-width 4; replace-tabs on;
"""
* Copyright © 2009-2010, Michael "Svedrin" Ziegler <diese-addy@funzt-halt.net>
@ -15,9 +16,9 @@
"""
def installed_apps(request):
from django.conf import settings
return { 'ROSETTA_INSTALLED': "rosetta" in settings.INSTALLED_APPS }
from django.conf import settings
return { 'ROSETTA_INSTALLED': "rosetta" in settings.INSTALLED_APPS }
def mumble_version(request):
from mumble import version_str
return { 'CURRENTVERSION': version_str }
from mumble import version_str
return { 'CURRENTVERSION': version_str }

103
pyweb/settings.py

@ -1,4 +1,5 @@
# -*- coding: utf-8 -*-
# kate: space-indent on; indent-width 4; replace-tabs on;
# Django settings for mumble_django project.
"""
@ -56,7 +57,7 @@ MUMBLE_DJANGO_ROOT = None ##
from os.path import join, dirname, abspath, exists
if not MUMBLE_DJANGO_ROOT or not exists( MUMBLE_DJANGO_ROOT ):
MUMBLE_DJANGO_ROOT = dirname(dirname(abspath(__file__)));
MUMBLE_DJANGO_ROOT = dirname(dirname(abspath(__file__)))
# URL Template for constructing Gravatars.
GRAVATAR_URL = 'http://www.gravatar.com/avatar/%(hash)s.jpg?d=monsterid&s=%(size)d'
@ -95,8 +96,8 @@ PROTECTED_MODE = False
# stolen they could easily take over the server. (So make sure the password can't be easily
# guessed, use at least over 9000 letters, blah blah.)
# This feature is only available if PROTECTED_MODE is not active.
ALLOW_ACCOUNT_LINKING = True # Allow linking in general?
ALLOW_ACCOUNT_LINKING_ADMINS = False # Allow linking for Admin accounts?
ALLOW_ACCOUNT_LINKING = True # Allow linking in general?
ALLOW_ACCOUNT_LINKING_ADMINS = False # Allow linking for Admin accounts?
# Warning and Critical levels for the Munin plugin. These will be multiplied with the
# server instance's slot count to calculate the real levels.
@ -155,85 +156,85 @@ MEDIA_URL = MUMBLE_DJANGO_URL+'static/'
ADMIN_MEDIA_PREFIX = MUMBLE_DJANGO_URL+'media/'
# URL to the login view
LOGIN_URL = MUMBLE_DJANGO_URL + 'accounts/login';
LOGIN_REDIRECT_URL = MUMBLE_DJANGO_URL + 'accounts/profile';
LOGIN_URL = MUMBLE_DJANGO_URL + 'accounts/login'
LOGIN_REDIRECT_URL = MUMBLE_DJANGO_URL + 'accounts/profile'
# Automatically generate a .secret.txt file containing the SECRET_KEY.
# Shamelessly stolen from ByteFlow: <http://www.byteflow.su>
try:
SECRET_KEY
SECRET_KEY
except NameError:
SECRET_FILE = join(MUMBLE_DJANGO_ROOT, '.secret.txt')
try:
SECRET_KEY = open(SECRET_FILE).read().strip()
except IOError:
try:
from random import choice
SECRET_KEY = ''.join([choice('abcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*(-_=+)') for i in range(50)])
secret = file(SECRET_FILE, 'w')
secret.write(SECRET_KEY)
secret.close()
except IOError:
Exception('Please create a %s file with random characters to generate your secret key!' % SECRET_FILE)
SECRET_FILE = join(MUMBLE_DJANGO_ROOT, '.secret.txt')
try:
SECRET_KEY = open(SECRET_FILE).read().strip()
except IOError:
try:
from random import choice
SECRET_KEY = ''.join([choice('abcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*(-_=+)') for i in range(50)])
secret = file(SECRET_FILE, 'w')
secret.write(SECRET_KEY)
secret.close()
except IOError:
Exception('Please create a %s file with random characters to generate your secret key!' % SECRET_FILE)
# List of callables that know how to import templates from various sources.
TEMPLATE_LOADERS = (
'django.template.loaders.filesystem.load_template_source',
'django.template.loaders.app_directories.load_template_source',
'django.template.loaders.filesystem.load_template_source',
'django.template.loaders.app_directories.load_template_source',
)
MIDDLEWARE_CLASSES = (
'django.middleware.common.CommonMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.locale.LocaleMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.middleware.common.CommonMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.locale.LocaleMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
)
ROOT_URLCONF = 'pyweb.urls'
TEMPLATE_DIRS = (
# Put strings here, like "/home/html/django_templates" or "C:/www/django/templates".
# Always use forward slashes, even on Windows.
# Don't forget to use absolute paths, not relative paths.
join( MUMBLE_DJANGO_ROOT, 'pyweb', 'templates' ),
# Put strings here, like "/home/html/django_templates" or "C:/www/django/templates".
# Always use forward slashes, even on Windows.
# Don't forget to use absolute paths, not relative paths.
join( MUMBLE_DJANGO_ROOT, 'pyweb', 'templates' ),
)
TEMPLATE_CONTEXT_PROCESSORS = (
"django.core.context_processors.auth",
"django.core.context_processors.debug",
"django.core.context_processors.i18n",
"django.core.context_processors.media",
'processors.installed_apps',
'processors.mumble_version',
"django.core.context_processors.auth",
"django.core.context_processors.debug",
"django.core.context_processors.i18n",
"django.core.context_processors.media",
'processors.installed_apps',
'processors.mumble_version',
)
TEST_RUNNER = 'mumble.testrunner.run_tests'
TEST_MURMUR_LAB_DIR = join( dirname(MUMBLE_DJANGO_ROOT), 'murmur' );
TEST_MURMUR_FILES_DIR = join( MUMBLE_DJANGO_ROOT, 'testdata' );
TEST_MURMUR_LAB_DIR = join( dirname(MUMBLE_DJANGO_ROOT), 'murmur' )
TEST_MURMUR_FILES_DIR = join( MUMBLE_DJANGO_ROOT, 'testdata' )
CONVERSIONSQL_ROOT = join( MUMBLE_DJANGO_ROOT, "pyweb", "mumble", "conversionsql" );
CONVERSIONSQL_ROOT = join( MUMBLE_DJANGO_ROOT, "pyweb", "mumble", "conversionsql" )
INSTALLED_APPS = [
'django.contrib.auth',
'django.contrib.admin',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.sites',
'registration',
'mumble',
'django.contrib.auth',
'django.contrib.admin',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.sites',
'registration',
'mumble',
]
def modprobe( name ):
""" Try to import the named module, and if that works add it to INSTALLED_APPS. """
try:
__import__( name )
except ImportError:
pass
else:
INSTALLED_APPS.append( name )
""" Try to import the named module, and if that works add it to INSTALLED_APPS. """
try:
__import__( name )
except ImportError:
pass
else:
INSTALLED_APPS.append( name )
# Check if rosetta is available.
# http://code.google.com/p/django-rosetta

37
pyweb/urls.py

@ -1,4 +1,5 @@
# -*- coding: utf-8 -*-
# kate: space-indent on; indent-width 4; replace-tabs on;
"""
* Copyright © 2009-2010, Michael "Svedrin" Ziegler <diese-addy@funzt-halt.net>
@ -26,32 +27,32 @@ handler404 = 'django.views.defaults.page_not_found'
handler500 = 'django.views.defaults.server_error'
urlpatterns = patterns('',
(r'^/?$', 'mumble.views.redir' ),
(r'^/?$', 'mumble.views.redir' ),
# Uncomment the admin/doc line below and add 'django.contrib.admindocs'
# to INSTALLED_APPS to enable admin documentation:
# (r'^admin/doc/', include('django.contrib.admindocs.urls')),
# Uncomment the admin/doc line below and add 'django.contrib.admindocs'
# to INSTALLED_APPS to enable admin documentation:
# (r'^admin/doc/', include('django.contrib.admindocs.urls')),
(r'^accounts/profile/', 'views.profile' ),
(r'^accounts/imprint/', 'views.imprint' ),
(r'^accounts/', include('registration.urls') ),
(r'^accounts/profile/', 'views.profile' ),
(r'^accounts/imprint/', 'views.imprint' ),
(r'^accounts/', include('registration.urls') ),
(r'^mumble/', include('mumble.urls')),
(r'^mumble/', include('mumble.urls')),
# Uncomment the next line to enable the admin:
(r'^admin/', admin.site.urls),
# Uncomment the next line to enable the admin:
(r'^admin/', admin.site.urls),
)
if "rosetta" in settings.INSTALLED_APPS:
urlpatterns += patterns( '',
( r'rosetta/', include( 'rosetta.urls' ) )
)
urlpatterns += patterns( '',
( r'rosetta/', include( 'rosetta.urls' ) )
)
# Development stuff
if settings.DEBUG or True:
urlpatterns += patterns('',
(r'^%s(?P<path>.*)$' % settings.MEDIA_URL[1:],
'django.views.static.serve',
{'document_root': settings.MEDIA_ROOT, 'show_indexes': True} ),
)
urlpatterns += patterns('',
(r'^%s(?P<path>.*)$' % settings.MEDIA_URL[1:],
'django.views.static.serve',
{'document_root': settings.MEDIA_ROOT, 'show_indexes': True} ),
)

39
pyweb/views.py

@ -1,4 +1,5 @@
# -*- coding: utf-8 -*-
# kate: space-indent on; indent-width 4; replace-tabs on;
"""
* Copyright © 2009-2010, Michael "Svedrin" Ziegler <diese-addy@funzt-halt.net>
@ -14,29 +15,29 @@
* GNU General Public License for more details.
"""
from django.shortcuts import render_to_response
from django.template import RequestContext
from django.contrib.auth.decorators import login_required
from django.shortcuts import render_to_response
from django.template import RequestContext
from django.contrib.auth.decorators import login_required
from mumble.models import MumbleUser
from mumble.models import MumbleUser
@login_required
def profile( request ):
userdata = {
"ProfileActive": True,
"mumbleaccs": MumbleUser.objects.filter( owner = request.user ),
};
return render_to_response(
'registration/profile.html',
userdata,
context_instance = RequestContext(request)
);
userdata = {
"ProfileActive": True,
"mumbleaccs": MumbleUser.objects.filter( owner = request.user ),
}
return render_to_response(
'registration/profile.html',
userdata,
context_instance = RequestContext(request)
)
def imprint( request ):
import mumble
return render_to_response(
'registration/imprint.html',
{ 'upstreamversion': mumble.getLatestUpstreamVersion() },
context_instance = RequestContext(request) );
import mumble
return render_to_response(
'registration/imprint.html',
{ 'upstreamversion': mumble.getLatestUpstreamVersion() },
context_instance = RequestContext(request) )
Loading…
Cancel
Save