webui-refactor:use deluge.component for components/prepare for plugins

This commit is contained in:
Martijn Voncken 2008-03-17 19:42:44 +00:00
parent 1a5ebf73ee
commit f1cd5071da
22 changed files with 377 additions and 518 deletions

View file

@ -40,9 +40,9 @@ from lib.webpy022.http import seeother
import sys
import os
import utils
from deluge import component
groups = []
blocks = forms.utils.datastructures.SortedDict()
config_page_manager = component.get("ConfigPageManager")
class WebCfgForm(forms.Form):
"config base for webui"
@ -76,9 +76,9 @@ class config_page:
"""
def get_form_class(self,name):
try:
return blocks[name]
return config_page_manager.blocks[name]
except KeyError:
raise Exception('no config page named:"%s"')
raise Exception('no config page named:"%s"' % name)
@deco.deluge_page
def GET(self, name):
@ -109,18 +109,4 @@ class config_page:
error= _('Correct the errors above and try again'))
def render(self, f , name , message = '' , error=''):
return render.config(groups, blocks, f, name , message , error)
def register_block(group, name, form):
if not group in groups:
groups.append(group)
form.group = group
blocks[name] = form
def unregister_block(name):
del blocks[name]
return render.config(config_page_manager.groups, config_page_manager.blocks, f, name , message , error)

View file

@ -0,0 +1,58 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
# Copyright (C) Martijn Voncken 2008 <mvoncken@gmail.com>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2, or (at your option)
# any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, write to:
# The Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor
# Boston, MA 02110-1301, USA.
#
# In addition, as a special exception, the copyright holders give
# permission to link the code of portions of this program with the OpenSSL
# library.
# You must obey the GNU General Public License in all respects for all of
# the code used other than OpenSSL. If you modify file(s) with this
# exception, you may extend this exception to your version of the file(s),
# but you are not obligated to do so. If you do not wish to do so, delete
# this exception statement from your version. If you delete this exception
# statement from all source files in the program, then also delete it here.
from utils import logcall
from render import template
from deluge import component
import lib.newforms_plus as forms
class ConfigPageManager(component.Component):
def __init__(self):
component.Component.__init__(self, "ConfigPageManager")
self.groups = []
self.blocks = forms.utils.datastructures.SortedDict()
def register(self, group, name, form):
if not group in self.groups:
self.groups.append(group)
form.group = group
self.blocks[name] = form
def unregister(self, name):
del self.blocks[name]
__config_page_manager = ConfigPageManager()

View file

@ -31,13 +31,16 @@
# this exception statement from your version. If you delete this exception
# statement from all source files in the program, then also delete it here.
import lib.newforms_plus as forms
import config
import utils
from webserver_common import ws, proxy , log
import lib.newforms_plus as forms
import config_forms
from deluge import component
config_page = component.get("ConfigPageManager")
class NetworkPorts(config.CfgForm ):
class NetworkPorts(config_forms.CfgForm ):
title = _("Ports")
info = _("Restart daemon after changing these values.")
_port_from = forms.IntegerField(_("From"))
@ -45,7 +48,7 @@ class NetworkPorts(config.CfgForm ):
random_port = forms.CheckBox(_("Random"))
def initial_data(self):
data = config.CfgForm.initial_data(self)
data = config_forms.CfgForm.initial_data(self)
data['_port_from'] , data['_port_to'] = data['listen_ports']
return data
@ -53,15 +56,15 @@ class NetworkPorts(config.CfgForm ):
data['listen_ports'] = [data['_port_from'] , data['_port_to'] ]
del(data['_port_from'])
del(data['_port_to'])
config.CfgForm.save(self, data)
config_forms.config.CfgForm.save(self, data)
def validate(self, data):
if (data['_port_to'] < data['_port_from']):
raise ValidationError('"Port from" must be greater than "Port to"')
config.register_block('network','ports', NetworkPorts)
config_page.register('network','ports', NetworkPorts)
class NetworkExtra(config.CfgForm ):
class NetworkExtra(config_forms.CfgForm ):
title = _("Extra's")
dht = forms.CheckBox(_("Mainline DHT"))
upnp = forms.CheckBox(_("UpNP"))
@ -69,9 +72,9 @@ class NetworkExtra(config.CfgForm ):
utpex = forms.CheckBox(_("Peer-Exchange"))
lsd = forms.CheckBox(_("LSD"))
config.register_block('network','extra', NetworkExtra)
config_page.register('network','extra', NetworkExtra)
class NetworkEnc(config.CfgForm ):
class NetworkEnc(config_forms.CfgForm ):
title = _("Encryption")
_enc_choices = list(enumerate([_("Forced"),_("Enabled"),_("Disabled")]))
@ -82,10 +85,10 @@ class NetworkEnc(config.CfgForm ):
enc_level = forms.IntChoiceField(_("Level"), _level_choices)
enc_prefer_rc4 = forms.CheckBox("Prefer to encrypt entire stream")
config.register_block('network','encryption', NetworkEnc)
config_page.register('network','encryption', NetworkEnc)
class BandwithGlobal(config.CfgForm):
class BandwithGlobal(config_forms.CfgForm):
title = _("Global")
info = _("-1 = Unlimited")
max_connections_global = forms.DelugeInt(_("Maximum Connections"))
@ -93,18 +96,18 @@ class BandwithGlobal(config.CfgForm):
max_upload_speed = forms.DelugeFloat(_("Maximum Upload Speed (Kib/s)"))
max_upload_slots_global = forms.DelugeInt(_("Maximum Upload Slots"))
config.register_block('bandwidth','global', BandwithGlobal)
config_page.register('bandwidth','global', BandwithGlobal)
class BandwithTorrent(config.CfgForm):
class BandwithTorrent(config_forms.CfgForm):
title = _("Per Torrent")
info = _("-1 = Unlimited")
max_connections_per_torrent = forms.DelugeInt(_("Maximum Connections"))
max_upload_slots_per_torrent = forms.DelugeInt(_("Maximum Upload Slots"))
config.register_block('bandwidth','torrent', BandwithTorrent)
config_page.register('bandwidth','torrent', BandwithTorrent)
class Download(config.CfgForm):
class Download(config_forms.CfgForm):
title = _("Download")
download_location = forms.ServerFolder(_("Store all downoads in"))
torrentfiles_location = forms.ServerFolder(_("Save .torrent files to"))
@ -113,15 +116,15 @@ class Download(config.CfgForm):
prioritize_first_last_pieces = forms.CheckBox(
_('Prioritize first and last pieces'))
config.register_block('deluge','download', Download)
config_page.register('deluge','download', Download)
class Daemon(config.CfgForm):
class Daemon(config_forms.CfgForm):
title = _("Daemon")
info = _("Restart daemon and webui after changing these settings")
daemon_port = forms.IntegerField(_("Port"))
allow_remote = forms.CheckBox(_("Allow Remote Connections"))
config.register_block('deluge','daemon', Daemon)
config_page.register('deluge','daemon', Daemon)
class Plugins(forms.Form):
title = _("Enabled Plugins")
@ -139,9 +142,9 @@ class Plugins(forms.Form):
def save(self, value):
raise forms.ValidationError("SAVE:TODO")
config.register_block('deluge','plugins', Plugins)
config_page.register('deluge','plugins', Plugins)
"""
class Queue(forms.Form):
title = _("Queue")
info = _("queue-cfg not finished")
@ -159,4 +162,5 @@ class Queue(forms.Form):
def save(self, value):
raise forms.ValidationError("SAVE:TODO")
config.register_block('plugins','queue', Queue)
config_page.register('plugins','queue', Queue)
"""

View file

@ -31,13 +31,17 @@
# this exception statement from your version. If you delete this exception
# statement from all source files in the program, then also delete it here.
import lib.newforms_plus as forms
import config
import utils
from webserver_common import ws
from webserver_common import ws, log
import lib.newforms_plus as forms
import config_forms
from deluge import component
config_page = component.get("ConfigPageManager")
plugins = component.get("WebPluginManager")
class Template(config.WebCfgForm):
class Template(config_forms.WebCfgForm):
title = _("Template")
_templates = [(t,t) for t in ws.get_templates()]
@ -52,20 +56,16 @@ class Template(config.WebCfgForm):
from render import render
render.apply_cfg()
class Server(config.WebCfgForm):
class Server(config_forms.WebCfgForm):
title = _("Server")
port = forms.IntegerField(label = _("Port"),min_value=80)
use_https = forms.CheckBox(_("Use https"))
try:
import OpenSSL
except ImportError:
info = _("pyopenssl not installed, install this for https.")
port = forms.IntegerField(label = _("Port"),min_value=80)
use_https = forms.CheckBox(_("Use https"))
def post_save(self):
pass
#raise forms.ValidationError(
@ -93,6 +93,21 @@ class Password(forms.Form):
utils.end_session()
#raise forms.ValidationError(_("Password changed,please login again"))
config.register_block('webui','template', Template)
config.register_block('webui','server',Server)
config.register_block('webui','password',Password)
class WebUiPlugins(forms.Form):
title = _("WebUi Plugins")
_choices = [(p,p) for p in plugins.get_available_plugins()]
enabled_plugins = forms.MultipleChoice(_(""), _choices)
def initial_data(self):
return {'enabled_plugins':plugins.get_enabled_plugins()}
def save(self, data):
log.debug()
for plugin_name in data['enabled_plugins']:
plugins.enable_plugin(plugin_name)
config_page.register('webui','template', Template)
config_page.register('webui','server',Server)
config_page.register('webui','password',Password)
config_page.register('webui','webuiplugins',WebUiPlugins)

View file

@ -1,283 +0,0 @@
# -*- coding: utf-8 -*-
# Dbus Ipc for experimental web interface
#
# dbus_interface.py
#
# Copyright (C) Martijn Voncken 2007 <mvoncken@gmail.com>
# Contains copy and pasted code from other parts of deluge,see deluge AUTHORS
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2, or (at your option)
# any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, write to:
# The Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor
# Boston, MA 02110-1301, USA.
#
# In addition, as a special exception, the copyright holders give
# permission to link the code of portions of this program with the OpenSSL
# library.
# You must obey the GNU General Public License in all respects for all of
# the code used other than OpenSSL. If you modify file(s) with this
# exception, you may extend this exception to your version of the file(s),
# but you are not obligated to do so. If you do not wish to do so, delete
# this exception statement from your version. If you delete this exception
# statement from all source files in the program, then also delete it here.
import os
import gtk
import dbus
import deluge.common as common
from lib.pythonize import pythonize
import base64
import random
random.seed()
dbus_interface="org.deluge_torrent.dbusplugin"
dbus_service="/org/deluge_torrent/DelugeDbusPlugin"
dbus_manager = None
def get_dbus_manager(*args):
#another way to make a singleton.
global dbus_manager
if not dbus_manager:
dbus_manager = DbusManager(*args)
return dbus_manager
class DbusManager(dbus.service.Object):
def __init__(self, core, interface,config,config_file):
self.core = core
self.interface = interface
self.config = config
self.config_file = config_file
self.bus = dbus.SessionBus()
bus_name = dbus.service.BusName(dbus_interface,bus=self.bus)
dbus.service.Object.__init__(self, bus_name,dbus_service)
#
#todo : add: get_interface_version in=i,get_config_value in=s out=s
#
@dbus.service.method(dbus_interface=dbus_interface,
in_signature="",out_signature="as")
def get_session_state(self):
"""Returns a list of torrent_ids in the session.
same as 0.6, but returns type "as" instead of a pickle
"""
torrent_list = [str(key) for key in self.core.unique_IDs]
return torrent_list
@dbus.service.method(dbus_interface=dbus_interface,
in_signature="sas",out_signature="a{sv}")
def get_torrent_status(self, torrent_id, keys):
"""return torrent metadata of a single torrent as a dict
0.6 returns a pickle, this returns a dbus-type.
+added some more values to the dict
"""
torrent_id = int(torrent_id)
# Convert the array of strings to a python list of strings
nkeys = [str(key) for key in keys]
state = self.core.get_torrent_state(torrent_id)
torrent = self.core.unique_IDs[torrent_id]
status = {
"name": state["name"],
"total_size": state["total_size"],
"num_pieces": state["num_pieces"],
"state": state['state'],
"user_paused": self.core.is_user_paused(torrent_id),
"paused":state['is_paused'],
"progress": int(state["progress"] * 100),
"next_announce": state["next_announce"],
"total_payload_download":state["total_payload_download"],
"total_payload_upload": state["total_payload_upload"],
"download_payload_rate": state["download_rate"],
"upload_payload_rate": state["upload_rate"],
"num_peers": state["num_peers"],
"num_seeds": state["num_seeds"],
"total_wanted": state["total_wanted"],
"eta": common.estimate_eta(state),
"ratio": self.interface.manager.calc_ratio(torrent_id,state),
#non 0.6 values follow here:
"tracker_status": state.get("tracker_status","?"),
"uploaded_memory": torrent.uploaded_memory,
}
#more non 0.6 values
for key in ["total_seeds", "total_peers","is_seed", "total_done",
"total_download", "total_upload"
#, "download_rate","upload_rate"
, "num_files", "piece_length", "distributed_copies"
,"next_announce","tracker","queue_pos"]:
status[key] = state[key]
#print 'all_keys:',sorted(status.keys())
status_subset = {}
for key in keys:
if key in status:
status_subset[key] = status[key]
else:
print 'mbus error,no key named:', key
return status_subset
@dbus.service.method(dbus_interface=dbus_interface,
in_signature="as",out_signature="")
def pause_torrent(self, torrents):
"""same as 0.6 interface"""
for torrent_id in torrents:
torrent_id = int(torrent_id)
self.core.set_user_pause(torrent_id, True)
@dbus.service.method(dbus_interface=dbus_interface,
in_signature="as", out_signature="")
def resume_torrent(self, torrents):
"""same as 0.6 interface"""
for torrent_id in torrents:
torrent_id = int(torrent_id)
self.core.set_user_pause(torrent_id, False)
@dbus.service.method(dbus_interface=dbus_interface,
in_signature="as", out_signature="")
def force_reannounce(self, torrents):
"""same as 0.6 interface"""
for torrent_id in torrents:
torrent_id = int(torrent_id)
self.core.update_tracker(torrent_id)
@dbus.service.method(dbus_interface=dbus_interface,
in_signature="asbb", out_signature="")
def remove_torrent(self, torrent_ids, data_also, torrent_also):
"""remove a torrent,and optionally data and torrent
additions compared to 0.6 interface: (data_also, torrent_also)
"""
for torrent_id in torrent_ids:
torrent_id = int(torrent_id)
self.core.remove_torrent(torrent_id, bool(data_also)
,bool( torrent_also))
#this should not be needed:
gtk.gdk.threads_enter()
try:
self.interface.torrent_model_remove(torrent_id)
except:
pass
@dbus.service.method(dbus_interface=dbus_interface,
in_signature="s", out_signature="b")
def add_torrent_url(self, url):
filename = fetch_url(url)
self._add_torrent(filename)
return True
@dbus.service.method(dbus_interface=dbus_interface,
in_signature="s", out_signature="b")
def queue_up(self, torrent_id):
self.core.queue_up(int(torrent_id))
return True
@dbus.service.method(dbus_interface=dbus_interface,
in_signature="s", out_signature="b")
def queue_down(self, torrent_id):
self.core.queue_down(int(torrent_id))
return True
@dbus.service.method(dbus_interface=dbus_interface,
in_signature="ss", out_signature="b")
def add_torrent_filecontent(self, name, filecontent_b64):
"""not available in deluge 0.6 interface"""
#name = fillename without directory
name = name.replace('\\','/')
name = 'deluge_' + str(random.random()) + '_' + name.split('/')[-1]
filename = os.path.join(self.core.config.get("default_download_path"), name)
filecontent = base64.b64decode(filecontent_b64)
f = open(filename,"wb") #no with statement, that's py 2.5+
f.write(filecontent)
f.close()
print 'write:',filename
self._add_torrent(filename)
return True
@dbus.service.method(dbus_interface=dbus_interface,
in_signature="", out_signature="a{sv}")
def get_config(self):
return self.core.config.mapping
@dbus.service.method(dbus_interface=dbus_interface,
in_signature="s", out_signature="v")
def get_config_value(self,key):
return self.core.config.mapping[pythonize(key)] #ugly!
@dbus.service.method(dbus_interface=dbus_interface,
in_signature="a{sv}", out_signature="")
def set_config(self, config):
"""Set the config with values from dictionary"""
config = deluge.common.pythonize(config)
# Load all the values into the configuration
for key in self.core.config.keys():
self.core.config[key] = config[key]
self.core.apply_prefs()
@dbus.service.method(dbus_interface=dbus_interface,
in_signature="", out_signature="v")
def get_download_rate(self):
return self.core.get_state()['download_rate']
@dbus.service.method(dbus_interface=dbus_interface,
in_signature="", out_signature="v")
def get_upload_rate(self):
return self.core.get_state()['upload_rate']
@dbus.service.method(dbus_interface=dbus_interface,
in_signature="", out_signature="v")
def get_num_connections(self):
core_state = self.core.get_state()
return core_state['num_connections']
#internal
def _add_torrent(self, filename):
filename = unicode(filename)
target = self.core.config.get("default_download_path")
torrent_id = self.core.add_torrent(filename, target,
self.interface.config.get("use_compact_storage"))
#update gtk-ui This should not be needed!!
gtk.gdk.threads_enter()
try:
self.interface.torrent_model_append(torrent_id)
except:
pass
#finally is 2.5 only!
gtk.gdk.threads_leave()
return True
def fetch_url(url):
import urllib
try:
filename, headers = urllib.urlretrieve(url)
except IOError:
raise Exception( "Network error while trying to fetch torrent from %s"
% url)
else:
if (filename.endswith(".torrent") or
headers["content-type"]=="application/x-bittorrent"):
return filename
else:
raise Exception("URL doesn't appear to be a valid torrent file:%s"
% url)
return None

View file

@ -29,16 +29,28 @@
# this exception statement from your version. If you delete this exception
# statement from all source files in the program, then also delete it here.
#initialize components:
import menu_manager #registers as "MenuManager"
import config_page_manager #registers as "ConfigPageManager"
import plugin_manager #registers as "WebPluginManager"
import page_manager #registers as "PageManager"
from webserver_common import ws
#self registering pages etc.
import pages
import config_tabs_webui #auto registers in ConfigUiManager
import config_tabs_deluge #auto registers in ConfigUiManager
import register_menu
from webserver_common import ws #todo: remove ws.
from lib.webpy022.request import webpyfunc
from lib.webpy022 import webapi
from lib.gtk_cherrypy_wsgiserver import CherryPyWSGIServer
import lib.webpy022 as web
import os
def create_webserver(urls, methods, middleware):
from webserver_common import ws
from lib.webpy022.request import webpyfunc
from lib.webpy022 import webapi
from lib.gtk_cherrypy_wsgiserver import CherryPyWSGIServer
import os
func = webapi.wsgifunc(webpyfunc(urls, methods, False), *middleware)
server_address=("0.0.0.0", int(ws.config.get('port')))
@ -51,13 +63,14 @@ def create_webserver(urls, methods, middleware):
return server
def WebServer(debug = False):
import lib.webpy022 as web
from deluge import component
if debug:
middleware = [web.reloader]
else:
middleware = []
import pages
return create_webserver(pages.urls, pages.page_classes, middleware)
pagemanager = component.get("PageManager")
return create_webserver(pagemanager.urls, pagemanager.page_classes, middleware)
def run(debug = False):
server = WebServer(debug)

View file

@ -37,52 +37,56 @@ future : required for plugin-api.
"""
from utils import logcall
from render import template
from deluge import component
admin_pages = [] #[(title, url),..]
detail_tabs = [] #[(title, url),..]
toolbar_items = [] #((id,title ,flag ,method ,url ,image ),.. )
#a storage+sorteddict == evildict.
#toolbar:
class TB:
class TOOLBAR_FLAGS:
generic = 0
torrent = 1
torrent_list = 2
def register_toolbar_item(id, title, image, flag, method, url, important):
toolbar_items.append((id, title, image, flag, method, url, important))
#todo: remove lower hack.
class MenuManager(component.Component):
TOOLBAR_FLAGS = TOOLBAR_FLAGS
def __init__(self):
component.Component.__init__(self, "MenuManager")
self.admin_pages = [] #[(title, url),..]
self.detail_tabs = [] #[(title, url),..]
self.toolbar_items = [] #((id,title ,flag ,method ,url ,image ),.. )
def unregister_toolbar_item(item_id):
for (i, toolbar) in enumerate(admin_pages):
if toolbar[0] == item_id:
del toolbar_items[i]
#admin:
#register vars in template.
template.Template.globals["admin_pages"] = self.admin_pages
template.Template.globals["detail_tabs"] = self.detail_tabs
template.Template.globals["toolbar_items"] = self.toolbar_items
def register_admin_page(id, title, url):
admin_pages.append((id, title, url))
def unregister_admin_page(page_id):
for (i, (id, title, url)) in list(enumerate(admin_pages)):
if id == page_id:
del admin_pages[i]
return
def register_toolbar_item(self, id, title, image, flag, method, url, important):
self.toolbar_items.append((id, title, image, flag, method, url, important))
#todo: remove lower hack.
#detail:
def unregister_toolbar_item(self, item_id):
for (i, toolbar) in enumerate(admin_pages):
if toolbar[0] == item_id:
del self.toolbar_items[i]
def register_detail_tab(id, title, page):
detail_tabs.append((id, title, page))
#admin:
def register_admin_page(self, id, title, url):
self.admin_pages.append((id, title, url))
def unregister_detail_tab(tab_id):
for (i, (id, title, tab)) in list(enumerate(detail_tabs)):
if id == tab_id:
del detail_tabs[i]
return
def unregister_admin_page(page_id):
for (i, (id, title, url)) in list(enumerate(admin_pages)):
if id == page_id:
del self.admin_pages[i]
return
#detail:
def register_detail_tab(self, id, title, page):
self.detail_tabs.append((id, title, page))
def unregister_detail_tab(self, tab_id):
for (i, (id, title, tab)) in list(enumerate(detail_tabs)):
if id == tab_id:
del self.detail_tabs[i]
return
__menu_manager = MenuManager()
#register vars in template.
template.Template.globals["admin_pages"] = admin_pages
template.Template.globals["detail_tabs"] = detail_tabs
template.Template.globals["toolbar_items"] = toolbar_items

