From fe6f045be1e28e63798e53f11d8945bcd1663dea Mon Sep 17 00:00:00 2001 From: Damien Churchill Date: Fri, 6 Mar 2009 15:01:05 +0000 Subject: [PATCH] remove old webui --- deluge/ui/webui/LICENSE | 621 ---------- deluge/ui/webui/TODO | 30 - deluge/ui/webui/__init__.py | 21 - deluge/ui/webui/apache.py | 57 - deluge/ui/webui/components.py | 212 ---- deluge/ui/webui/config_forms.py | 103 -- deluge/ui/webui/config_tabs_deluge.py | 215 ---- deluge/ui/webui/config_tabs_webui.py | 112 -- deluge/ui/webui/debugerror.py | 411 ------- deluge/ui/webui/deluge_webserver.py | 135 --- deluge/ui/webui/json_api.py | 257 ----- deluge/ui/webui/lib/__init__.py | 0 deluge/ui/webui/lib/egg_handler.py | 61 - deluge/ui/webui/lib/egg_render.py | 33 - deluge/ui/webui/lib/json.py | 815 ------------- deluge/ui/webui/lib/newforms_plus.py | 255 ---- deluge/ui/webui/lib/newforms_portable/LICENSE | 27 - .../webui/lib/newforms_portable/__init__.py | 18 - .../ui/webui/lib/newforms_portable/about.txt | 3 - .../lib/newforms_portable/django/__init__.py | 0 .../newforms_portable/django/core/__init__.py | 0 .../django/core/exceptions.py | 29 - .../django/utils/__init__.py | 0 .../django/utils/datastructures.py | 345 ------ .../django/utils/encoding.py | 102 -- .../django/utils/functional.py | 241 ---- .../newforms_portable/django/utils/html.py | 163 --- .../newforms_portable/django/utils/http.py | 67 -- .../django/utils/safestring.py | 119 -- .../django/utils/translation.py | 9 - .../ui/webui/lib/newforms_portable/fields.py | 784 ------------- .../ui/webui/lib/newforms_portable/forms.py | 350 ------ .../ui/webui/lib/newforms_portable/models.py | 398 ------- deluge/ui/webui/lib/newforms_portable/util.py | 70 -- .../ui/webui/lib/newforms_portable/widgets.py | 471 -------- deluge/ui/webui/lib/readme.txt | 14 - deluge/ui/webui/lib/static_handler.py | 137 --- deluge/ui/webui/lib/web.py | 2 - .../Dependency-not-really part of webui.txt | 1 - deluge/ui/webui/lib/webpy022/LICENSE | 3 - deluge/ui/webui/lib/webpy022/__init__.py | 62 - deluge/ui/webui/lib/webpy022/changes.txt | 5 - deluge/ui/webui/lib/webpy022/cheetah.py | 98 -- deluge/ui/webui/lib/webpy022/db.py | 703 ------------ deluge/ui/webui/lib/webpy022/debugerror.py | 316 ----- deluge/ui/webui/lib/webpy022/form.py | 215 ---- deluge/ui/webui/lib/webpy022/http.py | 271 ----- deluge/ui/webui/lib/webpy022/httpserver.py | 227 ---- deluge/ui/webui/lib/webpy022/net.py | 155 --- deluge/ui/webui/lib/webpy022/request.py | 153 --- deluge/ui/webui/lib/webpy022/template.py | 878 -------------- deluge/ui/webui/lib/webpy022/utils.py | 787 ------------- deluge/ui/webui/lib/webpy022/webapi.py | 375 ------ deluge/ui/webui/lib/webpy022/wsgi.py | 54 - .../webui/lib/webpy022/wsgiserver/LICENSE.txt | 25 - .../webui/lib/webpy022/wsgiserver/__init__.py | 1022 ----------------- deluge/ui/webui/page_decorators.py | 159 --- deluge/ui/webui/pages.py | 481 -------- deluge/ui/webui/register_menu.py | 54 - deluge/ui/webui/render.py | 217 ---- deluge/ui/webui/revno | 1 - deluge/ui/webui/run_devserver | 25 - .../ui/webui/scripts/build_webui_tarball.sh | 7 - deluge/ui/webui/scripts/copy_icons.py | 96 -- deluge/ui/webui/scripts/curl-example | 1 - .../ui/webui/scripts/extract_ajax_strings.py | 53 - .../webui/scripts/extract_template_strings.py | 51 - deluge/ui/webui/scripts/template_strings.py | 123 -- deluge/ui/webui/static/deluge-moo.js | 75 -- deluge/ui/webui/static/deluge.js | 236 ---- deluge/ui/webui/static/images/16/LICENSE | 14 - .../ui/webui/static/images/16/connections.png | Bin 868 -> 0 bytes deluge/ui/webui/static/images/16/details.png | Bin 692 -> 0 bytes deluge/ui/webui/static/images/16/down.png | Bin 525 -> 0 bytes .../webui/static/images/16/drive-harddisk.png | Bin 632 -> 0 bytes .../ui/webui/static/images/16/edit-clear.png | Bin 625 -> 0 bytes .../ui/webui/static/images/16/edit-redo.png | Bin 813 -> 0 bytes .../ui/webui/static/images/16/go-bottom.png | Bin 788 -> 0 bytes deluge/ui/webui/static/images/16/go-top.png | Bin 792 -> 0 bytes deluge/ui/webui/static/images/16/gtk-yes.png | Bin 562 -> 0 bytes deluge/ui/webui/static/images/16/label.png | Bin 746 -> 0 bytes deluge/ui/webui/static/images/16/list-add.png | Bin 761 -> 0 bytes .../ui/webui/static/images/16/list-remove.png | Bin 820 -> 0 bytes deluge/ui/webui/static/images/16/move.png | Bin 860 -> 0 bytes deluge/ui/webui/static/images/16/pause.png | Bin 484 -> 0 bytes .../static/images/16/preferences-system.png | Bin 874 -> 0 bytes .../webui/static/images/16/process-stop.png | Bin 722 -> 0 bytes .../ui/webui/static/images/16/queue-down.png | Bin 525 -> 0 bytes deluge/ui/webui/static/images/16/queue-up.png | Bin 539 -> 0 bytes deluge/ui/webui/static/images/16/readme.txt | 5 - .../ui/webui/static/images/16/select-all.png | Bin 541 -> 0 bytes deluge/ui/webui/static/images/16/start.png | Bin 501 -> 0 bytes deluge/ui/webui/static/images/16/stop.png | Bin 499 -> 0 bytes .../webui/static/images/16/system-log-out.png | Bin 775 -> 0 bytes deluge/ui/webui/static/images/16/up.png | Bin 525 -> 0 bytes .../ui/webui/static/images/16/user-trash.png | Bin 844 -> 0 bytes .../webui/static/images/16/view-refresh.png | Bin 931 -> 0 bytes deluge/ui/webui/static/images/debugerror.png | Bin 9489 -> 0 bytes deluge/ui/webui/static/images/deluge-icon.png | Bin 722 -> 0 bytes deluge/ui/webui/static/images/deluge16.png | Bin 722 -> 0 bytes deluge/ui/webui/static/images/deluge32.png | Bin 1888 -> 0 bytes deluge/ui/webui/static/images/deluge_icon.gif | Bin 588 -> 0 bytes deluge/ui/webui/static/images/simple_bg.jpg | Bin 1150 -> 0 bytes .../webui/static/images/simple_bg_flipped.jpg | Bin 587 -> 0 bytes deluge/ui/webui/static/images/simple_line.jpg | Bin 631 -> 0 bytes deluge/ui/webui/static/images/simple_logo.jpg | Bin 1785 -> 0 bytes deluge/ui/webui/static/mootools-1.2-core.js | 349 ------ deluge/ui/webui/static/mootools-1.2-more.js | 44 - .../ui/webui/static/mootools-1.2.1-core-yc.js | 349 ------ deluge/ui/webui/static/mooui.js | 1 - deluge/ui/webui/static/refresh.js | 71 -- deluge/ui/webui/static/simple_site_style.css | 127 -- deluge/ui/webui/templates/ajax/TODO | 18 - deluge/ui/webui/templates/ajax/gettext.js | 70 -- deluge/ui/webui/templates/ajax/index.html | 67 -- deluge/ui/webui/templates/ajax/meta.cfg | 9 - .../ajax/render/html/add_torrent_files.html | 1 - .../ajax/render/html/add_torrent_options.html | 42 - .../ajax/render/html/create_torrent_info.html | 2 - .../render/html/create_torrent_options.html | 21 - .../render/html/create_torrent_trackers.html | 17 - .../render/html/create_torrent_webseeds.html | 3 - .../render/html/preferences_bandwidth.html | 51 - .../ajax/render/html/preferences_daemon.html | 14 - .../render/html/preferences_download.html | 45 - .../ajax/render/html/preferences_network.html | 94 -- .../ajax/render/html/preferences_queue.html | 21 - .../ajax/render/html/preferences_webui.html | 31 - .../ajax/render/html/tab_details.html | 10 - .../templates/ajax/render/html/tab_files.html | 13 - .../ajax/render/html/tab_options.html | 26 - .../templates/ajax/render/html/tab_peers.html | 14 - .../ajax/render/html/tab_statistics.html | 25 - .../ajax/render/html/window_add_torrent.html | 13 - .../render/html/window_add_torrent_file.html | 18 - .../render/html/window_create_torrent.html | 14 - .../ajax/render/html/window_preferences.html | 13 - .../webui/templates/ajax/static/css/Roar.css | 55 - .../webui/templates/ajax/static/css/mooui.css | 160 --- .../ajax/static/icons/16/gtk-edit.png | Bin 692 -> 0 bytes .../ajax/static/icons/16/gtk-yes.png | Bin 562 -> 0 bytes .../ajax/static/icons/16/network-idle.png | Bin 868 -> 0 bytes .../ajax/static/icons/16/view-refresh.png | Bin 931 -> 0 bytes .../static/icons/16/view-sort-ascending.png | Bin 632 -> 0 bytes .../static/icons/16/view-sort-descending.png | Bin 642 -> 0 bytes .../templates/ajax/static/icons/32/add.png | Bin 1573 -> 0 bytes .../ajax/static/icons/32/connections.png | Bin 1979 -> 0 bytes .../templates/ajax/static/icons/32/deluge.png | Bin 1888 -> 0 bytes .../templates/ajax/static/icons/32/down.png | Bin 1006 -> 0 bytes .../templates/ajax/static/icons/32/new.png | Bin 1410 -> 0 bytes .../ajax/static/icons/32/options.png | Bin 2171 -> 0 bytes .../templates/ajax/static/icons/32/pause.png | Bin 1145 -> 0 bytes .../templates/ajax/static/icons/32/remove.png | Bin 1958 -> 0 bytes .../templates/ajax/static/icons/32/resume.png | Bin 1177 -> 0 bytes .../templates/ajax/static/icons/32/up.png | Bin 960 -> 0 bytes .../templates/ajax/static/images/spacer.gif | Bin 63 -> 0 bytes .../ui/webui/templates/ajax/static/js/Roar.js | 166 --- .../ui/webui/templates/ajax/static/js/Rpc.js | 142 --- .../templates/ajax/static/js/deluge-add.js | 504 -------- .../templates/ajax/static/js/deluge-bars.js | 330 ------ .../ajax/static/js/deluge-details.js | 585 ---------- .../templates/ajax/static/js/deluge-menus.js | 435 ------- .../templates/ajax/static/js/deluge-mime.js | 162 --- .../ajax/static/js/deluge-preferences.js | 316 ----- .../ajax/static/js/deluge-torrent-grid.js | 136 --- .../templates/ajax/static/js/deluge-ui.js | 435 ------- .../webui/templates/ajax/static/js/deluge.js | 58 - .../templates/ajax/static/js/gears_init.js | 87 -- .../ajax/static/themes/classic/down.png | Bin 176 -> 0 bytes .../ajax/static/themes/classic/down_hover.png | Bin 176 -> 0 bytes .../ajax/static/themes/classic/iframe.css | 85 -- .../ajax/static/themes/classic/menu_bg.jpg | Bin 425 -> 0 bytes .../themes/classic/mime_icons/image.png | Bin 693 -> 0 bytes .../themes/classic/mime_icons/unknown.png | Bin 655 -> 0 bytes .../themes/classic/simple_line_flipped.png | Bin 169 -> 0 bytes .../themes/classic/split_horizontal.png | Bin 144 -> 0 bytes .../static/themes/classic/split_vertical.png | Bin 142 -> 0 bytes .../ajax/static/themes/classic/style.css | 475 -------- .../ajax/static/themes/classic/up.png | Bin 171 -> 0 bytes .../ajax/static/themes/classic/up_hover.png | Bin 171 -> 0 bytes .../static/themes/classic/window_close.png | Bin 614 -> 0 bytes .../static/themes/white/mime_icons/image.png | Bin 693 -> 0 bytes .../themes/white/mime_icons/unknown.png | Bin 655 -> 0 bytes .../ajax/static/themes/white/style.css | 440 ------- .../ajax/static/themes/white/window_close.png | Bin 614 -> 0 bytes .../webui/templates/ajax/template_style.css | 213 ---- deluge/ui/webui/templates/classic/about.html | 47 - .../templates/classic/admin_toolbar.html | 1 - deluge/ui/webui/templates/classic/authors.txt | 5 - deluge/ui/webui/templates/classic/config.html | 46 - .../ui/webui/templates/classic/connect.html | 58 - deluge/ui/webui/templates/classic/error.html | 6 - deluge/ui/webui/templates/classic/footer.html | 6 - deluge/ui/webui/templates/classic/gettext.js | 87 -- deluge/ui/webui/templates/classic/header.html | 59 - deluge/ui/webui/templates/classic/index.html | 69 -- deluge/ui/webui/templates/classic/login.html | 32 - deluge/ui/webui/templates/classic/meta.cfg | 10 - .../templates/classic/part_auto_refresh.html | 24 - .../webui/templates/classic/part_button.html | 26 - .../templates/classic/part_label_filters.html | 60 - .../templates/classic/part_organize.html | 2 - .../webui/templates/classic/part_stats.html | 25 - .../webui/templates/classic/refresh_form.html | 11 - .../templates/classic/sort_column_head.html | 12 - .../webui/templates/classic/tab_details.html | 44 - .../ui/webui/templates/classic/tab_files.html | 35 - .../webui/templates/classic/tab_options.html | 30 - .../ui/webui/templates/classic/tab_peers.html | 38 - .../templates/classic/tab_statistics.html | 102 -- .../webui/templates/classic/tab_trackers.html | 24 - .../webui/templates/classic/torrent_add.html | 56 - .../templates/classic/torrent_delete.html | 31 - .../templates/classic/torrent_files.html | 14 - .../webui/templates/classic/torrent_info.html | 17 - .../webui/templates/classic/torrent_move.html | 22 - .../ui/webui/templates/hacking-templates.txt | 39 - .../webui/templates/white/admin_toolbar.html | 3 - .../webui/templates/white/basic_header.html | 21 - deluge/ui/webui/templates/white/footer.html | 3 - deluge/ui/webui/templates/white/header.html | 37 - deluge/ui/webui/templates/white/index.html | 62 - deluge/ui/webui/templates/white/meta.cfg | 11 - .../templates/white/part_label_filters.html | 68 -- .../webui/templates/white/part_organize.html | 2 - .../templates/white/part_tab_button.html | 8 - .../webui/templates/white/part_tb_button.html | 26 - .../webui/templates/white/part_toolbar.html | 13 - .../templates/white/part_torrent_list.html | 104 -- .../webui/templates/white/template_style.css | 342 ------ .../templates/white/torrent_info_inner.html | 22 - .../webui/templates/white/torrent_label.html | 29 - deluge/ui/webui/tests/test_all.py | 413 ------- deluge/ui/webui/torrent_add.py | 135 --- deluge/ui/webui/torrent_move.py | 71 -- deluge/ui/webui/torrent_options.py | 90 -- deluge/ui/webui/utils.py | 289 ----- deluge/ui/webui/version | 1 - deluge/ui/webui/web.py | 2 - deluge/ui/webui/webserver_common.py | 63 - deluge/ui/webui/webui.py | 34 - 241 files changed, 22899 deletions(-) delete mode 100644 deluge/ui/webui/LICENSE delete mode 100644 deluge/ui/webui/TODO delete mode 100644 deluge/ui/webui/__init__.py delete mode 100644 deluge/ui/webui/apache.py delete mode 100644 deluge/ui/webui/components.py delete mode 100644 deluge/ui/webui/config_forms.py delete mode 100644 deluge/ui/webui/config_tabs_deluge.py delete mode 100644 deluge/ui/webui/config_tabs_webui.py delete mode 100644 deluge/ui/webui/debugerror.py delete mode 100644 deluge/ui/webui/deluge_webserver.py delete mode 100644 deluge/ui/webui/json_api.py delete mode 100644 deluge/ui/webui/lib/__init__.py delete mode 100644 deluge/ui/webui/lib/egg_handler.py delete mode 100644 deluge/ui/webui/lib/egg_render.py delete mode 100644 deluge/ui/webui/lib/json.py delete mode 100644 deluge/ui/webui/lib/newforms_plus.py delete mode 100644 deluge/ui/webui/lib/newforms_portable/LICENSE delete mode 100644 deluge/ui/webui/lib/newforms_portable/__init__.py delete mode 100644 deluge/ui/webui/lib/newforms_portable/about.txt delete mode 100644 deluge/ui/webui/lib/newforms_portable/django/__init__.py delete mode 100644 deluge/ui/webui/lib/newforms_portable/django/core/__init__.py delete mode 100644 deluge/ui/webui/lib/newforms_portable/django/core/exceptions.py delete mode 100644 deluge/ui/webui/lib/newforms_portable/django/utils/__init__.py delete mode 100644 deluge/ui/webui/lib/newforms_portable/django/utils/datastructures.py delete mode 100644 deluge/ui/webui/lib/newforms_portable/django/utils/encoding.py delete mode 100644 deluge/ui/webui/lib/newforms_portable/django/utils/functional.py delete mode 100644 deluge/ui/webui/lib/newforms_portable/django/utils/html.py delete mode 100644 deluge/ui/webui/lib/newforms_portable/django/utils/http.py delete mode 100644 deluge/ui/webui/lib/newforms_portable/django/utils/safestring.py delete mode 100644 deluge/ui/webui/lib/newforms_portable/django/utils/translation.py delete mode 100644 deluge/ui/webui/lib/newforms_portable/fields.py delete mode 100644 deluge/ui/webui/lib/newforms_portable/forms.py delete mode 100644 deluge/ui/webui/lib/newforms_portable/models.py delete mode 100644 deluge/ui/webui/lib/newforms_portable/util.py delete mode 100644 deluge/ui/webui/lib/newforms_portable/widgets.py delete mode 100644 deluge/ui/webui/lib/readme.txt delete mode 100644 deluge/ui/webui/lib/static_handler.py delete mode 100644 deluge/ui/webui/lib/web.py delete mode 100644 deluge/ui/webui/lib/webpy022/Dependency-not-really part of webui.txt delete mode 100644 deluge/ui/webui/lib/webpy022/LICENSE delete mode 100644 deluge/ui/webui/lib/webpy022/__init__.py delete mode 100644 deluge/ui/webui/lib/webpy022/changes.txt delete mode 100644 deluge/ui/webui/lib/webpy022/cheetah.py delete mode 100644 deluge/ui/webui/lib/webpy022/db.py delete mode 100644 deluge/ui/webui/lib/webpy022/debugerror.py delete mode 100644 deluge/ui/webui/lib/webpy022/form.py delete mode 100644 deluge/ui/webui/lib/webpy022/http.py delete mode 100644 deluge/ui/webui/lib/webpy022/httpserver.py delete mode 100644 deluge/ui/webui/lib/webpy022/net.py delete mode 100644 deluge/ui/webui/lib/webpy022/request.py delete mode 100644 deluge/ui/webui/lib/webpy022/template.py delete mode 100644 deluge/ui/webui/lib/webpy022/utils.py delete mode 100644 deluge/ui/webui/lib/webpy022/webapi.py delete mode 100644 deluge/ui/webui/lib/webpy022/wsgi.py delete mode 100644 deluge/ui/webui/lib/webpy022/wsgiserver/LICENSE.txt delete mode 100644 deluge/ui/webui/lib/webpy022/wsgiserver/__init__.py delete mode 100644 deluge/ui/webui/page_decorators.py delete mode 100644 deluge/ui/webui/pages.py delete mode 100644 deluge/ui/webui/register_menu.py delete mode 100644 deluge/ui/webui/render.py delete mode 100644 deluge/ui/webui/revno delete mode 100755 deluge/ui/webui/run_devserver delete mode 100755 deluge/ui/webui/scripts/build_webui_tarball.sh delete mode 100644 deluge/ui/webui/scripts/copy_icons.py delete mode 100644 deluge/ui/webui/scripts/curl-example delete mode 100644 deluge/ui/webui/scripts/extract_ajax_strings.py delete mode 100644 deluge/ui/webui/scripts/extract_template_strings.py delete mode 100644 deluge/ui/webui/scripts/template_strings.py delete mode 100644 deluge/ui/webui/static/deluge-moo.js delete mode 100644 deluge/ui/webui/static/deluge.js delete mode 100644 deluge/ui/webui/static/images/16/LICENSE delete mode 100644 deluge/ui/webui/static/images/16/connections.png delete mode 100644 deluge/ui/webui/static/images/16/details.png delete mode 100644 deluge/ui/webui/static/images/16/down.png delete mode 100644 deluge/ui/webui/static/images/16/drive-harddisk.png delete mode 100644 deluge/ui/webui/static/images/16/edit-clear.png delete mode 100644 deluge/ui/webui/static/images/16/edit-redo.png delete mode 100644 deluge/ui/webui/static/images/16/go-bottom.png delete mode 100644 deluge/ui/webui/static/images/16/go-top.png delete mode 100644 deluge/ui/webui/static/images/16/gtk-yes.png delete mode 100644 deluge/ui/webui/static/images/16/label.png delete mode 100644 deluge/ui/webui/static/images/16/list-add.png delete mode 100644 deluge/ui/webui/static/images/16/list-remove.png delete mode 100644 deluge/ui/webui/static/images/16/move.png delete mode 100644 deluge/ui/webui/static/images/16/pause.png delete mode 100644 deluge/ui/webui/static/images/16/preferences-system.png delete mode 100644 deluge/ui/webui/static/images/16/process-stop.png delete mode 100644 deluge/ui/webui/static/images/16/queue-down.png delete mode 100644 deluge/ui/webui/static/images/16/queue-up.png delete mode 100644 deluge/ui/webui/static/images/16/readme.txt delete mode 100644 deluge/ui/webui/static/images/16/select-all.png delete mode 100644 deluge/ui/webui/static/images/16/start.png delete mode 100644 deluge/ui/webui/static/images/16/stop.png delete mode 100644 deluge/ui/webui/static/images/16/system-log-out.png delete mode 100644 deluge/ui/webui/static/images/16/up.png delete mode 100644 deluge/ui/webui/static/images/16/user-trash.png delete mode 100644 deluge/ui/webui/static/images/16/view-refresh.png delete mode 100644 deluge/ui/webui/static/images/debugerror.png delete mode 100644 deluge/ui/webui/static/images/deluge-icon.png delete mode 100644 deluge/ui/webui/static/images/deluge16.png delete mode 100644 deluge/ui/webui/static/images/deluge32.png delete mode 100644 deluge/ui/webui/static/images/deluge_icon.gif delete mode 100644 deluge/ui/webui/static/images/simple_bg.jpg delete mode 100644 deluge/ui/webui/static/images/simple_bg_flipped.jpg delete mode 100644 deluge/ui/webui/static/images/simple_line.jpg delete mode 100644 deluge/ui/webui/static/images/simple_logo.jpg delete mode 100644 deluge/ui/webui/static/mootools-1.2-core.js delete mode 100644 deluge/ui/webui/static/mootools-1.2-more.js delete mode 100644 deluge/ui/webui/static/mootools-1.2.1-core-yc.js delete mode 100644 deluge/ui/webui/static/mooui.js delete mode 100644 deluge/ui/webui/static/refresh.js delete mode 100644 deluge/ui/webui/static/simple_site_style.css delete mode 100644 deluge/ui/webui/templates/ajax/TODO delete mode 100644 deluge/ui/webui/templates/ajax/gettext.js delete mode 100644 deluge/ui/webui/templates/ajax/index.html delete mode 100644 deluge/ui/webui/templates/ajax/meta.cfg delete mode 100644 deluge/ui/webui/templates/ajax/render/html/add_torrent_files.html delete mode 100644 deluge/ui/webui/templates/ajax/render/html/add_torrent_options.html delete mode 100644 deluge/ui/webui/templates/ajax/render/html/create_torrent_info.html delete mode 100644 deluge/ui/webui/templates/ajax/render/html/create_torrent_options.html delete mode 100644 deluge/ui/webui/templates/ajax/render/html/create_torrent_trackers.html delete mode 100644 deluge/ui/webui/templates/ajax/render/html/create_torrent_webseeds.html delete mode 100644 deluge/ui/webui/templates/ajax/render/html/preferences_bandwidth.html delete mode 100644 deluge/ui/webui/templates/ajax/render/html/preferences_daemon.html delete mode 100644 deluge/ui/webui/templates/ajax/render/html/preferences_download.html delete mode 100644 deluge/ui/webui/templates/ajax/render/html/preferences_network.html delete mode 100644 deluge/ui/webui/templates/ajax/render/html/preferences_queue.html delete mode 100644 deluge/ui/webui/templates/ajax/render/html/preferences_webui.html delete mode 100644 deluge/ui/webui/templates/ajax/render/html/tab_details.html delete mode 100644 deluge/ui/webui/templates/ajax/render/html/tab_files.html delete mode 100644 deluge/ui/webui/templates/ajax/render/html/tab_options.html delete mode 100644 deluge/ui/webui/templates/ajax/render/html/tab_peers.html delete mode 100644 deluge/ui/webui/templates/ajax/render/html/tab_statistics.html delete mode 100644 deluge/ui/webui/templates/ajax/render/html/window_add_torrent.html delete mode 100644 deluge/ui/webui/templates/ajax/render/html/window_add_torrent_file.html delete mode 100644 deluge/ui/webui/templates/ajax/render/html/window_create_torrent.html delete mode 100644 deluge/ui/webui/templates/ajax/render/html/window_preferences.html delete mode 100644 deluge/ui/webui/templates/ajax/static/css/Roar.css delete mode 100644 deluge/ui/webui/templates/ajax/static/css/mooui.css delete mode 100644 deluge/ui/webui/templates/ajax/static/icons/16/gtk-edit.png delete mode 100644 deluge/ui/webui/templates/ajax/static/icons/16/gtk-yes.png delete mode 100644 deluge/ui/webui/templates/ajax/static/icons/16/network-idle.png delete mode 100644 deluge/ui/webui/templates/ajax/static/icons/16/view-refresh.png delete mode 100644 deluge/ui/webui/templates/ajax/static/icons/16/view-sort-ascending.png delete mode 100644 deluge/ui/webui/templates/ajax/static/icons/16/view-sort-descending.png delete mode 100644 deluge/ui/webui/templates/ajax/static/icons/32/add.png delete mode 100644 deluge/ui/webui/templates/ajax/static/icons/32/connections.png delete mode 100644 deluge/ui/webui/templates/ajax/static/icons/32/deluge.png delete mode 100644 deluge/ui/webui/templates/ajax/static/icons/32/down.png delete mode 100644 deluge/ui/webui/templates/ajax/static/icons/32/new.png delete mode 100644 deluge/ui/webui/templates/ajax/static/icons/32/options.png delete mode 100644 deluge/ui/webui/templates/ajax/static/icons/32/pause.png delete mode 100644 deluge/ui/webui/templates/ajax/static/icons/32/remove.png delete mode 100644 deluge/ui/webui/templates/ajax/static/icons/32/resume.png delete mode 100644 deluge/ui/webui/templates/ajax/static/icons/32/up.png delete mode 100644 deluge/ui/webui/templates/ajax/static/images/spacer.gif delete mode 100644 deluge/ui/webui/templates/ajax/static/js/Roar.js delete mode 100644 deluge/ui/webui/templates/ajax/static/js/Rpc.js delete mode 100644 deluge/ui/webui/templates/ajax/static/js/deluge-add.js delete mode 100644 deluge/ui/webui/templates/ajax/static/js/deluge-bars.js delete mode 100644 deluge/ui/webui/templates/ajax/static/js/deluge-details.js delete mode 100644 deluge/ui/webui/templates/ajax/static/js/deluge-menus.js delete mode 100644 deluge/ui/webui/templates/ajax/static/js/deluge-mime.js delete mode 100644 deluge/ui/webui/templates/ajax/static/js/deluge-preferences.js delete mode 100644 deluge/ui/webui/templates/ajax/static/js/deluge-torrent-grid.js delete mode 100644 deluge/ui/webui/templates/ajax/static/js/deluge-ui.js delete mode 100644 deluge/ui/webui/templates/ajax/static/js/deluge.js delete mode 100644 deluge/ui/webui/templates/ajax/static/js/gears_init.js delete mode 100644 deluge/ui/webui/templates/ajax/static/themes/classic/down.png delete mode 100644 deluge/ui/webui/templates/ajax/static/themes/classic/down_hover.png delete mode 100644 deluge/ui/webui/templates/ajax/static/themes/classic/iframe.css delete mode 100644 deluge/ui/webui/templates/ajax/static/themes/classic/menu_bg.jpg delete mode 100644 deluge/ui/webui/templates/ajax/static/themes/classic/mime_icons/image.png delete mode 100644 deluge/ui/webui/templates/ajax/static/themes/classic/mime_icons/unknown.png delete mode 100644 deluge/ui/webui/templates/ajax/static/themes/classic/simple_line_flipped.png delete mode 100644 deluge/ui/webui/templates/ajax/static/themes/classic/split_horizontal.png delete mode 100644 deluge/ui/webui/templates/ajax/static/themes/classic/split_vertical.png delete mode 100644 deluge/ui/webui/templates/ajax/static/themes/classic/style.css delete mode 100644 deluge/ui/webui/templates/ajax/static/themes/classic/up.png delete mode 100644 deluge/ui/webui/templates/ajax/static/themes/classic/up_hover.png delete mode 100644 deluge/ui/webui/templates/ajax/static/themes/classic/window_close.png delete mode 100644 deluge/ui/webui/templates/ajax/static/themes/white/mime_icons/image.png delete mode 100644 deluge/ui/webui/templates/ajax/static/themes/white/mime_icons/unknown.png delete mode 100644 deluge/ui/webui/templates/ajax/static/themes/white/style.css delete mode 100644 deluge/ui/webui/templates/ajax/static/themes/white/window_close.png delete mode 100644 deluge/ui/webui/templates/ajax/template_style.css delete mode 100644 deluge/ui/webui/templates/classic/about.html delete mode 100644 deluge/ui/webui/templates/classic/admin_toolbar.html delete mode 100644 deluge/ui/webui/templates/classic/authors.txt delete mode 100644 deluge/ui/webui/templates/classic/config.html delete mode 100644 deluge/ui/webui/templates/classic/connect.html delete mode 100644 deluge/ui/webui/templates/classic/error.html delete mode 100644 deluge/ui/webui/templates/classic/footer.html delete mode 100644 deluge/ui/webui/templates/classic/gettext.js delete mode 100644 deluge/ui/webui/templates/classic/header.html delete mode 100644 deluge/ui/webui/templates/classic/index.html delete mode 100644 deluge/ui/webui/templates/classic/login.html delete mode 100644 deluge/ui/webui/templates/classic/meta.cfg delete mode 100644 deluge/ui/webui/templates/classic/part_auto_refresh.html delete mode 100644 deluge/ui/webui/templates/classic/part_button.html delete mode 100644 deluge/ui/webui/templates/classic/part_label_filters.html delete mode 100644 deluge/ui/webui/templates/classic/part_organize.html delete mode 100644 deluge/ui/webui/templates/classic/part_stats.html delete mode 100644 deluge/ui/webui/templates/classic/refresh_form.html delete mode 100644 deluge/ui/webui/templates/classic/sort_column_head.html delete mode 100644 deluge/ui/webui/templates/classic/tab_details.html delete mode 100644 deluge/ui/webui/templates/classic/tab_files.html delete mode 100644 deluge/ui/webui/templates/classic/tab_options.html delete mode 100644 deluge/ui/webui/templates/classic/tab_peers.html delete mode 100644 deluge/ui/webui/templates/classic/tab_statistics.html delete mode 100644 deluge/ui/webui/templates/classic/tab_trackers.html delete mode 100644 deluge/ui/webui/templates/classic/torrent_add.html delete mode 100644 deluge/ui/webui/templates/classic/torrent_delete.html delete mode 100644 deluge/ui/webui/templates/classic/torrent_files.html delete mode 100644 deluge/ui/webui/templates/classic/torrent_info.html delete mode 100644 deluge/ui/webui/templates/classic/torrent_move.html delete mode 100644 deluge/ui/webui/templates/hacking-templates.txt delete mode 100644 deluge/ui/webui/templates/white/admin_toolbar.html delete mode 100644 deluge/ui/webui/templates/white/basic_header.html delete mode 100644 deluge/ui/webui/templates/white/footer.html delete mode 100644 deluge/ui/webui/templates/white/header.html delete mode 100644 deluge/ui/webui/templates/white/index.html delete mode 100644 deluge/ui/webui/templates/white/meta.cfg delete mode 100644 deluge/ui/webui/templates/white/part_label_filters.html delete mode 100644 deluge/ui/webui/templates/white/part_organize.html delete mode 100644 deluge/ui/webui/templates/white/part_tab_button.html delete mode 100644 deluge/ui/webui/templates/white/part_tb_button.html delete mode 100644 deluge/ui/webui/templates/white/part_toolbar.html delete mode 100644 deluge/ui/webui/templates/white/part_torrent_list.html delete mode 100644 deluge/ui/webui/templates/white/template_style.css delete mode 100644 deluge/ui/webui/templates/white/torrent_info_inner.html delete mode 100644 deluge/ui/webui/templates/white/torrent_label.html delete mode 100644 deluge/ui/webui/tests/test_all.py delete mode 100644 deluge/ui/webui/torrent_add.py delete mode 100644 deluge/ui/webui/torrent_move.py delete mode 100644 deluge/ui/webui/torrent_options.py delete mode 100644 deluge/ui/webui/utils.py delete mode 100644 deluge/ui/webui/version delete mode 100644 deluge/ui/webui/web.py delete mode 100644 deluge/ui/webui/webserver_common.py delete mode 100644 deluge/ui/webui/webui.py diff --git a/deluge/ui/webui/LICENSE b/deluge/ui/webui/LICENSE deleted file mode 100644 index 94a045322..000000000 --- a/deluge/ui/webui/LICENSE +++ /dev/null @@ -1,621 +0,0 @@ - GNU GENERAL PUBLIC LICENSE - Version 3, 29 June 2007 - - Copyright (C) 2007 Free Software Foundation, Inc. - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - - Preamble - - The GNU General Public License is a free, copyleft license for -software and other kinds of works. - - The licenses for most software and other practical works are designed -to take away your freedom to share and change the works. By contrast, -the GNU General Public License is intended to guarantee your freedom to -share and change all versions of a program--to make sure it remains free -software for all its users. We, the Free Software Foundation, use the -GNU General Public License for most of our software; it applies also to -any other work released this way by its authors. You can apply it to -your programs, too. - - When we speak of free software, we are referring to freedom, not -price. Our General Public Licenses are designed to make sure that you -have the freedom to distribute copies of free software (and charge for -them if you wish), that you receive source code or can get it if you -want it, that you can change the software or use pieces of it in new -free programs, and that you know you can do these things. - - To protect your rights, we need to prevent others from denying you -these rights or asking you to surrender the rights. Therefore, you have -certain responsibilities if you distribute copies of the software, or if -you modify it: responsibilities to respect the freedom of others. - - For example, if you distribute copies of such a program, whether -gratis or for a fee, you must pass on to the recipients the same -freedoms that you received. You must make sure that they, too, receive -or can get the source code. And you must show them these terms so they -know their rights. - - Developers that use the GNU GPL protect your rights with two steps: -(1) assert copyright on the software, and (2) offer you this License -giving you legal permission to copy, distribute and/or modify it. - - For the developers' and authors' protection, the GPL clearly explains -that there is no warranty for this free software. For both users' and -authors' sake, the GPL requires that modified versions be marked as -changed, so that their problems will not be attributed erroneously to -authors of previous versions. - - Some devices are designed to deny users access to install or run -modified versions of the software inside them, although the manufacturer -can do so. This is fundamentally incompatible with the aim of -protecting users' freedom to change the software. The systematic -pattern of such abuse occurs in the area of products for individuals to -use, which is precisely where it is most unacceptable. Therefore, we -have designed this version of the GPL to prohibit the practice for those -products. If such problems arise substantially in other domains, we -stand ready to extend this provision to those domains in future versions -of the GPL, as needed to protect the freedom of users. - - Finally, every program is threatened constantly by software patents. -States should not allow patents to restrict development and use of -software on general-purpose computers, but in those that do, we wish to -avoid the special danger that patents applied to a free program could -make it effectively proprietary. To prevent this, the GPL assures that -patents cannot be used to render the program non-free. - - The precise terms and conditions for copying, distribution and -modification follow. - - TERMS AND CONDITIONS - - 0. Definitions. - - "This License" refers to version 3 of the GNU General Public License. - - "Copyright" also means copyright-like laws that apply to other kinds of -works, such as semiconductor masks. - - "The Program" refers to any copyrightable work licensed under this -License. Each licensee is addressed as "you". "Licensees" and -"recipients" may be individuals or organizations. - - To "modify" a work means to copy from or adapt all or part of the work -in a fashion requiring copyright permission, other than the making of an -exact copy. The resulting work is called a "modified version" of the -earlier work or a work "based on" the earlier work. - - A "covered work" means either the unmodified Program or a work based -on the Program. - - To "propagate" a work means to do anything with it that, without -permission, would make you directly or secondarily liable for -infringement under applicable copyright law, except executing it on a -computer or modifying a private copy. Propagation includes copying, -distribution (with or without modification), making available to the -public, and in some countries other activities as well. - - To "convey" a work means any kind of propagation that enables other -parties to make or receive copies. Mere interaction with a user through -a computer network, with no transfer of a copy, is not conveying. - - An interactive user interface displays "Appropriate Legal Notices" -to the extent that it includes a convenient and prominently visible -feature that (1) displays an appropriate copyright notice, and (2) -tells the user that there is no warranty for the work (except to the -extent that warranties are provided), that licensees may convey the -work under this License, and how to view a copy of this License. If -the interface presents a list of user commands or options, such as a -menu, a prominent item in the list meets this criterion. - - 1. Source Code. - - The "source code" for a work means the preferred form of the work -for making modifications to it. "Object code" means any non-source -form of a work. - - A "Standard Interface" means an interface that either is an official -standard defined by a recognized standards body, or, in the case of -interfaces specified for a particular programming language, one that -is widely used among developers working in that language. - - The "System Libraries" of an executable work include anything, other -than the work as a whole, that (a) is included in the normal form of -packaging a Major Component, but which is not part of that Major -Component, and (b) serves only to enable use of the work with that -Major Component, or to implement a Standard Interface for which an -implementation is available to the public in source code form. A -"Major Component", in this context, means a major essential component -(kernel, window system, and so on) of the specific operating system -(if any) on which the executable work runs, or a compiler used to -produce the work, or an object code interpreter used to run it. - - The "Corresponding Source" for a work in object code form means all -the source code needed to generate, install, and (for an executable -work) run the object code and to modify the work, including scripts to -control those activities. However, it does not include the work's -System Libraries, or general-purpose tools or generally available free -programs which are used unmodified in performing those activities but -which are not part of the work. For example, Corresponding Source -includes interface definition files associated with source files for -the work, and the source code for shared libraries and dynamically -linked subprograms that the work is specifically designed to require, -such as by intimate data communication or control flow between those -subprograms and other parts of the work. - - The Corresponding Source need not include anything that users -can regenerate automatically from other parts of the Corresponding -Source. - - The Corresponding Source for a work in source code form is that -same work. - - 2. Basic Permissions. - - All rights granted under this License are granted for the term of -copyright on the Program, and are irrevocable provided the stated -conditions are met. This License explicitly affirms your unlimited -permission to run the unmodified Program. The output from running a -covered work is covered by this License only if the output, given its -content, constitutes a covered work. This License acknowledges your -rights of fair use or other equivalent, as provided by copyright law. - - You may make, run and propagate covered works that you do not -convey, without conditions so long as your license otherwise remains -in force. You may convey covered works to others for the sole purpose -of having them make modifications exclusively for you, or provide you -with facilities for running those works, provided that you comply with -the terms of this License in conveying all material for which you do -not control copyright. Those thus making or running the covered works -for you must do so exclusively on your behalf, under your direction -and control, on terms that prohibit them from making any copies of -your copyrighted material outside their relationship with you. - - Conveying under any other circumstances is permitted solely under -the conditions stated below. Sublicensing is not allowed; section 10 -makes it unnecessary. - - 3. Protecting Users' Legal Rights From Anti-Circumvention Law. - - No covered work shall be deemed part of an effective technological -measure under any applicable law fulfilling obligations under article -11 of the WIPO copyright treaty adopted on 20 December 1996, or -similar laws prohibiting or restricting circumvention of such -measures. - - When you convey a covered work, you waive any legal power to forbid -circumvention of technological measures to the extent such circumvention -is effected by exercising rights under this License with respect to -the covered work, and you disclaim any intention to limit operation or -modification of the work as a means of enforcing, against the work's -users, your or third parties' legal rights to forbid circumvention of -technological measures. - - 4. Conveying Verbatim Copies. - - You may convey verbatim copies of the Program's source code as you -receive it, in any medium, provided that you conspicuously and -appropriately publish on each copy an appropriate copyright notice; -keep intact all notices stating that this License and any -non-permissive terms added in accord with section 7 apply to the code; -keep intact all notices of the absence of any warranty; and give all -recipients a copy of this License along with the Program. - - You may charge any price or no price for each copy that you convey, -and you may offer support or warranty protection for a fee. - - 5. Conveying Modified Source Versions. - - You may convey a work based on the Program, or the modifications to -produce it from the Program, in the form of source code under the -terms of section 4, provided that you also meet all of these conditions: - - a) The work must carry prominent notices stating that you modified - it, and giving a relevant date. - - b) The work must carry prominent notices stating that it is - released under this License and any conditions added under section - 7. This requirement modifies the requirement in section 4 to - "keep intact all notices". - - c) You must license the entire work, as a whole, under this - License to anyone who comes into possession of a copy. This - License will therefore apply, along with any applicable section 7 - additional terms, to the whole of the work, and all its parts, - regardless of how they are packaged. This License gives no - permission to license the work in any other way, but it does not - invalidate such permission if you have separately received it. - - d) If the work has interactive user interfaces, each must display - Appropriate Legal Notices; however, if the Program has interactive - interfaces that do not display Appropriate Legal Notices, your - work need not make them do so. - - A compilation of a covered work with other separate and independent -works, which are not by their nature extensions of the covered work, -and which are not combined with it such as to form a larger program, -in or on a volume of a storage or distribution medium, is called an -"aggregate" if the compilation and its resulting copyright are not -used to limit the access or legal rights of the compilation's users -beyond what the individual works permit. Inclusion of a covered work -in an aggregate does not cause this License to apply to the other -parts of the aggregate. - - 6. Conveying Non-Source Forms. - - You may convey a covered work in object code form under the terms -of sections 4 and 5, provided that you also convey the -machine-readable Corresponding Source under the terms of this License, -in one of these ways: - - a) Convey the object code in, or embodied in, a physical product - (including a physical distribution medium), accompanied by the - Corresponding Source fixed on a durable physical medium - customarily used for software interchange. - - b) Convey the object code in, or embodied in, a physical product - (including a physical distribution medium), accompanied by a - written offer, valid for at least three years and valid for as - long as you offer spare parts or customer support for that product - model, to give anyone who possesses the object code either (1) a - copy of the Corresponding Source for all the software in the - product that is covered by this License, on a durable physical - medium customarily used for software interchange, for a price no - more than your reasonable cost of physically performing this - conveying of source, or (2) access to copy the - Corresponding Source from a network server at no charge. - - c) Convey individual copies of the object code with a copy of the - written offer to provide the Corresponding Source. This - alternative is allowed only occasionally and noncommercially, and - only if you received the object code with such an offer, in accord - with subsection 6b. - - d) Convey the object code by offering access from a designated - place (gratis or for a charge), and offer equivalent access to the - Corresponding Source in the same way through the same place at no - further charge. You need not require recipients to copy the - Corresponding Source along with the object code. If the place to - copy the object code is a network server, the Corresponding Source - may be on a different server (operated by you or a third party) - that supports equivalent copying facilities, provided you maintain - clear directions next to the object code saying where to find the - Corresponding Source. Regardless of what server hosts the - Corresponding Source, you remain obligated to ensure that it is - available for as long as needed to satisfy these requirements. - - e) Convey the object code using peer-to-peer transmission, provided - you inform other peers where the object code and Corresponding - Source of the work are being offered to the general public at no - charge under subsection 6d. - - A separable portion of the object code, whose source code is excluded -from the Corresponding Source as a System Library, need not be -included in conveying the object code work. - - A "User Product" is either (1) a "consumer product", which means any -tangible personal property which is normally used for personal, family, -or household purposes, or (2) anything designed or sold for incorporation -into a dwelling. In determining whether a product is a consumer product, -doubtful cases shall be resolved in favor of coverage. For a particular -product received by a particular user, "normally used" refers to a -typical or common use of that class of product, regardless of the status -of the particular user or of the way in which the particular user -actually uses, or expects or is expected to use, the product. A product -is a consumer product regardless of whether the product has substantial -commercial, industrial or non-consumer uses, unless such uses represent -the only significant mode of use of the product. - - "Installation Information" for a User Product means any methods, -procedures, authorization keys, or other information required to install -and execute modified versions of a covered work in that User Product from -a modified version of its Corresponding Source. The information must -suffice to ensure that the continued functioning of the modified object -code is in no case prevented or interfered with solely because -modification has been made. - - If you convey an object code work under this section in, or with, or -specifically for use in, a User Product, and the conveying occurs as -part of a transaction in which the right of possession and use of the -User Product is transferred to the recipient in perpetuity or for a -fixed term (regardless of how the transaction is characterized), the -Corresponding Source conveyed under this section must be accompanied -by the Installation Information. But this requirement does not apply -if neither you nor any third party retains the ability to install -modified object code on the User Product (for example, the work has -been installed in ROM). - - The requirement to provide Installation Information does not include a -requirement to continue to provide support service, warranty, or updates -for a work that has been modified or installed by the recipient, or for -the User Product in which it has been modified or installed. Access to a -network may be denied when the modification itself materially and -adversely affects the operation of the network or violates the rules and -protocols for communication across the network. - - Corresponding Source conveyed, and Installation Information provided, -in accord with this section must be in a format that is publicly -documented (and with an implementation available to the public in -source code form), and must require no special password or key for -unpacking, reading or copying. - - 7. Additional Terms. - - "Additional permissions" are terms that supplement the terms of this -License by making exceptions from one or more of its conditions. -Additional permissions that are applicable to the entire Program shall -be treated as though they were included in this License, to the extent -that they are valid under applicable law. If additional permissions -apply only to part of the Program, that part may be used separately -under those permissions, but the entire Program remains governed by -this License without regard to the additional permissions. - - When you convey a copy of a covered work, you may at your option -remove any additional permissions from that copy, or from any part of -it. (Additional permissions may be written to require their own -removal in certain cases when you modify the work.) You may place -additional permissions on material, added by you to a covered work, -for which you have or can give appropriate copyright permission. - - Notwithstanding any other provision of this License, for material you -add to a covered work, you may (if authorized by the copyright holders of -that material) supplement the terms of this License with terms: - - a) Disclaiming warranty or limiting liability differently from the - terms of sections 15 and 16 of this License; or - - b) Requiring preservation of specified reasonable legal notices or - author attributions in that material or in the Appropriate Legal - Notices displayed by works containing it; or - - c) Prohibiting misrepresentation of the origin of that material, or - requiring that modified versions of such material be marked in - reasonable ways as different from the original version; or - - d) Limiting the use for publicity purposes of names of licensors or - authors of the material; or - - e) Declining to grant rights under trademark law for use of some - trade names, trademarks, or service marks; or - - f) Requiring indemnification of licensors and authors of that - material by anyone who conveys the material (or modified versions of - it) with contractual assumptions of liability to the recipient, for - any liability that these contractual assumptions directly impose on - those licensors and authors. - - All other non-permissive additional terms are considered "further -restrictions" within the meaning of section 10. If the Program as you -received it, or any part of it, contains a notice stating that it is -governed by this License along with a term that is a further -restriction, you may remove that term. If a license document contains -a further restriction but permits relicensing or conveying under this -License, you may add to a covered work material governed by the terms -of that license document, provided that the further restriction does -not survive such relicensing or conveying. - - If you add terms to a covered work in accord with this section, you -must place, in the relevant source files, a statement of the -additional terms that apply to those files, or a notice indicating -where to find the applicable terms. - - Additional terms, permissive or non-permissive, may be stated in the -form of a separately written license, or stated as exceptions; -the above requirements apply either way. - - 8. Termination. - - You may not propagate or modify a covered work except as expressly -provided under this License. Any attempt otherwise to propagate or -modify it is void, and will automatically terminate your rights under -this License (including any patent licenses granted under the third -paragraph of section 11). - - However, if you cease all violation of this License, then your -license from a particular copyright holder is reinstated (a) -provisionally, unless and until the copyright holder explicitly and -finally terminates your license, and (b) permanently, if the copyright -holder fails to notify you of the violation by some reasonable means -prior to 60 days after the cessation. - - Moreover, your license from a particular copyright holder is -reinstated permanently if the copyright holder notifies you of the -violation by some reasonable means, this is the first time you have -received notice of violation of this License (for any work) from that -copyright holder, and you cure the violation prior to 30 days after -your receipt of the notice. - - Termination of your rights under this section does not terminate the -licenses of parties who have received copies or rights from you under -this License. If your rights have been terminated and not permanently -reinstated, you do not qualify to receive new licenses for the same -material under section 10. - - 9. Acceptance Not Required for Having Copies. - - You are not required to accept this License in order to receive or -run a copy of the Program. Ancillary propagation of a covered work -occurring solely as a consequence of using peer-to-peer transmission -to receive a copy likewise does not require acceptance. However, -nothing other than this License grants you permission to propagate or -modify any covered work. These actions infringe copyright if you do -not accept this License. Therefore, by modifying or propagating a -covered work, you indicate your acceptance of this License to do so. - - 10. Automatic Licensing of Downstream Recipients. - - Each time you convey a covered work, the recipient automatically -receives a license from the original licensors, to run, modify and -propagate that work, subject to this License. You are not responsible -for enforcing compliance by third parties with this License. - - An "entity transaction" is a transaction transferring control of an -organization, or substantially all assets of one, or subdividing an -organization, or merging organizations. If propagation of a covered -work results from an entity transaction, each party to that -transaction who receives a copy of the work also receives whatever -licenses to the work the party's predecessor in interest had or could -give under the previous paragraph, plus a right to possession of the -Corresponding Source of the work from the predecessor in interest, if -the predecessor has it or can get it with reasonable efforts. - - You may not impose any further restrictions on the exercise of the -rights granted or affirmed under this License. For example, you may -not impose a license fee, royalty, or other charge for exercise of -rights granted under this License, and you may not initiate litigation -(including a cross-claim or counterclaim in a lawsuit) alleging that -any patent claim is infringed by making, using, selling, offering for -sale, or importing the Program or any portion of it. - - 11. Patents. - - A "contributor" is a copyright holder who authorizes use under this -License of the Program or a work on which the Program is based. The -work thus licensed is called the contributor's "contributor version". - - A contributor's "essential patent claims" are all patent claims -owned or controlled by the contributor, whether already acquired or -hereafter acquired, that would be infringed by some manner, permitted -by this License, of making, using, or selling its contributor version, -but do not include claims that would be infringed only as a -consequence of further modification of the contributor version. For -purposes of this definition, "control" includes the right to grant -patent sublicenses in a manner consistent with the requirements of -this License. - - Each contributor grants you a non-exclusive, worldwide, royalty-free -patent license under the contributor's essential patent claims, to -make, use, sell, offer for sale, import and otherwise run, modify and -propagate the contents of its contributor version. - - In the following three paragraphs, a "patent license" is any express -agreement or commitment, however denominated, not to enforce a patent -(such as an express permission to practice a patent or covenant not to -sue for patent infringement). To "grant" such a patent license to a -party means to make such an agreement or commitment not to enforce a -patent against the party. - - If you convey a covered work, knowingly relying on a patent license, -and the Corresponding Source of the work is not available for anyone -to copy, free of charge and under the terms of this License, through a -publicly available network server or other readily accessible means, -then you must either (1) cause the Corresponding Source to be so -available, or (2) arrange to deprive yourself of the benefit of the -patent license for this particular work, or (3) arrange, in a manner -consistent with the requirements of this License, to extend the patent -license to downstream recipients. "Knowingly relying" means you have -actual knowledge that, but for the patent license, your conveying the -covered work in a country, or your recipient's use of the covered work -in a country, would infringe one or more identifiable patents in that -country that you have reason to believe are valid. - - If, pursuant to or in connection with a single transaction or -arrangement, you convey, or propagate by procuring conveyance of, a -covered work, and grant a patent license to some of the parties -receiving the covered work authorizing them to use, propagate, modify -or convey a specific copy of the covered work, then the patent license -you grant is automatically extended to all recipients of the covered -work and works based on it. - - A patent license is "discriminatory" if it does not include within -the scope of its coverage, prohibits the exercise of, or is -conditioned on the non-exercise of one or more of the rights that are -specifically granted under this License. You may not convey a covered -work if you are a party to an arrangement with a third party that is -in the business of distributing software, under which you make payment -to the third party based on the extent of your activity of conveying -the work, and under which the third party grants, to any of the -parties who would receive the covered work from you, a discriminatory -patent license (a) in connection with copies of the covered work -conveyed by you (or copies made from those copies), or (b) primarily -for and in connection with specific products or compilations that -contain the covered work, unless you entered into that arrangement, -or that patent license was granted, prior to 28 March 2007. - - Nothing in this License shall be construed as excluding or limiting -any implied license or other defenses to infringement that may -otherwise be available to you under applicable patent law. - - 12. No Surrender of Others' Freedom. - - If conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot convey a -covered work so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you may -not convey it at all. For example, if you agree to terms that obligate you -to collect a royalty for further conveying from those to whom you convey -the Program, the only way you could satisfy both those terms and this -License would be to refrain entirely from conveying the Program. - - 13. Use with the GNU Affero General Public License. - - Notwithstanding any other provision of this License, you have -permission to link or combine any covered work with a work licensed -under version 3 of the GNU Affero General Public License into a single -combined work, and to convey the resulting work. The terms of this -License will continue to apply to the part which is the covered work, -but the special requirements of the GNU Affero General Public License, -section 13, concerning interaction through a network will apply to the -combination as such. - - 14. Revised Versions of this License. - - The Free Software Foundation may publish revised and/or new versions of -the GNU General Public License from time to time. Such new versions will -be similar in spirit to the present version, but may differ in detail to -address new problems or concerns. - - Each version is given a distinguishing version number. If the -Program specifies that a certain numbered version of the GNU General -Public License "or any later version" applies to it, you have the -option of following the terms and conditions either of that numbered -version or of any later version published by the Free Software -Foundation. If the Program does not specify a version number of the -GNU General Public License, you may choose any version ever published -by the Free Software Foundation. - - If the Program specifies that a proxy can decide which future -versions of the GNU General Public License can be used, that proxy's -public statement of acceptance of a version permanently authorizes you -to choose that version for the Program. - - Later license versions may give you additional or different -permissions. However, no additional obligations are imposed on any -author or copyright holder as a result of your choosing to follow a -later version. - - 15. Disclaimer of Warranty. - - THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY -APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT -HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY -OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, -THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM -IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF -ALL NECESSARY SERVICING, REPAIR OR CORRECTION. - - 16. Limitation of Liability. - - IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING -WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS -THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY -GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE -USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF -DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD -PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), -EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF -SUCH DAMAGES. - - 17. Interpretation of Sections 15 and 16. - - If the disclaimer of warranty and limitation of liability provided -above cannot be given local legal effect according to their terms, -reviewing courts shall apply local law that most closely approximates -an absolute waiver of all civil liability in connection with the -Program, unless a warranty or assumption of liability accompanies a -copy of the Program in return for a fee. - - END OF TERMS AND CONDITIONS diff --git a/deluge/ui/webui/TODO b/deluge/ui/webui/TODO deleted file mode 100644 index 0fd8a6b53..000000000 --- a/deluge/ui/webui/TODO +++ /dev/null @@ -1,30 +0,0 @@ -After labels: -*templates : remove advanced , rename deluge to classic , result = classic-templ -> no-javascript ; white-templ -> static enhanced with js ; ajax-templ -> json api -*white temnplate: add deluge icon. -*fix all comments from IRC-nonicknamename2. - -0.6 RC: -*Fix IE7 for advanced/white template. -*white template : add auto-refresh (with a nice js-progress-bar) -*gettext : update template_strings.py + add all .py files to gettext input files - -after 0.6 /before 1.0: -*hide-option for details iframe. -*white template:better css fluid layout or switch to tables. -*rethink details iframe. -*persistent sessions - -maybe/ideas/after 0.6.1: -*checkboxes for multiple select? -*switch to webpy 0.3 -*right-click menu on torrent-rows -*multi row template like transmission etc. - -Half-done: -*labels (organize-plugin) -*add new major features in available gtk ui but not in webui. - -Done: -*plugin-config + (re)enable webui plugins. -*white-template : green-iframe ->make blue - diff --git a/deluge/ui/webui/__init__.py b/deluge/ui/webui/__init__.py deleted file mode 100644 index 00825b045..000000000 --- a/deluge/ui/webui/__init__.py +++ /dev/null @@ -1,21 +0,0 @@ -# -*- coding: utf-8 -*- -# -# -# Copyright (C) Martijn Voncken 2007 -# -# 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 3, 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. -# diff --git a/deluge/ui/webui/apache.py b/deluge/ui/webui/apache.py deleted file mode 100644 index fc76a4fed..000000000 --- a/deluge/ui/webui/apache.py +++ /dev/null @@ -1,57 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- -# -# -# Copyright (C) Martijn Voncken 2008 -# -# 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 3, 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. -# - -# - -""" -this is an ugly hack, and it will be changed. -for experimental use only!! -""" -import os - -def get_wsgi_application(base_url, config_dir): - - #monkeypatch: - from deluge import common - def get_config_dir(filename = ""): - return os.path.join(config_dir, filename) - common.get_config_dir = get_config_dir - #/monkeypatch - - from deluge.configmanager import ConfigManager - from deluge.ui.webui import deluge_webserver - from deluge.ui.webui import utils - - config = ConfigManager("webui06.conf") - - utils.set_config_defaults() - - config['base'] = '/deluge' - config['disallow'] = { - '/daemon/control':'running as an apache user', - '/config/server':'running as an apache-user' - } - - utils.apply_config() - - return deluge_webserver.WsgiApplication() diff --git a/deluge/ui/webui/components.py b/deluge/ui/webui/components.py deleted file mode 100644 index f7edcaef7..000000000 --- a/deluge/ui/webui/components.py +++ /dev/null @@ -1,212 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- -# -# -# Copyright (C) Martijn Voncken 2008 -# -# 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 3, 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. -# - -# - -""" -deluge components. - -MenuManager:add torrent-menu-items and torrent-detail tabs. -PageManager: add pages(urls) -PluginManager: deluge plugin manager -ConfigPageManager: add config pages(tabs) - -These managers/components are accesible as: - -from deluge import component -manager = component.get("ClassName") - -""" -from deluge import component -import lib.newforms_plus as forms -from lib.egg_handler import egg_handler -from lib.egg_render import egg_render -from deluge.ui.client import aclient -from deluge import component, pluginmanagerbase -from deluge.configmanager import ConfigManager -from deluge.log import LOG as log - -class TOOLBAR_FLAGS: - generic = 0 - torrent = 1 - torrent_list = 2 - -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 ),.. ) - - - #register vars in template. - from render import 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_toolbar_item(self, id, title, image, flag, method, url, important): - self.toolbar_items.append((id, title, image, flag, method, url, important)) - - def deregister_toolbar_item(self, item_id): - for (i, toolbar) in enumerate(admin_pages): - if toolbar[0] == item_id: - del self.toolbar_items[i] - - #admin: - def register_admin_page(self, id, title, url): - self.admin_pages.append((id, title, url)) - - def deregister_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 deregister_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 - -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 = [] - self.include_javascript = [] - self.ajax_javascript = [] - - def register_pages(self, url_list, class_list): - self.urls += url_list - self.page_classes.update(class_list) - - def register_page(self, url, klass, use_module=True): - if use_module: - name = klass.__module__ + "." + klass.__name__ - else: - name = klass.__name__ - self.urls.append(url) - self.urls.append(name) - self.page_classes[name] = klass - - def deregister_page(self, url): - raise NotImplemenetedError() - #self.page_classes[klass.__name__] = None - -class PluginManager(pluginmanagerbase.PluginManagerBase, - component.Component): - def __init__(self): - component.Component.__init__(self, "WebPluginManager") - self.config = ConfigManager("webui06.conf") - pluginmanagerbase.PluginManagerBase.__init__( - self, "webui06.conf", "deluge.plugin.webui") - - def start(self): - """Start the plugin manager""" - # Update the enabled_plugins from the core - log.debug("start webui plugin manager") - aclient.get_enabled_plugins(self._on_get_enabled_plugins) - aclient.force_call(block=True) - - def stop(self): - # Disable the plugins - self.disable_plugins() - - def _on_get_enabled_plugins(self, enabled_plugins): - - log.debug("..Webui has these plugins enabled: %s", enabled_plugins) - - log.debug("abababab") - log.debug(self.config) - - self.config.config["enabled_plugins"] = enabled_plugins - - # Enable the plugins that are enabled in the config and core - log.debug(self.enable_plugins) - try: - self.enable_plugins() - except Exception, e: - log.debug(e) - - -class ConfigPageManager(component.Component): - def __init__(self): - component.Component.__init__(self, "ConfigPageManager") - self.groups = [] - self.blocks = forms.django.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 deregister(self, name): - del self.blocks[name] - -class PluginApi(component.Component): - """ - """ - def __init__(self): - component.Component.__init__(self, "WebPluginApi") - import web - from render import render - import page_decorators as deco - import utils - import lib.newforms_plus as forms - - self.egg_handler = egg_handler - self.egg_render = egg_render - self.render = render - self.web = web - self.deco = deco - self.forms = forms - self.page_manager = component.get("PageManager") - self.config_page_manager = component.get("ConfigPageManager") - self.menu_manager = component.get("MenuManager") - self.utils = utils - -def register(): - __page_manager = PageManager() - __plugin_manager = PluginManager() - __menu_manager = MenuManager() - __config_page_manager = ConfigPageManager() - __plugin_api = PluginApi() - - -if __name__ == "__main__": - register() - - - diff --git a/deluge/ui/webui/config_forms.py b/deluge/ui/webui/config_forms.py deleted file mode 100644 index 960abb960..000000000 --- a/deluge/ui/webui/config_forms.py +++ /dev/null @@ -1,103 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- -# -# Copyright (C) Martijn Voncken 2008 -# -# 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 3, 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. -# - - -import lib.newforms_plus as forms -import page_decorators as deco -import web -from deluge.ui.client import sclient as proxy -from deluge.log import LOG as log - -from render import render -from utils import seeother -import sys -import os -import utils - -from deluge import component -from deluge.configmanager import ConfigManager - -config = ConfigManager("webui06.conf") -config_page_manager = component.get("ConfigPageManager") - -class WebCfgForm(forms.Form): - "config base for webui" - def initial_data(self): - return config.config - - def save(self, data): - utils.validate_config(data) - for key, value in data.iteritems(): - config[key] = value - config.save() - -class CfgForm(forms.Form): - "config base for deluge-cfg" - def initial_data(self): - return proxy.get_config() - def save(self, data): - proxy.set_config(dict(data)) - -class config_page: - """ - web.py config page - """ - def get_form_class(self,name): - try: - return config_page_manager.blocks[name] - except KeyError: - raise Exception('no config page named:"%s"' % name) - - @deco.deluge_page - def GET(self, name): - if name == '': - return seeother('/config/template') - - form_class = self.get_form_class(name) - f = form_class() - f.full_clean() - return self.render(f , name) - - @deco.deluge_page - def POST(self,name): - - form_class = self.get_form_class(name) - form_data = web.Storage(utils.get_newforms_data(form_class)) - form = form_class(form_data) - if form.is_valid(): - log.debug('save config %s' % form_data) - try: - form.start_save() - return self.render(form , name, _('These changes were saved')) - except forms.ValidationError, e: - log.debug(e.message) - return self.render(form , name, error = e.message) - else: - return self.render(form , name, - error= _('Correct the errors above and try again')) - - def render(self, f , name , message = '' , error=''): - return render.config(config_page_manager.groups, config_page_manager.blocks, f, name , message , error) - -def register(): - component.get("PageManager").register_page("/config/(.*)", config_page) - diff --git a/deluge/ui/webui/config_tabs_deluge.py b/deluge/ui/webui/config_tabs_deluge.py deleted file mode 100644 index 8d8d4f086..000000000 --- a/deluge/ui/webui/config_tabs_deluge.py +++ /dev/null @@ -1,215 +0,0 @@ -# -*- coding: utf-8 -*- -# -# deluge_webserver.py -# -# Copyright (C) Martijn Voncken 2008 -# -# 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 3, 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. -# - - -from deluge.ui.client import sclient -from deluge.log import LOG as log - -import utils - -import lib.newforms_plus as forms -import config_forms -from deluge import component - -config_page = component.get("ConfigPageManager") - -class NetworkPorts(config_forms.CfgForm ): - title = _("Ports") - _port_from = forms.IntegerField(label= _("From"),min_value = 0, max_value=65535) - _port_to = forms.IntegerField(label = _("To"),min_value = 0, max_value=65535) - random_port = forms.CheckBox(label = _("Random")) - - def initial_data(self): - data = config_forms.CfgForm.initial_data(self) - data['_port_from'] , data['_port_to'] = data['listen_ports'] - return data - - def save(self,data): - data['listen_ports'] = [data['_port_from'] , data['_port_to'] ] - del(data['_port_from']) - del(data['_port_to']) - config_forms.CfgForm.save(self, data) - - def validate(self, data): - if (data['_port_to'] < data['_port_from']): - raise forms.ValidationError('"Port from" must be greater than "Port to"') - - def post_html(self): - return """ - - """ % {'active_port':sclient.get_listen_port()} - -config_page.register('network','ports', NetworkPorts) - -class NetworkExtra(config_forms.CfgForm ): - title = _("Extra's") - dht = forms.CheckBox(_("Mainline DHT")) - upnp = forms.CheckBox(_("UpNP")) - natpmp = forms.CheckBox(_("NAT-PMP")) - utpex = forms.CheckBox(_("Peer-Exchange")) - lsd = forms.CheckBox(_("LSD")) - -config_page.register('network','extra', NetworkExtra) - -class NetworkEnc(config_forms.CfgForm ): - title = _("Encryption") - - _enc_choices = list(enumerate([_("Forced"),_("Enabled"),_("Disabled")])) - _level_choices = list(enumerate([_("Handshake"), _("Full") , _("Either")])) - - enc_in_policy = forms.IntChoiceField(_("Inbound"), _enc_choices) - enc_out_policy = forms.IntChoiceField(_("Outbound"), _enc_choices) - enc_level = forms.IntChoiceField(_("Level"), _level_choices) - enc_prefer_rc4 = forms.CheckBox("Prefer to encrypt entire stream") - -config_page.register('network','encryption', NetworkEnc) - -class Proxy(config_forms.CfgForm): - title = _("Proxy") - _type_choices = list(enumerate( - [_("None"), _("Socksv4"), _("Socksv5"), _("Socksv5 W/ Auth"),_("HTTP"), _("HTTP W/ Auth")])) - - proxy_type = forms.IntChoiceField(_("Type"), _type_choices) - proxy_server =forms.CharField(label= _("Host"),required=False) - proxy_port = forms.IntegerField(label= _("Port"),min_value = 0, max_value=65535 , required=False) - proxy_username = forms.CharField(label= _("Username"), required=False) - proxy_password = forms.Password(label= _("Password"), required=False) - -config_page.register('network','proxy', Proxy) - -class BandwithGlobal(config_forms.CfgForm): - title = _("Global") - info = _("-1 = Unlimited") - max_connections_global = forms.DelugeInt(_("Maximum Connections")) - max_download_speed = forms.DelugeFloat(_("Maximum Download Speed (Kib/s)")) - max_upload_speed = forms.DelugeFloat(_("Maximum Upload Speed (Kib/s)")) - max_upload_slots_global = forms.DelugeInt(_("Maximum Upload Slots")) - - max_half_open_connections = forms.DelugeInt(_("Maximum Half-Open Connections")) - max_connections_per_second = forms.DelugeInt(_("Maximum Connection Attempts per Second")) - ignore_limits_on_local_network = forms.CheckBox(_("Ignore limits on local network")) - rate_limit_ip_overhead = forms.CheckBox(_("Rate Limit IP Overhead")) - - -config_page.register('bandwidth','global', BandwithGlobal) - -class BandwithTorrent(config_forms.CfgForm): - title = _("Per Torrent") - info = _("-1 = Unlimited") - max_connections_per_torrent = forms.DelugeInt(_("Maximum Connections")) - max_download_speed_per_torrent = forms.DelugeFloat(_("Maximum Download Speed (Kib/s)")) - max_upload_speed_per_torrent = forms.DelugeFloat(_("Maximum Upload Speed (Kib/s)")) - max_upload_slots_per_torrent = forms.DelugeInt(_("Maximum Upload Slots")) - -config_page.register('bandwidth','torrent', BandwithTorrent) - -class Download(config_forms.CfgForm): - title = _("Download") - download_location = forms.ServerFolder(_("Store all downoads in")) - torrentfiles_location = forms.ServerFolder(_("Save .torrent files to")) - autoadd_location = forms.ServerFolder(_("Auto Add folder"), required=False) - autoadd_enable = forms.CheckBox(_("Auto Add enabled")) - compact_allocation = forms.CheckBox(_('Use Compact Allocation')) - prioritize_first_last_pieces = forms.CheckBox(_('Prioritize first and last pieces')) - #default_private = forms.CheckBox(_('Set private flag by default')) - -config_page.register('deluge','download', Download) - -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_page.register('deluge','daemon', Daemon) - -class Queue(config_forms.CfgForm): - title = _("Queue") - info = _("-1 = unlimited") - - queue_new_to_top = forms.CheckBox(_("Queue new torrents to top")) - - - #total_downloading = forms.DelugeInt(_("Total active downloading")) - max_active_limit = forms.DelugeInt(_("Total active torrents")) - max_active_downloading = forms.DelugeInt(_("Total active downloading")) - max_active_seeding = forms.DelugeInt(_("Total active seeding")) - - - share_ratio_limit = forms.FloatField(min_value=-1) - seed_time_ratio_limit = forms.FloatField(min_value=-1) - seed_time_limit = forms.FloatField(min_value=-1) - - stop_seed_at_ratio = forms.CheckBox(_("Stop seeding when ratio reaches")) - #stop_ratio = forms.FloatField(min_value=-1) - remove_seed_at_ratio = forms.CheckBox(_("Remove torrent when ratio reached")) - stop_seed_ratio = forms.FloatField(min_value=-1) - -config_page.register('deluge','queue', Queue) - -""" -Will become a plugin, saved for later use. -class Notification(config_forms.CfgForm): - title = _("Notification") - _security_choices = [(t,t) for t in [None,"SSL","TLS"]] - ntf_email = forms.EmailField(label=_("Email"), required=False) - ntf_server =forms.CharField(label= _("Server"), required=False) - ntf_username = forms.CharField(label= _("Username"), required=False) - ntf_password = forms.CharField(label= _("Password"), required=False) - ntf_security = forms.ChoiceField( label=_("Security"), choices = _security_choices ) - -config_page.register('deluge','notification', Notification) -""" - -class Plugins(forms.Form): - title = _("Enabled Plugins") - - enabled_plugins = forms.LazyMultipleChoice( - choices_getter = lambda: [(p,p) for p in sclient.get_available_plugins()] - ) - - def initial_data(self): - return {'enabled_plugins':sclient.get_enabled_plugins()} - - def save(self, data): - new_plugins = data.enabled_plugins - old_plugins = sclient.get_enabled_plugins() - - enable = [p for p in new_plugins if p not in old_plugins] - disable = [p for p in old_plugins if p not in new_plugins] - - - plugin_manager = component.get("WebPluginManager") - for p in enable: - sclient.enable_plugin(p) - plugin_manager.enable_plugin(p) - - for p in disable: - sclient.disable_plugin(p) - plugin_manager.disable_plugin(p) - -config_page.register('deluge','plugins', Plugins) - diff --git a/deluge/ui/webui/config_tabs_webui.py b/deluge/ui/webui/config_tabs_webui.py deleted file mode 100644 index c1a73a2d8..000000000 --- a/deluge/ui/webui/config_tabs_webui.py +++ /dev/null @@ -1,112 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- -# -# deluge_webserver.py -# -# Copyright (C) Martijn Voncken 2008 -# -# 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 3, 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. -# - - -from deluge.ui.client import sclient as proxy -from deluge.log import LOG as log - - -import utils -import lib.newforms_plus as forms -import config_forms -from deluge import component -from render import render - -config_page = component.get("ConfigPageManager") -plugins = component.get("WebPluginManager") - - -class Template(config_forms.WebCfgForm): - title = _("Template") - - _templates = [(t,t) for t in render.get_templates()] - _button_choices = enumerate([_('Text and image'), _('Image Only') - , _('Text Only')]) - - template = forms.ChoiceField( label=_("Template"), choices = _templates) - button_style = forms.IntChoiceField(_("Button style"),_button_choices) - refresh_secs = forms.IntegerField(label= _("Auto refresh (seconds)"), min_value=2, max_value=60*60) - cache_templates = forms.CheckBox(_("Cache templates")) - - def post_save(self): - from render import render - render.apply_cfg() - -class Server(config_forms.WebCfgForm): - title = _("Server") - info = _("Manually restart webui to apply changes.") - - port = forms.IntegerField(label = _("Port"),min_value=80) - https = forms.CheckBox(_("Https")) - - def validate(self, data): - import os - from deluge.common import get_default_config_dir - - if data.https: - cert_path = os.path.join(get_default_config_dir("ssl") ,"deluge.cert.pem" ) - if not os.path.exists (cert_path): - raise forms.ValidationError(_("Certificate not found at '%s'" % cert_path)) - key_path = os.path.join(get_default_config_dir("ssl") ,"deluge.key.pem" ) - if not os.path.exists (key_path): - raise forms.ValidationError(_("Key not found at '%s'" % key_path)) - - - def post_save(self): - pass - #raise forms.ValidationError( - # ) - -class Password(forms.Form): - title = _("Password") - - old_pwd = forms.Password(_("Current Password")) - new1 = forms.Password(_("New Password")) - new2 = forms.Password(_("New Password (Confirm)")) - - def save(self,data): - utils.update_pwd(data.new1) - - def validate(self, data): - if not utils.check_pwd(data.old_pwd): - raise forms.ValidationError(_("Old password is invalid")) - if data.new1 <> data.new2: - raise forms.ValidationError( - _("New Password is not equal to New Password(confirm)")) - - def post_save(self): - utils.end_session() - #raise forms.ValidationError(_("Password changed,please login again")) - -class Sidebar(config_forms.WebCfgForm): - title = _("Sidebar") - show_sidebar = forms.CheckBox(_("Show sidebar")) - sidebar_show_zero = forms.CheckBox(_("Show zero hits")) - sidebar_show_trackers = forms.CheckBox(_("Show trackers")) - show_keyword_search = forms.CheckBox(_("Show keyword search")) - -config_page.register('webui','template', Template) -config_page.register('webui','server',Server) -config_page.register('webui','password',Password) -config_page.register('webui','sidebar',Sidebar) diff --git a/deluge/ui/webui/debugerror.py b/deluge/ui/webui/debugerror.py deleted file mode 100644 index ea8e21226..000000000 --- a/deluge/ui/webui/debugerror.py +++ /dev/null @@ -1,411 +0,0 @@ -""" -adapted for deluge-webui: --edit-box with traceback for cut+paste. --pretty errors for well known exceptions. - - -debugerror.py : -This is adapted from Django -with modifications Copyright (C) Martijn Voncken 2008 -Copyright (c) 2005, the Lawrence Journal-World -Used under the modified BSD license: -http://www.xfree86.org/3.3.6/COPYRIGHT2.html#5 -""" -__all__ = ["debugerror", "djangoerror"] - -import utils - -pretty_errors_str = { -"org.freedesktop.DBus.Error.ServiceUnknown": - """ Webui Lost the connection to deluge
- Unable to reconnect, please restart deluge. - """, -"InvalidUniqueIDError:": - """ - this torrent was removed, -
click here to go to the torrent-list - """ -} - - -pretty_errors_cls = { - type(utils.UnknownTorrentError):""" - this torrent was removed, - click here to go to the torrent-list - """ -} - -import sys, urlparse, pprint -from web import websafe -from web import template -import web #import lib.webpy022.webapi as web -import webserver_common as ws -from traceback import format_tb -from deluge import common - -Template = template.Template - -import os, os.path -whereami = os.path.join(os.getcwd(), __file__) -whereami = os.path.sep.join(whereami.split(os.path.sep)[:-1]) -djangoerror_t = """\ -$def with (exception_type, exception_value, frames, exception_message, version_info, tback_txt) - - - - - - $exception_type at $ctx.path - - - - - -
- - -

