Forked mumble-django project from https://bitbucket.org/Svedrin/mumble-django
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

515 lines
12 KiB

  1. #!/usr/bin/python
  2. # -*- coding: utf-8 -*-
  3. """
  4. * Copyright (C) 2009, Michael "Svedrin" Ziegler <diese-addy@funzt-halt.net>
  5. *
  6. * Mumble-Django is free software; you can redistribute it and/or modify
  7. * it under the terms of the GNU General Public License as published by
  8. * the Free Software Foundation; either version 2 of the License, or
  9. * (at your option) any later version.
  10. *
  11. * This package is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU General Public License for more details.
  15. """
  16. # Set this to the same path you used in settings.py, or None for auto-detection.
  17. MUMBLE_DJANGO_ROOT = None;
  18. ### DO NOT CHANGE ANYTHING BELOW THIS LINE ###
  19. import os, sys
  20. from os.path import join, dirname, abspath, exists
  21. # Path auto-detection
  22. if not MUMBLE_DJANGO_ROOT or not exists( MUMBLE_DJANGO_ROOT ):
  23. MUMBLE_DJANGO_ROOT = dirname(abspath(__file__));
  24. # environment variables
  25. sys.path.append( MUMBLE_DJANGO_ROOT )
  26. sys.path.append( join( MUMBLE_DJANGO_ROOT, 'pyweb' ) )
  27. os.environ['DJANGO_SETTINGS_MODULE'] = 'pyweb.settings'
  28. # If you get an error about Python not being able to write to the Python
  29. # egg cache, the egg cache path might be set awkwardly. This should not
  30. # happen under normal circumstances, but every now and then, it does.
  31. # Uncomment this line to point the egg cache to /tmp.
  32. #os.environ['PYTHON_EGG_CACHE'] = '/tmp/pyeggs'
  33. import locale
  34. import curses
  35. from curses.textpad import Textbox
  36. from django.db.models.fields.related import ForeignKey
  37. from django.db import models
  38. from mumble.models import *
  39. from mumble.forms import *
  40. locale.setlocale(locale.LC_ALL, '')
  41. def getNum( prompt, **kwargs ):
  42. id = None;
  43. while type(id) != int:
  44. print
  45. try:
  46. id = raw_input( "%s >>> " % prompt ).strip();
  47. if id == 'q':
  48. return None;
  49. elif id in kwargs:
  50. return kwargs[id];
  51. id = int( id );
  52. except Exception, instance:
  53. print "Error reading input. Did you type a number?";
  54. print instance;
  55. return id;
  56. def util_editModel( model, blacklist = None ):
  57. while True:
  58. print "Current settings"
  59. print "================"
  60. for field in model._meta.fields:
  61. if blacklist and field.name in blacklist:
  62. continue;
  63. print "#%-5d %-30s %s" % ( model._meta.fields.index( field ), field.verbose_name, getattr( model, field.name ) );
  64. print "================"
  65. print "Enter the index of the parameter you would like to change,"
  66. print "or q to return."
  67. idx = getNum( "Index" );
  68. if idx is None:
  69. save = raw_input( "save? Y/n >>> " );
  70. if not save or save.lower() == 'y':
  71. print "saving changes.";
  72. model.save();
  73. else:
  74. print "NOT saving changes."
  75. return;
  76. field = model._meta.fields[idx];
  77. if blacklist and field.name in blacklist:
  78. print "This field can not be changed.";
  79. elif isinstance( field, ForeignKey ):
  80. print "This is a ForeignKey.";
  81. print field.rel.to.objects.all();
  82. else:
  83. value = None;
  84. while value is None:
  85. print
  86. try:
  87. value = field.to_python( raw_input( "%s >>> " % field.name ).strip() );
  88. except Exception, instance:
  89. print instance;
  90. setattr( model, field.name, value );
  91. def act_serverDetails( server ):
  92. "View or edit server settings."
  93. util_editModel( server, ( "id", "sslcrt", "sslkey" ) );
  94. def act_registeredUsers( server ):
  95. "View or edit user registrations."
  96. mumbleusers_list = server.mumbleuser_set.all();
  97. print "Currently registered accounts";
  98. print "=============================";
  99. for mu in mumbleusers_list:
  100. if mu.owner is not None:
  101. print "#%-5d %-20s Owner: %-20s Admin: %s" % ( mu.id, mu.name, mu.owner.username, mu.getAdmin() );
  102. else:
  103. print "#%-5d %-20s" % ( mu.id, mu.name );
  104. print "=============================";
  105. print "Enter the ID of the account you would like to change, n to create a new one, or q to return."
  106. while True:
  107. idx = getNum( "ID", n=-1 );
  108. if idx is None:
  109. return;
  110. if idx == -1:
  111. mu = MumbleUser();
  112. mu.server = server;
  113. else:
  114. mu = mumbleusers_list.get( id=idx );
  115. util_editModel( mu, ( "id", "mumbleid", "server" ) );
  116. def act_listChannels( server ):
  117. "Display a channel tree."
  118. def printItem( item, level ):
  119. print "%s%s" % ( " "*level, item );
  120. server.rootchan.visit( printItem );
  121. def act_chanDetails( server ):
  122. "Display detailed information about one specific channel."
  123. print "Please choose the channel by entering the according ID (the number in parentheses)."
  124. act_listChannels( server );
  125. id = getNum( "ID" );
  126. if id is None: return;
  127. print "Channel name: %s" % server.channels[id].name
  128. print "Channel ID: %d" % server.channels[id].chanid
  129. print "Users online: %d" % len( server.channels[id].players )
  130. print "Linked chans: %d" % len( server.channels[id].linked )
  131. def cli_chooseServer():
  132. mumble_all = Mumble.objects.all().order_by( 'name', 'id' );
  133. print "Please choose a Server instance by typing the corresponding ID.\n";
  134. for mm in mumble_all:
  135. print "#%d\t%s" % ( mm.id, mm.name );
  136. print "n: Create new instance";
  137. print "q: Exit";
  138. id = getNum( "ID", n = -1 );
  139. if id is None:
  140. return;
  141. elif id == -1:
  142. return Mumble();
  143. return Mumble.objects.get( id=id );
  144. def cli_chooseAction( server ):
  145. actions = {
  146. "LISTCHAN": act_listChannels,
  147. "CHANINFO": act_chanDetails,
  148. "EDITSERVER": act_serverDetails,
  149. "EDITUSERS": act_registeredUsers,
  150. };
  151. while True:
  152. print "What do you want to do?"
  153. keys = actions.keys();
  154. for act in keys:
  155. print "#%-5d %-20s %s" % ( keys.index(act), act, actions[act].__doc__ );
  156. print "q: Return to server selection";
  157. idx = getNum( "Index" );
  158. if idx is None:
  159. return;
  160. # call action function
  161. func = actions[ keys[idx] ]
  162. func( server );
  163. print
  164. def oldmain():
  165. print
  166. while True:
  167. mumble = cli_chooseServer();
  168. if mumble is None:
  169. print "Bye.";
  170. return;
  171. print "Selected %s." % mumble;
  172. print
  173. cli_chooseAction( mumble );
  174. print
  175. class BaseWindow( object ):
  176. tabName = "tehBasez";
  177. def __init__( self, parentwin, mumble, pos_x, pos_y ):
  178. self.pos = ( pos_x, pos_y );
  179. self.win = parentwin.subwin( pos_y, pos_x );
  180. self.mm = mumble;
  181. self.win.keypad(1);
  182. def draw( self ):
  183. self.win.addstr( 1, 1, self.tabName );
  184. def border( self ):
  185. self.win.border();
  186. def enter( self ):
  187. while( True ):
  188. key = self.win.getch();
  189. if key == curses.KEY_UP:
  190. return;
  191. class WndChannels( BaseWindow ):
  192. tabName = 'Channels';
  193. def printItem( self, item, level ):
  194. str = "";
  195. if item.is_server or item.is_channel:
  196. str = "%s (Channel)" % item.name;
  197. else:
  198. str = "%s (Player)" % item.name
  199. self.win.addstr( self.curr_y, 4*level+1, str.encode(locale.getpreferredencoding()) )
  200. self.curr_y += 1;
  201. def draw( self ):
  202. self.curr_y = 1;
  203. self.mm.rootchan.visit( self.printItem );
  204. class WndSettings( BaseWindow ):
  205. tabName = 'Server settings';
  206. blacklist = ( 'id', 'sslkey', 'sslcrt' );
  207. def __init__( self, parentwin, mumble, pos_x, pos_y ):
  208. BaseWindow.__init__( self, parentwin, mumble, pos_x, pos_y );
  209. self.form = MumbleAdminForm( instance=mumble );
  210. self.editors = {};
  211. self.fields = [ mf for mf in mumble._meta.fields if mf.name not in self.blacklist ];
  212. def getFieldHeight( self, field ):
  213. if isinstance( field, models.TextField ):
  214. return 10;
  215. return 1;
  216. def getFieldYPos( self, field ):
  217. ypos = 3;
  218. for curr_field in self.fields:
  219. if curr_field is field:
  220. return ypos;
  221. ypos += self.getFieldHeight( curr_field );
  222. raise ReferenceError( "Field not found!" );
  223. def draw( self ):
  224. curr_y = 3;
  225. for field in self.fields:
  226. value = unicode( getattr( self.mm, field.name ) );
  227. self.win.addstr( curr_y, 1, field.verbose_name.encode(locale.getpreferredencoding()) );
  228. height = self.getFieldHeight( field );
  229. winsize = self.win.getmaxyx();
  230. editwin = self.win.subwin( height, winsize[1]-31, self.pos[1] + curr_y, self.pos[0] + 30 );
  231. editwin.keypad(1);
  232. editwin.addstr( value.encode(locale.getpreferredencoding()) );
  233. editbox = Textbox( editwin );
  234. self.editors[field.name] = ( editwin, editbox );
  235. curr_y += height;
  236. def enter( self ):
  237. self.selIdx = 0;
  238. self.selMax = len( self.fields ) - 1;
  239. while( True ):
  240. # Highlight selected field label
  241. field = self.fields[self.selIdx];
  242. self.win.addstr(
  243. self.getFieldYPos(field), 1,
  244. field.verbose_name.encode(locale.getpreferredencoding()),
  245. curses.A_STANDOUT
  246. );
  247. self.win.refresh();
  248. key = self.win.getch();
  249. if key == curses.KEY_UP and self.selIdx > 0:
  250. self.selIdx -= 1;
  251. elif key == curses.KEY_DOWN and self.selIdx < self.selMax:
  252. self.selIdx += 1;
  253. elif key in ( ord('q'), ord('Q') ):
  254. return;
  255. elif key in ( ord('s'), ord('S') ):
  256. try:
  257. self.mm.save();
  258. except Exception, instance:
  259. msg = unicode( instance );
  260. else:
  261. msg = "Your settings have been saved.";
  262. self.win.addstr( 1, 5, msg.encode(locale.getpreferredencoding()) );
  263. elif key in ( curses.KEY_RIGHT, curses.KEY_ENTER, ord('\n') ):
  264. self.editors[field.name][1].edit();
  265. setattr( self.mm, field.name, field.to_python( self.editors[field.name][1].gather().strip() ) );
  266. self.editors[field.name][0].refresh();
  267. self.win.addstr(
  268. self.getFieldYPos(field), 1,
  269. field.verbose_name.encode(locale.getpreferredencoding())
  270. );
  271. class WndUsers( BaseWindow ):
  272. tabName = 'Registered users';
  273. class MumbleForm( object ):
  274. def __init__( self, parentwin, mumble, pos_x, pos_y ):
  275. self.pos = ( pos_x, pos_y );
  276. self.win = parentwin.subwin( pos_y, pos_x );
  277. self.mm = mumble;
  278. self.win.keypad(1);
  279. self.windows = (
  280. WndChannels( self.win, mumble, pos_x + 2, pos_y + 2 ),
  281. WndSettings( self.win, mumble, pos_x + 2, pos_y + 2 ),
  282. WndUsers( self.win, mumble, pos_x + 2, pos_y + 2 ),
  283. );
  284. self.curridx = 0;
  285. self.currmax = len( self.windows ) - 1;
  286. currwin = property( lambda self: self.windows[self.curridx], None );
  287. def mvwin( self, pos_x, pos_y ):
  288. self.win.mvwin( pos_y, pos_x );
  289. def mvdefault( self ):
  290. self.win.mvwin( self.pos[1], self.pos[0] );
  291. def draw( self ):
  292. self.win.addstr( 0, 0, self.mm.name.encode(locale.getpreferredencoding()) );
  293. def drawTabs( self ):
  294. first = True;
  295. for subwin in self.windows:
  296. flags = 0;
  297. if subwin is self.currwin: flags |= curses.A_STANDOUT;
  298. if first:
  299. self.win.addstr( 1, 2, "%-20s" % subwin.tabName, flags );
  300. first = False;
  301. else:
  302. self.win.addstr( "%-20s" % subwin.tabName, flags );
  303. def enter( self ):
  304. self.drawTabs();
  305. self.currwin.draw();
  306. self.currwin.border();
  307. while( True ):
  308. key = self.win.getch();
  309. if key == curses.KEY_LEFT and self.curridx > 0:
  310. self.curridx -= 1;
  311. elif key == curses.KEY_RIGHT and self.curridx < self.currmax:
  312. self.curridx += 1;
  313. elif key in ( ord('q'), ord('Q'), curses.KEY_UP ):
  314. return;
  315. elif key in ( curses.KEY_ENTER, curses.KEY_DOWN, ord('\n') ):
  316. self.currwin.enter();
  317. self.win.clear();
  318. self.draw();
  319. self.drawTabs();
  320. self.currwin.draw();
  321. self.currwin.border();
  322. self.win.refresh();
  323. def main( stdscr ):
  324. first_y = 3;
  325. curr_y = first_y;
  326. mumbles = list();
  327. for mm in Mumble.objects.all().order_by( "name", "id" ):
  328. mwin = MumbleForm( stdscr, mm, pos_x=5, pos_y=curr_y );
  329. mumbles.append( mwin );
  330. mwin.draw();
  331. curr_y += 1;
  332. selectedIdx = 0;
  333. selectedMax = len(mumbles) - 1;
  334. while( True ):
  335. selectedObj = mumbles[selectedIdx];
  336. # Draw selection marker
  337. stdscr.addstr( first_y + selectedIdx, 3, '*' );
  338. stdscr.refresh();
  339. key = stdscr.getch();
  340. if key == curses.KEY_UP:
  341. stdscr.addstr( first_y + selectedIdx, 3, ' ' );
  342. selectedIdx -= 1;
  343. elif key == curses.KEY_DOWN:
  344. stdscr.addstr( first_y + selectedIdx, 3, ' ' );
  345. selectedIdx += 1;
  346. elif key in ( curses.KEY_RIGHT, curses.KEY_ENTER, ord('\n') ):
  347. stdscr.clear();
  348. selectedObj.mvwin( 5, first_y );
  349. selectedObj.draw();
  350. stdscr.refresh();
  351. selectedObj.enter();
  352. stdscr.clear();
  353. selectedObj.mvdefault();
  354. for mwin in mumbles:
  355. mwin.draw();
  356. elif key in ( ord('q'), ord('Q') ):
  357. return;
  358. if selectedIdx < 0: selectedIdx = 0;
  359. elif selectedIdx > selectedMax: selectedIdx = selectedMax;
  360. if __name__ == '__main__':
  361. #parser = OptionParser();
  362. #parser.add_option( "-v", "--verbose", help="verbose output messages", default=False, action="store_true" );
  363. #parser.add_option( "-n", "--num", help="size of the Matrix", default=4, type = 'int' );
  364. #parser.add_option( "-s", "--sure", help="don't prompt if num >= 10", default=False, action="store_true" );
  365. #options, args = parser.parse_args();
  366. curses.wrapper( main );