View file

@ -0,0 +1,69 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
#
# Copyright (C) Martijn Voncken 2007 <mvoncken@gmail.com>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2, or (at your option)
# any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, write to:
# The Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor
# Boston, MA 02110-1301, USA.
#
# In addition, as a special exception, the copyright holders give
# permission to link the code of portions of this program with the OpenSSL
# library.
# You must obey the GNU General Public License in all respects for all of
# the code used other than OpenSSL. If you modify file(s) with this
# exception, you may extend this exception to your version of the file(s),
# but you are not obligated to do so. If you do not wish to do so, delete
# this exception statement from your version. If you delete this exception
# statement from all source files in the program, then also delete it here.
#
from deluge import component
class PageManager(component.Component):
"""
web,py 0.2 mapping hack..
see deluge_webserver.py
"""
def __init__(self):
component.Component.__init__(self, "PageManager")
self.page_classes = {}
self.urls = []
def register_pages(self, url_list, class_list):
self.urls += url_list
self.page_classes.update(class_list)
def register_page(self, url, klass):
self.urls.append(url)
self.urls.append(klass.__name__)
self.page_classes[klass.__name__] = klass
def unregister_page(self, url):
raise NotImplemenetedError()
#self.page_classes[klass.__name__] = None
__page_manager = PageManager()