- -

Oops, Deluge Broke ...

- You might have found a bug, or you did something really stupid ;-). -
If the error persists :
- Read the Faq.
- Try downloading the latest version at - deluge-torrent.org -
Visit the forum - or the buglist for more info. -






-
-
-

$exception_type : $exception_value

-
- -
-Paste the contents of this text-box when you are asked for a traceback.
-Try to explain what you where doing, -and how you could work around the problem.
-Don't paste without context and expect us to know what went wrong. -
- - -
-Use a pastebin on IRC!
- - - - -
- - -
-

Traceback (innermost first)

-
    -$for frame in frames: -
  • - $frame.filename in $frame.function - $if frame.context_line: -
    - $if frame.pre_context: -
      - $for line in frame.pre_context: -
    1. $line
    2. -
    -
    1. $frame.context_line ...
    - $if frame.post_context: -
      - $for line in frame.post_context: -
    1. $line
    2. -
    -
    - - $if frame.vars: -
    - Local vars - $# $inspect.formatargvalues(*inspect.getargvalues(frame['tb'].tb_frame)) -
    - $:dicttable(frame.vars, kls='vars', id=('v' + str(frame.id))) -
  • -
-
- -
-$if ctx.output or ctx.headers: -

Response so far

-

HEADERS

-

- $for kv in ctx.headers: - $kv[0]: $kv[1]
- $else: - [no headers] -

- -

BODY

-

- $ctx.output -

- -

Request information

- -

INPUT

-$:dicttable(web.input()) - - -$:dicttable(web.cookies()) - -

META

-$ newctx = [] -$# ) and (k not in ['env', 'output', 'headers', 'environ', 'status', 'db_execute']): -$for k, v in ctx.iteritems(): - $if not k.startswith('_') and (k in x): - $newctx.append(kv) -$:dicttable(dict(newctx)) - -

ENVIRONMENT

-$:dicttable(ctx.env) -
- - - -""" - -dicttable_t = r"""$def with (d, kls='req', id=None) -$if d: - - - $ temp = d.items() - $temp.sort() - $for kv in temp: - - -
VariableValue
$kv[0]
$prettify(kv[1])
-$else: -

No data.

-""" - -dicttable_r = Template(dicttable_t, filter=websafe) -djangoerror_r = Template(djangoerror_t, filter=websafe) - -def djangoerror(): - def _get_lines_from_file(filename, lineno, context_lines): - """ - Returns context_lines before and after lineno from file. - Returns (pre_context_lineno, pre_context, context_line, post_context). - """ - try: - source = open(filename).readlines() - lower_bound = max(0, lineno - context_lines) - upper_bound = lineno + context_lines - - pre_context = \ - [line.strip('\n') for line in source[lower_bound:lineno]] - context_line = source[lineno].strip('\n') - post_context = \ - [line.strip('\n') for line in source[lineno + 1:upper_bound]] - - return lower_bound, pre_context, context_line, post_context - except (OSError, IOError): - return None, [], None, [] - - exception_type, exception_value, tback = sys.exc_info() - - exception_message = 'Error' - try: - exception_message = exception_value.message - except AttributeError: - exception_message = 'no message' - exception_type = exception_type.__name__ - - """ - for err_str in pretty_errors: - if err_str in exception_message: - #from render import render - return render.error(pretty_errors[err_str]) - """ - if exception_type in pretty_errors_cls: - from render import render - return render.error(pretty_errors_cls[exception_type]) - - version_info = "WebUi : %sr%s\nPython %s:" % ( common.get_version() ,common.get_revision(),sys.version) - - tback_txt = ''.join(format_tb(tback)) - - - frames = [] - while tback is not None: - filename = tback.tb_frame.f_code.co_filename - function = tback.tb_frame.f_code.co_name - lineno = tback.tb_lineno - 1 - pre_context_lineno, pre_context, context_line, post_context = \ - _get_lines_from_file(filename, lineno, 7) - frames.append(web.storage({ - 'tback': tback, - 'filename': filename, - 'function': function, - 'lineno': lineno, - 'vars': tback.tb_frame.f_locals, - 'id': id(tback), - 'pre_context': pre_context, - 'context_line': context_line, - 'post_context': post_context, - 'pre_context_lineno': pre_context_lineno, - })) - tback = tback.tb_next - frames.reverse() - urljoin = urlparse.urljoin - def prettify(x): - try: - out = pprint.pformat(x) - except Exception, e: - out = '[could not display: <' + e.__class__.__name__ + \ - ': '+str(e)+'>]' - return out - dt = dicttable_r - dt.globals = {'prettify': prettify} - t = djangoerror_r - t.globals = {'ctx': web.ctx, 'web':web, 'dicttable':dt, 'dict':dict, 'str':str} - return t(exception_type, exception_value, frames, exception_message, version_info, tback_txt) - -def deluge_debugerror(): - """ - A replacement for `internalerror` that presents a nice page with lots - of debug information for the programmer. - - (Based on the beautiful 500 page from [Django](http://djangoproject.com/), - designed by [Wilson Miner](http://wilsonminer.com/).) - """ - web.ctx.headers = [ - ('Content-Type', 'text/html') - ] - web.ctx.output = djangoerror() - -if __name__ == "__main__": - urls = ( - '/', 'index' - ) - - class index: - def GET(self): - thisdoesnotexist - - web.internalerror = web.debugerror - web.run(urls) diff --git a/deluge/ui/webui/deluge_webserver.py b/deluge/ui/webui/deluge_webserver.py deleted file mode 100644 index 0beab9b52..000000000 --- a/deluge/ui/webui/deluge_webserver.py +++ /dev/null @@ -1,135 +0,0 @@ -# -# Copyright (C) Martijn Voncken 2007 -# -# 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 3, 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. -# - - -import web -import random -import gettext -import locale -import deluge.common -from deluge.configmanager import ConfigManager -import pkg_resources -from deluge.ui.client import sclient -import components -from deluge.log import LOG as log -from webserver_common import CONFIG_DEFAULTS - -config = ConfigManager("webui06.conf", CONFIG_DEFAULTS) - -# Initialize gettext -try: - locale.setlocale(locale.LC_ALL, '') - if hasattr(locale, "bindtextdomain"): - locale.bindtextdomain("deluge", pkg_resources.resource_filename("deluge", "i18n")) - if hasattr(locale, "textdomain"): - locale.textdomain("deluge") - gettext.bindtextdomain("deluge", pkg_resources.resource_filename("deluge", "i18n")) - gettext.textdomain("deluge") - gettext.install("deluge", pkg_resources.resource_filename("deluge", "i18n")) -except Exception, e: - log.error("Unable to initialize gettext/locale: %s", e) - -components.register() #after gettext!! - -from debugerror import deluge_debugerror -from render import render -import utils - - -## Init ## -random.seed() -web.webapi.internalerror = deluge_debugerror - -#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 #auto registers. -#manual register: -import torrent_add -torrent_add.register() -import torrent_options -torrent_options.register() -import torrent_move -torrent_move.register() -import config_forms -config_forms.register() -import json_api -json_api.register() -#/self registering pages. - - -def WsgiApplication(middleware = None): - from web import webpyfunc, wsgifunc - from deluge import component - - pagemanager = component.get("PageManager") - if not middleware: - middleware = [] - - return wsgifunc(webpyfunc(pagemanager.urls, pagemanager.page_classes, False), *middleware) - -def create_webserver(debug = False, base_url =None): - "starts builtin webserver" - import web - - utils.set_config_defaults() - if base_url: - config['base'] = base_url - else: - config['base'] = '' - config['disallow'] = {} - utils.apply_config() - - - from lib.webpy022.wsgiserver import CherryPyWSGIServer - - middleware = None - if debug: - middleware = [web.reloader] - - wsgi_app = WsgiApplication(middleware) - - server_address=("0.0.0.0", int(config['port'])) - server = CherryPyWSGIServer(server_address, wsgi_app, server_name="localhost") - - https = False - if config["https"]: - import os - from deluge.common import get_default_config_dir - cert_path = os.path.join(get_default_config_dir("ssl") ,"deluge.cert.pem" ) - key_path = os.path.join(get_default_config_dir("ssl") ,"deluge.key.pem" ) - if os.path.exists (key_path) and os.path.exists (cert_path): - server.ssl_certificate = cert_path - server.ssl_private_key = key_path - https = True - - if https: - log.info("https://%s:%d/" % server_address) - else: - log.info("http://%s:%d/" % server_address) - return server - -def run(debug = False, base_url = ""): - server = create_webserver(debug, base_url) - try: - server.start() - except KeyboardInterrupt: - server.stop() diff --git a/deluge/ui/webui/json_api.py b/deluge/ui/webui/json_api.py deleted file mode 100644 index 20541db4e..000000000 --- a/deluge/ui/webui/json_api.py +++ /dev/null @@ -1,257 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- -# -# webserver_framework.py -# -# Copyright (C) Martijn Voncken 2008 -# Copyright (C) Damien Churchill 2008 -# -# 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 3, 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. -# - -""" -json api. - -design: -== Full client api == - * url : /json/rpc/ - * rpc-api : http://en.wikipedia.org/wiki/JSON-RPC - * methods : http://dev.deluge-torrent.org/wiki/Development/UiClient#Remoteapi - -""" -from traceback import format_exc -import web -from web import webapi -import page_decorators as deco -from web import cookies, setcookie as w_setcookie -import utils -from render import render -from utils import dict_cb - -try: - from json import dumps, loads -except ImportError: - from lib.json import write as dumps, read as loads - -from deluge.ui import common -from deluge.ui.client import sclient,aclient -from deluge.log import LOG as log -from deluge import component - -def json_response(result, id): - print dumps({ - "version":"1.1", - "result":result, - "id":id - }) - -def json_error(message , id=-1, msg_number=123): - log.error("JSON-error:%s" % message) - print dumps({ - "version":"1.1", - "id":id, - "error":{ - "number":msg_number, - "message":message, - "error":message - } - }) - -class json_rpc: - """ - == Full client api == - * url : /json/rpc - * rpc-api : http://en.wikipedia.org/wiki/JSON-RPC#Version_1.0 - * methods : http://dev.deluge-torrent.org/wiki/Development/UiClient#Remoteapi - """ - #extra exposed methods - json_exposed = ["update_ui","system_listMethods", "download_torrent_from_url", - "get_webui_config","set_webui_config","get_webui_templates", "get_torrent_info", - "add_torrents"] - cache = {} - - def GET(self): - return json_error("only POST is supported") - - def POST(self , name=None): - web.header("Content-Type", "application/x-json") - ck = cookies() - id = 0 - if not(ck.has_key("session_id") and ck["session_id"] in utils.config["sessions"]): - return json_error("not authenticated", id) - - try: - log.debug("json-data:") - log.debug(webapi.data()) - json_data = loads(webapi.data()) - id = json_data["id"] - method = json_data["method"].replace(".", "_") - params = json_data["params"] - - if method.startswith('_'): - raise Exception('_ methods are illegal.') - - elif method in self.json_exposed: - func = getattr(self, method) - result = func(*params) - else: - result = self.exec_client_method(method, params) - - #log.debug("JSON-result:%s(%s)[%s] = %s" % (method, params, id, result)) - - return json_response(result, id) - - except Exception,e: - #verbose because you don't want exeptions in the error-handler. - message = "" - if hasattr(e,"message"): - message = e.message - log.debug(format_exc()) - return json_error("%s:%s" % (e, message), id) - - def exec_client_method(self, method, params): - if not hasattr(sclient,method): - raise Exception('Unknown method:%s', method) - - #Call: - func = getattr(sclient, method) - return func(*params) - - # - #Extra exposed methods: - # - def system_listMethods(self): - "system.listMethods() see json/xmlrpc docs" - return sclient.list_methods() + self.json_exposed - - - def update_ui(self, keys ,filter_dict , cache_id = None ): - """ - Composite call. - Goal : limit the number of ajax calls - - input: - keys: see get_torrents_status - filter_dict: see get_torrents_status - cache_id: # todo - returns: - { - "torrents": see get_torrent_status - "filters": see get_filter_tree - "stats": see get_stats - "cache_id":int # todo - } - """ - filters = sclient.get_filter_tree() - return { - "torrents":sclient.get_torrents_status(filter_dict , keys), - "filters":filters, - "stats":sclient.get_stats(), - "cache_id":-1 - } - - def get_webui_config(self): - return dict([x for x in utils.config.config.iteritems() if not x[0].startswith("pwd")]) - - def set_webui_config(self, data): - utils.validate_config(data) - if "pwd" in data: - utils.update_pwd(pwd) - del data["pwd"] - for key, value in data.iteritems(): - utils.config[key] = value - utils.config.save() - utils.apply_config() - - def get_webui_templates(self): - return render.get_templates() - - def download_torrent_from_url(self, url): - """ - input: - url: the url of the torrent to download - - returns: - filename: the temporary file name of the torrent file - """ - import os - import urllib - import tempfile - tmp_file = os.path.join(tempfile.gettempdir(), url.split("/")[-1]) - filename, headers = urllib.urlretrieve(url, tmp_file) - log.debug("filename: %s", filename) - return filename - - def get_torrent_info(self, filename): - """ - Goal: - allow the webui to retrieve data about the torrent - - input: - filename: the filename of the torrent to gather info about - - returns: - { - "filename": the torrent file - "name": the torrent name - "size": the total size of the torrent - "files": the files the torrent contains - "info_hash" the torrents info_hash - } - """ - return common.get_torrent_info(filename.strip()) - - def add_torrents(self, torrents): - """ - input: - torrents [{ - path: the path of the torrent file, - options: the torrent options - }] - """ - import os - - for torrent in torrents: - filename = os.path.basename(torrent['path']) - fdump = open(torrent['path'], 'r').read() - aclient.add_torrent_file_binary(filename, fdump, torrent['options']) - aclient.force_call() - -class json_upload: - def GET(self): - pass - - @deco.check_session - def POST(self, name=None): - import os - import shutil - import tempfile - vars = web.input(torrentFile = {}) - vars.torrentFile - path = os.path.join(tempfile.gettempdir(), vars.torrentFile.filename) - tmp_file = open(path, 'w') - shutil.copyfileobj(vars.torrentFile.file, tmp_file) - tmp_file.close() - print path - - -def register(): - component.get("PageManager").register_page("/json/rpc",json_rpc) - component.get("PageManager").register_page("/json/upload",json_upload) - -if __name__ == '__main__': - print "todo: tests" diff --git a/deluge/ui/webui/lib/__init__.py b/deluge/ui/webui/lib/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/deluge/ui/webui/lib/egg_handler.py b/deluge/ui/webui/lib/egg_handler.py deleted file mode 100644 index aab696644..000000000 --- a/deluge/ui/webui/lib/egg_handler.py +++ /dev/null @@ -1,61 +0,0 @@ -#!/usr/bin/env python -#(c) Martijn Voncken, mvoncken@gmail.com -#Same Licence as web.py 0.22 -# -""" -static fileserving for web.py -serves 1 directory from a packed egg, using pkg_resourses -""" -import web -from web import url - -import posixpath -import urlparse -import urllib -import mimetypes -import os -import datetime -import cgi -from StringIO import StringIO -mimetypes.init() # try to read system mime.types -import pkg_resources - -class egg_handler: - """ - serves files directly from an egg - """ - resource = "label" - base_path = "data" - extensions_map = mimetypes.types_map - - def GET(self, path): - path = os.path.join(self.base_path, path) - ctype = self.guess_type(path) - - data = pkg_resources.resource_string(self.resource,path) - - web.header("Content-type", ctype) - web.header("Cache-Control" , "public, must-revalidate, max-age=86400") - #web.lastmodified(datetime.datetime.fromtimestamp(fs.st_mtime)) - print data - - def guess_type(self, path): - base, ext = posixpath.splitext(path) - if ext in self.extensions_map: - return self.extensions_map[ext] - ext = ext.lower() - if ext in self.extensions_map: - return self.extensions_map[ext] - else: - return 'application/octet-stream' - -if __name__ == '__main__': - #example: - class usr_static(egg_handler): - resource = "label" - base_path = "data" - - urls = ('/relative/(.*)','static_handler', - '/(.*)','usr_static') - - web.run(urls,globals()) diff --git a/deluge/ui/webui/lib/egg_render.py b/deluge/ui/webui/lib/egg_render.py deleted file mode 100644 index 0a54f2fb0..000000000 --- a/deluge/ui/webui/lib/egg_render.py +++ /dev/null @@ -1,33 +0,0 @@ -#!/usr/bin/env python -#(c) Martijn Voncken, mvoncken@gmail.com -#Same Licence as web.py 0.22 -""" -render object for web.py -renders from egg instead of directory. -""" -from web import template -import pkg_resources -import os - - -class egg_render: - """ - templates directly from an egg - """ - def __init__(self, resource, base_path , cache=False): - self.resource = resource - self.base_path = base_path - self.cache = cache - - def __getattr__(self, attr): - filename = attr + ".html" #<--bug, not consistent with the web.py renderer, that renderer ignores extensions. - template_data = pkg_resources.resource_string(self.resource, os.path.join(self.base_path, filename)) - c = template.Template(template_data, filename = filename) - if self.cache: - setattr(self, attr, c) - return c - - -if __name__ == '__main__': - #example: - pass diff --git a/deluge/ui/webui/lib/json.py b/deluge/ui/webui/lib/json.py deleted file mode 100644 index 9bb33d23d..000000000 --- a/deluge/ui/webui/lib/json.py +++ /dev/null @@ -1,815 +0,0 @@ -#mvoncken 2008: added complete LGPL to this file to ease distribution -import string -import types - -## json.py implements a JSON (http://json.org) reader and writer. -## Copyright (C) 2005 Patrick D. Logan -## Contact mailto:patrickdlogan@stardecisions.com -## -## This library is free software; you can redistribute it and/or -## modify it under the terms of the GNU Lesser General Public -## License as published by the Free Software Foundation; either -## version 2.1 of the License, or (at your option) any later version. -## -## This library 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 -## Lesser General Public License for more details. -## -## You should have received a copy of the GNU Lesser General Public -## License along with this library; if not, write to the Free Software -## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -""" - GNU LESSER GENERAL PUBLIC LICENSE - Version 2.1, February 1999 - - Copyright (C) 1991, 1999 Free Software Foundation, Inc. - 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - -[This is the first released version of the Lesser GPL. It also counts - as the successor of the GNU Library Public License, version 2, hence - the version number 2.1.] - - Preamble - - The licenses for most software are designed to take away your -freedom to share and change it. By contrast, the GNU General Public -Licenses are intended to guarantee your freedom to share and change -free software--to make sure the software is free for all its users. - - This license, the Lesser General Public License, applies to some -specially designated software packages--typically libraries--of the -Free Software Foundation and other authors who decide to use it. You -can use it too, but we suggest you first think carefully about whether -this license or the ordinary General Public License is the better -strategy to use in any particular case, based on the explanations below. - - When we speak of free software, we are referring to freedom of use, -not price. Our General Public Licenses are designed to make sure that -you have the freedom to distribute copies of free software (and charge -for this service if you wish); that you receive source code or can get -it if you want it; that you can change the software and use pieces of -it in new free programs; and that you are informed that you can do -these things. - - To protect your rights, we need to make restrictions that forbid -distributors to deny you these rights or to ask you to surrender these -rights. These restrictions translate to certain responsibilities for -you if you distribute copies of the library or if you modify it. - - For example, if you distribute copies of the library, whether gratis -or for a fee, you must give the recipients all the rights that we gave -you. You must make sure that they, too, receive or can get the source -code. If you link other code with the library, you must provide -complete object files to the recipients, so that they can relink them -with the library after making changes to the library and recompiling -it. And you must show them these terms so they know their rights. - - We protect your rights with a two-step method: (1) we copyright the -library, and (2) we offer you this license, which gives you legal -permission to copy, distribute and/or modify the library. - - To protect each distributor, we want to make it very clear that -there is no warranty for the free library. Also, if the library is -modified by someone else and passed on, the recipients should know -that what they have is not the original version, so that the original -author's reputation will not be affected by problems that might be -introduced by others. - - Finally, software patents pose a constant threat to the existence of -any free program. We wish to make sure that a company cannot -effectively restrict the users of a free program by obtaining a -restrictive license from a patent holder. Therefore, we insist that -any patent license obtained for a version of the library must be -consistent with the full freedom of use specified in this license. - - Most GNU software, including some libraries, is covered by the -ordinary GNU General Public License. This license, the GNU Lesser -General Public License, applies to certain designated libraries, and -is quite different from the ordinary General Public License. We use -this license for certain libraries in order to permit linking those -libraries into non-free programs. - - When a program is linked with a library, whether statically or using -a shared library, the combination of the two is legally speaking a -combined work, a derivative of the original library. The ordinary -General Public License therefore permits such linking only if the -entire combination fits its criteria of freedom. The Lesser General -Public License permits more lax criteria for linking other code with -the library. - - We call this license the "Lesser" General Public License because it -does Less to protect the user's freedom than the ordinary General -Public License. It also provides other free software developers Less -of an advantage over competing non-free programs. These disadvantages -are the reason we use the ordinary General Public License for many -libraries. However, the Lesser license provides advantages in certain -special circumstances. - - For example, on rare occasions, there may be a special need to -encourage the widest possible use of a certain library, so that it becomes -a de-facto standard. To achieve this, non-free programs must be -allowed to use the library. A more frequent case is that a free -library does the same job as widely used non-free libraries. In this -case, there is little to gain by limiting the free library to free -software only, so we use the Lesser General Public License. - - In other cases, permission to use a particular library in non-free -programs enables a greater number of people to use a large body of -free software. For example, permission to use the GNU C Library in -non-free programs enables many more people to use the whole GNU -operating system, as well as its variant, the GNU/Linux operating -system. - - Although the Lesser General Public License is Less protective of the -users' freedom, it does ensure that the user of a program that is -linked with the Library has the freedom and the wherewithal to run -that program using a modified version of the Library. - - The precise terms and conditions for copying, distribution and -modification follow. Pay close attention to the difference between a -"work based on the library" and a "work that uses the library". The -former contains code derived from the library, whereas the latter must -be combined with the library in order to run. - - GNU LESSER GENERAL PUBLIC LICENSE - TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION - - 0. This License Agreement applies to any software library or other -program which contains a notice placed by the copyright holder or -other authorized party saying it may be distributed under the terms of -this Lesser General Public License (also called "this License"). -Each licensee is addressed as "you". - - A "library" means a collection of software functions and/or data -prepared so as to be conveniently linked with application programs -(which use some of those functions and data) to form executables. - - The "Library", below, refers to any such software library or work -which has been distributed under these terms. A "work based on the -Library" means either the Library or any derivative work under -copyright law: that is to say, a work containing the Library or a -portion of it, either verbatim or with modifications and/or translated -straightforwardly into another language. (Hereinafter, translation is -included without limitation in the term "modification".) - - "Source code" for a work means the preferred form of the work for -making modifications to it. For a library, complete source code means -all the source code for all modules it contains, plus any associated -interface definition files, plus the scripts used to control compilation -and installation of the library. - - Activities other than copying, distribution and modification are not -covered by this License; they are outside its scope. The act of -running a program using the Library is not restricted, and output from -such a program is covered only if its contents constitute a work based -on the Library (independent of the use of the Library in a tool for -writing it). Whether that is true depends on what the Library does -and what the program that uses the Library does. - - 1. You may copy and distribute verbatim copies of the Library's -complete source code as you receive it, in any medium, provided that -you conspicuously and appropriately publish on each copy an -appropriate copyright notice and disclaimer of warranty; keep intact -all the notices that refer to this License and to the absence of any -warranty; and distribute a copy of this License along with the -Library. - - You may charge a fee for the physical act of transferring a copy, -and you may at your option offer warranty protection in exchange for a -fee. - - 2. You may modify your copy or copies of the Library or any portion -of it, thus forming a work based on the Library, and copy and -distribute such modifications or work under the terms of Section 1 -above, provided that you also meet all of these conditions: - - a) The modified work must itself be a software library. - - b) You must cause the files modified to carry prominent notices - stating that you changed the files and the date of any change. - - c) You must cause the whole of the work to be licensed at no - charge to all third parties under the terms of this License. - - d) If a facility in the modified Library refers to a function or a - table of data to be supplied by an application program that uses - the facility, other than as an argument passed when the facility - is invoked, then you must make a good faith effort to ensure that, - in the event an application does not supply such function or - table, the facility still operates, and performs whatever part of - its purpose remains meaningful. - - (For example, a function in a library to compute square roots has - a purpose that is entirely well-defined independent of the - application. Therefore, Subsection 2d requires that any - application-supplied function or table used by this function must - be optional: if the application does not supply it, the square - root function must still compute square roots.) - -These requirements apply to the modified work as a whole. If -identifiable sections of that work are not derived from the Library, -and can be reasonably considered independent and separate works in -themselves, then this License, and its terms, do not apply to those -sections when you distribute them as separate works. But when you -distribute the same sections as part of a whole which is a work based -on the Library, the distribution of the whole must be on the terms of -this License, whose permissions for other licensees extend to the -entire whole, and thus to each and every part regardless of who wrote -it. - -Thus, it is not the intent of this section to claim rights or contest -your rights to work written entirely by you; rather, the intent is to -exercise the right to control the distribution of derivative or -collective works based on the Library. - -In addition, mere aggregation of another work not based on the Library -with the Library (or with a work based on the Library) on a volume of -a storage or distribution medium does not bring the other work under -the scope of this License. - - 3. You may opt to apply the terms of the ordinary GNU General Public -License instead of this License to a given copy of the Library. To do -this, you must alter all the notices that refer to this License, so -that they refer to the ordinary GNU General Public License, version 2, -instead of to this License. (If a newer version than version 2 of the -ordinary GNU General Public License has appeared, then you can specify -that version instead if you wish.) Do not make any other change in -these notices. - - Once this change is made in a given copy, it is irreversible for -that copy, so the ordinary GNU General Public License applies to all -subsequent copies and derivative works made from that copy. - - This option is useful when you wish to copy part of the code of -the Library into a program that is not a library. - - 4. You may copy and distribute the Library (or a portion or -derivative of it, under Section 2) in object code or executable form -under the terms of Sections 1 and 2 above provided that you accompany -it with the complete corresponding machine-readable source code, which -must be distributed under the terms of Sections 1 and 2 above on a -medium customarily used for software interchange. - - If distribution of object code is made by offering access to copy -from a designated place, then offering equivalent access to copy the -source code from the same place satisfies the requirement to -distribute the source code, even though third parties are not -compelled to copy the source along with the object code. - - 5. A program that contains no derivative of any portion of the -Library, but is designed to work with the Library by being compiled or -linked with it, is called a "work that uses the Library". Such a -work, in isolation, is not a derivative work of the Library, and -therefore falls outside the scope of this License. - - However, linking a "work that uses the Library" with the Library -creates an executable that is a derivative of the Library (because it -contains portions of the Library), rather than a "work that uses the -library". The executable is therefore covered by this License. -Section 6 states terms for distribution of such executables. - - When a "work that uses the Library" uses material from a header file -that is part of the Library, the object code for the work may be a -derivative work of the Library even though the source code is not. -Whether this is true is especially significant if the work can be -linked without the Library, or if the work is itself a library. The -threshold for this to be true is not precisely defined by law. - - If such an object file uses only numerical parameters, data -structure layouts and accessors, and small macros and small inline -functions (ten lines or less in length), then the use of the object -file is unrestricted, regardless of whether it is legally a derivative -work. (Executables containing this object code plus portions of the -Library will still fall under Section 6.) - - Otherwise, if the work is a derivative of the Library, you may -distribute the object code for the work under the terms of Section 6. -Any executables containing that work also fall under Section 6, -whether or not they are linked directly with the Library itself. - - 6. As an exception to the Sections above, you may also combine or -link a "work that uses the Library" with the Library to produce a -work containing portions of the Library, and distribute that work -under terms of your choice, provided that the terms permit -modification of the work for the customer's own use and reverse -engineering for debugging such modifications. - - You must give prominent notice with each copy of the work that the -Library is used in it and that the Library and its use are covered by -this License. You must supply a copy of this License. If the work -during execution displays copyright notices, you must include the -copyright notice for the Library among them, as well as a reference -directing the user to the copy of this License. Also, you must do one -of these things: - - a) Accompany the work with the complete corresponding - machine-readable source code for the Library including whatever - changes were used in the work (which must be distributed under - Sections 1 and 2 above); and, if the work is an executable linked - with the Library, with the complete machine-readable "work that - uses the Library", as object code and/or source code, so that the - user can modify the Library and then relink to produce a modified - executable containing the modified Library. (It is understood - that the user who changes the contents of definitions files in the - Library will not necessarily be able to recompile the application - to use the modified definitions.) - - b) Use a suitable shared library mechanism for linking with the - Library. A suitable mechanism is one that (1) uses at run time a - copy of the library already present on the user's computer system, - rather than copying library functions into the executable, and (2) - will operate properly with a modified version of the library, if - the user installs one, as long as the modified version is - interface-compatible with the version that the work was made with. - - c) Accompany the work with a written offer, valid for at - least three years, to give the same user the materials - specified in Subsection 6a, above, for a charge no more - than the cost of performing this distribution. - - d) If distribution of the work is made by offering access to copy - from a designated place, offer equivalent access to copy the above - specified materials from the same place. - - e) Verify that the user has already received a copy of these - materials or that you have already sent this user a copy. - - For an executable, the required form of the "work that uses the -Library" must include any data and utility programs needed for -reproducing the executable from it. However, as a special exception, -the materials to be distributed need not include anything that is -normally distributed (in either source or binary form) with the major -components (compiler, kernel, and so on) of the operating system on -which the executable runs, unless that component itself accompanies -the executable. - - It may happen that this requirement contradicts the license -restrictions of other proprietary libraries that do not normally -accompany the operating system. Such a contradiction means you cannot -use both them and the Library together in an executable that you -distribute. - - 7. You may place library facilities that are a work based on the -Library side-by-side in a single library together with other library -facilities not covered by this License, and distribute such a combined -library, provided that the separate distribution of the work based on -the Library and of the other library facilities is otherwise -permitted, and provided that you do these two things: - - a) Accompany the combined library with a copy of the same work - based on the Library, uncombined with any other library - facilities. This must be distributed under the terms of the - Sections above. - - b) Give prominent notice with the combined library of the fact - that part of it is a work based on the Library, and explaining - where to find the accompanying uncombined form of the same work. - - 8. You may not copy, modify, sublicense, link with, or distribute -the Library except as expressly provided under this License. Any -attempt otherwise to copy, modify, sublicense, link with, or -distribute the Library is void, and will automatically terminate your -rights under this License. However, parties who have received copies, -or rights, from you under this License will not have their licenses -terminated so long as such parties remain in full compliance. - - 9. You are not required to accept this License, since you have not -signed it. However, nothing else grants you permission to modify or -distribute the Library or its derivative works. These actions are -prohibited by law if you do not accept this License. Therefore, by -modifying or distributing the Library (or any work based on the -Library), you indicate your acceptance of this License to do so, and -all its terms and conditions for copying, distributing or modifying -the Library or works based on it. - - 10. Each time you redistribute the Library (or any work based on the -Library), the recipient automatically receives a license from the -original licensor to copy, distribute, link with or modify the Library -subject to these terms and conditions. You may not impose any further -restrictions on the recipients' exercise of the rights granted herein. -You are not responsible for enforcing compliance by third parties with -this License. - - 11. If, as a consequence of a court judgment or allegation of patent -infringement or for any other reason (not limited to patent issues), -conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot -distribute so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you -may not distribute the Library at all. For example, if a patent -license would not permit royalty-free redistribution of the Library by -all those who receive copies directly or indirectly through you, then -the only way you could satisfy both it and this License would be to -refrain entirely from distribution of the Library. - -If any portion of this section is held invalid or unenforceable under any -particular circumstance, the balance of the section is intended to apply, -and the section as a whole is intended to apply in other circumstances. - -It is not the purpose of this section to induce you to infringe any -patents or other property right claims or to contest validity of any -such claims; this section has the sole purpose of protecting the -integrity of the free software distribution system which is -implemented by public license practices. Many people have made -generous contributions to the wide range of software distributed -through that system in reliance on consistent application of that -system; it is up to the author/donor to decide if he or she is willing -to distribute software through any other system and a licensee cannot -impose that choice. - -This section is intended to make thoroughly clear what is believed to -be a consequence of the rest of this License. - - 12. If the distribution and/or use of the Library is restricted in -certain countries either by patents or by copyrighted interfaces, the -original copyright holder who places the Library under this License may add -an explicit geographical distribution limitation excluding those countries, -so that distribution is permitted only in or among countries not thus -excluded. In such case, this License incorporates the limitation as if -written in the body of this License. - - 13. The Free Software Foundation may publish revised and/or new -versions of the Lesser General Public License from time to time. -Such new versions will be similar in spirit to the present version, -but may differ in detail to address new problems or concerns. - -Each version is given a distinguishing version number. If the Library -specifies a version number of this License which applies to it and -"any later version", you have the option of following the terms and -conditions either of that version or of any later version published by -the Free Software Foundation. If the Library does not specify a -license version number, you may choose any version ever published by -the Free Software Foundation. - - 14. If you wish to incorporate parts of the Library into other free -programs whose distribution conditions are incompatible with these, -write to the author to ask for permission. For software which is -copyrighted by the Free Software Foundation, write to the Free -Software Foundation; we sometimes make exceptions for this. Our -decision will be guided by the two goals of preserving the free status -of all derivatives of our free software and of promoting the sharing -and reuse of software generally. - - NO WARRANTY - - 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO -WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. -EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR -OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY -KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE -LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME -THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. - - 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN -WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY -AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU -FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR -CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE -LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING -RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A -FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF -SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH -DAMAGES. - - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Libraries - - If you develop a new library, and you want it to be of the greatest -possible use to the public, we recommend making it free software that -everyone can redistribute and change. You can do so by permitting -redistribution under these terms (or, alternatively, under the terms of the -ordinary General Public License). - - To apply these terms, attach the following notices to the library. It is -safest to attach them to the start of each source file to most effectively -convey the exclusion of warranty; and each file should have at least the -"copyright" line and a pointer to where the full notice is found. - - - Copyright (C) - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library 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 - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -Also add information on how to contact you by electronic and paper mail. - -You should also get your employer (if you work as a programmer) or your -school, if any, to sign a "copyright disclaimer" for the library, if -necessary. Here is a sample; alter the names: - - Yoyodyne, Inc., hereby disclaims all copyright interest in the - library `Frob' (a library for tweaking knobs) written by James Random Hacker. - - , 1 April 1990 - Ty Coon, President of Vice - -That's all there is to it! -""" - - -class _StringGenerator(object): - def __init__(self, string): - self.string = string - self.index = -1 - def peek(self): - i = self.index + 1 - if i < len(self.string): - return self.string[i] - else: - return None - def next(self): - self.index += 1 - if self.index < len(self.string): - return self.string[self.index] - else: - raise StopIteration - def all(self): - return self.string - -class WriteException(Exception): - pass - -class ReadException(Exception): - pass - -class JsonReader(object): - hex_digits = {'A': 10,'B': 11,'C': 12,'D': 13,'E': 14,'F':15} - escapes = {'t':'\t','n':'\n','f':'\f','r':'\r','b':'\b'} - - def read(self, s): - self._generator = _StringGenerator(s) - result = self._read() - return result - - def _read(self): - self._eatWhitespace() - peek = self._peek() - if peek is None: - raise ReadException, "Nothing to read: '%s'" % self._generator.all() - if peek == '{': - return self._readObject() - elif peek == '[': - return self._readArray() - elif peek == '"': - return self._readString() - elif peek == '-' or peek.isdigit(): - return self._readNumber() - elif peek == 't': - return self._readTrue() - elif peek == 'f': - return self._readFalse() - elif peek == 'n': - return self._readNull() - elif peek == '/': - self._readComment() - return self._read() - else: - raise ReadException, "Input is not valid JSON: '%s'" % self._generator.all() - - def _readTrue(self): - self._assertNext('t', "true") - self._assertNext('r', "true") - self._assertNext('u', "true") - self._assertNext('e', "true") - return True - - def _readFalse(self): - self._assertNext('f', "false") - self._assertNext('a', "false") - self._assertNext('l', "false") - self._assertNext('s', "false") - self._assertNext('e', "false") - return False - - def _readNull(self): - self._assertNext('n', "null") - self._assertNext('u', "null") - self._assertNext('l', "null") - self._assertNext('l', "null") - return None - - def _assertNext(self, ch, target): - if self._next() != ch: - raise ReadException, "Trying to read %s: '%s'" % (target, self._generator.all()) - - def _readNumber(self): - isfloat = False - result = self._next() - peek = self._peek() - while peek is not None and (peek.isdigit() or peek == "."): - isfloat = isfloat or peek == "." - result = result + self._next() - peek = self._peek() - try: - if isfloat: - return float(result) - else: - return int(result) - except ValueError: - raise ReadException, "Not a valid JSON number: '%s'" % result - - def _readString(self): - result = "" - assert self._next() == '"' - try: - while self._peek() != '"': - ch = self._next() - if ch == "\\": - ch = self._next() - if ch in 'brnft': - ch = self.escapes[ch] - elif ch == "u": - ch4096 = self._next() - ch256 = self._next() - ch16 = self._next() - ch1 = self._next() - n = 4096 * self._hexDigitToInt(ch4096) - n += 256 * self._hexDigitToInt(ch256) - n += 16 * self._hexDigitToInt(ch16) - n += self._hexDigitToInt(ch1) - ch = unichr(n) - elif ch not in '"/\\': - raise ReadException, "Not a valid escaped JSON character: '%s' in %s" % (ch, self._generator.all()) - result = result + ch - except StopIteration: - raise ReadException, "Not a valid JSON string: '%s'" % self._generator.all() - assert self._next() == '"' - return result - - def _hexDigitToInt(self, ch): - try: - result = self.hex_digits[ch.upper()] - except KeyError: - try: - result = int(ch) - except ValueError: - raise ReadException, "The character %s is not a hex digit." % ch - return result - - def _readComment(self): - assert self._next() == "/" - second = self._next() - if second == "/": - self._readDoubleSolidusComment() - elif second == '*': - self._readCStyleComment() - else: - raise ReadException, "Not a valid JSON comment: %s" % self._generator.all() - - def _readCStyleComment(self): - try: - done = False - while not done: - ch = self._next() - done = (ch == "*" and self._peek() == "/") - if not done and ch == "/" and self._peek() == "*": - raise ReadException, "Not a valid JSON comment: %s, '/*' cannot be embedded in the comment." % self._generator.all() - self._next() - except StopIteration: - raise ReadException, "Not a valid JSON comment: %s, expected */" % self._generator.all() - - def _readDoubleSolidusComment(self): - try: - ch = self._next() - while ch != "\r" and ch != "\n": - ch = self._next() - except StopIteration: - pass - - def _readArray(self): - result = [] - assert self._next() == '[' - done = self._peek() == ']' - while not done: - item = self._read() - result.append(item) - self._eatWhitespace() - done = self._peek() == ']' - if not done: - ch = self._next() - if ch != ",": - raise ReadException, "Not a valid JSON array: '%s' due to: '%s'" % (self._generator.all(), ch) - assert ']' == self._next() - return result - - def _readObject(self): - result = {} - assert self._next() == '{' - done = self._peek() == '}' - while not done: - key = self._read() - if type(key) is not types.StringType: - raise ReadException, "Not a valid JSON object key (should be a string): %s" % key - self._eatWhitespace() - ch = self._next() - if ch != ":": - raise ReadException, "Not a valid JSON object: '%s' due to: '%s'" % (self._generator.all(), ch) - self._eatWhitespace() - val = self._read() - result[key] = val - self._eatWhitespace() - done = self._peek() == '}' - if not done: - ch = self._next() - if ch != ",": - raise ReadException, "Not a valid JSON array: '%s' due to: '%s'" % (self._generator.all(), ch) - assert self._next() == "}" - return result - - def _eatWhitespace(self): - p = self._peek() - while p is not None and p in string.whitespace or p == '/': - if p == '/': - self._readComment() - else: - self._next() - p = self._peek() - - def _peek(self): - return self._generator.peek() - - def _next(self): - return self._generator.next() - -class JsonWriter(object): - - def _append(self, s): - self._results.append(s) - - def write(self, obj, escaped_forward_slash=False): - self._escaped_forward_slash = escaped_forward_slash - self._results = [] - self._write(obj) - return "".join(self._results) - - def _write(self, obj): - ty = type(obj) - if ty is types.DictType: - n = len(obj) - self._append("{") - for k, v in obj.items(): - self._write(k) - self._append(":") - self._write(v) - n = n - 1 - if n > 0: - self._append(",") - self._append("}") - elif ty is types.ListType or ty is types.TupleType: - n = len(obj) - self._append("[") - for item in obj: - self._write(item) - n = n - 1 - if n > 0: - self._append(",") - self._append("]") - elif ty is types.StringType or ty is types.UnicodeType: - self._append('"') - obj = obj.replace('\\', r'\\') - if self._escaped_forward_slash: - obj = obj.replace('/', r'\/') - obj = obj.replace('"', r'\"') - obj = obj.replace('\b', r'\b') - obj = obj.replace('\f', r'\f') - obj = obj.replace('\n', r'\n') - obj = obj.replace('\r', r'\r') - obj = obj.replace('\t', r'\t') - self._append(obj) - self._append('"') - elif ty is types.IntType or ty is types.LongType: - self._append(str(obj)) - elif ty is types.FloatType: - self._append("%f" % obj) - elif obj is True: - self._append("true") - elif obj is False: - self._append("false") - elif obj is None: - self._append("null") - else: - raise WriteException, "Cannot write in JSON: %s" % repr(obj) - -def write(obj, escaped_forward_slash=False): - return JsonWriter().write(obj, escaped_forward_slash) - -def read(s): - return JsonReader().read(s) diff --git a/deluge/ui/webui/lib/newforms_plus.py b/deluge/ui/webui/lib/newforms_plus.py deleted file mode 100644 index 66b3145f7..000000000 --- a/deluge/ui/webui/lib/newforms_plus.py +++ /dev/null @@ -1,255 +0,0 @@ -# -*- coding: utf-8 -*- -# -# Copyright (C) Martijn Voncken 2008 -# -# FilteredForm contains code copied from django newforms : -# Copyright (c) 2005, the Lawrence Journal-World -# -# Django Licence, see ./newforms_portable/LICENCE -# - -from newforms_portable import * -import newforms_portable as newforms -from newforms_portable.forms import BoundField -from newforms_portable.util import ErrorList, escape - - -import sys, os - -import web - -#Form -class FilteredForm(newforms.Form): - """ - used to enable more complex layouts. - the filter argument contains the names of the fields to render. - """ - def _html_output_filtered(self, normal_row, error_row, row_ender, help_text_html, errors_on_separate_row, filter): - """ - Helper function for outputting HTML. Used by as_table(), as_ul(), as_p(). - newforms_plus: 99% c&p from newforms, added filter. - """ - top_errors = self.non_field_errors() # Errors that should be displayed above all fields. - output, hidden_fields = [], [] - for name, field in self.fields.items(): - #FilteredForm - if (filter != None) and (not name in filter): - continue - #/FilteredForm - bf = BoundField(self, field, name) - bf_errors = ErrorList([escape(error) for error in bf.errors]) # Escape and cache in local variable. - if bf.is_hidden: - if bf_errors: - top_errors.extend(['(Hidden field %s) %s' % (name, e) for e in bf_errors]) - hidden_fields.append(unicode(bf)) - else: - if errors_on_separate_row and bf_errors: - output.append(error_row % bf_errors) - label = bf.label and bf.label_tag(escape(bf.label + ':')) or '' - if field.help_text: - help_text = help_text_html % field.help_text - else: - help_text = u'' - output.append(normal_row % {'errors': bf_errors, 'label': label, 'field': unicode(bf), 'help_text': help_text}) - if top_errors: - output.insert(0, error_row % top_errors) - if hidden_fields: # Insert any hidden fields in the last row. - str_hidden = u''.join(hidden_fields) - if output: - last_row = output[-1] - # Chop off the trailing row_ender (e.g. '') and insert the hidden fields. - output[-1] = last_row[:-len(row_ender)] + str_hidden + row_ender - else: # If there aren't any rows in the output, just append the hidden fields. - output.append(str_hidden) - return u'\n'.join(output) - - def as_table(self , filter = None): #add class="newforms" - "Returns this form rendered as HTML s -- excluding the
." - return self._html_output_filtered(u'%(label)s%(errors)s%(field)s%(help_text)s', u'%s', '', u'
%s', False, filter) - - def as_ul(self, filter = None): - "Returns this form rendered as HTML
  • s -- excluding the
      ." - return self._html_output_filtered(u'
    • %(errors)s%(label)s %(field)s%(help_text)s
    • ', u'
    • %s
    • ', '', u' %s', False , filter) - - def as_p(self , filter = None): - "Returns this form rendered as HTML

      s." - return self._html_output_filtered(u'

      %(label)s %(field)s%(help_text)s

      ', u'

      %s

      ', '

      ', u' %s', True, filter) - -class Form(FilteredForm): - info = "" - title = "No Title" - - def __init__(self,data = None): - if data == None: - data = self.initial_data() - newforms.Form.__init__(self,data) - - def initial_data(self): - "override in subclass" - return None - - def start_save(self): - "called by config_page" - data = web.Storage(self.cleaned_data) - self.validate(data) - self.save(data) - self.post_save() - - def save(self, vars): - "override in subclass" - raise NotImplementedError() - - def post_save(self): - pass - - def validate(self, data): - pass - - def pre_html(self): - return '' - - def post_html(self): - return '' - - -#convenience Input Fields. -class CheckBox(newforms.BooleanField): - "Non Required BooleanField,why the f is it required by default?" - def __init__(self,label, **kwargs): - newforms.BooleanField.__init__(self,label=label,required=False,**kwargs) - -class IntChoiceField(newforms.ChoiceField): - """same as ChoiceField, but returns an int - hint : Use IntChoiceField(choices=enumerate("list","of","strings"])) - for index-based values on a list of strings. - """ - def __init__(self, label, choices, **kwargs): - newforms.ChoiceField.__init__(self, label=label, choices=choices,**kwargs) - - def clean(self, value): - return int(newforms.ChoiceField.clean(self, value)) - -class ServerFolder(newforms.CharField): - def __init__(self, label, **kwargs): - newforms.CharField.__init__(self, label=label,**kwargs) - - def clean(self, value): - if value == None: - value = "" - value = value.rstrip('/').rstrip('\\') - self.validate(value) - return newforms.CharField.clean(self, value) - - def validate(self, value): - if (value and not os.path.isdir(value)): - raise newforms.ValidationError(_("This folder does not exist.")) - -class Password(newforms.CharField): - def __init__(self, label, **kwargs): - newforms.CharField.__init__(self, label=label, widget=newforms.PasswordInput, - **kwargs) - -#Lazy multiple select: -class _LazyCheckboxSelectMultiple(newforms.CheckboxSelectMultiple): - """ - choices are not know at define-time - choices_getter returns self.choices. - """ - def __init__(self, attrs=None,choices_getter = None): - self.choices_getter = choices_getter - newforms.CheckboxSelectMultiple.__init__(self,attrs) - - def render(self, name, value, attrs=None, choices=()): - self.choices = self.choices_getter() - return newforms.CheckboxSelectMultiple.render(self, name, value, attrs, choices) - - -class LazyMultipleChoice(newforms.MultipleChoiceField): - """ - choices are not know at define-time - choices_getter returns self.choices. - defaults to non-required. - """ - def __init__(self, label = "",widget=_LazyCheckboxSelectMultiple, - choices_getter = None, **kwargs): - - self.choices_getter = choices_getter - #default to non-required - if not 'required' in kwargs: - kwargs['required'] = False - #init, and pass get_choices to the widget. - newforms.MultipleChoiceField.__init__(self, label=label, - widget=widget(choices_getter=choices_getter),**kwargs) - - def clean(self, value): - self.choices = self.choices_getter() - return newforms.MultipleChoiceField.clean(self, value) - -#Deluge specific: -class _DelugeIntInputWidget(newforms.TextInput): - """ - because deluge-floats are edited as ints. - """ - def render(self, name, value, attrs=None): - try: - value = int(float(value)) - if value == -1 or value == None: - value = _("Unlimited") - except: - pass - return newforms.TextInput.render(self, name, value, attrs) - -class IntegerField(newforms.IntegerField): - def widget_attrs(self, widget): - return {'size': "8"} - -class FloatField(newforms.FloatField): - def widget_attrs(self, widget): - return {'size': "8"} - -class DelugeInt(IntegerField): - def __init__(self, label , **kwargs): - newforms.IntegerField.__init__(self, label=label, min_value=-1, - max_value=sys.maxint, widget=_DelugeIntInputWidget, **kwargs) - - def clean(self, value): - if str(value).lower() == _('Unlimited').lower(): - value = -1 - return int(newforms.IntegerField.clean(self, value)) - -class DelugeFloat(DelugeInt): - def clean(self, value): - try: - value = int(float(value)) #float->int - except: - pass - return float(DelugeInt.clean(self, value)) - - -class StringList(Field): - """for a list of strings """ - def __init__(self, label, *args, **kwargs): - if not "widget" in kwargs: - kwargs["widget"] = StringListWidget - newforms.Field.__init__(self, *args, **kwargs) - - def clean(self, value): - if type(value) in [str, unicode]: #bug - return value.split("/n") - -class StringListWidget(newforms.Textarea): - """for a list of strings """ - def __init__(self, attrs=None): - newforms.Textarea.__init__(self, attrs) - - def render(self, name, value, attrs=None): - if type(value) in [list, tuple]: #bug - value = "\n".join(value) - return newforms.Textarea.render(self, name, value, attrs) - -#/fields - - - - - diff --git a/deluge/ui/webui/lib/newforms_portable/LICENSE b/deluge/ui/webui/lib/newforms_portable/LICENSE deleted file mode 100644 index ba3e68a06..000000000 --- a/deluge/ui/webui/lib/newforms_portable/LICENSE +++ /dev/null @@ -1,27 +0,0 @@ -Copyright (c) 2005, the Lawrence Journal-World -All rights reserved. - -Redistribution and use in source and binary forms, with or without modification, -are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - - 3. Neither the name of Django nor the names of its contributors may be used - to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR -ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON -ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. \ No newline at end of file diff --git a/deluge/ui/webui/lib/newforms_portable/__init__.py b/deluge/ui/webui/lib/newforms_portable/__init__.py deleted file mode 100644 index a34f46c8e..000000000 --- a/deluge/ui/webui/lib/newforms_portable/__init__.py +++ /dev/null @@ -1,18 +0,0 @@ -""" -Django validation and HTML form handling. - -TODO: - Default value for field - Field labels - Nestable Forms - FatalValidationError -- short-circuits all other validators on a form - ValidationWarning - "This form field requires foo.js" and form.js_includes() -""" - -from util import ValidationError -from widgets import * -from fields import * -from forms import * -from models import * -import django diff --git a/deluge/ui/webui/lib/newforms_portable/about.txt b/deluge/ui/webui/lib/newforms_portable/about.txt deleted file mode 100644 index 333869ab8..000000000 --- a/deluge/ui/webui/lib/newforms_portable/about.txt +++ /dev/null @@ -1,3 +0,0 @@ -based on django rev.7350 -,/django/ contains the parts of django required to run newforms. - diff --git a/deluge/ui/webui/lib/newforms_portable/django/__init__.py b/deluge/ui/webui/lib/newforms_portable/django/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/deluge/ui/webui/lib/newforms_portable/django/core/__init__.py b/deluge/ui/webui/lib/newforms_portable/django/core/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/deluge/ui/webui/lib/newforms_portable/django/core/exceptions.py b/deluge/ui/webui/lib/newforms_portable/django/core/exceptions.py deleted file mode 100644 index d9fc326cf..000000000 --- a/deluge/ui/webui/lib/newforms_portable/django/core/exceptions.py +++ /dev/null @@ -1,29 +0,0 @@ -"Global Django exceptions" - -class ObjectDoesNotExist(Exception): - "The requested object does not exist" - silent_variable_failure = True - -class MultipleObjectsReturned(Exception): - "The query returned multiple objects when only one was expected." - pass - -class SuspiciousOperation(Exception): - "The user did something suspicious" - pass - -class PermissionDenied(Exception): - "The user did not have permission to do that" - pass - -class ViewDoesNotExist(Exception): - "The requested view does not exist" - pass - -class MiddlewareNotUsed(Exception): - "This middleware is not used in this server configuration" - pass - -class ImproperlyConfigured(Exception): - "Django is somehow improperly configured" - pass diff --git a/deluge/ui/webui/lib/newforms_portable/django/utils/__init__.py b/deluge/ui/webui/lib/newforms_portable/django/utils/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/deluge/ui/webui/lib/newforms_portable/django/utils/datastructures.py b/deluge/ui/webui/lib/newforms_portable/django/utils/datastructures.py deleted file mode 100644 index 4c278c0d8..000000000 --- a/deluge/ui/webui/lib/newforms_portable/django/utils/datastructures.py +++ /dev/null @@ -1,345 +0,0 @@ -class MergeDict(object): - """ - A simple class for creating new "virtual" dictionaries that actually look - up values in more than one dictionary, passed in the constructor. - - If a key appears in more than one of the given dictionaries, only the - first occurrence will be used. - """ - def __init__(self, *dicts): - self.dicts = dicts - - def __getitem__(self, key): - for dict_ in self.dicts: - try: - return dict_[key] - except KeyError: - pass - raise KeyError - - def __copy__(self): - return self.__class__(*self.dicts) - - def get(self, key, default=None): - try: - return self[key] - except KeyError: - return default - - def getlist(self, key): - for dict_ in self.dicts: - if key in dict_.keys(): - return dict_.getlist(key) - return [] - - def items(self): - item_list = [] - for dict_ in self.dicts: - item_list.extend(dict_.items()) - return item_list - - def has_key(self, key): - for dict_ in self.dicts: - if key in dict_: - return True - return False - - __contains__ = has_key - - def copy(self): - """Returns a copy of this object.""" - return self.__copy__() - -class SortedDict(dict): - """ - A dictionary that keeps its keys in the order in which they're inserted. - """ - def __init__(self, data=None): - if data is None: - data = {} - super(SortedDict, self).__init__(data) - if isinstance(data, dict): - self.keyOrder = data.keys() - else: - self.keyOrder = [] - for key, value in data: - if key not in self.keyOrder: - self.keyOrder.append(key) - - def __deepcopy__(self, memo): - from copy import deepcopy - return self.__class__([(key, deepcopy(value, memo)) - for key, value in self.iteritems()]) - - def __setitem__(self, key, value): - super(SortedDict, self).__setitem__(key, value) - if key not in self.keyOrder: - self.keyOrder.append(key) - - def __delitem__(self, key): - super(SortedDict, self).__delitem__(key) - self.keyOrder.remove(key) - - def __iter__(self): - for k in self.keyOrder: - yield k - - def pop(self, k, *args): - result = super(SortedDict, self).pop(k, *args) - try: - self.keyOrder.remove(k) - except ValueError: - # Key wasn't in the dictionary in the first place. No problem. - pass - return result - - def popitem(self): - result = super(SortedDict, self).popitem() - self.keyOrder.remove(result[0]) - return result - - def items(self): - return zip(self.keyOrder, self.values()) - - def iteritems(self): - for key in self.keyOrder: - yield key, super(SortedDict, self).__getitem__(key) - - def keys(self): - return self.keyOrder[:] - - def iterkeys(self): - return iter(self.keyOrder) - - def values(self): - return [super(SortedDict, self).__getitem__(k) for k in self.keyOrder] - - def itervalues(self): - for key in self.keyOrder: - yield super(SortedDict, self).__getitem__(key) - - def update(self, dict_): - for k, v in dict_.items(): - self.__setitem__(k, v) - - def setdefault(self, key, default): - if key not in self.keyOrder: - self.keyOrder.append(key) - return super(SortedDict, self).setdefault(key, default) - - def value_for_index(self, index): - """Returns the value of the item at the given zero-based index.""" - return self[self.keyOrder[index]] - - def insert(self, index, key, value): - """Inserts the key, value pair before the item with the given index.""" - if key in self.keyOrder: - n = self.keyOrder.index(key) - del self.keyOrder[n] - if n < index: - index -= 1 - self.keyOrder.insert(index, key) - super(SortedDict, self).__setitem__(key, value) - - def copy(self): - """Returns a copy of this object.""" - # This way of initializing the copy means it works for subclasses, too. - obj = self.__class__(self) - obj.keyOrder = self.keyOrder[:] - return obj - - def __repr__(self): - """ - Replaces the normal dict.__repr__ with a version that returns the keys - in their sorted order. - """ - return '{%s}' % ', '.join(['%r: %r' % (k, v) for k, v in self.items()]) - - def clear(self): - super(SortedDict, self).clear() - self.keyOrder = [] - -class MultiValueDictKeyError(KeyError): - pass - -class MultiValueDict(dict): - """ - A subclass of dictionary customized to handle multiple values for the - same key. - - >>> d = MultiValueDict({'name': ['Adrian', 'Simon'], 'position': ['Developer']}) - >>> d['name'] - 'Simon' - >>> d.getlist('name') - ['Adrian', 'Simon'] - >>> d.get('lastname', 'nonexistent') - 'nonexistent' - >>> d.setlist('lastname', ['Holovaty', 'Willison']) - - This class exists to solve the irritating problem raised by cgi.parse_qs, - which returns a list for every key, even though most Web forms submit - single name-value pairs. - """ - def __init__(self, key_to_list_mapping=()): - super(MultiValueDict, self).__init__(key_to_list_mapping) - - def __repr__(self): - return "<%s: %s>" % (self.__class__.__name__, - super(MultiValueDict, self).__repr__()) - - def __getitem__(self, key): - """ - Returns the last data value for this key, or [] if it's an empty list; - raises KeyError if not found. - """ - try: - list_ = super(MultiValueDict, self).__getitem__(key) - except KeyError: - raise MultiValueDictKeyError, "Key %r not found in %r" % (key, self) - try: - return list_[-1] - except IndexError: - return [] - - def __setitem__(self, key, value): - super(MultiValueDict, self).__setitem__(key, [value]) - - def __copy__(self): - return self.__class__(super(MultiValueDict, self).items()) - - def __deepcopy__(self, memo=None): - import copy - if memo is None: - memo = {} - result = self.__class__() - memo[id(self)] = result - for key, value in dict.items(self): - dict.__setitem__(result, copy.deepcopy(key, memo), - copy.deepcopy(value, memo)) - return result - - def get(self, key, default=None): - """ - Returns the last data value for the passed key. If key doesn't exist - or value is an empty list, then default is returned. - """ - try: - val = self[key] - except KeyError: - return default - if val == []: - return default - return val - - def getlist(self, key): - """ - Returns the list of values for the passed key. If key doesn't exist, - then an empty list is returned. - """ - try: - return super(MultiValueDict, self).__getitem__(key) - except KeyError: - return [] - - def setlist(self, key, list_): - super(MultiValueDict, self).__setitem__(key, list_) - - def setdefault(self, key, default=None): - if key not in self: - self[key] = default - return self[key] - - def setlistdefault(self, key, default_list=()): - if key not in self: - self.setlist(key, default_list) - return self.getlist(key) - - def appendlist(self, key, value): - """Appends an item to the internal list associated with key.""" - self.setlistdefault(key, []) - super(MultiValueDict, self).__setitem__(key, self.getlist(key) + [value]) - - def items(self): - """ - Returns a list of (key, value) pairs, where value is the last item in - the list associated with the key. - """ - return [(key, self[key]) for key in self.keys()] - - def lists(self): - """Returns a list of (key, list) pairs.""" - return super(MultiValueDict, self).items() - - def values(self): - """Returns a list of the last value on every key list.""" - return [self[key] for key in self.keys()] - - def copy(self): - """Returns a copy of this object.""" - return self.__deepcopy__() - - def update(self, *args, **kwargs): - """ - update() extends rather than replaces existing key lists. - Also accepts keyword args. - """ - if len(args) > 1: - raise TypeError, "update expected at most 1 arguments, got %d" % len(args) - if args: - other_dict = args[0] - if isinstance(other_dict, MultiValueDict): - for key, value_list in other_dict.lists(): - self.setlistdefault(key, []).extend(value_list) - else: - try: - for key, value in other_dict.items(): - self.setlistdefault(key, []).append(value) - except TypeError: - raise ValueError, "MultiValueDict.update() takes either a MultiValueDict or dictionary" - for key, value in kwargs.iteritems(): - self.setlistdefault(key, []).append(value) - -class DotExpandedDict(dict): - """ - A special dictionary constructor that takes a dictionary in which the keys - may contain dots to specify inner dictionaries. It's confusing, but this - example should make sense. - - >>> d = DotExpandedDict({'person.1.firstname': ['Simon'], \ - 'person.1.lastname': ['Willison'], \ - 'person.2.firstname': ['Adrian'], \ - 'person.2.lastname': ['Holovaty']}) - >>> d - {'person': {'1': {'lastname': ['Willison'], 'firstname': ['Simon']}, '2': {'lastname': ['Holovaty'], 'firstname': ['Adrian']}}} - >>> d['person'] - {'1': {'lastname': ['Willison'], 'firstname': ['Simon']}, '2': {'lastname': ['Holovaty'], 'firstname': ['Adrian']}} - >>> d['person']['1'] - {'lastname': ['Willison'], 'firstname': ['Simon']} - - # Gotcha: Results are unpredictable if the dots are "uneven": - >>> DotExpandedDict({'c.1': 2, 'c.2': 3, 'c': 1}) - {'c': 1} - """ - def __init__(self, key_to_list_mapping): - for k, v in key_to_list_mapping.items(): - current = self - bits = k.split('.') - for bit in bits[:-1]: - current = current.setdefault(bit, {}) - # Now assign value to current position - try: - current[bits[-1]] = v - except TypeError: # Special-case if current isn't a dict. - current = {bits[-1]: v} - -class FileDict(dict): - """ - A dictionary used to hold uploaded file contents. The only special feature - here is that repr() of this object won't dump the entire contents of the - file to the output. A handy safeguard for a large file upload. - """ - def __repr__(self): - if 'content' in self: - d = dict(self, content='') - return dict.__repr__(d) - return dict.__repr__(self) diff --git a/deluge/ui/webui/lib/newforms_portable/django/utils/encoding.py b/deluge/ui/webui/lib/newforms_portable/django/utils/encoding.py deleted file mode 100644 index 2b5219cc6..000000000 --- a/deluge/ui/webui/lib/newforms_portable/django/utils/encoding.py +++ /dev/null @@ -1,102 +0,0 @@ -import types -import urllib -import datetime - -from functional import Promise -from safestring import SafeData, mark_safe - -class DjangoUnicodeDecodeError(UnicodeDecodeError): - def __init__(self, obj, *args): - self.obj = obj - UnicodeDecodeError.__init__(self, *args) - - def __str__(self): - original = UnicodeDecodeError.__str__(self) - return '%s. You passed in %r (%s)' % (original, self.obj, - type(self.obj)) - -class StrAndUnicode(object): - """ - A class whose __str__ returns its __unicode__ as a UTF-8 bytestring. - - Useful as a mix-in. - """ - def __str__(self): - return self.__unicode__().encode('utf-8') - -def smart_unicode(s, encoding='utf-8', strings_only=False, errors='strict'): - """ - Returns a unicode object representing 's'. Treats bytestrings using the - 'encoding' codec. - - If strings_only is True, don't convert (some) non-string-like objects. - """ - if isinstance(s, Promise): - # The input is the result of a gettext_lazy() call. - return s - return force_unicode(s, encoding, strings_only, errors) - -def force_unicode(s, encoding='utf-8', strings_only=False, errors='strict'): - """ - Similar to smart_unicode, except that lazy instances are resolved to - strings, rather than kept as lazy objects. - - If strings_only is True, don't convert (some) non-string-like objects. - """ - if strings_only and isinstance(s, (types.NoneType, int, long, datetime.datetime, datetime.date, datetime.time, float)): - return s - try: - if not isinstance(s, basestring,): - if hasattr(s, '__unicode__'): - s = unicode(s) - else: - s = unicode(str(s), encoding, errors) - elif not isinstance(s, unicode): - # Note: We use .decode() here, instead of unicode(s, encoding, - # errors), so that if s is a SafeString, it ends up being a - # SafeUnicode at the end. - s = s.decode(encoding, errors) - except UnicodeDecodeError, e: - raise DjangoUnicodeDecodeError(s, *e.args) - return s - -def smart_str(s, encoding='utf-8', strings_only=False, errors='strict'): - """ - Returns a bytestring version of 's', encoded as specified in 'encoding'. - - If strings_only is True, don't convert (some) non-string-like objects. - """ - if strings_only and isinstance(s, (types.NoneType, int)): - return s - if isinstance(s, Promise): - return unicode(s).encode(encoding, errors) - elif not isinstance(s, basestring): - try: - return str(s) - except UnicodeEncodeError: - return unicode(s).encode(encoding, errors) - elif isinstance(s, unicode): - return s.encode(encoding, errors) - elif s and encoding != 'utf-8': - return s.decode('utf-8', errors).encode(encoding, errors) - else: - return s - -def iri_to_uri(iri): - """ - Convert an Internationalized Resource Identifier (IRI) portion to a URI - portion that is suitable for inclusion in a URL. - - This is the algorithm from section 3.1 of RFC 3987. However, since we are - assuming input is either UTF-8 or unicode already, we can simplify things a - little from the full method. - - Returns an ASCII string containing the encoded result. - """ - # The list of safe characters here is constructed from the printable ASCII - # characters that are not explicitly excluded by the list at the end of - # section 3.1 of RFC 3987. - if iri is None: - return iri - return urllib.quote(smart_str(iri), safe='/#%[]=:;$&()+,!?*') - diff --git a/deluge/ui/webui/lib/newforms_portable/django/utils/functional.py b/deluge/ui/webui/lib/newforms_portable/django/utils/functional.py deleted file mode 100644 index 3de693e18..000000000 --- a/deluge/ui/webui/lib/newforms_portable/django/utils/functional.py +++ /dev/null @@ -1,241 +0,0 @@ -# License for code in this file that was taken from Python 2.5. - -# PYTHON SOFTWARE FOUNDATION LICENSE VERSION 2 -# -------------------------------------------- -# -# 1. This LICENSE AGREEMENT is between the Python Software Foundation -# ("PSF"), and the Individual or Organization ("Licensee") accessing and -# otherwise using this software ("Python") in source or binary form and -# its associated documentation. -# -# 2. Subject to the terms and conditions of this License Agreement, PSF -# hereby grants Licensee a nonexclusive, royalty-free, world-wide -# license to reproduce, analyze, test, perform and/or display publicly, -# prepare derivative works, distribute, and otherwise use Python -# alone or in any derivative version, provided, however, that PSF's -# License Agreement and PSF's notice of copyright, i.e., "Copyright (c) -# 2001, 2002, 2003, 2004, 2005, 2006, 2007 Python Software Foundation; -# All Rights Reserved" are retained in Python alone or in any derivative -# version prepared by Licensee. -# -# 3. In the event Licensee prepares a derivative work that is based on -# or incorporates Python or any part thereof, and wants to make -# the derivative work available to others as provided herein, then -# Licensee hereby agrees to include in any such work a brief summary of -# the changes made to Python. -# -# 4. PSF is making Python available to Licensee on an "AS IS" -# basis. PSF MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR -# IMPLIED. BY WAY OF EXAMPLE, BUT NOT LIMITATION, PSF MAKES NO AND -# DISCLAIMS ANY REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS -# FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF PYTHON WILL NOT -# INFRINGE ANY THIRD PARTY RIGHTS. -# -# 5. PSF SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF PYTHON -# FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS AS -# A RESULT OF MODIFYING, DISTRIBUTING, OR OTHERWISE USING PYTHON, -# OR ANY DERIVATIVE THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF. -# -# 6. This License Agreement will automatically terminate upon a material -# breach of its terms and conditions. -# -# 7. Nothing in this License Agreement shall be deemed to create any -# relationship of agency, partnership, or joint venture between PSF and -# Licensee. This License Agreement does not grant permission to use PSF -# trademarks or trade name in a trademark sense to endorse or promote -# products or services of Licensee, or any third party. -# -# 8. By copying, installing or otherwise using Python, Licensee -# agrees to be bound by the terms and conditions of this License -# Agreement. - - -def curry(_curried_func, *args, **kwargs): - def _curried(*moreargs, **morekwargs): - return _curried_func(*(args+moreargs), **dict(kwargs, **morekwargs)) - return _curried - -### Begin from Python 2.5 functools.py ######################################## - -# Summary of changes made to the Python 2.5 code below: -# * swapped ``partial`` for ``curry`` to maintain backwards-compatibility -# in Django. -# * Wrapped the ``setattr`` call in ``update_wrapper`` with a try-except -# block to make it compatible with Python 2.3, which doesn't allow -# assigning to ``__name__``. - -# Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007 Python Software Foundation. -# All Rights Reserved. - -############################################################################### - -# update_wrapper() and wraps() are tools to help write -# wrapper functions that can handle naive introspection - -WRAPPER_ASSIGNMENTS = ('__module__', '__name__', '__doc__') -WRAPPER_UPDATES = ('__dict__',) -def update_wrapper(wrapper, - wrapped, - assigned = WRAPPER_ASSIGNMENTS, - updated = WRAPPER_UPDATES): - """Update a wrapper function to look like the wrapped function - - wrapper is the function to be updated - wrapped is the original function - assigned is a tuple naming the attributes assigned directly - from the wrapped function to the wrapper function (defaults to - functools.WRAPPER_ASSIGNMENTS) - updated is a tuple naming the attributes off the wrapper that - are updated with the corresponding attribute from the wrapped - function (defaults to functools.WRAPPER_UPDATES) - """ - for attr in assigned: - try: - setattr(wrapper, attr, getattr(wrapped, attr)) - except TypeError: # Python 2.3 doesn't allow assigning to __name__. - pass - for attr in updated: - getattr(wrapper, attr).update(getattr(wrapped, attr)) - # Return the wrapper so this can be used as a decorator via curry() - return wrapper - -def wraps(wrapped, - assigned = WRAPPER_ASSIGNMENTS, - updated = WRAPPER_UPDATES): - """Decorator factory to apply update_wrapper() to a wrapper function - - Returns a decorator that invokes update_wrapper() with the decorated - function as the wrapper argument and the arguments to wraps() as the - remaining arguments. Default arguments are as for update_wrapper(). - This is a convenience function to simplify applying curry() to - update_wrapper(). - """ - return curry(update_wrapper, wrapped=wrapped, - assigned=assigned, updated=updated) - -### End from Python 2.5 functools.py ########################################## - -def memoize(func, cache, num_args): - """ - Wrap a function so that results for any argument tuple are stored in - 'cache'. Note that the args to the function must be usable as dictionary - keys. - - Only the first num_args are considered when creating the key. - """ - def wrapper(*args): - mem_args = args[:num_args] - if mem_args in cache: - return cache[mem_args] - result = func(*args) - cache[mem_args] = result - return result - return wraps(func)(wrapper) - -class Promise(object): - """ - This is just a base class for the proxy class created in - the closure of the lazy function. It can be used to recognize - promises in code. - """ - pass - -def lazy(func, *resultclasses): - """ - Turns any callable into a lazy evaluated callable. You need to give result - classes or types -- at least one is needed so that the automatic forcing of - the lazy evaluation code is triggered. Results are not memoized; the - function is evaluated on every access. - """ - class __proxy__(Promise): - # This inner class encapsulates the code that should be evaluated - # lazily. On calling of one of the magic methods it will force - # the evaluation and store the result. Afterwards, the result - # is delivered directly. So the result is memoized. - def __init__(self, args, kw): - self.__func = func - self.__args = args - self.__kw = kw - self.__dispatch = {} - for resultclass in resultclasses: - self.__dispatch[resultclass] = {} - for (k, v) in resultclass.__dict__.items(): - setattr(self, k, self.__promise__(resultclass, k, v)) - self._delegate_str = str in resultclasses - self._delegate_unicode = unicode in resultclasses - assert not (self._delegate_str and self._delegate_unicode), "Cannot call lazy() with both str and unicode return types." - if self._delegate_unicode: - # Each call to lazy() makes a new __proxy__ object, so this - # doesn't interfere with any other lazy() results. - __proxy__.__unicode__ = __proxy__.__unicode_cast - elif self._delegate_str: - __proxy__.__str__ = __proxy__.__str_cast - - def __promise__(self, klass, funcname, func): - # Builds a wrapper around some magic method and registers that magic - # method for the given type and method name. - def __wrapper__(*args, **kw): - # Automatically triggers the evaluation of a lazy value and - # applies the given magic method of the result type. - res = self.__func(*self.__args, **self.__kw) - return self.__dispatch[type(res)][funcname](res, *args, **kw) - - if klass not in self.__dispatch: - self.__dispatch[klass] = {} - self.__dispatch[klass][funcname] = func - return __wrapper__ - - def __unicode_cast(self): - return self.__func(*self.__args, **self.__kw) - - def __str_cast(self): - return str(self.__func(*self.__args, **self.__kw)) - - def __cmp__(self, rhs): - if self._delegate_str: - s = str(self.__func(*self.__args, **self.__kw)) - elif self._delegate_unicode: - s = unicode(self.__func(*self.__args, **self.__kw)) - else: - s = self.__func(*self.__args, **self.__kw) - if isinstance(rhs, Promise): - return -cmp(rhs, s) - else: - return cmp(s, rhs) - - def __mod__(self, rhs): - if self._delegate_str: - return str(self) % rhs - elif self._delegate_unicode: - return unicode(self) % rhs - else: - raise AssertionError('__mod__ not supported for non-string types') - - def __deepcopy__(self, memo): - # Instances of this class are effectively immutable. It's just a - # collection of functions. So we don't need to do anything - # complicated for copying. - memo[id(self)] = self - return self - - def __wrapper__(*args, **kw): - # Creates the proxy object, instead of the actual value. - return __proxy__(args, kw) - - return wraps(func)(__wrapper__) - -def allow_lazy(func, *resultclasses): - """ - A decorator that allows a function to be called with one or more lazy - arguments. If none of the args are lazy, the function is evaluated - immediately, otherwise a __proxy__ is returned that will evaluate the - function when needed. - """ - def wrapper(*args, **kwargs): - for arg in list(args) + kwargs.values(): - if isinstance(arg, Promise): - break - else: - return func(*args, **kwargs) - return lazy(func, *resultclasses)(*args, **kwargs) - return wraps(func)(wrapper) diff --git a/deluge/ui/webui/lib/newforms_portable/django/utils/html.py b/deluge/ui/webui/lib/newforms_portable/django/utils/html.py deleted file mode 100644 index f18523e5f..000000000 --- a/deluge/ui/webui/lib/newforms_portable/django/utils/html.py +++ /dev/null @@ -1,163 +0,0 @@ -"""HTML utilities suitable for global use.""" - -import re -import string - -from safestring import SafeData, mark_safe -from encoding import force_unicode -from functional import allow_lazy -from http import urlquote - -# Configuration for urlize() function. -LEADING_PUNCTUATION = ['(', '<', '<'] -TRAILING_PUNCTUATION = ['.', ',', ')', '>', '\n', '>'] - -# List of possible strings used for bullets in bulleted lists. -DOTS = ['·', '*', u'\xe2\x80\xa2', '•', '•', '•'] - -unencoded_ampersands_re = re.compile(r'&(?!(\w+|#\d+);)') -word_split_re = re.compile(r'(\s+)') -punctuation_re = re.compile('^(?P(?:%s)*)(?P.*?)(?P(?:%s)*)$' % \ - ('|'.join([re.escape(x) for x in LEADING_PUNCTUATION]), - '|'.join([re.escape(x) for x in TRAILING_PUNCTUATION]))) -simple_email_re = re.compile(r'^\S+@[a-zA-Z0-9._-]+\.[a-zA-Z0-9._-]+$') -link_target_attribute_re = re.compile(r'(]*?)target=[^\s>]+') -html_gunk_re = re.compile(r'(?:
      |<\/i>|<\/b>|<\/em>|<\/strong>|<\/?smallcaps>|<\/?uppercase>)', re.IGNORECASE) -hard_coded_bullets_re = re.compile(r'((?:

      (?:%s).*?[a-zA-Z].*?

      \s*)+)' % '|'.join([re.escape(x) for x in DOTS]), re.DOTALL) -trailing_empty_content_re = re.compile(r'(?:

      (?: |\s|
      )*?

      \s*)+\Z') -del x # Temporary variable - -def escape(html): - """Returns the given HTML with ampersands, quotes and carets encoded.""" - return mark_safe(force_unicode(html).replace('&', '&').replace('<', '<').replace('>', '>').replace('"', '"').replace("'", ''')) -escape = allow_lazy(escape, unicode) - -def conditional_escape(html): - """ - Similar to escape(), except that it doesn't operate on pre-escaped strings. - """ - if isinstance(html, SafeData): - return html - else: - return escape(html) - -def linebreaks(value, autoescape=False): - """Converts newlines into

      and
      s.""" - value = re.sub(r'\r\n|\r|\n', '\n', force_unicode(value)) # normalize newlines - paras = re.split('\n{2,}', value) - if autoescape: - paras = [u'

      %s

      ' % escape(p.strip()).replace('\n', '
      ') for p in paras] - else: - paras = [u'

      %s

      ' % p.strip().replace('\n', '
      ') for p in paras] - return u'\n\n'.join(paras) -linebreaks = allow_lazy(linebreaks, unicode) - -def strip_tags(value): - """Returns the given HTML with all tags stripped.""" - return re.sub(r'<[^>]*?>', '', force_unicode(value)) -strip_tags = allow_lazy(strip_tags) - -def strip_spaces_between_tags(value): - """Returns the given HTML with spaces between tags removed.""" - return re.sub(r'>\s+<', '><', force_unicode(value)) -strip_spaces_between_tags = allow_lazy(strip_spaces_between_tags, unicode) - -def strip_entities(value): - """Returns the given HTML with all entities (&something;) stripped.""" - return re.sub(r'&(?:\w+|#\d+);', '', force_unicode(value)) -strip_entities = allow_lazy(strip_entities, unicode) - -def fix_ampersands(value): - """Returns the given HTML with all unencoded ampersands encoded correctly.""" - return unencoded_ampersands_re.sub('&', force_unicode(value)) -fix_ampersands = allow_lazy(fix_ampersands, unicode) - -def urlize(text, trim_url_limit=None, nofollow=False, autoescape=False): - """ - Converts any URLs in text into clickable links. - - Works on http://, https://, and www. links. Links can have trailing - punctuation (periods, commas, close-parens) and leading punctuation - (opening parens) and it'll still do the right thing. - - If trim_url_limit is not None, the URLs in link text longer than this limit - will truncated to trim_url_limit-3 characters and appended with an elipsis. - - If nofollow is True, the URLs in link text will get a rel="nofollow" - attribute. - """ - if autoescape: - trim_url = lambda x, limit=trim_url_limit: conditional_escape(limit is not None and (len(x) > limit and ('%s...' % x[:max(0, limit - 3)])) or x) - else: - trim_url = lambda x, limit=trim_url_limit: limit is not None and (len(x) > limit and ('%s...' % x[:max(0, limit - 3)])) or x - safe_input = isinstance(text, SafeData) - words = word_split_re.split(force_unicode(text)) - nofollow_attr = nofollow and ' rel="nofollow"' or '' - for i, word in enumerate(words): - match = punctuation_re.match(word) - if match: - lead, middle, trail = match.groups() - if safe_input: - middle = mark_safe(middle) - if middle.startswith('www.') or ('@' not in middle and not middle.startswith('http://') and \ - len(middle) > 0 and middle[0] in string.ascii_letters + string.digits and \ - (middle.endswith('.org') or middle.endswith('.net') or middle.endswith('.com'))): - middle = 'http://%s' % middle - if middle.startswith('http://') or middle.startswith('https://'): - url = urlquote(middle, safe='/&=:;#?+*') - if autoescape and not safe_input: - url = escape(url) - trimmed_url = trim_url(middle) - middle = '
      %s' % (url, nofollow_attr, - trimmed_url) - elif '@' in middle and not middle.startswith('www.') and \ - not ':' in middle and simple_email_re.match(middle): - if autoescape: - middle = conditional_escape(middle) - middle = '%s' % (middle, middle) - if lead + middle + trail != word: - if autoescape and not safe_input: - lead, trail = escape(lead), escape(trail) - words[i] = mark_safe('%s%s%s' % (lead, middle, trail)) - elif autoescape and not safe_input: - words[i] = escape(word) - elif safe_input: - words[i] = mark_safe(word) - elif autoescape: - words[i] = escape(word) - return u''.join(words) -urlize = allow_lazy(urlize, unicode) - -def clean_html(text): - """ - Clean the given HTML. Specifically, do the following: - * Convert and to and . - * Encode all ampersands correctly. - * Remove all "target" attributes from tags. - * Remove extraneous HTML, such as presentational tags that open and - immediately close and
      . - * Convert hard-coded bullets into HTML unordered lists. - * Remove stuff like "

        

      ", but only if it's at the - bottom of the text. - """ - from django.utils.text import normalize_newlines - text = normalize_newlines(force_unicode(text)) - text = re.sub(r'<(/?)\s*b\s*>', '<\\1strong>', text) - text = re.sub(r'<(/?)\s*i\s*>', '<\\1em>', text) - text = fix_ampersands(text) - # Remove all target="" attributes from
      tags. - text = link_target_attribute_re.sub('\\1', text) - # Trim stupid HTML such as
      . - text = html_gunk_re.sub('', text) - # Convert hard-coded bullets into HTML unordered lists. - def replace_p_tags(match): - s = match.group().replace('

      ', '') - for d in DOTS: - s = s.replace('

      %s' % d, '

    • ') - return u'
        \n%s\n
      ' % s - text = hard_coded_bullets_re.sub(replace_p_tags, text) - # Remove stuff like "

        

      ", but only if it's at the bottom - # of the text. - text = trailing_empty_content_re.sub('', text) - return text -clean_html = allow_lazy(clean_html, unicode) diff --git a/deluge/ui/webui/lib/newforms_portable/django/utils/http.py b/deluge/ui/webui/lib/newforms_portable/django/utils/http.py deleted file mode 100644 index db8bb9644..000000000 --- a/deluge/ui/webui/lib/newforms_portable/django/utils/http.py +++ /dev/null @@ -1,67 +0,0 @@ -import urllib -from email.Utils import formatdate - -from encoding import smart_str, force_unicode -from functional import allow_lazy - -def urlquote(url, safe='/'): - """ - A version of Python's urllib.quote() function that can operate on unicode - strings. The url is first UTF-8 encoded before quoting. The returned string - can safely be used as part of an argument to a subsequent iri_to_uri() call - without double-quoting occurring. - """ - return force_unicode(urllib.quote(smart_str(url), safe)) - -urlquote = allow_lazy(urlquote, unicode) - -def urlquote_plus(url, safe=''): - """ - A version of Python's urllib.quote_plus() function that can operate on - unicode strings. The url is first UTF-8 encoded before quoting. The - returned string can safely be used as part of an argument to a subsequent - iri_to_uri() call without double-quoting occurring. - """ - return force_unicode(urllib.quote_plus(smart_str(url), safe)) -urlquote_plus = allow_lazy(urlquote_plus, unicode) - -def urlencode(query, doseq=0): - """ - A version of Python's urllib.urlencode() function that can operate on - unicode strings. The parameters are first case to UTF-8 encoded strings and - then encoded as per normal. - """ - if hasattr(query, 'items'): - query = query.items() - return urllib.urlencode( - [(smart_str(k), - isinstance(v, (list,tuple)) and [smart_str(i) for i in v] or smart_str(v)) - for k, v in query], - doseq) - -def cookie_date(epoch_seconds=None): - """ - Formats the time to ensure compatibility with Netscape's cookie standard. - - Accepts a floating point number expressed in seconds since the epoch, in - UTC - such as that outputted by time.time(). If set to None, defaults to - the current time. - - Outputs a string in the format 'Wdy, DD-Mon-YYYY HH:MM:SS GMT'. - """ - rfcdate = formatdate(epoch_seconds) - return '%s-%s-%s GMT' % (rfcdate[:7], rfcdate[8:11], rfcdate[12:25]) - -def http_date(epoch_seconds=None): - """ - Formats the time to match the RFC1123 date format as specified by HTTP - RFC2616 section 3.3.1. - - Accepts a floating point number expressed in seconds since the epoch, in - UTC - such as that outputted by time.time(). If set to None, defaults to - the current time. - - Outputs a string in the format 'Wdy, DD Mon YYYY HH:MM:SS GMT'. - """ - rfcdate = formatdate(epoch_seconds) - return '%s GMT' % rfcdate[:25] diff --git a/deluge/ui/webui/lib/newforms_portable/django/utils/safestring.py b/deluge/ui/webui/lib/newforms_portable/django/utils/safestring.py deleted file mode 100644 index 99658fb8b..000000000 --- a/deluge/ui/webui/lib/newforms_portable/django/utils/safestring.py +++ /dev/null @@ -1,119 +0,0 @@ -""" -Functions for working with "safe strings": strings that can be displayed safely -without further escaping in HTML. Marking something as a "safe string" means -that the producer of the string has already turned characters that should not -be interpreted by the HTML engine (e.g. '<') into the appropriate entities. -""" -from functional import curry, Promise - -class EscapeData(object): - pass - -class EscapeString(str, EscapeData): - """ - A string that should be HTML-escaped when output. - """ - pass - -class EscapeUnicode(unicode, EscapeData): - """ - A unicode object that should be HTML-escaped when output. - """ - pass - -class SafeData(object): - pass - -class SafeString(str, SafeData): - """ - A string subclass that has been specifically marked as "safe" (requires no - further escaping) for HTML output purposes. - """ - def __add__(self, rhs): - """ - Concatenating a safe string with another safe string or safe unicode - object is safe. Otherwise, the result is no longer safe. - """ - t = super(SafeString, self).__add__(rhs) - if isinstance(rhs, SafeUnicode): - return SafeUnicode(t) - elif isinstance(rhs, SafeString): - return SafeString(t) - return t - - def _proxy_method(self, *args, **kwargs): - """ - Wrap a call to a normal unicode method up so that we return safe - results. The method that is being wrapped is passed in the 'method' - argument. - """ - method = kwargs.pop('method') - data = method(self, *args, **kwargs) - if isinstance(data, str): - return SafeString(data) - else: - return SafeUnicode(data) - - decode = curry(_proxy_method, method = str.decode) - -class SafeUnicode(unicode, SafeData): - """ - A unicode subclass that has been specifically marked as "safe" for HTML - output purposes. - """ - def __add__(self, rhs): - """ - Concatenating a safe unicode object with another safe string or safe - unicode object is safe. Otherwise, the result is no longer safe. - """ - t = super(SafeUnicode, self).__add__(rhs) - if isinstance(rhs, SafeData): - return SafeUnicode(t) - return t - - def _proxy_method(self, *args, **kwargs): - """ - Wrap a call to a normal unicode method up so that we return safe - results. The method that is being wrapped is passed in the 'method' - argument. - """ - method = kwargs.pop('method') - data = method(self, *args, **kwargs) - if isinstance(data, str): - return SafeString(data) - else: - return SafeUnicode(data) - - encode = curry(_proxy_method, method = unicode.encode) - -def mark_safe(s): - """ - Explicitly mark a string as safe for (HTML) output purposes. The returned - object can be used everywhere a string or unicode object is appropriate. - - Can be called multiple times on a single string. - """ - if isinstance(s, SafeData): - return s - if isinstance(s, str) or (isinstance(s, Promise) and s._delegate_str): - return SafeString(s) - if isinstance(s, (unicode, Promise)): - return SafeUnicode(s) - return SafeString(str(s)) - -def mark_for_escaping(s): - """ - Explicitly mark a string as requiring HTML escaping upon output. Has no - effect on SafeData subclasses. - - Can be called multiple times on a single string (the resulting escaping is - only applied once). - """ - if isinstance(s, (SafeData, EscapeData)): - return s - if isinstance(s, str) or (isinstance(s, Promise) and s._delegate_str): - return EscapeString(s) - if isinstance(s, (unicode, Promise)): - return EscapeUnicode(s) - return EscapeString(str(s)) - diff --git a/deluge/ui/webui/lib/newforms_portable/django/utils/translation.py b/deluge/ui/webui/lib/newforms_portable/django/utils/translation.py deleted file mode 100644 index ad65bd959..000000000 --- a/deluge/ui/webui/lib/newforms_portable/django/utils/translation.py +++ /dev/null @@ -1,9 +0,0 @@ -try: - _('translate something') -except: - import gettext - gettext.install('locale') - -ugettext = _ -ugettext_lazy = _ - diff --git a/deluge/ui/webui/lib/newforms_portable/fields.py b/deluge/ui/webui/lib/newforms_portable/fields.py deleted file mode 100644 index c20899ada..000000000 --- a/deluge/ui/webui/lib/newforms_portable/fields.py +++ /dev/null @@ -1,784 +0,0 @@ -""" -Field classes. -""" - -import copy -import datetime -import os -import re -import time -# Python 2.3 fallbacks -try: - from decimal import Decimal, DecimalException -except ImportError: - from django.utils._decimal import Decimal, DecimalException -try: - set -except NameError: - from sets import Set as set - -from django.utils.translation import ugettext_lazy as _ -from django.utils.encoding import StrAndUnicode, smart_unicode, smart_str - -from util import ErrorList, ValidationError -from widgets import TextInput, PasswordInput, HiddenInput, MultipleHiddenInput, FileInput, CheckboxInput, Select, NullBooleanSelect, SelectMultiple, DateTimeInput - - -__all__ = ( - 'Field', 'CharField', 'IntegerField', - 'DEFAULT_DATE_INPUT_FORMATS', 'DateField', - 'DEFAULT_TIME_INPUT_FORMATS', 'TimeField', - 'DEFAULT_DATETIME_INPUT_FORMATS', 'DateTimeField', - 'RegexField', 'EmailField', 'FileField', 'ImageField', 'URLField', - 'BooleanField', 'NullBooleanField', 'ChoiceField', 'MultipleChoiceField', - 'ComboField', 'MultiValueField', 'FloatField', 'DecimalField', - 'SplitDateTimeField', 'IPAddressField', 'FilePathField', -) - -# These values, if given to to_python(), will trigger the self.required check. -EMPTY_VALUES = (None, '') - - -class Field(object): - widget = TextInput # Default widget to use when rendering this type of Field. - hidden_widget = HiddenInput # Default widget to use when rendering this as "hidden". - default_error_messages = { - 'required': _(u'This field is required.'), - 'invalid': _(u'Enter a valid value.'), - } - - # Tracks each time a Field instance is created. Used to retain order. - creation_counter = 0 - - def __init__(self, required=True, widget=None, label=None, initial=None, - help_text=None, error_messages=None): - # required -- Boolean that specifies whether the field is required. - # True by default. - # widget -- A Widget class, or instance of a Widget class, that should - # be used for this Field when displaying it. Each Field has a - # default Widget that it'll use if you don't specify this. In - # most cases, the default widget is TextInput. - # label -- A verbose name for this field, for use in displaying this - # field in a form. By default, Django will use a "pretty" - # version of the form field name, if the Field is part of a - # Form. - # initial -- A value to use in this Field's initial display. This value - # is *not* used as a fallback if data isn't given. - # help_text -- An optional string to use as "help text" for this Field. - if label is not None: - label = smart_unicode(label) - self.required, self.label, self.initial = required, label, initial - self.help_text = smart_unicode(help_text or '') - widget = widget or self.widget - if isinstance(widget, type): - widget = widget() - - # Hook into self.widget_attrs() for any Field-specific HTML attributes. - extra_attrs = self.widget_attrs(widget) - if extra_attrs: - widget.attrs.update(extra_attrs) - - self.widget = widget - - # Increase the creation counter, and save our local copy. - self.creation_counter = Field.creation_counter - Field.creation_counter += 1 - - def set_class_error_messages(messages, klass): - for base_class in klass.__bases__: - set_class_error_messages(messages, base_class) - messages.update(getattr(klass, 'default_error_messages', {})) - - messages = {} - set_class_error_messages(messages, self.__class__) - messages.update(error_messages or {}) - self.error_messages = messages - - def clean(self, value): - """ - Validates the given value and returns its "cleaned" value as an - appropriate Python object. - - Raises ValidationError for any errors. - """ - if self.required and value in EMPTY_VALUES: - raise ValidationError(self.error_messages['required']) - return value - - def widget_attrs(self, widget): - """ - Given a Widget instance (*not* a Widget class), returns a dictionary of - any HTML attributes that should be added to the Widget, based on this - Field. - """ - return {} - - def __deepcopy__(self, memo): - result = copy.copy(self) - memo[id(self)] = result - result.widget = copy.deepcopy(self.widget, memo) - return result - -class CharField(Field): - default_error_messages = { - 'max_length': _(u'Ensure this value has at most %(max)d characters (it has %(length)d).'), - 'min_length': _(u'Ensure this value has at least %(min)d characters (it has %(length)d).'), - } - - def __init__(self, max_length=None, min_length=None, *args, **kwargs): - self.max_length, self.min_length = max_length, min_length - super(CharField, self).__init__(*args, **kwargs) - - def clean(self, value): - "Validates max_length and min_length. Returns a Unicode object." - super(CharField, self).clean(value) - if value in EMPTY_VALUES: - return u'' - value = smart_unicode(value) - value_length = len(value) - if self.max_length is not None and value_length > self.max_length: - raise ValidationError(self.error_messages['max_length'] % {'max': self.max_length, 'length': value_length}) - if self.min_length is not None and value_length < self.min_length: - raise ValidationError(self.error_messages['min_length'] % {'min': self.min_length, 'length': value_length}) - return value - - def widget_attrs(self, widget): - if self.max_length is not None and isinstance(widget, (TextInput, PasswordInput)): - # The HTML attribute is maxlength, not max_length. - return {'maxlength': str(self.max_length)} - -class IntegerField(Field): - default_error_messages = { - 'invalid': _(u'Enter a whole number.'), - 'max_value': _(u'Ensure this value is less than or equal to %s.'), - 'min_value': _(u'Ensure this value is greater than or equal to %s.'), - } - - def __init__(self, max_value=None, min_value=None, *args, **kwargs): - self.max_value, self.min_value = max_value, min_value - super(IntegerField, self).__init__(*args, **kwargs) - - def clean(self, value): - """ - Validates that int() can be called on the input. Returns the result - of int(). Returns None for empty values. - """ - super(IntegerField, self).clean(value) - if value in EMPTY_VALUES: - return None - try: - value = int(str(value)) - except (ValueError, TypeError): - raise ValidationError(self.error_messages['invalid']) - if self.max_value is not None and value > self.max_value: - raise ValidationError(self.error_messages['max_value'] % self.max_value) - if self.min_value is not None and value < self.min_value: - raise ValidationError(self.error_messages['min_value'] % self.min_value) - return value - -class FloatField(Field): - default_error_messages = { - 'invalid': _(u'Enter a number.'), - 'max_value': _(u'Ensure this value is less than or equal to %s.'), - 'min_value': _(u'Ensure this value is greater than or equal to %s.'), - } - - def __init__(self, max_value=None, min_value=None, *args, **kwargs): - self.max_value, self.min_value = max_value, min_value - Field.__init__(self, *args, **kwargs) - - def clean(self, value): - """ - Validates that float() can be called on the input. Returns a float. - Returns None for empty values. - """ - super(FloatField, self).clean(value) - if not self.required and value in EMPTY_VALUES: - return None - try: - value = float(value) - except (ValueError, TypeError): - raise ValidationError(self.error_messages['invalid']) - if self.max_value is not None and value > self.max_value: - raise ValidationError(self.error_messages['max_value'] % self.max_value) - if self.min_value is not None and value < self.min_value: - raise ValidationError(self.error_messages['min_value'] % self.min_value) - return value - -class DecimalField(Field): - default_error_messages = { - 'invalid': _(u'Enter a number.'), - 'max_value': _(u'Ensure this value is less than or equal to %s.'), - 'min_value': _(u'Ensure this value is greater than or equal to %s.'), - 'max_digits': _('Ensure that there are no more than %s digits in total.'), - 'max_decimal_places': _('Ensure that there are no more than %s decimal places.'), - 'max_whole_digits': _('Ensure that there are no more than %s digits before the decimal point.') - } - - def __init__(self, max_value=None, min_value=None, max_digits=None, decimal_places=None, *args, **kwargs): - self.max_value, self.min_value = max_value, min_value - self.max_digits, self.decimal_places = max_digits, decimal_places - Field.__init__(self, *args, **kwargs) - - def clean(self, value): - """ - Validates that the input is a decimal number. Returns a Decimal - instance. Returns None for empty values. Ensures that there are no more - than max_digits in the number, and no more than decimal_places digits - after the decimal point. - """ - super(DecimalField, self).clean(value) - if not self.required and value in EMPTY_VALUES: - return None - value = smart_str(value).strip() - try: - value = Decimal(value) - except DecimalException: - raise ValidationError(self.error_messages['invalid']) - pieces = str(value).lstrip("-").split('.') - decimals = (len(pieces) == 2) and len(pieces[1]) or 0 - digits = len(pieces[0]) - if self.max_value is not None and value > self.max_value: - raise ValidationError(self.error_messages['max_value'] % self.max_value) - if self.min_value is not None and value < self.min_value: - raise ValidationError(self.error_messages['min_value'] % self.min_value) - if self.max_digits is not None and (digits + decimals) > self.max_digits: - raise ValidationError(self.error_messages['max_digits'] % self.max_digits) - if self.decimal_places is not None and decimals > self.decimal_places: - raise ValidationError(self.error_messages['max_decimal_places'] % self.decimal_places) - if self.max_digits is not None and self.decimal_places is not None and digits > (self.max_digits - self.decimal_places): - raise ValidationError(self.error_messages['max_whole_digits'] % (self.max_digits - self.decimal_places)) - return value - -DEFAULT_DATE_INPUT_FORMATS = ( - '%Y-%m-%d', '%m/%d/%Y', '%m/%d/%y', # '2006-10-25', '10/25/2006', '10/25/06' - '%b %d %Y', '%b %d, %Y', # 'Oct 25 2006', 'Oct 25, 2006' - '%d %b %Y', '%d %b, %Y', # '25 Oct 2006', '25 Oct, 2006' - '%B %d %Y', '%B %d, %Y', # 'October 25 2006', 'October 25, 2006' - '%d %B %Y', '%d %B, %Y', # '25 October 2006', '25 October, 2006' -) - -class DateField(Field): - default_error_messages = { - 'invalid': _(u'Enter a valid date.'), - } - - def __init__(self, input_formats=None, *args, **kwargs): - super(DateField, self).__init__(*args, **kwargs) - self.input_formats = input_formats or DEFAULT_DATE_INPUT_FORMATS - - def clean(self, value): - """ - Validates that the input can be converted to a date. Returns a Python - datetime.date object. - """ - super(DateField, self).clean(value) - if value in EMPTY_VALUES: - return None - if isinstance(value, datetime.datetime): - return value.date() - if isinstance(value, datetime.date): - return value - for format in self.input_formats: - try: - return datetime.date(*time.strptime(value, format)[:3]) - except ValueError: - continue - raise ValidationError(self.error_messages['invalid']) - -DEFAULT_TIME_INPUT_FORMATS = ( - '%H:%M:%S', # '14:30:59' - '%H:%M', # '14:30' -) - -class TimeField(Field): - default_error_messages = { - 'invalid': _(u'Enter a valid time.') - } - - def __init__(self, input_formats=None, *args, **kwargs): - super(TimeField, self).__init__(*args, **kwargs) - self.input_formats = input_formats or DEFAULT_TIME_INPUT_FORMATS - - def clean(self, value): - """ - Validates that the input can be converted to a time. Returns a Python - datetime.time object. - """ - super(TimeField, self).clean(value) - if value in EMPTY_VALUES: - return None - if isinstance(value, datetime.time): - return value - for format in self.input_formats: - try: - return datetime.time(*time.strptime(value, format)[3:6]) - except ValueError: - continue - raise ValidationError(self.error_messages['invalid']) - -DEFAULT_DATETIME_INPUT_FORMATS = ( - '%Y-%m-%d %H:%M:%S', # '2006-10-25 14:30:59' - '%Y-%m-%d %H:%M', # '2006-10-25 14:30' - '%Y-%m-%d', # '2006-10-25' - '%m/%d/%Y %H:%M:%S', # '10/25/2006 14:30:59' - '%m/%d/%Y %H:%M', # '10/25/2006 14:30' - '%m/%d/%Y', # '10/25/2006' - '%m/%d/%y %H:%M:%S', # '10/25/06 14:30:59' - '%m/%d/%y %H:%M', # '10/25/06 14:30' - '%m/%d/%y', # '10/25/06' -) - -class DateTimeField(Field): - widget = DateTimeInput - default_error_messages = { - 'invalid': _(u'Enter a valid date/time.'), - } - - def __init__(self, input_formats=None, *args, **kwargs): - super(DateTimeField, self).__init__(*args, **kwargs) - self.input_formats = input_formats or DEFAULT_DATETIME_INPUT_FORMATS - - def clean(self, value): - """ - Validates that the input can be converted to a datetime. Returns a - Python datetime.datetime object. - """ - super(DateTimeField, self).clean(value) - if value in EMPTY_VALUES: - return None - if isinstance(value, datetime.datetime): - return value - if isinstance(value, datetime.date): - return datetime.datetime(value.year, value.month, value.day) - if isinstance(value, list): - # Input comes from a SplitDateTimeWidget, for example. So, it's two - # components: date and time. - if len(value) != 2: - raise ValidationError(self.error_messages['invalid']) - value = '%s %s' % tuple(value) - for format in self.input_formats: - try: - return datetime.datetime(*time.strptime(value, format)[:6]) - except ValueError: - continue - raise ValidationError(self.error_messages['invalid']) - -class RegexField(CharField): - def __init__(self, regex, max_length=None, min_length=None, error_message=None, *args, **kwargs): - """ - regex can be either a string or a compiled regular expression object. - error_message is an optional error message to use, if - 'Enter a valid value' is too generic for you. - """ - # error_message is just kept for backwards compatibility: - if error_message: - error_messages = kwargs.get('error_messages') or {} - error_messages['invalid'] = error_message - kwargs['error_messages'] = error_messages - super(RegexField, self).__init__(max_length, min_length, *args, **kwargs) - if isinstance(regex, basestring): - regex = re.compile(regex) - self.regex = regex - - def clean(self, value): - """ - Validates that the input matches the regular expression. Returns a - Unicode object. - """ - value = super(RegexField, self).clean(value) - if value == u'': - return value - if not self.regex.search(value): - raise ValidationError(self.error_messages['invalid']) - return value - -email_re = re.compile( - r"(^[-!#$%&'*+/=?^_`{}|~0-9A-Z]+(\.[-!#$%&'*+/=?^_`{}|~0-9A-Z]+)*" # dot-atom - r'|^"([\001-\010\013\014\016-\037!#-\[\]-\177]|\\[\001-011\013\014\016-\177])*"' # quoted-string - r')@(?:[A-Z0-9-]+\.)+[A-Z]{2,6}$', re.IGNORECASE) # domain - -class EmailField(RegexField): - default_error_messages = { - 'invalid': _(u'Enter a valid e-mail address.'), - } - - def __init__(self, max_length=None, min_length=None, *args, **kwargs): - RegexField.__init__(self, email_re, max_length, min_length, *args, - **kwargs) - -try: - from django.conf import settings - URL_VALIDATOR_USER_AGENT = settings.URL_VALIDATOR_USER_AGENT -except ImportError: - # It's OK if Django settings aren't configured. - URL_VALIDATOR_USER_AGENT = 'Django (http://www.djangoproject.com/)' - -class UploadedFile(StrAndUnicode): - "A wrapper for files uploaded in a FileField" - def __init__(self, filename, content): - self.filename = filename - self.content = content - - def __unicode__(self): - """ - The unicode representation is the filename, so that the pre-database-insertion - logic can use UploadedFile objects - """ - return self.filename - -class FileField(Field): - widget = FileInput - default_error_messages = { - 'invalid': _(u"No file was submitted. Check the encoding type on the form."), - 'missing': _(u"No file was submitted."), - 'empty': _(u"The submitted file is empty."), - } - - def __init__(self, *args, **kwargs): - super(FileField, self).__init__(*args, **kwargs) - - def clean(self, data, initial=None): - super(FileField, self).clean(initial or data) - if not self.required and data in EMPTY_VALUES: - return None - elif not data and initial: - return initial - try: - f = UploadedFile(data['filename'], data['content']) - except TypeError: - raise ValidationError(self.error_messages['invalid']) - except KeyError: - raise ValidationError(self.error_messages['missing']) - if not f.content: - raise ValidationError(self.error_messages['empty']) - return f - -class ImageField(FileField): - default_error_messages = { - 'invalid_image': _(u"Upload a valid image. The file you uploaded was either not an image or a corrupted image."), - } - - def clean(self, data, initial=None): - """ - Checks that the file-upload field data contains a valid image (GIF, JPG, - PNG, possibly others -- whatever the Python Imaging Library supports). - """ - f = super(ImageField, self).clean(data, initial) - if f is None: - return None - elif not data and initial: - return initial - from PIL import Image - from cStringIO import StringIO - try: - # load() is the only method that can spot a truncated JPEG, - # but it cannot be called sanely after verify() - trial_image = Image.open(StringIO(f.content)) - trial_image.load() - # verify() is the only method that can spot a corrupt PNG, - # but it must be called immediately after the constructor - trial_image = Image.open(StringIO(f.content)) - trial_image.verify() - except Exception: # Python Imaging Library doesn't recognize it as an image - raise ValidationError(self.error_messages['invalid_image']) - return f - -url_re = re.compile( - r'^https?://' # http:// or https:// - r'(?:(?:[A-Z0-9-]+\.)+[A-Z]{2,6}|' #domain... - r'localhost|' #localhost... - r'\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})' # ...or ip - r'(?::\d+)?' # optional port - r'(?:/?|/\S+)$', re.IGNORECASE) - -class URLField(RegexField): - default_error_messages = { - 'invalid': _(u'Enter a valid URL.'), - 'invalid_link': _(u'This URL appears to be a broken link.'), - } - - def __init__(self, max_length=None, min_length=None, verify_exists=False, - validator_user_agent=URL_VALIDATOR_USER_AGENT, *args, **kwargs): - super(URLField, self).__init__(url_re, max_length, min_length, *args, - **kwargs) - self.verify_exists = verify_exists - self.user_agent = validator_user_agent - - def clean(self, value): - # If no URL scheme given, assume http:// - if value and '://' not in value: - value = u'http://%s' % value - value = super(URLField, self).clean(value) - if value == u'': - return value - if self.verify_exists: - import urllib2 - from django.conf import settings - headers = { - "Accept": "text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5", - "Accept-Language": "en-us,en;q=0.5", - "Accept-Charset": "ISO-8859-1,utf-8;q=0.7,*;q=0.7", - "Connection": "close", - "User-Agent": self.user_agent, - } - try: - req = urllib2.Request(value, None, headers) - u = urllib2.urlopen(req) - except ValueError: - raise ValidationError(self.error_messages['invalid']) - except: # urllib2.URLError, httplib.InvalidURL, etc. - raise ValidationError(self.error_messages['invalid_link']) - return value - -class BooleanField(Field): - widget = CheckboxInput - - def clean(self, value): - """Returns a Python boolean object.""" - super(BooleanField, self).clean(value) - # Explicitly check for the string 'False', which is what a hidden field - # will submit for False. Because bool("True") == True, we don't need to - # handle that explicitly. - if value == 'False': - return False - return bool(value) - -class NullBooleanField(BooleanField): - """ - A field whose valid values are None, True and False. Invalid values are - cleaned to None. - """ - widget = NullBooleanSelect - - def clean(self, value): - return {True: True, False: False}.get(value, None) - -class ChoiceField(Field): - widget = Select - default_error_messages = { - 'invalid_choice': _(u'Select a valid choice. That choice is not one of the available choices.'), - } - - def __init__(self, choices=(), required=True, widget=None, label=None, - initial=None, help_text=None, *args, **kwargs): - super(ChoiceField, self).__init__(required, widget, label, initial, - help_text, *args, **kwargs) - self.choices = choices - - def _get_choices(self): - return self._choices - - def _set_choices(self, value): - # Setting choices also sets the choices on the widget. - # choices can be any iterable, but we call list() on it because - # it will be consumed more than once. - self._choices = self.widget.choices = list(value) - - choices = property(_get_choices, _set_choices) - - def clean(self, value): - """ - Validates that the input is in self.choices. - """ - value = super(ChoiceField, self).clean(value) - if value in EMPTY_VALUES: - value = u'' - value = smart_unicode(value) - if value == u'': - return value - valid_values = set([smart_unicode(k) for k, v in self.choices]) - if value not in valid_values: - raise ValidationError(self.error_messages['invalid_choice'] % {'value': value}) - return value - -class MultipleChoiceField(ChoiceField): - hidden_widget = MultipleHiddenInput - widget = SelectMultiple - default_error_messages = { - 'invalid_choice': _(u'Select a valid choice. %(value)s is not one of the available choices.'), - 'invalid_list': _(u'Enter a list of values.'), - } - - def clean(self, value): - """ - Validates that the input is a list or tuple. - """ - if self.required and not value: - raise ValidationError(self.error_messages['required']) - elif not self.required and not value: - return [] - if not isinstance(value, (list, tuple)): - raise ValidationError(self.error_messages['invalid_list']) - new_value = [smart_unicode(val) for val in value] - # Validate that each value in the value list is in self.choices. - valid_values = set([smart_unicode(k) for k, v in self.choices]) - for val in new_value: - if val not in valid_values: - raise ValidationError(self.error_messages['invalid_choice'] % {'value': val}) - return new_value - -class ComboField(Field): - """ - A Field whose clean() method calls multiple Field clean() methods. - """ - def __init__(self, fields=(), *args, **kwargs): - super(ComboField, self).__init__(*args, **kwargs) - # Set 'required' to False on the individual fields, because the - # required validation will be handled by ComboField, not by those - # individual fields. - for f in fields: - f.required = False - self.fields = fields - - def clean(self, value): - """ - Validates the given value against all of self.fields, which is a - list of Field instances. - """ - super(ComboField, self).clean(value) - for field in self.fields: - value = field.clean(value) - return value - -class MultiValueField(Field): - """ - A Field that aggregates the logic of multiple Fields. - - Its clean() method takes a "decompressed" list of values, which are then - cleaned into a single value according to self.fields. Each value in - this list is cleaned by the corresponding field -- the first value is - cleaned by the first field, the second value is cleaned by the second - field, etc. Once all fields are cleaned, the list of clean values is - "compressed" into a single value. - - Subclasses should not have to implement clean(). Instead, they must - implement compress(), which takes a list of valid values and returns a - "compressed" version of those values -- a single value. - - You'll probably want to use this with MultiWidget. - """ - default_error_messages = { - 'invalid': _(u'Enter a list of values.'), - } - - def __init__(self, fields=(), *args, **kwargs): - super(MultiValueField, self).__init__(*args, **kwargs) - # Set 'required' to False on the individual fields, because the - # required validation will be handled by MultiValueField, not by those - # individual fields. - for f in fields: - f.required = False - self.fields = fields - - def clean(self, value): - """ - Validates every value in the given list. A value is validated against - the corresponding Field in self.fields. - - For example, if this MultiValueField was instantiated with - fields=(DateField(), TimeField()), clean() would call - DateField.clean(value[0]) and TimeField.clean(value[1]). - """ - cleaned_data = [] - errors = ErrorList() - if not value or isinstance(value, (list, tuple)): - if not value or not [v for v in value if v not in EMPTY_VALUES]: - if self.required: - raise ValidationError(self.error_messages['required']) - else: - return self.compress([]) - else: - raise ValidationError(self.error_messages['invalid']) - for i, field in enumerate(self.fields): - try: - field_value = value[i] - except IndexError: - field_value = None - if self.required and field_value in EMPTY_VALUES: - raise ValidationError(self.error_messages['required']) - try: - cleaned_data.append(field.clean(field_value)) - except ValidationError, e: - # Collect all validation errors in a single list, which we'll - # raise at the end of clean(), rather than raising a single - # exception for the first error we encounter. - errors.extend(e.messages) - if errors: - raise ValidationError(errors) - return self.compress(cleaned_data) - - def compress(self, data_list): - """ - Returns a single value for the given list of values. The values can be - assumed to be valid. - - For example, if this MultiValueField was instantiated with - fields=(DateField(), TimeField()), this might return a datetime - object created by combining the date and time in data_list. - """ - raise NotImplementedError('Subclasses must implement this method.') - -class FilePathField(ChoiceField): - def __init__(self, path, match=None, recursive=False, required=True, - widget=Select, label=None, initial=None, help_text=None, - *args, **kwargs): - self.path, self.match, self.recursive = path, match, recursive - super(FilePathField, self).__init__(choices=(), required=required, - widget=widget, label=label, initial=initial, help_text=help_text, - *args, **kwargs) - self.choices = [] - if self.match is not None: - self.match_re = re.compile(self.match) - if recursive: - for root, dirs, files in os.walk(self.path): - for f in files: - if self.match is None or self.match_re.search(f): - f = os.path.join(root, f) - self.choices.append((f, f.replace(path, "", 1))) - else: - try: - for f in os.listdir(self.path): - full_file = os.path.join(self.path, f) - if os.path.isfile(full_file) and (self.match is None or self.match_re.search(f)): - self.choices.append((full_file, f)) - except OSError: - pass - self.widget.choices = self.choices - -class SplitDateTimeField(MultiValueField): - default_error_messages = { - 'invalid_date': _(u'Enter a valid date.'), - 'invalid_time': _(u'Enter a valid time.'), - } - - def __init__(self, *args, **kwargs): - errors = self.default_error_messages.copy() - if 'error_messages' in kwargs: - errors.update(kwargs['error_messages']) - fields = ( - DateField(error_messages={'invalid': errors['invalid_date']}), - TimeField(error_messages={'invalid': errors['invalid_time']}), - ) - super(SplitDateTimeField, self).__init__(fields, *args, **kwargs) - - def compress(self, data_list): - if data_list: - # Raise a validation error if time or date is empty - # (possible if SplitDateTimeField has required=False). - if data_list[0] in EMPTY_VALUES: - raise ValidationError(self.error_messages['invalid_date']) - if data_list[1] in EMPTY_VALUES: - raise ValidationError(self.error_messages['invalid_time']) - return datetime.datetime.combine(*data_list) - return None - -ipv4_re = re.compile(r'^(25[0-5]|2[0-4]\d|[0-1]?\d?\d)(\.(25[0-5]|2[0-4]\d|[0-1]?\d?\d)){3}$') - -class IPAddressField(RegexField): - default_error_messages = { - 'invalid': _(u'Enter a valid IPv4 address.'), - } - - def __init__(self, *args, **kwargs): - super(IPAddressField, self).__init__(ipv4_re, *args, **kwargs) diff --git a/deluge/ui/webui/lib/newforms_portable/forms.py b/deluge/ui/webui/lib/newforms_portable/forms.py deleted file mode 100644 index 2c481e47a..000000000 --- a/deluge/ui/webui/lib/newforms_portable/forms.py +++ /dev/null @@ -1,350 +0,0 @@ -""" -Form classes -""" - -from copy import deepcopy - -from django.utils.datastructures import SortedDict -from django.utils.html import escape -from django.utils.encoding import StrAndUnicode, smart_unicode, force_unicode -from django.utils.safestring import mark_safe - -from fields import Field, FileField -from widgets import TextInput, Textarea -from util import flatatt, ErrorDict, ErrorList, ValidationError - -__all__ = ('BaseForm', 'Form') - -NON_FIELD_ERRORS = '__all__' - -def pretty_name(name): - "Converts 'first_name' to 'First name'" - name = name[0].upper() + name[1:] - return name.replace('_', ' ') - -def get_declared_fields(bases, attrs, with_base_fields=True): - """ - Create a list of form field instances from the passed in 'attrs', plus any - similar fields on the base classes (in 'bases'). This is used by both the - Form and ModelForm metclasses. - - If 'with_base_fields' is True, all fields from the bases are used. - Otherwise, only fields in the 'declared_fields' attribute on the bases are - used. The distinction is useful in ModelForm subclassing. - """ - fields = [(field_name, attrs.pop(field_name)) for field_name, obj in attrs.items() if isinstance(obj, Field)] - fields.sort(lambda x, y: cmp(x[1].creation_counter, y[1].creation_counter)) - - # If this class is subclassing another Form, add that Form's fields. - # Note that we loop over the bases in *reverse*. This is necessary in - # order to preserve the correct order of fields. - if with_base_fields: - for base in bases[::-1]: - if hasattr(base, 'base_fields'): - fields = base.base_fields.items() + fields - else: - for base in bases[::-1]: - if hasattr(base, 'declared_fields'): - fields = base.declared_fields.items() + fields - - return SortedDict(fields) - -class DeclarativeFieldsMetaclass(type): - """ - Metaclass that converts Field attributes to a dictionary called - 'base_fields', taking into account parent class 'base_fields' as well. - """ - def __new__(cls, name, bases, attrs): - attrs['base_fields'] = get_declared_fields(bases, attrs) - return type.__new__(cls, name, bases, attrs) - -class BaseForm(StrAndUnicode): - # This is the main implementation of all the Form logic. Note that this - # class is different than Form. See the comments by the Form class for more - # information. Any improvements to the form API should be made to *this* - # class, not to the Form class. - def __init__(self, data=None, files=None, auto_id='id_%s', prefix=None, - initial=None, error_class=ErrorList, label_suffix=':'): - self.is_bound = data is not None or files is not None - self.data = data or {} - self.files = files or {} - self.auto_id = auto_id - self.prefix = prefix - self.initial = initial or {} - self.error_class = error_class - self.label_suffix = label_suffix - self._errors = None # Stores the errors after clean() has been called. - - # The base_fields class attribute is the *class-wide* definition of - # fields. Because a particular *instance* of the class might want to - # alter self.fields, we create self.fields here by copying base_fields. - # Instances should always modify self.fields; they should not modify - # self.base_fields. - self.fields = deepcopy(self.base_fields) - - def __unicode__(self): - return self.as_table() - - def __iter__(self): - for name, field in self.fields.items(): - yield BoundField(self, field, name) - - def __getitem__(self, name): - "Returns a BoundField with the given name." - try: - field = self.fields[name] - except KeyError: - raise KeyError('Key %r not found in Form' % name) - return BoundField(self, field, name) - - def _get_errors(self): - "Returns an ErrorDict for the data provided for the form" - if self._errors is None: - self.full_clean() - return self._errors - errors = property(_get_errors) - - def is_valid(self): - """ - Returns True if the form has no errors. Otherwise, False. If errors are - being ignored, returns False. - """ - return self.is_bound and not bool(self.errors) - - def add_prefix(self, field_name): - """ - Returns the field name with a prefix appended, if this Form has a - prefix set. - - Subclasses may wish to override. - """ - return self.prefix and ('%s-%s' % (self.prefix, field_name)) or field_name - - def _html_output(self, normal_row, error_row, row_ender, help_text_html, errors_on_separate_row): - "Helper function for outputting HTML. Used by as_table(), as_ul(), as_p()." - top_errors = self.non_field_errors() # Errors that should be displayed above all fields. - output, hidden_fields = [], [] - for name, field in self.fields.items(): - bf = BoundField(self, field, name) - bf_errors = self.error_class([escape(error) for error in bf.errors]) # Escape and cache in local variable. - if bf.is_hidden: - if bf_errors: - top_errors.extend([u'(Hidden field %s) %s' % (name, force_unicode(e)) for e in bf_errors]) - hidden_fields.append(unicode(bf)) - else: - if errors_on_separate_row and bf_errors: - output.append(error_row % force_unicode(bf_errors)) - if bf.label: - label = escape(force_unicode(bf.label)) - # Only add the suffix if the label does not end in - # punctuation. - if self.label_suffix: - if label[-1] not in ':?.!': - label += self.label_suffix - label = bf.label_tag(label) or '' - else: - label = '' - if field.help_text: - help_text = help_text_html % force_unicode(field.help_text) - else: - help_text = u'' - output.append(normal_row % {'errors': force_unicode(bf_errors), 'label': force_unicode(label), 'field': unicode(bf), 'help_text': help_text}) - if top_errors: - output.insert(0, error_row % force_unicode(top_errors)) - if hidden_fields: # Insert any hidden fields in the last row. - str_hidden = u''.join(hidden_fields) - if output: - last_row = output[-1] - # Chop off the trailing row_ender (e.g. '') and - # insert the hidden fields. - output[-1] = last_row[:-len(row_ender)] + str_hidden + row_ender - else: - # If there aren't any rows in the output, just append the - # hidden fields. - output.append(str_hidden) - return mark_safe(u'\n'.join(output)) - - def as_table(self): - "Returns this form rendered as HTML s -- excluding the
      ." - return self._html_output(u'%(label)s%(errors)s%(field)s%(help_text)s', u'%s', '', u'
      %s', False) - - def as_ul(self): - "Returns this form rendered as HTML
    • s -- excluding the
        ." - return self._html_output(u'
      • %(errors)s%(label)s %(field)s%(help_text)s
      • ', u'
      • %s
      • ', '', u' %s', False) - - def as_p(self): - "Returns this form rendered as HTML

        s." - return self._html_output(u'

        %(label)s %(field)s%(help_text)s

        ', u'%s', '

        ', u' %s', True) - - def non_field_errors(self): - """ - Returns an ErrorList of errors that aren't associated with a particular - field -- i.e., from Form.clean(). Returns an empty ErrorList if there - are none. - """ - return self.errors.get(NON_FIELD_ERRORS, self.error_class()) - - def full_clean(self): - """ - Cleans all of self.data and populates self._errors and - self.cleaned_data. - """ - self._errors = ErrorDict() - if not self.is_bound: # Stop further processing. - return - self.cleaned_data = {} - for name, field in self.fields.items(): - # value_from_datadict() gets the data from the data dictionaries. - # Each widget type knows how to retrieve its own data, because some - # widgets split data over several HTML fields. - value = field.widget.value_from_datadict(self.data, self.files, self.add_prefix(name)) - try: - if isinstance(field, FileField): - initial = self.initial.get(name, field.initial) - value = field.clean(value, initial) - else: - value = field.clean(value) - self.cleaned_data[name] = value - if hasattr(self, 'clean_%s' % name): - value = getattr(self, 'clean_%s' % name)() - self.cleaned_data[name] = value - except ValidationError, e: - self._errors[name] = e.messages - if name in self.cleaned_data: - del self.cleaned_data[name] - try: - self.cleaned_data = self.clean() - except ValidationError, e: - self._errors[NON_FIELD_ERRORS] = e.messages - if self._errors: - delattr(self, 'cleaned_data') - - def clean(self): - """ - Hook for doing any extra form-wide cleaning after Field.clean() been - called on every field. Any ValidationError raised by this method will - not be associated with a particular field; it will have a special-case - association with the field named '__all__'. - """ - return self.cleaned_data - - def is_multipart(self): - """ - Returns True if the form needs to be multipart-encrypted, i.e. it has - FileInput. Otherwise, False. - """ - for field in self.fields.values(): - if field.widget.needs_multipart_form: - return True - return False - -class Form(BaseForm): - "A collection of Fields, plus their associated data." - # This is a separate class from BaseForm in order to abstract the way - # self.fields is specified. This class (Form) is the one that does the - # fancy metaclass stuff purely for the semantic sugar -- it allows one - # to define a form using declarative syntax. - # BaseForm itself has no way of designating self.fields. - __metaclass__ = DeclarativeFieldsMetaclass - -class BoundField(StrAndUnicode): - "A Field plus data" - def __init__(self, form, field, name): - self.form = form - self.field = field - self.name = name - self.html_name = form.add_prefix(name) - if self.field.label is None: - self.label = pretty_name(name) - else: - self.label = self.field.label - self.help_text = field.help_text or '' - - def __unicode__(self): - """Renders this field as an HTML widget.""" - return self.as_widget() - - def _errors(self): - """ - Returns an ErrorList for this field. Returns an empty ErrorList - if there are none. - """ - return self.form.errors.get(self.name, self.form.error_class()) - errors = property(_errors) - - def as_widget(self, widget=None, attrs=None): - """ - Renders the field by rendering the passed widget, adding any HTML - attributes passed as attrs. If no widget is specified, then the - field's default widget will be used. - """ - if not widget: - widget = self.field.widget - attrs = attrs or {} - auto_id = self.auto_id - if auto_id and 'id' not in attrs and 'id' not in widget.attrs: - attrs['id'] = auto_id - if not self.form.is_bound: - data = self.form.initial.get(self.name, self.field.initial) - if callable(data): - data = data() - else: - data = self.data - return widget.render(self.html_name, data, attrs=attrs) - - def as_text(self, attrs=None): - """ - Returns a string of HTML for representing this as an . - """ - return self.as_widget(TextInput(), attrs) - - def as_textarea(self, attrs=None): - "Returns a string of HTML for representing this as a ' % (flatatt(final_attrs), - conditional_escape(force_unicode(value)))) - -class DateTimeInput(Input): - input_type = 'text' - format = '%Y-%m-%d %H:%M:%S' # '2006-10-25 14:30:59' - - def __init__(self, attrs=None, format=None): - super(DateTimeInput, self).__init__(attrs) - if format: - self.format = format - - def render(self, name, value, attrs=None): - if value is None: - value = '' - elif hasattr(value, 'strftime'): - value = value.strftime(self.format) - return super(DateTimeInput, self).render(name, value, attrs) - -class CheckboxInput(Widget): - def __init__(self, attrs=None, check_test=bool): - super(CheckboxInput, self).__init__(attrs) - # check_test is a callable that takes a value and returns True - # if the checkbox should be checked for that value. - self.check_test = check_test - - def render(self, name, value, attrs=None): - final_attrs = self.build_attrs(attrs, type='checkbox', name=name) - try: - result = self.check_test(value) - except: # Silently catch exceptions - result = False - if result: - final_attrs['checked'] = 'checked' - if value not in ('', True, False, None): - # Only add the 'value' attribute if a value is non-empty. - final_attrs['value'] = force_unicode(value) - return mark_safe(u'' % flatatt(final_attrs)) - - def value_from_datadict(self, data, files, name): - if name not in data: - # A missing value means False because HTML form submission does not - # send results for unselected checkboxes. - return False - return super(CheckboxInput, self).value_from_datadict(data, files, name) - -class Select(Widget): - def __init__(self, attrs=None, choices=()): - super(Select, self).__init__(attrs) - # choices can be any iterable, but we may need to render this widget - # multiple times. Thus, collapse it into a list so it can be consumed - # more than once. - self.choices = list(choices) - - def render(self, name, value, attrs=None, choices=()): - if value is None: value = '' - final_attrs = self.build_attrs(attrs, name=name) - output = [u'' % flatatt(final_attrs)] - # Normalize to string. - str_value = force_unicode(value) - for option_value, option_label in chain(self.choices, choices): - option_value = force_unicode(option_value) - selected_html = (option_value == str_value) and u' selected="selected"' or '' - output.append(u'' % ( - escape(option_value), selected_html, - conditional_escape(force_unicode(option_label)))) - output.append(u'') - return mark_safe(u'\n'.join(output)) - -class NullBooleanSelect(Select): - """ - A Select Widget intended to be used with NullBooleanField. - """ - def __init__(self, attrs=None): - choices = ((u'1', ugettext('Unknown')), (u'2', ugettext('Yes')), (u'3', ugettext('No'))) - super(NullBooleanSelect, self).__init__(attrs, choices) - - def render(self, name, value, attrs=None, choices=()): - try: - value = {True: u'2', False: u'3', u'2': u'2', u'3': u'3'}[value] - except KeyError: - value = u'1' - return super(NullBooleanSelect, self).render(name, value, attrs, choices) - - def value_from_datadict(self, data, files, name): - value = data.get(name, None) - return {u'2': True, u'3': False, True: True, False: False}.get(value, None) - -class SelectMultiple(Widget): - def __init__(self, attrs=None, choices=()): - super(SelectMultiple, self).__init__(attrs) - # choices can be any iterable - self.choices = choices - - def render(self, name, value, attrs=None, choices=()): - if value is None: value = [] - final_attrs = self.build_attrs(attrs, name=name) - output = [u'') - return mark_safe(u'\n'.join(output)) - - def value_from_datadict(self, data, files, name): - if isinstance(data, MultiValueDict): - return data.getlist(name) - return data.get(name, None) - -class RadioInput(StrAndUnicode): - """ - An object used by RadioFieldRenderer that represents a single - . - """ - - def __init__(self, name, value, attrs, choice, index): - self.name, self.value = name, value - self.attrs = attrs - self.choice_value = force_unicode(choice[0]) - self.choice_label = force_unicode(choice[1]) - self.index = index - - def __unicode__(self): - return mark_safe(u'' % (self.tag(), - conditional_escape(force_unicode(self.choice_label)))) - - def is_checked(self): - return self.value == self.choice_value - - def tag(self): - if 'id' in self.attrs: - self.attrs['id'] = '%s_%s' % (self.attrs['id'], self.index) - final_attrs = dict(self.attrs, type='radio', name=self.name, value=self.choice_value) - if self.is_checked(): - final_attrs['checked'] = 'checked' - return mark_safe(u'' % flatatt(final_attrs)) - -class RadioFieldRenderer(StrAndUnicode): - """ - An object used by RadioSelect to enable customization of radio widgets. - """ - - def __init__(self, name, value, attrs, choices): - self.name, self.value, self.attrs = name, value, attrs - self.choices = choices - - def __iter__(self): - for i, choice in enumerate(self.choices): - yield RadioInput(self.name, self.value, self.attrs.copy(), choice, i) - - def __getitem__(self, idx): - choice = self.choices[idx] # Let the IndexError propogate - return RadioInput(self.name, self.value, self.attrs.copy(), choice, idx) - - def __unicode__(self): - return self.render() - - def render(self): - """Outputs a