View file

@ -30,12 +30,16 @@
# this exception statement from your version. If you delete this exception
# statement from all source files in the program, then also delete it here.
#
#todo: remove useless imports.
from webserver_common import ws, proxy, log
from utils import *
import utils #todo remove the line above.
from render import render, error_page
import page_decorators as deco
from config import config_page
from config_forms import config_page
from torrent_options import torrent_options
from torrent_move import torrent_move
@ -48,55 +52,16 @@ web.webapi.internalerror = deluge_debugerror
import lib.webpy022 as web
from lib.webpy022.http import seeother, url
from lib.static_handler import static_handler
from torrent_add import torrent_add
from operator import attrgetter
import os
from deluge import component
page_manager = component.get("PageManager")
#from json_api import json_api #secuity leak, todo:fix
#self registering pages:
import config_tabs_webui #auto registers
import config_tabs_deluge #auto registers
from torrent_add import torrent_add #todo: self-register.
#plugin like api's
import menu_manager
from menu_manager import TB
#plugin-like api's : register
menu_manager.register_admin_page("config", _("Config"), "/config/")
menu_manager.register_admin_page("connect", _("Connect"), "/connect")
menu_manager.register_admin_page("about", _("About"), "/about")
menu_manager.register_admin_page("logout", _("Logout"), "/logout")
menu_manager.register_detail_tab("details", _("Details"), "tab_meta")
menu_manager.register_detail_tab("files", _("Files"), "tab_files")
menu_manager.register_detail_tab("options", _("Options"), "tab_options")
menu_manager.register_detail_tab("trackers", _("Trackers"), "tab_trackers")
menu_manager.register_toolbar_item("add", _("Add"), "list-add.png" , TB.generic,
"GET","/torrent/add/", True)
menu_manager.register_toolbar_item("delete",_("Delete"), "list-remove.png" ,TB.torrent_list,
"GET","/torrent/delete/" , True)
menu_manager.register_toolbar_item("stop",_("Stop"), "pause.png" ,TB.torrent_list,
"POST","/torrent/stop/", True)
menu_manager.register_toolbar_item("start",_("Start"), "start.png" ,TB.torrent_list,
"POST","/torrent/start/", True)
menu_manager.register_toolbar_item("queue_up",_("Up"), "queue-up.png" ,TB.torrent_list,
"POST","/torrent/queue/up/", True)
menu_manager.register_toolbar_item("queue_down",_("Down"), "queue-down.png" ,TB.torrent_list,
"POST","/torrent/queue/down/", True)
menu_manager.register_toolbar_item("details",_("Details"), "details.png" ,TB.torrent,
"GET","/torrent/info/", True)
menu_manager.register_toolbar_item("move",_("Move"), "move.png" ,TB.torrent_list,
"POST","/torrent/move/", True)
menu_manager.register_toolbar_item("reannounce",_("Reannounce"), "view-refresh.png" ,TB.torrent_list,
"POST","'/torrent/reannounce/", False)
menu_manager.register_toolbar_item("recheck",_("Recheck"), "view-refresh.png" ,TB.torrent_list,
"POST","'/torrent/recheck/", False)
#routing:
urls = [
@ -142,7 +107,6 @@ urls = [
#/routing
#pages:
class login:
@deco.deluge_page_noauth
@ -495,15 +459,4 @@ class pixmaps:
#/pages
#for plugins:
page_classes = dict(globals())
def register_page(url, klass):
urls.append(url)
urls.append(klass.__name__)
page_classes[klass.__name__] = klass
def unregister_page(url):
raise NotImplemenetedError()
#page_classes[klass.__name__] = None
page_manager.register_pages(urls,globals())

View file

@ -31,29 +31,16 @@
# statement from all source files in the program, then also delete it here.
#
import deluge.component as component
import deluge.pluginmanagerbase
from deluge import component, pluginmanagerbase
from deluge.configmanager import ConfigManager
from deluge.log import LOG as log
import lib.webpy022 as web
import lib.newforms_plus as forms
from render import render
from utils import logcall
import page_decorators as deco
import pages
import config
from menu_manager import TB
import menu_manager
class PluginManager(deluge.pluginmanagerbase.PluginManagerBase,
class PluginManager(pluginmanagerbase.PluginManagerBase,
component.Component):
def __init__(self):
component.Component.__init__(self, "PluginManager")
self.config = ConfigManager("gtkui.conf")
deluge.pluginmanagerbase.PluginManagerBase.__init__(
component.Component.__init__(self, "WebPluginManager")
self.config = ConfigManager("webui.conf")
pluginmanagerbase.PluginManagerBase.__init__(
self, "webui.conf", "deluge.plugin.webui")
def start(self):
@ -73,22 +60,7 @@ class PluginManager(deluge.pluginmanagerbase.PluginManagerBase,
self.enable_plugins()
register_template_path = staticmethod(render.register_template_path)
unregister_template_path = staticmethod(render.unregister_template_path)
register_admin_page = staticmethod(menu_manager.register_admin_page)
unregister_admin_page = staticmethod(menu_manager.unregister_admin_page)
register_toolbar_item = staticmethod(menu_manager.register_toolbar_item)
unregister_toolbar_item = staticmethod(menu_manager.register_toolbar_item)
register_page = staticmethod(pages.register_page)
unregister_page = staticmethod(pages.unregister_page)
register_config_form = staticmethod(config.register_block)
unregister_config_form = staticmethod(config.unregister_block)
__plugin_manager = PluginManager()
__all__ = ['PluginManager','web','forms','render','logcall','deco','TB']

View file

@ -0,0 +1,58 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
#
# Copyright (C) Martijn Voncken 2008 <mvoncken@gmail.com>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2, or (at your option)
# any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, write to:
# The Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor
# Boston, MA 02110-1301, USA.
#
# In addition, as a special exception, the copyright holders give
# permission to link the code of portions of this program with the OpenSSL
# library.
# You must obey the GNU General Public License in all respects for all of
# the code used other than OpenSSL. If you modify file(s) with this
# exception, you may extend this exception to your version of the file(s),
# but you are not obligated to do so. If you do not wish to do so, delete
# this exception statement from your version. If you delete this exception
# statement from all source files in the program, then also delete it here.
#
from deluge import component
menu = component.get("MenuManager")
TB = menu.TOOLBAR_FLAGS
menu.register_admin_page("config", _("Config"), "/config/")
menu.register_admin_page("connect", _("Connect"), "/connect")
menu.register_admin_page("about", _("About"), "/about")
menu.register_admin_page("logout", _("Logout"), "/logout")
menu.register_detail_tab("details", _("Details"), "tab_meta")
menu.register_detail_tab("files", _("Files"), "tab_files")
menu.register_detail_tab("options", _("Options"), "tab_options")
menu.register_detail_tab("trackers", _("Trackers"), "tab_trackers")
menu.register_toolbar_item("add", _("Add"), "list-add.png" , TB.generic, "GET","/torrent/add/", True)
menu.register_toolbar_item("delete",_("Delete"), "list-remove.png" ,TB.torrent_list, "GET","/torrent/delete/" , True)
menu.register_toolbar_item("stop",_("Stop"), "pause.png" ,TB.torrent_list, "POST","/torrent/stop/", True)
menu.register_toolbar_item("start",_("Start"), "start.png" ,TB.torrent_list, "POST","/torrent/start/", True)
menu.register_toolbar_item("queue_up",_("Up"), "queue-up.png" ,TB.torrent_list, "POST","/torrent/queue/up/", True)
menu.register_toolbar_item("queue_down",_("Down"), "queue-down.png" ,TB.torrent_list, "POST","/torrent/queue/down/", True)
menu.register_toolbar_item("details",_("Details"), "details.png" ,TB.torrent, "GET","/torrent/info/", True)
menu.register_toolbar_item("move",_("Move"), "move.png" ,TB.torrent_list,"POST","/torrent/move/", True)
menu.register_toolbar_item("reannounce",_("Reannounce"), "view-refresh.png" ,TB.torrent_list, "POST","'/torrent/reannounce/", False)
menu.register_toolbar_item("recheck",_("Recheck"), "view-refresh.png" ,TB.torrent_list, "POST","'/torrent/recheck/", False)

View file

@ -54,6 +54,8 @@ class subclassed_render(object):
#load template-meta-data
cfg_template = ws.config.get('template')
template_path = os.path.join(ws.webui_path, 'templates/%s/' % cfg_template)
if not os.path.exists(template_path):
template_path = os.path.join(ws.webui_path, 'templates/deluge/')
self.meta = Storage(eval(open(os.path.join(template_path,'meta.cfg')).read()))
#load renerders
@ -186,5 +188,4 @@ template.Template.globals.update({
})
#/template-defs
__all__ = ['render']

View file

@ -84,7 +84,7 @@ $for torrent in torrent_list:
</td>
<td>$ftime(torrent.eta)</td>
<td>$("%.3f" % torrent.distributed_copies)</td>
<td>$("%.3f" % torrent.ratio)</td\>
<td>$("%.3f" % torrent.ratio)</td>
</tr>
</tbody>
</table>

View file

@ -19,7 +19,7 @@ $for group in groups:
<!--form block-->
<div class="panel" id="config_panel">
<h2>$form.group / $form.title</h2>
<div id="info">$form.info</div>
<div class="info">$form.info</div>
<form method="POST">
<table id="config_table">
$:form.as_table()

View file

@ -1,10 +1,11 @@
$def with (connect_list, connected)
$:render.header(_("Connect to Daemon"), 'connect')
$:render.header(_("Connect to Daemon"), 'Connect')
$:render.admin_toolbar('connect')
<div class="panel" align="left">
<h2>$_("Connect")</h2>
$if connected:
<table><tr>
<td>

View file

@ -1,6 +1,8 @@
$def with (error)
$:render.header(_('Login'))
<div class="panel">
<h2>$_("Deluge Login")</h2>
$if error > 0:
<div class="error">$_("Password is invalid,try again")</div>

View file

@ -1,6 +1,7 @@
$def with (add_form, options_form, error)
$:render.header(_("Add Torrent"))
<div class="panel">
<h2>$_("Add Torrent")</h2>
<form method="POST" action="/torrent/add" ENCTYPE="multipart/form-data">
<input type="hidden" name="redir" value="$get('redir')">

View file

@ -1,4 +1,6 @@
$def with (torrent_list, organize_filters)
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html>
<head>
<title>Deluge:$_('Torrent list')</title>
@ -34,6 +36,7 @@ $if organize_filters:
$:render.part_organize(organize_filters)
<table id="torrent_list_block" width="70%">
<tr><td>
<div id="toolbar">
@ -44,12 +47,11 @@ $if organize_filters:
</td></tr><tr><td height=100%>
<!-- torrent info here?-->
</td></tr>
</table>
<div class="panel" id="info_panel_div" style="width:740px;">
<iframe
style="border-style:hidden;width:740px;height:200px;"
@ -57,10 +59,13 @@ $if organize_filters:
</iframe>
</div>
<br />
<script language='javascript'>
/*on_click_action = open_details;*/
on_click_action = on_click_row_js;

View file

@ -1,34 +0,0 @@
$def with (error)
<html>
<head>
<title>Deluge:$_('Login')</title>
<link rel="icon" href="/static/images/deluge_icon.gif" type="image/gif" />
<link rel="shortcut icon" href="/static/images/deluge_icon.gif" type="image/gif" />
<link rel="stylesheet" type="text/css" href="/template_style.css" />
<script language="javascript" src="/static/deluge.js"></script>
</head>
<body>
<div id="page">
<div class="panel">
$if error > 0:
<div class="error">$_("Password is invalid,try again")</div>
<form method="POST" id="loginform" action='/login'>
<input type="hidden" name="redir" value="$get('redir')">
<div id="loginpanel">
<div class="form_row">
<span class="form_label">$_('Password')</span>
<input type="password" name="pwd" id="pwd" class="form_input">
</div>
<div class="form_row">
<span class="form_label"></span>
<input type="submit" name="submit"
id="submit" value="Submit" class="form_input">
</div>
</div>
</form>
</div>
$:render.footer()

View file

@ -39,11 +39,13 @@ $for tracker, num in filters.tracker:
<div class="title">$_('Keyword')</div>
$if get('keyword'):
<div style="background-color:#F00">
<input type="text" name="keyword" value="$get('keyword')" style="width:100px"
title="$_('Filter on a keyword')"
/>
$if get('keyword'):
selected
</div>
</div>
</form>

View file

@ -32,6 +32,22 @@ img{
}
/*controls:*/
div.error {
background-color:#FFFFFF;
color:#AA0000;
font-weight:bold;
-moz-border-radius:10px;
width:200px;
margin-bottom:20px;
padding:10px;
}
div.info {
background-color:#FFFFFF;
color: #0000AA;
font-weight:bold;
}
a.tab_button_active {
color: #0000AA;
text-decoration:none;
@ -47,7 +63,7 @@ div.panel {
border-style:solid;
border-width:2px;
border-color:#C3D9FF;
background-color:#E0ECFF;
background-color:#FAFAFA; /*offf-topic-hint:allo allo*/
-moz-border-radius:5px;
width:700px;
margin-left:20px;
@ -55,6 +71,17 @@ div.panel {
}
h2 {
background-color:#E0ECFF;
margin:0;
}
h3 {
background-color:#E0ECFF;
margin:0;
}
/*page from top to bottom:*/
/*top part :*/
@ -216,9 +243,6 @@ div.progress_bar{
text-align:right;
}
#config_panel table {
background-color:none;
}

View file

@ -141,6 +141,11 @@ class Ws:
def init_process(self):
self.config = pickle.load(open(self.config_file))
if self.config.get('enabled_plugins') == None:
self.config['enabled_plugins'] = []
self.save_config()
def init_06(self, uri = 'http://localhost:58846'):
proxy.set_core_uri(uri)
@ -153,8 +158,11 @@ class Ws:
pickle.dump(CONFIG_DEFAULTS,f)
f.close()
self.init_process()
self.env = '0.6'
from render import render
render.apply_cfg()
#utils for config:
def get_templates(self):