From 28b41056e3ea962dce1ad017a3c0a60252195e7a Mon Sep 17 00:00:00 2001 From: Bharat Mediratta Date: Wed, 27 May 2009 15:07:27 -0700 Subject: Restructure things so that the application is now just another module. Kohana makes this type of transition fairly straightforward in that all controllers/helpers/etc are still located in the cascading filesystem without any extra effort, except that I've temporarily added a hack to force modules/gallery into the module path. Rename what's left of "core" to be "application" so that it conforms more closely to the Kohana standard (basically, just application/config/config.php which is the minimal thing that you need in the application directory) There's still considerable work left to be done here. --- application/config/config.php | 136 +++++ core/config/config.php | 135 ----- core/config/cookie.php | 49 -- core/config/database.php | 23 - core/config/locale.php | 46 -- core/config/routes.php | 31 - core/config/sendmail.php | 29 - core/config/session.php | 66 --- core/config/upload.php | 36 -- core/controllers/admin.php | 52 -- core/controllers/admin_advanced_settings.php | 53 -- core/controllers/admin_dashboard.php | 93 --- core/controllers/admin_graphics.php | 63 --- core/controllers/admin_languages.php | 136 ----- core/controllers/admin_maintenance.php | 181 ------ core/controllers/admin_modules.php | 65 --- core/controllers/admin_theme_details.php | 67 --- core/controllers/admin_themes.php | 79 --- core/controllers/after_install.php | 30 - core/controllers/albums.php | 229 -------- core/controllers/file_proxy.php | 120 ---- core/controllers/items.php | 30 - core/controllers/l10n_client.php | 128 ----- core/controllers/maintenance.php | 24 - core/controllers/move.php | 64 --- core/controllers/movies.php | 114 ---- core/controllers/permissions.php | 80 --- core/controllers/photos.php | 116 ---- core/controllers/quick.php | 122 ---- core/controllers/rest.php | 183 ------ core/controllers/scaffold.php | 437 -------------- core/controllers/simple_uploader.php | 86 --- core/css/debug.css | 28 - core/css/l10n_client.css | 185 ------ core/css/quick.css | 40 -- core/helpers/MY_remote.php | 163 ------ core/helpers/MY_url.php | 81 --- core/helpers/access.php | 628 --------------------- core/helpers/album.php | 132 ----- core/helpers/batch.php | 40 -- core/helpers/block_manager.php | 67 --- core/helpers/core.php | 52 -- core/helpers/core_block.php | 100 ---- core/helpers/core_event.php | 46 -- core/helpers/core_installer.php | 278 --------- core/helpers/core_menu.php | 162 ------ core/helpers/core_search.php | 24 - core/helpers/core_task.php | 166 ------ core/helpers/core_theme.php | 137 ----- core/helpers/dir.php | 40 -- core/helpers/graphics.php | 387 ------------- core/helpers/item.php | 105 ---- core/helpers/l10n_client.php | 203 ------- core/helpers/l10n_scanner.php | 154 ----- core/helpers/locale.php | 119 ---- core/helpers/log.php | 108 ---- core/helpers/message.php | 108 ---- core/helpers/model_cache.php | 46 -- core/helpers/module.php | 357 ------------ core/helpers/movie.php | 153 ----- core/helpers/photo.php | 171 ------ core/helpers/rest.php | 116 ---- core/helpers/site_status.php | 132 ----- core/helpers/task.php | 83 --- core/helpers/theme.php | 61 -- core/helpers/xml.php | 35 -- core/hooks/init_gallery.php | 44 -- core/images/gallery.png | Bin 22178 -> 0 bytes core/images/gd.png | Bin 5531 -> 0 bytes core/images/graphicsmagick.png | Bin 1486 -> 0 bytes core/images/imagemagick.jpg | Bin 20337 -> 0 bytes core/js/albums_form_add.js | 12 - core/js/fullsize.js | 78 --- core/js/l10n_client.js | 195 ------- core/js/quick.js | 95 ---- core/libraries/Admin_View.php | 126 ----- core/libraries/Block.php | 30 - core/libraries/I18n.php | 410 -------------- core/libraries/MY_Database.php | 92 --- core/libraries/MY_Forge.php | 59 -- core/libraries/MY_ORM.php | 46 -- core/libraries/MY_Pagination.php | 35 -- core/libraries/MY_View.php | 46 -- core/libraries/Menu.php | 187 ------ core/libraries/ORM_MPTT.php | 307 ---------- core/libraries/Sendmail.php | 97 ---- core/libraries/Task_Definition.php | 50 -- core/libraries/Theme_View.php | 221 -------- core/models/access_cache.php | 21 - core/models/access_intent.php | 21 - core/models/graphics_rule.php | 21 - core/models/incoming_translation.php | 21 - core/models/item.php | 497 ---------------- core/models/log.php | 22 - core/models/message.php | 21 - core/models/module.php | 21 - core/models/outgoing_translation.php | 21 - core/models/permission.php | 21 - core/models/task.php | 46 -- core/models/theme.php | 21 - core/models/var.php | 21 - core/module.info | 3 - core/tests/Access_Helper_Test.php | 323 ----------- core/tests/Album_Helper_Test.php | 87 --- core/tests/Albums_Controller_Test.php | 76 --- core/tests/Core_Installer_Test.php | 50 -- core/tests/Database_Test.php | 134 ----- core/tests/Dir_Helper_Test.php | 32 -- core/tests/DrawForm_Test.php | 84 --- core/tests/File_Structure_Test.php | 235 -------- core/tests/I18n_Test.php | 108 ---- core/tests/Item_Model_Test.php | 143 ----- core/tests/Menu_Test.php | 32 -- core/tests/Movie_Helper_Test.php | 46 -- core/tests/ORM_MPTT_Test.php | 221 -------- core/tests/Photo_Helper_Test.php | 109 ---- core/tests/Photos_Controller_Test.php | 74 --- core/tests/REST_Controller_Test.php | 197 ------- core/tests/REST_Helper_Test.php | 45 -- core/tests/Sendmail_Test.php | 115 ---- core/tests/Var_Test.php | 49 -- core/tests/images/DSC_0003.jpg | Bin 735609 -> 0 bytes core/tests/images/DSC_0005.jpg | Bin 687555 -> 0 bytes core/tests/images/DSC_0017.jpg | Bin 1246655 -> 0 bytes core/tests/images/DSC_0019.jpg | Bin 649556 -> 0 bytes core/tests/images/DSC_0067.jpg | Bin 1245526 -> 0 bytes core/tests/images/DSC_0072.jpg | Bin 1014511 -> 0 bytes core/tests/images/P4050088.jpg | Bin 1774906 -> 0 bytes core/tests/selenium/Add_Album.html | 52 -- core/tests/selenium/Add_Comment.html | 52 -- core/tests/selenium/Add_Item.html | 62 -- core/tests/selenium/Login.html | 47 -- core/tests/test.jpg | Bin 6232 -> 0 bytes core/views/admin_advanced_settings.html.php | 34 -- core/views/admin_block_log_entries.html.php | 11 - core/views/admin_block_news.html.php | 11 - core/views/admin_block_photo_stream.html.php | 14 - core/views/admin_block_platform.html.php | 18 - core/views/admin_block_stats.html.php | 12 - core/views/admin_block_welcome.html.php | 20 - core/views/admin_dashboard.html.php | 38 -- core/views/admin_graphics.html.php | 28 - core/views/admin_graphics_gd.html.php | 29 - core/views/admin_graphics_graphicsmagick.html.php | 21 - core/views/admin_graphics_imagemagick.html.php | 21 - core/views/admin_graphics_none.html.php | 7 - core/views/admin_languages.html.php | 15 - core/views/admin_maintenance.html.php | 181 ------ core/views/admin_maintenance_task.html.php | 32 -- core/views/admin_modules.html.php | 32 -- core/views/admin_theme_details.html.php | 6 - core/views/admin_themes.html.php | 89 --- core/views/admin_themes_preview.html.php | 7 - core/views/after_install.html.php | 29 - core/views/after_install_loader.html.php | 7 - core/views/form.html.php | 75 --- core/views/kohana_error_page.php | 118 ---- core/views/kohana_profiler.php | 35 -- core/views/l10n_client.html.php | 31 - core/views/maintenance.html.php | 50 -- core/views/move_browse.html.php | 47 -- core/views/move_tree.html.php | 19 - core/views/permissions_browse.html.php | 56 -- core/views/permissions_form.html.php | 94 --- core/views/quick_pane.html.php | 108 ---- core/views/scaffold.html.php | 169 ------ core/views/simple_uploader.html.php | 249 -------- index.php | 2 +- modules/gallery/config/cookie.php | 49 ++ modules/gallery/config/database.php | 23 + modules/gallery/config/locale.php | 46 ++ modules/gallery/config/routes.php | 31 + modules/gallery/config/sendmail.php | 29 + modules/gallery/config/session.php | 66 +++ modules/gallery/config/upload.php | 36 ++ modules/gallery/controllers/admin.php | 52 ++ .../controllers/admin_advanced_settings.php | 53 ++ modules/gallery/controllers/admin_dashboard.php | 93 +++ modules/gallery/controllers/admin_graphics.php | 63 +++ modules/gallery/controllers/admin_languages.php | 136 +++++ modules/gallery/controllers/admin_maintenance.php | 181 ++++++ modules/gallery/controllers/admin_modules.php | 65 +++ .../gallery/controllers/admin_theme_details.php | 67 +++ modules/gallery/controllers/admin_themes.php | 79 +++ modules/gallery/controllers/after_install.php | 30 + modules/gallery/controllers/albums.php | 229 ++++++++ modules/gallery/controllers/file_proxy.php | 120 ++++ modules/gallery/controllers/items.php | 30 + modules/gallery/controllers/l10n_client.php | 128 +++++ modules/gallery/controllers/maintenance.php | 24 + modules/gallery/controllers/move.php | 64 +++ modules/gallery/controllers/movies.php | 114 ++++ modules/gallery/controllers/permissions.php | 80 +++ modules/gallery/controllers/photos.php | 116 ++++ modules/gallery/controllers/quick.php | 122 ++++ modules/gallery/controllers/rest.php | 183 ++++++ modules/gallery/controllers/scaffold.php | 437 ++++++++++++++ modules/gallery/controllers/simple_uploader.php | 86 +++ modules/gallery/css/debug.css | 28 + modules/gallery/css/l10n_client.css | 185 ++++++ modules/gallery/css/quick.css | 40 ++ modules/gallery/helpers/MY_remote.php | 163 ++++++ modules/gallery/helpers/MY_url.php | 81 +++ modules/gallery/helpers/access.php | 628 +++++++++++++++++++++ modules/gallery/helpers/album.php | 132 +++++ modules/gallery/helpers/batch.php | 40 ++ modules/gallery/helpers/block_manager.php | 67 +++ modules/gallery/helpers/core.php | 52 ++ modules/gallery/helpers/core_block.php | 100 ++++ modules/gallery/helpers/core_event.php | 46 ++ modules/gallery/helpers/core_installer.php | 278 +++++++++ modules/gallery/helpers/core_menu.php | 162 ++++++ modules/gallery/helpers/core_search.php | 24 + modules/gallery/helpers/core_task.php | 166 ++++++ modules/gallery/helpers/core_theme.php | 137 +++++ modules/gallery/helpers/dir.php | 40 ++ modules/gallery/helpers/graphics.php | 387 +++++++++++++ modules/gallery/helpers/item.php | 105 ++++ modules/gallery/helpers/l10n_client.php | 203 +++++++ modules/gallery/helpers/l10n_scanner.php | 154 +++++ modules/gallery/helpers/locale.php | 119 ++++ modules/gallery/helpers/log.php | 108 ++++ modules/gallery/helpers/message.php | 108 ++++ modules/gallery/helpers/model_cache.php | 46 ++ modules/gallery/helpers/module.php | 357 ++++++++++++ modules/gallery/helpers/movie.php | 153 +++++ modules/gallery/helpers/photo.php | 171 ++++++ modules/gallery/helpers/rest.php | 116 ++++ modules/gallery/helpers/site_status.php | 132 +++++ modules/gallery/helpers/task.php | 83 +++ modules/gallery/helpers/theme.php | 61 ++ modules/gallery/helpers/xml.php | 35 ++ modules/gallery/hooks/init_gallery.php | 44 ++ modules/gallery/images/gallery.png | Bin 0 -> 22178 bytes modules/gallery/images/gd.png | Bin 0 -> 5531 bytes modules/gallery/images/graphicsmagick.png | Bin 0 -> 1486 bytes modules/gallery/images/imagemagick.jpg | Bin 0 -> 20337 bytes modules/gallery/js/albums_form_add.js | 12 + modules/gallery/js/fullsize.js | 78 +++ modules/gallery/js/l10n_client.js | 195 +++++++ modules/gallery/js/quick.js | 95 ++++ modules/gallery/libraries/Admin_View.php | 126 +++++ modules/gallery/libraries/Block.php | 30 + modules/gallery/libraries/I18n.php | 410 ++++++++++++++ modules/gallery/libraries/MY_Database.php | 92 +++ modules/gallery/libraries/MY_Forge.php | 59 ++ modules/gallery/libraries/MY_ORM.php | 46 ++ modules/gallery/libraries/MY_Pagination.php | 35 ++ modules/gallery/libraries/MY_View.php | 46 ++ modules/gallery/libraries/Menu.php | 187 ++++++ modules/gallery/libraries/ORM_MPTT.php | 307 ++++++++++ modules/gallery/libraries/Sendmail.php | 97 ++++ modules/gallery/libraries/Task_Definition.php | 50 ++ modules/gallery/libraries/Theme_View.php | 221 ++++++++ modules/gallery/models/access_cache.php | 21 + modules/gallery/models/access_intent.php | 21 + modules/gallery/models/graphics_rule.php | 21 + modules/gallery/models/incoming_translation.php | 21 + modules/gallery/models/item.php | 497 ++++++++++++++++ modules/gallery/models/log.php | 22 + modules/gallery/models/message.php | 21 + modules/gallery/models/module.php | 21 + modules/gallery/models/outgoing_translation.php | 21 + modules/gallery/models/permission.php | 21 + modules/gallery/models/task.php | 46 ++ modules/gallery/models/theme.php | 21 + modules/gallery/models/var.php | 21 + modules/gallery/module.info | 3 + modules/gallery/tests/Access_Helper_Test.php | 323 +++++++++++ modules/gallery/tests/Album_Helper_Test.php | 87 +++ modules/gallery/tests/Albums_Controller_Test.php | 76 +++ modules/gallery/tests/Core_Installer_Test.php | 50 ++ modules/gallery/tests/Database_Test.php | 134 +++++ modules/gallery/tests/Dir_Helper_Test.php | 32 ++ modules/gallery/tests/DrawForm_Test.php | 84 +++ modules/gallery/tests/File_Structure_Test.php | 235 ++++++++ modules/gallery/tests/I18n_Test.php | 108 ++++ modules/gallery/tests/Item_Model_Test.php | 143 +++++ modules/gallery/tests/Menu_Test.php | 32 ++ modules/gallery/tests/Movie_Helper_Test.php | 46 ++ modules/gallery/tests/ORM_MPTT_Test.php | 221 ++++++++ modules/gallery/tests/Photo_Helper_Test.php | 109 ++++ modules/gallery/tests/Photos_Controller_Test.php | 74 +++ modules/gallery/tests/REST_Controller_Test.php | 197 +++++++ modules/gallery/tests/REST_Helper_Test.php | 45 ++ modules/gallery/tests/Sendmail_Test.php | 115 ++++ modules/gallery/tests/Var_Test.php | 49 ++ modules/gallery/tests/images/DSC_0003.jpg | Bin 0 -> 735609 bytes modules/gallery/tests/images/DSC_0005.jpg | Bin 0 -> 687555 bytes modules/gallery/tests/images/DSC_0017.jpg | Bin 0 -> 1246655 bytes modules/gallery/tests/images/DSC_0019.jpg | Bin 0 -> 649556 bytes modules/gallery/tests/images/DSC_0067.jpg | Bin 0 -> 1245526 bytes modules/gallery/tests/images/DSC_0072.jpg | Bin 0 -> 1014511 bytes modules/gallery/tests/images/P4050088.jpg | Bin 0 -> 1774906 bytes modules/gallery/tests/selenium/Add_Album.html | 52 ++ modules/gallery/tests/selenium/Add_Comment.html | 52 ++ modules/gallery/tests/selenium/Add_Item.html | 62 ++ modules/gallery/tests/selenium/Login.html | 47 ++ modules/gallery/tests/test.jpg | Bin 0 -> 6232 bytes .../gallery/views/admin_advanced_settings.html.php | 34 ++ .../gallery/views/admin_block_log_entries.html.php | 11 + modules/gallery/views/admin_block_news.html.php | 11 + .../views/admin_block_photo_stream.html.php | 14 + .../gallery/views/admin_block_platform.html.php | 18 + modules/gallery/views/admin_block_stats.html.php | 12 + modules/gallery/views/admin_block_welcome.html.php | 20 + modules/gallery/views/admin_dashboard.html.php | 38 ++ modules/gallery/views/admin_graphics.html.php | 28 + modules/gallery/views/admin_graphics_gd.html.php | 29 + .../views/admin_graphics_graphicsmagick.html.php | 21 + .../views/admin_graphics_imagemagick.html.php | 21 + modules/gallery/views/admin_graphics_none.html.php | 7 + modules/gallery/views/admin_languages.html.php | 15 + modules/gallery/views/admin_maintenance.html.php | 181 ++++++ .../gallery/views/admin_maintenance_task.html.php | 32 ++ modules/gallery/views/admin_modules.html.php | 32 ++ modules/gallery/views/admin_theme_details.html.php | 6 + modules/gallery/views/admin_themes.html.php | 89 +++ .../gallery/views/admin_themes_preview.html.php | 7 + modules/gallery/views/after_install.html.php | 29 + .../gallery/views/after_install_loader.html.php | 7 + modules/gallery/views/form.html.php | 75 +++ modules/gallery/views/kohana_error_page.php | 118 ++++ modules/gallery/views/kohana_profiler.php | 35 ++ modules/gallery/views/l10n_client.html.php | 31 + modules/gallery/views/maintenance.html.php | 50 ++ modules/gallery/views/move_browse.html.php | 47 ++ modules/gallery/views/move_tree.html.php | 19 + modules/gallery/views/permissions_browse.html.php | 56 ++ modules/gallery/views/permissions_form.html.php | 94 +++ modules/gallery/views/quick_pane.html.php | 108 ++++ modules/gallery/views/scaffold.html.php | 169 ++++++ modules/gallery/views/simple_uploader.html.php | 249 ++++++++ 333 files changed, 14670 insertions(+), 14669 deletions(-) create mode 100644 application/config/config.php delete mode 100644 core/config/config.php delete mode 100644 core/config/cookie.php delete mode 100644 core/config/database.php delete mode 100644 core/config/locale.php delete mode 100644 core/config/routes.php delete mode 100644 core/config/sendmail.php delete mode 100644 core/config/session.php delete mode 100644 core/config/upload.php delete mode 100644 core/controllers/admin.php delete mode 100644 core/controllers/admin_advanced_settings.php delete mode 100644 core/controllers/admin_dashboard.php delete mode 100644 core/controllers/admin_graphics.php delete mode 100644 core/controllers/admin_languages.php delete mode 100644 core/controllers/admin_maintenance.php delete mode 100644 core/controllers/admin_modules.php delete mode 100644 core/controllers/admin_theme_details.php delete mode 100644 core/controllers/admin_themes.php delete mode 100644 core/controllers/after_install.php delete mode 100644 core/controllers/albums.php delete mode 100644 core/controllers/file_proxy.php delete mode 100644 core/controllers/items.php delete mode 100644 core/controllers/l10n_client.php delete mode 100644 core/controllers/maintenance.php delete mode 100644 core/controllers/move.php delete mode 100644 core/controllers/movies.php delete mode 100644 core/controllers/permissions.php delete mode 100644 core/controllers/photos.php delete mode 100644 core/controllers/quick.php delete mode 100644 core/controllers/rest.php delete mode 100644 core/controllers/scaffold.php delete mode 100644 core/controllers/simple_uploader.php delete mode 100644 core/css/debug.css delete mode 100644 core/css/l10n_client.css delete mode 100644 core/css/quick.css delete mode 100644 core/helpers/MY_remote.php delete mode 100644 core/helpers/MY_url.php delete mode 100644 core/helpers/access.php delete mode 100644 core/helpers/album.php delete mode 100644 core/helpers/batch.php delete mode 100644 core/helpers/block_manager.php delete mode 100644 core/helpers/core.php delete mode 100644 core/helpers/core_block.php delete mode 100644 core/helpers/core_event.php delete mode 100644 core/helpers/core_installer.php delete mode 100644 core/helpers/core_menu.php delete mode 100644 core/helpers/core_search.php delete mode 100644 core/helpers/core_task.php delete mode 100644 core/helpers/core_theme.php delete mode 100644 core/helpers/dir.php delete mode 100644 core/helpers/graphics.php delete mode 100644 core/helpers/item.php delete mode 100644 core/helpers/l10n_client.php delete mode 100644 core/helpers/l10n_scanner.php delete mode 100644 core/helpers/locale.php delete mode 100644 core/helpers/log.php delete mode 100644 core/helpers/message.php delete mode 100644 core/helpers/model_cache.php delete mode 100644 core/helpers/module.php delete mode 100644 core/helpers/movie.php delete mode 100644 core/helpers/photo.php delete mode 100644 core/helpers/rest.php delete mode 100644 core/helpers/site_status.php delete mode 100644 core/helpers/task.php delete mode 100644 core/helpers/theme.php delete mode 100644 core/helpers/xml.php delete mode 100644 core/hooks/init_gallery.php delete mode 100644 core/images/gallery.png delete mode 100644 core/images/gd.png delete mode 100644 core/images/graphicsmagick.png delete mode 100644 core/images/imagemagick.jpg delete mode 100644 core/js/albums_form_add.js delete mode 100644 core/js/fullsize.js delete mode 100644 core/js/l10n_client.js delete mode 100644 core/js/quick.js delete mode 100644 core/libraries/Admin_View.php delete mode 100644 core/libraries/Block.php delete mode 100644 core/libraries/I18n.php delete mode 100644 core/libraries/MY_Database.php delete mode 100644 core/libraries/MY_Forge.php delete mode 100644 core/libraries/MY_ORM.php delete mode 100644 core/libraries/MY_Pagination.php delete mode 100644 core/libraries/MY_View.php delete mode 100644 core/libraries/Menu.php delete mode 100644 core/libraries/ORM_MPTT.php delete mode 100644 core/libraries/Sendmail.php delete mode 100644 core/libraries/Task_Definition.php delete mode 100644 core/libraries/Theme_View.php delete mode 100644 core/models/access_cache.php delete mode 100644 core/models/access_intent.php delete mode 100644 core/models/graphics_rule.php delete mode 100644 core/models/incoming_translation.php delete mode 100644 core/models/item.php delete mode 100644 core/models/log.php delete mode 100644 core/models/message.php delete mode 100644 core/models/module.php delete mode 100644 core/models/outgoing_translation.php delete mode 100644 core/models/permission.php delete mode 100644 core/models/task.php delete mode 100644 core/models/theme.php delete mode 100644 core/models/var.php delete mode 100644 core/module.info delete mode 100644 core/tests/Access_Helper_Test.php delete mode 100644 core/tests/Album_Helper_Test.php delete mode 100644 core/tests/Albums_Controller_Test.php delete mode 100644 core/tests/Core_Installer_Test.php delete mode 100644 core/tests/Database_Test.php delete mode 100644 core/tests/Dir_Helper_Test.php delete mode 100644 core/tests/DrawForm_Test.php delete mode 100644 core/tests/File_Structure_Test.php delete mode 100644 core/tests/I18n_Test.php delete mode 100644 core/tests/Item_Model_Test.php delete mode 100644 core/tests/Menu_Test.php delete mode 100644 core/tests/Movie_Helper_Test.php delete mode 100644 core/tests/ORM_MPTT_Test.php delete mode 100644 core/tests/Photo_Helper_Test.php delete mode 100644 core/tests/Photos_Controller_Test.php delete mode 100644 core/tests/REST_Controller_Test.php delete mode 100644 core/tests/REST_Helper_Test.php delete mode 100644 core/tests/Sendmail_Test.php delete mode 100644 core/tests/Var_Test.php delete mode 100644 core/tests/images/DSC_0003.jpg delete mode 100644 core/tests/images/DSC_0005.jpg delete mode 100644 core/tests/images/DSC_0017.jpg delete mode 100644 core/tests/images/DSC_0019.jpg delete mode 100644 core/tests/images/DSC_0067.jpg delete mode 100644 core/tests/images/DSC_0072.jpg delete mode 100644 core/tests/images/P4050088.jpg delete mode 100644 core/tests/selenium/Add_Album.html delete mode 100644 core/tests/selenium/Add_Comment.html delete mode 100644 core/tests/selenium/Add_Item.html delete mode 100644 core/tests/selenium/Login.html delete mode 100644 core/tests/test.jpg delete mode 100644 core/views/admin_advanced_settings.html.php delete mode 100644 core/views/admin_block_log_entries.html.php delete mode 100644 core/views/admin_block_news.html.php delete mode 100644 core/views/admin_block_photo_stream.html.php delete mode 100644 core/views/admin_block_platform.html.php delete mode 100644 core/views/admin_block_stats.html.php delete mode 100644 core/views/admin_block_welcome.html.php delete mode 100644 core/views/admin_dashboard.html.php delete mode 100644 core/views/admin_graphics.html.php delete mode 100644 core/views/admin_graphics_gd.html.php delete mode 100644 core/views/admin_graphics_graphicsmagick.html.php delete mode 100644 core/views/admin_graphics_imagemagick.html.php delete mode 100644 core/views/admin_graphics_none.html.php delete mode 100644 core/views/admin_languages.html.php delete mode 100644 core/views/admin_maintenance.html.php delete mode 100644 core/views/admin_maintenance_task.html.php delete mode 100644 core/views/admin_modules.html.php delete mode 100644 core/views/admin_theme_details.html.php delete mode 100644 core/views/admin_themes.html.php delete mode 100644 core/views/admin_themes_preview.html.php delete mode 100644 core/views/after_install.html.php delete mode 100644 core/views/after_install_loader.html.php delete mode 100644 core/views/form.html.php delete mode 100644 core/views/kohana_error_page.php delete mode 100644 core/views/kohana_profiler.php delete mode 100644 core/views/l10n_client.html.php delete mode 100644 core/views/maintenance.html.php delete mode 100644 core/views/move_browse.html.php delete mode 100644 core/views/move_tree.html.php delete mode 100644 core/views/permissions_browse.html.php delete mode 100644 core/views/permissions_form.html.php delete mode 100644 core/views/quick_pane.html.php delete mode 100644 core/views/scaffold.html.php delete mode 100644 core/views/simple_uploader.html.php create mode 100644 modules/gallery/config/cookie.php create mode 100644 modules/gallery/config/database.php create mode 100644 modules/gallery/config/locale.php create mode 100644 modules/gallery/config/routes.php create mode 100644 modules/gallery/config/sendmail.php create mode 100644 modules/gallery/config/session.php create mode 100644 modules/gallery/config/upload.php create mode 100644 modules/gallery/controllers/admin.php create mode 100644 modules/gallery/controllers/admin_advanced_settings.php create mode 100644 modules/gallery/controllers/admin_dashboard.php create mode 100644 modules/gallery/controllers/admin_graphics.php create mode 100644 modules/gallery/controllers/admin_languages.php create mode 100644 modules/gallery/controllers/admin_maintenance.php create mode 100644 modules/gallery/controllers/admin_modules.php create mode 100644 modules/gallery/controllers/admin_theme_details.php create mode 100644 modules/gallery/controllers/admin_themes.php create mode 100644 modules/gallery/controllers/after_install.php create mode 100644 modules/gallery/controllers/albums.php create mode 100644 modules/gallery/controllers/file_proxy.php create mode 100644 modules/gallery/controllers/items.php create mode 100644 modules/gallery/controllers/l10n_client.php create mode 100644 modules/gallery/controllers/maintenance.php create mode 100644 modules/gallery/controllers/move.php create mode 100644 modules/gallery/controllers/movies.php create mode 100644 modules/gallery/controllers/permissions.php create mode 100644 modules/gallery/controllers/photos.php create mode 100644 modules/gallery/controllers/quick.php create mode 100644 modules/gallery/controllers/rest.php create mode 100644 modules/gallery/controllers/scaffold.php create mode 100644 modules/gallery/controllers/simple_uploader.php create mode 100644 modules/gallery/css/debug.css create mode 100644 modules/gallery/css/l10n_client.css create mode 100644 modules/gallery/css/quick.css create mode 100644 modules/gallery/helpers/MY_remote.php create mode 100644 modules/gallery/helpers/MY_url.php create mode 100644 modules/gallery/helpers/access.php create mode 100644 modules/gallery/helpers/album.php create mode 100644 modules/gallery/helpers/batch.php create mode 100644 modules/gallery/helpers/block_manager.php create mode 100644 modules/gallery/helpers/core.php create mode 100644 modules/gallery/helpers/core_block.php create mode 100644 modules/gallery/helpers/core_event.php create mode 100644 modules/gallery/helpers/core_installer.php create mode 100644 modules/gallery/helpers/core_menu.php create mode 100644 modules/gallery/helpers/core_search.php create mode 100644 modules/gallery/helpers/core_task.php create mode 100644 modules/gallery/helpers/core_theme.php create mode 100644 modules/gallery/helpers/dir.php create mode 100644 modules/gallery/helpers/graphics.php create mode 100644 modules/gallery/helpers/item.php create mode 100644 modules/gallery/helpers/l10n_client.php create mode 100644 modules/gallery/helpers/l10n_scanner.php create mode 100644 modules/gallery/helpers/locale.php create mode 100644 modules/gallery/helpers/log.php create mode 100644 modules/gallery/helpers/message.php create mode 100644 modules/gallery/helpers/model_cache.php create mode 100644 modules/gallery/helpers/module.php create mode 100644 modules/gallery/helpers/movie.php create mode 100644 modules/gallery/helpers/photo.php create mode 100644 modules/gallery/helpers/rest.php create mode 100644 modules/gallery/helpers/site_status.php create mode 100644 modules/gallery/helpers/task.php create mode 100644 modules/gallery/helpers/theme.php create mode 100644 modules/gallery/helpers/xml.php create mode 100644 modules/gallery/hooks/init_gallery.php create mode 100644 modules/gallery/images/gallery.png create mode 100644 modules/gallery/images/gd.png create mode 100644 modules/gallery/images/graphicsmagick.png create mode 100644 modules/gallery/images/imagemagick.jpg create mode 100644 modules/gallery/js/albums_form_add.js create mode 100644 modules/gallery/js/fullsize.js create mode 100644 modules/gallery/js/l10n_client.js create mode 100644 modules/gallery/js/quick.js create mode 100644 modules/gallery/libraries/Admin_View.php create mode 100644 modules/gallery/libraries/Block.php create mode 100644 modules/gallery/libraries/I18n.php create mode 100644 modules/gallery/libraries/MY_Database.php create mode 100644 modules/gallery/libraries/MY_Forge.php create mode 100644 modules/gallery/libraries/MY_ORM.php create mode 100644 modules/gallery/libraries/MY_Pagination.php create mode 100644 modules/gallery/libraries/MY_View.php create mode 100644 modules/gallery/libraries/Menu.php create mode 100644 modules/gallery/libraries/ORM_MPTT.php create mode 100644 modules/gallery/libraries/Sendmail.php create mode 100644 modules/gallery/libraries/Task_Definition.php create mode 100644 modules/gallery/libraries/Theme_View.php create mode 100644 modules/gallery/models/access_cache.php create mode 100644 modules/gallery/models/access_intent.php create mode 100644 modules/gallery/models/graphics_rule.php create mode 100644 modules/gallery/models/incoming_translation.php create mode 100644 modules/gallery/models/item.php create mode 100644 modules/gallery/models/log.php create mode 100644 modules/gallery/models/message.php create mode 100644 modules/gallery/models/module.php create mode 100644 modules/gallery/models/outgoing_translation.php create mode 100644 modules/gallery/models/permission.php create mode 100644 modules/gallery/models/task.php create mode 100644 modules/gallery/models/theme.php create mode 100644 modules/gallery/models/var.php create mode 100644 modules/gallery/module.info create mode 100644 modules/gallery/tests/Access_Helper_Test.php create mode 100644 modules/gallery/tests/Album_Helper_Test.php create mode 100644 modules/gallery/tests/Albums_Controller_Test.php create mode 100644 modules/gallery/tests/Core_Installer_Test.php create mode 100644 modules/gallery/tests/Database_Test.php create mode 100644 modules/gallery/tests/Dir_Helper_Test.php create mode 100644 modules/gallery/tests/DrawForm_Test.php create mode 100644 modules/gallery/tests/File_Structure_Test.php create mode 100644 modules/gallery/tests/I18n_Test.php create mode 100644 modules/gallery/tests/Item_Model_Test.php create mode 100644 modules/gallery/tests/Menu_Test.php create mode 100644 modules/gallery/tests/Movie_Helper_Test.php create mode 100644 modules/gallery/tests/ORM_MPTT_Test.php create mode 100644 modules/gallery/tests/Photo_Helper_Test.php create mode 100644 modules/gallery/tests/Photos_Controller_Test.php create mode 100644 modules/gallery/tests/REST_Controller_Test.php create mode 100644 modules/gallery/tests/REST_Helper_Test.php create mode 100644 modules/gallery/tests/Sendmail_Test.php create mode 100644 modules/gallery/tests/Var_Test.php create mode 100644 modules/gallery/tests/images/DSC_0003.jpg create mode 100644 modules/gallery/tests/images/DSC_0005.jpg create mode 100644 modules/gallery/tests/images/DSC_0017.jpg create mode 100644 modules/gallery/tests/images/DSC_0019.jpg create mode 100644 modules/gallery/tests/images/DSC_0067.jpg create mode 100644 modules/gallery/tests/images/DSC_0072.jpg create mode 100644 modules/gallery/tests/images/P4050088.jpg create mode 100644 modules/gallery/tests/selenium/Add_Album.html create mode 100644 modules/gallery/tests/selenium/Add_Comment.html create mode 100644 modules/gallery/tests/selenium/Add_Item.html create mode 100644 modules/gallery/tests/selenium/Login.html create mode 100644 modules/gallery/tests/test.jpg create mode 100644 modules/gallery/views/admin_advanced_settings.html.php create mode 100644 modules/gallery/views/admin_block_log_entries.html.php create mode 100644 modules/gallery/views/admin_block_news.html.php create mode 100644 modules/gallery/views/admin_block_photo_stream.html.php create mode 100644 modules/gallery/views/admin_block_platform.html.php create mode 100644 modules/gallery/views/admin_block_stats.html.php create mode 100644 modules/gallery/views/admin_block_welcome.html.php create mode 100644 modules/gallery/views/admin_dashboard.html.php create mode 100644 modules/gallery/views/admin_graphics.html.php create mode 100644 modules/gallery/views/admin_graphics_gd.html.php create mode 100644 modules/gallery/views/admin_graphics_graphicsmagick.html.php create mode 100644 modules/gallery/views/admin_graphics_imagemagick.html.php create mode 100644 modules/gallery/views/admin_graphics_none.html.php create mode 100644 modules/gallery/views/admin_languages.html.php create mode 100644 modules/gallery/views/admin_maintenance.html.php create mode 100644 modules/gallery/views/admin_maintenance_task.html.php create mode 100644 modules/gallery/views/admin_modules.html.php create mode 100644 modules/gallery/views/admin_theme_details.html.php create mode 100644 modules/gallery/views/admin_themes.html.php create mode 100644 modules/gallery/views/admin_themes_preview.html.php create mode 100644 modules/gallery/views/after_install.html.php create mode 100644 modules/gallery/views/after_install_loader.html.php create mode 100644 modules/gallery/views/form.html.php create mode 100644 modules/gallery/views/kohana_error_page.php create mode 100644 modules/gallery/views/kohana_profiler.php create mode 100644 modules/gallery/views/l10n_client.html.php create mode 100644 modules/gallery/views/maintenance.html.php create mode 100644 modules/gallery/views/move_browse.html.php create mode 100644 modules/gallery/views/move_tree.html.php create mode 100644 modules/gallery/views/permissions_browse.html.php create mode 100644 modules/gallery/views/permissions_form.html.php create mode 100644 modules/gallery/views/quick_pane.html.php create mode 100644 modules/gallery/views/scaffold.html.php create mode 100644 modules/gallery/views/simple_uploader.html.php diff --git a/application/config/config.php b/application/config/config.php new file mode 100644 index 00000000..92886dbe --- /dev/null +++ b/application/config/config.php @@ -0,0 +1,136 @@ + email address that appears as the from address - * line-length => word wrap length (PHP documentations suggest no larger tha 70 characters - * reply-to => what goes into the reply to header - */ -$config["from"] = "admin@gallery3.com"; -$config["line_length"] = 70; -$config["reply_to"] = "public@gallery3.com"; -$config["header_separator"] = "\n"; diff --git a/core/config/session.php b/core/config/session.php deleted file mode 100644 index 990fa31f..00000000 --- a/core/config/session.php +++ /dev/null @@ -1,66 +0,0 @@ -admin)) { - throw new Exception("@todo UNAUTHORIZED", 401); - } - parent::__construct(); - } - - public function __call($controller_name, $args) { - if (request::method() == "post") { - access::verify_csrf(); - } - - if ($controller_name == "index") { - $controller_name = "dashboard"; - } - $controller_name = "Admin_{$controller_name}_Controller"; - if ($args) { - $method = array_shift($args); - } else { - $method = "index"; - } - - if (!method_exists($controller_name, $method)) { - return kohana::show_404(); - } - - call_user_func_array(array(new $controller_name, $method), $args); - } -} - diff --git a/core/controllers/admin_advanced_settings.php b/core/controllers/admin_advanced_settings.php deleted file mode 100644 index 79bc1183..00000000 --- a/core/controllers/admin_advanced_settings.php +++ /dev/null @@ -1,53 +0,0 @@ -content = new View("admin_advanced_settings.html"); - $view->content->vars = ORM::factory("var") - ->orderby("module_name", "name") - ->find_all(); - print $view; - } - - public function edit($module_name, $var_name) { - $value = module::get_var($module_name, $var_name); - $form = new Forge("admin/advanced_settings/save/$module_name/$var_name", "", "post"); - $group = $form->group("edit_var")->label( - t("Edit %var (%module_name)", - array("module_name" => $module_name, "var" => $var_name))); - $group->input("module_name")->label(t("Module"))->value($module_name)->disabled(1); - $group->input("var_name")->label(t("Setting"))->value($var_name)->disabled(1); - $group->textarea("value")->label(t("Value"))->value($value); - $group->submit("")->value(t("Save")); - print $form; - } - - public function save($module_name, $var_name) { - access::verify_csrf(); - - module::set_var($module_name, $var_name, Input::instance()->post("value")); - message::success( - t("Saved value for %var (%module_name)", - array("var" => $var_name, "module_name" => $module_name))); - - print json_encode(array("result" => "success")); - } -} diff --git a/core/controllers/admin_dashboard.php b/core/controllers/admin_dashboard.php deleted file mode 100644 index d2d2f79b..00000000 --- a/core/controllers/admin_dashboard.php +++ /dev/null @@ -1,93 +0,0 @@ -content = new View("admin_dashboard.html"); - $view->content->blocks = block_manager::get_html("dashboard_center"); - $view->sidebar = "
" . - block_manager::get_html("dashboard_sidebar") . - "
"; - print $view; - } - - public function add_block() { - $form = core_block::get_add_block_form(); - if ($form->validate()) { - list ($module_name, $id) = explode(":", $form->add_block->id->value); - $available = block_manager::get_available(); - - if ($form->add_block->center->value) { - block_manager::add("dashboard_center", $module_name, $id); - message::success( - t("Added %title block to the dashboard center", - array("title" => $available["$module_name:$id"]))); - } else { - block_manager::add("dashboard_sidebar", $module_name, $id); - message::success( - t("Added %title to the dashboard sidebar", - array("title" => $available["$module_name:$id"]))); - } - } - url::redirect("admin/dashboard"); - } - - public function remove_block($id) { - access::verify_csrf(); - $blocks_center = block_manager::get_active("dashboard_center"); - $blocks_sidebar = block_manager::get_active("dashboard_sidebar"); - - if (array_key_exists($id, $blocks_sidebar)) { - $deleted = $blocks_sidebar[$id]; - block_manager::remove("dashboard_sidebar", $id); - } else if (array_key_exists($id, $blocks_center)) { - $deleted = $blocks_center[$id]; - block_manager::remove("dashboard_center", $id); - } - - if (!empty($deleted)) { - $available = block_manager::get_available(); - $title = $available[join(":", $deleted)]; - message::success(t("Removed %title block", array("title" => $title))); - } - - url::redirect("admin"); - } - - public function reorder() { - access::verify_csrf(); - $active_set = array(); - foreach (array("dashboard_sidebar", "dashboard_center") as $location) { - foreach (block_manager::get_active($location) as $id => $info) { - $active_set[$id] = $info; - } - } - - foreach (array("dashboard_sidebar", "dashboard_center") as $location) { - $new_blocks = array(); - foreach ($this->input->get($location, array()) as $id) { - $new_blocks[$id] = $active_set[$id]; - } - block_manager::set_active($location, $new_blocks); - } - - $this->_force_block_adder(); - } -} diff --git a/core/controllers/admin_graphics.php b/core/controllers/admin_graphics.php deleted file mode 100644 index 0b3014f0..00000000 --- a/core/controllers/admin_graphics.php +++ /dev/null @@ -1,63 +0,0 @@ -content = new View("admin_graphics.html"); - $view->content->available = ""; - - $tk = new ArrayObject(graphics::detect_toolkits(), ArrayObject::ARRAY_AS_PROPS); - $active = module::get_var("core", "graphics_toolkit", "none"); - foreach (array("gd", "imagemagick", "graphicsmagick", "none") as $id) { - if ($id == $active) { - $view->content->active = new View("admin_graphics_$id.html"); - $view->content->active->tk = $tk; - $view->content->active->is_active = true; - } else if ($id != "none") { - $v = new View("admin_graphics_$id.html"); - $v->tk = $tk; - $v->is_active = false; - $view->content->available .= $v; - } - } - - print $view; - } - - public function choose($toolkit) { - access::verify_csrf(); - if ($toolkit != module::get_var("core", "graphics_toolkit")) { - module::set_var("core", "graphics_toolkit", $toolkit); - - $toolkit_info = graphics::detect_toolkits(); - if ($toolkit == "graphicsmagick" || $toolkit == "imagemagick") { - module::set_var("core", "graphics_toolkit_path", $toolkit_info[$toolkit]); - } - - site_status::clear("missing_graphics_toolkit"); - message::success(t("Updated Graphics Toolkit")); - log::success("graphics", t("Changed graphics toolkit to: %toolkit", - array("toolkit" => $toolkit))); - } - - url::redirect("admin/graphics"); - } -} - diff --git a/core/controllers/admin_languages.php b/core/controllers/admin_languages.php deleted file mode 100644 index 37d335a3..00000000 --- a/core/controllers/admin_languages.php +++ /dev/null @@ -1,136 +0,0 @@ -content = new View("admin_languages.html"); - $v->content->settings_form = $this->_languages_form(); - if (empty($share_translations_form)) { - $share_translations_form = $this->_share_translations_form(); - } - $v->content->share_translations_form = $share_translations_form; - $this->_outgoing_translations_count(); - print $v; - } - - public function save() { - $form = $this->_languages_form(); - if ($form->validate()) { - module::set_var("core", "default_locale", $form->choose_language->locale->value); - locale::update_installed($form->choose_language->installed_locales->value); - message::success(t("Settings saved")); - } - url::redirect("admin/languages"); - } - - public function share() { - $form = $this->_share_translations_form(); - if (!$form->validate()) { - // Show the page with form errors - return $this->index($form); - } - - if ($form->sharing->share) { - l10n_client::submit_translations(); - message::success(t("Translations submitted")); - } else { - return $this->_save_api_key($form); - } - url::redirect("admin/languages"); - } - - private function _save_api_key($form) { - $new_key = $form->sharing->api_key->value; - if ($new_key && !l10n_client::validate_api_key($new_key)) { - $form->sharing->api_key->add_error("invalid", 1); - $valid = false; - } else { - $valid = true; - } - - if ($valid) { - $old_key = l10n_client::api_key(); - l10n_client::api_key($new_key); - if ($old_key && !$new_key) { - message::success(t("Your API key has been cleared.")); - } else if ($old_key && $new_key && $old_key != $new_key) { - message::success(t("Your API key has been changed.")); - } else if (!$old_key && $new_key) { - message::success(t("Your API key has been saved.")); - } - - log::success(t("core"), t("l10n_client API key changed.")); - url::redirect("admin/languages"); - } else { - // Show the page with form errors - $this->index($form); - } - } - - private function _languages_form() { - $all_locales = locale::available(); - $installed_locales = locale::installed(); - $form = new Forge("admin/languages/save", "", "post", array("id" => "gLanguageSettingsForm")); - $group = $form->group("choose_language") - ->label(t("Language settings")); - $group->dropdown("locale") - ->options($installed_locales) - ->selected(module::get_var("core", "default_locale")) - ->label(t("Default language")) - ->rules('required'); - - $installation_options = array(); - foreach ($all_locales as $code => $display_name) { - $installation_options[$code] = array($display_name, isset($installed_locales->$code)); - } - $group->checklist("installed_locales") - ->label(t("Installed Languages")) - ->options($installation_options) - ->rules("required"); - $group->submit("save")->value(t("Save settings")); - return $form; - } - - private function _outgoing_translations_count() { - return ORM::factory("outgoing_translation")->count_all(); - } - - private function _share_translations_form() { - $form = new Forge("admin/languages/share", "", "post", array("id" => "gShareTranslationsForm")); - $group = $form->group("sharing") - ->label(t("Sharing you own translations with the Gallery community is easy. Please do!")); - $api_key = l10n_client::api_key(); - $server_link = l10n_client::server_api_key_url(); - $group->input("api_key") - ->label(empty($api_key) - ? t("This is a unique key that will allow you to send translations to the remote server. To get your API key go to %server-link.", - array("server-link" => html::anchor($server_link))) - : t("API Key")) - ->value($api_key) - ->error_messages("invalid", t("The API key you provided is invalid.")); - $group->submit("save")->value(t("Save settings")); - if ($api_key && $this->_outgoing_translations_count()) { - // TODO: UI improvement: hide API key / save button when API key is set. - $group->submit("share")->value(t("Submit translations")); - } - return $form; - } -} - diff --git a/core/controllers/admin_maintenance.php b/core/controllers/admin_maintenance.php deleted file mode 100644 index c169de75..00000000 --- a/core/controllers/admin_maintenance.php +++ /dev/null @@ -1,181 +0,0 @@ -query( - "UPDATE {tasks} SET `state` = 'stalled' " . - "WHERE done = 0 " . - "AND state <> 'stalled' " . - "AND unix_timestamp(now()) - updated > 15"); - $stalled_count = $query->count(); - if ($stalled_count) { - log::warning("tasks", - t2("One task is stalled", - "%count tasks are stalled", - $stalled_count), - t('view', - array("url" => url::site("admin/maintenance")))); - } - - $view = new Admin_View("admin.html"); - $view->content = new View("admin_maintenance.html"); - $view->content->task_definitions = task::get_definitions(); - $view->content->running_tasks = ORM::factory("task") - ->where("done", 0)->orderby("updated", "DESC")->find_all(); - $view->content->finished_tasks = ORM::factory("task") - ->where("done", 1)->orderby("updated", "DESC")->find_all(); - print $view; - } - - /** - * Start a new task - * @param string $task_callback - */ - public function start($task_callback) { - access::verify_csrf(); - - $tasks = task::get_definitions(); - $task = task::create($tasks[$task_callback], array()); - $view = new View("admin_maintenance_task.html"); - $view->task = $task; - - log::info("tasks", t("Task %task_name started (task id %task_id)", - array("task_name" => $task->name, "task_id" => $task->id)), - html::anchor(url::site("admin/maintenance"), t("maintenance"))); - print $view; - } - - /** - * Resume a stalled task - * @param string $task_id - */ - public function resume($task_id) { - access::verify_csrf(); - - $task = ORM::factory("task", $task_id); - if (!$task->loaded) { - throw new Exception("@todo MISSING_TASK"); - } - $view = new View("admin_maintenance_task.html"); - $view->task = $task; - - log::info("tasks", t("Task %task_name resumed (task id %task_id)", - array("task_name" => $task->name, "task_id" => $task->id)), - html::anchor(url::site("admin/maintenance"), t("maintenance"))); - print $view; - } - - /** - * Cancel a task. - * @param string $task_id - */ - public function cancel($task_id) { - access::verify_csrf(); - - task::cancel($task_id); - - message::success(t("Task cancelled")); - url::redirect("admin/maintenance"); - } - - public function cancel_running_tasks() { - access::verify_csrf(); - Database::instance()->update( - "tasks", - array("done" => 1, "state" => "cancelled"), - array("done" => 0)); - message::success(t("All running tasks cancelled")); - url::redirect("admin/maintenance"); - } - - /** - * Remove a task. - * @param string $task_id - */ - public function remove($task_id) { - access::verify_csrf(); - - task::remove($task_id); - - message::success(t("Task removed")); - url::redirect("admin/maintenance"); - } - - public function remove_finished_tasks() { - access::verify_csrf(); - Database::instance()->delete("tasks", array("done" => 1)); - message::success(t("All finished tasks removed")); - url::redirect("admin/maintenance"); - } - - /** - * Run a task. This will trigger the task to do a small amount of work, then it will report - * back with status on the task. - * @param string $task_id - */ - public function run($task_id) { - access::verify_csrf(); - - try { - $task = task::run($task_id); - } catch (Exception $e) { - Kohana::log( - "error", - sprintf( - "%s in %s at line %s:\n%s", $e->getMessage(), $e->getFile(), - $e->getLine(), $e->getTraceAsString())); - throw $e; - } - - if ($task->done) { - switch ($task->state) { - case "success": - log::success("tasks", t("Task %task_name completed (task id %task_id)", - array("task_name" => $task->name, "task_id" => $task->id)), - html::anchor(url::site("admin/maintenance"), t("maintenance"))); - message::success(t("Task completed successfully")); - break; - - case "error": - log::error("tasks", t("Task %task_name failed (task id %task_id)", - array("task_name" => $task->name, "task_id" => $task->id)), - html::anchor(url::site("admin/maintenance"), t("maintenance"))); - message::success(t("Task failed")); - break; - } - print json_encode(array("result" => "success", - "task" => array( - "percent_complete" => $task->percent_complete, - "status" => $task->status, - "done" => $task->done), - "location" => url::site("admin/maintenance"))); - - } else { - print json_encode(array("result" => "in_progress", - "task" => array( - "percent_complete" => $task->percent_complete, - "status" => $task->status, - "done" => $task->done))); - } - } -} diff --git a/core/controllers/admin_modules.php b/core/controllers/admin_modules.php deleted file mode 100644 index f7dd909d..00000000 --- a/core/controllers/admin_modules.php +++ /dev/null @@ -1,65 +0,0 @@ -content = new View("admin_modules.html"); - $view->content->available = module::available(); - print $view; - } - - public function save() { - access::verify_csrf(); - - $changes->activate = array(); - $changes->deactivate = array(); - $activated_names = array(); - $deactivated_names = array(); - foreach (module::available() as $module_name => $info) { - if ($info->locked) { - continue; - } - - $desired = $this->input->post($module_name) == 1; - if ($info->active && !$desired && module::is_active($module_name)) { - $changes->deactivate[] = $module_name; - $deactivated_names[] = $info->name; - module::deactivate($module_name); - } else if (!$info->active && $desired && !module::is_active($module_name)) { - $changes->activate[] = $module_name; - $activated_names[] = $info->name; - module::install($module_name); - module::activate($module_name); - } - } - - module::event("module_change", $changes); - - // @todo this type of collation is questionable from a i18n perspective - if ($activated_names) { - message::success(t("Activated: %names", array("names" => join(", ", $activated_names)))); - } - if ($deactivated_names) { - message::success(t("Deactivated: %names", array("names" => join(", ", $deactivated_names)))); - } - url::redirect("admin/modules"); - } -} - diff --git a/core/controllers/admin_theme_details.php b/core/controllers/admin_theme_details.php deleted file mode 100644 index 542ec31c..00000000 --- a/core/controllers/admin_theme_details.php +++ /dev/null @@ -1,67 +0,0 @@ -content = new View("admin_theme_details.html"); - $view->content->form = theme::get_edit_form_admin(); - print $view; - } - - public function save() { - $form = theme::get_edit_form_admin(); - if ($form->validate()) { - module::set_var("core", "page_size", $form->edit_theme->page_size->value); - - $thumb_size = $form->edit_theme->thumb_size->value; - $thumb_dirty = false; - if (module::get_var("core", "thumb_size") != $thumb_size) { - graphics::remove_rule("core", "thumb", "resize"); - graphics::add_rule( - "core", "thumb", "resize", - array("width" => $thumb_size, "height" => $thumb_size, "master" => Image::AUTO), - 100); - module::set_var("core", "thumb_size", $thumb_size); - } - - $resize_size = $form->edit_theme->resize_size->value; - $resize_dirty = false; - if (module::get_var("core", "resize_size") != $resize_size) { - graphics::remove_rule("core", "resize", "resize"); - graphics::add_rule( - "core", "resize", "resize", - array("width" => $resize_size, "height" => $resize_size, "master" => Image::AUTO), - 100); - module::set_var("core", "resize_size", $resize_size); - } - - module::set_var("core", "header_text", $form->edit_theme->header_text->value); - module::set_var("core", "footer_text", $form->edit_theme->footer_text->value); - - message::success(t("Updated theme details")); - url::redirect("admin/theme_details"); - } else { - $view = new Admin_View("admin.html"); - $view->content = $form; - print $view; - } - } -} - diff --git a/core/controllers/admin_themes.php b/core/controllers/admin_themes.php deleted file mode 100644 index 05c134d1..00000000 --- a/core/controllers/admin_themes.php +++ /dev/null @@ -1,79 +0,0 @@ -content = new View("admin_themes.html"); - $view->content->admin = module::get_var("core", "active_admin_theme"); - $view->content->site = module::get_var("core", "active_site_theme"); - $view->content->themes = $this->_get_themes(); - print $view; - } - - private function _get_themes() { - $themes = array(); - foreach (scandir(THEMEPATH) as $theme_name) { - if ($theme_name[0] == ".") { - continue; - } - - $file = THEMEPATH . "$theme_name/theme.info"; - $theme_info = new ArrayObject(parse_ini_file($file), ArrayObject::ARRAY_AS_PROPS); - $themes[$theme_name] = $theme_info; - } - return $themes; - } - - public function preview($type, $theme_name) { - $view = new View("admin_themes_preview.html"); - $theme_name = preg_replace("/[^\w]/", "", $theme_name); - $view->info = new ArrayObject( - parse_ini_file(THEMEPATH . "$theme_name/theme.info"), ArrayObject::ARRAY_AS_PROPS); - $view->theme_name = $theme_name; - $view->type = $type; - if ($type == "admin") { - $view->url = url::site("admin?theme=$theme_name"); - } else { - $view->url = url::site("albums/1?theme=$theme_name"); - } - print $view; - } - - public function choose($type, $theme_name) { - access::verify_csrf(); - - $theme_name = preg_replace("/[^\w]/", "", $theme_name); - $info = new ArrayObject( - parse_ini_file(THEMEPATH . "$theme_name/theme.info"), ArrayObject::ARRAY_AS_PROPS); - - if ($type == "admin" && $info->admin) { - module::set_var("core", "active_admin_theme", $theme_name); - message::success(t("Successfully changed your admin theme to %theme_name", - array("theme_name" => $info->name))); - } else if ($type == "site" && $info->site) { - module::set_var("core", "active_site_theme", $theme_name); - message::success(t("Successfully changed your Gallery theme to %theme_name", - array("theme_name" => $info->name))); - } - - url::redirect("admin/themes"); - } -} - diff --git a/core/controllers/after_install.php b/core/controllers/after_install.php deleted file mode 100644 index f066afe4..00000000 --- a/core/controllers/after_install.php +++ /dev/null @@ -1,30 +0,0 @@ -admin) { - url::redirect("albums/1"); - } - - $v = new View("after_install.html"); - $v->user = user::active(); - print $v; - } -} diff --git a/core/controllers/albums.php b/core/controllers/albums.php deleted file mode 100644 index 5b4d5979..00000000 --- a/core/controllers/albums.php +++ /dev/null @@ -1,229 +0,0 @@ -id != 1) { - access::forbidden(); - } else { - print new Theme_View("login_page.html", "album"); - return; - } - } - - $page_size = module::get_var("core", "page_size", 9); - $show = $this->input->get("show"); - - if ($show) { - $index = $album->get_position($show); - $page = ceil($index / $page_size); - if ($page == 1) { - url::redirect("albums/$album->id"); - } else { - url::redirect("albums/$album->id?page=$page"); - } - } - - $page = $this->input->get("page", "1"); - $children_count = $album->viewable()->children_count(); - $offset = ($page - 1) * $page_size; - $max_pages = max(ceil($children_count / $page_size), 1); - - // Make sure that the page references a valid offset - if ($page < 1) { - url::redirect("albums/$album->id"); - } else if ($page > $max_pages) { - url::redirect("albums/$album->id?page=$max_pages"); - } - - $template = new Theme_View("page.html", "album"); - $template->set_global("page_size", $page_size); - $template->set_global("item", $album); - $template->set_global("children", $album->viewable()->children($page_size, $offset)); - $template->set_global("children_count", $children_count); - $template->set_global("parents", $album->parents()); - $template->content = new View("album.html"); - - // We can't use math in ORM or the query builder, so do this by hand. It's important - // that we do this with math, otherwise concurrent accesses will damage accuracy. - Database::instance()->query( - "UPDATE {items} SET `view_count` = `view_count` + 1 WHERE `id` = $album->id"); - - print $template; - } - - /** - * @see REST_Controller::_create($resource) - */ - public function _create($album) { - access::required("add", $album); - - switch ($this->input->post("type")) { - case "album": - return $this->_create_album($album); - - case "photo": - return $this->_create_photo($album); - - default: - access::forbidden(); - } - } - - private function _create_album($album) { - access::required("add", $album); - - $form = album::get_add_form($album); - if ($form->validate()) { - $new_album = album::create( - $album, - $this->input->post("name"), - $this->input->post("title", $this->input->post("name")), - $this->input->post("description"), - user::active()->id); - - log::success("content", "Created an album", - html::anchor("albums/$new_album->id", "view album")); - message::success(t("Created album %album_title", array("album_title" => $new_album->title))); - - print json_encode( - array("result" => "success", - "location" => url::site("albums/$new_album->id"), - "resource" => url::site("albums/$new_album->id"))); - } else { - print json_encode( - array("result" => "error", - "form" => $form->__toString() . html::script("core/js/albums_form_add.js"))); - } - } - - private function _create_photo($album) { - access::required("add", $album); - - // If we set the content type as JSON, it triggers saving the result as - // a document in the browser (well, in Chrome at least). - // @todo figure out why and fix this. - $form = photo::get_add_form($album); - if ($form->validate()) { - $photo = photo::create( - $album, - $this->input->post("file"), - $_FILES["file"]["name"], - $this->input->post("title", $this->input->post("name")), - $this->input->post("description"), - user::active()->id); - - log::success("content", "Added a photo", html::anchor("photos/$photo->id", "view photo")); - message::success(t("Added photo %photo_title", array("photo_title" => $photo->title))); - - print json_encode( - array("result" => "success", - "resource" => url::site("photos/$photo->id"), - "location" => url::site("photos/$photo->id"))); - } else { - print json_encode( - array("result" => "error", - "form" => $form->__toString())); - } - } - - /** - * @see REST_Controller::_update($resource) - */ - public function _update($album) { - access::required("edit", $album); - - $form = album::get_edit_form($album); - if ($valid = $form->validate()) { - // Make sure that there's not a conflict - if (Database::instance() - ->from("items") - ->where("parent_id", $album->parent_id) - ->where("id <>", $album->id) - ->where("name", $form->edit_album->dirname->value) - ->count_records()) { - $form->edit_album->dirname->add_error("conflict", 1); - $valid = false; - } - } - - // @todo - // @todo we need to make sure that filename / dirname components can't contain a / - // @todo - - if ($valid) { - $orig = clone $album; - $album->title = $form->edit_album->title->value; - $album->description = $form->edit_album->description->value; - $album->sort_column = $form->edit_album->sort_order->column->value; - $album->sort_order = $form->edit_album->sort_order->direction->value; - $album->rename($form->edit_album->dirname->value); - $album->save(); - - module::event("item_updated", $orig, $album); - - log::success("content", "Updated album", "id\">view"); - message::success(t("Saved album %album_title", array("album_title" => $album->title))); - - print json_encode( - array("result" => "success", - "location" => url::site("albums/$album->id"))); - } else { - print json_encode( - array("result" => "error", - "form" => $form->__toString())); - } - } - - /** - * @see REST_Controller::_form_add($parameters) - */ - public function _form_add($album_id) { - $album = ORM::factory("item", $album_id); - access::required("add", $album); - - switch ($this->input->get("type")) { - case "album": - print album::get_add_form($album) . - html::script("core/js/albums_form_add.js"); - break; - - case "photo": - print photo::get_add_form($album); - break; - - default: - kohana::show_404(); - } - } - - /** - * @see REST_Controller::_form_add($parameters) - */ - public function _form_edit($album) { - access::required("edit", $album); - - print album::get_edit_form($album); - } -} diff --git a/core/controllers/file_proxy.php b/core/controllers/file_proxy.php deleted file mode 100644 index f3c5f109..00000000 --- a/core/controllers/file_proxy.php +++ /dev/null @@ -1,120 +0,0 @@ -input->server("REQUEST_URI"); - $request_uri = preg_replace("/\?.*/", "", $request_uri); - - // var_uri: http://example.com/gallery3/var/ - $var_uri = url::file("var/"); - - // Make sure that the request is for a file inside var - $offset = strpos($request_uri, $var_uri); - if ($offset === false) { - kohana::show_404(); - } - - $file = substr($request_uri, strlen($var_uri)); - - // Make sure that we don't leave the var dir - if (strpos($file, "..") !== false) { - kohana::show_404(); - } - - // We only handle var/resizes and var/albums - $paths = explode("/", $file); - $type = $paths[0]; - if ($type != "resizes" && $type != "albums" && $type != "thumbs") { - kohana::show_404(); - } - - // If the last element is .album.jpg, pop that off since it's not a real item - if ($paths[count($paths)-1] == ".album.jpg") { - array_pop($paths); - } - if ($paths[count($paths)-1] == "") { - array_pop($paths); - } - - // Find all items that match the level and name, then iterate over those to find a match. - // In most cases we'll get it in one. Note that for the level calculation, we just count the - // size of $paths. $paths includes the type ("thumbs", etc) but it doesn't include the root, - // so it's a wash. - $count = count($paths); - $compare_file = VARPATH . $file; - $item = null; - foreach (ORM::factory("item") - ->where("name", $paths[$count - 1]) - ->where("level", $count) - ->find_all() as $match) { - if ($type == "albums") { - $match_file = $match->file_path(); - } else if ($type == "resizes") { - $match_file = $match->resize_path(); - } else { - $match_file = $match->thumb_path(); - } - if ($match_file == $compare_file) { - $item = $match; - break; - } - } - - if (!$item) { - kohana::show_404(); - } - - // Make sure we have access to the item - if (!access::can("view", $item)) { - kohana::show_404(); - } - - // Make sure we have view_full access to the original - if ($type == "albums" && !access::can("view_full", $item)) { - kohana::show_404(); - } - - // Don't try to load a directory - if ($type == "albums" && $item->is_album()) { - kohana::show_404(); - } - - if (!file_exists($match_file)) { - kohana::show_404(); - } - - // Dump out the image - header("Content-Type: $item->mime_type"); - Kohana::close_buffers(false); - $fd = fopen($match_file, "rb"); - fpassthru($fd); - fclose($fd); - } -} diff --git a/core/controllers/items.php b/core/controllers/items.php deleted file mode 100644 index 13891726..00000000 --- a/core/controllers/items.php +++ /dev/null @@ -1,30 +0,0 @@ -url(array(), true)); - } -} diff --git a/core/controllers/l10n_client.php b/core/controllers/l10n_client.php deleted file mode 100644 index 17520051..00000000 --- a/core/controllers/l10n_client.php +++ /dev/null @@ -1,128 +0,0 @@ -admin or access::forbidden(); - - $input = Input::instance(); - $message = $input->post("l10n-message-source"); - $translation = $input->post("l10n-edit-target"); - $key = I18n::get_message_key($message); - $locale = I18n::instance()->locale(); - - $entry = ORM::factory("outgoing_translation") - ->where(array("key" => $key, - "locale" => $locale)) - ->find(); - - if (!$entry->loaded) { - $entry->key = $key; - $entry->locale = $locale; - $entry->message = serialize($message); - $entry->base_revision = null; - } - - $entry->translation = serialize($translation); - - $entry_from_incoming = ORM::factory("incoming_translation") - ->where(array("key" => $key, - "locale" => $locale)) - ->find(); - - if (!$entry_from_incoming->loaded) { - $entry->base_revision = $entry_from_incoming->revision; - } - - $entry->save(); - - print json_encode(new stdClass()); - } - - public function toggle_l10n_mode() { - access::verify_csrf(); - - $session = Session::instance(); - $session->set("l10n_mode", - !$session->get("l10n_mode", false)); - - url::redirect("albums/1"); - } - - private static function _l10n_client_form() { - $form = new Forge("l10n_client/save", "", "post", array("id" => "gL10nClientSaveForm")); - $group = $form->group("l10n_message"); - $group->hidden("l10n-message-source")->value(""); - $group->textarea("l10n-edit-target"); - $group->submit("l10n-edit-save")->value(t("Save translation")); - // TODO(andy_st): Avoiding multiple submit buttons for now (hassle with jQuery form plugin). - // $group->submit("l10n-edit-copy")->value(t("Copy source")); - // $group->submit("l10n-edit-clear")->value(t("Clear")); - - return $form; - } - - private static function _l10n_client_search_form() { - $form = new Forge("l10n_client/search", "", "post", array("id" => "gL10nSearchForm")); - $group = $form->group("l10n_search"); - $group->input("l10n-search")->id("gL10nSearch"); - $group->submit("l10n-search-filter-clear")->value(t("X")); - - return $form; - } - - public static function l10n_form() { - $calls = I18n::instance()->call_log(); - - if ($calls) { - $string_list = array(); - foreach ($calls as $call) { - list ($message, $options) = $call; - // Note: Don't interpolate placeholders for the actual translation input field. - // TODO: Use $options to generate a preview. - if (is_array($message)) { - // TODO: Handle plural forms. - // Translate each message. If it has a plural form, get - // the current locale's plural rules and all plural translations. - continue; - } - $source = $message; - $translation = ''; - $options_for_raw_translation = array(); - if (isset($options['count'])) { - $options_for_raw_translation['count'] = $options['count']; - } - if (I18n::instance()->has_translation($message, $options_for_raw_translation)) { - $translation = I18n::instance()->translate($message, $options_for_raw_translation); - } - $string_list[] = array('source' => $source, - 'translation' => $translation); - } - - $v = new View('l10n_client.html'); - $v->string_list = $string_list; - $v->l10n_form = self::_l10n_client_form(); - $v->l10n_search_form = self::_l10n_client_search_form(); - return $v; - } - - return ''; - } -} diff --git a/core/controllers/maintenance.php b/core/controllers/maintenance.php deleted file mode 100644 index b5f39bed..00000000 --- a/core/controllers/maintenance.php +++ /dev/null @@ -1,24 +0,0 @@ -source = $source; - $view->tree = $this->_get_tree_html($source, ORM::factory("item", 1)); - print $view; - } - - public function save($source_id) { - access::verify_csrf(); - $source = ORM::factory("item", $source_id); - $target = ORM::factory("item", $this->input->post("target_id")); - - item::move($source, $target); - - print json_encode( - array("result" => "success", - "location" => url::site("albums/{$target->id}"))); - } - - public function show_sub_tree($source_id, $target_id) { - $source = ORM::factory("item", $source_id); - $target = ORM::factory("item", $target_id); - access::required("edit", $source); - access::required("view", $target); - - print $this->_get_tree_html($source, $target); - } - - private function _get_tree_html($source, $target) { - $view = new View("move_tree.html"); - $view->source = $source; - $view->parent = $target; - $view->children = ORM::factory("item") - ->viewable() - ->where("type", "album") - ->where("parent_id", $target->id) - ->find_all(); - return $view; - } - -} diff --git a/core/controllers/movies.php b/core/controllers/movies.php deleted file mode 100644 index 55bbb0e5..00000000 --- a/core/controllers/movies.php +++ /dev/null @@ -1,114 +0,0 @@ -viewable() - ->where("parent_id", $photo->parent_id) - ->where("id >", $photo->id) - ->orderby("id", "ASC") - ->find(); - $previous_item = ORM::factory("item") - ->viewable() - ->where("parent_id", $photo->parent_id) - ->where("id <", $photo->id) - ->orderby("id", "DESC") - ->find(); - $position = ORM::factory("item") - ->viewable() - ->where("parent_id", $photo->parent_id) - ->where("id <=", $photo->id) - ->count_all(); - - $template = new Theme_View("page.html", "photo"); - $template->set_global("item", $photo); - $template->set_global("children", array()); - $template->set_global("children_count", $photo->children_count()); - $template->set_global("parents", $photo->parents()); - $template->set_global("next_item", $next_item->loaded ? $next_item : null); - $template->set_global("previous_item", $previous_item->loaded ? $previous_item : null); - $template->set_global("sibling_count", $photo->parent()->children_count()); - $template->set_global("position", $position); - - $template->content = new View("movie.html"); - - $photo->view_count++; - $photo->save(); - - print $template; - } - - /** - * @see REST_Controller::_update($resource) - */ - public function _update($photo) { - access::required("edit", $photo); - - $form = photo::get_edit_form($photo); - if ($valid = $form->validate()) { - // Make sure that there's not a conflict - if (Database::instance() - ->from("items") - ->where("parent_id", $photo->parent_id) - ->where("id <>", $photo->id) - ->where("name", $form->edit_photo->filename->value) - ->count_records()) { - $form->edit_photo->filename->add_error("conflict", 1); - $valid = false; - } - } - - if ($valid) { - $orig = clone $photo; - $photo->title = $form->edit_photo->title->value; - $photo->description = $form->edit_photo->description->value; - $photo->rename($form->edit_photo->filename->value); - $photo->save(); - - module::event("item_updated", $orig, $photo); - - log::success("content", "Updated photo", "id\">view"); - message::success(t("Saved photo %photo_title", array("photo_title" => $photo->title))); - - print json_encode( - array("result" => "success", - "location" => url::site("photos/$photo->id"))); - } else { - print json_encode( - array("result" => "error", - "form" => $form->__toString())); - } - } - - /** - * @see REST_Controller::_form_edit($resource) - */ - public function _form_edit($photo) { - access::required("edit", $photo); - print photo::get_edit_form($photo); - } -} diff --git a/core/controllers/permissions.php b/core/controllers/permissions.php deleted file mode 100644 index b0cee303..00000000 --- a/core/controllers/permissions.php +++ /dev/null @@ -1,80 +0,0 @@ -is_album()) { - access::forbidden(); - } - - $view = new View("permissions_browse.html"); - $view->htaccess_works = access::htaccess_works(); - $view->item = $item; - $view->parents = $item->parents(); - $view->form = $this->_get_form($item); - - print $view; - } - - function form($id) { - $item = ORM::factory("item", $id); - access::required("edit", $item); - - if (!$item->is_album()) { - access::forbidden(); - } - - print $this->_get_form($item); - } - - function change($command, $group_id, $perm_id, $item_id) { - access::verify_csrf(); - $group = ORM::factory("group", $group_id); - $perm = ORM::factory("permission", $perm_id); - $item = ORM::factory("item", $item_id); - access::required("edit", $item); - - if ($group->loaded && $perm->loaded && $item->loaded) { - switch($command) { - case "allow": - access::allow($group, $perm->name, $item); - break; - - case "deny": - access::deny($group, $perm->name, $item); - break; - - case "reset": - access::reset($group, $perm->name, $item); - break; - } - } - } - - function _get_form($item) { - $view = new View("permissions_form.html"); - $view->item = $item; - $view->groups = ORM::factory("group")->find_all(); - $view->permissions = ORM::factory("permission")->find_all(); - return $view; - } -} diff --git a/core/controllers/photos.php b/core/controllers/photos.php deleted file mode 100644 index 5d4040cf..00000000 --- a/core/controllers/photos.php +++ /dev/null @@ -1,116 +0,0 @@ -viewable() - ->where("parent_id", $photo->parent_id) - ->where("id >", $photo->id) - ->orderby("id", "ASC") - ->find(); - $previous_item = ORM::factory("item") - ->viewable() - ->where("parent_id", $photo->parent_id) - ->where("id <", $photo->id) - ->orderby("id", "DESC") - ->find(); - $position = ORM::factory("item") - ->viewable() - ->where("parent_id", $photo->parent_id) - ->where("id <=", $photo->id) - ->count_all(); - - $template = new Theme_View("page.html", "photo"); - $template->set_global("item", $photo); - $template->set_global("children", array()); - $template->set_global("children_count", $photo->children_count()); - $template->set_global("parents", $photo->parents()); - $template->set_global("next_item", $next_item->loaded ? $next_item : null); - $template->set_global("previous_item", $previous_item->loaded ? $previous_item : null); - $template->set_global("sibling_count", $photo->parent()->children_count()); - $template->set_global("position", $position); - - $template->content = new View("photo.html"); - - $photo->view_count++; - $photo->save(); - - print $template; - } - - /** - * @see REST_Controller::_update($resource) - */ - public function _update($photo) { - access::required("edit", $photo); - - $form = photo::get_edit_form($photo); - if ($valid = $form->validate()) { - if ($form->edit_photo->filename->value != $photo->name) { - // Make sure that there's not a conflict - if (Database::instance() - ->from("items") - ->where("parent_id", $photo->parent_id) - ->where("id <>", $photo->id) - ->where("name", $form->edit_photo->filename->value) - ->count_records()) { - $form->edit_photo->filename->add_error("conflict", 1); - $valid = false; - } - } - } - - if ($valid) { - $orig = clone $photo; - $photo->title = $form->edit_photo->title->value; - $photo->description = $form->edit_photo->description->value; - $photo->rename($form->edit_photo->filename->value); - $photo->save(); - - module::event("item_updated", $orig, $photo); - - log::success("content", "Updated photo", "id\">view"); - message::success(t("Saved photo %photo_title", array("photo_title" => $photo->title))); - - print json_encode( - array("result" => "success", - "location" => url::site("photos/$photo->id"))); - } else { - print json_encode( - array("result" => "error", - "form" => $form->__toString())); - } - } - - /** - * @see REST_Controller::_form_edit($resource) - */ - public function _form_edit($photo) { - access::required("edit", $photo); - print photo::get_edit_form($photo); - } -} diff --git a/core/controllers/quick.php b/core/controllers/quick.php deleted file mode 100644 index 643dce30..00000000 --- a/core/controllers/quick.php +++ /dev/null @@ -1,122 +0,0 @@ -loaded) { - return ""; - } - - $view = new View("quick_pane.html"); - $view->item = $item; - $view->page_type = Input::instance()->get("page_type"); - print $view; - } - - public function rotate($id, $dir) { - access::verify_csrf(); - $item = ORM::factory("item", $id); - if (!$item->loaded) { - return ""; - } - - $degrees = 0; - switch($dir) { - case "ccw": - $degrees = -90; - break; - - case "cw": - $degrees = 90; - break; - } - - if ($degrees) { - graphics::rotate($item->file_path(), $item->file_path(), array("degrees" => $degrees)); - - list($item->width, $item->height) = getimagesize($item->file_path()); - $item->resize_dirty= 1; - $item->thumb_dirty= 1; - $item->save(); - - graphics::generate($item); - - $parent = $item->parent(); - if ($parent->album_cover_item_id == $item->id) { - copy($item->thumb_path(), $parent->thumb_path()); - $parent->thumb_width = $item->thumb_width; - $parent->thumb_height = $item->thumb_height; - $parent->save(); - } - } - - if (Input::instance()->get("page_type") == "album") { - print json_encode( - array("src" => $item->thumb_url() . "?rnd=" . rand(), - "width" => $item->thumb_width, - "height" => $item->thumb_height)); - } else { - print json_encode( - array("src" => $item->resize_url() . "?rnd=" . rand(), - "width" => $item->resize_width, - "height" => $item->resize_height)); - } - } - - public function make_album_cover($id) { - access::verify_csrf(); - item::make_album_cover(ORM::factory("item", $id)); - - print json_encode(array("result" => "success")); - } - - public function delete($id) { - access::verify_csrf(); - $item = ORM::factory("item", $id); - access::required("edit", $item); - - if ($item->is_album()) { - $msg = t("Deleted album %title", array("title" => $item->title)); - } else { - $msg = t("Deleted photo %title", array("title" => $item->title)); - } - - $item->delete(); - message::success($msg); - - if (Input::instance()->get("page_type") == "album") { - print json_encode(array("result" => "success", "reload" => 1)); - } else { - print json_encode(array("result" => "success", - "location" => url::site("albums/$parent->id"))); - } - } - - public function form_edit($id) { - $item = ORM::factory("item", $id); - access::required("edit", $item); - if ($item->is_album()) { - $form = album::get_edit_form($item); - } else { - $form = photo::get_edit_form($item); - } - print $form; - } -} diff --git a/core/controllers/rest.php b/core/controllers/rest.php deleted file mode 100644 index 11a6bbac..00000000 --- a/core/controllers/rest.php +++ /dev/null @@ -1,183 +0,0 @@ -resource_type == null) { - throw new Exception("@todo ERROR_MISSING_RESOURCE_TYPE"); - } - parent::__construct(); - } - - /** - * Handle dispatching for all REST controllers. - */ - public function __call($function, $args) { - // If no parameter was provided after the controller name (eg "/albums") then $function will - // be set to "index". Otherwise, $function is the first parameter, and $args are all - // subsequent parameters. - $request_method = rest::request_method(); - if ($function == "index" && $request_method == "get") { - return $this->_index(); - } - - $resource = ORM::factory($this->resource_type, (int)$function); - if (!$resource->loaded && $request_method != "post") { - return Kohana::show_404(); - } - - if ($request_method != "get") { - access::verify_csrf(); - } - - switch ($request_method) { - case "get": - return $this->_show($resource); - - case "put": - return $this->_update($resource); - - case "delete": - return $this->_delete($resource); - - case "post": - return $this->_create($resource); - } - } - - /* We're editing an existing item, load it from the database. */ - public function form_edit($resource_id) { - if ($this->resource_type == null) { - throw new Exception("@todo ERROR_MISSING_RESOURCE_TYPE"); - } - - // @todo this needs security checks - $resource = ORM::factory($this->resource_type, $resource_id); - if (!$resource->loaded) { - return Kohana::show_404(); - } - - return $this->_form_edit($resource); - } - - /* We're adding a new item, pass along any additional parameters. */ - public function form_add($parameters) { - return $this->_form_add($parameters); - } - - /** - * Perform a GET request on the controller root - * (e.g. http://www.example.com/gallery3/comments) - */ - public function _index() { - throw new Exception("@todo _create NOT IMPLEMENTED"); - } - - /** - * Perform a POST request on this resource - * @param ORM $resource the instance of this resource type - */ - public function _create($resource) { - throw new Exception("@todo _create NOT IMPLEMENTED"); - } - - /** - * Perform a GET request on this resource - * @param ORM $resource the instance of this resource type - */ - public function _show($resource) { - throw new Exception("@todo _show NOT IMPLEMENTED"); - } - - /** - * Perform a PUT request on this resource - * @param ORM $resource the instance of this resource type - */ - public function _update($resource) { - throw new Exception("@todo _update NOT IMPLEMENTED"); - } - - /** - * Perform a DELETE request on this resource - * @param ORM $resource the instance of this resource type - */ - public function _delete($resource) { - throw new Exception("@todo _delete NOT IMPLEMENTED"); - } - - /** - * Present a form for adding a new resource - * @param string part of the URI after the controller name - */ - public function _form_add($parameter) { - throw new Exception("@todo _form_add NOT IMPLEMENTED"); - } - - /** - * Present a form for editing an existing resource - * @param ORM $resource the resource container for instances of this resource type - */ - public function _form_edit($resource) { - throw new Exception("@todo _form_edit NOT IMPLEMENTED"); - } -} diff --git a/core/controllers/scaffold.php b/core/controllers/scaffold.php deleted file mode 100644 index f0063725..00000000 --- a/core/controllers/scaffold.php +++ /dev/null @@ -1,437 +0,0 @@ -template->album_count = ORM::factory("item")->where("type", "album")->count_all(); - $this->template->photo_count = ORM::factory("item")->where("type", "photo")->count_all(); - $this->template->album_tree = $this->_load_album_tree(); - $this->template->add_photo_html = $this->_get_add_photo_html(); - } catch (Exception $e) { - $this->template->album_count = 0; - $this->template->photo_count = 0; - $this->template->deepest_photo = null; - $this->template->album_tree = array(); - $this->template->add_photo_html = ""; - } - - $this->_load_comment_info(); - $this->_load_tag_info(); - - restore_error_handler(); - - if (!empty($session) && $session->get("profiler", false)) { - $profiler = new Profiler(); - $profiler->render(); - } - } - - - function add_photos() { - $path = trim($this->input->post("path")); - $parent_id = (int)$this->input->post("parent_id"); - $parent = ORM::factory("item", $parent_id); - if (!$parent->loaded) { - throw new Exception("@todo BAD_ALBUM"); - } - - batch::start(); - cookie::set("add_photos_path", $path); - $photo_count = 0; - foreach (glob("$path/*.[Jj][Pp][Gg]") as $file) { - set_time_limit(30); - photo::create($parent, $file, basename($file), basename($file)); - $photo_count++; - } - batch::stop(); - - if ($photo_count > 0) { - log::success("content", "(scaffold) Added $photo_count photos", - html::anchor("albums/$parent_id", "View album")); - } - - url::redirect("scaffold"); - } - - function add_albums_and_photos($count, $desired_type=null) { - srand(time()); - $parents = ORM::factory("item")->where("type", "album")->find_all()->as_array(); - $owner_id = user::active()->id; - - $test_images = glob(APPPATH . "tests/images/*.[Jj][Pp][Gg]"); - - batch::start(); - $album_count = $photo_count = 0; - for ($i = 0; $i < $count; $i++) { - set_time_limit(30); - - $parent = $parents[array_rand($parents)]; - $parent->reload(); - $type = $desired_type; - if (!$type) { - $type = rand(0, 10) ? "photo" : "album"; - } - if ($type == "album") { - $thumb_size = module::get_var("core", "thumb_size"); - $parents[] = album::create( - $parent, "rnd_" . rand(), "Rnd $i", "random album $i", $owner_id) - ->save(); - $album_count++; - } else { - $photo_index = rand(0, count($test_images) - 1); - photo::create($parent, $test_images[$photo_index], basename($test_images[$photo_index]), - "rnd_" . rand(), "sample thumb", $owner_id); - $photo_count++; - } - } - batch::stop(); - - if ($photo_count > 0) { - log::success("content", "(scaffold) Added $photo_count photos"); - } - - if ($album_count > 0) { - log::success("content", "(scaffold) Added $album_count albums"); - } - url::redirect("scaffold"); - } - - function random_phrase($count) { - static $words; - if (empty($words)) { - $sample_text = "Sed ut perspiciatis, unde omnis iste natus error sit voluptatem accusantium - laudantium, totam rem aperiam eaque ipsa, quae ab illo inventore veritatis et quasi - architecto beatae vitae dicta sunt, explicabo. Nemo enim ipsam voluptatem, quia voluptas - sit, aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos, qui ratione - voluptatem sequi nesciunt, neque porro quisquam est, qui dolorem ipsum, quia dolor sit, - amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora incidunt, ut - labore et dolore magnam aliquam quaerat voluptatem. Ut enim ad minima veniam, quis - nostrum exercitationem ullam corporis suscipit laboriosam, nisi ut aliquid ex ea commodi - consequatur? Quis autem vel eum iure reprehenderit, qui in ea voluptate velit esse, quam - nihil molestiae consequatur, vel illum, qui dolorem eum fugiat, quo voluptas nulla - pariatur? At vero eos et accusamus et iusto odio dignissimos ducimus, qui blanditiis - praesentium voluptatum deleniti atque corrupti, quos dolores et quas molestias excepturi - sint, obcaecati cupiditate non provident, similique sunt in culpa, qui officia deserunt - mollitia animi, id est laborum et dolorum fuga. Et harum quidem rerum facilis est et - expedita distinctio. Nam libero tempore, cum soluta nobis est eligendi optio, cumque - nihil impedit, quo minus id, quod maxime placeat, facere possimus, omnis voluptas - assumenda est, omnis dolor repellendus. Temporibus autem quibusdam et aut officiis - debitis aut rerum necessitatibus saepe eveniet, ut et voluptates repudiandae sint et - molestiae non recusandae. Itaque earum rerum hic tenetur a sapiente delectus, ut aut - reiciendis voluptatibus maiores alias consequatur aut perferendis doloribus asperiores - repellat."; - $words = preg_split('/\s+/', $sample_text); - } - - $chosen = array(); - for ($i = 0; $i < $count; $i++) { - $chosen[] = $words[array_rand($words)]; - } - - return implode(' ', $chosen); - } - - function add_comments($count) { - srand(time()); - $photos = ORM::factory("item")->where("type", "photo")->find_all()->as_array(); - $users = ORM::factory("user")->find_all()->as_array(); - - if (empty($photos)) { - url::redirect("scaffold"); - } - - if (module::is_active("akismet")) { - akismet::$test_mode = 1; - } - for ($i = 0; $i < $count; $i++) { - $photo = $photos[array_rand($photos)]; - $author = $users[array_rand($users)]; - $guest_name = ucfirst($this->random_phrase(rand(1, 3))); - $guest_email = sprintf("%s@%s.com", $this->random_phrase(1), $this->random_phrase(1)); - $guest_url = sprintf("http://www.%s.com", $this->random_phrase(1)); - comment::create($photo, $author, $this->random_phrase(rand(8, 500)), - $guest_name, $guest_email, $guest_url); - } - - url::redirect("scaffold"); - } - - function add_tags($count) { - $items = ORM::factory("item")->find_all()->as_array(); - - if (!empty($items)) { - $tags = $this->_generateTags($count); - - while ($count-- > 0) { - $tag_name = $tags[array_rand($tags)]; - $item = $items[array_rand($items)]; - - tag::add($item, $tag_name); - } - } - - url::redirect("scaffold"); - } - - private function _generateTags($number){ - // Words from lorem2.com - $words = explode( - " ", - "Lorem ipsum dolor sit amet consectetuer adipiscing elit Donec odio Quisque volutpat " . - "mattis eros Nullam malesuada erat ut turpis Suspendisse urna nibh viverra non " . - "semper suscipit posuere a pede Donec nec justo eget felis facilisis " . - "fermentum Aliquam porttitor mauris sit amet orci Aenean dignissim pellentesque " . - "felis Morbi in sem quis dui placerat ornare Pellentesque odio nisi euismod in " . - "pharetra a ultricies in diam Sed arcu Cras consequat Praesent dapibus neque " . - "id cursus faucibus tortor neque egestas augue eu vulputate magna eros eu " . - "erat Aliquam erat volutpat Nam dui mi tincidunt quis accumsan porttitor " . - "facilisis luctus metus Phasellus ultrices nulla quis nibh Quisque a " . - "lectus Donec consectetuer ligula vulputate sem tristique cursus Nam nulla quam " . - "gravida non commodo a sodales sit amet nisi Pellentesque fermentum " . - "dolor Aliquam quam lectus facilisis auctor ultrices ut elementum vulputate " . - "nunc Sed adipiscing ornare risus Morbi est est blandit sit amet sagittis vel " . - "euismod vel velit Pellentesque egestas sem Suspendisse commodo ullamcorper " . - "magna"); - - while ($number--) { - $results[] = $words[array_rand($words, 1)]; - } - return $results; - } - - function _error_handler($x) { - } - - private function _load_comment_info() { - if (class_exists("Comment_Model")) { - $this->template->comment_count = ORM::factory("comment")->count_all(); - } else { - $this->template->comment_count = 0; - } - } - - private function _load_tag_info() { - if (class_exists("Tag_Model")) { - $this->template->tag_count = ORM::factory("tag")->count_all(); - $this->template->most_tagged = Database::instance() - ->select("item_id AS id", "COUNT(tag_id) AS count") - ->from("items_tags") - ->groupby("item_id") - ->orderby("count", "DESC") - ->limit(1) - ->get() - ->current(); - } else { - $this->template->tag_count = 0; - $this->template->most_tagged = 0; - } - } - - function install($module_name, $redirect=true) { - $to_install = array(); - if ($module_name == "*") { - foreach (module::available() as $module_name => $info) { - if (empty($info->installed)) { - $to_install[] = $module_name; - } - } - } else { - $to_install[] = $module_name; - } - - foreach ($to_install as $module_name) { - if ($module_name != "core") { - require_once(DOCROOT . "modules/${module_name}/helpers/${module_name}_installer.php"); - } - module::install($module_name); - } - - if ($redirect) { - url::redirect("scaffold"); - } - } - - - public function package() { - $this->auto_render = false; - $db = Database::instance(); - - // Drop all tables - foreach ($db->list_tables() as $table) { - $db->query("DROP TABLE IF EXISTS `$table`"); - } - - // Clean out data - dir::unlink(VARPATH . "uploads"); - dir::unlink(VARPATH . "albums"); - dir::unlink(VARPATH . "resizes"); - dir::unlink(VARPATH . "thumbs"); - dir::unlink(VARPATH . "modules"); - dir::unlink(VARPATH . "tmp"); - - $db->clear_cache(); - module::$modules = array(); - module::$active = array(); - - // Use a known random seed so that subsequent packaging runs will reuse the same random - // numbers, keeping our install.sql file more stable. - srand(0); - - try { - core_installer::install(true); - module::load_modules(); - - foreach (array("user", "comment", "organize", "info", "rss", - "search", "slideshow", "tag") as $module_name) { - module::install($module_name); - module::activate($module_name); - } - } catch (Exception $e) { - Kohana::log("error", $e->getTraceAsString()); - print $e->getTrace(); - throw $e; - } - - url::redirect("scaffold/dump_database"); - } - - public function dump_database() { - $this->auto_render = false; - - // We now have a clean install with just the packages that we want. Make sure that the - // database is clean too. - $db = Database::instance(); - $db->query("TRUNCATE {sessions}"); - $db->query("TRUNCATE {logs}"); - $db->query("DELETE FROM {vars} WHERE `module_name` = 'core' AND `name` = '_cache'"); - $db->update("users", array("password" => ""), array("id" => 1)); - $db->update("users", array("password" => ""), array("id" => 2)); - - $dbconfig = Kohana::config('database.default'); - $conn = $dbconfig["connection"]; - $pass = $conn["pass"] ? "-p{$conn['pass']}" : ""; - $sql_file = DOCROOT . "installer/install.sql"; - if (!is_writable($sql_file)) { - print "$sql_file is not writeable"; - return; - } - $command = "mysqldump --compact --add-drop-table -h{$conn['host']} " . - "-u{$conn['user']} $pass {$conn['database']} > $sql_file"; - exec($command, $output, $status); - if ($status) { - print "
";
-      print "$command\n";
-      print "Failed to dump database\n";
-      print implode("\n", $output);
-      return;
-    }
-
-    // Post-process the sql file
-    $buf = "";
-    $root_timestamp = ORM::factory("item", 1)->created;
-    foreach (file($sql_file) as $line) {
-      // Prefix tables
-      $line = preg_replace(
-        "/(CREATE TABLE|IF EXISTS|INSERT INTO) `{$dbconfig['table_prefix']}(\w+)`/", "\\1 {\\2}",
-        $line);
-
-      // Normalize dates
-      $line = preg_replace("/,$root_timestamp,/", ",UNIX_TIMESTAMP(),", $line);
-      $buf .= $line;
-    }
-    $fd = fopen($sql_file, "wb");
-    fwrite($fd, $buf);
-    fclose($fd);
-
-    url::redirect("scaffold/dump_var");
-  }
-
-  public function dump_var() {
-    $this->auto_render = false;
-
-    $objects = new RecursiveIteratorIterator(
-      new RecursiveDirectoryIterator(VARPATH),
-      RecursiveIteratorIterator::SELF_FIRST);
-
-    $var_file = DOCROOT . "installer/init_var.php";
-    if (!is_writable($var_file)) {
-      print "$var_file is not writeable";
-      return;
-    }
-
-    $paths = array();
-    foreach($objects as $name => $file){
-      if ($file->getBasename() == "database.php") {
-        continue;
-      } else if (basename($file->getPath()) == "logs") {
-        continue;
-      }
-
-      if ($file->isDir()) {
-        $paths[] = "VARPATH . \"" . substr($name, strlen(VARPATH)) . "\"";
-      } else {
-        // @todo: serialize non-directories
-        print "Unknown file: $name";
-        return;
-      }
-    }
-    // Sort the paths so that the var file is stable
-    sort($paths);
-
-    $fd = fopen($var_file, "w");
-    fwrite($fd, "\n");
-    fwrite($fd, "where("type", "album")->find_all() as $album) {
-      if ($album->parent_id) {
-        $tree[$album->parent_id]->children[] = $album->id;
-      }
-      $tree[$album->id]->album = $album;
-      $tree[$album->id]->children = array();
-    }
-
-    return $tree;
-  }
-
-  public function form($arg1, $arg2) {
-    if ($arg1 == "add" && $arg2 == "photos") {
-      print $this->_get_add_photo_html();
-    }
-    $this->auto_render = false;
-  }
-
-  public function _get_add_photo_html($parent_id=1) {
-    $parent = ORM::factory("item", $parent_id);
-    return photo::get_add_form($parent);
-  }
-}
diff --git a/core/controllers/simple_uploader.php b/core/controllers/simple_uploader.php
deleted file mode 100644
index bdf9582f..00000000
--- a/core/controllers/simple_uploader.php
+++ /dev/null
@@ -1,86 +0,0 @@
-item = $item;
-    print $v;
-  }
-
-  public function start() {
-    batch::start();
-  }
-
-  public function add_photo($id) {
-    $album = ORM::factory("item", $id);
-    access::required("add", $album);
-    access::verify_csrf();
-
-    $file_validation = new Validation($_FILES);
-    $file_validation->add_rules("Filedata", "upload::valid", "upload::type[gif,jpg,png,flv,mp4]");
-    if ($file_validation->validate()) {
-
-      // SimpleUploader.swf does not yet call /start directly, so simulate it here for now.
-      if (!batch::in_progress()) {
-        batch::start();
-      }
-
-      $temp_filename = upload::save("Filedata");
-      try {
-        $name = substr(basename($temp_filename), 10);  // Skip unique identifier Kohana adds
-        $title = $this->convert_filename_to_title($name);
-        $path_info = pathinfo($temp_filename);
-        if (array_key_exists("extension", $path_info) &&
-            in_array(strtolower($path_info["extension"]), array("flv", "mp4"))) {
-          $movie = movie::create($album, $temp_filename, $name, $title);
-          log::success("content", t("Added a movie"),
-                       html::anchor("movies/$movie->id", t("view movie")));
-        } else {
-          $photo = photo::create($album, $temp_filename, $name, $title);
-          log::success("content", t("Added a photo"),
-                       html::anchor("photos/$photo->id", t("view photo")));
-        }
-      } catch (Exception $e) {
-        unlink($temp_filename);
-        throw $e;
-      }
-      unlink($temp_filename);
-    }
-    print "File Received";
-  }
-
-  /**
-   * We should move this into a helper somewhere.. but where is appropriate?
-   */
-  private function convert_filename_to_title($filename) {
-    $title = strtr($filename, "_", " ");
-    $title = preg_replace("/\..*?$/", "", $title);
-    $title = preg_replace("/ +/", " ", $title);
-    return $title;
-  }
-
-  public function finish() {
-    batch::stop();
-    print json_encode(array("result" => "success"));
-  }
-}
diff --git a/core/css/debug.css b/core/css/debug.css
deleted file mode 100644
index fe5665ad..00000000
--- a/core/css/debug.css
+++ /dev/null
@@ -1,28 +0,0 @@
-.gAnnotatedThemeBlock {
-  border: 1px solid #C00;
-  clear: both;
-  margin: 1em;
-  padding: 1em;
-  position: relative;
-}
-
-.gAnnotatedThemeBlock_album_top {
-  float: right;
-}
-
-.gAnnotatedThemeBlock_header_bottom {
-  float: right;
-}
-
-.gAnnotatedThemeBlock div.title {
-  background: #C00;
-  border: 1px solid black;
-  color: white;
-  font-size: 110%;
-  padding: 4px;
-  position: absolute;
-  right: -1em;
-  top: -1em;
-  text-align: left;
-  -moz-border-radius: 5%;
-}
diff --git a/core/css/l10n_client.css b/core/css/l10n_client.css
deleted file mode 100644
index 8973715f..00000000
--- a/core/css/l10n_client.css
+++ /dev/null
@@ -1,185 +0,0 @@
-// TODO(andy_st): Add original copyright notice from Drupal l10_client.
-// TODO(andy_st): Add G3 copyright notice.
-// TODO(andy_st): clean up formatting to match our other CSS files.
-
-/* $Id: l10n_client.css,v 1.6 2008/09/09 10:48:20 goba Exp $ */
-
-/* width percentages add to 99% rather than 100% to prevent float
-overflows from occurring in an unnamed browser that can't decide
-how it wants to round. */
-
-/* l10n_client container */
-#l10n-client {
-  text-align:left;
-  z-index:99;
-  line-height:1em;
-  color:#000; background:#fff;
-  position:fixed;
-  width:100%; height: 2em;
-  bottom:0px; left:0px;
-  overflow:hidden;}
-
-  * html #l10n-client {
-    position:static;}
-
-#l10n-client-string-select .string-list,
-#l10n-client-string-editor .source,
-#l10n-client-string-editor .editor {
-  height:20em;}
-
-#l10n-client .labels {
-  overflow:hidden;
-  position:relative;
-  height:2em;
-  color:#fff;
-  background:#37a;}
-
-  #l10n-client .labels .label {
-    display:none;}
-
-  /* Panel toggle button (span) */
-  #l10n-client .labels .toggle {
-    cursor:pointer;
-    display:block;
-    position:absolute; right:0em;
-    padding: 0em .75em; height:2em; line-height:2em;
-    text-transform:uppercase;
-    text-align:center; background:#000;}
-
-  /* Panel labels */
-  #l10n-client h2 {
-    border-left:1px solid #fff;
-    height:1em; line-height:1em;
-    padding: .5em; margin:0px;
-    font-size:1em;
-    text-transform:uppercase;}
-
-    #l10n-client .strings h2 {
-      border:0px;}
-
-  /* 25 + 37 + 37 = 99 */
-  #l10n-client .strings {
-    width:25%; float:left;}
-
-  #l10n-client .source {
-    width:37%; float:left;}
-
-  #l10n-client .translation {
-    width:37%; float:left;}
-
-/* Translatable string list */
-#l10n-client-string-select {
-  display:none;
-  float:left;
-  width:25%;}
-
-  #l10n-client .string-list {
-    height:17em;
-    overflow:auto;
-    list-style:none; list-style-image:none;
-    margin:0em; padding:0em;}
-
-  #l10n-client .string-list li {
-    font-size:.9em;
-    line-height:1.5em;
-    cursor:default;
-    background:transparent;
-    list-style:none; list-style-image:none;
-    border-bottom:1px solid #ddd;
-    padding:.25em .5em;
-    margin:0em;}
-
-  /* Green for translated */
-  #l10n-client .string-list li.translated {
-    border-bottom-color:#9c3;
-    background:#cf6; color:#360;}
-
-    #l10n-client .string-list li.translated:hover {
-      background: #df8;}
-
-    #l10n-client .string-list li.translated:active {
-      background: #9c3;}
-
-  #l10n-client .string-list li.hidden {
-    display:none;}
-
-  /* Gray + Blue hover for untranslated */
-  #l10n-client .string-list li.untranslated {}
-
-    #l10n-client .string-list li.untranslated:hover {
-      background: #ace;}
-
-    #l10n-client .string-list li.untranslated:active {
-      background: #8ac;}
-
-  /* Selected string is indicated by bold text */
-  #l10n-client .string-list li.active {
-    font-weight:bold;}
-
-  #l10n-client #gL10nSearchForm {
-    background:#eee;
-    text-align:center;
-    height:2em; line-height:2em;
-    margin:0em; padding:.5em .5em;
-  }
-
-  #l10n-client #gL10nSearchForm .form-item,
-  #l10n-client #gL10nSearchForm input.form-text,
-  #l10n-client #gL10nSearchForm #search-filter-go,
-  #l10n-client #gL10nSearchForm #search-filter-clear {
-    display:inline;
-    vertical-align:middle;
-  }
-
-    #l10n-client #gL10nSearchForm .form-item {
-      margin:0em;
-      padding:0em;
-    }
-
-    #l10n-client #gL10nSearchForm input.form-text {
-      width:80%;
-    }
-
-    #l10n-client #gL10nSearchForm #search-filter-clear {
-      width:10%;
-      margin:0em;
-    }
-
-
-#l10n-client-string-editor {
-  display:none;
-  float:left;
-  width:74%;}
-
-  #l10n-client-string-editor .source {
-    overflow:hidden;
-    width:50%; float:left;}
-
-    #l10n-client-string-editor .source .source-text {
-      line-height:1.5em;
-      background:#eee;
-      height:16em; margin:1em; padding:1em;
-      overflow:auto;}
-
-  #l10n-client-string-editor .translation {
-    overflow:hidden;
-    width:49%; float:right;}
-
-#gL10nClientSaveForm {
-  padding:0em;}
-
-  #gL10nClientSaveForm .form-textarea {
-    height:13em;
-    font-size:1em; line-height:1.25em;
-    width:95%;}
-
-  #gL10nClientSaveForm .form-submit {
-    margin-top: 0em;}
-
-
-#l10n-client form ul,
-#l10n-client form li,
-#l10n-client form input[type=submit],
-#l10n-client form input[type=text] {
-  display: inline ! important ;
-}
diff --git a/core/css/quick.css b/core/css/quick.css
deleted file mode 100644
index 02f9953e..00000000
--- a/core/css/quick.css
+++ /dev/null
@@ -1,40 +0,0 @@
-.gItem:hover {
-  background-color: #cfdeff;
-}
-
-.gQuick {
-  border: none !important;
-  margin: 0 !important;
-  padding: 0 !important;
-}
-
-#gQuickPane {
-  background: #000;
-  border-bottom: 1px solid #ccc;
-  opacity: 0.9;
-}
-
-#gQuickPane a {
-  cursor: pointer;
-  float: left;
-  margin: 4px;
-}
-
-#gQuickPaneOptions {
-  background: #000;
-  float: left;
-  width: 100%;
-}
-
-#gQuickPaneOptions li a {
-  display: block;
-  float: none;
-  width: auto;
-  margin: 0;
-  padding: .5em .5em .5em .8em;
-  text-align: left;
-}
-
-#gQuickPaneOptions li a:hover {
-  background-color: #4d4d4d;
-}
diff --git a/core/helpers/MY_remote.php b/core/helpers/MY_remote.php
deleted file mode 100644
index 4abf5bf1..00000000
--- a/core/helpers/MY_remote.php
+++ /dev/null
@@ -1,163 +0,0 @@
- $value) {
-      if (!empty($post_data_raw)) {
-        $post_data_raw .= '&';
-      }
-      $post_data_raw .= urlencode($key) . '=' . urlencode($value);
-    }
-    
-    $extra_headers['Content-Type'] = 'application/x-www-form-urlencoded';
-    $extra_headers['Content-Length'] = strlen($post_data_raw);
-    
-    return $post_data_raw;
-  }
-
-  /**
-   * A single request, without following redirects
-   *
-   * @todo: Handle redirects? If so, only for GET (i.e. not for POST), and use G2's WebHelper_simple::_parseLocation logic.
-   */
-  static function do_request($url, $method='GET', $headers=array(), $body='') {
-    /* Convert illegal characters */
-    $url = str_replace(' ', '%20', $url);
-    
-    $url_components = self::_parse_url_for_fsockopen($url);
-    $handle = fsockopen(
-      $url_components['fsockhost'], $url_components['port'], $errno, $errstr, 5);
-    if (empty($handle)) {
-      // log "Error $errno: '$errstr' requesting $url";
-      return array(null, null, null);
-    }
-    
-    $header_lines = array('Host: ' . $url_components['host']);
-    foreach ($headers as $key => $value) {
-      $header_lines[] = $key . ': ' . $value;
-    }
-    
-    $success = fwrite($handle, sprintf("%s %s HTTP/1.0\r\n%s\r\n\r\n%s",
-                                       $method,
-                                       $url_components['uri'],
-                                       implode("\r\n", $header_lines),
-                                       $body));
-    if (!$success) {
-      // Zero bytes written or false was returned
-      // log "fwrite failed in requestWebPage($url)" . ($success === false ? ' - false' : ''
-      return array(null, null, null);
-    }
-    fflush($handle);
-    
-    /*
-     * Read the status line.  fgets stops after newlines.  The first line is the protocol
-     * version followed by a numeric status code and its associated textual phrase.
-     */
-    $response_status = trim(fgets($handle, 4096));
-    if (empty($response_status)) {
-      // 'Empty http response code, maybe timeout'
-      return array(null, null, null);
-    }
-    
-    /* Read the headers */
-    $response_headers = array();
-    while (!feof($handle)) {
-      $line = trim(fgets($handle, 4096));
-      if (empty($line)) {
-        break;
-      }
-      
-      /* Normalize the line endings */
-      $line = str_replace("\r", '', $line);
-      
-      list ($key, $value) = explode(':', $line, 2);
-      if (isset($response_headers[$key])) {
-        if (!is_array($response_headers[$key])) {
-          $response_headers[$key] = array($response_headers[$key]);
-        }
-        $response_headers[$key][] = trim($value);
-      } else {
-        $response_headers[$key] = trim($value);
-      }
-    }
-    
-    /* Read the body */
-    $response_body = '';
-    while (!feof($handle)) {
-      $response_body .= fread($handle, 4096);
-    }
-    fclose($handle);
-
-    return array($response_status, $response_headers, $response_body);
-  }
-
-  /**
-   * Prepare for fsockopen call.
-   * @param string $url
-   * @return array url components
-   * @access private
-   */
-  private static function _parse_url_for_fsockopen($url) {
-    $url_components = parse_url($url);
-    if (strtolower($url_components['scheme']) == 'https') {
-      $url_components['fsockhost'] = 'ssl://' . $url_components['host'];
-      $default_port = 443;
-    } else {
-      $url_components['fsockhost'] = $url_components['host'];
-      $default_port = 80;
-    }
-    if (empty($url_components['port'])) {
-      $url_components['port'] = $default_port;
-    }
-    if (empty($url_components['path'])) {
-      $url_components['path'] = '/';
-    }
-    $uri = $url_components['path']
-      . (empty($url_components['query']) ? '' : '?' . $url_components['query']);
-    /* Unescape ampersands, since if the url comes from form input it will be escaped */
-    $url_components['uri'] = str_replace('&', '&', $uri);
-    return $url_components;
-  }
-}
-
diff --git a/core/helpers/MY_url.php b/core/helpers/MY_url.php
deleted file mode 100644
index 81dcbe1e..00000000
--- a/core/helpers/MY_url.php
+++ /dev/null
@@ -1,81 +0,0 @@
-relative_path();
-    }
-    return parent::site($uri . $query, $protocol);
-  }
-
-  static function parse_url() {
-    if (Router::$controller) {
-      return;
-    }
-
-    $count = count(Router::$segments);
-    foreach (ORM::factory("item")
-             ->where("name", html_entity_decode(Router::$segments[$count - 1], ENT_QUOTES))
-             ->where("level", $count + 1)
-             ->find_all() as $match) {
-      if ($match->relative_path() == html_entity_decode(Router::$current_uri, ENT_QUOTES)) {
-        $item = $match;
-      }
-    }
-
-    if (!empty($item)) {
-      Router::$controller = "{$item->type}s";
-      Router::$controller_path = APPPATH . "controllers/{$item->type}s.php";
-      Router::$method = $item->id;
-    }
-  }
-
-  /**
-   * Just like url::file() except that it returns an absolute URI
-   */
-  static function abs_file($path) {
-    return url::base(
-      false, (empty($_SERVER['HTTPS']) || $_SERVER['HTTPS'] === 'off') ? 'http' : 'https') . $path;
-  }
-
-  /**
-   * Just like url::site() except that it returns an absolute URI and
-   * doesn't take a protocol parameter.
-   */
-  static function abs_site($path) {
-    return url::site(
-      $path, (empty($_SERVER['HTTPS']) || $_SERVER['HTTPS'] === 'off') ? 'http' : 'https');
-  }
-
-  /**
-   * Just like url::current except that it returns an absolute URI
-   */
-  static function abs_current($qs=false) {
-    return self::abs_site(url::current($qs));
-  }
-}
diff --git a/core/helpers/access.php b/core/helpers/access.php
deleted file mode 100644
index 64ce91fa..00000000
--- a/core/helpers/access.php
+++ /dev/null
@@ -1,628 +0,0 @@
- tuples.  It would be inefficient to check
- *   these tuples every time we want to do a lookup, so we use these intents to create an entire
- *   table of permissions for easy lookup in the Access_Cache_Model.  There's a 1:1 mapping
- *   between Item_Model and Access_Cache_Model entries.
- *
- * o For efficiency, we create columns in Access_Intent_Model and Access_Cache_Model for each of
- *   the possible Group_Model and Permission_Model combinations.  This may lead to performance
- *   issues for very large Gallery installs, but for small to medium sized ones (5-10 groups, 5-10
- *   permissions) it's especially efficient because there's a single field value for each
- *   group/permission/item combination.
- *
- * o For efficiency, we store the cache columns for view permissions directly in the Item_Model.
- *   This means that we can filter items by group/permission combination without doing any table
- *   joins making for an especially efficient permission check at the expense of having to
- *   maintain extra columns for each item.
- *
- * o If at any time the Access_Cache_Model becomes invalid, we can rebuild the entire table from
- *   the Access_Intent_Model
- */
-class access_Core {
-  const DENY      = 0;
-  const ALLOW     = 1;
-  const UNKNOWN   = 2;
-
-  /**
-   * Does the active user have this permission on this item?
-   *
-   * @param  string     $perm_name
-   * @param  Item_Model $item
-   * @return boolean
-   */
-  static function can($perm_name, $item) {
-    if (!$item->loaded) {
-      return false;
-    }
-
-    if (user::active()->admin) {
-      return true;
-    }
-
-    $resource = $perm_name == "view" ?
-      $item : model_cache::get("access_cache", $item->id, "item_id");
-    foreach (user::group_ids() as $id) {
-      if ($resource->__get("{$perm_name}_$id") === self::ALLOW) {
-        return true;
-      }
-    }
-    return false;
-  }
-
-  /**
-   * If the active user does not have this permission, failed with an access::forbidden().
-   *
-   * @param  string     $perm_name
-   * @param  Item_Model $item
-   * @return boolean
-   */
-  static function required($perm_name, $item) {
-    if (!self::can($perm_name, $item)) {
-      self::forbidden();
-    }
-  }
-
-  /**
-   * Does this group have this permission on this item?
-   *
-   * @param  Group_Model $group
-   * @param  string      $perm_name
-   * @param  Item_Model  $item
-   * @return boolean
-   */
-  static function group_can($group, $perm_name, $item) {
-    $resource = $perm_name == "view" ?
-      $item : model_cache::get("access_cache", $item->id, "item_id");
-    return $resource->__get("{$perm_name}_{$group->id}") === self::ALLOW;
-  }
-
-  /**
-   * Return this group's intent for this permission on this item.
-   *
-   * @param  Group_Model $group
-   * @param  string      $perm_name
-   * @param  Item_Model  $item
-   * @return integer     access::ALLOW, access::DENY or null for no intent
-   */
-  static function group_intent($group, $perm_name, $item) {
-    $intent = model_cache::get("access_intent", $item->id, "item_id");
-    return $intent->__get("{$perm_name}_{$group->id}");
-  }
-
-  /**
-   * Is the permission on this item locked by a parent?  If so return the nearest parent that
-   * locks it.
-   *
-   * @param  Group_Model $group
-   * @param  string      $perm_name
-   * @param  Item_Model  $item
-   * @return ORM_Model   item that locks this one
-   */
-  static function locked_by($group, $perm_name, $item) {
-    if ($perm_name != "view") {
-      return null;
-    }
-
-    // For view permissions, if any parent is self::DENY, then those parents lock this one.
-    // Return
-    $lock = ORM::factory("item")
-      ->where("`left` <= $item->left")
-      ->where("`right` >= $item->right")
-      ->where("items.id <> $item->id")
-      ->join("access_intents", "items.id", "access_intents.item_id")
-      ->where("access_intents.view_$group->id", 0)
-      ->orderby("level", "DESC")
-      ->limit(1)
-      ->find();
-
-    if ($lock->loaded) {
-      return $lock;
-    } else {
-      return null;
-    }
-  }
-
-  /**
-   * Terminate immediately with an HTTP 503 Forbidden response.
-   */
-  static function forbidden() {
-    throw new Exception("@todo FORBIDDEN", 503);
-  }
-
-  /**
-   * Internal method to set a permission
-   *
-   * @param  Group_Model $group
-   * @param  string      $perm_name
-   * @param  Item_Model  $item
-   * @param  boolean     $value
-   */
-  private static function _set(Group_Model $group, $perm_name, $album, $value) {
-    if (get_class($group) != "Group_Model") {
-      throw new Exception("@todo PERMISSIONS_ONLY_WORK_ON_GROUPS");
-    }
-    if (!$album->loaded) {
-      throw new Exception("@todo INVALID_ALBUM $album->id");
-    }
-    if (!$album->is_album()) {
-      throw new Exception("@todo INVALID_ALBUM_TYPE not an album");
-    }
-    $access = model_cache::get("access_intent", $album->id, "item_id");
-    $access->__set("{$perm_name}_{$group->id}", $value);
-    $access->save();
-
-    if ($perm_name == "view") {
-      self::_update_access_view_cache($group, $album);
-    } else {
-      self::_update_access_non_view_cache($group, $perm_name, $album);
-    }
-
-    self::_update_htaccess_files($album, $group, $perm_name, $value);
-  }
-
-  /**
-   * Allow a group to have a permission on an item.
-   *
-   * @param  Group_Model $group
-   * @param  string  $perm_name
-   * @param  Item_Model $item
-   */
-  static function allow($group, $perm_name, $item) {
-    self::_set($group, $perm_name, $item, self::ALLOW);
-  }
-
-  /**
-   * Deny a group the given permission on an item.
-   *
-   * @param  Group_Model $group
-   * @param  string  $perm_name
-   * @param  Item_Model $item
-   */
-  static function deny($group, $perm_name, $item) {
-    self::_set($group, $perm_name, $item, self::DENY);
-  }
-
-  /**
-   * Unset the given permission for this item and use inherited values
-   *
-   * @param  Group_Model $group
-   * @param  string  $perm_name
-   * @param  Item_Model $item
-   */
-  static function reset($group, $perm_name, $item) {
-    if ($item->id == 1) {
-      throw new Exception("@todo CANT_RESET_ROOT_PERMISSION");
-    }
-    self::_set($group, $perm_name, $item, null);
-  }
-
-  /**
-   * Register a permission so that modules can use it.
-   *
-   * @param  string $name           The internal name for for this permission
-   * @param  string $display_name   The internationalized version of the displayable name
-   * @return void
-  */
-  static function register_permission($name, $display_name) {
-    $permission = ORM::factory("permission", $name);
-    if ($permission->loaded) {
-      throw new Exception("@todo PERMISSION_ALREADY_EXISTS $name");
-    }
-    $permission->name = $name;
-    $permission->display_name = $display_name;
-    $permission->save();
-
-    foreach (self::_get_all_groups() as $group) {
-      self::_add_columns($name, $group);
-    }
-  }
-
-  /**
-   * Delete a permission.
-   *
-   * @param  string $perm_name
-   * @return void
-   */
-  static function delete_permission($name) {
-    foreach (self::_get_all_groups() as $group) {
-      self::_drop_columns($name, $group);
-    }
-    $permission = ORM::factory("permission")->where("name", $name)->find();
-    if ($permission->loaded) {
-      $permission->delete();
-    }
-  }
-
-  /**
-   * Add the appropriate columns for a new group
-   *
-   * @param Group_Model $group
-   * @return void
-   */
-  static function add_group($group) {
-    foreach (ORM::factory("permission")->find_all() as $perm) {
-      self::_add_columns($perm->name, $group);
-    }
-  }
-
-  /**
-   * Remove a group's permission columns (usually when it's deleted)
-   *
-   * @param Group_Model $group
-   * @return void
-   */
-  static function delete_group($group) {
-    foreach (ORM::factory("permission")->find_all() as $perm) {
-      self::_drop_columns($perm->name, $group);
-    }
-  }
-
-  /**
-   * Add new access rows when a new item is added.
-   *
-   * @param Item_Model $item
-   * @return void
-   */
-  static function add_item($item) {
-    $access_intent = ORM::factory("access_intent", $item->id);
-    if ($access_intent->loaded) {
-      throw new Exception("@todo ITEM_ALREADY_ADDED $item->id");
-    }
-    $access_intent = ORM::factory("access_intent");
-    $access_intent->item_id = $item->id;
-    $access_intent->save();
-
-    // Create a new access cache entry and copy the parents values.
-    $access_cache = ORM::factory("access_cache");
-    $access_cache->item_id = $item->id;
-    if ($item->id != 1) {
-      $parent_access_cache =
-        ORM::factory("access_cache")->where("item_id", $item->parent()->id)->find();
-      foreach (self::_get_all_groups() as $group) {
-        foreach (ORM::factory("permission")->find_all() as $perm) {
-          $field = "{$perm->name}_{$group->id}";
-          if ($perm->name == "view") {
-            $item->$field = $item->parent()->$field;
-          } else {
-            $access_cache->$field = $parent_access_cache->$field;
-          }
-        }
-      }
-    }
-    $item->save();
-    $access_cache->save();
-  }
-
-  /**
-   * Delete appropriate access rows when an item is deleted.
-   *
-   * @param Item_Model $item
-   * @return void
-   */
-  static function delete_item($item) {
-    ORM::factory("access_intent")->where("item_id", $item->id)->find()->delete();
-    ORM::factory("access_cache")->where("item_id", $item->id)->find()->delete();
-  }
-
-  /**
-   * Verify our Cross Site Request Forgery token is valid, else throw an exception.
-   */
-  static function verify_csrf() {
-    $input = Input::instance();
-    if ($input->post("csrf", $input->get("csrf", null)) !== Session::instance()->get("csrf")) {
-      self::forbidden();
-    }
-  }
-
-  /**
-   * Get the Cross Site Request Forgery token for this session.
-   * @return string
-   */
-  static function csrf_token() {
-    $session = Session::instance();
-    $csrf = $session->get("csrf");
-    if (empty($csrf)) {
-      $csrf = md5(rand());
-      $session->set("csrf", $csrf);
-    }
-    return $csrf;
-  }
-
-  /**
-   * Generate an  element containing the Cross Site Request Forgery token for this session.
-   * @return string
-   */
-  static function csrf_form_field() {
-    return "";
-  }
-
-  /**
-   * Internal method to get all available groups.
-   *
-   * @return ORM_Iterator
-   */
-  private static function _get_all_groups() {
-    // When we build the core package, it's possible that the user module is not installed yet.
-    // This is ok at packaging time, so work around it.
-    if (module::is_active("user")) {
-      return ORM::factory("group")->find_all();
-    } else {
-      return array();
-    }
-  }
-
-  /**
-   * Internal method to  remove Permission/Group columns
-   *
-   * @param  Group_Model $group
-   * @param  string      $perm_name
-   * @return void
-   */
-  private static function _drop_columns($perm_name, $group) {
-    $db = Database::instance();
-    $field = "{$perm_name}_{$group->id}";
-    $cache_table = $perm_name == "view" ? "items" : "access_caches";
-    $db->query("ALTER TABLE {{$cache_table}} DROP `$field`");
-    $db->query("ALTER TABLE {access_intents} DROP `$field`");
-    ORM::factory("access_intent")->clear_cache();
-  }
-
-  /**
-   * Internal method to add Permission/Group columns
-   *
-   * @param  Group_Model $group
-   * @param  string  $perm_name
-   * @return void
-   */
-  private static function _add_columns($perm_name, $group) {
-    $db = Database::instance();
-    $field = "{$perm_name}_{$group->id}";
-    $cache_table = $perm_name == "view" ? "items" : "access_caches";
-    $db->query("ALTER TABLE {{$cache_table}} ADD `$field` SMALLINT NOT NULL DEFAULT 0");
-    $db->query("ALTER TABLE {access_intents} ADD `$field` BOOLEAN DEFAULT NULL");
-    $db->update("access_intents", array($field => 0), array("item_id" => 1));
-    ORM::factory("access_intent")->clear_cache();
-  }
-
-  /**
-   * Update the Access_Cache model based on information from the Access_Intent model for view
-   * permissions only.
-   *
-   * @todo: use database locking
-   *
-   * @param  Group_Model $group
-   * @param  Item_Model $item
-   * @return void
-   */
-  private static function _update_access_view_cache($group, $item) {
-    $access = ORM::factory("access_intent")->where("item_id", $item->id)->find();
-
-    $db = Database::instance();
-    $field = "view_{$group->id}";
-
-    // With view permissions, deny values in the parent can override allow values in the child,
-    // so start from the bottom of the tree and work upwards overlaying negative on top of
-    // positive.
-    //
-    // If the item's intent is ALLOW or DEFAULT, it's possible that some ancestor has specified
-    // DENY and this ALLOW cannot be obeyed.  So in that case, back up the tree and find any
-    // non-DEFAULT and non-ALLOW parent and propagate from there.  If we can't find a matching
-    // item, then its safe to propagate from here.
-    if ($access->$field !== self::DENY) {
-      $tmp_item = ORM::factory("item")
-        ->where("left <", $item->left)
-        ->where("right >", $item->right)
-        ->join("access_intents", "access_intents.item_id", "items.id")
-        ->where("access_intents.$field", self::DENY)
-        ->orderby("left", "DESC")
-        ->limit(1)
-        ->find();
-      if ($tmp_item->loaded) {
-        $item = $tmp_item;
-      }
-    }
-
-    // We will have a problem if we're trying to change a DENY to an ALLOW because the
-    // access_caches table will already contain DENY values and we won't be able to overwrite
-    // them according the rule above.  So mark every permission below this level as UNKNOWN so
-    // that we can tell which permissions have been changed, and which ones need to be updated.
-    $db->update("items", array($field => self::UNKNOWN),
-                array("left >=" => $item->left, "right <=" => $item->right));
-
-    $query = ORM::factory("access_intent")
-      ->select(array("access_intents.$field", "items.left", "items.right", "items.id"))
-      ->join("items", "items.id", "access_intents.item_id")
-      ->where("left >=", $item->left)
-      ->where("right <=", $item->right)
-      ->where("type", "album")
-      ->where("access_intents.$field IS NOT", null)
-      ->orderby("level", "DESC")
-      ->find_all();
-    foreach ($query as $row) {
-      if ($row->$field == self::ALLOW) {
-        // Propagate ALLOW for any row that is still UNKNOWN.
-        $db->update("items", array($field => $row->$field),
-          array($field => self::UNKNOWN, "left >=" => $row->left, "right <=" => $row->right));
-      } else if ($row->$field == self::DENY) {
-        // DENY overwrites everything below it
-        $db->update("items", array($field => $row->$field),
-                    array("left >=" => $row->left, "right <=" => $row->right));
-      }
-    }
-
-    // Finally, if our intent is DEFAULT at this point it means that we were unable to find a
-    // DENY parent in the hierarchy to propagate from.  So we'll still have a UNKNOWN values in
-    // the hierarchy, and all of those are safe to change to ALLOW.
-    $db->update("items", array($field => self::ALLOW),
-                array($field => self::UNKNOWN, "left >=" => $item->left, "right <=" => $item->right));
-  }
-
-  /**
-   * Update the Access_Cache model based on information from the Access_Intent model for non-view
-   * permissions.
-   *
-   * @todo: use database locking
-   *
-   * @param  Group_Model $group
-   * @param  string  $perm_name
-   * @param  Item_Model $item
-   * @return void
-   */
-  private static function _update_access_non_view_cache($group, $perm_name, $item) {
-    $access = ORM::factory("access_intent")->where("item_id", $item->id)->find();
-
-    $db = Database::instance();
-    $field = "{$perm_name}_{$group->id}";
-
-    // If the item's intent is DEFAULT, then we need to back up the chain to find the nearest
-    // parent with an intent and propagate from there.
-    //
-    // @todo To optimize this, we wouldn't need to propagate from the parent, we could just
-    //       propagate from here with the parent's intent.
-    if ($access->$field === null) {
-      $tmp_item = ORM::factory("item")
-        ->join("access_intents", "items.id", "access_intents.item_id")
-        ->where("left <", $item->left)
-        ->where("right >", $item->right)
-        ->where("$field IS NOT", null)
-        ->orderby("left", "DESC")
-        ->limit(1)
-        ->find();
-      if ($tmp_item->loaded) {
-        $item = $tmp_item;
-      }
-    }
-
-    // With non-view permissions, each level can override any permissions that came above it
-    // so start at the top and work downwards, overlaying permissions as we go.
-    $query = ORM::factory("access_intent")
-      ->select(array("access_intents.$field", "items.left", "items.right"))
-      ->join("items", "items.id", "access_intents.item_id")
-      ->where("left >=", $item->left)
-      ->where("right <=", $item->right)
-      ->where("$field IS NOT", null)
-      ->orderby("level", "ASC")
-      ->find_all();
-    foreach  ($query as $row) {
-      $db->query(
-        "UPDATE {access_caches} SET `$field` = {$row->$field} " .
-        "WHERE `item_id` IN " .
-        "  (SELECT `id` FROM {items} " .
-        "  WHERE `left` >= $row->left " .
-        "  AND `right` <= $row->right)");
-    }
-  }
-
-  /**
-   * Maintain .htacccess files to prevent direct access to albums, resizes and thumbnails when we
-   * apply the view and view_full permissions to guest users.
-   */
-  private static function _update_htaccess_files($album, $group, $perm_name, $value) {
-    if ($group->id != 1 || !($perm_name == "view" || $perm_name == "view_full")) {
-      return;
-    }
-
-    $dirs = array($album->file_path());
-    if ($perm_name == "view") {
-      $dirs[] = dirname($album->resize_path());
-      $dirs[] = dirname($album->thumb_path());
-    }
-
-    $base_url = url::site("file_proxy");
-    foreach ($dirs as $dir) {
-      if ($value === self::DENY) {
-        $fp = fopen("$dir/.htaccess", "w+");
-        fwrite($fp, "\n");
-        fwrite($fp, "  RewriteEngine On\n");
-        fwrite($fp, "  RewriteRule (.*) $base_url/\$1 [L]\n");
-        fwrite($fp, "\n");
-        fwrite($fp, "\n");
-        fwrite($fp, "  Order Deny,Allow\n");
-        fwrite($fp, "  Deny from All\n");
-        fwrite($fp, "\n");
-        fclose($fp);
-      } else {
-        @unlink($dir . "/.htaccess");
-      }
-    }
-  }
-
-  static function private_key() {
-    return module::get_var("core", "private_key");
-  }
-
-  /**
-   * Verify that our htaccess based permission system actually works.  Create a temporary
-   * directory containing an .htaccess file that uses mod_rewrite to redirect /verify to
-   * /success.  Then request that url.  If we retrieve it successfully, then our redirects are
-   * working and our permission system works.
-   */
-  static function htaccess_works() {
-    $success_url = url::file("var/tmp/security_test/success");
-
-    @mkdir(VARPATH . "tmp/security_test");
-    if ($fp = @fopen(VARPATH . "tmp/security_test/.htaccess", "w+")) {
-      fwrite($fp, "RewriteEngine On\n");
-      fwrite($fp, "RewriteRule verify $success_url [L]\n");
-      fclose($fp);
-    }
-
-    if ($fp = @fopen(VARPATH . "tmp/security_test/success", "w+")) {
-      fwrite($fp, "success");
-      fclose($fp);
-    }
-
-    list ($response) = remote::do_request(url::abs_file("var/tmp/security_test/verify"));
-    $works = $response == "HTTP/1.1 200 OK";
-    @dir::unlink(VARPATH . "tmp/security_test");
-
-    return $works;
-  }
-}
diff --git a/core/helpers/album.php b/core/helpers/album.php
deleted file mode 100644
index 362b93d0..00000000
--- a/core/helpers/album.php
+++ /dev/null
@@ -1,132 +0,0 @@
-loaded || !$parent->is_album()) {
-      throw new Exception("@todo INVALID_PARENT");
-    }
-
-    if (strpos($name, "/")) {
-      throw new Exception("@todo NAME_CANNOT_CONTAIN_SLASH");
-    }
-
-    // We don't allow trailing periods as a security measure
-    // ref: http://dev.kohanaphp.com/issues/684
-    if (rtrim($name, ".") != $name) {
-      throw new Exception("@todo NAME_CANNOT_END_IN_PERIOD");
-    }
-
-    $album = ORM::factory("item");
-    $album->type = "album";
-    $album->title = $title;
-    $album->description = $description;
-    $album->name = $name;
-    $album->owner_id = $owner_id;
-    $album->thumb_dirty = 1;
-    $album->resize_dirty = 1;
-    $album->rand_key = ((float)mt_rand()) / (float)mt_getrandmax();
-    $album->sort_column = "weight";
-    $album->sort_order = "ASC";
-
-    while (ORM::factory("item")
-           ->where("parent_id", $parent->id)
-           ->where("name", $album->name)
-           ->find()->id) {
-      $album->name = "{$name}-" . rand();
-    }
-
-    $album = $album->add_to_parent($parent);
-    mkdir($album->file_path());
-    mkdir(dirname($album->thumb_path()));
-    mkdir(dirname($album->resize_path()));
-
-    module::event("item_created", $album);
-
-    return $album;
-  }
-
-  static function get_add_form($parent) {
-    $form = new Forge("albums/{$parent->id}", "", "post", array("id" => "gAddAlbumForm"));
-    $group = $form->group("add_album")
-      ->label(t("Add an album to %album_title", array("album_title" => $parent->title)));
-    $group->input("title")->label(t("Title"));
-    $group->textarea("description")->label(t("Description"));
-    $group->input("name")->label(t("Directory Name"))
-      ->callback("item::validate_no_slashes")
-      ->error_messages("no_slashes", t("The directory name can't contain the \"/\" character"));
-    $group->hidden("type")->value("album");
-    $group->submit("")->value(t("Create"));
-    $form->add_rules_from(ORM::factory("item"));
-    return $form;
-  }
-
-  static function get_edit_form($parent) {
-    $form = new Forge("albums/{$parent->id}", "", "post", array("id" => "gEditAlbumForm"));
-    $form->hidden("_method")->value("put");
-    $group = $form->group("edit_album")->label(t("Edit Album"));
-
-    $group->input("title")->label(t("Title"))->value($parent->title);
-    $group->textarea("description")->label(t("Description"))->value($parent->description);
-    if ($parent->id != 1) {
-      $group->input("dirname")->label(t("Directory Name"))->value($parent->name)
-        ->callback("item::validate_no_slashes")
-        ->error_messages("no_slashes", t("The directory name can't contain a \"/\""))
-        ->callback("item::validate_no_trailing_period")
-        ->error_messages("no_trailing_period", t("The directory name can't end in \".\""));
-    }
-
-    $sort_order = $group->group("sort_order", array("id" => "gAlbumSortOrder"))
-      ->label(t("Sort Order"));
-
-    $sort_order->dropdown("column", array("id" => "gAlbumSortColumn"))
-      ->label(t("Sort by"))
-      ->options(array("weight" => t("Default"),
-                      "captured" => t("Capture Date"),
-                      "created" => t("Creation Date"),
-                      "title" => t("Title"),
-                      "updated" => t("Updated Date"),
-                      "view_count" => t("Number of views"),
-                      "rand_key" => t("Random")))
-      ->selected($parent->sort_column);
-    $sort_order->dropdown("direction", array("id" => "gAlbumSortDirection"))
-      ->label(t("Order"))
-      ->options(array("ASC" => t("Ascending"),
-                      "DESC" => t("Descending")))
-      ->selected($parent->sort_order);
-    $group->hidden("type")->value("album");
-    $group->submit("")->value(t("Modify"));
-    $form->add_rules_from(ORM::factory("item"));
-    return $form;
-  }
-}
diff --git a/core/helpers/batch.php b/core/helpers/batch.php
deleted file mode 100644
index 0faa3369..00000000
--- a/core/helpers/batch.php
+++ /dev/null
@@ -1,40 +0,0 @@
-set("batch_level", $session->get("batch_level", 0) + 1);
-  }
-
-  static function stop() {
-    $session = Session::instance();
-    $batch_level = $session->get("batch_level", 0) - 1;
-    if ($batch_level > 0) {
-      $session->set("batch_level", $batch_level);
-    } else {
-      $session->delete("batch_level");
-      module::event("batch_complete");
-    }
-  }
-
-  static function in_progress() {
-    return Session::instance()->get("batch_level", 0) > 0;
-  }
-}
diff --git a/core/helpers/block_manager.php b/core/helpers/block_manager.php
deleted file mode 100644
index 022626e5..00000000
--- a/core/helpers/block_manager.php
+++ /dev/null
@@ -1,67 +0,0 @@
-name}_block";
-      if (method_exists($class_name, "get_list")) {
-        foreach (call_user_func(array($class_name, "get_list")) as $id => $title) {
-          $blocks["{$module->name}:$id"] = $title;
-        }
-      }
-    }
-    return $blocks;
-  }
-
-  static function get_html($location) {
-    $active = self::get_active($location);
-    $result = "";
-    foreach ($active as $id => $desc) {
-      if (method_exists("$desc[0]_block", "get")) {
-        $block = call_user_func(array("$desc[0]_block", "get"), $desc[1]);
-        $block->id = $id;
-        $result .= $block;
-      }
-    }
-    return $result;
-  }
-}
diff --git a/core/helpers/core.php b/core/helpers/core.php
deleted file mode 100644
index 63f51f86..00000000
--- a/core/helpers/core.php
+++ /dev/null
@@ -1,52 +0,0 @@
-admin) {
-      Router::$controller = "maintenance";
-      Router::$controller_path = APPPATH . "controllers/maintenance.php";
-      Router::$method = "index";
-    }
-  }
-
-  /**
-   * This function is called when the Gallery is fully initialized.  We relay it to modules as the
-   * "gallery_ready" event.  Any module that wants to perform an action at the start of every
-   * request should implement the _event::gallery_ready() handler.
-   */
-  static function ready() {
-    module::event("gallery_ready");
-  }
-
-  /**
-   * This function is called right before the Kohana framework shuts down.  We relay it to modules
-   * as the "gallery_shutdown" event.  Any module that wants to perform an action at the start of
-   * every request should implement the _event::gallery_shutdown() handler.
-   */
-  static function shutdown() {
-    module::event("gallery_shutdown");
-  }
-}
\ No newline at end of file
diff --git a/core/helpers/core_block.php b/core/helpers/core_block.php
deleted file mode 100644
index 0e2e9c54..00000000
--- a/core/helpers/core_block.php
+++ /dev/null
@@ -1,100 +0,0 @@
- t("Welcome to Gallery 3!"),
-      "photo_stream" => t("Photo Stream"),
-      "log_entries" => t("Log Entries"),
-      "stats" => t("Gallery Stats"),
-      "platform_info" => t("Platform Information"),
-      "project_news" => t("Gallery Project News"));
-  }
-
-  static function get($block_id) {
-    $block = new Block();
-    switch($block_id) {
-    case "welcome":
-      $block->css_id = "gWelcome";
-      $block->title = t("Welcome to Gallery3");
-      $block->content = new View("admin_block_welcome.html");
-      break;
-
-    case "photo_stream":
-      $block->css_id = "gPhotoStream";
-      $block->title = t("Photo Stream");
-      $block->content = new View("admin_block_photo_stream.html");
-      $block->content->photos =
-        ORM::factory("item")->where("type", "photo")->orderby("created", "DESC")->find_all(10);
-      break;
-
-    case "log_entries":
-      $block->css_id = "gLogEntries";
-      $block->title = t("Log Entries");
-      $block->content = new View("admin_block_log_entries.html");
-      $block->content->entries = ORM::factory("log")->orderby("timestamp", "DESC")->find_all(5);
-        break;
-
-    case "stats":
-      $block->css_id = "gStats";
-      $block->title = t("Gallery Stats");
-      $block->content = new View("admin_block_stats.html");
-      $block->content->album_count = ORM::factory("item")->where("type", "album")->count_all();
-      $block->content->photo_count = ORM::factory("item")->where("type", "photo")->count_all();
-      break;
-
-    case "platform_info":
-      $block->css_id = "gPlatform";
-      $block->title = t("Platform Information");
-      $block->content = new View("admin_block_platform.html");
-      if (is_readable("/proc/loadavg")) {
-        $block->content->load_average =
-          join(" ", array_slice(split(" ", array_shift(file("/proc/loadavg"))), 0, 3));
-      } else {
-        $block->content->load_average = t("Unavailable");
-      }
-      break;
-
-    case "project_news":
-      $block->css_id = "gProjectNews";
-      $block->title = t("Gallery Project News");
-      $block->content = new View("admin_block_news.html");
-      $block->content->feed = feed::parse("http://gallery.menalto.com/node/feed", 3);
-      break;
-
-    case "block_adder":
-      $block->css_id = "gBlockAdder";
-      $block->title = t("Dashboard Content");
-      $block->content = self::get_add_block_form();
-    }
-
-    return $block;
-  }
-
-  static function get_add_block_form() {
-    $form = new Forge("admin/dashboard/add_block", "", "post",
-                      array("id" => "gAddDashboardBlockForm"));
-    $group = $form->group("add_block")->label(t("Add Block"));
-    $group->dropdown("id")->label("Available Blocks")->options(block_manager::get_available());
-    $group->submit("center")->value(t("Add to center"));
-    $group->submit("sidebar")->value(t("Add to sidebar"));
-    return $form;
-  }
-}
\ No newline at end of file
diff --git a/core/helpers/core_event.php b/core/helpers/core_event.php
deleted file mode 100644
index bbb53cc9..00000000
--- a/core/helpers/core_event.php
+++ /dev/null
@@ -1,46 +0,0 @@
-admin && module::get_var("core", "choose_default_tookit", null)) {
-      graphics::choose_default_toolkit();
-      module::clear_var("core", "choose_default_tookit");
-    }
-  }
-}
diff --git a/core/helpers/core_installer.php b/core/helpers/core_installer.php
deleted file mode 100644
index cffcbedb..00000000
--- a/core/helpers/core_installer.php
+++ /dev/null
@@ -1,278 +0,0 @@
-query("CREATE TABLE {access_caches} (
-                   `id` int(9) NOT NULL auto_increment,
-                   `item_id` int(9),
-                   PRIMARY KEY (`id`))
-                 ENGINE=InnoDB DEFAULT CHARSET=utf8;");
-
-      $db->query("CREATE TABLE {access_intents} (
-                   `id` int(9) NOT NULL auto_increment,
-                   `item_id` int(9),
-                   PRIMARY KEY (`id`))
-                 ENGINE=InnoDB DEFAULT CHARSET=utf8;");
-
-      $db->query("CREATE TABLE {graphics_rules} (
-                   `id` int(9) NOT NULL auto_increment,
-                   `active` BOOLEAN default 0,
-                   `args` varchar(255) default NULL,
-                   `module_name` varchar(64) NOT NULL,
-                   `operation` varchar(64) NOT NULL,
-                   `priority` int(9) NOT NULL,
-                   `target`  varchar(32) NOT NULL,
-                   PRIMARY KEY (`id`))
-                 ENGINE=InnoDB DEFAULT CHARSET=utf8;");
-
-      $db->query("CREATE TABLE {items} (
-                   `id` int(9) NOT NULL auto_increment,
-                   `album_cover_item_id` int(9) default NULL,
-                   `captured` int(9) default NULL,
-                   `created` int(9) default NULL,
-                   `description` varchar(2048) default NULL,
-                   `height` int(9) default NULL,
-                   `left` int(9) NOT NULL,
-                   `level` int(9) NOT NULL,
-                   `mime_type` varchar(64) default NULL,
-                   `name` varchar(255) default NULL,
-                   `owner_id` int(9) default NULL,
-                   `parent_id` int(9) NOT NULL,
-                   `rand_key` float default NULL,
-                   `relative_path_cache` varchar(255) default NULL,
-                   `resize_dirty` boolean default 1,
-                   `resize_height` int(9) default NULL,
-                   `resize_width` int(9) default NULL,
-                   `right` int(9) NOT NULL,
-                   `sort_column` varchar(64) default NULL,
-                   `sort_order` char(4) default 'ASC',
-                   `thumb_dirty` boolean default 1,
-                   `thumb_height` int(9) default NULL,
-                   `thumb_width` int(9) default NULL,
-                   `title` varchar(255) default NULL,
-                   `type` varchar(32) NOT NULL,
-                   `updated` int(9) default NULL,
-                   `view_count` int(9) default 0,
-                   `weight` int(9) NOT NULL default 0,
-                   `width` int(9) default NULL,
-                   PRIMARY KEY (`id`),
-                   KEY `parent_id` (`parent_id`),
-                   KEY `type` (`type`),
-                   KEY `random` (`rand_key`))
-                 ENGINE=InnoDB DEFAULT CHARSET=utf8;");
-
-      $db->query("CREATE TABLE {logs} (
-                   `id` int(9) NOT NULL auto_increment,
-                   `category` varchar(64) default NULL,
-                   `html` varchar(255) default NULL,
-                   `message` text default NULL,
-                   `referer` varchar(255) default NULL,
-                   `severity` int(9) default 0,
-                   `timestamp` int(9) default 0,
-                   `url` varchar(255) default NULL,
-                   `user_id` int(9) default 0,
-                   PRIMARY KEY (`id`))
-                 ENGINE=InnoDB DEFAULT CHARSET=utf8;");
-
-      $db->query("CREATE TABLE {messages} (
-                   `id` int(9) NOT NULL auto_increment,
-                   `key` varchar(255) default NULL,
-                   `severity` varchar(32) default NULL,
-                   `value` varchar(255) default NULL,
-                   PRIMARY KEY (`id`),
-                   UNIQUE KEY(`key`))
-                 ENGINE=InnoDB DEFAULT CHARSET=utf8;");
-
-      $db->query("CREATE TABLE {modules} (
-                   `id` int(9) NOT NULL auto_increment,
-                   `active` BOOLEAN default 0,
-                   `name` varchar(64) default NULL,
-                   `version` int(9) default NULL,
-                   PRIMARY KEY (`id`),
-                   UNIQUE KEY(`name`))
-                 ENGINE=InnoDB DEFAULT CHARSET=utf8;");
-
-      $db->query("CREATE TABLE {themes} (
-                   `id` int(9) NOT NULL auto_increment,
-                   `name` varchar(64) default NULL,
-                   `version` int(9) default NULL,
-                   PRIMARY KEY (`id`),
-                   UNIQUE KEY(`name`))
-                 ENGINE=InnoDB DEFAULT CHARSET=utf8;");
-
-      $db->query("CREATE TABLE {permissions} (
-                   `id` int(9) NOT NULL auto_increment,
-                   `display_name` varchar(64) default NULL,
-                   `name` varchar(64) default NULL,
-                   PRIMARY KEY (`id`),
-                   UNIQUE KEY(`name`))
-                 ENGINE=InnoDB DEFAULT CHARSET=utf8;");
-
-      $db->query("CREATE TABLE {incoming_translations} (
-                   `id` int(9) NOT NULL auto_increment,
-                   `key` char(32) NOT NULL,
-                   `locale` char(10) NOT NULL,
-                   `message` text NOT NULL,
-                   `revision` int(9) DEFAULT NULL,
-                   `translation` text,
-                   PRIMARY KEY (`id`),
-                   UNIQUE KEY(`key`, `locale`),
-                   KEY `locale_key` (`locale`, `key`))
-                 ENGINE=InnoDB DEFAULT CHARSET=utf8;");
-
-      $db->query("CREATE TABLE {outgoing_translations} (
-                   `id` int(9) NOT NULL auto_increment,
-                   `base_revision` int(9) DEFAULT NULL,
-                   `key` char(32) NOT NULL,
-                   `locale` char(10) NOT NULL,
-                   `message` text NOT NULL,
-                   `translation` text,
-                   PRIMARY KEY (`id`),
-                   UNIQUE KEY(`key`, `locale`),
-                   KEY `locale_key` (`locale`, `key`))
-                 ENGINE=InnoDB DEFAULT CHARSET=utf8;");
-
-      $db->query("CREATE TABLE {sessions} (
-                  `session_id` varchar(127) NOT NULL,
-                  `data` text NOT NULL,
-                  `last_activity` int(10) UNSIGNED NOT NULL,
-                  PRIMARY KEY (`session_id`))
-                 ENGINE=InnoDB DEFAULT CHARSET=utf8;");
-
-      $db->query("CREATE TABLE {tasks} (
-                  `id` int(9) NOT NULL auto_increment,
-                  `callback` varchar(128) default NULL,
-                  `context` text NOT NULL,
-                  `done` boolean default 0,
-                  `name` varchar(128) default NULL,
-                  `owner_id` int(9) default NULL,
-                  `percent_complete` int(9) default 0,
-                  `state` varchar(32) default NULL,
-                  `status` varchar(255) default NULL,
-                  `updated` int(9) default NULL,
-                  PRIMARY KEY (`id`),
-                  KEY (`owner_id`))
-                 ENGINE=InnoDB DEFAULT CHARSET=utf8;");
-
-      $db->query("CREATE TABLE {vars} (
-                  `id` int(9) NOT NULL auto_increment,
-                  `module_name` varchar(64) NOT NULL,
-                  `name` varchar(64) NOT NULL,
-                  `value` text,
-                  PRIMARY KEY (`id`),
-                  UNIQUE KEY(`module_name`, `name`))
-                 ENGINE=InnoDB DEFAULT CHARSET=utf8;");
-
-      foreach (array("albums", "logs", "modules", "resizes", "thumbs", "tmp", "uploads") as $dir) {
-        @mkdir(VARPATH . $dir);
-      }
-
-      access::register_permission("view", "View");
-      access::register_permission("view_full", "View Full Size");
-      access::register_permission("edit", "Edit");
-      access::register_permission("add", "Add");
-
-      $root = ORM::factory("item");
-      $root->type = "album";
-      $root->title = "Gallery";
-      $root->description = "";
-      $root->left = 1;
-      $root->right = 2;
-      $root->parent_id = 0;
-      $root->level = 1;
-      $root->thumb_dirty = 1;
-      $root->resize_dirty = 1;
-      $root->sort_column = "weight";
-      $root->sort_order = "ASC";
-      $root->save();
-      access::add_item($root);
-
-      module::set_var("core", "active_site_theme", "default");
-      module::set_var("core", "active_admin_theme", "admin_default");
-      module::set_var("core", "page_size", 9);
-      module::set_var("core", "thumb_size", 200);
-      module::set_var("core", "resize_size", 640);
-      module::set_var("core", "default_locale", "en_US");
-      module::set_var("core", "image_quality", 75);
-
-      // Add rules for generating our thumbnails and resizes
-      graphics::add_rule(
-        "core", "thumb", "resize",
-        array("width" => 200, "height" => 200, "master" => Image::AUTO),
-        100);
-      graphics::add_rule(
-        "core", "resize", "resize",
-        array("width" => 640, "height" => 480, "master" => Image::AUTO),
-        100);
-
-      // Instantiate default themes (site and admin)
-      foreach (array("default", "admin_default") as $theme_name) {
-        $theme_info = new ArrayObject(parse_ini_file(THEMEPATH . $theme_name . "/theme.info"),
-                                      ArrayObject::ARRAY_AS_PROPS);
-        $theme = ORM::factory("theme");
-        $theme->name = $theme_name;
-        $theme->version = $theme_info->version;
-        $theme->save();
-      }
-
-      block_manager::add("dashboard_sidebar", "core", "block_adder");
-      block_manager::add("dashboard_sidebar", "core", "stats");
-      block_manager::add("dashboard_sidebar", "core", "platform_info");
-      block_manager::add("dashboard_sidebar", "core", "project_news");
-      block_manager::add("dashboard_center", "core", "welcome");
-      block_manager::add("dashboard_center", "core", "photo_stream");
-      block_manager::add("dashboard_center", "core", "log_entries");
-
-      module::set_version("core", 1);
-      module::set_var("core", "version", "3.0 pre-beta svn");
-      module::set_var("core", "choose_default_tookit", 1);
-    }
-  }
-
-  static function uninstall() {
-    $db = Database::instance();
-    $db->query("DROP TABLE IF EXISTS {access_caches}");
-    $db->query("DROP TABLE IF EXISTS {access_intents}");
-    $db->query("DROP TABLE IF EXISTS {graphics_rules}");
-    $db->query("DROP TABLE IF EXISTS {items}");
-    $db->query("DROP TABLE IF EXISTS {logs}");
-    $db->query("DROP TABLE IF EXISTS {messages}");
-    $db->query("DROP TABLE IF EXISTS {modules}");
-    $db->query("DROP TABLE IF EXISTS {themes}");
-    $db->query("DROP TABLE IF EXISTS {incoming_translations}");
-    $db->query("DROP TABLE IF EXISTS {outgoing_translations}");
-    $db->query("DROP TABLE IF EXISTS {permissions}");
-    $db->query("DROP TABLE IF EXISTS {sessions}");
-    $db->query("DROP TABLE IF EXISTS {tasks}");
-    $db->query("DROP TABLE IF EXISTS {vars}");
-    foreach (array("albums", "resizes", "thumbs", "uploads",
-                   "modules", "logs", "database.php") as $entry) {
-      system("/bin/rm -rf " . VARPATH . $entry);
-    }
-  }
-}
diff --git a/core/helpers/core_menu.php b/core/helpers/core_menu.php
deleted file mode 100644
index eb208560..00000000
--- a/core/helpers/core_menu.php
+++ /dev/null
@@ -1,162 +0,0 @@
-admin) {
-      $menu->append($scaffold_menu = Menu::factory("submenu")
-                    ->id("scaffold")
-                    ->label("Scaffold"));
-      $scaffold_menu->append(Menu::factory("link")
-                             ->id("scaffold_home")
-                             ->label("Dashboard")
-                             ->url(url::site("scaffold")));
-    }
-
-    $menu->append(Menu::factory("link")
-                  ->id("home")
-                  ->label(t("Home"))
-                  ->url(url::site("albums/1")));
-
-    $item = $theme->item();
-
-    if (user::active()->admin || ($item && access::can("edit", $item))) {
-      $menu->append($options_menu = Menu::factory("submenu")
-                    ->id("options_menu")
-                    ->label(t("Options")));
-
-      if ($item && access::can("edit", $item)) {
-        $options_menu
-          ->append(Menu::factory("dialog")
-                   ->id("edit_item")
-                   ->label($item->is_album() ? t("Edit album") : t("Edit photo"))
-                   ->url(url::site("form/edit/{$item->type}s/$item->id")));
-
-        // @todo Move album options menu to the album quick edit pane
-        // @todo Create resized item quick edit pane menu
-        if ($item->is_album()) {
-          $options_menu
-            ->append(Menu::factory("dialog")
-                     ->id("add_item")
-                     ->label(t("Add a photo"))
-                     ->url(url::site("simple_uploader/app/$item->id")))
-            ->append(Menu::factory("dialog")
-                     ->id("add_album")
-                     ->label(t("Add an album"))
-                     ->url(url::site("form/add/albums/$item->id?type=album")))
-            ->append(Menu::factory("dialog")
-                     ->id("edit_permissions")
-                     ->label(t("Edit permissions"))
-                     ->url(url::site("permissions/browse/$item->id")));
-        }
-      }
-    }
-
-    if (user::active()->admin) {
-      $menu->append($admin_menu = Menu::factory("submenu")
-                    ->id("admin_menu")
-                    ->label(t("Admin")));
-      self::admin($admin_menu, $theme);
-      foreach (module::active() as $module) {
-        if ($module->name == "core") {
-          continue;
-        }
-        $class = "{$module->name}_menu";
-        if (method_exists($class, "admin")) {
-          call_user_func_array(array($class, "admin"), array(&$admin_menu, $theme));
-        }
-      }
-    }
-  }
-
-  static function album($menu, $theme) {
-  }
-
-  static function photo($menu, $theme) {
-    if (access::can("view_full", $theme->item())) {
-      $menu
-        ->append(Menu::factory("link")
-               ->id("fullsize")
-               ->label(t("View full size"))
-               ->url("#")
-               ->css_class("gFullSizeLink"));
-    }
-    $menu
-      ->append(Menu::factory("link")
-               ->id("album")
-               ->label(t("Return to album"))
-               ->url($theme->item()->parent()->url("show={$theme->item->id}"))
-               ->css_id("gAlbumLink"));
-  }
-
-  static function admin($menu, $theme) {
-    $menu
-      ->append(Menu::factory("link")
-               ->id("dashboard")
-               ->label(t("Dashboard"))
-               ->url(url::site("admin")))
-      ->append(Menu::factory("submenu")
-               ->id("settings_menu")
-               ->label(t("Settings"))
-               ->append(Menu::factory("link")
-                        ->id("graphics_toolkits")
-                        ->label(t("Graphics"))
-                        ->url(url::site("admin/graphics")))
-               ->append(Menu::factory("link")
-                        ->id("languages")
-                        ->label(t("Languages"))
-                        ->url(url::site("admin/languages")))
-               ->append(Menu::factory("link")
-                        ->id("l10n_mode")
-                        ->label(Session::instance()->get("l10n_mode", false)
-                                ? t("Stop translating") : t("Start translating"))
-                        ->url(url::site("l10n_client/toggle_l10n_mode?csrf=" .
-                                        access::csrf_token())))
-               ->append(Menu::factory("link")
-                        ->id("advanced")
-                        ->label("Advanced")
-                        ->url(url::site("admin/advanced_settings"))))
-      ->append(Menu::factory("link")
-               ->id("modules")
-               ->label(t("Modules"))
-               ->url(url::site("admin/modules")))
-      ->append(Menu::factory("submenu")
-               ->id("content_menu")
-               ->label(t("Content")))
-      ->append(Menu::factory("submenu")
-               ->id("appearance_menu")
-               ->label(t("Appearance"))
-               ->append(Menu::factory("link")
-                        ->id("themes")
-                        ->label(t("Theme Choice"))
-                        ->url(url::site("admin/themes")))
-               ->append(Menu::factory("link")
-                        ->id("theme_details")
-                        ->label(t("Theme Options"))
-                        ->url(url::site("admin/theme_details"))))
-      ->append(Menu::factory("link")
-               ->id("maintenance")
-               ->label(t("Maintenance"))
-               ->url(url::site("admin/maintenance")))
-      ->append(Menu::factory("submenu")
-               ->id("statistics_menu")
-               ->label(t("Statistics"))
-               ->url("#"));
-  }
-}
diff --git a/core/helpers/core_search.php b/core/helpers/core_search.php
deleted file mode 100644
index 9957a493..00000000
--- a/core/helpers/core_search.php
+++ /dev/null
@@ -1,24 +0,0 @@
-description, $item->name, $item->title));
-  }
-}
diff --git a/core/helpers/core_task.php b/core/helpers/core_task.php
deleted file mode 100644
index e078192c..00000000
--- a/core/helpers/core_task.php
+++ /dev/null
@@ -1,166 +0,0 @@
-count();
-    $tasks = array();
-    $tasks[] = Task_Definition::factory()
-                 ->callback("core_task::rebuild_dirty_images")
-                 ->name(t("Rebuild Images"))
-                 ->description($dirty_count ?
-                               t2("You have one out of date photo",
-                                  "You have %count out of date photos",
-                                  $dirty_count)
-                               : t("All your photos are up to date"))
-      ->severity($dirty_count ? log::WARNING : log::SUCCESS);
-
-    $tasks[] = Task_Definition::factory()
-                 ->callback("core_task::update_l10n")
-                 ->name(t("Update translations"))
-                 ->description(t("Download new and updated translated strings"))
-      ->severity(log::SUCCESS);
-
-    return $tasks;
-  }
-
-  /**
-   * Task that rebuilds all dirty images.
-   * @param Task_Model the task
-   */
-  static function rebuild_dirty_images($task) {
-    $result = graphics::find_dirty_images_query();
-    $remaining = $result->count();
-    $completed = $task->get("completed", 0);
-
-    $i = 0;
-    foreach ($result as $row) {
-      $item = ORM::factory("item", $row->id);
-      if ($item->loaded) {
-        graphics::generate($item);
-      }
-
-      $completed++;
-      $remaining--;
-
-      if (++$i == 2) {
-        break;
-      }
-    }
-
-    $task->status = t2("Updated: 1 image. Total: %total_count.",
-                       "Updated: %count images. Total: %total_count.",
-                       $completed,
-                       array("total_count" => ($remaining + $completed)));
-
-    if ($completed + $remaining > 0) {
-      $task->percent_complete = (int)(100 * $completed / ($completed + $remaining));
-    } else {
-      $task->percent_complete = 100;
-    }
-
-    $task->set("completed", $completed);
-    if ($remaining == 0) {
-      $task->done = true;
-      $task->state = "success";
-      site_status::clear("graphics_dirty");
-    }
-  }
-
-  static function update_l10n(&$task) {
-    $start = microtime(true);
-    $dirs = $task->get("dirs");
-    $files = $task->get("files");
-    $cache = $task->get("cache", array());
-    $i = 0;
-
-    switch ($task->get("mode", "init")) {
-    case "init":  // 0%
-      $dirs = array("core", "modules", "themes", "installer");
-      $files = array();
-      $task->set("mode", "find_files");
-      $task->status = t("Finding files");
-      break;
-
-    case "find_files":  // 0% - 10%
-      while (($dir = array_pop($dirs)) && microtime(true) - $start < 0.5) {
-        if (basename($dir) == "tests") {
-          continue;
-        }
-
-        foreach (glob(DOCROOT . "$dir/*") as $path) {
-          $relative_path = str_replace(DOCROOT, "", $path);
-          if (is_dir($path)) {
-            $dirs[] = $relative_path;
-          } else {
-            $files[] = $relative_path;
-          }
-        }
-      }
-
-      $task->status = t2("Finding files: found 1 file",
-                         "Finding files: found %count files", count($files));
-
-      if (!$dirs) {
-        $task->set("mode", "scan_files");
-        $task->set("total_files", count($files));
-        $task->status = t("Scanning files");
-        $task->percent_complete = 10;
-      }
-      break;
-
-    case "scan_files": // 10% - 90%
-      while (($file = array_pop($files)) && microtime(true) - $start < 0.5) {
-        $file = DOCROOT . $file;
-        switch (pathinfo($file, PATHINFO_EXTENSION)) {
-        case "php":
-          l10n_scanner::scan_php_file($file, $cache);
-          break;
-
-        case "info":
-          l10n_scanner::scan_info_file($file, $cache);
-          break;
-        }
-      }
-
-      $total_files = $task->get("total_files");
-      $task->status = t2("Scanning files: scanned 1 file",
-                         "Scanning files: scanned %count files", $total_files - count($files));
-
-      $task->percent_complete = 10 + 80 * ($total_files - count($files)) / $total_files;
-      if (empty($files)) {
-        $task->set("mode", "fetch_updates");
-        $task->status = t("Fetching updates");
-        $task->percent_complete = 90;
-      }
-      break;
-
-    case "fetch_updates":  // 90% - 100%
-      l10n_client::fetch_updates();
-      $task->done = true;
-      $task->state = "success";
-      $task->status = t("Translations installed/updated");
-      $task->percent_complete = 100;
-    }
-
-    $task->set("files", $files);
-    $task->set("dirs", $dirs);
-    $task->set("cache", $cache);
-  }
-}
\ No newline at end of file
diff --git a/core/helpers/core_theme.php b/core/helpers/core_theme.php
deleted file mode 100644
index 28f544a1..00000000
--- a/core/helpers/core_theme.php
+++ /dev/null
@@ -1,137 +0,0 @@
-get("debug")) {
-      $buf .= "";
-    }
-    if (($theme->page_type == "album" || $theme->page_type == "photo")
-        && access::can("edit", $theme->item())) {
-      $buf .= "";
-      $buf .= html::script("core/js/quick.js");
-    }
-    if ($theme->page_type == "photo" && access::can("view_full", $theme->item())) {
-      $buf .= "";
-      $buf .= html::script("core/js/fullsize.js");
-    }
-
-    if ($session->get("l10n_mode", false)) {
-      $buf .= "";
-      $buf .= html::script("lib/jquery.cookie.js");
-      $buf .= html::script("core/js/l10n_client.js");
-    }
-
-    return $buf;
-  }
-
-  static function resize_top($theme, $item) {
-    if (access::can("edit", $item)) {
-      $edit_link = url::site("quick/pane/$item->id?page_type=photo");
-      return "
"; - } - } - - static function resize_bottom($theme, $item) { - if (access::can("edit", $item)) { - return "
"; - } - } - - static function thumb_top($theme, $child) { - if (access::can("edit", $child)) { - $edit_link = url::site("quick/pane/$child->id?page_type=album"); - return "
"; - } - } - - static function thumb_bottom($theme, $child) { - if (access::can("edit", $child)) { - return "
"; - } - } - - static function admin_head($theme) { - $session = Session::instance(); - $buf = ""; - if ($session->get("debug")) { - $buf .= ""; - } - - if ($session->get("l10n_mode", false)) { - $buf .= ""; - $buf .= html::script("lib/jquery.cookie.js"); - $buf .= html::script("core/js/l10n_client.js"); - } - - return $buf; - } - - static function page_bottom($theme) { - $session = Session::instance(); - if ($session->get("profiler", false)) { - $profiler = new Profiler(); - $profiler->render(); - } - if ($session->get("l10n_mode", false)) { - return L10n_Client_Controller::l10n_form(); - } - - if ($session->get("after_install")) { - $session->delete("after_install"); - return new View("after_install_loader.html"); - } - } - - static function admin_page_bottom($theme) { - $session = Session::instance(); - if ($session->get("profiler", false)) { - $profiler = new Profiler(); - $profiler->render(); - } - if ($session->get("l10n_mode", false)) { - return L10n_Client_Controller::l10n_form(); - } - } - - static function credits() { - return "
  • " . - t("Powered by Gallery %version", - array("url" => "http://gallery.menalto.com", - "version" => module::get_var("core", "version"))) . - "
  • "; - } - - static function admin_credits() { - return core_theme::credits(); - } -} \ No newline at end of file diff --git a/core/helpers/dir.php b/core/helpers/dir.php deleted file mode 100644 index 1717bdd9..00000000 --- a/core/helpers/dir.php +++ /dev/null @@ -1,40 +0,0 @@ -isDot()) { - unset($resource); - continue; - } else if ($resource->isFile()) { - unlink($resource->getPathName()); - } else if ($resource->isDir()) { - dir::unlink($resource->getRealPath()); - } - unset($resource); - } - return @rmdir($path); - } - return false; - } - - -} diff --git a/core/helpers/graphics.php b/core/helpers/graphics.php deleted file mode 100644 index 805a95c0..00000000 --- a/core/helpers/graphics.php +++ /dev/null @@ -1,387 +0,0 @@ - 200, "height" => 200, "master" => Image::AUTO), 100); - * - * Specifies that "core" is adding a rule to resize thumbnails down to a max of 200px on - * the longest side. The core module adds default rules at a priority of 100. You can set - * higher and lower priorities to perform operations before or after this fires. - * - * @param string $module_name the module that added the rule - * @param string $target the target for this operation ("thumb" or "resize") - * @param string $operation the name of the operation - * @param array $args arguments to the operation - * @param integer $priority the priority for this rule (lower priorities are run first) - */ - static function add_rule($module_name, $target, $operation, $args, $priority) { - $rule = ORM::factory("graphics_rule"); - $rule->module_name = $module_name; - $rule->target = $target; - $rule->operation = $operation; - $rule->priority = $priority; - $rule->args = serialize($args); - $rule->active = true; - $rule->save(); - - self::mark_dirty($target == "thumb", $target == "resize"); - } - - /** - * Remove any matching graphics rules - * @param string $module_name the module that added the rule - * @param string $target the target for this operation ("thumb" or "resize") - * @param string $operation the name of the operation - */ - static function remove_rule($module_name, $target, $operation) { - ORM::factory("graphics_rule") - ->where("module_name", $module_name) - ->where("target", $target) - ->where("operation", $operation) - ->delete_all(); - - self::mark_dirty($target == "thumb", $target == "resize"); - } - - /** - * Remove all rules for this module - * @param string $module_name - */ - static function remove_rules($module_name) { - $status = Database::instance()->delete("graphics_rules", array("module_name" => $module_name)); - if (count($status)) { - self::mark_dirty(true, true); - } - } - - /** - * Activate the rules for this module, typically done when the module itself is deactivated. - * Note that this does not mark images as dirty so that if you deactivate and reactivate a - * module it won't cause all of your images to suddenly require a rebuild. - */ - static function activate_rules($module_name) { - Database::instance() - ->update("graphics_rules",array("active" => true), array("module_name" => $module_name)); - } - - /** - * Deactivate the rules for this module, typically done when the module itself is deactivated. - * Note that this does not mark images as dirty so that if you deactivate and reactivate a - * module it won't cause all of your images to suddenly require a rebuild. - */ - static function deactivate_rules($module_name) { - Database::instance() - ->update("graphics_rules",array("active" => false), array("module_name" => $module_name)); - } - - /** - * Rebuild the thumb and resize for the given item. - * @param Item_Model $item - */ - static function generate($item) { - if ($item->is_album()) { - if (!$cover = $item->album_cover()) { - return; - } - $input_file = $cover->file_path(); - $input_item = $cover; - } else { - $input_file = $item->file_path(); - $input_item = $item; - } - - if ($item->thumb_dirty) { - $ops["thumb"] = $item->thumb_path(); - } - if ($item->resize_dirty && !$item->is_album() && !$item->is_movie()) { - $ops["resize"] = $item->resize_path(); - } - - if (empty($ops)) { - return; - } - - try { - foreach ($ops as $target => $output_file) { - if ($input_item->is_movie()) { - // Convert the movie to a JPG first - $output_file = preg_replace("/...$/", "jpg", $output_file); - movie::extract_frame($input_file, $output_file); - $working_file = $output_file; - } else { - $working_file = $input_file; - } - - foreach (ORM::factory("graphics_rule") - ->where("target", $target) - ->where("active", true) - ->orderby("priority", "asc") - ->find_all() as $rule) { - $args = array($working_file, $output_file, unserialize($rule->args)); - call_user_func_array(array("graphics", $rule->operation), $args); - $working_file = $output_file; - } - } - - if (!empty($ops["thumb"])) { - $dims = getimagesize($item->thumb_path()); - $item->thumb_width = $dims[0]; - $item->thumb_height = $dims[1]; - $item->thumb_dirty = 0; - } - - if (!empty($ops["resize"])) { - $dims = getimagesize($item->resize_path()); - $item->resize_width = $dims[0]; - $item->resize_height = $dims[1]; - $item->resize_dirty = 0; - } - $item->save(); - } catch (Kohana_Exception $e) { - // Something went wrong rebuilding the image. Leave it dirty and move on. - // @todo we should handle this better. - Kohana::log("error", "Caught exception rebuilding image: {$item->title}\n" . - $e->getTraceAsString()); - } - } - - /** - * Resize an image. Valid options are width, height and master. Master is one of the Image - * master dimension constants. - * - * @param string $input_file - * @param string $output_file - * @param array $options - */ - static function resize($input_file, $output_file, $options) { - if (!self::$init) { - self::init_toolkit(); - } - - if (filesize($input_file) == 0) { - throw new Exception("@todo MALFORMED_INPUT_FILE"); - } - - $dims = getimagesize($input_file); - if (max($dims[0], $dims[1]) < min($options["width"], $options["height"])) { - // Image would get upscaled; do nothing - copy($input_file, $output_file); - } else { - Image::factory($input_file) - ->resize($options["width"], $options["height"], $options["master"]) - ->quality(module::get_var("core", "image_quality")) - ->save($output_file); - } - } - - /** - * Rotate an image. Valid options are degrees - * - * @param string $input_file - * @param string $output_file - * @param array $options - */ - static function rotate($input_file, $output_file, $options) { - if (!self::$init) { - self::init_toolkit(); - } - - Image::factory($input_file) - ->quality(module::get_var("core", "image_quality")) - ->rotate($options["degrees"]) - ->save($output_file); - } - - /** - * Overlay an image on top of the input file. - * - * Valid options are: file, mime_type, position, transparency_percent, padding - * - * Valid positions: northwest, north, northeast, - * west, center, east, - * southwest, south, southeast - * - * padding is in pixels - * - * @param string $input_file - * @param string $output_file - * @param array $options - */ - static function composite($input_file, $output_file, $options) { - if (!self::$init) { - self::init_toolkit(); - } - - list ($width, $height) = getimagesize($input_file); - list ($w_width, $w_height) = getimagesize($options["file"]); - - $pad = isset($options["padding"]) ? $options["padding"] : 10; - $top = $pad; - $left = $pad; - $y_center = max($height / 2 - $w_height / 2, $pad); - $x_center = max($width / 2 - $w_width / 2, $pad); - $bottom = max($height - $w_height - $pad, $pad); - $right = max($width - $w_width - $pad, $pad); - - switch ($options["position"]) { - case "northwest": $x = $left; $y = $top; break; - case "north": $x = $x_center; $y = $top; break; - case "northeast": $x = $right; $y = $top; break; - case "west": $x = $left; $y = $y_center; break; - case "center": $x = $x_center; $y = $y_center; break; - case "east": $x = $right; $y = $y_center; break; - case "southwest": $x = $left; $y = $bottom; break; - case "south": $x = $x_center; $y = $bottom; break; - case "southeast": $x = $right; $y = $bottom; break; - } - - Image::factory($input_file) - ->composite($options["file"], $x, $y, $options["transparency"]) - ->quality(module::get_var("core", "image_quality")) - ->save($output_file); - } - - /** - * Return a query result that locates all items with dirty images. - * @return Database_Result Query result - */ - static function find_dirty_images_query() { - return Database::instance()->query( - "SELECT `id` FROM {items} " . - "WHERE ((`thumb_dirty` = 1 AND (`type` <> 'album' OR `album_cover_item_id` IS NOT NULL))" . - " OR (`resize_dirty` = 1 AND `type` = 'photo')) " . - " AND `id` != 1"); - } - - /** - * Mark thumbnails and resizes as dirty. They will have to be rebuilt. - */ - static function mark_dirty($thumbs, $resizes) { - if ($thumbs || $resizes) { - $db = Database::instance(); - $fields = array(); - if ($thumbs) { - $fields["thumb_dirty"] = 1; - } - if ($resizes) { - $fields["resize_dirty"] = 1; - } - $db->update("items", $fields, true); - } - - $count = self::find_dirty_images_query()->count(); - if ($count) { - site_status::warning( - t2("One of your photos is out of date. Click here to fix it", - "%count of your photos are out of date. Click here to fix them", - $count, - array("attrs" => sprintf( - 'href="%s" class="gDialogLink"', - url::site("admin/maintenance/start/core_task::rebuild_dirty_images?csrf=__CSRF__")))), - "graphics_dirty"); - } - } - - /** - * Detect which graphics toolkits are available on this system. Return an array of key value - * pairs where the key is one of gd, imagemagick, graphicsmagick and the value is information - * about that toolkit. For GD we return the version string, and for ImageMagick and - * GraphicsMagick we return the path to the directory containing the appropriate binaries. - */ - static function detect_toolkits() { - $gd = function_exists("gd_info") ? gd_info() : array(); - $exec = function_exists("exec"); - if (!isset($gd["GD Version"])) { - $gd["GD Version"] = false; - } - return array("gd" => $gd, - "imagemagick" => $exec ? dirname(exec("which convert")) : false, - "graphicsmagick" => $exec ? dirname(exec("which gm")) : false); - } - - /** - * This needs to be run once, after the initial install, to choose a graphics toolkit. - */ - static function choose_default_toolkit() { - // Detect a graphics toolkit - $toolkits = graphics::detect_toolkits(); - foreach (array("imagemagick", "graphicsmagick", "gd") as $tk) { - if ($toolkits[$tk]) { - module::set_var("core", "graphics_toolkit", $tk); - module::set_var("core", "graphics_toolkit_path", $tk == "gd" ? "" : $toolkits[$tk]); - break; - } - } - if (!module::get_var("core", "graphics_toolkit")) { - site_status::warning( - t("Graphics toolkit missing! Please choose a toolkit", - array("url" => url::site("admin/graphics"))), - "missing_graphics_toolkit"); - } - } - - /** - * Choose which driver the Kohana Image library uses. - */ - static function init_toolkit() { - switch(module::get_var("core", "graphics_toolkit")) { - case "gd": - Kohana::config_set("image.driver", "GD"); - break; - - case "imagemagick": - Kohana::config_set("image.driver", "ImageMagick"); - Kohana::config_set( - "image.params.directory", module::get_var("core", "graphics_toolkit_path")); - break; - - case "graphicsmagick": - Kohana::config_set("image.driver", "GraphicsMagick"); - Kohana::config_set( - "image.params.directory", module::get_var("core", "graphics_toolkit_path")); - break; - } - - self::$init = 1; - } - - /** - * Verify that a specific graphics function is available with the active toolkit. - * @param string $func (eg rotate, resize) - * @return boolean - */ - static function can($func) { - if (module::get_var("core", "graphics_toolkit") == "gd" && - $func == "rotate" && - !function_exists("imagerotate")) { - return false; - } - - return true; - } -} diff --git a/core/helpers/item.php b/core/helpers/item.php deleted file mode 100644 index 7daaf1e1..00000000 --- a/core/helpers/item.php +++ /dev/null @@ -1,105 +0,0 @@ -parent(); - if ($parent->album_cover_item_id == $source->id) { - if ($parent->children_count() > 1) { - foreach ($parent->children(2) as $child) { - if ($child->id != $source->id) { - $new_cover_item = $child; - break; - } - } - item::make_album_cover($new_cover_item); - } else { - item::remove_album_cover($parent); - } - } - - $source->move_to($target); - - // If the target has no cover item, make this it. - if ($target->album_cover_item_id == null) { - item::make_album_cover($source); - } - } - - static function make_album_cover($item) { - $parent = $item->parent(); - access::required("edit", $parent); - - model_cache::clear("item", $parent->album_cover_item_id); - $parent->album_cover_item_id = $item->is_album() ? $item->album_cover_item_id : $item->id; - $parent->thumb_dirty = 1; - $parent->save(); - graphics::generate($parent); - $grand_parent = $parent->parent(); - if ($grand_parent && $grand_parent->album_cover_item_id == null) { - item::make_album_cover($parent); - } - } - - static function remove_album_cover($album) { - access::required("edit", $album); - @unlink($album->thumb_path()); - - model_cache::clear("item", $album->album_cover_item_id) ; - $album->album_cover_item_id = null; - $album->thumb_width = 0; - $album->thumb_height = 0; - $album->thumb_dirty = 1; - $album->save(); - graphics::generate($album); - } - - static function validate_no_slashes($input) { - if (strpos($input->value, "/") !== false) { - $input->add_error("no_slashes", 1); - } - } - - static function validate_no_trailing_period($input) { - if (rtrim($input->value, ".") !== $input->value) { - $input->add_error("no_trailing_period", 1); - } - } - - static function validate_no_name_conflict($input) { - $itemid = Input::instance()->post("item"); - if (is_array($itemid)) { - $itemid = $itemid[0]; - } - $item = ORM::factory("item") - ->in("id", $itemid) - ->find(); - if (Database::instance() - ->from("items") - ->where("parent_id", $item->parent_id) - ->where("id <>", $item->id) - ->where("name", $input->value) - ->count_records()) { - $input->add_error("conflict", 1); - } - } -} \ No newline at end of file diff --git a/core/helpers/l10n_client.php b/core/helpers/l10n_client.php deleted file mode 100644 index ec4c5429..00000000 --- a/core/helpers/l10n_client.php +++ /dev/null @@ -1,203 +0,0 @@ - $version, - "client_token" => self::client_token(), - "signature" => $signature, - "uid" => self::server_uid($api_key))); - if (!remote::success($response_status)) { - return false; - } - return true; - } - - static function fetch_updates() { - $request->locales = array(); - $request->messages = new stdClass(); - - $locales = locale::installed(); - foreach ($locales as $locale => $locale_data) { - $request->locales[] = $locale; - } - - // @todo Batch requests (max request size) - foreach (Database::instance() - ->select("key", "locale", "revision", "translation") - ->from("incoming_translations") - ->get() - ->as_array() as $row) { - if (!isset($request->messages->{$row->key})) { - $request->messages->{$row->key} = 1; - } - if (!empty($row->revision) && !empty($row->translation)) { - if (!is_object($request->messages->{$row->key})) { - $request->messages->{$row->key} = new stdClass(); - } - $request->messages->{$row->key}->{$row->locale} = $row->revision; - } - } - // @todo Include messages from outgoing_translations? - - $request_data = json_encode($request); - $url = self::_server_url() . "?q=translations/fetch"; - list ($response_data, $response_status) = remote::post($url, array("data" => $request_data)); - if (!remote::success($response_status)) { - throw new Exception("@todo TRANSLATIONS_FETCH_REQUEST_FAILED " . $response_status); - } - if (empty($response_data)) { - log::info("translations", "Translations fetch request resulted in an empty response"); - return; - } - - $response = json_decode($response_data); - - // Response format (JSON payload): - // [{key:, translation: , rev:, locale:}, - // {key:, ...} - // ] - $count = count($response); - log::info("translations", "Installed $count new / updated translation messages"); - - foreach ($response as $message_data) { - // @todo Better input validation - if (empty($message_data->key) || empty($message_data->translation) || - empty($message_data->locale) || empty($message_data->rev)) { - throw new Exception("@todo TRANSLATIONS_FETCH_REQUEST_FAILED: Invalid response data"); - } - $key = $message_data->key; - $locale = $message_data->locale; - $revision = $message_data->rev; - $translation = serialize(json_decode($message_data->translation)); - - // @todo Should we normalize the incoming_translations table into messages(id, key, message) - // and incoming_translations(id, translation, locale, revision)? Or just allow - // incoming_translations.message to be NULL? - $locale = $message_data->locale; - $entry = ORM::factory("incoming_translation") - ->where(array("key" => $key, "locale" => $locale)) - ->find(); - if (!$entry->loaded) { - // @todo Load a message key -> message (text) dict into memory outside of this loop - $root_entry = ORM::factory("incoming_translation") - ->where(array("key" => $key, "locale" => "root")) - ->find(); - $entry->key = $key; - $entry->message = $root_entry->message; - $entry->locale = $locale; - } - $entry->revision = $revision; - $entry->translation = $translation; - $entry->save(); - } - } - - static function submit_translations() { - // Request format (HTTP POST): - // client_token = - // uid = - // signature = md5(user_api_key($uid, $client_token) . $data . $client_token)) - // data = // JSON payload - // - // {: {message: - // translations: {: , - // : ...}}, - // : {...} - // } - - // @todo Batch requests (max request size) - // @todo include base_revision in submission / how to handle resubmissions / edit fights? - foreach (Database::instance() - ->select("key", "message", "locale", "base_revision", "translation") - ->from("outgoing_translations") - ->get() as $row) { - $key = $row->key; - if (!isset($request->{$key})) { - $request->{$key}->message = json_encode(unserialize($row->message)); - } - $request->{$key}->translations->{$row->locale} = json_encode(unserialize($row->translation)); - } - - // @todo reduce memory consumpotion, e.g. free $request - $request_data = json_encode($request); - $url = self::_server_url() . "?q=translations/submit"; - $signature = self::_sign($request_data); - - list ($response_data, $response_status) = remote::post( - $url, array("data" => $request_data, - "client_token" => self::client_token(), - "signature" => $signature, - "uid" => self::server_uid())); - - if (!remote::success($response_status)) { - throw new Exception("@todo TRANSLATIONS_SUBMISSION_FAILED " . $response_status); - } - if (empty($response_data)) { - return; - } - - $response = json_decode($response_data); - // Response format (JSON payload): - // [{key:, locale:, rev:, status:}, - // {key:, ...} - // ] - - // @todo Move messages out of outgoing into incoming, using new rev? - // @todo show which messages have been rejected / are pending? - } -} \ No newline at end of file diff --git a/core/helpers/l10n_scanner.php b/core/helpers/l10n_scanner.php deleted file mode 100644 index 80b6f01c..00000000 --- a/core/helpers/l10n_scanner.php +++ /dev/null @@ -1,154 +0,0 @@ -select("key") - ->from("incoming_translations") - ->where("locale", "root") - ->get() as $row) { - $cache[$row->key] = true; - } - } - - $key = I18n::get_message_key($message); - if (array_key_exists($key, $cache)) { - return $cache[$key]; - } - - $entry = ORM::factory("incoming_translation", array("key" => $key)); - if (!$entry->loaded) { - $entry->key = $key; - $entry->message = serialize($message); - $entry->locale = "root"; - $entry->save(); - } - } - - static function scan_php_file($file, &$cache) { - $code = file_get_contents($file); - $raw_tokens = token_get_all($code); - unset($code); - - $tokens = array(); - $func_token_list = array("t" => array(), "t2" => array()); - $token_number = 0; - // Filter out HTML / whitespace, and build a lookup for global function calls. - foreach ($raw_tokens as $token) { - if ((!is_array($token)) || (($token[0] != T_WHITESPACE) && ($token[0] != T_INLINE_HTML))) { - if (is_array($token)) { - if ($token[0] == T_STRING && in_array($token[1], array("t", "t2"))) { - $func_token_list[$token[1]][] = $token_number; - } - } - $tokens[] = $token; - $token_number++; - } - } - unset($raw_tokens); - - if (!empty($func_token_list["t"])) { - l10n_scanner::_parse_t_calls($tokens, $func_token_list["t"], $cache); - } - if (!empty($func_token_list["t2"])) { - l10n_scanner::_parse_plural_calls($tokens, $func_token_list["t2"], $cache); - } - } - - static function scan_info_file($file, &$cache) { - $code = file_get_contents($file); - if (preg_match("#name\s*?=\s*(.*?)\ndescription\s*?=\s*(.*)\n#", $code, $matches)) { - unset($matches[0]); - foreach ($matches as $string) { - l10n_scanner::process_message($string, $cache); - } - } - } - - private static function _parse_t_calls(&$tokens, &$call_list, &$cache) { - foreach ($call_list as $index) { - $function_name = $tokens[$index++]; - $parens = $tokens[$index++]; - $first_param = $tokens[$index++]; - $next_token = $tokens[$index]; - - if ($parens == "(") { - if (in_array($next_token, array(")", ",")) - && (is_array($first_param) && ($first_param[0] == T_CONSTANT_ENCAPSED_STRING))) { - $message = self::_escape_quoted_string($first_param[1]); - l10n_scanner::process_message($message, $cache); - } else { - // t() found, but inside is something which is not a string literal. - // @todo Call status callback with error filename/line. - } - } - } - } - - private static function _parse_plural_calls(&$tokens, &$call_list, &$cache) { - foreach ($call_list as $index) { - $function_name = $tokens[$index++]; - $parens = $tokens[$index++]; - $first_param = $tokens[$index++]; - $first_separator = $tokens[$index++]; - $second_param = $tokens[$index++]; - $next_token = $tokens[$index]; - - if ($parens == "(") { - if ($first_separator == "," && $next_token == "," - && is_array($first_param) && $first_param[0] == T_CONSTANT_ENCAPSED_STRING - && is_array($second_param) && $second_param[0] == T_CONSTANT_ENCAPSED_STRING) { - $singular = self::_escape_quoted_string($first_param[1]); - $plural = self::_escape_quoted_string($first_param[1]); - l10n_scanner::process_message(array("one" => $singular, "other" => $plural), $cache); - } else { - // t2() found, but inside is something which is not a string literal. - // @todo Call status callback with error filename/line. - } - } - } - } - - /** - * Escape quotes in a strings depending on the surrounding - * quote type used. - * - * @param $str The strings to escape - */ - private static function _escape_quoted_string($str) { - $quo = substr($str, 0, 1); - $str = substr($str, 1, -1); - if ($quo == '"') { - $str = stripcslashes($str); - } else { - $str = strtr($str, array("\\'" => "'", "\\\\" => "\\")); - } - return addcslashes($str, "\0..\37\\\""); - } -} diff --git a/core/helpers/locale.php b/core/helpers/locale.php deleted file mode 100644 index b707637f..00000000 --- a/core/helpers/locale.php +++ /dev/null @@ -1,119 +0,0 @@ -$code)) { - $installed[$code] = $available[$code]; - } - } - return $installed; - } - - static function update_installed($locales) { - // Ensure that the default is included... - $default = module::get_var("core", "default_locale"); - $locales = array_merge($locales, array($default)); - - module::set_var("core", "installed_locales", join("|", $locales)); - } - - // @todo Might want to add a localizable language name as well. - private static function _init_language_data() { - $l["af_ZA"] = "Afrikaans"; // Afrikaans - $l["ar_SA"] = "العربية"; // Arabic - $l["bg_BG"] = "Български"; // Bulgarian - $l["ca_ES"] = "Catalan"; // Catalan - $l["cs_CZ"] = "Česky"; // Czech - $l["da_DK"] = "Dansk"; // Danish - $l["de_DE"] = "Deutsch"; // German - $l["el_GR"] = "Greek"; // Greek - $l["en_GB"] = "English (UK)"; // English (UK) - $l["en_US"] = "English (US)"; // English (US) - $l["es_AR"] = "Español (AR)"; // Spanish (AR) - $l["es_ES"] = "Español"; // Spanish (ES) - $l["es_MX"] = "Español (MX)"; // Spanish (MX) - $l["et_EE"] = "Eesti"; // Estonian - $l["eu_ES"] = "Euskara"; // Basque - $l["fa_IR"] = "فارسي"; // Farsi - $l["fi_FI"] = "Suomi"; // Finnish - $l["fr_FR"] = "Français"; // French - $l["ga_IE"] = "Gaeilge"; // Irish - $l["he_IL"] = "עברית"; // Hebrew - $l["hu_HU"] = "Magyar"; // Hungarian - $l["is_IS"] = "Icelandic"; // Icelandic - $l["it_IT"] = "Italiano"; // Italian - $l["ja_JP"] = "日本語"; // Japanese - $l["ko_KR"] = "한국말"; // Korean - $l["lt_LT"] = "Lietuvių"; // Lithuanian - $l["lv_LV"] = "Latviešu"; // Latvian - $l["nl_NL"] = "Nederlands"; // Dutch - $l["no_NO"] = "Norsk bokmål"; // Norwegian - $l["pl_PL"] = "Polski"; // Polish - $l["pt_BR"] = "Português Brasileiro"; // Portuguese (BR) - $l["pt_PT"] = "Português"; // Portuguese (PT) - $l["ro_RO"] = "Română"; // Romanian - $l["ru_RU"] = "Русский"; // Russian - $l["sk_SK"] = "Slovenčina"; // Slovak - $l["sl_SI"] = "Slovenščina"; // Slovenian - $l["sr_CS"] = "Srpski"; // Serbian - $l["sv_SE"] = "Svenska"; // Swedish - $l["tr_TR"] = "Türkçe"; // Turkish - $l["uk_UA"] = "Українська"; // Ukrainian - $l["vi_VN"] = "Tiếng Việt"; // Vietnamese - $l["zh_CN"] = "简体中文"; // Chinese (CN) - $l["zh_TW"] = "繁體中文"; // Chinese (TW) - asort($l, SORT_LOCALE_STRING); - self::$locales = $l; - } - - static function display_name($locale=null) { - if (empty(self::$locales)) { - self::_init_language_data(); - } - $locale or $locale = I18n::instance()->locale(); - - return self::$locales["$locale"]; - } - - static function is_rtl($locale) { - return in_array($locale, array("he_IL", "fa_IR", "ar_SA")); - } -} \ No newline at end of file diff --git a/core/helpers/log.php b/core/helpers/log.php deleted file mode 100644 index 451f985a..00000000 --- a/core/helpers/log.php +++ /dev/null @@ -1,108 +0,0 @@ -category = $category; - $log->message = $message; - $log->severity = $severity; - $log->html = $html; - $log->url = substr(url::abs_current(true), 0, 255); - $log->referer = request::referrer(null); - $log->timestamp = time(); - $log->user_id = user::active()->id; - $log->save(); - } - - - /** - * Convert a message severity to a CSS class - * @param integer $severity - * @return string - */ - static function severity_class($severity) { - switch($severity) { - case self::SUCCESS: - return "gSuccess"; - - case self::INFO: - return "gInfo"; - - case self::WARNING: - return "gWarning"; - - case self::ERROR: - return "gError"; - } - } -} diff --git a/core/helpers/message.php b/core/helpers/message.php deleted file mode 100644 index af3b96cc..00000000 --- a/core/helpers/message.php +++ /dev/null @@ -1,108 +0,0 @@ -get("messages"); - $status[] = array($msg, $severity); - $session->set("messages", $status); - } - - /** - * Get any pending messages. There are two types of messages, transient and permanent. - * Permanent messages are used to let the admin know that there are pending administrative - * issues that need to be resolved. Transient ones are only displayed once. - * @return html text - */ - static function get() { - $buf = array(); - - $messages = Session::instance()->get_once("messages", array()); - foreach ($messages as $msg) { - $buf[] = "
  • $msg[0]
  • "; - } - if ($buf) { - return "
      " . implode("", $buf) . "
    "; - } - } - - /** - * Convert a message severity to a CSS class - * @param integer $severity - * @return string - */ - static function severity_class($severity) { - switch($severity) { - case self::SUCCESS: - return "gSuccess"; - - case self::INFO: - return "gInfo"; - - case self::WARNING: - return "gWarning"; - - case self::ERROR: - return "gError"; - } - } -} diff --git a/core/helpers/model_cache.php b/core/helpers/model_cache.php deleted file mode 100644 index 2649fdbd..00000000 --- a/core/helpers/model_cache.php +++ /dev/null @@ -1,46 +0,0 @@ -$model_name->$field_name->$id)) { - $model = ORM::factory($model_name)->where($field_name, $id)->find(); - if (!$model->loaded) { - throw new Exception("@todo MISSING_MODEL $model_name:$id"); - } - self::$cache->$model_name->$field_name->$id = $model; - } - - return self::$cache->$model_name->$field_name->$id; - } - - static function clear($model_name, $id, $field_name="id") { - if (!empty(self::$cache->$model_name->$field_name->$id)) { - unset(self::$cache->$model_name->$field_name->$id); - } - } - - static function set($model) { - self::$cache->{$model->object_name} - ->{$model->primary_key} - ->{$model->{$model->primary_key}} = $model; - } -} diff --git a/core/helpers/module.php b/core/helpers/module.php deleted file mode 100644 index a48c89ed..00000000 --- a/core/helpers/module.php +++ /dev/null @@ -1,357 +0,0 @@ -loaded) { - $module->name = $module_name; - $module->active = $module_name == "core"; // only core is active by default - } - $module->version = 1; - $module->save(); - Kohana::log("debug", "$module_name: version is now $version"); - } - - /** - * Load the corresponding Module_Model - * @param string $module_name - */ - static function get($module_name) { - // @todo can't easily use model_cache here because it throw an exception on missing models. - return ORM::factory("module", array("name" => $module_name)); - } - - /** - * Check to see if a module is installed - * @param string $module_name - */ - static function is_installed($module_name) { - return array_key_exists($module_name, self::$modules); - } - - /** - * Check to see if a module is active - * @param string $module_name - */ - static function is_active($module_name) { - return array_key_exists($module_name, self::$modules) && - self::$modules[$module_name]->active; - } - - /** - * Return the list of available modules, including uninstalled modules. - */ - static function available() { - $modules = new ArrayObject(array(), ArrayObject::ARRAY_AS_PROPS); - foreach (array_merge(array("core/module.info"), glob(MODPATH . "*/module.info")) as $file) { - $module_name = basename(dirname($file)); - $modules->$module_name = new ArrayObject(parse_ini_file($file), ArrayObject::ARRAY_AS_PROPS); - $modules->$module_name->installed = self::is_installed($module_name); - $modules->$module_name->active = self::is_active($module_name); - $modules->$module_name->version = self::get_version($module_name); - $modules->$module_name->locked = false; - } - - // Lock certain modules - $modules->core->locked = true; - $modules->user->locked = true; - $modules->ksort(); - - return $modules; - } - - /** - * Return a list of all the active modules in no particular order. - */ - static function active() { - return self::$active; - } - - /** - * Install a module. This will call _installer::install(), which is responsible for - * creating database tables, setting module variables and and calling module::set_version(). - * Note that after installing, the module must be activated before it is available for use. - * @param string $module_name - */ - static function install($module_name) { - $kohana_modules = Kohana::config("core.modules"); - $kohana_modules[] = MODPATH . $module_name; - Kohana::config_set("core.modules", $kohana_modules); - - $installer_class = "{$module_name}_installer"; - if (method_exists($installer_class, "install")) { - call_user_func_array(array($installer_class, "install"), array()); - } - - // Now the module is installed but inactive, so don't leave it in the active path - array_pop($kohana_modules); - Kohana::config_set("core.modules", $kohana_modules); - - log::success( - "module", t("Installed module %module_name", array("module_name" => $module_name))); - } - - /** - * Activate an installed module. This will call _installer::activate() which should take - * any steps to make sure that the module is ready for use. This will also activate any - * existing graphics rules for this module. - * @param string $module_name - */ - static function activate($module_name) { - $kohana_modules = Kohana::config("core.modules"); - $kohana_modules[] = MODPATH . $module_name; - Kohana::config_set("core.modules", $kohana_modules); - - $installer_class = "{$module_name}_installer"; - if (method_exists($installer_class, "activate")) { - call_user_func_array(array($installer_class, "activate"), array()); - } - - $module = self::get($module_name); - if ($module->loaded) { - $module->active = true; - $module->save(); - } - - self::load_modules(); - graphics::activate_rules($module_name); - log::success( - "module", t("Activated module %module_name", array("module_name" => $module_name))); - } - - /** - * Deactivate an installed module. This will call _installer::deactivate() which - * should take any cleanup steps to make sure that the module isn't visible in any way. - * @param string $module_name - */ - static function deactivate($module_name) { - $installer_class = "{$module_name}_installer"; - if (method_exists($installer_class, "deactivate")) { - call_user_func_array(array($installer_class, "deactivate"), array()); - } - - $module = self::get($module_name); - if ($module->loaded) { - $module->active = false; - $module->save(); - } - - self::load_modules(); - graphics::deactivate_rules($module_name); - log::success( - "module", t("Deactivated module %module_name", array("module_name" => $module_name))); - } - - /** - * Uninstall a deactivated module. This will call _installer::uninstall() which should - * take whatever steps necessary to make sure that all traces of a module are gone. - * @param string $module_name - */ - static function uninstall($module_name) { - $installer_class = "{$module_name}_installer"; - if (method_exists($installer_class, "uninstall")) { - call_user_func(array($installer_class, "uninstall")); - } - - graphics::remove_rule($module_name); - $module = self::get($module_name); - if ($module->loaded) { - $module->delete(); - } - - // We could delete the module vars here too, but it's nice to leave them around - // in case the module gets reinstalled. - - self::load_modules(); - log::success( - "module", t("Uninstalled module %module_name", array("module_name" => $module_name))); - } - - /** - * Load the active modules. This is called at bootstrap time. - */ - static function load_modules() { - // Reload module list from the config file since we'll do a refresh after calling install() - $core = Kohana::config_load("core"); - $kohana_modules = $core["modules"]; - $modules = ORM::factory("module")->find_all(); - - self::$modules = array(); - self::$active = array(); - foreach ($modules as $module) { - self::$modules[$module->name] = $module; - if ($module->active) { - self::$active[] = $module; - } - if ($module->name != "core") { - $kohana_modules[] = MODPATH . $module->name; - } - } - Kohana::config_set("core.modules", $kohana_modules); - } - - /** - * Run a specific event on all active modules. - * @param string $name the event name - * @param mixed $data data to pass to each event handler - */ - static function event($name, &$data=null) { - $args = func_get_args(); - array_shift($args); - $function = str_replace(".", "_", $name); - - foreach (self::$modules as $module) { - if (!$module->active) { - continue; - } - - $class = "{$module->name}_event"; - if (method_exists($class, $function)) { - call_user_func_array(array($class, $function), $args); - } - } - } - - /** - * Get a variable from this module - * @param string $module_name - * @param string $name - * @param string $default_value - * @return the value - */ - static function get_var($module_name, $name, $default_value=null) { - // We cache all vars in core._cache so that we can load all vars at once for - // performance. - if (empty(self::$var_cache)) { - $row = Database::instance() - ->select("value") - ->from("vars") - ->where(array("module_name" => "core", "name" => "_cache")) - ->get() - ->current(); - if ($row) { - self::$var_cache = unserialize($row->value); - } else { - // core._cache doesn't exist. Create it now. - foreach (Database::instance() - ->select("module_name", "name", "value") - ->from("vars") - ->orderby("module_name", "name") - ->get() as $row) { - if ($row->module_name == "core" && $row->name == "_cache") { - // This could happen if there's a race condition - continue; - } - self::$var_cache->{$row->module_name}->{$row->name} = $row->value; - } - $cache = ORM::factory("var"); - $cache->module_name = "core"; - $cache->name = "_cache"; - $cache->value = serialize(self::$var_cache); - $cache->save(); - } - } - - if (isset(self::$var_cache->$module_name->$name)) { - return self::$var_cache->$module_name->$name; - } else { - return $default_value; - } - } - - /** - * Store a variable for this module - * @param string $module_name - * @param string $name - * @param string $value - */ - static function set_var($module_name, $name, $value) { - $var = ORM::factory("var") - ->where("module_name", $module_name) - ->where("name", $name) - ->find(); - if (!$var->loaded) { - $var->module_name = $module_name; - $var->name = $name; - } - $var->value = $value; - $var->save(); - - Database::instance()->delete("vars", array("module_name" => "core", "name" => "_cache")); - self::$var_cache = null; - } - - /** - * Increment the value of a variable for this module - * @param string $module_name - * @param string $name - * @param string $increment (optional, default is 1) - */ - static function incr_var($module_name, $name, $increment=1) { - Database::instance()->query( - "UPDATE {vars} SET `value` = `value` + $increment " . - "WHERE `module_name` = '$module_name' " . - "AND `name` = '$name'"); - - Database::instance()->delete("vars", array("module_name" => "core", "name" => "_cache")); - self::$var_cache = null; - } - - /** - * Remove a variable for this module. - * @param string $module_name - * @param string $name - */ - static function clear_var($module_name, $name) { - $var = ORM::factory("var") - ->where("module_name", $module_name) - ->where("name", $name) - ->find(); - if ($var->loaded) { - $var->delete(); - } - - Database::instance()->delete("vars", array("module_name" => "core", "name" => "_cache")); - self::$var_cache = null; - } - - /** - * Return the version of the installed module. - * @param string $module_name - */ - static function get_version($module_name) { - return self::get($module_name)->version; - } -} diff --git a/core/helpers/movie.php b/core/helpers/movie.php deleted file mode 100644 index 3293d4ac..00000000 --- a/core/helpers/movie.php +++ /dev/null @@ -1,153 +0,0 @@ -loaded || !$parent->is_album()) { - throw new Exception("@todo INVALID_PARENT"); - } - - if (!is_file($filename)) { - throw new Exception("@todo MISSING_MOVIE_FILE"); - } - - if (strpos($name, "/")) { - throw new Exception("@todo NAME_CANNOT_CONTAIN_SLASH"); - } - - // We don't allow trailing periods as a security measure - // ref: http://dev.kohanaphp.com/issues/684 - if (rtrim($name, ".") != $name) { - throw new Exception("@todo NAME_CANNOT_END_IN_PERIOD"); - } - - $movie_info = movie::getmoviesize($filename); - - // Force an extension onto the name - $pi = pathinfo($filename); - if (empty($pi["extension"])) { - $pi["extension"] = image_type_to_extension($movie_info[2], false); - $name .= "." . $pi["extension"]; - } - - $movie = ORM::factory("item"); - $movie->type = "movie"; - $movie->title = $title; - $movie->description = $description; - $movie->name = $name; - $movie->owner_id = $owner_id ? $owner_id : user::active(); - $movie->width = $movie_info[0]; - $movie->height = $movie_info[1]; - $movie->mime_type = strtolower($pi["extension"]) == "mp4" ? "video/mp4" : "video/x-flv"; - $movie->thumb_dirty = 1; - $movie->resize_dirty = 1; - $movie->sort_column = "weight"; - $movie->rand_key = ((float)mt_rand()) / (float)mt_getrandmax(); - - // Randomize the name if there's a conflict - while (ORM::Factory("item") - ->where("parent_id", $parent->id) - ->where("name", $movie->name) - ->find()->id) { - // @todo Improve this. Random numbers are not user friendly - $movie->name = rand() . "." . $pi["extension"]; - } - - // This saves the photo - $movie->add_to_parent($parent); - - // If the thumb or resize already exists then rename it - if (file_exists($movie->resize_path()) || - file_exists($movie->thumb_path())) { - $movie->name = $pi["filename"] . "-" . rand() . "." . $pi["extension"]; - $movie->save(); - } - - copy($filename, $movie->file_path()); - - module::event("item_created", $movie); - - // Build our thumbnail - graphics::generate($movie); - - // If the parent has no cover item, make this it. - if (access::can("edit", $parent) && $parent->album_cover_item_id == null) { - item::make_album_cover($movie); - } - - return $movie; - } - - static function getmoviesize($filename) { - $ffmpeg = self::find_ffmpeg(); - if (empty($ffmpeg)) { - throw new Exception("@todo MISSING_FFMPEG"); - } - - $cmd = escapeshellcmd($ffmpeg) . " -i " . escapeshellarg($filename) . " 2>&1"; - $result = `$cmd`; - if (preg_match("/Stream.*?Video:.*?(\d+)x(\d+).*\ +([0-9\.]+) (fps|tb).*/", - $result, $regs)) { - list ($width, $height) = array($regs[1], $regs[2]); - } else { - list ($width, $height) = array(0, 0); - } - return array($width, $height); - } - - static function extract_frame($input_file, $output_file) { - $ffmpeg = self::find_ffmpeg(); - if (empty($ffmpeg)) { - throw new Exception("@todo MISSING_FFMPEG"); - } - - $cmd = escapeshellcmd($ffmpeg) . " -i " . escapeshellarg($input_file) . - " -an -ss 00:00:03 -an -r 1 -vframes 1" . - " -y -f mjpeg " . escapeshellarg($output_file); - exec($cmd); - } - - static function find_ffmpeg() { - if (!$ffmpeg_path = module::get_var("core", "ffmpeg_path")) { - if (function_exists("exec")) { - $ffmpeg_path = exec("which ffmpeg"); - if ($ffmpeg_path) { - module::set_var("core", "ffmpeg_path", $ffmpeg_path); - } - } - } - return $ffmpeg_path; - } -} diff --git a/core/helpers/photo.php b/core/helpers/photo.php deleted file mode 100644 index c1c005f5..00000000 --- a/core/helpers/photo.php +++ /dev/null @@ -1,171 +0,0 @@ -loaded || !$parent->is_album()) { - throw new Exception("@todo INVALID_PARENT"); - } - - if (!is_file($filename)) { - throw new Exception("@todo MISSING_IMAGE_FILE"); - } - - if (strpos($name, "/")) { - throw new Exception("@todo NAME_CANNOT_CONTAIN_SLASH"); - } - - // We don't allow trailing periods as a security measure - // ref: http://dev.kohanaphp.com/issues/684 - if (rtrim($name, ".") != $name) { - throw new Exception("@todo NAME_CANNOT_END_IN_PERIOD"); - } - - $image_info = getimagesize($filename); - - // Force an extension onto the name - $pi = pathinfo($filename); - if (empty($pi["extension"])) { - $pi["extension"] = image_type_to_extension($image_info[2], false); - $name .= "." . $pi["extension"]; - } - - $photo = ORM::factory("item"); - $photo->type = "photo"; - $photo->title = $title; - $photo->description = $description; - $photo->name = $name; - $photo->owner_id = $owner_id ? $owner_id : user::active(); - $photo->width = $image_info[0]; - $photo->height = $image_info[1]; - $photo->mime_type = empty($image_info['mime']) ? "application/unknown" : $image_info['mime']; - $photo->thumb_dirty = 1; - $photo->resize_dirty = 1; - $photo->sort_column = "weight"; - $photo->rand_key = ((float)mt_rand()) / (float)mt_getrandmax(); - - // Randomize the name if there's a conflict - while (ORM::Factory("item") - ->where("parent_id", $parent->id) - ->where("name", $photo->name) - ->find()->id) { - // @todo Improve this. Random numbers are not user friendly - $photo->name = rand() . "." . $pi["extension"]; - } - - // This saves the photo - $photo->add_to_parent($parent); - - /* - * If the thumb or resize already exists then rename it. We need to do this after the save - * because the resize_path and thumb_path both call relative_path which caches the - * path. Before add_to_parent the relative path will be incorrect. - */ - if (file_exists($photo->resize_path()) || - file_exists($photo->thumb_path())) { - $photo->name = $pi["filename"] . "-" . rand() . "." . $pi["extension"]; - $photo->save(); - } - - copy($filename, $photo->file_path()); - - module::event("item_created", $photo); - - // Build our thumbnail/resizes - graphics::generate($photo); - - // If the parent has no cover item, make this it. - if (access::can("edit", $parent) && $parent->album_cover_item_id == null) { - item::make_album_cover($photo); - } - - return $photo; - } - - static function get_add_form($parent) { - $form = new Forge("albums/{$parent->id}", "", "post", array("id" => "gAddPhotoForm")); - $group = $form->group("add_photo")->label( - t("Add Photo to %album_title", array("album_title" =>$parent->title))); - $group->input("title")->label(t("Title")); - $group->textarea("description")->label(t("Description")); - $group->input("name")->label(t("Filename")); - $group->upload("file")->label(t("File"))->rules("required|allow[jpg,png,gif,flv,mp4]"); - $group->hidden("type")->value("photo"); - $group->submit("")->value(t("Upload")); - $form->add_rules_from(ORM::factory("item")); - return $form; - } - - static function get_edit_form($photo) { - $form = new Forge("photos/$photo->id", "", "post", array("id" => "gEditPhotoForm")); - $form->hidden("_method")->value("put"); - $group = $form->group("edit_photo")->label(t("Edit Photo")); - $group->input("title")->label(t("Title"))->value($photo->title); - $group->textarea("description")->label(t("Description"))->value($photo->description); - $group->input("filename")->label(t("Filename"))->value($photo->name) - ->error_messages("conflict", t("There is already a file with this name")) - ->callback("item::validate_no_slashes") - ->error_messages("no_slashes", t("The photo name can't contain a \"/\"")) - ->callback("item::validate_no_trailing_period") - ->error_messages("no_trailing_period", t("The photo name can't end in \".\"")); - - $group->submit("")->value(t("Modify")); - $form->add_rules_from(ORM::factory("item")); - return $form; - } - - /** - * Return scaled width and height. - * - * @param integer $width - * @param integer $height - * @param integer $max the target size for the largest dimension - * @param string $format the output format using %d placeholders for width and height - */ - static function img_dimensions($width, $height, $max, $format="width=\"%d\" height=\"%d\"") { - if (!$width || !$height) { - return ""; - } - - if ($width > $height) { - $new_width = $max; - $new_height = (int)$max * ($height / $width); - } else { - $new_height = $max; - $new_width = (int)$max * ($width / $height); - } - return sprintf($format, $new_width, $new_height); - } -} diff --git a/core/helpers/rest.php b/core/helpers/rest.php deleted file mode 100644 index a63b94c8..00000000 --- a/core/helpers/rest.php +++ /dev/null @@ -1,116 +0,0 @@ -post("_method", $input->get("_method", request::method())))) { - case "put": return "put"; - case "delete": return "delete"; - default: return "post"; - } - } - } - - /** - * Choose an output format based on what the client prefers to accept. - * @return string "html", "xml" or "json" - */ - static function output_format() { - // Pick a format, but let it be overridden. - $input = Input::instance(); - $fmt = $input->get( - "_format", $input->post( - "_format", request::preferred_accept( - array("xhtml", "html", "xml", "json")))); - - // Some browsers (Chrome!) prefer xhtml over html, but we'll normalize this to html for now. - if ($fmt == "xhtml") { - $fmt = "html"; - } - return $fmt; - } - - /** - * Set HTTP response code. - * @param string Use one of the status code constants defined in this class. - */ - static function http_status($status_code) { - header("HTTP/1.1 " . $status_code); - } - - /** - * Set HTTP Location header. - * @param string URL - */ - static function http_location($url) { - header("Location: " . $url); - } - - /** - * Set HTTP Content-Type header. - * @param string content type - */ - static function http_content_type($type) { - header("Content-Type: " . $type); - } -} diff --git a/core/helpers/site_status.php b/core/helpers/site_status.php deleted file mode 100644 index 6d47e565..00000000 --- a/core/helpers/site_status.php +++ /dev/null @@ -1,132 +0,0 @@ -where("key", $permanent_key) - ->find(); - if (!$message->loaded) { - $message->key = $permanent_key; - } - $message->severity = $severity; - $message->value = $msg; - $message->save(); - } - - /** - * Remove any permanent message by key. - * @param string $permanent_key - */ - static function clear($permanent_key) { - $message = ORM::factory("message")->where("key", $permanent_key)->find(); - if ($message->loaded) { - $message->delete(); - } - } - - /** - * Get any pending messages. There are two types of messages, transient and permanent. - * Permanent messages are used to let the admin know that there are pending administrative - * issues that need to be resolved. Transient ones are only displayed once. - * @return html text - */ - static function get() { - if (!user::active()->admin) { - return; - } - $buf = array(); - foreach (ORM::factory("message")->find_all() as $msg) { - $value = str_replace('__CSRF__', access::csrf_token(), $msg->value); - $buf[] = "
  • severity) . "\">$value
  • "; - } - - if ($buf) { - return "
      " . implode("", $buf) . "
    "; - } - } - - /** - * Convert a message severity to a CSS class - * @param integer $severity - * @return string - */ - static function severity_class($severity) { - switch($severity) { - case self::SUCCESS: - return "gSuccess"; - - case self::INFO: - return "gInfo"; - - case self::WARNING: - return "gWarning"; - - case self::ERROR: - return "gError"; - } - } -} diff --git a/core/helpers/task.php b/core/helpers/task.php deleted file mode 100644 index a8a004ab..00000000 --- a/core/helpers/task.php +++ /dev/null @@ -1,83 +0,0 @@ -name}_task"; - if (method_exists($class_name, "available_tasks")) { - foreach (call_user_func(array($class_name, "available_tasks")) as $task) { - $tasks[$task->callback] = $task; - } - } - } - - return $tasks; - } - - static function create($task_def, $context) { - $task = ORM::factory("task"); - $task->callback = $task_def->callback; - $task->name = $task_def->name; - $task->percent_complete = 0; - $task->status = ""; - $task->state = "started"; - $task->owner_id = user::active()->id; - $task->context = serialize($context); - $task->save(); - - return $task; - } - - static function cancel($task_id) { - $task = ORM::factory("task", $task_id); - if (!$task->loaded) { - throw new Exception("@todo MISSING_TASK"); - } - $task->done = 1; - $task->state = "cancelled"; - $task->save(); - - return $task; - } - - static function remove($task_id) { - $task = ORM::factory("task", $task_id); - if ($task->loaded) { - $task->delete(); - } - } - - static function run($task_id) { - $task = ORM::factory("task", $task_id); - if (!$task->loaded) { - throw new Exception("@todo MISSING_TASK"); - } - - $task->state = "running"; - call_user_func_array($task->callback, array(&$task)); - $task->save(); - - return $task; - } -} \ No newline at end of file diff --git a/core/helpers/theme.php b/core/helpers/theme.php deleted file mode 100644 index cbe224db..00000000 --- a/core/helpers/theme.php +++ /dev/null @@ -1,61 +0,0 @@ -"gThemeDetailsForm")); - $group = $form->group("edit_theme"); - $group->input("page_size")->label(t("Items per page"))->id("gPageSize") - ->rules("required|valid_digit") - ->value(module::get_var("core", "page_size")); - $group->input("thumb_size")->label(t("Thumbnail size (in pixels)"))->id("gThumbSize") - ->rules("required|valid_digit") - ->value(module::get_var("core", "thumb_size")); - $group->input("resize_size")->label(t("Resized image size (in pixels)"))->id("gResizeSize") - ->rules("required|valid_digit") - ->value(module::get_var("core", "resize_size")); - $group->textarea("header_text")->label(t("Header text"))->id("gHeaderText") - ->value(module::get_var("core", "header_text")); - $group->textarea("footer_text")->label(t("Footer text"))->id("gFooterText") - ->value(module::get_var("core", "footer_text")); - $group->submit("")->value(t("Save")); - return $form; - } -} - diff --git a/core/helpers/xml.php b/core/helpers/xml.php deleted file mode 100644 index e734e90c..00000000 --- a/core/helpers/xml.php +++ /dev/null @@ -1,35 +0,0 @@ -\n"; - foreach ($array as $key => $value) { - if (is_array($value)) { - $xml .= xml::to_xml($value, array_slice($element_names, 1)); - } else if (is_object($value)) { - $xml .= xml::to_xml($value->as_array(), array_slice($element_names, 1)); - } else { - $xml .= "<$key>$value\n"; - } - } - $xml .= "\n"; - return $xml; - } -} diff --git a/core/hooks/init_gallery.php b/core/hooks/init_gallery.php deleted file mode 100644 index 2c36795a..00000000 --- a/core/hooks/init_gallery.php +++ /dev/null @@ -1,44 +0,0 @@ -post("g3sid", $input->get("g3sid"))) { - $_COOKIE["g3sid"] = $g3sid; -} - -if ($user_agent = $input->post("user_agent", $input->get("user_agent"))) { - Kohana::$user_agent = $user_agent; -} diff --git a/core/images/gallery.png b/core/images/gallery.png deleted file mode 100644 index ca8e0e95..00000000 Binary files a/core/images/gallery.png and /dev/null differ diff --git a/core/images/gd.png b/core/images/gd.png deleted file mode 100644 index b341d71c..00000000 Binary files a/core/images/gd.png and /dev/null differ diff --git a/core/images/graphicsmagick.png b/core/images/graphicsmagick.png deleted file mode 100644 index 3d1d77e9..00000000 Binary files a/core/images/graphicsmagick.png and /dev/null differ diff --git a/core/images/imagemagick.jpg b/core/images/imagemagick.jpg deleted file mode 100644 index d83c4509..00000000 Binary files a/core/images/imagemagick.jpg and /dev/null differ diff --git a/core/js/albums_form_add.js b/core/js/albums_form_add.js deleted file mode 100644 index 06a364f3..00000000 --- a/core/js/albums_form_add.js +++ /dev/null @@ -1,12 +0,0 @@ -$("#gAddAlbumForm input[name=title]").change( - function() { - $("#gAddAlbumForm input[name=name]").attr( - "value", $("#gAddAlbumForm input[name=title]").attr("value"). - replace(/\s+/g, "_").replace(/\.+$/, "")); - }); -$("#gAddAlbumForm input[name=title]").keyup( - function() { - $("#gAddAlbumForm input[name=name]").attr( - "value", $("#gAddAlbumForm input[name=title]").attr("value"). - replace(/\s+/g, "_").replace(/\.+$/, "")); - }); diff --git a/core/js/fullsize.js b/core/js/fullsize.js deleted file mode 100644 index 7428adb5..00000000 --- a/core/js/fullsize.js +++ /dev/null @@ -1,78 +0,0 @@ -/** - * @todo Move inline CSS out to external style sheet (theme style sheet) - */ -$(document).ready(function() { - $(".gFullSizeLink").click(function() { - var width = $(document).width(); - var height = $(document).height(); - - $("body").append('
    '); - - var image_size = _auto_fit(fullsize_detail.width, fullsize_detail.height); - - $("body").append('
    ' + - '
    '); - - $("#gFullsize").append(''); - $("#gFullsizeClose").click(function() { - $("#gFullsizeOverlay*").remove(); - $("#gFullsize").remove(); - }); - $(window).resize(function() { - $("#gFullsizeOverlay").width($(document).width()); - $("#gFullsizeOverlay").height($(document).height()); - image_size = _auto_fit(fullsize_detail.width, fullsize_detail.height); - $("#gFullsize").height(image_size.height); - $("#gFullsize").width(image_size.width); - $("#gFullsize").css("top", image_size.top); - $("#gFullsize").css("left", image_size.left); - $("#gFullSizeImage").height(image_size.height); - $("#gFullSizeImage").width(image_size.width); - }); - }); -}); - -/* - * Calculate the size of the image panel based on the size of the image and the size of the - * window. Scale the image so the entire panel fits in the view port. - */ -function _auto_fit(imageWidth, imageHeight) { - // ui-dialog gives a padding of 2 pixels - var windowWidth = $(window).width() - 10; - var windowHeight = $(window).height() - 10; - - /* If the width is greater then scale the image width first */ - if (imageWidth > windowWidth) { - var ratio = windowWidth / imageWidth; - imageWidth *= ratio; - imageHeight *= ratio; - } - /* after scaling the width, check that the height fits */ - if (imageHeight > windowHeight) { - var ratio = windowHeight / imageHeight; - imageWidth *= ratio; - imageHeight *= ratio; - } - - // handle the case where the calculation is almost zero (2.14e-14) - return { - top: ((windowHeight - imageHeight) / 2).toFixed(2), - left: ((windowWidth - imageWidth) / 2).toFixed(2), - width: imageWidth.toFixed(2), - height: imageHeight.toFixed(2) - }; -} diff --git a/core/js/l10n_client.js b/core/js/l10n_client.js deleted file mode 100644 index f43671f1..00000000 --- a/core/js/l10n_client.js +++ /dev/null @@ -1,195 +0,0 @@ -// Fork from Drupal's l10n_client module, originally written by: -// G‡bor Hojtsy http://drupal.org/user/4166 (original author) -// Young Hahn / Development Seed - http://developmentseed.org/ (friendly user interface) - -var Gallery = Gallery || { 'behaviors': {} }; - -Gallery.attachBehaviors = function(context) { - context = context || document; - // Execute all of them. - jQuery.each(Gallery.behaviors, - function() { - this(context); - }); -}; - -$(document).ready(function() { - Gallery.attachBehaviors(this); -}); - - -// Store all l10n_client related data + methods in its own object -jQuery.extend(Gallery, { - l10nClient: new (function() { - // Set "selected" string to unselected, i.e. -1 - this.selected = -1; - // Keybindings - this.keys = {'toggle':'ctrl+shift+s', 'clear': 'esc'}; // Keybindings - // Keybinding functions - this.key = function(pressed) { - switch(pressed) { - case 'toggle': - // Grab user-hilighted text & send it into the search filter - userSelection = window.getSelection ? window.getSelection() : document.getSelection ? document.getSelection() : document.selection.createRange().text; - userSelection = String(userSelection); - if(userSelection.length > 0) { - Gallery.l10nClient.filter(userSelection); - Gallery.l10nClient.toggle(1); - $('#l10n-client #gL10nSearch').focus(); - } else { - if($('#l10n-client').is('.hidden')) { - Gallery.l10nClient.toggle(1); - if(!$.browser.safari) { - $('#l10n-client #gL10nSearch').focus(); - } - } else { - Gallery.l10nClient.toggle(0); - } - } - break; - case 'clear': - this.filter(false); - break; - } - } - // Toggle the l10nclient - this.toggle = function(state) { - switch(state) { - case 1: - $('#l10n-client-string-select, #l10n-client-string-editor, #l10n-client .labels .label').show(); - $('#l10n-client').height('22em').removeClass('hidden'); - $('#l10n-client .labels .toggle').text('X'); - /* - * This CSS clashes with Gallery's CSS, probably due to - * YUI's grid / floats. - if(!$.browser.msie) { - $('body').css('border-bottom', '22em solid #fff'); - } - */ - $.cookie('Gallery_l10n_client', '1', {expires: 7, path: '/'}); - break; - case 0: - $('#l10n-client-string-select, #l10n-client-string-editor, #l10n-client .labels .label').hide(); - $('#l10n-client').height('2em').addClass('hidden'); - // TODO: Localize this message - $('#l10n-client .labels .toggle').text('Translate Text'); - /* - if(!$.browser.msie) { - $('body').css('border-bottom', '0px'); - } - */ - $.cookie('Gallery_l10n_client', '0', {expires: 7, path: '/'}); - break; - } - } - // Get a string from the DOM tree - this.getString = function(index, type) { - return l10n_client_data[index][type]; - } - // Set a string in the DOM tree - this.setString = function(index, data) { - l10n_client_data[index]['translation'] = data; - } - // Filter the the string list by a search string - this.filter = function(search) { - if(search == false || search == '') { - $('#l10n-client #l10n-search-filter-clear').focus(); - $('#l10n-client-string-select li').show(); - $('#l10n-client #gL10nSearch').val(''); - $('#l10n-client #gL10nSearch').focus(); - } else { - if(search.length > 0) { - $('#l10n-client-string-select li').hide(); - $('#l10n-client-string-select li:contains('+search+')').show(); - $('#l10n-client #gL10nSearch').val(search); - } - } - } - }) -}); - -// Attaches the localization editor behavior to all required fields. -Gallery.behaviors.l10nClient = function(context) { - - switch($.cookie('Gallery_l10n_client')) { - case '1': - Gallery.l10nClient.toggle(1); - break; - default: - Gallery.l10nClient.toggle(0); - break; - } - - // If the selection changes, copy string values to the source and target fields. - // Add class to indicate selected string in list widget. - $('#l10n-client-string-select li').click(function() { - $('#l10n-client-string-select li').removeClass('active'); - $(this).addClass('active'); - var index = $('#l10n-client-string-select li').index(this); - - $('#l10n-client-string-editor .source-text').text(Gallery.l10nClient.getString(index, 'source')); - $("#gL10nClientSaveForm input[name='l10n-message-source']").val(Gallery.l10nClient.getString(index, 'source')); - $('#gL10nClientSaveForm #l10n-edit-target').val(Gallery.l10nClient.getString(index, 'translation')); - - Gallery.l10nClient.selected = index; - }); - - // When l10n_client window is clicked, toggle based on current state. - $('#l10n-client .labels .toggle').click(function() { - if($('#l10n-client').is('.hidden')) { - Gallery.l10nClient.toggle(1); - } else { - Gallery.l10nClient.toggle(0); - } - }); - - // Register keybindings using jQuery hotkeys - // TODO: Either remove hotkeys code or add query.hotkeys.js. - if($.hotkeys) { - $.hotkeys.add(Gallery.l10nClient.keys['toggle'], function(){Gallery.l10nClient.key('toggle')}); - $.hotkeys.add(Gallery.l10nClient.keys['clear'], {target:'#l10n-client #gL10nSearch', type:'keyup'}, function(){Gallery.l10nClient.key('clear')}); - } - - // Custom listener for l10n_client livesearch - $('#l10n-client #gL10nSearch').keyup(function(key) { - Gallery.l10nClient.filter($('#l10n-client #gL10nSearch').val()); - }); - - // Clear search - $('#l10n-client #l10n-search-filter-clear').click(function() { - Gallery.l10nClient.filter(false); - return false; - }); - - // Send AJAX POST data on form submit. - $('#gL10nClientSaveForm').ajaxForm({ - dataType: "json", - success: function(data) { - // Store string in local js - Gallery.l10nClient.setString(Gallery.l10nClient.selected, $('#gL10nClientSaveForm #l10n-edit-target').val()); - - // Mark string as translated. - $('#l10n-client-string-select li').eq(Gallery.l10nClient.selected).removeClass('untranslated').removeClass('active').addClass('translated').text($('#gL10nClientSaveForm #l10n-edit-target').val()); - - // Empty input fields. - $('#l10n-client-string-editor .source-text').html(''); - $('#gL10nClientSaveForm #l10n-edit-target').val(''); - $("#gL10nClientSaveForm input[name='l10n-message-source']").val(''); - }, - error: function(xmlhttp) { - // TODO: Localize this message - alert('An HTTP error @status occured (or empty response).'.replace('@status', xmlhttp.status)); - } - }); - - - // Copy source text to translation field on button click. - $('#gL10nClientSaveForm #l10n-edit-copy').click(function() { - $('#gL10nClientSaveForm #l10n-edit-target').val($('#l10n-client-string-editor .source-text').text()); - }); - - // Clear translation field on button click. - $('#gL10nClientSaveForm #l10n-edit-clear').click(function() { - $('#gL10nClientSaveForm #l10n-edit-target').val(''); - }); -}; diff --git a/core/js/quick.js b/core/js/quick.js deleted file mode 100644 index e7f35cea..00000000 --- a/core/js/quick.js +++ /dev/null @@ -1,95 +0,0 @@ -$(document).ready(function() { - if ($("#gAlbumGrid").length) { - // @todo Add quick edit pane for album (meta, move, permissions, delete) - $(".gItem").hover(show_quick, function() {}); - } - if ($("#gPhoto").length) { - $("#gPhoto").hover(show_quick, function() {}); - } -}); - -var show_quick = function() { - var cont = $(this); - var quick = $(this).find(".gQuick"); - $("#gQuickPane").remove(); - cont.append("
    "); - var img = cont.find(".gThumbnail,.gResize"); - var pos = cont.position(); - $("#gQuickPane").css({ - "position": "absolute", - "top": pos.top, - "left": pos.left, - "text-align": "center", - "width": cont.innerWidth() + 1, - "height": "auto" - }).hide(); - cont.hover(function() {}, hide_quick); - $.get( - quick.attr("href"), - {}, - function(data, textStatus) { - $("#gQuickPane").html(data).slideDown("fast"); - $(".ui-state-default").hover( - function(){ - $(this).addClass("ui-state-hover"); - }, - function(){ - $(this).removeClass("ui-state-hover"); - } - ); - $("#gQuickPane a:not(.options)").click(function(e) { - e.preventDefault(); - if ($(this).attr("id") == "gQuickDelete" && - !confirm($(this).attr("ref"))) { - return; - } - quick_do(cont, $(this), img); - }); - $("#gQuickPane a.options").click(function(e) { - e.preventDefault(); - $("#gQuickPaneOptions").slideToggle("fast"); - }); - } - ); -}; - -var quick_do = function(cont, pane, img) { - if (pane.hasClass("ui-state-disabled")) { - return false; - } - if (pane.hasClass("gDialogLink")) { - openDialog(pane, function() { window.location.reload(); }); - } else { - img.css("opacity", "0.1"); - cont.addClass("gLoadingLarge"); - $.ajax({ - type: "GET", - url: pane.attr("href"), - dataType: "json", - success: function(data) { - img.css("opacity", "1"); - cont.removeClass("gLoadingLarge"); - if (data.src) { - img.attr("width", data.width); - img.attr("height", data.height); - img.attr("src", data.src); - if (data.height > data.width) { - img.css("margin-top", -32); - } else { - img.css("margin-top", 0); - } - } else if (data.location) { - window.location = data.location; - } else if (data.reload) { - window.location.reload(); - } - } - }); - } - return false; -}; - -var hide_quick = function() { - $("#gQuickPane").remove(); -}; - diff --git a/core/libraries/Admin_View.php b/core/libraries/Admin_View.php deleted file mode 100644 index acc3f8ec..00000000 --- a/core/libraries/Admin_View.php +++ /dev/null @@ -1,126 +0,0 @@ -theme_name = module::get_var("core", "active_admin_theme"); - if (user::active()->admin) { - $this->theme_name = Input::instance()->get("theme", $this->theme_name); - } - $this->sidebar = ""; - $this->set_global("theme", $this); - $this->set_global("user", user::active()); - } - - public function url($path, $absolute_url=false) { - $arg = "themes/{$this->theme_name}/$path"; - return $absolute_url ? url::abs_file($arg) : url::file($arg); - } - - public function display($page_name, $view_class="View") { - return new $view_class($page_name); - } - - public function admin_menu() { - $menu = Menu::factory("root"); - core_menu::admin($menu, $this); - - foreach (module::active() as $module) { - if ($module->name == "core") { - continue; - } - $class = "{$module->name}_menu"; - if (method_exists($class, "admin")) { - call_user_func_array(array($class, "admin"), array(&$menu, $this)); - } - } - - print $menu; - } - - /** - * Print out any site wide status information. - */ - public function site_status() { - return site_status::get(); - } - - /** - * Print out any messages waiting for this user. - */ - public function messages() { - return message::get(); - } - - /** - * Handle all theme functions that insert module content. - */ - public function __call($function, $args) { - switch ($function) { - case "admin_credits"; - case "admin_footer": - case "admin_header_top": - case "admin_header_bottom": - case "admin_page_bottom": - case "admin_page_top": - case "admin_head": - $blocks = array(); - foreach (module::active() as $module) { - $helper_class = "{$module->name}_theme"; - if (method_exists($helper_class, $function)) { - $blocks[] = call_user_func_array( - array($helper_class, $function), - array_merge(array($this), $args)); - } - } - - if (Session::instance()->get("debug")) { - if ($function != "admin_head") { - array_unshift( - $blocks, "
    " . - "
    $function
    "); - $blocks[] = "
    "; - } - } - - return implode("\n", $blocks); - - default: - throw new Exception("@todo UNKNOWN_THEME_FUNCTION: $function"); - } - } -} \ No newline at end of file diff --git a/core/libraries/Block.php b/core/libraries/Block.php deleted file mode 100644 index 6fe679f1..00000000 --- a/core/libraries/Block.php +++ /dev/null @@ -1,30 +0,0 @@ -__toString(); - } -} diff --git a/core/libraries/I18n.php b/core/libraries/I18n.php deleted file mode 100644 index c936be88..00000000 --- a/core/libraries/I18n.php +++ /dev/null @@ -1,410 +0,0 @@ -translate($message, $options); -} - -/** - * Translates a localizable message with plural forms. - * @param $singular String The message to be translated. E.g. "There is one album." - * @param $plural String The plural message to be translated. E.g. - * "There are %count albums." - * @param $count Number The number which is inserted for the %count placeholder and - * which is used to select the proper plural form ($singular or $plural). - * @param $options array (optional) Options array for key value pairs which are used - * for pluralization and interpolation. Special key: "locale" to override the - * currently configured locale. - * @return String The translated message string. - */ -function t2($singular, $plural, $count, $options=array()) { - return I18n::instance()->translate(array("one" => $singular, "other" => $plural), - array_merge($options, array("count" => $count))); -} - -class I18n_Core { - private static $_instance; - private $_config = array(); - private $_call_log = array(); - private $_cache = array(); - - private function __construct($config) { - $this->_config = $config; - $this->locale($config['default_locale']); - } - - public static function instance($config=null) { - if (self::$_instance == NULL || isset($config)) { - $config = isset($config) ? $config : Kohana::config('locale'); - if (empty($config['default_locale'])) { - $config['default_locale'] = module::get_var('core', 'default_locale'); - } - self::$_instance = new I18n_Core($config); - } - - return self::$_instance; - } - - public function locale($locale=null) { - if ($locale) { - $this->_config['default_locale'] = $locale; - // Attempt to set PHP's locale as well (for number formatting, collation, etc.) - // TODO: See G2 for better fallack code. - $locale_prefs = array($locale); - $locale_prefs[] = 'en_US'; - setlocale(LC_ALL, $locale_prefs); - } - return $this->_config['default_locale']; - } - - /** - * Translates a localizable message. - * @param $message String|array The message to be translated. E.g. "Hello world" - * or array("one" => "One album", "other" => "%count albums") - * @param $options array (optional) Options array for key value pairs which are used - * for pluralization and interpolation. Special keys are "count" and "locale", - * the latter to override the currently configured locale. - * @return String The translated message string. - */ - public function translate($message, $options=array()) { - $locale = empty($options['locale']) ? $this->_config['default_locale'] : $options['locale']; - $count = isset($options['count']) ? $options['count'] : null; - $values = $options; - unset($values['locale']); - $this->log($message, $options); - - $entry = $this->lookup($locale, $message); - - if (null === $entry) { - // Default to the root locale. - $entry = $message; - $locale = $this->_config['root_locale']; - } - - $entry = $this->pluralize($locale, $entry, $count); - - $entry = $this->interpolate($locale, $entry, $values); - - return $entry; - } - - private function lookup($locale, $message) { - if (!isset($this->_cache[$locale])) { - $this->_cache[$locale] = array(); - // TODO: Load data from locale file instead of the DB. - foreach (Database::instance() - ->select("key", "translation") - ->from("incoming_translations") - ->where(array("locale" => $locale)) - ->get() - ->as_array() as $row) { - $this->_cache[$locale][$row->key] = unserialize($row->translation); - } - - // Override incoming with outgoing... - foreach (Database::instance() - ->select("key", "translation") - ->from("outgoing_translations") - ->where(array("locale" => $locale)) - ->get() - ->as_array() as $row) { - $this->_cache[$locale][$row->key] = unserialize($row->translation); - } - } - - $key = self::get_message_key($message); - - if (isset($this->_cache[$locale][$key])) { - return $this->_cache[$locale][$key]; - } else { - return null; - } - } - - public function has_translation($message, $options=null) { - $locale = empty($options['locale']) ? $this->_config['default_locale'] : $options['locale']; - $count = empty($options['count']) ? null : $options['count']; - $values = $options; - unset($values['locale']); - $this->log($message, $options); - - $entry = $this->lookup($locale, $message); - - if (null === $entry) { - return false; - } else if (!is_array($entry)) { - return $entry !== ''; - } else { - $plural_key = self::get_plural_key($locale, $count); - return isset($entry[$plural_key]) - && $entry[$plural_key] !== null - && $entry[$plural_key] !== ''; - } - } - - public static function get_message_key($message) { - $as_string = is_array($message) ? implode('|', $message) : $message; - return md5($as_string); - } - - private function interpolate($locale, $string, $values) { - // TODO: Handle locale specific number formatting. - - // Replace x_y before replacing x. - krsort($values, SORT_STRING); - - $keys = array(); - foreach (array_keys($values) as $key) { - $keys[] = "%$key"; - } - return str_replace($keys, array_values($values), $string); - } - - private function pluralize($locale, $entry, $count) { - if (!is_array($entry)) { - return $entry; - } - - $plural_key = self::get_plural_key($locale, $count); - if (!isset($entry[$plural_key])) { - // Fallback to the default plural form. - $plural_key = 'other'; - } - - if (isset($entry[$plural_key])) { - return $entry[$plural_key]; - } else { - // Fallback to just any plural form. - list ($plural_key, $string) = each($entry); - return $string; - } - } - - private function log($message, $options) { - $key = self::get_message_key($message); - isset($this->_call_log[$key]) or $this->_call_log[$key] = array($message, $options); - } - - public function call_log() { - return $this->_call_log; - } - - private static function get_plural_key($locale, $count) { - $parts = explode('_', $locale); - $language = $parts[0]; - - // Data from CLDR 1.6 (http://unicode.org/cldr/data/common/supplemental/plurals.xml). - // Docs: http://www.unicode.org/cldr/data/charts/supplemental/language_plural_rules.html - switch ($language) { - case 'az': - case 'fa': - case 'hu': - case 'ja': - case 'ko': - case 'my': - case 'to': - case 'tr': - case 'vi': - case 'yo': - case 'zh': - case 'bo': - case 'dz': - case 'id': - case 'jv': - case 'ka': - case 'km': - case 'kn': - case 'ms': - case 'th': - return 'other'; - - case 'ar': - if ($count == 0) { - return 'zero'; - } else if ($count == 1) { - return 'one'; - } else if ($count == 2) { - return 'two'; - } else if (is_int($count) && ($i = $count % 100) >= 3 && $i <= 10) { - return 'few'; - } else if (is_int($count) && ($i = $count % 100) >= 11 && $i <= 99) { - return 'many'; - } else { - return 'other'; - } - - case 'pt': - case 'am': - case 'bh': - case 'fil': - case 'tl': - case 'guw': - case 'hi': - case 'ln': - case 'mg': - case 'nso': - case 'ti': - case 'wa': - if ($count == 0 || $count == 1) { - return 'one'; - } else { - return 'other'; - } - - case 'fr': - if ($count >= 0 and $count < 2) { - return 'one'; - } else { - return 'other'; - } - - case 'lv': - if ($count == 0) { - return 'zero'; - } else if ($count % 10 == 1 && $count % 100 != 11) { - return 'one'; - } else { - return 'other'; - } - - case 'ga': - case 'se': - case 'sma': - case 'smi': - case 'smj': - case 'smn': - case 'sms': - if ($count == 1) { - return 'one'; - } else if ($count == 2) { - return 'two'; - } else { - return 'other'; - } - - case 'ro': - case 'mo': - if ($count == 1) { - return 'one'; - } else if (is_int($count) && $count == 0 && ($i = $count % 100) >= 1 && $i <= 19) { - return 'few'; - } else { - return 'other'; - } - - case 'lt': - if (is_int($count) && $count % 10 == 1 && $count % 100 != 11) { - return 'one'; - } else if (is_int($count) && ($i = $count % 10) >= 2 && $i <= 9 && ($i = $count % 100) < 11 && $i > 19) { - return 'few'; - } else { - return 'other'; - } - - case 'hr': - case 'ru': - case 'sr': - case 'uk': - case 'be': - case 'bs': - case 'sh': - if (is_int($count) && $count % 10 == 1 && $count % 100 != 11) { - return 'one'; - } else if (is_int($count) && ($i = $count % 10) >= 2 && $i <= 4 && ($i = $count % 100) < 12 && $i > 14) { - return 'few'; - } else if (is_int($count) && ($count % 10 == 0 || (($i = $count % 10) >= 5 && $i <= 9) || (($i = $count % 100) >= 11 && $i <= 14))) { - return 'many'; - } else { - return 'other'; - } - - case 'cs': - case 'sk': - if ($count == 1) { - return 'one'; - } else if (is_int($count) && $count >= 2 && $count <= 4) { - return 'few'; - } else { - return 'other'; - } - - case 'pl': - if ($count == 1) { - return 'one'; - } else if (is_int($count) && ($i = $count % 10) >= 2 && $i <= 4 && - ($i = $count % 100) < 12 && $i > 14 && ($i = $count % 100) < 22 && $i > 24) { - return 'few'; - } else { - return 'other'; - } - - case 'sl': - if ($count % 100 == 1) { - return 'one'; - } else if ($count % 100 == 2) { - return 'two'; - } else if (is_int($count) && ($i = $count % 100) >= 3 && $i <= 4) { - return 'few'; - } else { - return 'other'; - } - - case 'mt': - if ($count == 1) { - return 'one'; - } else if ($count == 0 || is_int($count) && ($i = $count % 100) >= 2 && $i <= 10) { - return 'few'; - } else if (is_int($count) && ($i = $count % 100) >= 11 && $i <= 19) { - return 'many'; - } else { - return 'other'; - } - - case 'mk': - if ($count % 10 == 1) { - return 'one'; - } else { - return 'other'; - } - - case 'cy': - if ($count == 1) { - return 'one'; - } else if ($count == 2) { - return 'two'; - } else if ($count == 8 || $count == 11) { - return 'many'; - } else { - return 'other'; - } - - default: // en, de, etc. - return $count == 1 ? 'one' : 'other'; - } - } -} \ No newline at end of file diff --git a/core/libraries/MY_Database.php b/core/libraries/MY_Database.php deleted file mode 100644 index c56f16e8..00000000 --- a/core/libraries/MY_Database.php +++ /dev/null @@ -1,92 +0,0 @@ -where[] = "("; - return $this; - } - - public function close_paren() { - // Search backwards for the last opening paren and resolve it - $i = count($this->where) - 1; - $this->where[$i] .= ")"; - while (--$i >= 0) { - if ($this->where[$i] == "(") { - // Remove the paren from the where clauses, and add it to the right of the operator of the - // next where clause. If removing the paren makes the next where clause the first element - // in the where list, then the operator shouldn't be there. It's there because we - // calculate whether or not we need an operator based on the number of where clauses, and - // the open paren seems like a where clause even though it isn't. - array_splice($this->where, $i, 1); - $this->where[$i] = preg_replace("/^(AND|OR) /", $i ? "\\1 (" : "(", $this->where[$i]); - return $this; - } - } - - throw new Kohana_Database_Exception('database.missing_open_paren'); - } - - /** - * Parse the query string and convert any strings of the form `\([a-zA-Z0-9_]*?)\] - * table prefix . $1 - */ - public function query($sql = '') { - if (!empty($sql)) { - $sql = $this->add_table_prefixes($sql); - } - return parent::query($sql); - } - - public function add_table_prefixes($sql) { - $prefix = $this->config["table_prefix"]; - if (strpos($sql, "SHOW TABLES") === 0) { - /* - * Don't ignore "show tables", otherwise we could have a infinite - * @todo this may have to be changed if we support more than mysql - */ - return $sql; - } else if (strpos($sql, "CREATE TABLE") === 0) { - // Creating a new table add it to the table cache. - $open_brace = strpos($sql, "{") + 1; - $close_brace = strpos($sql, "}", $open_brace); - $name = substr($sql, $open_brace, $close_brace - $open_brace); - $this->_table_names["{{$name}}"] = "{$prefix}$name"; - } - - if (!isset($this->_table_names)) { - // This should only run once on the first query - $this->_table_names =array(); - $len = strlen($prefix); - foreach($this->list_tables() as $table_name) { - if ($len > 0) { - $naked_name = strpos($table_name, $prefix) !== 0 ? - $table_name : substr($table_name, $len); - } else { - $naked_name = $table_name; - } - $this->_table_names["{{$naked_name}}"] = $table_name; - } - } - - return empty($this->_table_names) ? $sql : strtr($sql, $this->_table_names); - } -} \ No newline at end of file diff --git a/core/libraries/MY_Forge.php b/core/libraries/MY_Forge.php deleted file mode 100644 index 17d0465b..00000000 --- a/core/libraries/MY_Forge.php +++ /dev/null @@ -1,59 +0,0 @@ -hidden("csrf")->value(""); - } - /** - * Use our own template - */ - public function render($template="form.html", $custom=false) { - $this->hidden["csrf"]->value(access::csrf_token()); - return parent::render($template, $custom); - } - - /** - * Associate validation rules defined in the model with this form. - */ - public function add_rules_from($model) { - foreach ($this->inputs as $name => $input) { - if (isset($input->inputs)) { - $input->add_rules_from($model); - } - if (isset($model->rules[$name])) { - $input->rules($model->rules[$name]); - } - } - } - - /** - * Validate our CSRF value as a mandatory part of all form validation. - */ - public function validate() { - $status = parent::validate(); - access::verify_csrf(); - return $status; - } -} \ No newline at end of file diff --git a/core/libraries/MY_ORM.php b/core/libraries/MY_ORM.php deleted file mode 100644 index fb2f80a7..00000000 --- a/core/libraries/MY_ORM.php +++ /dev/null @@ -1,46 +0,0 @@ -db->open_paren(); - return $this; - } - - public function close_paren() { - $this->db->close_paren(); - return $this; - } -} - -/** - * Slide this in here for convenience. We won't ever be overloading ORM_Iterator without ORM. - */ -class ORM_Iterator extends ORM_Iterator_Core { - /** - * Cache the result row - */ - public function current() { - $row = parent::current(); - if (is_object($row)) { - model_cache::set($row); - } - return $row; - } -} \ No newline at end of file diff --git a/core/libraries/MY_Pagination.php b/core/libraries/MY_Pagination.php deleted file mode 100644 index d06a974f..00000000 --- a/core/libraries/MY_Pagination.php +++ /dev/null @@ -1,35 +0,0 @@ -auto_hide === TRUE AND $this->total_pages <= 1) { - return ""; - } - - if ($style === NULL) { - // Use default style - $style = $this->style; - } - - // Return rendered pagination view - return View::factory("pager.html", get_object_vars($this))->render(); - } -} diff --git a/core/libraries/MY_View.php b/core/libraries/MY_View.php deleted file mode 100644 index 836d1087..00000000 --- a/core/libraries/MY_View.php +++ /dev/null @@ -1,46 +0,0 @@ -set_global("csrf", access::csrf_token()); - } - - /** - * Override View_Core::render so that we trap errors stemming from bad PHP includes and show a - * visible stack trace to help developers. - * - * @see View_Core::render - */ - public function render($print=false, $renderer=false) { - try { - return parent::render($print, $renderer); - } catch (Exception $e) { - Kohana::Log('error', $e->getTraceAsString()); - Kohana::Log('debug', $e->getMessage()); - return ""; - } - } -} diff --git a/core/libraries/Menu.php b/core/libraries/Menu.php deleted file mode 100644 index d19d8b1e..00000000 --- a/core/libraries/Menu.php +++ /dev/null @@ -1,187 +0,0 @@ -id = $id; - return $this; - } - - /** - * Set the label - * @chainable - */ - public function label($label) { - $this->label = $label; - return $this; - } - - /** - * Set the url - * @chainable - */ - public function url($url) { - $this->url = $url; - return $this; - } - - /** - * Set the css id - * @chainable - */ - public function css_id($css_id) { - $this->css_id = $css_id; - return $this; - } - - /** - * Set the css class - * @chainable - */ - public function css_class($css_class) { - $this->css_class = $css_class; - return $this; - } - -} - -/** - * Menu element that provides a link to a new page. - */ -class Menu_Element_Link extends Menu_Element { - public function __toString() { - if (isset($this->css_id) && !empty($this->css_id)) { - $css_id = " id=\"$this->css_id\""; - } else { - $css_id = ""; - } - if (isset($this->css_class) && !empty($this->css_class)) { - $css_class = " $this->css_class"; - } else { - $css_class = ""; - } - return "
  • url\" " . - "title=\"$this->label\">$this->label
  • "; - } -} - -/** - * Menu element that provides a pop-up dialog - */ -class Menu_Element_Dialog extends Menu_Element { - public function __toString() { - if (isset($this->css_id) && !empty($this->css_id)) { - $css_id = " id=\"$this->css_id\""; - } else { - $css_id = ""; - } - if (isset($this->css_class) && !empty($this->css_class)) { - $css_class = " $this->css_class"; - } else { - $css_class = ""; - } - return "
  • url\" " . - "title=\"$this->label\">$this->label
  • "; - } -} - -/** - * Root menu or submenu - */ -class Menu_Core extends Menu_Element { - public $elements; - public $is_root = false; - - /** - * Return an instance of a Menu_Element - * @chainable - */ - public static function factory($type) { - switch($type) { - case "link": - return new Menu_Element_Link(); - - case "dialog": - return new Menu_Element_Dialog(); - - case "root": - $menu = new Menu(); - $menu->is_root = true; - return $menu; - - case "submenu": - return new Menu(); - - default: - throw Exception("@todo UNKNOWN_MENU_TYPE"); - } - } - - public function __construct() { - $this->elements = array(); - } - - /** - * Add a new element to this menu - */ - public function append($menu_element) { - $this->elements[$menu_element->id] = $menu_element; - return $this; - } - - /** - * Add a new element to this menu - */ - public function add_after($target_id, $new_menu_element) { - $copy = array(); - foreach ($this->elements as $id => $menu_element) { - $copy[$id] = $menu_element; - if ($id == $target_id) { - $copy[$new_menu_element->id] = $new_menu_element; - } - } - $this->elements = $copy; - return $this; - } - - /** - * Retrieve a Menu_Element by id - */ - public function get($id) { - return $this->elements[$id]; - } - - public function __toString() { - $html = $this->is_root ? "
      " : - "
    • $this->label
        "; - $html .= implode("\n", $this->elements); - $html .= $this->is_root ? "
      " : "
    "; - return $html; - } -} diff --git a/core/libraries/ORM_MPTT.php b/core/libraries/ORM_MPTT.php deleted file mode 100644 index 46280d95..00000000 --- a/core/libraries/ORM_MPTT.php +++ /dev/null @@ -1,307 +0,0 @@ -model_name = inflector::singular($this->table_name); - } - - /** - * Add this node as a child of the parent provided. - * - * @chainable - * @param integer $parent_id the id of the parent node - * @return ORM - */ - function add_to_parent($parent) { - $this->lock(); - - try { - // Make a hole in the parent for this new item - $this->db->query( - "UPDATE {{$this->table_name}} SET `left` = `left` + 2 WHERE `left` >= {$parent->right}"); - $this->db->query( - "UPDATE {{$this->table_name}} SET `right` = `right` + 2 WHERE `right` >= {$parent->right}"); - $parent->right += 2; - - // Insert this item into the hole - $this->left = $parent->right - 2; - $this->right = $parent->right - 1; - $this->parent_id = $parent->id; - $this->level = $parent->level + 1; - $this->save(); - $parent->reload(); - } catch (Exception $e) { - $this->unlock(); - throw $e; - } - - $this->unlock(); - return $this; - } - - /** - * Delete this node and all of its children. - */ - public function delete() { - $children = $this->children(); - if ($children) { - foreach ($this->children() as $item) { - // Deleting children affects the MPTT tree, so we have to reload each child before we - // delete it so that we have current left/right pointers. This is inefficient. - // @todo load each child once, not twice. - $item->reload()->delete(); - } - - // Deleting children has affected this item - $this->reload(); - } - - $this->lock(); - try { - $this->db->query( - "UPDATE {{$this->table_name}} SET `left` = `left` - 2 WHERE `left` > {$this->right}"); - $this->db->query( - "UPDATE {{$this->table_name}} SET `right` = `right` - 2 WHERE `right` > {$this->right}"); - } catch (Exception $e) { - $this->unlock(); - throw $e; - } - - $this->unlock(); - parent::delete(); - } - - /** - * Return true if the target is descendant of this item. - * @param ORM $target - * @return boolean - */ - function is_descendant($target) { - return ($this->left <= $target->left && $this->right >= $target->right); - } - - /** - * Return the parent of this node - * - * @return ORM - */ - function parent() { - if (!$this->parent_id) { - return null; - } - return model_cache::get($this->model_name, $this->parent_id); - } - - /** - * Return all the parents of this node, in order from root to this node's immediate parent. - * - * @return array ORM - */ - function parents() { - return $this - ->where("`left` <= {$this->left}") - ->where("`right` >= {$this->right}") - ->where("id <> {$this->id}") - ->orderby("left", "ASC") - ->find_all(); - } - - /** - * Return all of the children of this node, ordered by id. - * - * @chainable - * @param integer SQL limit - * @param integer SQL offset - * @param array orderby - * @return array ORM - */ - function children($limit=null, $offset=0, $orderby=null) { - $this->where("parent_id", $this->id); - if (empty($orderby)) { - $this->orderby("id", "ASC"); - } else { - $this->orderby($orderby); - } - return $this->find_all($limit, $offset); - } - - /** - * Return all of the children of this node, ordered by id. - * - * @chainable - * @param integer SQL limit - * @param integer SQL offset - * @return array ORM - */ - function children_count() { - return $this->where("parent_id", $this->id)->count_all(); - } - - /** - * Return all of the children of the specified type, ordered by id. - * - * @param integer SQL limit - * @param integer SQL offset - * @param string type to return - * @param array orderby - * @return object ORM_Iterator - */ - function descendants($limit=null, $offset=0, $type=null, $orderby=null) { - $this->where("left >", $this->left) - ->where("right <=", $this->right); - if ($type) { - $this->where("type", $type); - } - - if (empty($orderby)) { - $this->orderby("id", "ASC"); - } else { - $this->orderby($orderby); - } - - return $this->find_all($limit, $offset); - } - - /** - * Return the count of all the children of the specified type. - * - * @param string type to count - * @return integer child count - */ - function descendants_count($type=null) { - $this->where("left >", $this->left) - ->where("right <=", $this->right); - if ($type) { - $this->where("type", $type); - } - return $this->count_all(); - } - - /** - * Move this item to the specified target. - * - * @chainable - * @param Item_Model $target Target node - * @return ORM_MTPP - */ - function move_to($target) { - if ($this->left <= $target->left && - $this->right >= $target->right) { - throw new Exception("@todo INVALID_TARGET can't move item inside itself"); - } - - $number_to_move = (int)(($this->right - $this->left) / 2 + 1); - $size_of_hole = $number_to_move * 2; - $original_left = $this->left; - $original_right = $this->right; - $target_right = $target->right; - $level_delta = ($target->level + 1) - $this->level; - - $this->lock(); - try { - if ($level_delta) { - // Update the levels for the to-be-moved items - $this->db->query( - "UPDATE {{$this->table_name}} SET `level` = `level` + $level_delta" . - " WHERE `left` >= $original_left AND `right` <= $original_right"); - } - - // Make a hole in the target for the move - $target->db->query( - "UPDATE {{$this->table_name}} SET `left` = `left` + $size_of_hole" . - " WHERE `left` >= $target_right"); - $target->db->query( - "UPDATE {{$this->table_name}} SET `right` = `right` + $size_of_hole" . - " WHERE `right` >= $target_right"); - - // Change the parent. - $this->db->query( - "UPDATE {{$this->table_name}} SET `parent_id` = {$target->id}" . - " WHERE `id` = {$this->id}"); - - // If the source is to the right of the target then we just adjusted its left and right above. - $left = $original_left; - $right = $original_right; - if ($original_left > $target_right) { - $left += $size_of_hole; - $right += $size_of_hole; - } - - $new_offset = $target->right - $left; - $this->db->query( - "UPDATE {{$this->table_name}}" . - " SET `left` = `left` + $new_offset," . - " `right` = `right` + $new_offset" . - " WHERE `left` >= $left" . - " AND `right` <= $right"); - - // Close the hole in the source's parent after the move - $this->db->query( - "UPDATE {{$this->table_name}} SET `left` = `left` - $size_of_hole" . - " WHERE `left` > $right"); - $this->db->query( - "UPDATE {{$this->table_name}} SET `right` = `right` - $size_of_hole" . - " WHERE `right` > $right"); - } catch (Exception $e) { - $this->unlock(); - throw $e; - } - - $this->unlock(); - - // Lets reload to get the changes. - $this->reload(); - return $this; - } - - /** - * Lock the tree to prevent concurrent modification. - */ - protected function lock() { - $result = $this->db->query("SELECT GET_LOCK('{$this->table_name}', 1) AS l")->current(); - if (empty($result->l)) { - throw new Exception("@todo UNABLE_TO_LOCK_EXCEPTION"); - } - } - - /** - * Unlock the tree. - */ - protected function unlock() { - $this->db->query("SELECT RELEASE_LOCK('{$this->table_name}')"); - } -} diff --git a/core/libraries/Sendmail.php b/core/libraries/Sendmail.php deleted file mode 100644 index 90998457..00000000 --- a/core/libraries/Sendmail.php +++ /dev/null @@ -1,97 +0,0 @@ -headers = array(); - $config = Kohana::config("sendmail"); - foreach ($config as $key => $value) { - $this->$key($value); - } - } - - public function __get($key) { - return null; - } - - public function __call($key, $value) { - switch ($key) { - case "to": - $this->to = is_array($value[0]) ? $value[0] : array($value[0]); - break; - case "header": - if (count($value) != 2) { - throw new Exception("@todo INVALID_HEADER_PARAMETERS"); - } - $this->headers[$value[0]] = $value[1]; - break; - case "from": - $this->headers["From"] = $value[0]; - break; - case "reply_to": - $this->headers["Reply-To"] = $value[0]; - break; - default: - $this->$key = $value[0]; - } - return $this; - } - - public function send() { - if (empty($this->to)) { - throw new Exception("@todo TO_IS_REQUIRED_FOR_MAIL"); - } - $to = implode(", ", $this->to); - $headers = array(); - foreach ($this->headers as $key => $value) { - $key = ucfirst($key); - $headers[] = "$key: $value"; - } - - // The docs say headers should be separated by \r\n, but occasionaly that doesn't work and you - // need to use a single \n. This can be set in config/sendmail.php - $headers = implode($this->header_separator, $headers); - $message = wordwrap($this->message, $this->line_length, "\n"); - if (!$this->mail($to, $this->subject, $message, $headers)) { - Kohana::log("error", wordwrap("Sending mail failed:\nTo: $to\n $this->subject\n" . - "Headers: $headers\n $this->message")); - throw new Exception("@todo SEND_MAIL_FAILED"); - } - return $this; - } - - public function mail($to, $subject, $message, $headers) { - return mail($to, $subject, $message, $headers); - } -} diff --git a/core/libraries/Task_Definition.php b/core/libraries/Task_Definition.php deleted file mode 100644 index 8d9c5922..00000000 --- a/core/libraries/Task_Definition.php +++ /dev/null @@ -1,50 +0,0 @@ -callback = $callback; - return $this; - } - - function description($description) { - $this->description = $description; - return $this; - } - - function name($name) { - $this->name = $name; - return $this; - } - - function severity($severity) { - $this->severity = $severity; - return $this; - } -} diff --git a/core/libraries/Theme_View.php b/core/libraries/Theme_View.php deleted file mode 100644 index b5b97666..00000000 --- a/core/libraries/Theme_View.php +++ /dev/null @@ -1,221 +0,0 @@ -theme_name = module::get_var("core", "active_site_theme"); - if (user::active()->admin) { - $this->theme_name = Input::instance()->get("theme", $this->theme_name); - } - $this->item = null; - $this->tag = null; - $this->set_global("theme", $this); - $this->set_global("user", user::active()); - $this->set_global("page_type", $page_type); - if ($page_type == "album") { - $this->set_global("thumb_proportion", $this->thumb_proportion()); - } - - $maintenance_mode = Kohana::config("core.maintenance_mode", false, false); - if ($maintenance_mode) { - message::warning(t("This site is currently in maintenance mode")); - } - } - - /** - * Proportion of the current thumb_size's to default - * @return int - */ - public function thumb_proportion() { - // @TODO change the 200 to a theme supplied value when and if we come up with an - // API to allow the theme to set defaults. - return module::get_var("core", "thumb_size", 200) / 200; - } - - public function url($path, $absolute_url=false) { - $arg = "themes/{$this->theme_name}/$path"; - return $absolute_url ? url::abs_file($arg) : url::file($arg); - } - - public function item() { - return $this->item; - } - - public function tag() { - return $this->tag; - } - - public function page_type() { - return $this->page_type; - } - - public function display($page_name, $view_class="View") { - return new $view_class($page_name); - } - - public function site_menu() { - $menu = Menu::factory("root"); - if ($this->page_type != "login") { - core_menu::site($menu, $this); - - foreach (module::active() as $module) { - if ($module->name == "core") { - continue; - } - $class = "{$module->name}_menu"; - if (method_exists($class, "site")) { - call_user_func_array(array($class, "site"), array(&$menu, $this)); - } - } - } - - print $menu; - } - - public function album_menu() { - $menu = Menu::factory("root"); - core_menu::album($menu, $this); - - foreach (module::active() as $module) { - if ($module->name == "core") { - continue; - } - $class = "{$module->name}_menu"; - if (method_exists($class, "album")) { - call_user_func_array(array($class, "album"), array(&$menu, $this)); - } - } - - print $menu; - } - - public function photo_menu() { - $menu = Menu::factory("root"); - core_menu::photo($menu, $this); - - foreach (module::active() as $module) { - if ($module->name == "core") { - continue; - } - $class = "{$module->name}_menu"; - if (method_exists($class, "photo")) { - call_user_func_array(array($class, "photo"), array(&$menu, $this)); - } - } - - print $menu; - } - - public function pager() { - if ($this->children_count) { - $this->pagination = new Pagination(); - $this->pagination->initialize( - array('query_string' => 'page', - 'total_items' => $this->children_count, - 'items_per_page' => $this->page_size, - 'style' => 'classic')); - return $this->pagination->render(); - } - } - - /** - * Print out any site wide status information. - */ - public function site_status() { - return site_status::get(); - } - - /** - * Print out any messages waiting for this user. - */ - public function messages() { - return message::get(); - } - - /** - * Handle all theme functions that insert module content. - */ - public function __call($function, $args) { - switch ($function) { - case "album_blocks": - case "album_bottom": - case "album_top": - case "credits"; - case "dynamic_bottom": - case "dynamic_top": - case "footer": - case "head": - case "header_bottom": - case "header_top": - case "page_bottom": - case "page_top": - case "photo_blocks": - case "photo_bottom": - case "photo_top": - case "resize_bottom": - case "resize_top": - case "sidebar_blocks": - case "sidebar_bottom": - case "sidebar_top": - case "thumb_bottom": - case "thumb_info": - case "thumb_top": - $blocks = array(); - foreach (module::active() as $module) { - $helper_class = "{$module->name}_theme"; - if (method_exists($helper_class, $function)) { - $blocks[] = call_user_func_array( - array($helper_class, $function), - array_merge(array($this), $args)); - } - } - if (Session::instance()->get("debug")) { - if ($function != "head") { - array_unshift( - $blocks, "
    " . - "
    $function
    "); - $blocks[] = "
    "; - } - } - return implode("\n", $blocks); - - default: - throw new Exception("@todo UNKNOWN_THEME_FUNCTION: $function"); - } - } -} \ No newline at end of file diff --git a/core/models/access_cache.php b/core/models/access_cache.php deleted file mode 100644 index 10d05df7..00000000 --- a/core/models/access_cache.php +++ /dev/null @@ -1,21 +0,0 @@ - "required|length[0,255]", - "title" => "required|length[0,255]", - "description" => "length[0,65535]" - ); - - /** - * Add a set of restrictions to any following queries to restrict access only to items - * viewable by the active user. - * @chainable - */ - public function viewable() { - if (is_null($this->view_restrictions)) { - if (user::active()->admin) { - $this->view_restrictions = array(); - } else { - foreach (user::group_ids() as $id) { - // Separate the first restriction from the rest to make it easier for us to formulate - // our where clause below - if (empty($this->view_restrictions)) { - $this->view_restrictions[0] = "view_$id"; - } else { - $this->view_restrictions[1]["view_$id"] = access::ALLOW; - } - } - } - } - switch (count($this->view_restrictions)) { - case 0: - break; - - case 1: - $this->where($this->view_restrictions[0], access::ALLOW); - break; - - default: - $this->open_paren(); - $this->where($this->view_restrictions[0], access::ALLOW); - $this->orwhere($this->view_restrictions[1]); - $this->close_paren(); - break; - } - - return $this; - } - - /** - * Is this item an album? - * @return true if it's an album - */ - public function is_album() { - return $this->type == 'album'; - } - - /** - * Is this item a photo? - * @return true if it's a photo - */ - public function is_photo() { - return $this->type == 'photo'; - } - - /** - * Is this item a movie? - * @return true if it's a movie - */ - public function is_movie() { - return $this->type == 'movie'; - } - - public function delete() { - module::event("item_before_delete", $this); - - $parent = $this->parent(); - if ($parent->album_cover_item_id == $this->id) { - item::remove_album_cover($parent); - } - - $path = $this->file_path(); - $resize_path = $this->resize_path(); - $thumb_path = $this->thumb_path(); - - parent::delete(); - if (is_dir($path)) { - @dir::unlink($path); - @dir::unlink(dirname($resize_path)); - @dir::unlink(dirname($thumb_path)); - } else { - @unlink($path); - @unlink($resize_path); - @unlink($thumb_path); - } - } - - /** - * Move this item to the specified target. - * @chainable - * @param Item_Model $target Target item (must be an album - * @return ORM_MTPP - */ - function move_to($target) { - if (!$target->is_album()) { - throw new Exception("@todo INVALID_MOVE_TYPE $target->type"); - } - - if ($this->id == 1) { - throw new Exception("@todo INVALID_SOURCE root album"); - } - - $original_path = $this->file_path(); - $original_resize_path = $this->resize_path(); - $original_thumb_path = $this->thumb_path(); - - parent::move_to($target, true); - $this->relative_path_cache = null; - - rename($original_path, $this->file_path()); - if ($this->is_album()) { - @rename(dirname($original_resize_path), dirname($this->resize_path())); - @rename(dirname($original_thumb_path), dirname($this->thumb_path())); - Database::instance() - ->update("items", - array("relative_path_cache" => null), - array("left >" => $this->left, "right <" => $this->right)); - } else { - @rename($original_resize_path, $this->resize_path()); - @rename($original_thumb_path, $this->thumb_path()); - } - - return $this; - } - - /** - * Rename the underlying file for this item to a new name. Move all the files. This requires a - * save. - * - * @chainable - */ - public function rename($new_name) { - if ($new_name == $this->name) { - return; - } - - if (strpos($new_name, "/")) { - throw new Exception("@todo NAME_CANNOT_CONTAIN_SLASH"); - } - - $old_relative_path = $this->relative_path(); - $new_relative_path = dirname($old_relative_path) . "/" . $new_name; - @rename(VARPATH . "albums/$old_relative_path", VARPATH . "albums/$new_relative_path"); - @rename(VARPATH . "resizes/$old_relative_path", VARPATH . "resizes/$new_relative_path"); - @rename(VARPATH . "thumbs/$old_relative_path", VARPATH . "thumbs/$new_relative_path"); - $this->name = $new_name; - - if ($this->is_album()) { - Database::instance() - ->update("items", - array("relative_path_cache" => null), - array("left >" => $this->left, "right <" => $this->right)); - } - - return $this; - } - - /** - * album: url::site("albums/2") - * photo: url::site("photos/3") - * - * @param string $query the query string (eg "show=3") - */ - public function url($query=array(), $full_uri=false) { - $url = ($full_uri ? url::abs_site("{$this->type}s/$this->id") - : url::site("{$this->type}s/$this->id")); - if ($query) { - $url .= "?$query"; - } - return $url; - } - - /** - * album: /var/albums/album1/album2 - * photo: /var/albums/album1/album2/photo.jpg - */ - public function file_path() { - return VARPATH . "albums/" . $this->relative_path(); - } - - /** - * album: http://example.com/gallery3/var/resizes/album1/ - * photo: http://example.com/gallery3/var/albums/album1/photo.jpg - */ - public function file_url($full_uri=false) { - return $full_uri ? - url::abs_file("var/albums/" . $this->relative_path()) : - url::file("var/albums/" . $this->relative_path()); - } - - /** - * album: /var/resizes/album1/.thumb.jpg - * photo: /var/albums/album1/photo.thumb.jpg - */ - public function thumb_path() { - $base = VARPATH . "thumbs/" . $this->relative_path(); - if ($this->is_photo()) { - return $base; - } else if ($this->is_album()) { - return $base . "/.album.jpg"; - } else if ($this->is_movie()) { - // Replace the extension with jpg - return preg_replace("/...$/", "jpg", $base); - } - } - - /** - * Return true if there is a thumbnail for this item. - */ - public function has_thumb() { - return $this->thumb_width && $this->thumb_height; - } - - /** - * album: http://example.com/gallery3/var/resizes/album1/.thumb.jpg - * photo: http://example.com/gallery3/var/albums/album1/photo.thumb.jpg - */ - public function thumb_url($full_uri=false) { - $cache_buster = "?m=" . $this->updated; - $base = ($full_uri ? - url::abs_file("var/thumbs/" . $this->relative_path()) : - url::file("var/thumbs/" . $this->relative_path())); - if ($this->is_photo()) { - return $base . $cache_buster; - } else if ($this->is_album()) { - return $base . "/.album.jpg" . $cache_buster; - } else if ($this->is_movie()) { - // Replace the extension with jpg - $base = preg_replace("/...$/", "jpg", $base); - return $base . $cache_buster; - } - } - - /** - * album: /var/resizes/album1/.resize.jpg - * photo: /var/albums/album1/photo.resize.jpg - */ - public function resize_path() { - return VARPATH . "resizes/" . $this->relative_path() . - ($this->is_album() ? "/.album.jpg" : ""); - } - - /** - * album: http://example.com/gallery3/var/resizes/album1/.resize.jpg - * photo: http://example.com/gallery3/var/albums/album1/photo.resize.jpg - */ - public function resize_url($full_uri=false) { - return ($full_uri ? - url::abs_file("var/resizes/" . $this->relative_path()) : - url::file("var/resizes/" . $this->relative_path())) . - ($this->is_album() ? "/.album.jpg" : ""); - } - - /** - * Return the relative path to this item's file. - * @return string - */ - public function relative_path() { - if (!isset($this->relative_path_cache)) { - $paths = array(); - foreach (Database::instance() - ->select("name") - ->from("items") - ->where("left <=", $this->left) - ->where("right >=", $this->right) - ->where("id <>", 1) - ->orderby("left", "ASC") - ->get() as $row) { - $paths[] = $row->name; - } - $this->relative_path_cache = implode($paths, "/"); - $this->save(); - } - return $this->relative_path_cache; - } - - /** - * @see ORM::__get() - */ - public function __get($column) { - if ($column == "owner") { - // This relationship depends on an outside module, which may not be present so handle - // failures gracefully. - try { - return model_cache::get("user", $this->owner_id); - } catch (Exception $e) { - return null; - } - } else { - return parent::__get($column); - } - } - - /** - * @see ORM::__set() - */ - public function __set($column, $value) { - if ($column == "name") { - // Clear the relative path as it is no longer valid. - $this->relative_path_cache = null; - } - parent::__set($column, $value); - } - - /** - * @see ORM::save() - */ - public function save() { - if (!empty($this->changed) && $this->changed != array("view_count" => "view_count")) { - $this->updated = time(); - if (!$this->loaded) { - $this->created = $this->updated; - $r = ORM::factory("item")->select("MAX(weight) as max_weight")->find(); - $this->weight = $r->max_weight + 1; - } - } - return parent::save(); - } - - /** - * Return the Item_Model representing the cover for this album. - * @return Item_Model or null if there's no cover - */ - public function album_cover() { - if (!$this->is_album()) { - return null; - } - - if (empty($this->album_cover_item_id)) { - return null; - } - - try { - return model_cache::get("item", $this->album_cover_item_id); - } catch (Exception $e) { - // It's possible (unlikely) that the item was deleted, if so keep going. - return null; - } - } - - /** - * Find the position of the given child id in this album. The resulting value is 1-indexed, so - * the first child in the album is at position 1. - */ - public function get_position($child_id) { - $result = Database::instance()->query(" - SELECT COUNT(*) AS position FROM {items} - WHERE parent_id = {$this->parent_id} - AND {$this->sort_column} <= (SELECT {$this->sort_column} - FROM {items} WHERE id = $child_id) - ORDER BY {$this->sort_column} {$this->sort_order}"); - - return $result->current()->position; - } - - /** - * Return an tag for the thumbnail. - * @param array $extra_attrs Extra attributes to add to the img tag - * @param int (optional) $max Maximum size of the thumbnail (default: null) - * @param boolean (optional) $center_vertically Center vertically (default: false) - * @return string - */ - public function thumb_tag($extra_attrs=array(), $max=null, $center_vertically=false) { - list ($height, $width) = $this->scale_dimensions($max); - if ($center_vertically && $max) { - // The constant is divide by 2 to calculate the file and 10 to convert to em - $margin_top = ($max - $height) / 20; - $extra_attrs["style"] = "margin-top: {$margin_top}em"; - $extra_attrs["title"] = $this->title; - } - $attrs = array_merge($extra_attrs, - array( - "src" => $this->thumb_url(), - "alt" => $this->title, - "width" => $width, - "height" => $height) - ); - // html::image forces an absolute url which we don't want - return ""; - } - - /** - * Calculate the largest width/height that fits inside the given maximum, while preserving the - * aspect ratio. - * @param int $max Maximum size of the largest dimension - * @return array - */ - public function scale_dimensions($max) { - $width = $this->thumb_width; - $height = $this->thumb_height; - - if ($height) { - if (isset($max)) { - if ($width > $height) { - $height = (int)($max * ($height / $width)); - $width = $max; - } else { - $width = (int)($max * ($width / $height)); - $height = $max; - } - } - } else { - // Missing thumbnail, can happen on albums with no photos yet. - // @todo we should enforce a placeholder for those albums. - $width = 0; - $height = 0; - } - return array($height, $width); - } - - /** - * Return an tag for the resize. - * @param array $extra_attrs Extra attributes to add to the img tag - * @return string - */ - public function resize_tag($extra_attrs) { - $attrs = array_merge($extra_attrs, - array("src" => $this->resize_url(), - "alt" => $this->title, - "width" => $this->resize_width, - "height" => $this->resize_height) - ); - // html::image forces an absolute url which we don't want - return ""; - } - - /** - * Return a flowplayer "; - } - - /** - * Return all of the children of this node, ordered by the defined sort order. - * - * @chainable - * @param integer SQL limit - * @param integer SQL offset - * @return array ORM - */ - function children($limit=null, $offset=0) { - return parent::children($limit, $offset, array($this->sort_column => $this->sort_order)); - } - - /** - * Return all of the children of the specified type, ordered by the defined sort order. - * @param integer SQL limit - * @param integer SQL offset - * @param string type to return - * @return object ORM_Iterator - */ - function descendants($limit=null, $offset=0, $type=null) { - return parent::descendants($limit, $offset, $type, - array($this->sort_column => $this->sort_order)); - } -} diff --git a/core/models/log.php b/core/models/log.php deleted file mode 100644 index 6734afb8..00000000 --- a/core/models/log.php +++ /dev/null @@ -1,22 +0,0 @@ -context); - if (array_key_exists($key, $context)) { - return $context[$key]; - } else { - return $default; - } - } - - public function set($key, $value) { - $context = unserialize($this->context); - $context[$key] = $value; - $this->context = serialize($context); - } - - public function save() { - if (!empty($this->changed)) { - $this->updated = time(); - } - return parent::save(); - } - - public function owner() { - return user::lookup($this->owner_id); - } -} \ No newline at end of file diff --git a/core/models/theme.php b/core/models/theme.php deleted file mode 100644 index f479fd5a..00000000 --- a/core/models/theme.php +++ /dev/null @@ -1,21 +0,0 @@ -where("name", "access_test")->find(); - if ($group->loaded) { - $group->delete(); - } - } catch (Exception $e) { } - - try { - access::delete_permission("access_test"); - } catch (Exception $e) { } - - try { - $user = ORM::factory("user")->where("name", "access_test")->find(); - if ($user->loaded) { - $user->delete(); - } - } catch (Exception $e) { } - } - - public function setup() { - user::set_active(user::guest()); - } - - public function groups_and_permissions_are_bound_to_columns_test() { - access::register_permission("access_test", "Access Test"); - $group = group::create("access_test"); - - // We have a new column for this perm / group combo - $fields = Database::instance()->list_fields("access_caches"); - $this->assert_true(array_key_exists("access_test_{$group->id}", $fields)); - - access::delete_permission("access_test"); - $group->delete(); - - // Now the column has gone away - $fields = Database::instance()->list_fields("access_caches"); - $this->assert_false(array_key_exists("access_test_{$group->id}", $fields)); - } - - public function adding_and_removing_items_adds_ands_removes_rows_test() { - $root = ORM::factory("item", 1); - $item = album::create($root, rand(), "test album"); - - // New rows exist - $this->assert_true(ORM::factory("access_cache")->where("item_id", $item->id)->find()->loaded); - $this->assert_true(ORM::factory("access_intent")->where("item_id", $item->id)->find()->loaded); - - // Delete the item - $item->delete(); - - // Rows are gone - $this->assert_false(ORM::factory("access_cache")->where("item_id", $item->id)->find()->loaded); - $this->assert_false(ORM::factory("access_intent")->where("item_id", $item->id)->find()->loaded); - } - - public function new_photos_inherit_parent_permissions_test() { - $root = ORM::factory("item", 1); - - $album = album::create($root, rand(), "test album"); - access::allow(group::everybody(), "view", $album); - - $photo = ORM::factory("item"); - $photo->type = "photo"; - $photo->add_to_parent($album); - access::add_item($photo); - - $this->assert_true($photo->__get("view_" . group::everybody()->id)); - } - - public function can_allow_deny_and_reset_intent_test() { - $root = ORM::factory("item", 1); - $album = album::create($root, rand(), "test album"); - $intent = ORM::factory("access_intent")->where("item_id", $album)->find(); - - // Allow - access::allow(group::everybody(), "view", $album); - $this->assert_same(access::ALLOW, $intent->reload()->view_1); - - // Deny - access::deny(group::everybody(), "view", $album); - $this->assert_same( - access::DENY, - ORM::factory("access_intent")->where("item_id", $album)->find()->view_1); - - // Allow again. If the initial value was allow, then the first Allow clause above may not - // have actually changed any values. - access::allow(group::everybody(), "view", $album); - $this->assert_same( - access::ALLOW, - ORM::factory("access_intent")->where("item_id", $album)->find()->view_1); - - access::reset(group::everybody(), "view", $album); - $this->assert_same( - null, - ORM::factory("access_intent")->where("item_id", $album)->find()->view_1); - } - - public function cant_reset_root_item_test() { - try { - access::reset(group::everybody(), "view", ORM::factory("item", 1)); - } catch (Exception $e) { - return; - } - $this->assert_true(false, "Should not be able to reset root intent"); - } - - public function can_view_item_test() { - $root = ORM::factory("item", 1); - access::allow(group::everybody(), "view", $root); - $this->assert_true(access::group_can(group::everybody(), "view", $root)); - } - - public function can_always_fails_on_unloaded_items_test() { - $root = ORM::factory("item", 1); - access::allow(group::everybody(), "view", $root); - $this->assert_true(access::group_can(group::everybody(), "view", $root)); - - $bogus = ORM::factory("item", -1); - $this->assert_false(access::group_can(group::everybody(), "view", $bogus)); - } - - public function cant_view_child_of_hidden_parent_test() { - $root = ORM::factory("item", 1); - $album = album::create($root, rand(), "test album"); - - $root->reload(); - access::deny(group::everybody(), "view", $root); - access::reset(group::everybody(), "view", $album); - - $album->reload(); - $this->assert_false(access::group_can(group::everybody(), "view", $album)); - } - - public function view_permissions_propagate_down_test() { - $root = ORM::factory("item", 1); - $album = album::create($root, rand(), "test album"); - - access::allow(group::everybody(), "view", $root); - access::reset(group::everybody(), "view", $album); - $album->reload(); - $this->assert_true(access::group_can(group::everybody(), "view", $album)); - } - - public function can_toggle_view_permissions_propagate_down_test() { - $root = ORM::factory("item", 1); - $album1 = album::create($root, rand(), "test album"); - $album2 = album::create($album1, rand(), "test album"); - $album3 = album::create($album2, rand(), "test album"); - $album4 = album::create($album3, rand(), "test album"); - - $album1->reload(); - $album2->reload(); - $album3->reload(); - $album4->reload(); - - access::allow(group::everybody(), "view", $root); - access::deny(group::everybody(), "view", $album1); - access::reset(group::everybody(), "view", $album2); - access::reset(group::everybody(), "view", $album3); - access::reset(group::everybody(), "view", $album4); - - $album4->reload(); - $this->assert_false(access::group_can(group::everybody(), "view", $album4)); - - access::allow(group::everybody(), "view", $album1); - $album4->reload(); - $this->assert_true(access::group_can(group::everybody(), "view", $album4)); - } - - public function revoked_view_permissions_cant_be_allowed_lower_down_test() { - $root = ORM::factory("item", 1); - $album1 = album::create($root, rand(), "test album"); - $album2 = album::create($album1, rand(), "test album"); - - $root->reload(); - access::deny(group::everybody(), "view", $root); - access::allow(group::everybody(), "view", $album2); - - $album1->reload(); - $this->assert_false(access::group_can(group::everybody(), "view", $album1)); - - $album2->reload(); - $this->assert_false(access::group_can(group::everybody(), "view", $album2)); - } - - public function can_edit_item_test() { - $root = ORM::factory("item", 1); - access::allow(group::everybody(), "edit", $root); - $this->assert_true(access::group_can(group::everybody(), "edit", $root)); - } - - public function non_view_permissions_propagate_down_test() { - $root = ORM::factory("item", 1); - $album = album::create($root, rand(), "test album"); - - access::allow(group::everybody(), "edit", $root); - access::reset(group::everybody(), "edit", $album); - $this->assert_true(access::group_can(group::everybody(), "edit", $album)); - } - - public function non_view_permissions_can_be_revoked_lower_down_test() { - $root = ORM::factory("item", 1); - $outer = album::create($root, rand(), "test album"); - $outer_photo = ORM::factory("item"); - $outer_photo->type = "photo"; - $outer_photo->add_to_parent($outer); - access::add_item($outer_photo); - - $inner = album::create($outer, rand(), "test album"); - $inner_photo = ORM::factory("item"); - $inner_photo->type = "photo"; - $inner_photo->add_to_parent($inner); - access::add_item($inner_photo); - - $outer->reload(); - $inner->reload(); - - access::allow(group::everybody(), "edit", $root); - access::deny(group::everybody(), "edit", $outer); - access::allow(group::everybody(), "edit", $inner); - - // Outer album is not editable, inner one is. - $this->assert_false(access::group_can(group::everybody(), "edit", $outer_photo)); - $this->assert_true(access::group_can(group::everybody(), "edit", $inner_photo)); - } - - public function i_can_edit_test() { - // Create a new user that belongs to no groups - $user = user::create("access_test", "Access Test", ""); - foreach ($user->groups as $group) { - $user->remove($group); - } - $user->save(); - user::set_active($user); - - // This user can't edit anything - $root = ORM::factory("item", 1); - $this->assert_false(access::can("edit", $root)); - - // Now add them to a group that has edit permission - $group = group::create("access_test"); - $group->add($user); - $group->save(); - access::allow($group, "edit", $root); - - $user = ORM::factory("user", $user->id); // reload() does not flush related columns - user::set_active($user); - - // And verify that the user can edit. - $this->assert_true(access::can("edit", $root)); - } - - public function everybody_view_permission_maintains_htaccess_files_test() { - $root = ORM::factory("item", 1); - $album = album::create($root, rand(), "test album"); - - $this->assert_false(file_exists($album->file_path() . "/.htaccess")); - - access::deny(group::everybody(), "view", $album); - $this->assert_true(file_exists($album->file_path() . "/.htaccess")); - - access::allow(group::everybody(), "view", $album); - $this->assert_false(file_exists($album->file_path() . "/.htaccess")); - - access::deny(group::everybody(), "view", $album); - $this->assert_true(file_exists($album->file_path() . "/.htaccess")); - - access::reset(group::everybody(), "view", $album); - $this->assert_false(file_exists($album->file_path() . "/.htaccess")); - } - - public function everybody_view_full_permission_maintains_htaccess_files_test() { - $root = ORM::factory("item", 1); - $album = album::create($root, rand(), "test album"); - - $this->assert_false(file_exists($album->file_path() . "/.htaccess")); - $this->assert_false(file_exists($album->resize_path() . "/.htaccess")); - $this->assert_false(file_exists($album->thumb_path() . "/.htaccess")); - - access::deny(group::everybody(), "view_full", $album); - $this->assert_true(file_exists($album->file_path() . "/.htaccess")); - $this->assert_false(file_exists($album->resize_path() . "/.htaccess")); - $this->assert_false(file_exists($album->thumb_path() . "/.htaccess")); - - access::allow(group::everybody(), "view_full", $album); - $this->assert_false(file_exists($album->file_path() . "/.htaccess")); - $this->assert_false(file_exists($album->resize_path() . "/.htaccess")); - $this->assert_false(file_exists($album->thumb_path() . "/.htaccess")); - - access::deny(group::everybody(), "view_full", $album); - $this->assert_true(file_exists($album->file_path() . "/.htaccess")); - $this->assert_false(file_exists($album->resize_path() . "/.htaccess")); - $this->assert_false(file_exists($album->thumb_path() . "/.htaccess")); - - access::reset(group::everybody(), "view_full", $album); - $this->assert_false(file_exists($album->file_path() . "/.htaccess")); - $this->assert_false(file_exists($album->resize_path() . "/.htaccess")); - $this->assert_false(file_exists($album->thumb_path() . "/.htaccess")); - } -} diff --git a/core/tests/Album_Helper_Test.php b/core/tests/Album_Helper_Test.php deleted file mode 100644 index 80afa8d1..00000000 --- a/core/tests/Album_Helper_Test.php +++ /dev/null @@ -1,87 +0,0 @@ -assert_equal(VARPATH . "albums/$rand", $album->file_path()); - $this->assert_equal(VARPATH . "thumbs/$rand/.album.jpg", $album->thumb_path()); - $this->assert_true(is_dir(VARPATH . "thumbs/$rand"), "missing thumb dir"); - - // It's unclear that a resize makes sense for an album. But we have one. - $this->assert_equal(VARPATH . "resizes/$rand/.album.jpg", $album->resize_path()); - $this->assert_true(is_dir(VARPATH . "resizes/$rand"), "missing resizes dir"); - - $this->assert_equal(1, $album->parent_id); // MPTT tests will cover other hierarchy checks - $this->assert_equal($rand, $album->name); - $this->assert_equal($rand, $album->title); - $this->assert_equal($rand, $album->description); - } - - public function create_conflicting_album_test() { - $rand = rand(); - $root = ORM::factory("item", 1); - $album1 = album::create($root, $rand, $rand, $rand); - $album2 = album::create($root, $rand, $rand, $rand); - $this->assert_true($album1->name != $album2->name); - } - - public function thumb_url_test() { - $rand = rand(); - $root = ORM::factory("item", 1); - $album = album::create($root, $rand, $rand, $rand); - $this->assert_equal("http://./var/thumbs/$rand/.album.jpg", $album->thumb_url()); - } - - public function resize_url_test() { - $rand = rand(); - $root = ORM::factory("item", 1); - $album = album::create($root, $rand, $rand, $rand); - $this->assert_equal("http://./var/resizes/$rand/.album.jpg", $album->resize_url()); - } - - public function create_album_shouldnt_allow_names_with_slash_test() { - $rand = rand(); - $root = ORM::factory("item", 1); - try { - $album = album::create($root, $rand . "/", $rand, $rand); - } catch (Exception $e) { - // pass - return; - } - - $this->assert_true(false, "Shouldn't create an album with / in the name"); - } - - public function create_album_silently_trims_trailing_periods_test() { - $rand = rand(); - $root = ORM::factory("item", 1); - try { - $album = album::create($root, $rand . "..", $rand, $rand); - } catch (Exception $e) { - $this->assert_equal("@todo NAME_CANNOT_END_IN_PERIOD", $e->getMessage()); - return; - } - - $this->assert_true(false, "Shouldn't create an album with trailing . in the name"); - } -} diff --git a/core/tests/Albums_Controller_Test.php b/core/tests/Albums_Controller_Test.php deleted file mode 100644 index ef1fac77..00000000 --- a/core/tests/Albums_Controller_Test.php +++ /dev/null @@ -1,76 +0,0 @@ -_post = $_POST; - } - - public function teardown() { - $_POST = $this->_post; - } - - public function change_album_test() { - $controller = new Albums_Controller(); - $root = ORM::factory("item", 1); - $album = album::create($root, "test", "test", "test"); - $orig_name = $album->name; - - $_POST["dirname"] = "test"; - $_POST["name"] = "new name"; - $_POST["title"] = "new title"; - $_POST["description"] = "new description"; - $_POST["column"] = "weight"; - $_POST["direction"] = "ASC"; - $_POST["csrf"] = access::csrf_token(); - $_POST["_method"] = "put"; - access::allow(group::everybody(), "edit", $root); - - ob_start(); - $controller->_update($album); - $results = ob_get_contents(); - ob_end_clean(); - - $this->assert_equal( - json_encode(array("result" => "success", "location" => "http://./index.php/test")), - $results); - $this->assert_equal("new title", $album->title); - $this->assert_equal("new description", $album->description); - - // We don't change the name, yet. - $this->assert_equal($orig_name, $album->name); - } - - public function change_album_no_csrf_fails_test() { - $controller = new Albums_Controller(); - $root = ORM::factory("item", 1); - $album = album::create($root, "test", "test", "test"); - $_POST["name"] = "new name"; - $_POST["title"] = "new title"; - $_POST["description"] = "new description"; - access::allow(group::everybody(), "edit", $root); - - try { - $controller->_update($album); - $this->assert_true(false, "This should fail"); - } catch (Exception $e) { - // pass - } - } -} diff --git a/core/tests/Core_Installer_Test.php b/core/tests/Core_Installer_Test.php deleted file mode 100644 index f7036286..00000000 --- a/core/tests/Core_Installer_Test.php +++ /dev/null @@ -1,50 +0,0 @@ -assert_true(file_exists(VARPATH . "albums")); - $this->assert_true(file_exists(VARPATH . "resizes")); - } - - public function install_registers_core_module_test() { - $core = ORM::factory("module")->where("name", "core")->find(); - $this->assert_equal("core", $core->name); - - // This is probably too volatile to keep for long - $this->assert_equal(1, $core->version); - } - - public function install_creates_root_item_test() { - $max_right = ORM::factory("item") - ->select("MAX(`right`) AS `right`") - ->find()->right; - $root = ORM::factory('item')->find(1); - $this->assert_equal("Gallery", $root->title); - $this->assert_equal(1, $root->left); - $this->assert_equal($max_right, $root->right); - $this->assert_equal(null, $root->parent_id); - $this->assert_equal(1, $root->level); - } -} diff --git a/core/tests/Database_Test.php b/core/tests/Database_Test.php deleted file mode 100644 index bd3d2f53..00000000 --- a/core/tests/Database_Test.php +++ /dev/null @@ -1,134 +0,0 @@ -where("a", 1) - ->where("b", 2) - ->compile(); - $sql = str_replace("\n", " ", $sql); - $this->assert_same("SELECT * WHERE `a` = 1 AND `b` = 2", $sql); - } - - function compound_where_test() { - $sql = Database::instance() - ->where("outer1", 1) - ->open_paren() - ->where("inner1", 1) - ->orwhere("inner2", 2) - ->close_paren() - ->where("outer2", 2) - ->compile(); - $sql = str_replace("\n", " ", $sql); - $this->assert_same( - "SELECT * WHERE `outer1` = 1 AND (`inner1` = 1 OR `inner2` = 2) AND `outer2` = 2", - $sql); - } - - function group_first_test() { - $sql = Database::instance() - ->open_paren() - ->where("inner1", 1) - ->orwhere("inner2", 2) - ->close_paren() - ->where("outer1", 1) - ->where("outer2", 2) - ->compile(); - $sql = str_replace("\n", " ", $sql); - $this->assert_same( - "SELECT * WHERE (`inner1` = 1 OR `inner2` = 2) AND `outer1` = 1 AND `outer2` = 2", - $sql); - } - - function where_array_test() { - $sql = Database::instance() - ->where("outer1", 1) - ->open_paren() - ->where("inner1", 1) - ->orwhere(array("inner2" => 2, "inner3" => 3)) - ->close_paren() - ->compile(); - $sql = str_replace("\n", " ", $sql); - $this->assert_same( - "SELECT * WHERE `outer1` = 1 AND (`inner1` = 1 OR `inner2` = 2 OR `inner3` = 3)", - $sql); - } - - function notlike_test() { - $sql = Database::instance() - ->where("outer1", 1) - ->open_paren() - ->ornotlike("inner1", 1) - ->close_paren() - ->compile(); - $sql = str_replace("\n", " ", $sql); - $this->assert_same( - "SELECT * WHERE `outer1` = 1 OR ( `inner1` NOT LIKE '%1%')", - $sql); - } - - function prefix_replacement_test() { - $db = Database_For_Test::instance(); - $converted = $db->add_table_prefixes("CREATE TABLE IF NOT EXISTS {test_tables} ( - `id` int(9) NOT NULL auto_increment, - `name` varchar(32) NOT NULL, - PRIMARY KEY (`id`), - UNIQUE KEY(`name`)) - ENGINE=InnoDB DEFAULT CHARSET=utf8"); - $expected = "CREATE TABLE IF NOT EXISTS g3test_test_tables ( - `id` int(9) NOT NULL auto_increment, - `name` varchar(32) NOT NULL, - PRIMARY KEY (`id`), - UNIQUE KEY(`name`)) - ENGINE=InnoDB DEFAULT CHARSET=utf8"; - $this->assert_same($expected, $converted); - - $sql = "UPDATE {test_tables} SET `name` = '{test string}' " . - "WHERE `item_id` IN " . - " (SELECT `id` FROM {items} " . - " WHERE `left` >= 1 " . - " AND `right` <= 6)"; - $sql = $db->add_table_prefixes($sql); - - $expected = "UPDATE g3test_test_tables SET `name` = '{test string}' " . - "WHERE `item_id` IN " . - " (SELECT `id` FROM g3test_items " . - " WHERE `left` >= 1 " . - " AND `right` <= 6)"; - - $this->assert_same($expected, $sql); - } - - public function setup() { - } - - public function teardown() { - } - -} - -class Database_For_Test extends Database { - static function instance() { - $db = new Database_For_Test(); - $db->_table_names["{items}"] = "g3test_items"; - $db->config["table_prefix"] = "g3test_"; - return $db; - } -} diff --git a/core/tests/Dir_Helper_Test.php b/core/tests/Dir_Helper_Test.php deleted file mode 100644 index 46bb871c..00000000 --- a/core/tests/Dir_Helper_Test.php +++ /dev/null @@ -1,32 +0,0 @@ -assert_boolean(!file_exists($filename), "File not deleted"); - $this->assert_boolean(!file_exists($dirname), "Directory not deleted"); - } -} diff --git a/core/tests/DrawForm_Test.php b/core/tests/DrawForm_Test.php deleted file mode 100644 index 2c5aaba4..00000000 --- a/core/tests/DrawForm_Test.php +++ /dev/null @@ -1,84 +0,0 @@ - "gTestGroupForm")); - $form->input("title")->label(t("Title")); - $form->textarea("description")->label(t("Text Area")); - $form->submit("")->value(t("Submit")); - $rendered = $form->__toString(); - - $expected = "
    \n" . - "\n" . - "
      \n" . - "
    • \n" . - " \n" . - " \n" . - "
    • \n" . - "
    • \n" . - " \n" . - " \n" . - "
    • \n" . - "
    • \n" . - " \n" . - "
    • \n" . - "
    \n" . - "
    \n"; - $this->assert_same($expected, $rendered); - } - - function group_test() { - $form = new Forge("test/controller", "", "post", array("id" => "gTestGroupForm")); - $group = $form->group("test_group")->label(t("Test Group")); - $group->input("title")->label(t("Title")); - $group->textarea("description")->label(t("Text Area")); - $group->submit("")->value(t("Submit")); - $rendered = $form->__toString(); - - $expected = "
    \n" . - "\n" . - "
    \n" . - " Test Group\n" . - "
      \n" . - "
    • \n" . - " \n" . - " \n" . - "
    • \n" . - "
    • \n" . - " \n" . - " \n" . - "
    • \n" . - "
    • \n" . - " \n" . - "
    • \n" . - "
    \n" . - "
    \n" . - "
    \n"; - $this->assert_same($expected, $rendered); - } - -} - diff --git a/core/tests/File_Structure_Test.php b/core/tests/File_Structure_Test.php deleted file mode 100644 index 1caa82ba..00000000 --- a/core/tests/File_Structure_Test.php +++ /dev/null @@ -1,235 +0,0 @@ -getPathname())) { - $this->assert_false( - preg_match('/\?\>\s*$/', file_get_contents($file)), - "{$file->getPathname()} ends in ?>"); - } - } - } - - public function view_files_correct_suffix_test() { - $dir = new GalleryCodeFilterIterator( - new RecursiveIteratorIterator(new RecursiveDirectoryIterator(DOCROOT))); - foreach ($dir as $file) { - if (strpos($file, "views")) { - $this->assert_true( - preg_match("#/views/.*?(\.html|mrss|txt)\.php$#", $file->getPathname()), - "{$file->getPathname()} should end in .{html,mrss,txt}.php"); - } - } - } - - public function no_windows_line_endings_test() { - $dir = new GalleryCodeFilterIterator( - new RecursiveIteratorIterator(new RecursiveDirectoryIterator(DOCROOT))); - foreach ($dir as $file) { - if (preg_match("/\.(php|css|html|js)$/", $file)) { - foreach (file($file) as $line) { - $this->assert_true(substr($line, -2) != "\r\n", "$file has windows style line endings"); - } - } - } - } - - private function _check_view_preamble($path, &$errors) { - // The preamble for views is a single line that prevents direct script access - if (strpos($path, SYSPATH) === 0) { - // Kohana preamble - $expected = "\n"; - } else { - // Gallery preamble - // @todo use the same preamble for both! - $expected = "\n"; - } - - $fp = fopen($path, "r"); - $actual = fgets($fp); - fclose($fp); - - if ($expected != $actual) { - $errors[] = "$path:1\n expected:\n\t$expected\n actual:\n\t$actual"; - } - } - - private function _check_php_preamble($path, &$errors) { - if (strpos($path, SYSPATH) === 0 || - strpos($path, MODPATH . "unit_test") === 0) { - // Kohana: we only care about the first line - $fp = fopen($path, "r"); - $actual = array(fgets($fp)); - fclose($fp); - $expected = array("_get_preamble($path); - $expected = array( - "getPathname(); - switch ($path) { - case DOCROOT . "installer/database_config.php": - case DOCROOT . "installer/init_var.php": - // Special case views - $this->_check_view_preamble($path, $errors); - break; - - case DOCROOT . "index.php": - case DOCROOT . "installer/index.php": - // Front controllers - break; - - case DOCROOT . "index.local.php": - // Special case optional file, not part of the codebase - break; - - default: - if (strpos($path, DOCROOT . "var/logs") === 0) { - continue; - } else if (preg_match("/views/", $path)) { - $this->_check_view_preamble($path, $errors); - } else { - $this->_check_php_preamble($path, $errors); - } - } - } - - if ($errors) { - $this->assert_false(true, "Preamble errors:\n" . join("\n", $errors)); - } - } - - public function no_tabs_in_our_code_test() { - $dir = new PhpCodeFilterIterator( - new GalleryCodeFilterIterator( - new RecursiveIteratorIterator( - new RecursiveDirectoryIterator(DOCROOT)))); - foreach ($dir as $file) { - $this->assert_false( - preg_match('/\t/', file_get_contents($file)), - "{$file->getPathname()} has tabs in it"); - } - } - - private function _get_preamble($file) { - $lines = file($file); - $copy = array(); - for ($i = 0; $i < count($lines); $i++) { - $copy[] = rtrim($lines[$i]); - if (!strncmp($lines[$i], ' */', 3)) { - return $copy; - } - } - return $copy; - } - - public function helpers_are_static_test() { - $dir = new PhpCodeFilterIterator( - new GalleryCodeFilterIterator( - new RecursiveIteratorIterator( - new RecursiveDirectoryIterator(DOCROOT)))); - foreach ($dir as $file) { - if (basename(dirname($file)) == "helpers") { - foreach (file($file) as $line) { - $this->assert_true( - !preg_match("/\sfunction\s.*\(/", $line) || - preg_match("/^\s*(private static function _|static function)/", $line), - "should be \"static function foo\" or \"private static function _foo\":\n" . - "$file\n$line\n"); - } - } - } - } -} - -class PhpCodeFilterIterator extends FilterIterator { - public function accept() { - $path_name = $this->getInnerIterator()->getPathName(); - return (substr($path_name, -4) == ".php" && - !(strpos($path_name, VARPATH) === 0)); - } -} - -class GalleryCodeFilterIterator extends FilterIterator { - public function accept() { - // Skip anything that we didn"t write - $path_name = $this->getInnerIterator()->getPathName(); - return !( - strpos($path_name, ".svn") || - strpos($path_name, "core/views/kohana_profiler.php") !== false || - strpos($path_name, DOCROOT . "test") !== false || - strpos($path_name, DOCROOT . "var") !== false || - strpos($path_name, MODPATH . "forge") !== false || - strpos($path_name, APPPATH . "views/kohana_error_page.php") !== false || - strpos($path_name, MODPATH . "gallery_unit_test/views/kohana_error_page.php") !== false || - strpos($path_name, MODPATH . "gallery_unit_test/views/kohana_unit_test_cli.php") !== false || - strpos($path_name, MODPATH . "unit_test") !== false || - strpos($path_name, MODPATH . "exif/lib") !== false || - strpos($path_name, MODPATH . "user/lib/PasswordHash") !== false || - strpos($path_name, DOCROOT . "lib/swfupload") !== false || - strpos($path_name, SYSPATH) !== false || - substr($path_name, -1, 1) == "~"); - } -} diff --git a/core/tests/I18n_Test.php b/core/tests/I18n_Test.php deleted file mode 100644 index 9010606a..00000000 --- a/core/tests/I18n_Test.php +++ /dev/null @@ -1,108 +0,0 @@ - 'en', - 'default_locale' => 'te_ST', - 'locale_dir' => VARPATH . 'locale/'); - $this->i18n = I18n::instance($config); - - ORM::factory("incoming_translation") - ->where("locale", "te_ST") - ->delete_all(); - - $messages_te_ST = array( - array('Hello world', 'Hallo Welt'), - array(array('one' => 'One item has been added', - 'other' => '%count elements have been added'), - array('one' => 'Ein Element wurde hinzugefuegt.', - 'other' => '%count Elemente wurden hinzugefuegt.')), - array('Hello %name, how are you today?', 'Hallo %name, wie geht es Dir heute?')); - - foreach ($messages_te_ST as $data) { - list ($message, $translation) = $data; - $entry = ORM::factory("incoming_translation"); - $entry->key = I18n::get_message_key($message); - $entry->message = serialize($message); - $entry->translation = serialize($translation); - $entry->locale = 'te_ST'; - $entry->revision = null; - $entry->save(); - } - } - - public function get_locale_test() { - $locale = $this->i18n->locale(); - $this->assert_equal("te_ST", $locale); - } - - public function set_locale_test() { - $this->i18n->locale("de_DE"); - $locale = $this->i18n->locale(); - $this->assert_equal("de_DE", $locale); - } - - public function translate_simple_test() { - $result = $this->i18n->translate('Hello world'); - $this->assert_equal('Hallo Welt', $result); - } - - public function translate_simple_root_fallback_test() { - $result = $this->i18n->translate('Hello world zzz'); - $this->assert_equal('Hello world zzz', $result); - } - - public function translate_plural_other_test() { - $result = $this->i18n->translate(array('one' => 'One item has been added', - 'other' => '%count elements have been added'), - array('count' => 5)); - $this->assert_equal('5 Elemente wurden hinzugefuegt.', $result); - } - - public function translate_plural_one_test() { - $result = $this->i18n->translate(array('one' => 'One item has been added', - 'other' => '%count elements have been added'), - array('count' => 1)); - $this->assert_equal('Ein Element wurde hinzugefuegt.', $result); - } - - public function translate_interpolate_test() { - $result = $this->i18n->translate('Hello %name, how are you today?', array('name' => 'John')); - $this->assert_equal('Hallo John, wie geht es Dir heute?', $result); - } - - public function translate_interpolate_missing_value_test() { - $result = $this->i18n->translate('Hello %name, how are you today?', array('foo' => 'bar')); - $this->assert_equal('Hallo %name, wie geht es Dir heute?', $result); - } - - public function translate_plural_zero_test() { - // te_ST has the same plural rules as en and de. - // For count 0, plural form "other" should be used. - $result = $this->i18n->translate(array('one' => 'One item has been added', - 'other' => '%count elements have been added'), - array('count' => 0)); - $this->assert_equal('0 Elemente wurden hinzugefuegt.', $result); - } -} \ No newline at end of file diff --git a/core/tests/Item_Model_Test.php b/core/tests/Item_Model_Test.php deleted file mode 100644 index 615b8997..00000000 --- a/core/tests/Item_Model_Test.php +++ /dev/null @@ -1,143 +0,0 @@ -assert_true(!empty($item->created)); - $this->assert_true(!empty($item->updated)); - } - - private function create_random_item() { - $item = ORM::factory("item"); - /* Set all required fields (values are irrelevant) */ - $item->name = rand(); - $item->type = "photo"; - return $item->add_to_parent(ORM::factory("item", 1)); - } - - public function updating_doesnt_change_created_date_test() { - $item = self::create_random_item(); - - // Force the creation date to something well known - $db = Database::instance(); - $db->update("items", array("created" => 0, "updated" => 0), array("id" => $item->id)); - $item->reload(); - $item->title = "foo"; // force a change - $item->save(); - - $this->assert_true(empty($item->created)); - $this->assert_true(!empty($item->updated)); - } - - public function updating_view_count_only_doesnt_change_updated_date_test() { - $item = self::create_random_item(); - $item->reload(); - $this->assert_same(0, $item->view_count); - - // Force the updated date to something well known - $db = Database::instance(); - $db->update("items", array("updated" => 0), array("id" => $item->id)); - $item->reload(); - $item->view_count++; - $item->save(); - - $this->assert_same(1, $item->view_count); - $this->assert_true(empty($item->updated)); - } - - public function move_photo_test() { - // Create a test photo - $item = self::create_random_item(); - - file_put_contents($item->thumb_path(), "thumb"); - file_put_contents($item->resize_path(), "resize"); - file_put_contents($item->file_path(), "file"); - - $original_name = $item->name; - $new_name = rand(); - - // Now rename it - $item->rename($new_name)->save(); - - // Expected: the name changed, the name is now baked into all paths, and all files were moved. - $this->assert_equal($new_name, $item->name); - $this->assert_equal($new_name, basename($item->file_path())); - $this->assert_equal($new_name, basename($item->thumb_path())); - $this->assert_equal($new_name, basename($item->resize_path())); - $this->assert_equal("thumb", file_get_contents($item->thumb_path())); - $this->assert_equal("resize", file_get_contents($item->resize_path())); - $this->assert_equal("file", file_get_contents($item->file_path())); - } - - public function move_album_test() { - // Create an album with a photo in it - $root = ORM::factory("item", 1); - $album = album::create($root, rand(), rand(), rand()); - $photo = ORM::factory("item"); - $photo->name = rand(); - $photo->type = "photo"; - $photo->add_to_parent($album); - - file_put_contents($photo->thumb_path(), "thumb"); - file_put_contents($photo->resize_path(), "resize"); - file_put_contents($photo->file_path(), "file"); - - $original_album_name = $album->name; - $original_photo_name = $photo->name; - $new_album_name = rand(); - - // Now rename the album - $album->rename($new_album_name)->save(); - $photo->reload(); - - // Expected: - // * the album name changed. - // * the album dirs are all moved - // * the photo's paths are all inside the albums paths - // * the photo files are all still intact and accessible - $this->assert_equal($new_album_name, $album->name); - $this->assert_equal($new_album_name, basename($album->file_path())); - $this->assert_equal($new_album_name, basename(dirname($album->thumb_path()))); - $this->assert_equal($new_album_name, basename(dirname($album->resize_path()))); - - $this->assert_same(0, strpos($photo->file_path(), $album->file_path())); - $this->assert_same(0, strpos($photo->thumb_path(), dirname($album->thumb_path()))); - $this->assert_same(0, strpos($photo->resize_path(), dirname($album->resize_path()))); - - $this->assert_equal("thumb", file_get_contents($photo->thumb_path())); - $this->assert_equal("resize", file_get_contents($photo->resize_path())); - $this->assert_equal("file", file_get_contents($photo->file_path())); - } - - public function item_rename_wont_accept_slash_test() { - // Create a test photo - $item = self::create_random_item(); - - $new_name = rand() . "/"; - - try { - $item->rename($new_name)->save(); - } catch (Exception $e) { - // pass - return; - } - $this->assert_false(true, "Item_Model::rename should not accept / characters"); - } -} diff --git a/core/tests/Menu_Test.php b/core/tests/Menu_Test.php deleted file mode 100644 index c91aee0b..00000000 --- a/core/tests/Menu_Test.php +++ /dev/null @@ -1,32 +0,0 @@ -append(Menu::factory("link")->id("element_1")) - ->append(Menu::factory("dialog")->id("element_2")) - ->append(Menu::factory("submenu")->id("element_3") - ->append(Menu::factory("link")->id("element_3_1"))); - - $this->assert_equal("element_2", $menu->get("element_2")->id); - $this->assert_equal("element_3_1", $menu->get("element_3")->get("element_3_1")->id); - } -} \ No newline at end of file diff --git a/core/tests/Movie_Helper_Test.php b/core/tests/Movie_Helper_Test.php deleted file mode 100644 index b92ef3f8..00000000 --- a/core/tests/Movie_Helper_Test.php +++ /dev/null @@ -1,46 +0,0 @@ -assert_true(false, "Shouldn't create a movie with / in the name"); - } - - public function create_movie_shouldnt_allow_names_with_trailing_periods_test() { - $rand = rand(); - $root = ORM::factory("item", 1); - try { - $movie = movie::create($root, DOCROOT . "core/tests/test.jpg", "$rand.jpg.", $rand, $rand); - } catch (Exception $e) { - $this->assert_equal("@todo NAME_CANNOT_END_IN_PERIOD", $e->getMessage()); - return; - } - - $this->assert_true(false, "Shouldn't create a movie with trailing . in the name"); - } -} diff --git a/core/tests/ORM_MPTT_Test.php b/core/tests/ORM_MPTT_Test.php deleted file mode 100644 index 200c8a74..00000000 --- a/core/tests/ORM_MPTT_Test.php +++ /dev/null @@ -1,221 +0,0 @@ -type = "album"; - $album->rand_key = ((float)mt_rand()) / (float)mt_getrandmax(); - $album->sort_column = "weight"; - $album->sort_order = "ASC"; - $album->add_to_parent($root); - - $this->assert_equal($album->parent()->right - 2, $album->left); - $this->assert_equal($album->parent()->right - 1, $album->right); - $this->assert_equal($album->parent()->level + 1, $album->level); - $this->assert_equal($album->parent()->id, $album->parent_id); - } - - public function add_hierarchy_test() { - $root = ORM::factory("item", 1); - $album1 = self::create_item_and_add_to_parent($root); - $album1_1 = self::create_item_and_add_to_parent($album1); - $album1_2 = self::create_item_and_add_to_parent($album1); - $album1_1_1 = self::create_item_and_add_to_parent($album1_1); - $album1_1_2 = self::create_item_and_add_to_parent($album1_1); - - $album1->reload(); - $this->assert_equal(9, $album1->right - $album1->left); - - $album1_1->reload(); - $this->assert_equal(5, $album1_1->right - $album1_1->left); - } - - public function delete_hierarchy_test() { - $root = ORM::factory("item", 1); - $album1 = self::create_item_and_add_to_parent($root); - $album1_1 = self::create_item_and_add_to_parent($album1); - $album1_2 = self::create_item_and_add_to_parent($album1); - $album1_1_1 = self::create_item_and_add_to_parent($album1_1); - $album1_1_2 = self::create_item_and_add_to_parent($album1_1); - - $album1_1->delete(); - $album1->reload(); - - // Now album1 contains only album1_2 - $this->assert_equal(3, $album1->right - $album1->left); - } - - public function move_to_test() { - $root = ORM::factory("item", 1); - $album1 = album::create($root, "move_to_test_1", "move_to_test_1"); - $album1_1 = album::create($album1, "move_to_test_1_1", "move_to_test_1_1"); - $album1_2 = album::create($album1, "move_to_test_1_2", "move_to_test_1_2"); - $album1_1_1 = album::create($album1_1, "move_to_test_1_1_1", "move_to_test_1_1_1"); - $album1_1_2 = album::create($album1_1, "move_to_test_1_1_2", "move_to_test_1_1_2"); - - $album1_2->reload(); - $album1_1_1->reload(); - - $album1_1_1->move_to($album1_2); - - $album1_1->reload(); - $album1_2->reload(); - - $this->assert_equal(3, $album1_1->right - $album1_1->left); - $this->assert_equal(3, $album1_2->right - $album1_2->left); - - $this->assert_equal( - array($album1_1_2->id => "move_to_test_1_1_2"), - $album1_1->children()->select_list()); - - $this->assert_equal( - array($album1_1_1->id => "move_to_test_1_1_1"), - $album1_2->children()->select_list()); - } - - public function parent_test() { - $root = ORM::factory("item", 1); - $album = self::create_item_and_add_to_parent($root); - - $parent = ORM::factory("item", 1); - $this->assert_equal($parent->id, $album->parent()->id); - } - - public function parents_test() { - $root = ORM::factory("item", 1); - $outer = self::create_item_and_add_to_parent($root); - $inner = self::create_item_and_add_to_parent($outer); - - $parent_ids = array(); - foreach ($inner->parents() as $parent) { - $parent_ids[] = $parent->id; - } - $this->assert_equal(array(1, $outer->id), $parent_ids); - } - - public function children_test() { - $root = ORM::factory("item", 1); - $outer = self::create_item_and_add_to_parent($root); - $inner1 = self::create_item_and_add_to_parent($outer); - $inner2 = self::create_item_and_add_to_parent($outer); - - $child_ids = array(); - foreach ($outer->children() as $child) { - $child_ids[] = $child->id; - } - $this->assert_equal(array($inner1->id, $inner2->id), $child_ids); - } - - public function children_limit_test() { - $root = ORM::factory("item", 1); - $outer = self::create_item_and_add_to_parent($root); - $inner1 = self::create_item_and_add_to_parent($outer); - $inner2 = self::create_item_and_add_to_parent($outer); - - $this->assert_equal(array($inner2->id => $inner2->name), - $outer->children(1, 1)->select_list('id')); - } - - public function children_count_test() { - $root = ORM::factory("item", 1); - $outer = self::create_item_and_add_to_parent($root); - $inner1 = self::create_item_and_add_to_parent($outer); - $inner2 = self::create_item_and_add_to_parent($outer); - - $this->assert_equal(2, $outer->children_count()); - } - - public function descendant_test() { - $root = ORM::factory("item", 1); - - $parent = ORM::factory("item"); - $parent->type = "album"; - $parent->rand_key = ((float)mt_rand()) / (float)mt_getrandmax(); - $parent->sort_column = "weight"; - $parent->sort_order = "ASC"; - $parent->add_to_parent($root); - - $photo = ORM::factory("item"); - $photo->type = "photo"; - $photo->add_to_parent($parent); - - $album1 = ORM::factory("item"); - $album1->type = "album"; - $album1->rand_key = ((float)mt_rand()) / (float)mt_getrandmax(); - $album1->sort_column = "weight"; - $album1->sort_order = "ASC"; - $album1->add_to_parent($parent); - - $photo1 = ORM::factory("item"); - $photo1->type = "photo"; - $photo1->add_to_parent($album1); - - $parent->reload(); - - $this->assert_equal(3, $parent->descendants()->count()); - $this->assert_equal(2, $parent->descendants(null, 0, "photo")->count()); - $this->assert_equal(1, $parent->descendants(null, 0, "album")->count()); - } - - public function descendant_limit_test() { - $root = ORM::factory("item", 1); - - $parent = self::create_item_and_add_to_parent($root); - $album1 = self::create_item_and_add_to_parent($parent); - $album2 = self::create_item_and_add_to_parent($parent); - $album3 = self::create_item_and_add_to_parent($parent); - - $parent->reload(); - $this->assert_equal(2, $parent->descendants(2)->count()); - } - - public function descendant_count_test() { - $root = ORM::factory("item", 1); - - $parent = ORM::factory("item"); - $parent->type = "album"; - $parent->add_to_parent($root); - - $photo = ORM::factory("item"); - $photo->type = "photo"; - $photo->add_to_parent($parent); - - $album1 = ORM::factory("item"); - $album1->type = "album"; - $album1->add_to_parent($parent); - - $photo1 = ORM::factory("item"); - $photo1->type = "photo"; - $photo1->add_to_parent($album1); - - $parent->reload(); - - $this->assert_equal(3, $parent->descendants_count()); - $this->assert_equal(2, $parent->descendants_count("photo")); - $this->assert_equal(1, $parent->descendants_count("album")); - } -} diff --git a/core/tests/Photo_Helper_Test.php b/core/tests/Photo_Helper_Test.php deleted file mode 100644 index deb11bb9..00000000 --- a/core/tests/Photo_Helper_Test.php +++ /dev/null @@ -1,109 +0,0 @@ -assert_equal(VARPATH . "albums/$rand.jpg", $photo->file_path()); - $this->assert_equal(VARPATH . "thumbs/{$rand}.jpg", $photo->thumb_path()); - $this->assert_equal(VARPATH . "resizes/{$rand}.jpg", $photo->resize_path()); - - $this->assert_true(is_file($photo->file_path()), "missing: {$photo->file_path()}"); - $this->assert_true(is_file($photo->resize_path()), "missing: {$photo->resize_path()}"); - $this->assert_true(is_file($photo->thumb_path()), "missing: {$photo->thumb_path()}"); - - $this->assert_equal($root->id, $photo->parent_id); // MPTT tests cover other hierarchy checks - $this->assert_equal("$rand.jpg", $photo->name); - $this->assert_equal($rand, $photo->title); - $this->assert_equal($rand, $photo->description); - $this->assert_equal("image/jpeg", $photo->mime_type); - $this->assert_equal($image_info[0], $photo->width); - $this->assert_equal($image_info[1], $photo->height); - - $this->assert_equal($photo->parent()->right - 2, $photo->left); - $this->assert_equal($photo->parent()->right - 1, $photo->right); - } - - public function create_conflicting_photo_test() { - $rand = rand(); - $root = ORM::factory("item", 1); - $photo1 = photo::create($root, DOCROOT . "core/tests/test.jpg", "$rand.jpg", $rand, $rand); - $photo2 = photo::create($root, DOCROOT . "core/tests/test.jpg", "$rand.jpg", $rand, $rand); - $this->assert_true($photo1->name != $photo2->name); - } - - public function create_photo_with_no_extension_test() { - $root = ORM::factory("item", 1); - try { - photo::create($root, "/tmp", "name", "title", "description"); - $this->assert_false("should fail with an exception"); - } catch (Exception $e) { - // pass - } - } - - public function thumb_url_test() { - $rand = rand(); - $root = ORM::factory("item", 1); - $photo = photo::create($root, DOCROOT . "core/tests/test.jpg", "$rand.jpg", $rand, $rand); - $this->assert_equal("http://./var/thumbs/{$rand}.jpg", $photo->thumb_url()); - } - - public function resize_url_test() { - $rand = rand(); - $root = ORM::factory("item", 1); - $album = album::create($root, $rand, $rand, $rand); - $photo = photo::create($album, DOCROOT . "core/tests/test.jpg", "$rand.jpg", $rand, $rand); - - $this->assert_equal("http://./var/resizes/{$rand}/{$rand}.jpg", $photo->resize_url()); - } - - public function create_photo_shouldnt_allow_names_with_slash_test() { - $rand = rand(); - $root = ORM::factory("item", 1); - try { - $photo = photo::create($root, DOCROOT . "core/tests/test.jpg", "$rand/.jpg", $rand, $rand); - } catch (Exception $e) { - // pass - return; - } - - $this->assert_true(false, "Shouldn't create a photo with / in the name"); - } - - public function create_photo_silently_trims_trailing_periods_test() { - $rand = rand(); - $root = ORM::factory("item", 1); - try { - $photo = photo::create($root, DOCROOT . "core/tests/test.jpg", "$rand.jpg.", $rand, $rand); - } catch (Exception $e) { - $this->assert_equal("@todo NAME_CANNOT_END_IN_PERIOD", $e->getMessage()); - return; - } - - $this->assert_true(false, "Shouldn't create a photo with trailing . in the name"); - } -} diff --git a/core/tests/Photos_Controller_Test.php b/core/tests/Photos_Controller_Test.php deleted file mode 100644 index 71319315..00000000 --- a/core/tests/Photos_Controller_Test.php +++ /dev/null @@ -1,74 +0,0 @@ -_post = $_POST; - } - - public function teardown() { - $_POST = $this->_post; - } - - public function change_photo_test() { - $controller = new Photos_Controller(); - $root = ORM::factory("item", 1); - $photo = photo::create($root, DOCROOT . "core/tests/test.jpg", "test.jpeg", "test", "test"); - $orig_name = $photo->name; - - $_POST["filename"] = "test.jpeg"; - $_POST["name"] = "new name"; - $_POST["title"] = "new title"; - $_POST["description"] = "new description"; - $_POST["csrf"] = access::csrf_token(); - access::allow(group::everybody(), "edit", $root); - - ob_start(); - $controller->_update($photo); - $results = ob_get_contents(); - ob_end_clean(); - - $this->assert_equal( - json_encode(array("result" => "success", - "location" => "http://./index.php/test.jpeg")), - $results); - $this->assert_equal("new title", $photo->title); - $this->assert_equal("new description", $photo->description); - - // We don't change the name, yet. - $this->assert_equal($orig_name, $photo->name); - } - - public function change_photo_no_csrf_fails_test() { - $controller = new Photos_Controller(); - $root = ORM::factory("item", 1); - $photo = photo::create($root, DOCROOT . "core/tests/test.jpg", "test", "test", "test"); - $_POST["name"] = "new name"; - $_POST["title"] = "new title"; - $_POST["description"] = "new description"; - access::allow(group::everybody(), "edit", $root); - - try { - $controller->_update($photo); - $this->assert_true(false, "This should fail"); - } catch (Exception $e) { - // pass - } - } -} diff --git a/core/tests/REST_Controller_Test.php b/core/tests/REST_Controller_Test.php deleted file mode 100644 index 8fb04d86..00000000 --- a/core/tests/REST_Controller_Test.php +++ /dev/null @@ -1,197 +0,0 @@ -_post = $_POST; - $this->mock_controller = new Mock_RESTful_Controller("mock"); - $this->mock_not_loaded_controller = new Mock_RESTful_Controller("mock_not_loaded"); - $_POST = array(); - } - - public function teardown() { - $_POST = $this->_post; - } - - public function dispatch_index_test() { - $_SERVER["REQUEST_METHOD"] = "GET"; - $_POST["_method"] = ""; - $this->mock_controller->__call("index", ""); - $this->assert_equal("index", $this->mock_controller->method_called); - } - - public function dispatch_show_test() { - $_SERVER["REQUEST_METHOD"] = "GET"; - $_POST["_method"] = ""; - $this->mock_controller->__call("3", ""); - $this->assert_equal("show", $this->mock_controller->method_called); - $this->assert_equal("Mock_Model", get_class($this->mock_controller->resource)); - } - - public function dispatch_update_test() { - $_SERVER["REQUEST_METHOD"] = "POST"; - $_POST["_method"] = "PUT"; - $_POST["csrf"] = access::csrf_token(); - $this->mock_controller->__call("3", ""); - $this->assert_equal("update", $this->mock_controller->method_called); - $this->assert_equal("Mock_Model", get_class($this->mock_controller->resource)); - } - - public function dispatch_update_fails_without_csrf_test() { - $_SERVER["REQUEST_METHOD"] = "POST"; - $_POST["_method"] = "PUT"; - try { - $this->mock_controller->__call("3", ""); - $this->assert_false(true, "this should fail with a forbidden exception"); - } catch (Exception $e) { - // pass - } - } - - public function dispatch_delete_test() { - $_SERVER["REQUEST_METHOD"] = "POST"; - $_POST["_method"] = "DELETE"; - $_POST["csrf"] = access::csrf_token(); - $this->mock_controller->__call("3", ""); - $this->assert_equal("delete", $this->mock_controller->method_called); - $this->assert_equal("Mock_Model", get_class($this->mock_controller->resource)); - } - - public function dispatch_delete_fails_without_csrf_test() { - $_SERVER["REQUEST_METHOD"] = "POST"; - $_POST["_method"] = "DELETE"; - try { - $this->mock_controller->__call("3", ""); - $this->assert_false(true, "this should fail with a forbidden exception"); - } catch (Exception $e) { - // pass - } - } - - public function dispatch_404_test() { - /* The dispatcher should throw a 404 if the resource isn't loaded and the method isn't POST. */ - $methods = array( - array("GET", ""), - array("POST", "PUT"), - array("POST", "DELETE")); - - foreach ($methods as $method) { - $_SERVER["REQUEST_METHOD"] = $method[0]; - $_POST["_method"] = $method[1]; - $exception_caught = false; - try { - $this->mock_not_loaded_controller->__call(rand(), ""); - } catch (Kohana_404_Exception $e) { - $exception_caught = true; - } - $this->assert_true($exception_caught, "$method[0], $method[1]"); - } - } - - public function dispatch_create_test() { - $_SERVER["REQUEST_METHOD"] = "POST"; - $_POST["_method"] = ""; - $_POST["csrf"] = access::csrf_token(); - $this->mock_not_loaded_controller->__call("", ""); - $this->assert_equal("create", $this->mock_not_loaded_controller->method_called); - $this->assert_equal( - "Mock_Not_Loaded_Model", get_class($this->mock_not_loaded_controller->resource)); - } - - public function dispatch_create_fails_without_csrf_test() { - $_SERVER["REQUEST_METHOD"] = "POST"; - $_POST["_method"] = ""; - try { - $this->mock_not_loaded_controller->__call("", ""); - $this->assert_false(true, "this should fail with a forbidden exception"); - } catch (Exception $e) { - // pass - } - } - - public function dispatch_form_test_add() { - $this->mock_controller->form_add("args"); - $this->assert_equal("form_add", $this->mock_controller->method_called); - $this->assert_equal("args", $this->mock_controller->resource); - } - - public function dispatch_form_test_edit() { - $this->mock_controller->form_edit("1"); - $this->assert_equal("form_edit", $this->mock_controller->method_called); - $this->assert_equal("Mock_Model", get_class($this->mock_controller->resource)); - } - - public function routes_test() { - $this->assert_equal("mock/form_add/args", router::routed_uri("form/add/mock/args")); - $this->assert_equal("mock/form_edit/args", router::routed_uri("form/edit/mock/args")); - $this->assert_equal(null, router::routed_uri("rest/args")); - } -} - -class Mock_RESTful_Controller extends REST_Controller { - public $method_called; - public $resource; - - public function __construct($type) { - $this->resource_type = $type; - parent::__construct(); - } - - public function _index() { - $this->method_called = "index"; - } - - public function _create($resource) { - $this->method_called = "create"; - $this->resource = $resource; - } - - public function _show($resource) { - $this->method_called = "show"; - $this->resource = $resource; - } - - public function _update($resource) { - $this->method_called = "update"; - $this->resource = $resource; - } - - public function _delete($resource) { - $this->method_called = "delete"; - $this->resource = $resource; - } - - public function _form_add($args) { - $this->method_called = "form_add"; - $this->resource = $args; - } - - public function _form_edit($resource) { - $this->method_called = "form_edit"; - $this->resource = $resource; - } -} - -class Mock_Model { - public $loaded = true; -} - -class Mock_Not_Loaded_Model { - public $loaded = false; -} diff --git a/core/tests/REST_Helper_Test.php b/core/tests/REST_Helper_Test.php deleted file mode 100644 index 1bfc63ab..00000000 --- a/core/tests/REST_Helper_Test.php +++ /dev/null @@ -1,45 +0,0 @@ -_post = $_POST; - } - - public function teardown() { - $_POST = $this->_post; - } - - public function request_method_test() { - foreach (array("GET", "POST") as $method) { - foreach (array("", "PUT", "DELETE") as $tunnel) { - if ($method == "GET") { - $expected = "GET"; - } else { - $expected = $tunnel == "" ? $method : $tunnel; - } - $_SERVER["REQUEST_METHOD"] = $method; - $_POST["_method"] = $tunnel; - - $this->assert_equal(strtolower(rest::request_method()), strtolower($expected), - "Request method: {$method}, tunneled: {$tunnel}"); - } - } - } -} diff --git a/core/tests/Sendmail_Test.php b/core/tests/Sendmail_Test.php deleted file mode 100644 index 64c1fff0..00000000 --- a/core/tests/Sendmail_Test.php +++ /dev/null @@ -1,115 +0,0 @@ -to("receiver@someemail.com") - /* - * @todo figure out why this test fails so badly, when the following - * line is not supplied. It doesn't seem to be set by setup method - * as you would expect. - */ - ->from("from@gallery3.com") - ->subject("Test Email Unit test") - ->message("The mail message body") - ->send() - ->send_text; - - $this->assert_equal($expected, $result); - } - - public function sendmail_reply_to_test() { - $expected = "To: receiver@someemail.com\r\n" . - "From: from@gallery3.com\n" . - "Reply-To: reply-to@gallery3.com\r\n" . - "Subject: Test Email Unit test\r\n\r\n" . - "The mail message body"; - $result = Sendmail_For_Test::factory() - ->to("receiver@someemail.com") - ->subject("Test Email Unit test") - ->reply_to("reply-to@gallery3.com") - ->message("The mail message body") - ->send() - ->send_text; - $this->assert_equal($expected, $result); - } - - public function sendmail_html_message_test() { - $expected = "To: receiver@someemail.com\r\n" . - "From: from@gallery3.com\n" . - "Reply-To: public@gallery3.com\n" . - "MIME-Version: 1.0\n" . - "Content-type: text/html; charset=iso-8859-1\r\n" . - "Subject: Test Email Unit test\r\n\r\n" . - "

    This is an html msg

    "; - $result = Sendmail_For_Test::factory() - ->to("receiver@someemail.com") - ->subject("Test Email Unit test") - ->header("MIME-Version", "1.0") - ->header("Content-type", "text/html; charset=iso-8859-1") - ->message("

    This is an html msg

    ") - ->send() - ->send_text; - $this->assert_equal($expected, $result); - } - - public function sendmail_wrapped_message_test() { - $expected = "To: receiver@someemail.com\r\n" . - "From: from@gallery3.com\n" . - "Reply-To: public@gallery3.com\r\n" . - "Subject: Test Email Unit test\r\n\r\n" . - "This is a long message that needs to go\n" . - "over forty characters If we get lucky we\n" . - "might make it long enought to wrap a\n" . - "couple of times."; - $result = Sendmail_For_Test::factory() - ->to("receiver@someemail.com") - ->subject("Test Email Unit test") - ->line_length(40) - ->message("This is a long message that needs to go over forty characters " . - "If we get lucky we might make it long enought to wrap a couple " . - "of times.") - ->send() - ->send_text; - $this->assert_equal($expected, $result); - } -} - -class Sendmail_For_Test extends Sendmail { - static function factory() { - return new Sendmail_For_Test(); - } - - public function mail($to, $subject, $message, $headers) { - $this->send_text = "To: $to\r\n{$headers}\r\nSubject: $this->subject\r\n\r\n$message"; - return true; - } -} \ No newline at end of file diff --git a/core/tests/Var_Test.php b/core/tests/Var_Test.php deleted file mode 100644 index 82370631..00000000 --- a/core/tests/Var_Test.php +++ /dev/null @@ -1,49 +0,0 @@ -assert_equal("original value", module::get_var("core", "Parameter")); - - module::set_var("core", "Parameter", "updated value"); - $this->assert_equal("updated value", module::get_var("core", "Parameter")); - } - - public function clear_parameter_test() { - module::set_var("core", "Parameter", "original value"); - $this->assert_equal("original value", module::get_var("core", "Parameter")); - - module::clear_var("core", "Parameter"); - $this->assert_equal(null, module::get_var("core", "Parameter")); - } - - public function incr_parameter_test() { - module::set_var("core", "Parameter", "original value"); - module::incr_var("core", "Parameter"); - $this->assert_equal("1", module::get_var("core", "Parameter")); - - module::set_var("core", "Parameter", "2"); - module::incr_var("core", "Parameter", "9"); - $this->assert_equal("11", module::get_var("core", "Parameter")); - - module::incr_var("core", "NonExistent", "9"); - $this->assert_equal(null, module::get_var("core", "NonExistent")); - } -} \ No newline at end of file diff --git a/core/tests/images/DSC_0003.jpg b/core/tests/images/DSC_0003.jpg deleted file mode 100644 index 5780d9d8..00000000 Binary files a/core/tests/images/DSC_0003.jpg and /dev/null differ diff --git a/core/tests/images/DSC_0005.jpg b/core/tests/images/DSC_0005.jpg deleted file mode 100644 index 4d2b53a9..00000000 Binary files a/core/tests/images/DSC_0005.jpg and /dev/null differ diff --git a/core/tests/images/DSC_0017.jpg b/core/tests/images/DSC_0017.jpg deleted file mode 100644 index b7f7bb90..00000000 Binary files a/core/tests/images/DSC_0017.jpg and /dev/null differ diff --git a/core/tests/images/DSC_0019.jpg b/core/tests/images/DSC_0019.jpg deleted file mode 100644 index 0ce25aa4..00000000 Binary files a/core/tests/images/DSC_0019.jpg and /dev/null differ diff --git a/core/tests/images/DSC_0067.jpg b/core/tests/images/DSC_0067.jpg deleted file mode 100644 index 84f134cb..00000000 Binary files a/core/tests/images/DSC_0067.jpg and /dev/null differ diff --git a/core/tests/images/DSC_0072.jpg b/core/tests/images/DSC_0072.jpg deleted file mode 100644 index dfad82b0..00000000 Binary files a/core/tests/images/DSC_0072.jpg and /dev/null differ diff --git a/core/tests/images/P4050088.jpg b/core/tests/images/P4050088.jpg deleted file mode 100644 index 62f4749d..00000000 Binary files a/core/tests/images/P4050088.jpg and /dev/null differ diff --git a/core/tests/selenium/Add_Album.html b/core/tests/selenium/Add_Album.html deleted file mode 100644 index ccd4d0b7..00000000 --- a/core/tests/selenium/Add_Album.html +++ /dev/null @@ -1,52 +0,0 @@ - - - - - - -AddAlbum - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    AddAlbum
    open/index.php/albums/1
    clicklink=Add album
    typenameseleniumtest
    typetitleSelenium Test Album
    typedescriptionTest
    click//button[@type='button']
    assertTextPresentSelenium Test Album
    - - diff --git a/core/tests/selenium/Add_Comment.html b/core/tests/selenium/Add_Comment.html deleted file mode 100644 index b4b96ed2..00000000 --- a/core/tests/selenium/Add_Comment.html +++ /dev/null @@ -1,52 +0,0 @@ - - - - - - -Add comment - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    Add comment
    open/index.php/albums/1
    clickAndWaitgPhotoId-2
    typegAuthorTest
    typegEmailtest@gmail.com
    typegTextThis is a selenium test comment.
    click//button[@type='submit']
    assertTextPresentThis is a selenium test comment.
    - - diff --git a/core/tests/selenium/Add_Item.html b/core/tests/selenium/Add_Item.html deleted file mode 100644 index 741dff65..00000000 --- a/core/tests/selenium/Add_Item.html +++ /dev/null @@ -1,62 +0,0 @@ - - - - - - -AddItem - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    AddItem
    open/index.php/albums/1
    clicklink=Add an item
    typenameseleniumitem.jpg
    typetitleSelenium Item
    typedescriptionTest item
    typefile/Users/ckieffer/Sites/gallery3.0/core/tests/images/DSC_0003.jpg
    click//button[@type='button']
    clicklink=X
    assertTextPresentSelenium Item
    - - diff --git a/core/tests/selenium/Login.html b/core/tests/selenium/Login.html deleted file mode 100644 index 5e17a3c7..00000000 --- a/core/tests/selenium/Login.html +++ /dev/null @@ -1,47 +0,0 @@ - - - - - - -Login - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    Login
    open/index.php/albums/1
    clickgLoginLink
    typegNameadmin
    typegPasswordadmin
    clickAndWait//button[@type='button']
    clickAndWaitgUserProfileLink
    - - diff --git a/core/tests/test.jpg b/core/tests/test.jpg deleted file mode 100644 index 1f3525e5..00000000 Binary files a/core/tests/test.jpg and /dev/null differ diff --git a/core/views/admin_advanced_settings.html.php b/core/views/admin_advanced_settings.html.php deleted file mode 100644 index 1f3825bd..00000000 --- a/core/views/admin_advanced_settings.html.php +++ /dev/null @@ -1,34 +0,0 @@ - -
    -

    -

    - -

    -
      -
    • - ") ?> -
    • -
    - - - - - - - - - module_name == "core" && $var->name == "_cache") continue ?> - - - - - - -
    module_name ?> name ?> - module_name/$var->name") ?>" - class="gDialogLink" - title=" $var->name, "module_name" => $var->module_name)) ?>"> - value ?> - -
    -
    diff --git a/core/views/admin_block_log_entries.html.php b/core/views/admin_block_log_entries.html.php deleted file mode 100644 index db6313e1..00000000 --- a/core/views/admin_block_log_entries.html.php +++ /dev/null @@ -1,11 +0,0 @@ - - diff --git a/core/views/admin_block_news.html.php b/core/views/admin_block_news.html.php deleted file mode 100644 index cb276ae5..00000000 --- a/core/views/admin_block_news.html.php +++ /dev/null @@ -1,11 +0,0 @@ - -
      - -
    • - "> -

      - -

      -
    • - -
    diff --git a/core/views/admin_block_photo_stream.html.php b/core/views/admin_block_photo_stream.html.php deleted file mode 100644 index e8a4d933..00000000 --- a/core/views/admin_block_photo_stream.html.php +++ /dev/null @@ -1,14 +0,0 @@ - - -

    - -

    diff --git a/core/views/admin_block_platform.html.php b/core/views/admin_block_platform.html.php deleted file mode 100644 index 6b79f047..00000000 --- a/core/views/admin_block_platform.html.php +++ /dev/null @@ -1,18 +0,0 @@ - -
      -
    • - PHP_OS)) ?> -
    • -
    • - function_exists("apache_get_version") ? apache_get_version() : t("Unknown"))) ?> -
    • -
    • - phpversion())) ?> -
    • -
    • - Database::instance()->query("SELECT version() as v")->current()->v)) ?> -
    • -
    • - $load_average)) ?> -
    • -
    diff --git a/core/views/admin_block_stats.html.php b/core/views/admin_block_stats.html.php deleted file mode 100644 index 2d975073..00000000 --- a/core/views/admin_block_stats.html.php +++ /dev/null @@ -1,12 +0,0 @@ - -
      -
    • - module::get_var("core", "version"))) ?> -
    • -
    • - $album_count)) ?> -
    • -
    • - $photo_count)) ?> -
    • -
    diff --git a/core/views/admin_block_welcome.html.php b/core/views/admin_block_welcome.html.php deleted file mode 100644 index 488fa908..00000000 --- a/core/views/admin_block_welcome.html.php +++ /dev/null @@ -1,20 +0,0 @@ - -

    - -

    -
      -
    • - graphics and language settings.", - array("graphics_url" => url::site("admin/graphics"), - "language_url" => url::site("admin/languages"))) ?> -
    • -
    • - choose a theme, or customize the way it looks.", - array("theme_url" => url::site("admin/theme"), - "theme_details_url" => url::site("admin/theme_details"))) ?> -
    • -
    • - install modules to add cool features!", - array("modules_url" => url::site("admin/modules"))) ?> -
    • -
    diff --git a/core/views/admin_dashboard.html.php b/core/views/admin_dashboard.html.php deleted file mode 100644 index c266d7e1..00000000 --- a/core/views/admin_dashboard.html.php +++ /dev/null @@ -1,38 +0,0 @@ - - -
    - -
    diff --git a/core/views/admin_graphics.html.php b/core/views/admin_graphics.html.php deleted file mode 100644 index 08374471..00000000 --- a/core/views/admin_graphics.html.php +++ /dev/null @@ -1,28 +0,0 @@ - - -
    -

    -

    - -

    - -

    - - -
    -

    - -
    -
    - diff --git a/core/views/admin_graphics_gd.html.php b/core/views/admin_graphics_gd.html.php deleted file mode 100644 index cae68b74..00000000 --- a/core/views/admin_graphics_gd.html.php +++ /dev/null @@ -1,29 +0,0 @@ - -
    gd["GD Version"] ? " gInstalledToolkit" : " gUnavailable" ?>"> - " alt="" /> -

    -

    - GD website for more information.", - array("url" => "http://www.boutell.com/gd")) ?> -

    - gd["GD Version"] && function_exists('imagerotate')): ?> -

    - $tk->gd["GD Version"])) ?> -

    -

    - -

    - gd["GD Version"]): ?> -

    - $tk->gd["GD Version"])) ?> -

    -

    - -

    - -

    - -

    - -
    diff --git a/core/views/admin_graphics_graphicsmagick.html.php b/core/views/admin_graphics_graphicsmagick.html.php deleted file mode 100644 index 720a9459..00000000 --- a/core/views/admin_graphics_graphicsmagick.html.php +++ /dev/null @@ -1,21 +0,0 @@ - -
    graphicsmagick ? " gInstalledToolkit" : " gUnavailable" ?>"> -

    - " alt="" /> -

    - GraphicsMagick website for more information.", - array("url" => "http://www.graphicsmagick.org")) ?> -

    - graphicsmagick): ?> -

    - $tk->graphicsmagick)) ?> -

    -

    - -

    - -

    - -

    - -
    diff --git a/core/views/admin_graphics_imagemagick.html.php b/core/views/admin_graphics_imagemagick.html.php deleted file mode 100644 index c7468eed..00000000 --- a/core/views/admin_graphics_imagemagick.html.php +++ /dev/null @@ -1,21 +0,0 @@ - -
    imagemagick ? " gInstalledToolkit" : " gUnavailable" ?>"> -

    - " alt="" /> -

    - ImageMagick website for more information.", - array("url" => "http://www.imagemagick.org")) ?> -

    - imagemagick): ?> -

    - $tk->imagemagick)) ?> -

    -

    - -

    - -

    - -

    - -
    diff --git a/core/views/admin_graphics_none.html.php b/core/views/admin_graphics_none.html.php deleted file mode 100644 index 5306a70d..00000000 --- a/core/views/admin_graphics_none.html.php +++ /dev/null @@ -1,7 +0,0 @@ - -
    -

    -

    - -

    -
    diff --git a/core/views/admin_languages.html.php b/core/views/admin_languages.html.php deleted file mode 100644 index 2b43f1b4..00000000 --- a/core/views/admin_languages.html.php +++ /dev/null @@ -1,15 +0,0 @@ - -
    -

    - - - -

    - " - class="gDialogLink"> - - - -

    - -
    diff --git a/core/views/admin_maintenance.html.php b/core/views/admin_maintenance.html.php deleted file mode 100644 index bc060a7b..00000000 --- a/core/views/admin_maintenance.html.php +++ /dev/null @@ -1,181 +0,0 @@ - -
    -

    -

    - -

    - -
    -

    - - - - - - - - - - - - - -
    - - - - - -
    - name ?> - - description ?> - - callback?csrf=$csrf") ?>" - class="gDialogLink"> - - -
    -
    - - count()): ?> -
    -

    - " - class="gButtonLink ui-icon-left ui-state-default ui-corner-all right"> - - - - - - - - - - - - - "> - - - - - - - - -
    - - - - - - - - - - - -
    - updated) ?> - - name ?> - - done): ?> - state == "cancelled"): ?> - - - - state == "stalled"): ?> - - - $task->percent_complete)) ?> - - - status ?> - - owner()->name ?> - - state == "stalled"): ?> - id?csrf=$csrf") ?>"> - - - - id?csrf=$csrf") ?>"> - - -
    -
    - - - count()): ?> -
    - " - class="gButtonLink ui-icon-left ui-state-default ui-corner-all right"> - - -

    - - - - - - - - - - - "> - - - - - - - - -
    - - - - - - - - - - - -
    - updated) ?> - - name ?> - - state == "success"): ?> - - state == "error"): ?> - - state == "cancelled"): ?> - - - - status ?> - - owner()->name ?> - - done): ?> - id?csrf=$csrf") ?>"> - - - - id?csrf=$csrf") ?>"> - - - id?csrf=$csrf") ?>"> - - - -
    -
    - -
    diff --git a/core/views/admin_maintenance_task.html.php b/core/views/admin_maintenance_task.html.php deleted file mode 100644 index 1ee02311..00000000 --- a/core/views/admin_maintenance_task.html.php +++ /dev/null @@ -1,32 +0,0 @@ - - -
    -
    -
    -
    - - -
    -
    diff --git a/core/views/admin_modules.html.php b/core/views/admin_modules.html.php deleted file mode 100644 index 3fddd6cd..00000000 --- a/core/views/admin_modules.html.php +++ /dev/null @@ -1,32 +0,0 @@ - -
    -

    -

    - -

    - -
    "> - - - - - - - - - - $module_info): ?> - "> - $module_name); ?> - locked) $data["disabled"] = 1; ?> - - - - - - - -
    name) ?> version ?> description) ?>
    - "/> -
    -
    diff --git a/core/views/admin_theme_details.html.php b/core/views/admin_theme_details.html.php deleted file mode 100644 index eb450b16..00000000 --- a/core/views/admin_theme_details.html.php +++ /dev/null @@ -1,6 +0,0 @@ - -
    -

    - - -
    diff --git a/core/views/admin_themes.html.php b/core/views/admin_themes.html.php deleted file mode 100644 index f85bce70..00000000 --- a/core/views/admin_themes.html.php +++ /dev/null @@ -1,89 +0,0 @@ - - - -

    -

    - -

    - -
    -

    -
    - " - alt="name ?>" /> -

    name ?>

    -

    - description ?> -

    -
    - -

    - -
    - -
    -

    -
    - " - alt="name ?>" /> -

    name ?>

    -

    - description ?> -

    -
    - -

    - -
    \ No newline at end of file diff --git a/core/views/admin_themes_preview.html.php b/core/views/admin_themes_preview.html.php deleted file mode 100644 index a7aea172..00000000 --- a/core/views/admin_themes_preview.html.php +++ /dev/null @@ -1,7 +0,0 @@ - -

    - "> - %theme_name", array("theme_name" => $info->name)) ?> - -

    - diff --git a/core/views/after_install.html.php b/core/views/after_install.html.php deleted file mode 100644 index aa26858a..00000000 --- a/core/views/after_install.html.php +++ /dev/null @@ -1,29 +0,0 @@ - -

    - -

    - -

    - -

    - -

    - %user_name account. The very first thing you should do is to change your password to something that you'll remember.", array("user_name" => $user->name)) ?> -

    - -

    - id}") ?>" - title="" - id="gAfterInstallChangePasswordLink" class="gButtonLink ui-state-default ui-corners-all"> - -

    - -

    - Gallery website has news and information about Gallery Project and community.", array("url" => "http://gallery.menalto.com")) ?> -

    - -

    - documentation site or you can ask for help in the forums!", array("codex_url" => "http://codex.gallery2.org/Main_Page", "forum_url" => "http://gallery.menalto.com/forum")) ?> - diff --git a/core/views/after_install_loader.html.php b/core/views/after_install_loader.html.php deleted file mode 100644 index baf91eed..00000000 --- a/core/views/after_install_loader.html.php +++ /dev/null @@ -1,7 +0,0 @@ - -" - href=""/> - diff --git a/core/views/form.html.php b/core/views/form.html.php deleted file mode 100644 index ec2a56a9..00000000 --- a/core/views/form.html.php +++ /dev/null @@ -1,75 +0,0 @@ - -"; -} -if ($title) { - print $title; -} - -if (!function_exists("DrawForm")) { - function DrawForm($inputs, $level=1) { - $error_messages = array(); - $prefix = str_repeat(" ", $level); - $haveGroup = false; - // On the first level, make sure we have a group if not add the

      tag now - if ($level == 1) { - foreach ($inputs as $input) { - $haveGroup |= $input->type == 'group'; - } - if (!$haveGroup) { - print "$prefix
        \n"; - } - } - - foreach ($inputs as $input) { - if ($input->type == 'group') { - print "$prefix
        \n"; - print "$prefix {$input->label}\n"; - print "$prefix
          \n"; - - DrawForm($input->inputs, $level + 2); - print "$prefix
        \n"; - - // Since hidden fields can only have name and value attributes lets just render it now - $hidden_prefix = "$prefix "; - foreach ($input->hidden as $hidden) { - print "$prefix {$hidden->render()}\n"; - } - print "$prefix
        \n"; - } else { - if ($input->error_messages()) { - print "$prefix
      • \n"; - } else { - print "$prefix
      • \n"; - } - - if ($input->label()) { - print "$prefix {$input->label()}\n"; - } - print "$prefix {$input->render()}\n"; - if ($input->message()) { - print "$prefix

        {$input->message()}

        \n"; - } - if ($input->error_messages()) { - foreach ($input->error_messages() as $error_message) { - print "$prefix

        \n"; - print "$prefix $error_message\n"; - print "$prefix

        \n"; - } - } - print "$prefix
      • \n"; - } - } - if ($level == 1 && !$haveGroup) { - print "$prefix
      \n"; - } - } -} -DrawForm($inputs); - -print($close); -?> diff --git a/core/views/kohana_error_page.php b/core/views/kohana_error_page.php deleted file mode 100644 index d9bf9698..00000000 --- a/core/views/kohana_error_page.php +++ /dev/null @@ -1,118 +0,0 @@ - - - - - - - <?= t("Something went wrong!") ?> - - - - admin ?> -
      -

      - -

      -

      - -

      - -

      - -

      - -
      - -
      -

      - -

      - - - - - - - diff --git a/core/views/kohana_profiler.php b/core/views/kohana_profiler.php deleted file mode 100644 index c7534349..00000000 --- a/core/views/kohana_profiler.php +++ /dev/null @@ -1,35 +0,0 @@ - - - -
      - - render(); ?> - -

      s

      -
      diff --git a/core/views/l10n_client.html.php b/core/views/l10n_client.html.php deleted file mode 100644 index 8f4092c7..00000000 --- a/core/views/l10n_client.html.php +++ /dev/null @@ -1,31 +0,0 @@ - - diff --git a/core/views/maintenance.html.php b/core/views/maintenance.html.php deleted file mode 100644 index f80b6e7a..00000000 --- a/core/views/maintenance.html.php +++ /dev/null @@ -1,50 +0,0 @@ - - - - - <?= t("Gallery - Maintenance Mode") ?> - - - - -

      - -

      -

      - -

      - - - - - diff --git a/core/views/move_browse.html.php b/core/views/move_browse.html.php deleted file mode 100644 index 4f69c0e9..00000000 --- a/core/views/move_browse.html.php +++ /dev/null @@ -1,47 +0,0 @@ - - -

      - type == "photo"): ?> - - type == "movie"): ?> - - type == "album"): ?> - - -

      -
      -
        -
      • - -
      • -
      -
      id") ?>"> - - - " disabled="disabled"/> -
      -
      diff --git a/core/views/move_tree.html.php b/core/views/move_tree.html.php deleted file mode 100644 index a3a4bc8f..00000000 --- a/core/views/move_tree.html.php +++ /dev/null @@ -1,19 +0,0 @@ - -thumb_tag(array(), 25); ?> -is_descendant($parent)): ?> - title ?> - - title ?> - - diff --git a/core/views/permissions_browse.html.php b/core/views/permissions_browse.html.php deleted file mode 100644 index afd87c2b..00000000 --- a/core/views/permissions_browse.html.php +++ /dev/null @@ -1,56 +0,0 @@ - - -
      - -
        -
      • - AllowOverride FileInfo Options to fix this.", array("url" => "http://httpd.apache.org/docs/2.0/mod/core.html#allowoverride")) ?> -
      • -
      - - - -
      diff --git a/core/views/permissions_form.html.php b/core/views/permissions_form.html.php deleted file mode 100644 index 3dbd0d98..00000000 --- a/core/views/permissions_form.html.php +++ /dev/null @@ -1,94 +0,0 @@ - -
      - -
      - - - - - - - - - - - - - - - name, $item) ?> - name, $item) ?> - name, $item) ?> - - - - - - - - - - - - - - - - - - - - - -
      name ?>
      display_name) ?> - <?= t('denied icon') ?> - - <?= t('locked icon') ?> - - - - <?= t('passive allowed icon') ?> - - - <?= t('inactive denied icon') ?> - - - - <?= t('inactive allowed icon') ?> - - - <?= t('passive denied icon') ?> - - - - <?= t('inactive allowed icon') ?> - - id == 1): ?> - <?= t('denied icon') ?> - - - <?= t('denied icon') ?> - - - - id == 1): ?> - <?= t('allowed icon') ?> - - - <?= t('allowed icon') ?> - - - - <?= t('inactive denied icon') ?> - -
      -
      -
      diff --git a/core/views/quick_pane.html.php b/core/views/quick_pane.html.php deleted file mode 100644 index 95de972b..00000000 --- a/core/views/quick_pane.html.php +++ /dev/null @@ -1,108 +0,0 @@ - -type == "photo"): ?> - -type == "movie"): ?> - -type == "album"): ?> - - -id?page_type=$page_type") ?>" - title=""> - - - - - -is_photo() && graphics::can("rotate")): ?> -id/ccw?csrf=$csrf&page_type=$page_type") ?>" - title=""> - - - - - -id/cw?csrf=$csrf&page_type=$page_type") ?>" - title=""> - - - - - - - - -type == "photo"): ?> - -type == "movie"): ?> - -type == "album"): ?> - - -id") ?>" - title=""> - - - - - - - -parent())): ?> -type == "photo"): ?> - -type == "movie"): ?> - -type == "album"): ?> -album_cover_item_id)): ?> -album_cover_item_id) ? " ui-state-disabled" : "" ?> - - - -id?csrf=$csrf&page_type=$page_type") ?>" - title=""> - - - - - -type == "photo"): ?> - - -type == "movie"): ?> - - -type == "album"): ?> - - - -id?csrf=$csrf&page_type=$page_type") ?>" ref="" id="gQuickDelete" title=""> - - - - - - -is_album()): ?> -"> - - - - - - - diff --git a/core/views/scaffold.html.php b/core/views/scaffold.html.php deleted file mode 100644 index 765464b5..00000000 --- a/core/views/scaffold.html.php +++ /dev/null @@ -1,169 +0,0 @@ - - - - Gallery3 Scaffold - - - -
      -
      - "/> -
      -
      -

      Gallery3 Scaffold

      -

      - This is - a scaffold: - a temporary structure built to support the developers as - they create the real product. As we flesh out Gallery 3, - we'll make it possible for you to peer inside and see the - application taking shape. Eventually, this page will go - away and you'll start in the application itself. In the - meantime, here are some useful links to get you started. -

      - - 0): ?> -
      -

      - - ( albums, photos, comments, tags) -

      -
      - - -
      -
      - Generate Test Data -

      - add: [ - - - - ] photos and albums -

      -

      - add: [ - - - - ] albums only -

      -

      - add: [ - - - - ] comments -

      -

      - add: [ - - - - ] tags -

      -
      -
      - Packaging - ">Make Package -
      -
      -
      -
      - - diff --git a/core/views/simple_uploader.html.php b/core/views/simple_uploader.html.php deleted file mode 100644 index b6725c31..00000000 --- a/core/views/simple_uploader.html.php +++ /dev/null @@ -1,249 +0,0 @@ - - - - - -
      "> -
      - $item->title)) ?> -
      -
      - -
      - -
        -
      • - suhosin.session.encrypt setting from Suhosin. You must disable this setting to upload photos.", - array("encrypt_url" => "http://www.hardened-php.net/suhosin/configuration.html#suhosin.session.encrypt", - "suhosin_url" => "http://www.hardened-php.net/suhosin/")) ?> -
      • -
      - - -

      - -

      -
        - parents() as $parent): ?> -
      • title ?>
      • - -
      • title ?>
      • -
      - -

      -
      -
      -
      - -
      - - - - -
      - - - - diff --git a/index.php b/index.php index 815ff5f5..4a531d5c 100644 --- a/index.php +++ b/index.php @@ -41,7 +41,7 @@ define('KOHANA', 'index.php'); is_link(basename(__FILE__)) and chdir(dirname(realpath(__FILE__))); // Define application and system paths -define('APPPATH', strtr(realpath('core') . '/', DIRECTORY_SEPARATOR, '/')); +define('APPPATH', strtr(realpath('application') . '/', DIRECTORY_SEPARATOR, '/')); define('MODPATH', strtr(realpath('modules') . '/', DIRECTORY_SEPARATOR, '/')); define('THEMEPATH', strtr(realpath('themes') . '/', DIRECTORY_SEPARATOR, '/')); define('SYSPATH', strtr(realpath('kohana') . '/', DIRECTORY_SEPARATOR, '/')); diff --git a/modules/gallery/config/cookie.php b/modules/gallery/config/cookie.php new file mode 100644 index 00000000..692ef548 --- /dev/null +++ b/modules/gallery/config/cookie.php @@ -0,0 +1,49 @@ + email address that appears as the from address + * line-length => word wrap length (PHP documentations suggest no larger tha 70 characters + * reply-to => what goes into the reply to header + */ +$config["from"] = "admin@gallery3.com"; +$config["line_length"] = 70; +$config["reply_to"] = "public@gallery3.com"; +$config["header_separator"] = "\n"; diff --git a/modules/gallery/config/session.php b/modules/gallery/config/session.php new file mode 100644 index 00000000..990fa31f --- /dev/null +++ b/modules/gallery/config/session.php @@ -0,0 +1,66 @@ +admin)) { + throw new Exception("@todo UNAUTHORIZED", 401); + } + parent::__construct(); + } + + public function __call($controller_name, $args) { + if (request::method() == "post") { + access::verify_csrf(); + } + + if ($controller_name == "index") { + $controller_name = "dashboard"; + } + $controller_name = "Admin_{$controller_name}_Controller"; + if ($args) { + $method = array_shift($args); + } else { + $method = "index"; + } + + if (!method_exists($controller_name, $method)) { + return kohana::show_404(); + } + + call_user_func_array(array(new $controller_name, $method), $args); + } +} + diff --git a/modules/gallery/controllers/admin_advanced_settings.php b/modules/gallery/controllers/admin_advanced_settings.php new file mode 100644 index 00000000..79bc1183 --- /dev/null +++ b/modules/gallery/controllers/admin_advanced_settings.php @@ -0,0 +1,53 @@ +content = new View("admin_advanced_settings.html"); + $view->content->vars = ORM::factory("var") + ->orderby("module_name", "name") + ->find_all(); + print $view; + } + + public function edit($module_name, $var_name) { + $value = module::get_var($module_name, $var_name); + $form = new Forge("admin/advanced_settings/save/$module_name/$var_name", "", "post"); + $group = $form->group("edit_var")->label( + t("Edit %var (%module_name)", + array("module_name" => $module_name, "var" => $var_name))); + $group->input("module_name")->label(t("Module"))->value($module_name)->disabled(1); + $group->input("var_name")->label(t("Setting"))->value($var_name)->disabled(1); + $group->textarea("value")->label(t("Value"))->value($value); + $group->submit("")->value(t("Save")); + print $form; + } + + public function save($module_name, $var_name) { + access::verify_csrf(); + + module::set_var($module_name, $var_name, Input::instance()->post("value")); + message::success( + t("Saved value for %var (%module_name)", + array("var" => $var_name, "module_name" => $module_name))); + + print json_encode(array("result" => "success")); + } +} diff --git a/modules/gallery/controllers/admin_dashboard.php b/modules/gallery/controllers/admin_dashboard.php new file mode 100644 index 00000000..d2d2f79b --- /dev/null +++ b/modules/gallery/controllers/admin_dashboard.php @@ -0,0 +1,93 @@ +content = new View("admin_dashboard.html"); + $view->content->blocks = block_manager::get_html("dashboard_center"); + $view->sidebar = "
      " . + block_manager::get_html("dashboard_sidebar") . + "
      "; + print $view; + } + + public function add_block() { + $form = core_block::get_add_block_form(); + if ($form->validate()) { + list ($module_name, $id) = explode(":", $form->add_block->id->value); + $available = block_manager::get_available(); + + if ($form->add_block->center->value) { + block_manager::add("dashboard_center", $module_name, $id); + message::success( + t("Added %title block to the dashboard center", + array("title" => $available["$module_name:$id"]))); + } else { + block_manager::add("dashboard_sidebar", $module_name, $id); + message::success( + t("Added %title to the dashboard sidebar", + array("title" => $available["$module_name:$id"]))); + } + } + url::redirect("admin/dashboard"); + } + + public function remove_block($id) { + access::verify_csrf(); + $blocks_center = block_manager::get_active("dashboard_center"); + $blocks_sidebar = block_manager::get_active("dashboard_sidebar"); + + if (array_key_exists($id, $blocks_sidebar)) { + $deleted = $blocks_sidebar[$id]; + block_manager::remove("dashboard_sidebar", $id); + } else if (array_key_exists($id, $blocks_center)) { + $deleted = $blocks_center[$id]; + block_manager::remove("dashboard_center", $id); + } + + if (!empty($deleted)) { + $available = block_manager::get_available(); + $title = $available[join(":", $deleted)]; + message::success(t("Removed %title block", array("title" => $title))); + } + + url::redirect("admin"); + } + + public function reorder() { + access::verify_csrf(); + $active_set = array(); + foreach (array("dashboard_sidebar", "dashboard_center") as $location) { + foreach (block_manager::get_active($location) as $id => $info) { + $active_set[$id] = $info; + } + } + + foreach (array("dashboard_sidebar", "dashboard_center") as $location) { + $new_blocks = array(); + foreach ($this->input->get($location, array()) as $id) { + $new_blocks[$id] = $active_set[$id]; + } + block_manager::set_active($location, $new_blocks); + } + + $this->_force_block_adder(); + } +} diff --git a/modules/gallery/controllers/admin_graphics.php b/modules/gallery/controllers/admin_graphics.php new file mode 100644 index 00000000..0b3014f0 --- /dev/null +++ b/modules/gallery/controllers/admin_graphics.php @@ -0,0 +1,63 @@ +content = new View("admin_graphics.html"); + $view->content->available = ""; + + $tk = new ArrayObject(graphics::detect_toolkits(), ArrayObject::ARRAY_AS_PROPS); + $active = module::get_var("core", "graphics_toolkit", "none"); + foreach (array("gd", "imagemagick", "graphicsmagick", "none") as $id) { + if ($id == $active) { + $view->content->active = new View("admin_graphics_$id.html"); + $view->content->active->tk = $tk; + $view->content->active->is_active = true; + } else if ($id != "none") { + $v = new View("admin_graphics_$id.html"); + $v->tk = $tk; + $v->is_active = false; + $view->content->available .= $v; + } + } + + print $view; + } + + public function choose($toolkit) { + access::verify_csrf(); + if ($toolkit != module::get_var("core", "graphics_toolkit")) { + module::set_var("core", "graphics_toolkit", $toolkit); + + $toolkit_info = graphics::detect_toolkits(); + if ($toolkit == "graphicsmagick" || $toolkit == "imagemagick") { + module::set_var("core", "graphics_toolkit_path", $toolkit_info[$toolkit]); + } + + site_status::clear("missing_graphics_toolkit"); + message::success(t("Updated Graphics Toolkit")); + log::success("graphics", t("Changed graphics toolkit to: %toolkit", + array("toolkit" => $toolkit))); + } + + url::redirect("admin/graphics"); + } +} + diff --git a/modules/gallery/controllers/admin_languages.php b/modules/gallery/controllers/admin_languages.php new file mode 100644 index 00000000..37d335a3 --- /dev/null +++ b/modules/gallery/controllers/admin_languages.php @@ -0,0 +1,136 @@ +content = new View("admin_languages.html"); + $v->content->settings_form = $this->_languages_form(); + if (empty($share_translations_form)) { + $share_translations_form = $this->_share_translations_form(); + } + $v->content->share_translations_form = $share_translations_form; + $this->_outgoing_translations_count(); + print $v; + } + + public function save() { + $form = $this->_languages_form(); + if ($form->validate()) { + module::set_var("core", "default_locale", $form->choose_language->locale->value); + locale::update_installed($form->choose_language->installed_locales->value); + message::success(t("Settings saved")); + } + url::redirect("admin/languages"); + } + + public function share() { + $form = $this->_share_translations_form(); + if (!$form->validate()) { + // Show the page with form errors + return $this->index($form); + } + + if ($form->sharing->share) { + l10n_client::submit_translations(); + message::success(t("Translations submitted")); + } else { + return $this->_save_api_key($form); + } + url::redirect("admin/languages"); + } + + private function _save_api_key($form) { + $new_key = $form->sharing->api_key->value; + if ($new_key && !l10n_client::validate_api_key($new_key)) { + $form->sharing->api_key->add_error("invalid", 1); + $valid = false; + } else { + $valid = true; + } + + if ($valid) { + $old_key = l10n_client::api_key(); + l10n_client::api_key($new_key); + if ($old_key && !$new_key) { + message::success(t("Your API key has been cleared.")); + } else if ($old_key && $new_key && $old_key != $new_key) { + message::success(t("Your API key has been changed.")); + } else if (!$old_key && $new_key) { + message::success(t("Your API key has been saved.")); + } + + log::success(t("core"), t("l10n_client API key changed.")); + url::redirect("admin/languages"); + } else { + // Show the page with form errors + $this->index($form); + } + } + + private function _languages_form() { + $all_locales = locale::available(); + $installed_locales = locale::installed(); + $form = new Forge("admin/languages/save", "", "post", array("id" => "gLanguageSettingsForm")); + $group = $form->group("choose_language") + ->label(t("Language settings")); + $group->dropdown("locale") + ->options($installed_locales) + ->selected(module::get_var("core", "default_locale")) + ->label(t("Default language")) + ->rules('required'); + + $installation_options = array(); + foreach ($all_locales as $code => $display_name) { + $installation_options[$code] = array($display_name, isset($installed_locales->$code)); + } + $group->checklist("installed_locales") + ->label(t("Installed Languages")) + ->options($installation_options) + ->rules("required"); + $group->submit("save")->value(t("Save settings")); + return $form; + } + + private function _outgoing_translations_count() { + return ORM::factory("outgoing_translation")->count_all(); + } + + private function _share_translations_form() { + $form = new Forge("admin/languages/share", "", "post", array("id" => "gShareTranslationsForm")); + $group = $form->group("sharing") + ->label(t("Sharing you own translations with the Gallery community is easy. Please do!")); + $api_key = l10n_client::api_key(); + $server_link = l10n_client::server_api_key_url(); + $group->input("api_key") + ->label(empty($api_key) + ? t("This is a unique key that will allow you to send translations to the remote server. To get your API key go to %server-link.", + array("server-link" => html::anchor($server_link))) + : t("API Key")) + ->value($api_key) + ->error_messages("invalid", t("The API key you provided is invalid.")); + $group->submit("save")->value(t("Save settings")); + if ($api_key && $this->_outgoing_translations_count()) { + // TODO: UI improvement: hide API key / save button when API key is set. + $group->submit("share")->value(t("Submit translations")); + } + return $form; + } +} + diff --git a/modules/gallery/controllers/admin_maintenance.php b/modules/gallery/controllers/admin_maintenance.php new file mode 100644 index 00000000..c169de75 --- /dev/null +++ b/modules/gallery/controllers/admin_maintenance.php @@ -0,0 +1,181 @@ +query( + "UPDATE {tasks} SET `state` = 'stalled' " . + "WHERE done = 0 " . + "AND state <> 'stalled' " . + "AND unix_timestamp(now()) - updated > 15"); + $stalled_count = $query->count(); + if ($stalled_count) { + log::warning("tasks", + t2("One task is stalled", + "%count tasks are stalled", + $stalled_count), + t('view', + array("url" => url::site("admin/maintenance")))); + } + + $view = new Admin_View("admin.html"); + $view->content = new View("admin_maintenance.html"); + $view->content->task_definitions = task::get_definitions(); + $view->content->running_tasks = ORM::factory("task") + ->where("done", 0)->orderby("updated", "DESC")->find_all(); + $view->content->finished_tasks = ORM::factory("task") + ->where("done", 1)->orderby("updated", "DESC")->find_all(); + print $view; + } + + /** + * Start a new task + * @param string $task_callback + */ + public function start($task_callback) { + access::verify_csrf(); + + $tasks = task::get_definitions(); + $task = task::create($tasks[$task_callback], array()); + $view = new View("admin_maintenance_task.html"); + $view->task = $task; + + log::info("tasks", t("Task %task_name started (task id %task_id)", + array("task_name" => $task->name, "task_id" => $task->id)), + html::anchor(url::site("admin/maintenance"), t("maintenance"))); + print $view; + } + + /** + * Resume a stalled task + * @param string $task_id + */ + public function resume($task_id) { + access::verify_csrf(); + + $task = ORM::factory("task", $task_id); + if (!$task->loaded) { + throw new Exception("@todo MISSING_TASK"); + } + $view = new View("admin_maintenance_task.html"); + $view->task = $task; + + log::info("tasks", t("Task %task_name resumed (task id %task_id)", + array("task_name" => $task->name, "task_id" => $task->id)), + html::anchor(url::site("admin/maintenance"), t("maintenance"))); + print $view; + } + + /** + * Cancel a task. + * @param string $task_id + */ + public function cancel($task_id) { + access::verify_csrf(); + + task::cancel($task_id); + + message::success(t("Task cancelled")); + url::redirect("admin/maintenance"); + } + + public function cancel_running_tasks() { + access::verify_csrf(); + Database::instance()->update( + "tasks", + array("done" => 1, "state" => "cancelled"), + array("done" => 0)); + message::success(t("All running tasks cancelled")); + url::redirect("admin/maintenance"); + } + + /** + * Remove a task. + * @param string $task_id + */ + public function remove($task_id) { + access::verify_csrf(); + + task::remove($task_id); + + message::success(t("Task removed")); + url::redirect("admin/maintenance"); + } + + public function remove_finished_tasks() { + access::verify_csrf(); + Database::instance()->delete("tasks", array("done" => 1)); + message::success(t("All finished tasks removed")); + url::redirect("admin/maintenance"); + } + + /** + * Run a task. This will trigger the task to do a small amount of work, then it will report + * back with status on the task. + * @param string $task_id + */ + public function run($task_id) { + access::verify_csrf(); + + try { + $task = task::run($task_id); + } catch (Exception $e) { + Kohana::log( + "error", + sprintf( + "%s in %s at line %s:\n%s", $e->getMessage(), $e->getFile(), + $e->getLine(), $e->getTraceAsString())); + throw $e; + } + + if ($task->done) { + switch ($task->state) { + case "success": + log::success("tasks", t("Task %task_name completed (task id %task_id)", + array("task_name" => $task->name, "task_id" => $task->id)), + html::anchor(url::site("admin/maintenance"), t("maintenance"))); + message::success(t("Task completed successfully")); + break; + + case "error": + log::error("tasks", t("Task %task_name failed (task id %task_id)", + array("task_name" => $task->name, "task_id" => $task->id)), + html::anchor(url::site("admin/maintenance"), t("maintenance"))); + message::success(t("Task failed")); + break; + } + print json_encode(array("result" => "success", + "task" => array( + "percent_complete" => $task->percent_complete, + "status" => $task->status, + "done" => $task->done), + "location" => url::site("admin/maintenance"))); + + } else { + print json_encode(array("result" => "in_progress", + "task" => array( + "percent_complete" => $task->percent_complete, + "status" => $task->status, + "done" => $task->done))); + } + } +} diff --git a/modules/gallery/controllers/admin_modules.php b/modules/gallery/controllers/admin_modules.php new file mode 100644 index 00000000..f7dd909d --- /dev/null +++ b/modules/gallery/controllers/admin_modules.php @@ -0,0 +1,65 @@ +content = new View("admin_modules.html"); + $view->content->available = module::available(); + print $view; + } + + public function save() { + access::verify_csrf(); + + $changes->activate = array(); + $changes->deactivate = array(); + $activated_names = array(); + $deactivated_names = array(); + foreach (module::available() as $module_name => $info) { + if ($info->locked) { + continue; + } + + $desired = $this->input->post($module_name) == 1; + if ($info->active && !$desired && module::is_active($module_name)) { + $changes->deactivate[] = $module_name; + $deactivated_names[] = $info->name; + module::deactivate($module_name); + } else if (!$info->active && $desired && !module::is_active($module_name)) { + $changes->activate[] = $module_name; + $activated_names[] = $info->name; + module::install($module_name); + module::activate($module_name); + } + } + + module::event("module_change", $changes); + + // @todo this type of collation is questionable from a i18n perspective + if ($activated_names) { + message::success(t("Activated: %names", array("names" => join(", ", $activated_names)))); + } + if ($deactivated_names) { + message::success(t("Deactivated: %names", array("names" => join(", ", $deactivated_names)))); + } + url::redirect("admin/modules"); + } +} + diff --git a/modules/gallery/controllers/admin_theme_details.php b/modules/gallery/controllers/admin_theme_details.php new file mode 100644 index 00000000..542ec31c --- /dev/null +++ b/modules/gallery/controllers/admin_theme_details.php @@ -0,0 +1,67 @@ +content = new View("admin_theme_details.html"); + $view->content->form = theme::get_edit_form_admin(); + print $view; + } + + public function save() { + $form = theme::get_edit_form_admin(); + if ($form->validate()) { + module::set_var("core", "page_size", $form->edit_theme->page_size->value); + + $thumb_size = $form->edit_theme->thumb_size->value; + $thumb_dirty = false; + if (module::get_var("core", "thumb_size") != $thumb_size) { + graphics::remove_rule("core", "thumb", "resize"); + graphics::add_rule( + "core", "thumb", "resize", + array("width" => $thumb_size, "height" => $thumb_size, "master" => Image::AUTO), + 100); + module::set_var("core", "thumb_size", $thumb_size); + } + + $resize_size = $form->edit_theme->resize_size->value; + $resize_dirty = false; + if (module::get_var("core", "resize_size") != $resize_size) { + graphics::remove_rule("core", "resize", "resize"); + graphics::add_rule( + "core", "resize", "resize", + array("width" => $resize_size, "height" => $resize_size, "master" => Image::AUTO), + 100); + module::set_var("core", "resize_size", $resize_size); + } + + module::set_var("core", "header_text", $form->edit_theme->header_text->value); + module::set_var("core", "footer_text", $form->edit_theme->footer_text->value); + + message::success(t("Updated theme details")); + url::redirect("admin/theme_details"); + } else { + $view = new Admin_View("admin.html"); + $view->content = $form; + print $view; + } + } +} + diff --git a/modules/gallery/controllers/admin_themes.php b/modules/gallery/controllers/admin_themes.php new file mode 100644 index 00000000..05c134d1 --- /dev/null +++ b/modules/gallery/controllers/admin_themes.php @@ -0,0 +1,79 @@ +content = new View("admin_themes.html"); + $view->content->admin = module::get_var("core", "active_admin_theme"); + $view->content->site = module::get_var("core", "active_site_theme"); + $view->content->themes = $this->_get_themes(); + print $view; + } + + private function _get_themes() { + $themes = array(); + foreach (scandir(THEMEPATH) as $theme_name) { + if ($theme_name[0] == ".") { + continue; + } + + $file = THEMEPATH . "$theme_name/theme.info"; + $theme_info = new ArrayObject(parse_ini_file($file), ArrayObject::ARRAY_AS_PROPS); + $themes[$theme_name] = $theme_info; + } + return $themes; + } + + public function preview($type, $theme_name) { + $view = new View("admin_themes_preview.html"); + $theme_name = preg_replace("/[^\w]/", "", $theme_name); + $view->info = new ArrayObject( + parse_ini_file(THEMEPATH . "$theme_name/theme.info"), ArrayObject::ARRAY_AS_PROPS); + $view->theme_name = $theme_name; + $view->type = $type; + if ($type == "admin") { + $view->url = url::site("admin?theme=$theme_name"); + } else { + $view->url = url::site("albums/1?theme=$theme_name"); + } + print $view; + } + + public function choose($type, $theme_name) { + access::verify_csrf(); + + $theme_name = preg_replace("/[^\w]/", "", $theme_name); + $info = new ArrayObject( + parse_ini_file(THEMEPATH . "$theme_name/theme.info"), ArrayObject::ARRAY_AS_PROPS); + + if ($type == "admin" && $info->admin) { + module::set_var("core", "active_admin_theme", $theme_name); + message::success(t("Successfully changed your admin theme to %theme_name", + array("theme_name" => $info->name))); + } else if ($type == "site" && $info->site) { + module::set_var("core", "active_site_theme", $theme_name); + message::success(t("Successfully changed your Gallery theme to %theme_name", + array("theme_name" => $info->name))); + } + + url::redirect("admin/themes"); + } +} + diff --git a/modules/gallery/controllers/after_install.php b/modules/gallery/controllers/after_install.php new file mode 100644 index 00000000..f066afe4 --- /dev/null +++ b/modules/gallery/controllers/after_install.php @@ -0,0 +1,30 @@ +admin) { + url::redirect("albums/1"); + } + + $v = new View("after_install.html"); + $v->user = user::active(); + print $v; + } +} diff --git a/modules/gallery/controllers/albums.php b/modules/gallery/controllers/albums.php new file mode 100644 index 00000000..5b4d5979 --- /dev/null +++ b/modules/gallery/controllers/albums.php @@ -0,0 +1,229 @@ +id != 1) { + access::forbidden(); + } else { + print new Theme_View("login_page.html", "album"); + return; + } + } + + $page_size = module::get_var("core", "page_size", 9); + $show = $this->input->get("show"); + + if ($show) { + $index = $album->get_position($show); + $page = ceil($index / $page_size); + if ($page == 1) { + url::redirect("albums/$album->id"); + } else { + url::redirect("albums/$album->id?page=$page"); + } + } + + $page = $this->input->get("page", "1"); + $children_count = $album->viewable()->children_count(); + $offset = ($page - 1) * $page_size; + $max_pages = max(ceil($children_count / $page_size), 1); + + // Make sure that the page references a valid offset + if ($page < 1) { + url::redirect("albums/$album->id"); + } else if ($page > $max_pages) { + url::redirect("albums/$album->id?page=$max_pages"); + } + + $template = new Theme_View("page.html", "album"); + $template->set_global("page_size", $page_size); + $template->set_global("item", $album); + $template->set_global("children", $album->viewable()->children($page_size, $offset)); + $template->set_global("children_count", $children_count); + $template->set_global("parents", $album->parents()); + $template->content = new View("album.html"); + + // We can't use math in ORM or the query builder, so do this by hand. It's important + // that we do this with math, otherwise concurrent accesses will damage accuracy. + Database::instance()->query( + "UPDATE {items} SET `view_count` = `view_count` + 1 WHERE `id` = $album->id"); + + print $template; + } + + /** + * @see REST_Controller::_create($resource) + */ + public function _create($album) { + access::required("add", $album); + + switch ($this->input->post("type")) { + case "album": + return $this->_create_album($album); + + case "photo": + return $this->_create_photo($album); + + default: + access::forbidden(); + } + } + + private function _create_album($album) { + access::required("add", $album); + + $form = album::get_add_form($album); + if ($form->validate()) { + $new_album = album::create( + $album, + $this->input->post("name"), + $this->input->post("title", $this->input->post("name")), + $this->input->post("description"), + user::active()->id); + + log::success("content", "Created an album", + html::anchor("albums/$new_album->id", "view album")); + message::success(t("Created album %album_title", array("album_title" => $new_album->title))); + + print json_encode( + array("result" => "success", + "location" => url::site("albums/$new_album->id"), + "resource" => url::site("albums/$new_album->id"))); + } else { + print json_encode( + array("result" => "error", + "form" => $form->__toString() . html::script("core/js/albums_form_add.js"))); + } + } + + private function _create_photo($album) { + access::required("add", $album); + + // If we set the content type as JSON, it triggers saving the result as + // a document in the browser (well, in Chrome at least). + // @todo figure out why and fix this. + $form = photo::get_add_form($album); + if ($form->validate()) { + $photo = photo::create( + $album, + $this->input->post("file"), + $_FILES["file"]["name"], + $this->input->post("title", $this->input->post("name")), + $this->input->post("description"), + user::active()->id); + + log::success("content", "Added a photo", html::anchor("photos/$photo->id", "view photo")); + message::success(t("Added photo %photo_title", array("photo_title" => $photo->title))); + + print json_encode( + array("result" => "success", + "resource" => url::site("photos/$photo->id"), + "location" => url::site("photos/$photo->id"))); + } else { + print json_encode( + array("result" => "error", + "form" => $form->__toString())); + } + } + + /** + * @see REST_Controller::_update($resource) + */ + public function _update($album) { + access::required("edit", $album); + + $form = album::get_edit_form($album); + if ($valid = $form->validate()) { + // Make sure that there's not a conflict + if (Database::instance() + ->from("items") + ->where("parent_id", $album->parent_id) + ->where("id <>", $album->id) + ->where("name", $form->edit_album->dirname->value) + ->count_records()) { + $form->edit_album->dirname->add_error("conflict", 1); + $valid = false; + } + } + + // @todo + // @todo we need to make sure that filename / dirname components can't contain a / + // @todo + + if ($valid) { + $orig = clone $album; + $album->title = $form->edit_album->title->value; + $album->description = $form->edit_album->description->value; + $album->sort_column = $form->edit_album->sort_order->column->value; + $album->sort_order = $form->edit_album->sort_order->direction->value; + $album->rename($form->edit_album->dirname->value); + $album->save(); + + module::event("item_updated", $orig, $album); + + log::success("content", "Updated album", "id\">view"); + message::success(t("Saved album %album_title", array("album_title" => $album->title))); + + print json_encode( + array("result" => "success", + "location" => url::site("albums/$album->id"))); + } else { + print json_encode( + array("result" => "error", + "form" => $form->__toString())); + } + } + + /** + * @see REST_Controller::_form_add($parameters) + */ + public function _form_add($album_id) { + $album = ORM::factory("item", $album_id); + access::required("add", $album); + + switch ($this->input->get("type")) { + case "album": + print album::get_add_form($album) . + html::script("core/js/albums_form_add.js"); + break; + + case "photo": + print photo::get_add_form($album); + break; + + default: + kohana::show_404(); + } + } + + /** + * @see REST_Controller::_form_add($parameters) + */ + public function _form_edit($album) { + access::required("edit", $album); + + print album::get_edit_form($album); + } +} diff --git a/modules/gallery/controllers/file_proxy.php b/modules/gallery/controllers/file_proxy.php new file mode 100644 index 00000000..f3c5f109 --- /dev/null +++ b/modules/gallery/controllers/file_proxy.php @@ -0,0 +1,120 @@ +input->server("REQUEST_URI"); + $request_uri = preg_replace("/\?.*/", "", $request_uri); + + // var_uri: http://example.com/gallery3/var/ + $var_uri = url::file("var/"); + + // Make sure that the request is for a file inside var + $offset = strpos($request_uri, $var_uri); + if ($offset === false) { + kohana::show_404(); + } + + $file = substr($request_uri, strlen($var_uri)); + + // Make sure that we don't leave the var dir + if (strpos($file, "..") !== false) { + kohana::show_404(); + } + + // We only handle var/resizes and var/albums + $paths = explode("/", $file); + $type = $paths[0]; + if ($type != "resizes" && $type != "albums" && $type != "thumbs") { + kohana::show_404(); + } + + // If the last element is .album.jpg, pop that off since it's not a real item + if ($paths[count($paths)-1] == ".album.jpg") { + array_pop($paths); + } + if ($paths[count($paths)-1] == "") { + array_pop($paths); + } + + // Find all items that match the level and name, then iterate over those to find a match. + // In most cases we'll get it in one. Note that for the level calculation, we just count the + // size of $paths. $paths includes the type ("thumbs", etc) but it doesn't include the root, + // so it's a wash. + $count = count($paths); + $compare_file = VARPATH . $file; + $item = null; + foreach (ORM::factory("item") + ->where("name", $paths[$count - 1]) + ->where("level", $count) + ->find_all() as $match) { + if ($type == "albums") { + $match_file = $match->file_path(); + } else if ($type == "resizes") { + $match_file = $match->resize_path(); + } else { + $match_file = $match->thumb_path(); + } + if ($match_file == $compare_file) { + $item = $match; + break; + } + } + + if (!$item) { + kohana::show_404(); + } + + // Make sure we have access to the item + if (!access::can("view", $item)) { + kohana::show_404(); + } + + // Make sure we have view_full access to the original + if ($type == "albums" && !access::can("view_full", $item)) { + kohana::show_404(); + } + + // Don't try to load a directory + if ($type == "albums" && $item->is_album()) { + kohana::show_404(); + } + + if (!file_exists($match_file)) { + kohana::show_404(); + } + + // Dump out the image + header("Content-Type: $item->mime_type"); + Kohana::close_buffers(false); + $fd = fopen($match_file, "rb"); + fpassthru($fd); + fclose($fd); + } +} diff --git a/modules/gallery/controllers/items.php b/modules/gallery/controllers/items.php new file mode 100644 index 00000000..13891726 --- /dev/null +++ b/modules/gallery/controllers/items.php @@ -0,0 +1,30 @@ +url(array(), true)); + } +} diff --git a/modules/gallery/controllers/l10n_client.php b/modules/gallery/controllers/l10n_client.php new file mode 100644 index 00000000..17520051 --- /dev/null +++ b/modules/gallery/controllers/l10n_client.php @@ -0,0 +1,128 @@ +admin or access::forbidden(); + + $input = Input::instance(); + $message = $input->post("l10n-message-source"); + $translation = $input->post("l10n-edit-target"); + $key = I18n::get_message_key($message); + $locale = I18n::instance()->locale(); + + $entry = ORM::factory("outgoing_translation") + ->where(array("key" => $key, + "locale" => $locale)) + ->find(); + + if (!$entry->loaded) { + $entry->key = $key; + $entry->locale = $locale; + $entry->message = serialize($message); + $entry->base_revision = null; + } + + $entry->translation = serialize($translation); + + $entry_from_incoming = ORM::factory("incoming_translation") + ->where(array("key" => $key, + "locale" => $locale)) + ->find(); + + if (!$entry_from_incoming->loaded) { + $entry->base_revision = $entry_from_incoming->revision; + } + + $entry->save(); + + print json_encode(new stdClass()); + } + + public function toggle_l10n_mode() { + access::verify_csrf(); + + $session = Session::instance(); + $session->set("l10n_mode", + !$session->get("l10n_mode", false)); + + url::redirect("albums/1"); + } + + private static function _l10n_client_form() { + $form = new Forge("l10n_client/save", "", "post", array("id" => "gL10nClientSaveForm")); + $group = $form->group("l10n_message"); + $group->hidden("l10n-message-source")->value(""); + $group->textarea("l10n-edit-target"); + $group->submit("l10n-edit-save")->value(t("Save translation")); + // TODO(andy_st): Avoiding multiple submit buttons for now (hassle with jQuery form plugin). + // $group->submit("l10n-edit-copy")->value(t("Copy source")); + // $group->submit("l10n-edit-clear")->value(t("Clear")); + + return $form; + } + + private static function _l10n_client_search_form() { + $form = new Forge("l10n_client/search", "", "post", array("id" => "gL10nSearchForm")); + $group = $form->group("l10n_search"); + $group->input("l10n-search")->id("gL10nSearch"); + $group->submit("l10n-search-filter-clear")->value(t("X")); + + return $form; + } + + public static function l10n_form() { + $calls = I18n::instance()->call_log(); + + if ($calls) { + $string_list = array(); + foreach ($calls as $call) { + list ($message, $options) = $call; + // Note: Don't interpolate placeholders for the actual translation input field. + // TODO: Use $options to generate a preview. + if (is_array($message)) { + // TODO: Handle plural forms. + // Translate each message. If it has a plural form, get + // the current locale's plural rules and all plural translations. + continue; + } + $source = $message; + $translation = ''; + $options_for_raw_translation = array(); + if (isset($options['count'])) { + $options_for_raw_translation['count'] = $options['count']; + } + if (I18n::instance()->has_translation($message, $options_for_raw_translation)) { + $translation = I18n::instance()->translate($message, $options_for_raw_translation); + } + $string_list[] = array('source' => $source, + 'translation' => $translation); + } + + $v = new View('l10n_client.html'); + $v->string_list = $string_list; + $v->l10n_form = self::_l10n_client_form(); + $v->l10n_search_form = self::_l10n_client_search_form(); + return $v; + } + + return ''; + } +} diff --git a/modules/gallery/controllers/maintenance.php b/modules/gallery/controllers/maintenance.php new file mode 100644 index 00000000..b5f39bed --- /dev/null +++ b/modules/gallery/controllers/maintenance.php @@ -0,0 +1,24 @@ +source = $source; + $view->tree = $this->_get_tree_html($source, ORM::factory("item", 1)); + print $view; + } + + public function save($source_id) { + access::verify_csrf(); + $source = ORM::factory("item", $source_id); + $target = ORM::factory("item", $this->input->post("target_id")); + + item::move($source, $target); + + print json_encode( + array("result" => "success", + "location" => url::site("albums/{$target->id}"))); + } + + public function show_sub_tree($source_id, $target_id) { + $source = ORM::factory("item", $source_id); + $target = ORM::factory("item", $target_id); + access::required("edit", $source); + access::required("view", $target); + + print $this->_get_tree_html($source, $target); + } + + private function _get_tree_html($source, $target) { + $view = new View("move_tree.html"); + $view->source = $source; + $view->parent = $target; + $view->children = ORM::factory("item") + ->viewable() + ->where("type", "album") + ->where("parent_id", $target->id) + ->find_all(); + return $view; + } + +} diff --git a/modules/gallery/controllers/movies.php b/modules/gallery/controllers/movies.php new file mode 100644 index 00000000..55bbb0e5 --- /dev/null +++ b/modules/gallery/controllers/movies.php @@ -0,0 +1,114 @@ +viewable() + ->where("parent_id", $photo->parent_id) + ->where("id >", $photo->id) + ->orderby("id", "ASC") + ->find(); + $previous_item = ORM::factory("item") + ->viewable() + ->where("parent_id", $photo->parent_id) + ->where("id <", $photo->id) + ->orderby("id", "DESC") + ->find(); + $position = ORM::factory("item") + ->viewable() + ->where("parent_id", $photo->parent_id) + ->where("id <=", $photo->id) + ->count_all(); + + $template = new Theme_View("page.html", "photo"); + $template->set_global("item", $photo); + $template->set_global("children", array()); + $template->set_global("children_count", $photo->children_count()); + $template->set_global("parents", $photo->parents()); + $template->set_global("next_item", $next_item->loaded ? $next_item : null); + $template->set_global("previous_item", $previous_item->loaded ? $previous_item : null); + $template->set_global("sibling_count", $photo->parent()->children_count()); + $template->set_global("position", $position); + + $template->content = new View("movie.html"); + + $photo->view_count++; + $photo->save(); + + print $template; + } + + /** + * @see REST_Controller::_update($resource) + */ + public function _update($photo) { + access::required("edit", $photo); + + $form = photo::get_edit_form($photo); + if ($valid = $form->validate()) { + // Make sure that there's not a conflict + if (Database::instance() + ->from("items") + ->where("parent_id", $photo->parent_id) + ->where("id <>", $photo->id) + ->where("name", $form->edit_photo->filename->value) + ->count_records()) { + $form->edit_photo->filename->add_error("conflict", 1); + $valid = false; + } + } + + if ($valid) { + $orig = clone $photo; + $photo->title = $form->edit_photo->title->value; + $photo->description = $form->edit_photo->description->value; + $photo->rename($form->edit_photo->filename->value); + $photo->save(); + + module::event("item_updated", $orig, $photo); + + log::success("content", "Updated photo", "id\">view"); + message::success(t("Saved photo %photo_title", array("photo_title" => $photo->title))); + + print json_encode( + array("result" => "success", + "location" => url::site("photos/$photo->id"))); + } else { + print json_encode( + array("result" => "error", + "form" => $form->__toString())); + } + } + + /** + * @see REST_Controller::_form_edit($resource) + */ + public function _form_edit($photo) { + access::required("edit", $photo); + print photo::get_edit_form($photo); + } +} diff --git a/modules/gallery/controllers/permissions.php b/modules/gallery/controllers/permissions.php new file mode 100644 index 00000000..b0cee303 --- /dev/null +++ b/modules/gallery/controllers/permissions.php @@ -0,0 +1,80 @@ +is_album()) { + access::forbidden(); + } + + $view = new View("permissions_browse.html"); + $view->htaccess_works = access::htaccess_works(); + $view->item = $item; + $view->parents = $item->parents(); + $view->form = $this->_get_form($item); + + print $view; + } + + function form($id) { + $item = ORM::factory("item", $id); + access::required("edit", $item); + + if (!$item->is_album()) { + access::forbidden(); + } + + print $this->_get_form($item); + } + + function change($command, $group_id, $perm_id, $item_id) { + access::verify_csrf(); + $group = ORM::factory("group", $group_id); + $perm = ORM::factory("permission", $perm_id); + $item = ORM::factory("item", $item_id); + access::required("edit", $item); + + if ($group->loaded && $perm->loaded && $item->loaded) { + switch($command) { + case "allow": + access::allow($group, $perm->name, $item); + break; + + case "deny": + access::deny($group, $perm->name, $item); + break; + + case "reset": + access::reset($group, $perm->name, $item); + break; + } + } + } + + function _get_form($item) { + $view = new View("permissions_form.html"); + $view->item = $item; + $view->groups = ORM::factory("group")->find_all(); + $view->permissions = ORM::factory("permission")->find_all(); + return $view; + } +} diff --git a/modules/gallery/controllers/photos.php b/modules/gallery/controllers/photos.php new file mode 100644 index 00000000..5d4040cf --- /dev/null +++ b/modules/gallery/controllers/photos.php @@ -0,0 +1,116 @@ +viewable() + ->where("parent_id", $photo->parent_id) + ->where("id >", $photo->id) + ->orderby("id", "ASC") + ->find(); + $previous_item = ORM::factory("item") + ->viewable() + ->where("parent_id", $photo->parent_id) + ->where("id <", $photo->id) + ->orderby("id", "DESC") + ->find(); + $position = ORM::factory("item") + ->viewable() + ->where("parent_id", $photo->parent_id) + ->where("id <=", $photo->id) + ->count_all(); + + $template = new Theme_View("page.html", "photo"); + $template->set_global("item", $photo); + $template->set_global("children", array()); + $template->set_global("children_count", $photo->children_count()); + $template->set_global("parents", $photo->parents()); + $template->set_global("next_item", $next_item->loaded ? $next_item : null); + $template->set_global("previous_item", $previous_item->loaded ? $previous_item : null); + $template->set_global("sibling_count", $photo->parent()->children_count()); + $template->set_global("position", $position); + + $template->content = new View("photo.html"); + + $photo->view_count++; + $photo->save(); + + print $template; + } + + /** + * @see REST_Controller::_update($resource) + */ + public function _update($photo) { + access::required("edit", $photo); + + $form = photo::get_edit_form($photo); + if ($valid = $form->validate()) { + if ($form->edit_photo->filename->value != $photo->name) { + // Make sure that there's not a conflict + if (Database::instance() + ->from("items") + ->where("parent_id", $photo->parent_id) + ->where("id <>", $photo->id) + ->where("name", $form->edit_photo->filename->value) + ->count_records()) { + $form->edit_photo->filename->add_error("conflict", 1); + $valid = false; + } + } + } + + if ($valid) { + $orig = clone $photo; + $photo->title = $form->edit_photo->title->value; + $photo->description = $form->edit_photo->description->value; + $photo->rename($form->edit_photo->filename->value); + $photo->save(); + + module::event("item_updated", $orig, $photo); + + log::success("content", "Updated photo", "id\">view"); + message::success(t("Saved photo %photo_title", array("photo_title" => $photo->title))); + + print json_encode( + array("result" => "success", + "location" => url::site("photos/$photo->id"))); + } else { + print json_encode( + array("result" => "error", + "form" => $form->__toString())); + } + } + + /** + * @see REST_Controller::_form_edit($resource) + */ + public function _form_edit($photo) { + access::required("edit", $photo); + print photo::get_edit_form($photo); + } +} diff --git a/modules/gallery/controllers/quick.php b/modules/gallery/controllers/quick.php new file mode 100644 index 00000000..643dce30 --- /dev/null +++ b/modules/gallery/controllers/quick.php @@ -0,0 +1,122 @@ +loaded) { + return ""; + } + + $view = new View("quick_pane.html"); + $view->item = $item; + $view->page_type = Input::instance()->get("page_type"); + print $view; + } + + public function rotate($id, $dir) { + access::verify_csrf(); + $item = ORM::factory("item", $id); + if (!$item->loaded) { + return ""; + } + + $degrees = 0; + switch($dir) { + case "ccw": + $degrees = -90; + break; + + case "cw": + $degrees = 90; + break; + } + + if ($degrees) { + graphics::rotate($item->file_path(), $item->file_path(), array("degrees" => $degrees)); + + list($item->width, $item->height) = getimagesize($item->file_path()); + $item->resize_dirty= 1; + $item->thumb_dirty= 1; + $item->save(); + + graphics::generate($item); + + $parent = $item->parent(); + if ($parent->album_cover_item_id == $item->id) { + copy($item->thumb_path(), $parent->thumb_path()); + $parent->thumb_width = $item->thumb_width; + $parent->thumb_height = $item->thumb_height; + $parent->save(); + } + } + + if (Input::instance()->get("page_type") == "album") { + print json_encode( + array("src" => $item->thumb_url() . "?rnd=" . rand(), + "width" => $item->thumb_width, + "height" => $item->thumb_height)); + } else { + print json_encode( + array("src" => $item->resize_url() . "?rnd=" . rand(), + "width" => $item->resize_width, + "height" => $item->resize_height)); + } + } + + public function make_album_cover($id) { + access::verify_csrf(); + item::make_album_cover(ORM::factory("item", $id)); + + print json_encode(array("result" => "success")); + } + + public function delete($id) { + access::verify_csrf(); + $item = ORM::factory("item", $id); + access::required("edit", $item); + + if ($item->is_album()) { + $msg = t("Deleted album %title", array("title" => $item->title)); + } else { + $msg = t("Deleted photo %title", array("title" => $item->title)); + } + + $item->delete(); + message::success($msg); + + if (Input::instance()->get("page_type") == "album") { + print json_encode(array("result" => "success", "reload" => 1)); + } else { + print json_encode(array("result" => "success", + "location" => url::site("albums/$parent->id"))); + } + } + + public function form_edit($id) { + $item = ORM::factory("item", $id); + access::required("edit", $item); + if ($item->is_album()) { + $form = album::get_edit_form($item); + } else { + $form = photo::get_edit_form($item); + } + print $form; + } +} diff --git a/modules/gallery/controllers/rest.php b/modules/gallery/controllers/rest.php new file mode 100644 index 00000000..11a6bbac --- /dev/null +++ b/modules/gallery/controllers/rest.php @@ -0,0 +1,183 @@ +resource_type == null) { + throw new Exception("@todo ERROR_MISSING_RESOURCE_TYPE"); + } + parent::__construct(); + } + + /** + * Handle dispatching for all REST controllers. + */ + public function __call($function, $args) { + // If no parameter was provided after the controller name (eg "/albums") then $function will + // be set to "index". Otherwise, $function is the first parameter, and $args are all + // subsequent parameters. + $request_method = rest::request_method(); + if ($function == "index" && $request_method == "get") { + return $this->_index(); + } + + $resource = ORM::factory($this->resource_type, (int)$function); + if (!$resource->loaded && $request_method != "post") { + return Kohana::show_404(); + } + + if ($request_method != "get") { + access::verify_csrf(); + } + + switch ($request_method) { + case "get": + return $this->_show($resource); + + case "put": + return $this->_update($resource); + + case "delete": + return $this->_delete($resource); + + case "post": + return $this->_create($resource); + } + } + + /* We're editing an existing item, load it from the database. */ + public function form_edit($resource_id) { + if ($this->resource_type == null) { + throw new Exception("@todo ERROR_MISSING_RESOURCE_TYPE"); + } + + // @todo this needs security checks + $resource = ORM::factory($this->resource_type, $resource_id); + if (!$resource->loaded) { + return Kohana::show_404(); + } + + return $this->_form_edit($resource); + } + + /* We're adding a new item, pass along any additional parameters. */ + public function form_add($parameters) { + return $this->_form_add($parameters); + } + + /** + * Perform a GET request on the controller root + * (e.g. http://www.example.com/gallery3/comments) + */ + public function _index() { + throw new Exception("@todo _create NOT IMPLEMENTED"); + } + + /** + * Perform a POST request on this resource + * @param ORM $resource the instance of this resource type + */ + public function _create($resource) { + throw new Exception("@todo _create NOT IMPLEMENTED"); + } + + /** + * Perform a GET request on this resource + * @param ORM $resource the instance of this resource type + */ + public function _show($resource) { + throw new Exception("@todo _show NOT IMPLEMENTED"); + } + + /** + * Perform a PUT request on this resource + * @param ORM $resource the instance of this resource type + */ + public function _update($resource) { + throw new Exception("@todo _update NOT IMPLEMENTED"); + } + + /** + * Perform a DELETE request on this resource + * @param ORM $resource the instance of this resource type + */ + public function _delete($resource) { + throw new Exception("@todo _delete NOT IMPLEMENTED"); + } + + /** + * Present a form for adding a new resource + * @param string part of the URI after the controller name + */ + public function _form_add($parameter) { + throw new Exception("@todo _form_add NOT IMPLEMENTED"); + } + + /** + * Present a form for editing an existing resource + * @param ORM $resource the resource container for instances of this resource type + */ + public function _form_edit($resource) { + throw new Exception("@todo _form_edit NOT IMPLEMENTED"); + } +} diff --git a/modules/gallery/controllers/scaffold.php b/modules/gallery/controllers/scaffold.php new file mode 100644 index 00000000..f0063725 --- /dev/null +++ b/modules/gallery/controllers/scaffold.php @@ -0,0 +1,437 @@ +template->album_count = ORM::factory("item")->where("type", "album")->count_all(); + $this->template->photo_count = ORM::factory("item")->where("type", "photo")->count_all(); + $this->template->album_tree = $this->_load_album_tree(); + $this->template->add_photo_html = $this->_get_add_photo_html(); + } catch (Exception $e) { + $this->template->album_count = 0; + $this->template->photo_count = 0; + $this->template->deepest_photo = null; + $this->template->album_tree = array(); + $this->template->add_photo_html = ""; + } + + $this->_load_comment_info(); + $this->_load_tag_info(); + + restore_error_handler(); + + if (!empty($session) && $session->get("profiler", false)) { + $profiler = new Profiler(); + $profiler->render(); + } + } + + + function add_photos() { + $path = trim($this->input->post("path")); + $parent_id = (int)$this->input->post("parent_id"); + $parent = ORM::factory("item", $parent_id); + if (!$parent->loaded) { + throw new Exception("@todo BAD_ALBUM"); + } + + batch::start(); + cookie::set("add_photos_path", $path); + $photo_count = 0; + foreach (glob("$path/*.[Jj][Pp][Gg]") as $file) { + set_time_limit(30); + photo::create($parent, $file, basename($file), basename($file)); + $photo_count++; + } + batch::stop(); + + if ($photo_count > 0) { + log::success("content", "(scaffold) Added $photo_count photos", + html::anchor("albums/$parent_id", "View album")); + } + + url::redirect("scaffold"); + } + + function add_albums_and_photos($count, $desired_type=null) { + srand(time()); + $parents = ORM::factory("item")->where("type", "album")->find_all()->as_array(); + $owner_id = user::active()->id; + + $test_images = glob(APPPATH . "tests/images/*.[Jj][Pp][Gg]"); + + batch::start(); + $album_count = $photo_count = 0; + for ($i = 0; $i < $count; $i++) { + set_time_limit(30); + + $parent = $parents[array_rand($parents)]; + $parent->reload(); + $type = $desired_type; + if (!$type) { + $type = rand(0, 10) ? "photo" : "album"; + } + if ($type == "album") { + $thumb_size = module::get_var("core", "thumb_size"); + $parents[] = album::create( + $parent, "rnd_" . rand(), "Rnd $i", "random album $i", $owner_id) + ->save(); + $album_count++; + } else { + $photo_index = rand(0, count($test_images) - 1); + photo::create($parent, $test_images[$photo_index], basename($test_images[$photo_index]), + "rnd_" . rand(), "sample thumb", $owner_id); + $photo_count++; + } + } + batch::stop(); + + if ($photo_count > 0) { + log::success("content", "(scaffold) Added $photo_count photos"); + } + + if ($album_count > 0) { + log::success("content", "(scaffold) Added $album_count albums"); + } + url::redirect("scaffold"); + } + + function random_phrase($count) { + static $words; + if (empty($words)) { + $sample_text = "Sed ut perspiciatis, unde omnis iste natus error sit voluptatem accusantium + laudantium, totam rem aperiam eaque ipsa, quae ab illo inventore veritatis et quasi + architecto beatae vitae dicta sunt, explicabo. Nemo enim ipsam voluptatem, quia voluptas + sit, aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos, qui ratione + voluptatem sequi nesciunt, neque porro quisquam est, qui dolorem ipsum, quia dolor sit, + amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora incidunt, ut + labore et dolore magnam aliquam quaerat voluptatem. Ut enim ad minima veniam, quis + nostrum exercitationem ullam corporis suscipit laboriosam, nisi ut aliquid ex ea commodi + consequatur? Quis autem vel eum iure reprehenderit, qui in ea voluptate velit esse, quam + nihil molestiae consequatur, vel illum, qui dolorem eum fugiat, quo voluptas nulla + pariatur? At vero eos et accusamus et iusto odio dignissimos ducimus, qui blanditiis + praesentium voluptatum deleniti atque corrupti, quos dolores et quas molestias excepturi + sint, obcaecati cupiditate non provident, similique sunt in culpa, qui officia deserunt + mollitia animi, id est laborum et dolorum fuga. Et harum quidem rerum facilis est et + expedita distinctio. Nam libero tempore, cum soluta nobis est eligendi optio, cumque + nihil impedit, quo minus id, quod maxime placeat, facere possimus, omnis voluptas + assumenda est, omnis dolor repellendus. Temporibus autem quibusdam et aut officiis + debitis aut rerum necessitatibus saepe eveniet, ut et voluptates repudiandae sint et + molestiae non recusandae. Itaque earum rerum hic tenetur a sapiente delectus, ut aut + reiciendis voluptatibus maiores alias consequatur aut perferendis doloribus asperiores + repellat."; + $words = preg_split('/\s+/', $sample_text); + } + + $chosen = array(); + for ($i = 0; $i < $count; $i++) { + $chosen[] = $words[array_rand($words)]; + } + + return implode(' ', $chosen); + } + + function add_comments($count) { + srand(time()); + $photos = ORM::factory("item")->where("type", "photo")->find_all()->as_array(); + $users = ORM::factory("user")->find_all()->as_array(); + + if (empty($photos)) { + url::redirect("scaffold"); + } + + if (module::is_active("akismet")) { + akismet::$test_mode = 1; + } + for ($i = 0; $i < $count; $i++) { + $photo = $photos[array_rand($photos)]; + $author = $users[array_rand($users)]; + $guest_name = ucfirst($this->random_phrase(rand(1, 3))); + $guest_email = sprintf("%s@%s.com", $this->random_phrase(1), $this->random_phrase(1)); + $guest_url = sprintf("http://www.%s.com", $this->random_phrase(1)); + comment::create($photo, $author, $this->random_phrase(rand(8, 500)), + $guest_name, $guest_email, $guest_url); + } + + url::redirect("scaffold"); + } + + function add_tags($count) { + $items = ORM::factory("item")->find_all()->as_array(); + + if (!empty($items)) { + $tags = $this->_generateTags($count); + + while ($count-- > 0) { + $tag_name = $tags[array_rand($tags)]; + $item = $items[array_rand($items)]; + + tag::add($item, $tag_name); + } + } + + url::redirect("scaffold"); + } + + private function _generateTags($number){ + // Words from lorem2.com + $words = explode( + " ", + "Lorem ipsum dolor sit amet consectetuer adipiscing elit Donec odio Quisque volutpat " . + "mattis eros Nullam malesuada erat ut turpis Suspendisse urna nibh viverra non " . + "semper suscipit posuere a pede Donec nec justo eget felis facilisis " . + "fermentum Aliquam porttitor mauris sit amet orci Aenean dignissim pellentesque " . + "felis Morbi in sem quis dui placerat ornare Pellentesque odio nisi euismod in " . + "pharetra a ultricies in diam Sed arcu Cras consequat Praesent dapibus neque " . + "id cursus faucibus tortor neque egestas augue eu vulputate magna eros eu " . + "erat Aliquam erat volutpat Nam dui mi tincidunt quis accumsan porttitor " . + "facilisis luctus metus Phasellus ultrices nulla quis nibh Quisque a " . + "lectus Donec consectetuer ligula vulputate sem tristique cursus Nam nulla quam " . + "gravida non commodo a sodales sit amet nisi Pellentesque fermentum " . + "dolor Aliquam quam lectus facilisis auctor ultrices ut elementum vulputate " . + "nunc Sed adipiscing ornare risus Morbi est est blandit sit amet sagittis vel " . + "euismod vel velit Pellentesque egestas sem Suspendisse commodo ullamcorper " . + "magna"); + + while ($number--) { + $results[] = $words[array_rand($words, 1)]; + } + return $results; + } + + function _error_handler($x) { + } + + private function _load_comment_info() { + if (class_exists("Comment_Model")) { + $this->template->comment_count = ORM::factory("comment")->count_all(); + } else { + $this->template->comment_count = 0; + } + } + + private function _load_tag_info() { + if (class_exists("Tag_Model")) { + $this->template->tag_count = ORM::factory("tag")->count_all(); + $this->template->most_tagged = Database::instance() + ->select("item_id AS id", "COUNT(tag_id) AS count") + ->from("items_tags") + ->groupby("item_id") + ->orderby("count", "DESC") + ->limit(1) + ->get() + ->current(); + } else { + $this->template->tag_count = 0; + $this->template->most_tagged = 0; + } + } + + function install($module_name, $redirect=true) { + $to_install = array(); + if ($module_name == "*") { + foreach (module::available() as $module_name => $info) { + if (empty($info->installed)) { + $to_install[] = $module_name; + } + } + } else { + $to_install[] = $module_name; + } + + foreach ($to_install as $module_name) { + if ($module_name != "core") { + require_once(DOCROOT . "modules/${module_name}/helpers/${module_name}_installer.php"); + } + module::install($module_name); + } + + if ($redirect) { + url::redirect("scaffold"); + } + } + + + public function package() { + $this->auto_render = false; + $db = Database::instance(); + + // Drop all tables + foreach ($db->list_tables() as $table) { + $db->query("DROP TABLE IF EXISTS `$table`"); + } + + // Clean out data + dir::unlink(VARPATH . "uploads"); + dir::unlink(VARPATH . "albums"); + dir::unlink(VARPATH . "resizes"); + dir::unlink(VARPATH . "thumbs"); + dir::unlink(VARPATH . "modules"); + dir::unlink(VARPATH . "tmp"); + + $db->clear_cache(); + module::$modules = array(); + module::$active = array(); + + // Use a known random seed so that subsequent packaging runs will reuse the same random + // numbers, keeping our install.sql file more stable. + srand(0); + + try { + core_installer::install(true); + module::load_modules(); + + foreach (array("user", "comment", "organize", "info", "rss", + "search", "slideshow", "tag") as $module_name) { + module::install($module_name); + module::activate($module_name); + } + } catch (Exception $e) { + Kohana::log("error", $e->getTraceAsString()); + print $e->getTrace(); + throw $e; + } + + url::redirect("scaffold/dump_database"); + } + + public function dump_database() { + $this->auto_render = false; + + // We now have a clean install with just the packages that we want. Make sure that the + // database is clean too. + $db = Database::instance(); + $db->query("TRUNCATE {sessions}"); + $db->query("TRUNCATE {logs}"); + $db->query("DELETE FROM {vars} WHERE `module_name` = 'core' AND `name` = '_cache'"); + $db->update("users", array("password" => ""), array("id" => 1)); + $db->update("users", array("password" => ""), array("id" => 2)); + + $dbconfig = Kohana::config('database.default'); + $conn = $dbconfig["connection"]; + $pass = $conn["pass"] ? "-p{$conn['pass']}" : ""; + $sql_file = DOCROOT . "installer/install.sql"; + if (!is_writable($sql_file)) { + print "$sql_file is not writeable"; + return; + } + $command = "mysqldump --compact --add-drop-table -h{$conn['host']} " . + "-u{$conn['user']} $pass {$conn['database']} > $sql_file"; + exec($command, $output, $status); + if ($status) { + print "
      ";
      +      print "$command\n";
      +      print "Failed to dump database\n";
      +      print implode("\n", $output);
      +      return;
      +    }
      +
      +    // Post-process the sql file
      +    $buf = "";
      +    $root_timestamp = ORM::factory("item", 1)->created;
      +    foreach (file($sql_file) as $line) {
      +      // Prefix tables
      +      $line = preg_replace(
      +        "/(CREATE TABLE|IF EXISTS|INSERT INTO) `{$dbconfig['table_prefix']}(\w+)`/", "\\1 {\\2}",
      +        $line);
      +
      +      // Normalize dates
      +      $line = preg_replace("/,$root_timestamp,/", ",UNIX_TIMESTAMP(),", $line);
      +      $buf .= $line;
      +    }
      +    $fd = fopen($sql_file, "wb");
      +    fwrite($fd, $buf);
      +    fclose($fd);
      +
      +    url::redirect("scaffold/dump_var");
      +  }
      +
      +  public function dump_var() {
      +    $this->auto_render = false;
      +
      +    $objects = new RecursiveIteratorIterator(
      +      new RecursiveDirectoryIterator(VARPATH),
      +      RecursiveIteratorIterator::SELF_FIRST);
      +
      +    $var_file = DOCROOT . "installer/init_var.php";
      +    if (!is_writable($var_file)) {
      +      print "$var_file is not writeable";
      +      return;
      +    }
      +
      +    $paths = array();
      +    foreach($objects as $name => $file){
      +      if ($file->getBasename() == "database.php") {
      +        continue;
      +      } else if (basename($file->getPath()) == "logs") {
      +        continue;
      +      }
      +
      +      if ($file->isDir()) {
      +        $paths[] = "VARPATH . \"" . substr($name, strlen(VARPATH)) . "\"";
      +      } else {
      +        // @todo: serialize non-directories
      +        print "Unknown file: $name";
      +        return;
      +      }
      +    }
      +    // Sort the paths so that the var file is stable
      +    sort($paths);
      +
      +    $fd = fopen($var_file, "w");
      +    fwrite($fd, "\n");
      +    fwrite($fd, "where("type", "album")->find_all() as $album) {
      +      if ($album->parent_id) {
      +        $tree[$album->parent_id]->children[] = $album->id;
      +      }
      +      $tree[$album->id]->album = $album;
      +      $tree[$album->id]->children = array();
      +    }
      +
      +    return $tree;
      +  }
      +
      +  public function form($arg1, $arg2) {
      +    if ($arg1 == "add" && $arg2 == "photos") {
      +      print $this->_get_add_photo_html();
      +    }
      +    $this->auto_render = false;
      +  }
      +
      +  public function _get_add_photo_html($parent_id=1) {
      +    $parent = ORM::factory("item", $parent_id);
      +    return photo::get_add_form($parent);
      +  }
      +}
      diff --git a/modules/gallery/controllers/simple_uploader.php b/modules/gallery/controllers/simple_uploader.php
      new file mode 100644
      index 00000000..bdf9582f
      --- /dev/null
      +++ b/modules/gallery/controllers/simple_uploader.php
      @@ -0,0 +1,86 @@
      +item = $item;
      +    print $v;
      +  }
      +
      +  public function start() {
      +    batch::start();
      +  }
      +
      +  public function add_photo($id) {
      +    $album = ORM::factory("item", $id);
      +    access::required("add", $album);
      +    access::verify_csrf();
      +
      +    $file_validation = new Validation($_FILES);
      +    $file_validation->add_rules("Filedata", "upload::valid", "upload::type[gif,jpg,png,flv,mp4]");
      +    if ($file_validation->validate()) {
      +
      +      // SimpleUploader.swf does not yet call /start directly, so simulate it here for now.
      +      if (!batch::in_progress()) {
      +        batch::start();
      +      }
      +
      +      $temp_filename = upload::save("Filedata");
      +      try {
      +        $name = substr(basename($temp_filename), 10);  // Skip unique identifier Kohana adds
      +        $title = $this->convert_filename_to_title($name);
      +        $path_info = pathinfo($temp_filename);
      +        if (array_key_exists("extension", $path_info) &&
      +            in_array(strtolower($path_info["extension"]), array("flv", "mp4"))) {
      +          $movie = movie::create($album, $temp_filename, $name, $title);
      +          log::success("content", t("Added a movie"),
      +                       html::anchor("movies/$movie->id", t("view movie")));
      +        } else {
      +          $photo = photo::create($album, $temp_filename, $name, $title);
      +          log::success("content", t("Added a photo"),
      +                       html::anchor("photos/$photo->id", t("view photo")));
      +        }
      +      } catch (Exception $e) {
      +        unlink($temp_filename);
      +        throw $e;
      +      }
      +      unlink($temp_filename);
      +    }
      +    print "File Received";
      +  }
      +
      +  /**
      +   * We should move this into a helper somewhere.. but where is appropriate?
      +   */
      +  private function convert_filename_to_title($filename) {
      +    $title = strtr($filename, "_", " ");
      +    $title = preg_replace("/\..*?$/", "", $title);
      +    $title = preg_replace("/ +/", " ", $title);
      +    return $title;
      +  }
      +
      +  public function finish() {
      +    batch::stop();
      +    print json_encode(array("result" => "success"));
      +  }
      +}
      diff --git a/modules/gallery/css/debug.css b/modules/gallery/css/debug.css
      new file mode 100644
      index 00000000..fe5665ad
      --- /dev/null
      +++ b/modules/gallery/css/debug.css
      @@ -0,0 +1,28 @@
      +.gAnnotatedThemeBlock {
      +  border: 1px solid #C00;
      +  clear: both;
      +  margin: 1em;
      +  padding: 1em;
      +  position: relative;
      +}
      +
      +.gAnnotatedThemeBlock_album_top {
      +  float: right;
      +}
      +
      +.gAnnotatedThemeBlock_header_bottom {
      +  float: right;
      +}
      +
      +.gAnnotatedThemeBlock div.title {
      +  background: #C00;
      +  border: 1px solid black;
      +  color: white;
      +  font-size: 110%;
      +  padding: 4px;
      +  position: absolute;
      +  right: -1em;
      +  top: -1em;
      +  text-align: left;
      +  -moz-border-radius: 5%;
      +}
      diff --git a/modules/gallery/css/l10n_client.css b/modules/gallery/css/l10n_client.css
      new file mode 100644
      index 00000000..8973715f
      --- /dev/null
      +++ b/modules/gallery/css/l10n_client.css
      @@ -0,0 +1,185 @@
      +// TODO(andy_st): Add original copyright notice from Drupal l10_client.
      +// TODO(andy_st): Add G3 copyright notice.
      +// TODO(andy_st): clean up formatting to match our other CSS files.
      +
      +/* $Id: l10n_client.css,v 1.6 2008/09/09 10:48:20 goba Exp $ */
      +
      +/* width percentages add to 99% rather than 100% to prevent float
      +overflows from occurring in an unnamed browser that can't decide
      +how it wants to round. */
      +
      +/* l10n_client container */
      +#l10n-client {
      +  text-align:left;
      +  z-index:99;
      +  line-height:1em;
      +  color:#000; background:#fff;
      +  position:fixed;
      +  width:100%; height: 2em;
      +  bottom:0px; left:0px;
      +  overflow:hidden;}
      +
      +  * html #l10n-client {
      +    position:static;}
      +
      +#l10n-client-string-select .string-list,
      +#l10n-client-string-editor .source,
      +#l10n-client-string-editor .editor {
      +  height:20em;}
      +
      +#l10n-client .labels {
      +  overflow:hidden;
      +  position:relative;
      +  height:2em;
      +  color:#fff;
      +  background:#37a;}
      +
      +  #l10n-client .labels .label {
      +    display:none;}
      +
      +  /* Panel toggle button (span) */
      +  #l10n-client .labels .toggle {
      +    cursor:pointer;
      +    display:block;
      +    position:absolute; right:0em;
      +    padding: 0em .75em; height:2em; line-height:2em;
      +    text-transform:uppercase;
      +    text-align:center; background:#000;}
      +
      +  /* Panel labels */
      +  #l10n-client h2 {
      +    border-left:1px solid #fff;
      +    height:1em; line-height:1em;
      +    padding: .5em; margin:0px;
      +    font-size:1em;
      +    text-transform:uppercase;}
      +
      +    #l10n-client .strings h2 {
      +      border:0px;}
      +
      +  /* 25 + 37 + 37 = 99 */
      +  #l10n-client .strings {
      +    width:25%; float:left;}
      +
      +  #l10n-client .source {
      +    width:37%; float:left;}
      +
      +  #l10n-client .translation {
      +    width:37%; float:left;}
      +
      +/* Translatable string list */
      +#l10n-client-string-select {
      +  display:none;
      +  float:left;
      +  width:25%;}
      +
      +  #l10n-client .string-list {
      +    height:17em;
      +    overflow:auto;
      +    list-style:none; list-style-image:none;
      +    margin:0em; padding:0em;}
      +
      +  #l10n-client .string-list li {
      +    font-size:.9em;
      +    line-height:1.5em;
      +    cursor:default;
      +    background:transparent;
      +    list-style:none; list-style-image:none;
      +    border-bottom:1px solid #ddd;
      +    padding:.25em .5em;
      +    margin:0em;}
      +
      +  /* Green for translated */
      +  #l10n-client .string-list li.translated {
      +    border-bottom-color:#9c3;
      +    background:#cf6; color:#360;}
      +
      +    #l10n-client .string-list li.translated:hover {
      +      background: #df8;}
      +
      +    #l10n-client .string-list li.translated:active {
      +      background: #9c3;}
      +
      +  #l10n-client .string-list li.hidden {
      +    display:none;}
      +
      +  /* Gray + Blue hover for untranslated */
      +  #l10n-client .string-list li.untranslated {}
      +
      +    #l10n-client .string-list li.untranslated:hover {
      +      background: #ace;}
      +
      +    #l10n-client .string-list li.untranslated:active {
      +      background: #8ac;}
      +
      +  /* Selected string is indicated by bold text */
      +  #l10n-client .string-list li.active {
      +    font-weight:bold;}
      +
      +  #l10n-client #gL10nSearchForm {
      +    background:#eee;
      +    text-align:center;
      +    height:2em; line-height:2em;
      +    margin:0em; padding:.5em .5em;
      +  }
      +
      +  #l10n-client #gL10nSearchForm .form-item,
      +  #l10n-client #gL10nSearchForm input.form-text,
      +  #l10n-client #gL10nSearchForm #search-filter-go,
      +  #l10n-client #gL10nSearchForm #search-filter-clear {
      +    display:inline;
      +    vertical-align:middle;
      +  }
      +
      +    #l10n-client #gL10nSearchForm .form-item {
      +      margin:0em;
      +      padding:0em;
      +    }
      +
      +    #l10n-client #gL10nSearchForm input.form-text {
      +      width:80%;
      +    }
      +
      +    #l10n-client #gL10nSearchForm #search-filter-clear {
      +      width:10%;
      +      margin:0em;
      +    }
      +
      +
      +#l10n-client-string-editor {
      +  display:none;
      +  float:left;
      +  width:74%;}
      +
      +  #l10n-client-string-editor .source {
      +    overflow:hidden;
      +    width:50%; float:left;}
      +
      +    #l10n-client-string-editor .source .source-text {
      +      line-height:1.5em;
      +      background:#eee;
      +      height:16em; margin:1em; padding:1em;
      +      overflow:auto;}
      +
      +  #l10n-client-string-editor .translation {
      +    overflow:hidden;
      +    width:49%; float:right;}
      +
      +#gL10nClientSaveForm {
      +  padding:0em;}
      +
      +  #gL10nClientSaveForm .form-textarea {
      +    height:13em;
      +    font-size:1em; line-height:1.25em;
      +    width:95%;}
      +
      +  #gL10nClientSaveForm .form-submit {
      +    margin-top: 0em;}
      +
      +
      +#l10n-client form ul,
      +#l10n-client form li,
      +#l10n-client form input[type=submit],
      +#l10n-client form input[type=text] {
      +  display: inline ! important ;
      +}
      diff --git a/modules/gallery/css/quick.css b/modules/gallery/css/quick.css
      new file mode 100644
      index 00000000..02f9953e
      --- /dev/null
      +++ b/modules/gallery/css/quick.css
      @@ -0,0 +1,40 @@
      +.gItem:hover {
      +  background-color: #cfdeff;
      +}
      +
      +.gQuick {
      +  border: none !important;
      +  margin: 0 !important;
      +  padding: 0 !important;
      +}
      +
      +#gQuickPane {
      +  background: #000;
      +  border-bottom: 1px solid #ccc;
      +  opacity: 0.9;
      +}
      +
      +#gQuickPane a {
      +  cursor: pointer;
      +  float: left;
      +  margin: 4px;
      +}
      +
      +#gQuickPaneOptions {
      +  background: #000;
      +  float: left;
      +  width: 100%;
      +}
      +
      +#gQuickPaneOptions li a {
      +  display: block;
      +  float: none;
      +  width: auto;
      +  margin: 0;
      +  padding: .5em .5em .5em .8em;
      +  text-align: left;
      +}
      +
      +#gQuickPaneOptions li a:hover {
      +  background-color: #4d4d4d;
      +}
      diff --git a/modules/gallery/helpers/MY_remote.php b/modules/gallery/helpers/MY_remote.php
      new file mode 100644
      index 00000000..4abf5bf1
      --- /dev/null
      +++ b/modules/gallery/helpers/MY_remote.php
      @@ -0,0 +1,163 @@
      + $value) {
      +      if (!empty($post_data_raw)) {
      +        $post_data_raw .= '&';
      +      }
      +      $post_data_raw .= urlencode($key) . '=' . urlencode($value);
      +    }
      +    
      +    $extra_headers['Content-Type'] = 'application/x-www-form-urlencoded';
      +    $extra_headers['Content-Length'] = strlen($post_data_raw);
      +    
      +    return $post_data_raw;
      +  }
      +
      +  /**
      +   * A single request, without following redirects
      +   *
      +   * @todo: Handle redirects? If so, only for GET (i.e. not for POST), and use G2's WebHelper_simple::_parseLocation logic.
      +   */
      +  static function do_request($url, $method='GET', $headers=array(), $body='') {
      +    /* Convert illegal characters */
      +    $url = str_replace(' ', '%20', $url);
      +    
      +    $url_components = self::_parse_url_for_fsockopen($url);
      +    $handle = fsockopen(
      +      $url_components['fsockhost'], $url_components['port'], $errno, $errstr, 5);
      +    if (empty($handle)) {
      +      // log "Error $errno: '$errstr' requesting $url";
      +      return array(null, null, null);
      +    }
      +    
      +    $header_lines = array('Host: ' . $url_components['host']);
      +    foreach ($headers as $key => $value) {
      +      $header_lines[] = $key . ': ' . $value;
      +    }
      +    
      +    $success = fwrite($handle, sprintf("%s %s HTTP/1.0\r\n%s\r\n\r\n%s",
      +                                       $method,
      +                                       $url_components['uri'],
      +                                       implode("\r\n", $header_lines),
      +                                       $body));
      +    if (!$success) {
      +      // Zero bytes written or false was returned
      +      // log "fwrite failed in requestWebPage($url)" . ($success === false ? ' - false' : ''
      +      return array(null, null, null);
      +    }
      +    fflush($handle);
      +    
      +    /*
      +     * Read the status line.  fgets stops after newlines.  The first line is the protocol
      +     * version followed by a numeric status code and its associated textual phrase.
      +     */
      +    $response_status = trim(fgets($handle, 4096));
      +    if (empty($response_status)) {
      +      // 'Empty http response code, maybe timeout'
      +      return array(null, null, null);
      +    }
      +    
      +    /* Read the headers */
      +    $response_headers = array();
      +    while (!feof($handle)) {
      +      $line = trim(fgets($handle, 4096));
      +      if (empty($line)) {
      +        break;
      +      }
      +      
      +      /* Normalize the line endings */
      +      $line = str_replace("\r", '', $line);
      +      
      +      list ($key, $value) = explode(':', $line, 2);
      +      if (isset($response_headers[$key])) {
      +        if (!is_array($response_headers[$key])) {
      +          $response_headers[$key] = array($response_headers[$key]);
      +        }
      +        $response_headers[$key][] = trim($value);
      +      } else {
      +        $response_headers[$key] = trim($value);
      +      }
      +    }
      +    
      +    /* Read the body */
      +    $response_body = '';
      +    while (!feof($handle)) {
      +      $response_body .= fread($handle, 4096);
      +    }
      +    fclose($handle);
      +
      +    return array($response_status, $response_headers, $response_body);
      +  }
      +
      +  /**
      +   * Prepare for fsockopen call.
      +   * @param string $url
      +   * @return array url components
      +   * @access private
      +   */
      +  private static function _parse_url_for_fsockopen($url) {
      +    $url_components = parse_url($url);
      +    if (strtolower($url_components['scheme']) == 'https') {
      +      $url_components['fsockhost'] = 'ssl://' . $url_components['host'];
      +      $default_port = 443;
      +    } else {
      +      $url_components['fsockhost'] = $url_components['host'];
      +      $default_port = 80;
      +    }
      +    if (empty($url_components['port'])) {
      +      $url_components['port'] = $default_port;
      +    }
      +    if (empty($url_components['path'])) {
      +      $url_components['path'] = '/';
      +    }
      +    $uri = $url_components['path']
      +      . (empty($url_components['query']) ? '' : '?' . $url_components['query']);
      +    /* Unescape ampersands, since if the url comes from form input it will be escaped */
      +    $url_components['uri'] = str_replace('&', '&', $uri);
      +    return $url_components;
      +  }
      +}
      +
      diff --git a/modules/gallery/helpers/MY_url.php b/modules/gallery/helpers/MY_url.php
      new file mode 100644
      index 00000000..81dcbe1e
      --- /dev/null
      +++ b/modules/gallery/helpers/MY_url.php
      @@ -0,0 +1,81 @@
      +relative_path();
      +    }
      +    return parent::site($uri . $query, $protocol);
      +  }
      +
      +  static function parse_url() {
      +    if (Router::$controller) {
      +      return;
      +    }
      +
      +    $count = count(Router::$segments);
      +    foreach (ORM::factory("item")
      +             ->where("name", html_entity_decode(Router::$segments[$count - 1], ENT_QUOTES))
      +             ->where("level", $count + 1)
      +             ->find_all() as $match) {
      +      if ($match->relative_path() == html_entity_decode(Router::$current_uri, ENT_QUOTES)) {
      +        $item = $match;
      +      }
      +    }
      +
      +    if (!empty($item)) {
      +      Router::$controller = "{$item->type}s";
      +      Router::$controller_path = APPPATH . "controllers/{$item->type}s.php";
      +      Router::$method = $item->id;
      +    }
      +  }
      +
      +  /**
      +   * Just like url::file() except that it returns an absolute URI
      +   */
      +  static function abs_file($path) {
      +    return url::base(
      +      false, (empty($_SERVER['HTTPS']) || $_SERVER['HTTPS'] === 'off') ? 'http' : 'https') . $path;
      +  }
      +
      +  /**
      +   * Just like url::site() except that it returns an absolute URI and
      +   * doesn't take a protocol parameter.
      +   */
      +  static function abs_site($path) {
      +    return url::site(
      +      $path, (empty($_SERVER['HTTPS']) || $_SERVER['HTTPS'] === 'off') ? 'http' : 'https');
      +  }
      +
      +  /**
      +   * Just like url::current except that it returns an absolute URI
      +   */
      +  static function abs_current($qs=false) {
      +    return self::abs_site(url::current($qs));
      +  }
      +}
      diff --git a/modules/gallery/helpers/access.php b/modules/gallery/helpers/access.php
      new file mode 100644
      index 00000000..64ce91fa
      --- /dev/null
      +++ b/modules/gallery/helpers/access.php
      @@ -0,0 +1,628 @@
      + tuples.  It would be inefficient to check
      + *   these tuples every time we want to do a lookup, so we use these intents to create an entire
      + *   table of permissions for easy lookup in the Access_Cache_Model.  There's a 1:1 mapping
      + *   between Item_Model and Access_Cache_Model entries.
      + *
      + * o For efficiency, we create columns in Access_Intent_Model and Access_Cache_Model for each of
      + *   the possible Group_Model and Permission_Model combinations.  This may lead to performance
      + *   issues for very large Gallery installs, but for small to medium sized ones (5-10 groups, 5-10
      + *   permissions) it's especially efficient because there's a single field value for each
      + *   group/permission/item combination.
      + *
      + * o For efficiency, we store the cache columns for view permissions directly in the Item_Model.
      + *   This means that we can filter items by group/permission combination without doing any table
      + *   joins making for an especially efficient permission check at the expense of having to
      + *   maintain extra columns for each item.
      + *
      + * o If at any time the Access_Cache_Model becomes invalid, we can rebuild the entire table from
      + *   the Access_Intent_Model
      + */
      +class access_Core {
      +  const DENY      = 0;
      +  const ALLOW     = 1;
      +  const UNKNOWN   = 2;
      +
      +  /**
      +   * Does the active user have this permission on this item?
      +   *
      +   * @param  string     $perm_name
      +   * @param  Item_Model $item
      +   * @return boolean
      +   */
      +  static function can($perm_name, $item) {
      +    if (!$item->loaded) {
      +      return false;
      +    }
      +
      +    if (user::active()->admin) {
      +      return true;
      +    }
      +
      +    $resource = $perm_name == "view" ?
      +      $item : model_cache::get("access_cache", $item->id, "item_id");
      +    foreach (user::group_ids() as $id) {
      +      if ($resource->__get("{$perm_name}_$id") === self::ALLOW) {
      +        return true;
      +      }
      +    }
      +    return false;
      +  }
      +
      +  /**
      +   * If the active user does not have this permission, failed with an access::forbidden().
      +   *
      +   * @param  string     $perm_name
      +   * @param  Item_Model $item
      +   * @return boolean
      +   */
      +  static function required($perm_name, $item) {
      +    if (!self::can($perm_name, $item)) {
      +      self::forbidden();
      +    }
      +  }
      +
      +  /**
      +   * Does this group have this permission on this item?
      +   *
      +   * @param  Group_Model $group
      +   * @param  string      $perm_name
      +   * @param  Item_Model  $item
      +   * @return boolean
      +   */
      +  static function group_can($group, $perm_name, $item) {
      +    $resource = $perm_name == "view" ?
      +      $item : model_cache::get("access_cache", $item->id, "item_id");
      +    return $resource->__get("{$perm_name}_{$group->id}") === self::ALLOW;
      +  }
      +
      +  /**
      +   * Return this group's intent for this permission on this item.
      +   *
      +   * @param  Group_Model $group
      +   * @param  string      $perm_name
      +   * @param  Item_Model  $item
      +   * @return integer     access::ALLOW, access::DENY or null for no intent
      +   */
      +  static function group_intent($group, $perm_name, $item) {
      +    $intent = model_cache::get("access_intent", $item->id, "item_id");
      +    return $intent->__get("{$perm_name}_{$group->id}");
      +  }
      +
      +  /**
      +   * Is the permission on this item locked by a parent?  If so return the nearest parent that
      +   * locks it.
      +   *
      +   * @param  Group_Model $group
      +   * @param  string      $perm_name
      +   * @param  Item_Model  $item
      +   * @return ORM_Model   item that locks this one
      +   */
      +  static function locked_by($group, $perm_name, $item) {
      +    if ($perm_name != "view") {
      +      return null;
      +    }
      +
      +    // For view permissions, if any parent is self::DENY, then those parents lock this one.
      +    // Return
      +    $lock = ORM::factory("item")
      +      ->where("`left` <= $item->left")
      +      ->where("`right` >= $item->right")
      +      ->where("items.id <> $item->id")
      +      ->join("access_intents", "items.id", "access_intents.item_id")
      +      ->where("access_intents.view_$group->id", 0)
      +      ->orderby("level", "DESC")
      +      ->limit(1)
      +      ->find();
      +
      +    if ($lock->loaded) {
      +      return $lock;
      +    } else {
      +      return null;
      +    }
      +  }
      +
      +  /**
      +   * Terminate immediately with an HTTP 503 Forbidden response.
      +   */
      +  static function forbidden() {
      +    throw new Exception("@todo FORBIDDEN", 503);
      +  }
      +
      +  /**
      +   * Internal method to set a permission
      +   *
      +   * @param  Group_Model $group
      +   * @param  string      $perm_name
      +   * @param  Item_Model  $item
      +   * @param  boolean     $value
      +   */
      +  private static function _set(Group_Model $group, $perm_name, $album, $value) {
      +    if (get_class($group) != "Group_Model") {
      +      throw new Exception("@todo PERMISSIONS_ONLY_WORK_ON_GROUPS");
      +    }
      +    if (!$album->loaded) {
      +      throw new Exception("@todo INVALID_ALBUM $album->id");
      +    }
      +    if (!$album->is_album()) {
      +      throw new Exception("@todo INVALID_ALBUM_TYPE not an album");
      +    }
      +    $access = model_cache::get("access_intent", $album->id, "item_id");
      +    $access->__set("{$perm_name}_{$group->id}", $value);
      +    $access->save();
      +
      +    if ($perm_name == "view") {
      +      self::_update_access_view_cache($group, $album);
      +    } else {
      +      self::_update_access_non_view_cache($group, $perm_name, $album);
      +    }
      +
      +    self::_update_htaccess_files($album, $group, $perm_name, $value);
      +  }
      +
      +  /**
      +   * Allow a group to have a permission on an item.
      +   *
      +   * @param  Group_Model $group
      +   * @param  string  $perm_name
      +   * @param  Item_Model $item
      +   */
      +  static function allow($group, $perm_name, $item) {
      +    self::_set($group, $perm_name, $item, self::ALLOW);
      +  }
      +
      +  /**
      +   * Deny a group the given permission on an item.
      +   *
      +   * @param  Group_Model $group
      +   * @param  string  $perm_name
      +   * @param  Item_Model $item
      +   */
      +  static function deny($group, $perm_name, $item) {
      +    self::_set($group, $perm_name, $item, self::DENY);
      +  }
      +
      +  /**
      +   * Unset the given permission for this item and use inherited values
      +   *
      +   * @param  Group_Model $group
      +   * @param  string  $perm_name
      +   * @param  Item_Model $item
      +   */
      +  static function reset($group, $perm_name, $item) {
      +    if ($item->id == 1) {
      +      throw new Exception("@todo CANT_RESET_ROOT_PERMISSION");
      +    }
      +    self::_set($group, $perm_name, $item, null);
      +  }
      +
      +  /**
      +   * Register a permission so that modules can use it.
      +   *
      +   * @param  string $name           The internal name for for this permission
      +   * @param  string $display_name   The internationalized version of the displayable name
      +   * @return void
      +  */
      +  static function register_permission($name, $display_name) {
      +    $permission = ORM::factory("permission", $name);
      +    if ($permission->loaded) {
      +      throw new Exception("@todo PERMISSION_ALREADY_EXISTS $name");
      +    }
      +    $permission->name = $name;
      +    $permission->display_name = $display_name;
      +    $permission->save();
      +
      +    foreach (self::_get_all_groups() as $group) {
      +      self::_add_columns($name, $group);
      +    }
      +  }
      +
      +  /**
      +   * Delete a permission.
      +   *
      +   * @param  string $perm_name
      +   * @return void
      +   */
      +  static function delete_permission($name) {
      +    foreach (self::_get_all_groups() as $group) {
      +      self::_drop_columns($name, $group);
      +    }
      +    $permission = ORM::factory("permission")->where("name", $name)->find();
      +    if ($permission->loaded) {
      +      $permission->delete();
      +    }
      +  }
      +
      +  /**
      +   * Add the appropriate columns for a new group
      +   *
      +   * @param Group_Model $group
      +   * @return void
      +   */
      +  static function add_group($group) {
      +    foreach (ORM::factory("permission")->find_all() as $perm) {
      +      self::_add_columns($perm->name, $group);
      +    }
      +  }
      +
      +  /**
      +   * Remove a group's permission columns (usually when it's deleted)
      +   *
      +   * @param Group_Model $group
      +   * @return void
      +   */
      +  static function delete_group($group) {
      +    foreach (ORM::factory("permission")->find_all() as $perm) {
      +      self::_drop_columns($perm->name, $group);
      +    }
      +  }
      +
      +  /**
      +   * Add new access rows when a new item is added.
      +   *
      +   * @param Item_Model $item
      +   * @return void
      +   */
      +  static function add_item($item) {
      +    $access_intent = ORM::factory("access_intent", $item->id);
      +    if ($access_intent->loaded) {
      +      throw new Exception("@todo ITEM_ALREADY_ADDED $item->id");
      +    }
      +    $access_intent = ORM::factory("access_intent");
      +    $access_intent->item_id = $item->id;
      +    $access_intent->save();
      +
      +    // Create a new access cache entry and copy the parents values.
      +    $access_cache = ORM::factory("access_cache");
      +    $access_cache->item_id = $item->id;
      +    if ($item->id != 1) {
      +      $parent_access_cache =
      +        ORM::factory("access_cache")->where("item_id", $item->parent()->id)->find();
      +      foreach (self::_get_all_groups() as $group) {
      +        foreach (ORM::factory("permission")->find_all() as $perm) {
      +          $field = "{$perm->name}_{$group->id}";
      +          if ($perm->name == "view") {
      +            $item->$field = $item->parent()->$field;
      +          } else {
      +            $access_cache->$field = $parent_access_cache->$field;
      +          }
      +        }
      +      }
      +    }
      +    $item->save();
      +    $access_cache->save();
      +  }
      +
      +  /**
      +   * Delete appropriate access rows when an item is deleted.
      +   *
      +   * @param Item_Model $item
      +   * @return void
      +   */
      +  static function delete_item($item) {
      +    ORM::factory("access_intent")->where("item_id", $item->id)->find()->delete();
      +    ORM::factory("access_cache")->where("item_id", $item->id)->find()->delete();
      +  }
      +
      +  /**
      +   * Verify our Cross Site Request Forgery token is valid, else throw an exception.
      +   */
      +  static function verify_csrf() {
      +    $input = Input::instance();
      +    if ($input->post("csrf", $input->get("csrf", null)) !== Session::instance()->get("csrf")) {
      +      self::forbidden();
      +    }
      +  }
      +
      +  /**
      +   * Get the Cross Site Request Forgery token for this session.
      +   * @return string
      +   */
      +  static function csrf_token() {
      +    $session = Session::instance();
      +    $csrf = $session->get("csrf");
      +    if (empty($csrf)) {
      +      $csrf = md5(rand());
      +      $session->set("csrf", $csrf);
      +    }
      +    return $csrf;
      +  }
      +
      +  /**
      +   * Generate an  element containing the Cross Site Request Forgery token for this session.
      +   * @return string
      +   */
      +  static function csrf_form_field() {
      +    return "";
      +  }
      +
      +  /**
      +   * Internal method to get all available groups.
      +   *
      +   * @return ORM_Iterator
      +   */
      +  private static function _get_all_groups() {
      +    // When we build the core package, it's possible that the user module is not installed yet.
      +    // This is ok at packaging time, so work around it.
      +    if (module::is_active("user")) {
      +      return ORM::factory("group")->find_all();
      +    } else {
      +      return array();
      +    }
      +  }
      +
      +  /**
      +   * Internal method to  remove Permission/Group columns
      +   *
      +   * @param  Group_Model $group
      +   * @param  string      $perm_name
      +   * @return void
      +   */
      +  private static function _drop_columns($perm_name, $group) {
      +    $db = Database::instance();
      +    $field = "{$perm_name}_{$group->id}";
      +    $cache_table = $perm_name == "view" ? "items" : "access_caches";
      +    $db->query("ALTER TABLE {{$cache_table}} DROP `$field`");
      +    $db->query("ALTER TABLE {access_intents} DROP `$field`");
      +    ORM::factory("access_intent")->clear_cache();
      +  }
      +
      +  /**
      +   * Internal method to add Permission/Group columns
      +   *
      +   * @param  Group_Model $group
      +   * @param  string  $perm_name
      +   * @return void
      +   */
      +  private static function _add_columns($perm_name, $group) {
      +    $db = Database::instance();
      +    $field = "{$perm_name}_{$group->id}";
      +    $cache_table = $perm_name == "view" ? "items" : "access_caches";
      +    $db->query("ALTER TABLE {{$cache_table}} ADD `$field` SMALLINT NOT NULL DEFAULT 0");
      +    $db->query("ALTER TABLE {access_intents} ADD `$field` BOOLEAN DEFAULT NULL");
      +    $db->update("access_intents", array($field => 0), array("item_id" => 1));
      +    ORM::factory("access_intent")->clear_cache();
      +  }
      +
      +  /**
      +   * Update the Access_Cache model based on information from the Access_Intent model for view
      +   * permissions only.
      +   *
      +   * @todo: use database locking
      +   *
      +   * @param  Group_Model $group
      +   * @param  Item_Model $item
      +   * @return void
      +   */
      +  private static function _update_access_view_cache($group, $item) {
      +    $access = ORM::factory("access_intent")->where("item_id", $item->id)->find();
      +
      +    $db = Database::instance();
      +    $field = "view_{$group->id}";
      +
      +    // With view permissions, deny values in the parent can override allow values in the child,
      +    // so start from the bottom of the tree and work upwards overlaying negative on top of
      +    // positive.
      +    //
      +    // If the item's intent is ALLOW or DEFAULT, it's possible that some ancestor has specified
      +    // DENY and this ALLOW cannot be obeyed.  So in that case, back up the tree and find any
      +    // non-DEFAULT and non-ALLOW parent and propagate from there.  If we can't find a matching
      +    // item, then its safe to propagate from here.
      +    if ($access->$field !== self::DENY) {
      +      $tmp_item = ORM::factory("item")
      +        ->where("left <", $item->left)
      +        ->where("right >", $item->right)
      +        ->join("access_intents", "access_intents.item_id", "items.id")
      +        ->where("access_intents.$field", self::DENY)
      +        ->orderby("left", "DESC")
      +        ->limit(1)
      +        ->find();
      +      if ($tmp_item->loaded) {
      +        $item = $tmp_item;
      +      }
      +    }
      +
      +    // We will have a problem if we're trying to change a DENY to an ALLOW because the
      +    // access_caches table will already contain DENY values and we won't be able to overwrite
      +    // them according the rule above.  So mark every permission below this level as UNKNOWN so
      +    // that we can tell which permissions have been changed, and which ones need to be updated.
      +    $db->update("items", array($field => self::UNKNOWN),
      +                array("left >=" => $item->left, "right <=" => $item->right));
      +
      +    $query = ORM::factory("access_intent")
      +      ->select(array("access_intents.$field", "items.left", "items.right", "items.id"))
      +      ->join("items", "items.id", "access_intents.item_id")
      +      ->where("left >=", $item->left)
      +      ->where("right <=", $item->right)
      +      ->where("type", "album")
      +      ->where("access_intents.$field IS NOT", null)
      +      ->orderby("level", "DESC")
      +      ->find_all();
      +    foreach ($query as $row) {
      +      if ($row->$field == self::ALLOW) {
      +        // Propagate ALLOW for any row that is still UNKNOWN.
      +        $db->update("items", array($field => $row->$field),
      +          array($field => self::UNKNOWN, "left >=" => $row->left, "right <=" => $row->right));
      +      } else if ($row->$field == self::DENY) {
      +        // DENY overwrites everything below it
      +        $db->update("items", array($field => $row->$field),
      +                    array("left >=" => $row->left, "right <=" => $row->right));
      +      }
      +    }
      +
      +    // Finally, if our intent is DEFAULT at this point it means that we were unable to find a
      +    // DENY parent in the hierarchy to propagate from.  So we'll still have a UNKNOWN values in
      +    // the hierarchy, and all of those are safe to change to ALLOW.
      +    $db->update("items", array($field => self::ALLOW),
      +                array($field => self::UNKNOWN, "left >=" => $item->left, "right <=" => $item->right));
      +  }
      +
      +  /**
      +   * Update the Access_Cache model based on information from the Access_Intent model for non-view
      +   * permissions.
      +   *
      +   * @todo: use database locking
      +   *
      +   * @param  Group_Model $group
      +   * @param  string  $perm_name
      +   * @param  Item_Model $item
      +   * @return void
      +   */
      +  private static function _update_access_non_view_cache($group, $perm_name, $item) {
      +    $access = ORM::factory("access_intent")->where("item_id", $item->id)->find();
      +
      +    $db = Database::instance();
      +    $field = "{$perm_name}_{$group->id}";
      +
      +    // If the item's intent is DEFAULT, then we need to back up the chain to find the nearest
      +    // parent with an intent and propagate from there.
      +    //
      +    // @todo To optimize this, we wouldn't need to propagate from the parent, we could just
      +    //       propagate from here with the parent's intent.
      +    if ($access->$field === null) {
      +      $tmp_item = ORM::factory("item")
      +        ->join("access_intents", "items.id", "access_intents.item_id")
      +        ->where("left <", $item->left)
      +        ->where("right >", $item->right)
      +        ->where("$field IS NOT", null)
      +        ->orderby("left", "DESC")
      +        ->limit(1)
      +        ->find();
      +      if ($tmp_item->loaded) {
      +        $item = $tmp_item;
      +      }
      +    }
      +
      +    // With non-view permissions, each level can override any permissions that came above it
      +    // so start at the top and work downwards, overlaying permissions as we go.
      +    $query = ORM::factory("access_intent")
      +      ->select(array("access_intents.$field", "items.left", "items.right"))
      +      ->join("items", "items.id", "access_intents.item_id")
      +      ->where("left >=", $item->left)
      +      ->where("right <=", $item->right)
      +      ->where("$field IS NOT", null)
      +      ->orderby("level", "ASC")
      +      ->find_all();
      +    foreach  ($query as $row) {
      +      $db->query(
      +        "UPDATE {access_caches} SET `$field` = {$row->$field} " .
      +        "WHERE `item_id` IN " .
      +        "  (SELECT `id` FROM {items} " .
      +        "  WHERE `left` >= $row->left " .
      +        "  AND `right` <= $row->right)");
      +    }
      +  }
      +
      +  /**
      +   * Maintain .htacccess files to prevent direct access to albums, resizes and thumbnails when we
      +   * apply the view and view_full permissions to guest users.
      +   */
      +  private static function _update_htaccess_files($album, $group, $perm_name, $value) {
      +    if ($group->id != 1 || !($perm_name == "view" || $perm_name == "view_full")) {
      +      return;
      +    }
      +
      +    $dirs = array($album->file_path());
      +    if ($perm_name == "view") {
      +      $dirs[] = dirname($album->resize_path());
      +      $dirs[] = dirname($album->thumb_path());
      +    }
      +
      +    $base_url = url::site("file_proxy");
      +    foreach ($dirs as $dir) {
      +      if ($value === self::DENY) {
      +        $fp = fopen("$dir/.htaccess", "w+");
      +        fwrite($fp, "\n");
      +        fwrite($fp, "  RewriteEngine On\n");
      +        fwrite($fp, "  RewriteRule (.*) $base_url/\$1 [L]\n");
      +        fwrite($fp, "\n");
      +        fwrite($fp, "\n");
      +        fwrite($fp, "  Order Deny,Allow\n");
      +        fwrite($fp, "  Deny from All\n");
      +        fwrite($fp, "\n");
      +        fclose($fp);
      +      } else {
      +        @unlink($dir . "/.htaccess");
      +      }
      +    }
      +  }
      +
      +  static function private_key() {
      +    return module::get_var("core", "private_key");
      +  }
      +
      +  /**
      +   * Verify that our htaccess based permission system actually works.  Create a temporary
      +   * directory containing an .htaccess file that uses mod_rewrite to redirect /verify to
      +   * /success.  Then request that url.  If we retrieve it successfully, then our redirects are
      +   * working and our permission system works.
      +   */
      +  static function htaccess_works() {
      +    $success_url = url::file("var/tmp/security_test/success");
      +
      +    @mkdir(VARPATH . "tmp/security_test");
      +    if ($fp = @fopen(VARPATH . "tmp/security_test/.htaccess", "w+")) {
      +      fwrite($fp, "RewriteEngine On\n");
      +      fwrite($fp, "RewriteRule verify $success_url [L]\n");
      +      fclose($fp);
      +    }
      +
      +    if ($fp = @fopen(VARPATH . "tmp/security_test/success", "w+")) {
      +      fwrite($fp, "success");
      +      fclose($fp);
      +    }
      +
      +    list ($response) = remote::do_request(url::abs_file("var/tmp/security_test/verify"));
      +    $works = $response == "HTTP/1.1 200 OK";
      +    @dir::unlink(VARPATH . "tmp/security_test");
      +
      +    return $works;
      +  }
      +}
      diff --git a/modules/gallery/helpers/album.php b/modules/gallery/helpers/album.php
      new file mode 100644
      index 00000000..362b93d0
      --- /dev/null
      +++ b/modules/gallery/helpers/album.php
      @@ -0,0 +1,132 @@
      +loaded || !$parent->is_album()) {
      +      throw new Exception("@todo INVALID_PARENT");
      +    }
      +
      +    if (strpos($name, "/")) {
      +      throw new Exception("@todo NAME_CANNOT_CONTAIN_SLASH");
      +    }
      +
      +    // We don't allow trailing periods as a security measure
      +    // ref: http://dev.kohanaphp.com/issues/684
      +    if (rtrim($name, ".") != $name) {
      +      throw new Exception("@todo NAME_CANNOT_END_IN_PERIOD");
      +    }
      +
      +    $album = ORM::factory("item");
      +    $album->type = "album";
      +    $album->title = $title;
      +    $album->description = $description;
      +    $album->name = $name;
      +    $album->owner_id = $owner_id;
      +    $album->thumb_dirty = 1;
      +    $album->resize_dirty = 1;
      +    $album->rand_key = ((float)mt_rand()) / (float)mt_getrandmax();
      +    $album->sort_column = "weight";
      +    $album->sort_order = "ASC";
      +
      +    while (ORM::factory("item")
      +           ->where("parent_id", $parent->id)
      +           ->where("name", $album->name)
      +           ->find()->id) {
      +      $album->name = "{$name}-" . rand();
      +    }
      +
      +    $album = $album->add_to_parent($parent);
      +    mkdir($album->file_path());
      +    mkdir(dirname($album->thumb_path()));
      +    mkdir(dirname($album->resize_path()));
      +
      +    module::event("item_created", $album);
      +
      +    return $album;
      +  }
      +
      +  static function get_add_form($parent) {
      +    $form = new Forge("albums/{$parent->id}", "", "post", array("id" => "gAddAlbumForm"));
      +    $group = $form->group("add_album")
      +      ->label(t("Add an album to %album_title", array("album_title" => $parent->title)));
      +    $group->input("title")->label(t("Title"));
      +    $group->textarea("description")->label(t("Description"));
      +    $group->input("name")->label(t("Directory Name"))
      +      ->callback("item::validate_no_slashes")
      +      ->error_messages("no_slashes", t("The directory name can't contain the \"/\" character"));
      +    $group->hidden("type")->value("album");
      +    $group->submit("")->value(t("Create"));
      +    $form->add_rules_from(ORM::factory("item"));
      +    return $form;
      +  }
      +
      +  static function get_edit_form($parent) {
      +    $form = new Forge("albums/{$parent->id}", "", "post", array("id" => "gEditAlbumForm"));
      +    $form->hidden("_method")->value("put");
      +    $group = $form->group("edit_album")->label(t("Edit Album"));
      +
      +    $group->input("title")->label(t("Title"))->value($parent->title);
      +    $group->textarea("description")->label(t("Description"))->value($parent->description);
      +    if ($parent->id != 1) {
      +      $group->input("dirname")->label(t("Directory Name"))->value($parent->name)
      +        ->callback("item::validate_no_slashes")
      +        ->error_messages("no_slashes", t("The directory name can't contain a \"/\""))
      +        ->callback("item::validate_no_trailing_period")
      +        ->error_messages("no_trailing_period", t("The directory name can't end in \".\""));
      +    }
      +
      +    $sort_order = $group->group("sort_order", array("id" => "gAlbumSortOrder"))
      +      ->label(t("Sort Order"));
      +
      +    $sort_order->dropdown("column", array("id" => "gAlbumSortColumn"))
      +      ->label(t("Sort by"))
      +      ->options(array("weight" => t("Default"),
      +                      "captured" => t("Capture Date"),
      +                      "created" => t("Creation Date"),
      +                      "title" => t("Title"),
      +                      "updated" => t("Updated Date"),
      +                      "view_count" => t("Number of views"),
      +                      "rand_key" => t("Random")))
      +      ->selected($parent->sort_column);
      +    $sort_order->dropdown("direction", array("id" => "gAlbumSortDirection"))
      +      ->label(t("Order"))
      +      ->options(array("ASC" => t("Ascending"),
      +                      "DESC" => t("Descending")))
      +      ->selected($parent->sort_order);
      +    $group->hidden("type")->value("album");
      +    $group->submit("")->value(t("Modify"));
      +    $form->add_rules_from(ORM::factory("item"));
      +    return $form;
      +  }
      +}
      diff --git a/modules/gallery/helpers/batch.php b/modules/gallery/helpers/batch.php
      new file mode 100644
      index 00000000..0faa3369
      --- /dev/null
      +++ b/modules/gallery/helpers/batch.php
      @@ -0,0 +1,40 @@
      +set("batch_level", $session->get("batch_level", 0) + 1);
      +  }
      +
      +  static function stop() {
      +    $session = Session::instance();
      +    $batch_level = $session->get("batch_level", 0) - 1;
      +    if ($batch_level > 0) {
      +      $session->set("batch_level", $batch_level);
      +    } else {
      +      $session->delete("batch_level");
      +      module::event("batch_complete");
      +    }
      +  }
      +
      +  static function in_progress() {
      +    return Session::instance()->get("batch_level", 0) > 0;
      +  }
      +}
      diff --git a/modules/gallery/helpers/block_manager.php b/modules/gallery/helpers/block_manager.php
      new file mode 100644
      index 00000000..022626e5
      --- /dev/null
      +++ b/modules/gallery/helpers/block_manager.php
      @@ -0,0 +1,67 @@
      +name}_block";
      +      if (method_exists($class_name, "get_list")) {
      +        foreach (call_user_func(array($class_name, "get_list")) as $id => $title) {
      +          $blocks["{$module->name}:$id"] = $title;
      +        }
      +      }
      +    }
      +    return $blocks;
      +  }
      +
      +  static function get_html($location) {
      +    $active = self::get_active($location);
      +    $result = "";
      +    foreach ($active as $id => $desc) {
      +      if (method_exists("$desc[0]_block", "get")) {
      +        $block = call_user_func(array("$desc[0]_block", "get"), $desc[1]);
      +        $block->id = $id;
      +        $result .= $block;
      +      }
      +    }
      +    return $result;
      +  }
      +}
      diff --git a/modules/gallery/helpers/core.php b/modules/gallery/helpers/core.php
      new file mode 100644
      index 00000000..63f51f86
      --- /dev/null
      +++ b/modules/gallery/helpers/core.php
      @@ -0,0 +1,52 @@
      +admin) {
      +      Router::$controller = "maintenance";
      +      Router::$controller_path = APPPATH . "controllers/maintenance.php";
      +      Router::$method = "index";
      +    }
      +  }
      +
      +  /**
      +   * This function is called when the Gallery is fully initialized.  We relay it to modules as the
      +   * "gallery_ready" event.  Any module that wants to perform an action at the start of every
      +   * request should implement the _event::gallery_ready() handler.
      +   */
      +  static function ready() {
      +    module::event("gallery_ready");
      +  }
      +
      +  /**
      +   * This function is called right before the Kohana framework shuts down.  We relay it to modules
      +   * as the "gallery_shutdown" event.  Any module that wants to perform an action at the start of
      +   * every request should implement the _event::gallery_shutdown() handler.
      +   */
      +  static function shutdown() {
      +    module::event("gallery_shutdown");
      +  }
      +}
      \ No newline at end of file
      diff --git a/modules/gallery/helpers/core_block.php b/modules/gallery/helpers/core_block.php
      new file mode 100644
      index 00000000..0e2e9c54
      --- /dev/null
      +++ b/modules/gallery/helpers/core_block.php
      @@ -0,0 +1,100 @@
      + t("Welcome to Gallery 3!"),
      +      "photo_stream" => t("Photo Stream"),
      +      "log_entries" => t("Log Entries"),
      +      "stats" => t("Gallery Stats"),
      +      "platform_info" => t("Platform Information"),
      +      "project_news" => t("Gallery Project News"));
      +  }
      +
      +  static function get($block_id) {
      +    $block = new Block();
      +    switch($block_id) {
      +    case "welcome":
      +      $block->css_id = "gWelcome";
      +      $block->title = t("Welcome to Gallery3");
      +      $block->content = new View("admin_block_welcome.html");
      +      break;
      +
      +    case "photo_stream":
      +      $block->css_id = "gPhotoStream";
      +      $block->title = t("Photo Stream");
      +      $block->content = new View("admin_block_photo_stream.html");
      +      $block->content->photos =
      +        ORM::factory("item")->where("type", "photo")->orderby("created", "DESC")->find_all(10);
      +      break;
      +
      +    case "log_entries":
      +      $block->css_id = "gLogEntries";
      +      $block->title = t("Log Entries");
      +      $block->content = new View("admin_block_log_entries.html");
      +      $block->content->entries = ORM::factory("log")->orderby("timestamp", "DESC")->find_all(5);
      +        break;
      +
      +    case "stats":
      +      $block->css_id = "gStats";
      +      $block->title = t("Gallery Stats");
      +      $block->content = new View("admin_block_stats.html");
      +      $block->content->album_count = ORM::factory("item")->where("type", "album")->count_all();
      +      $block->content->photo_count = ORM::factory("item")->where("type", "photo")->count_all();
      +      break;
      +
      +    case "platform_info":
      +      $block->css_id = "gPlatform";
      +      $block->title = t("Platform Information");
      +      $block->content = new View("admin_block_platform.html");
      +      if (is_readable("/proc/loadavg")) {
      +        $block->content->load_average =
      +          join(" ", array_slice(split(" ", array_shift(file("/proc/loadavg"))), 0, 3));
      +      } else {
      +        $block->content->load_average = t("Unavailable");
      +      }
      +      break;
      +
      +    case "project_news":
      +      $block->css_id = "gProjectNews";
      +      $block->title = t("Gallery Project News");
      +      $block->content = new View("admin_block_news.html");
      +      $block->content->feed = feed::parse("http://gallery.menalto.com/node/feed", 3);
      +      break;
      +
      +    case "block_adder":
      +      $block->css_id = "gBlockAdder";
      +      $block->title = t("Dashboard Content");
      +      $block->content = self::get_add_block_form();
      +    }
      +
      +    return $block;
      +  }
      +
      +  static function get_add_block_form() {
      +    $form = new Forge("admin/dashboard/add_block", "", "post",
      +                      array("id" => "gAddDashboardBlockForm"));
      +    $group = $form->group("add_block")->label(t("Add Block"));
      +    $group->dropdown("id")->label("Available Blocks")->options(block_manager::get_available());
      +    $group->submit("center")->value(t("Add to center"));
      +    $group->submit("sidebar")->value(t("Add to sidebar"));
      +    return $form;
      +  }
      +}
      \ No newline at end of file
      diff --git a/modules/gallery/helpers/core_event.php b/modules/gallery/helpers/core_event.php
      new file mode 100644
      index 00000000..bbb53cc9
      --- /dev/null
      +++ b/modules/gallery/helpers/core_event.php
      @@ -0,0 +1,46 @@
      +admin && module::get_var("core", "choose_default_tookit", null)) {
      +      graphics::choose_default_toolkit();
      +      module::clear_var("core", "choose_default_tookit");
      +    }
      +  }
      +}
      diff --git a/modules/gallery/helpers/core_installer.php b/modules/gallery/helpers/core_installer.php
      new file mode 100644
      index 00000000..cffcbedb
      --- /dev/null
      +++ b/modules/gallery/helpers/core_installer.php
      @@ -0,0 +1,278 @@
      +query("CREATE TABLE {access_caches} (
      +                   `id` int(9) NOT NULL auto_increment,
      +                   `item_id` int(9),
      +                   PRIMARY KEY (`id`))
      +                 ENGINE=InnoDB DEFAULT CHARSET=utf8;");
      +
      +      $db->query("CREATE TABLE {access_intents} (
      +                   `id` int(9) NOT NULL auto_increment,
      +                   `item_id` int(9),
      +                   PRIMARY KEY (`id`))
      +                 ENGINE=InnoDB DEFAULT CHARSET=utf8;");
      +
      +      $db->query("CREATE TABLE {graphics_rules} (
      +                   `id` int(9) NOT NULL auto_increment,
      +                   `active` BOOLEAN default 0,
      +                   `args` varchar(255) default NULL,
      +                   `module_name` varchar(64) NOT NULL,
      +                   `operation` varchar(64) NOT NULL,
      +                   `priority` int(9) NOT NULL,
      +                   `target`  varchar(32) NOT NULL,
      +                   PRIMARY KEY (`id`))
      +                 ENGINE=InnoDB DEFAULT CHARSET=utf8;");
      +
      +      $db->query("CREATE TABLE {items} (
      +                   `id` int(9) NOT NULL auto_increment,
      +                   `album_cover_item_id` int(9) default NULL,
      +                   `captured` int(9) default NULL,
      +                   `created` int(9) default NULL,
      +                   `description` varchar(2048) default NULL,
      +                   `height` int(9) default NULL,
      +                   `left` int(9) NOT NULL,
      +                   `level` int(9) NOT NULL,
      +                   `mime_type` varchar(64) default NULL,
      +                   `name` varchar(255) default NULL,
      +                   `owner_id` int(9) default NULL,
      +                   `parent_id` int(9) NOT NULL,
      +                   `rand_key` float default NULL,
      +                   `relative_path_cache` varchar(255) default NULL,
      +                   `resize_dirty` boolean default 1,
      +                   `resize_height` int(9) default NULL,
      +                   `resize_width` int(9) default NULL,
      +                   `right` int(9) NOT NULL,
      +                   `sort_column` varchar(64) default NULL,
      +                   `sort_order` char(4) default 'ASC',
      +                   `thumb_dirty` boolean default 1,
      +                   `thumb_height` int(9) default NULL,
      +                   `thumb_width` int(9) default NULL,
      +                   `title` varchar(255) default NULL,
      +                   `type` varchar(32) NOT NULL,
      +                   `updated` int(9) default NULL,
      +                   `view_count` int(9) default 0,
      +                   `weight` int(9) NOT NULL default 0,
      +                   `width` int(9) default NULL,
      +                   PRIMARY KEY (`id`),
      +                   KEY `parent_id` (`parent_id`),
      +                   KEY `type` (`type`),
      +                   KEY `random` (`rand_key`))
      +                 ENGINE=InnoDB DEFAULT CHARSET=utf8;");
      +
      +      $db->query("CREATE TABLE {logs} (
      +                   `id` int(9) NOT NULL auto_increment,
      +                   `category` varchar(64) default NULL,
      +                   `html` varchar(255) default NULL,
      +                   `message` text default NULL,
      +                   `referer` varchar(255) default NULL,
      +                   `severity` int(9) default 0,
      +                   `timestamp` int(9) default 0,
      +                   `url` varchar(255) default NULL,
      +                   `user_id` int(9) default 0,
      +                   PRIMARY KEY (`id`))
      +                 ENGINE=InnoDB DEFAULT CHARSET=utf8;");
      +
      +      $db->query("CREATE TABLE {messages} (
      +                   `id` int(9) NOT NULL auto_increment,
      +                   `key` varchar(255) default NULL,
      +                   `severity` varchar(32) default NULL,
      +                   `value` varchar(255) default NULL,
      +                   PRIMARY KEY (`id`),
      +                   UNIQUE KEY(`key`))
      +                 ENGINE=InnoDB DEFAULT CHARSET=utf8;");
      +
      +      $db->query("CREATE TABLE {modules} (
      +                   `id` int(9) NOT NULL auto_increment,
      +                   `active` BOOLEAN default 0,
      +                   `name` varchar(64) default NULL,
      +                   `version` int(9) default NULL,
      +                   PRIMARY KEY (`id`),
      +                   UNIQUE KEY(`name`))
      +                 ENGINE=InnoDB DEFAULT CHARSET=utf8;");
      +
      +      $db->query("CREATE TABLE {themes} (
      +                   `id` int(9) NOT NULL auto_increment,
      +                   `name` varchar(64) default NULL,
      +                   `version` int(9) default NULL,
      +                   PRIMARY KEY (`id`),
      +                   UNIQUE KEY(`name`))
      +                 ENGINE=InnoDB DEFAULT CHARSET=utf8;");
      +
      +      $db->query("CREATE TABLE {permissions} (
      +                   `id` int(9) NOT NULL auto_increment,
      +                   `display_name` varchar(64) default NULL,
      +                   `name` varchar(64) default NULL,
      +                   PRIMARY KEY (`id`),
      +                   UNIQUE KEY(`name`))
      +                 ENGINE=InnoDB DEFAULT CHARSET=utf8;");
      +
      +      $db->query("CREATE TABLE {incoming_translations} (
      +                   `id` int(9) NOT NULL auto_increment,
      +                   `key` char(32) NOT NULL,
      +                   `locale` char(10) NOT NULL,
      +                   `message` text NOT NULL,
      +                   `revision` int(9) DEFAULT NULL,
      +                   `translation` text,
      +                   PRIMARY KEY (`id`),
      +                   UNIQUE KEY(`key`, `locale`),
      +                   KEY `locale_key` (`locale`, `key`))
      +                 ENGINE=InnoDB DEFAULT CHARSET=utf8;");
      +
      +      $db->query("CREATE TABLE {outgoing_translations} (
      +                   `id` int(9) NOT NULL auto_increment,
      +                   `base_revision` int(9) DEFAULT NULL,
      +                   `key` char(32) NOT NULL,
      +                   `locale` char(10) NOT NULL,
      +                   `message` text NOT NULL,
      +                   `translation` text,
      +                   PRIMARY KEY (`id`),
      +                   UNIQUE KEY(`key`, `locale`),
      +                   KEY `locale_key` (`locale`, `key`))
      +                 ENGINE=InnoDB DEFAULT CHARSET=utf8;");
      +
      +      $db->query("CREATE TABLE {sessions} (
      +                  `session_id` varchar(127) NOT NULL,
      +                  `data` text NOT NULL,
      +                  `last_activity` int(10) UNSIGNED NOT NULL,
      +                  PRIMARY KEY (`session_id`))
      +                 ENGINE=InnoDB DEFAULT CHARSET=utf8;");
      +
      +      $db->query("CREATE TABLE {tasks} (
      +                  `id` int(9) NOT NULL auto_increment,
      +                  `callback` varchar(128) default NULL,
      +                  `context` text NOT NULL,
      +                  `done` boolean default 0,
      +                  `name` varchar(128) default NULL,
      +                  `owner_id` int(9) default NULL,
      +                  `percent_complete` int(9) default 0,
      +                  `state` varchar(32) default NULL,
      +                  `status` varchar(255) default NULL,
      +                  `updated` int(9) default NULL,
      +                  PRIMARY KEY (`id`),
      +                  KEY (`owner_id`))
      +                 ENGINE=InnoDB DEFAULT CHARSET=utf8;");
      +
      +      $db->query("CREATE TABLE {vars} (
      +                  `id` int(9) NOT NULL auto_increment,
      +                  `module_name` varchar(64) NOT NULL,
      +                  `name` varchar(64) NOT NULL,
      +                  `value` text,
      +                  PRIMARY KEY (`id`),
      +                  UNIQUE KEY(`module_name`, `name`))
      +                 ENGINE=InnoDB DEFAULT CHARSET=utf8;");
      +
      +      foreach (array("albums", "logs", "modules", "resizes", "thumbs", "tmp", "uploads") as $dir) {
      +        @mkdir(VARPATH . $dir);
      +      }
      +
      +      access::register_permission("view", "View");
      +      access::register_permission("view_full", "View Full Size");
      +      access::register_permission("edit", "Edit");
      +      access::register_permission("add", "Add");
      +
      +      $root = ORM::factory("item");
      +      $root->type = "album";
      +      $root->title = "Gallery";
      +      $root->description = "";
      +      $root->left = 1;
      +      $root->right = 2;
      +      $root->parent_id = 0;
      +      $root->level = 1;
      +      $root->thumb_dirty = 1;
      +      $root->resize_dirty = 1;
      +      $root->sort_column = "weight";
      +      $root->sort_order = "ASC";
      +      $root->save();
      +      access::add_item($root);
      +
      +      module::set_var("core", "active_site_theme", "default");
      +      module::set_var("core", "active_admin_theme", "admin_default");
      +      module::set_var("core", "page_size", 9);
      +      module::set_var("core", "thumb_size", 200);
      +      module::set_var("core", "resize_size", 640);
      +      module::set_var("core", "default_locale", "en_US");
      +      module::set_var("core", "image_quality", 75);
      +
      +      // Add rules for generating our thumbnails and resizes
      +      graphics::add_rule(
      +        "core", "thumb", "resize",
      +        array("width" => 200, "height" => 200, "master" => Image::AUTO),
      +        100);
      +      graphics::add_rule(
      +        "core", "resize", "resize",
      +        array("width" => 640, "height" => 480, "master" => Image::AUTO),
      +        100);
      +
      +      // Instantiate default themes (site and admin)
      +      foreach (array("default", "admin_default") as $theme_name) {
      +        $theme_info = new ArrayObject(parse_ini_file(THEMEPATH . $theme_name . "/theme.info"),
      +                                      ArrayObject::ARRAY_AS_PROPS);
      +        $theme = ORM::factory("theme");
      +        $theme->name = $theme_name;
      +        $theme->version = $theme_info->version;
      +        $theme->save();
      +      }
      +
      +      block_manager::add("dashboard_sidebar", "core", "block_adder");
      +      block_manager::add("dashboard_sidebar", "core", "stats");
      +      block_manager::add("dashboard_sidebar", "core", "platform_info");
      +      block_manager::add("dashboard_sidebar", "core", "project_news");
      +      block_manager::add("dashboard_center", "core", "welcome");
      +      block_manager::add("dashboard_center", "core", "photo_stream");
      +      block_manager::add("dashboard_center", "core", "log_entries");
      +
      +      module::set_version("core", 1);
      +      module::set_var("core", "version", "3.0 pre-beta svn");
      +      module::set_var("core", "choose_default_tookit", 1);
      +    }
      +  }
      +
      +  static function uninstall() {
      +    $db = Database::instance();
      +    $db->query("DROP TABLE IF EXISTS {access_caches}");
      +    $db->query("DROP TABLE IF EXISTS {access_intents}");
      +    $db->query("DROP TABLE IF EXISTS {graphics_rules}");
      +    $db->query("DROP TABLE IF EXISTS {items}");
      +    $db->query("DROP TABLE IF EXISTS {logs}");
      +    $db->query("DROP TABLE IF EXISTS {messages}");
      +    $db->query("DROP TABLE IF EXISTS {modules}");
      +    $db->query("DROP TABLE IF EXISTS {themes}");
      +    $db->query("DROP TABLE IF EXISTS {incoming_translations}");
      +    $db->query("DROP TABLE IF EXISTS {outgoing_translations}");
      +    $db->query("DROP TABLE IF EXISTS {permissions}");
      +    $db->query("DROP TABLE IF EXISTS {sessions}");
      +    $db->query("DROP TABLE IF EXISTS {tasks}");
      +    $db->query("DROP TABLE IF EXISTS {vars}");
      +    foreach (array("albums", "resizes", "thumbs", "uploads",
      +                   "modules", "logs", "database.php") as $entry) {
      +      system("/bin/rm -rf " . VARPATH . $entry);
      +    }
      +  }
      +}
      diff --git a/modules/gallery/helpers/core_menu.php b/modules/gallery/helpers/core_menu.php
      new file mode 100644
      index 00000000..eb208560
      --- /dev/null
      +++ b/modules/gallery/helpers/core_menu.php
      @@ -0,0 +1,162 @@
      +admin) {
      +      $menu->append($scaffold_menu = Menu::factory("submenu")
      +                    ->id("scaffold")
      +                    ->label("Scaffold"));
      +      $scaffold_menu->append(Menu::factory("link")
      +                             ->id("scaffold_home")
      +                             ->label("Dashboard")
      +                             ->url(url::site("scaffold")));
      +    }
      +
      +    $menu->append(Menu::factory("link")
      +                  ->id("home")
      +                  ->label(t("Home"))
      +                  ->url(url::site("albums/1")));
      +
      +    $item = $theme->item();
      +
      +    if (user::active()->admin || ($item && access::can("edit", $item))) {
      +      $menu->append($options_menu = Menu::factory("submenu")
      +                    ->id("options_menu")
      +                    ->label(t("Options")));
      +
      +      if ($item && access::can("edit", $item)) {
      +        $options_menu
      +          ->append(Menu::factory("dialog")
      +                   ->id("edit_item")
      +                   ->label($item->is_album() ? t("Edit album") : t("Edit photo"))
      +                   ->url(url::site("form/edit/{$item->type}s/$item->id")));
      +
      +        // @todo Move album options menu to the album quick edit pane
      +        // @todo Create resized item quick edit pane menu
      +        if ($item->is_album()) {
      +          $options_menu
      +            ->append(Menu::factory("dialog")
      +                     ->id("add_item")
      +                     ->label(t("Add a photo"))
      +                     ->url(url::site("simple_uploader/app/$item->id")))
      +            ->append(Menu::factory("dialog")
      +                     ->id("add_album")
      +                     ->label(t("Add an album"))
      +                     ->url(url::site("form/add/albums/$item->id?type=album")))
      +            ->append(Menu::factory("dialog")
      +                     ->id("edit_permissions")
      +                     ->label(t("Edit permissions"))
      +                     ->url(url::site("permissions/browse/$item->id")));
      +        }
      +      }
      +    }
      +
      +    if (user::active()->admin) {
      +      $menu->append($admin_menu = Menu::factory("submenu")
      +                    ->id("admin_menu")
      +                    ->label(t("Admin")));
      +      self::admin($admin_menu, $theme);
      +      foreach (module::active() as $module) {
      +        if ($module->name == "core") {
      +          continue;
      +        }
      +        $class = "{$module->name}_menu";
      +        if (method_exists($class, "admin")) {
      +          call_user_func_array(array($class, "admin"), array(&$admin_menu, $theme));
      +        }
      +      }
      +    }
      +  }
      +
      +  static function album($menu, $theme) {
      +  }
      +
      +  static function photo($menu, $theme) {
      +    if (access::can("view_full", $theme->item())) {
      +      $menu
      +        ->append(Menu::factory("link")
      +               ->id("fullsize")
      +               ->label(t("View full size"))
      +               ->url("#")
      +               ->css_class("gFullSizeLink"));
      +    }
      +    $menu
      +      ->append(Menu::factory("link")
      +               ->id("album")
      +               ->label(t("Return to album"))
      +               ->url($theme->item()->parent()->url("show={$theme->item->id}"))
      +               ->css_id("gAlbumLink"));
      +  }
      +
      +  static function admin($menu, $theme) {
      +    $menu
      +      ->append(Menu::factory("link")
      +               ->id("dashboard")
      +               ->label(t("Dashboard"))
      +               ->url(url::site("admin")))
      +      ->append(Menu::factory("submenu")
      +               ->id("settings_menu")
      +               ->label(t("Settings"))
      +               ->append(Menu::factory("link")
      +                        ->id("graphics_toolkits")
      +                        ->label(t("Graphics"))
      +                        ->url(url::site("admin/graphics")))
      +               ->append(Menu::factory("link")
      +                        ->id("languages")
      +                        ->label(t("Languages"))
      +                        ->url(url::site("admin/languages")))
      +               ->append(Menu::factory("link")
      +                        ->id("l10n_mode")
      +                        ->label(Session::instance()->get("l10n_mode", false)
      +                                ? t("Stop translating") : t("Start translating"))
      +                        ->url(url::site("l10n_client/toggle_l10n_mode?csrf=" .
      +                                        access::csrf_token())))
      +               ->append(Menu::factory("link")
      +                        ->id("advanced")
      +                        ->label("Advanced")
      +                        ->url(url::site("admin/advanced_settings"))))
      +      ->append(Menu::factory("link")
      +               ->id("modules")
      +               ->label(t("Modules"))
      +               ->url(url::site("admin/modules")))
      +      ->append(Menu::factory("submenu")
      +               ->id("content_menu")
      +               ->label(t("Content")))
      +      ->append(Menu::factory("submenu")
      +               ->id("appearance_menu")
      +               ->label(t("Appearance"))
      +               ->append(Menu::factory("link")
      +                        ->id("themes")
      +                        ->label(t("Theme Choice"))
      +                        ->url(url::site("admin/themes")))
      +               ->append(Menu::factory("link")
      +                        ->id("theme_details")
      +                        ->label(t("Theme Options"))
      +                        ->url(url::site("admin/theme_details"))))
      +      ->append(Menu::factory("link")
      +               ->id("maintenance")
      +               ->label(t("Maintenance"))
      +               ->url(url::site("admin/maintenance")))
      +      ->append(Menu::factory("submenu")
      +               ->id("statistics_menu")
      +               ->label(t("Statistics"))
      +               ->url("#"));
      +  }
      +}
      diff --git a/modules/gallery/helpers/core_search.php b/modules/gallery/helpers/core_search.php
      new file mode 100644
      index 00000000..9957a493
      --- /dev/null
      +++ b/modules/gallery/helpers/core_search.php
      @@ -0,0 +1,24 @@
      +description, $item->name, $item->title));
      +  }
      +}
      diff --git a/modules/gallery/helpers/core_task.php b/modules/gallery/helpers/core_task.php
      new file mode 100644
      index 00000000..e078192c
      --- /dev/null
      +++ b/modules/gallery/helpers/core_task.php
      @@ -0,0 +1,166 @@
      +count();
      +    $tasks = array();
      +    $tasks[] = Task_Definition::factory()
      +                 ->callback("core_task::rebuild_dirty_images")
      +                 ->name(t("Rebuild Images"))
      +                 ->description($dirty_count ?
      +                               t2("You have one out of date photo",
      +                                  "You have %count out of date photos",
      +                                  $dirty_count)
      +                               : t("All your photos are up to date"))
      +      ->severity($dirty_count ? log::WARNING : log::SUCCESS);
      +
      +    $tasks[] = Task_Definition::factory()
      +                 ->callback("core_task::update_l10n")
      +                 ->name(t("Update translations"))
      +                 ->description(t("Download new and updated translated strings"))
      +      ->severity(log::SUCCESS);
      +
      +    return $tasks;
      +  }
      +
      +  /**
      +   * Task that rebuilds all dirty images.
      +   * @param Task_Model the task
      +   */
      +  static function rebuild_dirty_images($task) {
      +    $result = graphics::find_dirty_images_query();
      +    $remaining = $result->count();
      +    $completed = $task->get("completed", 0);
      +
      +    $i = 0;
      +    foreach ($result as $row) {
      +      $item = ORM::factory("item", $row->id);
      +      if ($item->loaded) {
      +        graphics::generate($item);
      +      }
      +
      +      $completed++;
      +      $remaining--;
      +
      +      if (++$i == 2) {
      +        break;
      +      }
      +    }
      +
      +    $task->status = t2("Updated: 1 image. Total: %total_count.",
      +                       "Updated: %count images. Total: %total_count.",
      +                       $completed,
      +                       array("total_count" => ($remaining + $completed)));
      +
      +    if ($completed + $remaining > 0) {
      +      $task->percent_complete = (int)(100 * $completed / ($completed + $remaining));
      +    } else {
      +      $task->percent_complete = 100;
      +    }
      +
      +    $task->set("completed", $completed);
      +    if ($remaining == 0) {
      +      $task->done = true;
      +      $task->state = "success";
      +      site_status::clear("graphics_dirty");
      +    }
      +  }
      +
      +  static function update_l10n(&$task) {
      +    $start = microtime(true);
      +    $dirs = $task->get("dirs");
      +    $files = $task->get("files");
      +    $cache = $task->get("cache", array());
      +    $i = 0;
      +
      +    switch ($task->get("mode", "init")) {
      +    case "init":  // 0%
      +      $dirs = array("core", "modules", "themes", "installer");
      +      $files = array();
      +      $task->set("mode", "find_files");
      +      $task->status = t("Finding files");
      +      break;
      +
      +    case "find_files":  // 0% - 10%
      +      while (($dir = array_pop($dirs)) && microtime(true) - $start < 0.5) {
      +        if (basename($dir) == "tests") {
      +          continue;
      +        }
      +
      +        foreach (glob(DOCROOT . "$dir/*") as $path) {
      +          $relative_path = str_replace(DOCROOT, "", $path);
      +          if (is_dir($path)) {
      +            $dirs[] = $relative_path;
      +          } else {
      +            $files[] = $relative_path;
      +          }
      +        }
      +      }
      +
      +      $task->status = t2("Finding files: found 1 file",
      +                         "Finding files: found %count files", count($files));
      +
      +      if (!$dirs) {
      +        $task->set("mode", "scan_files");
      +        $task->set("total_files", count($files));
      +        $task->status = t("Scanning files");
      +        $task->percent_complete = 10;
      +      }
      +      break;
      +
      +    case "scan_files": // 10% - 90%
      +      while (($file = array_pop($files)) && microtime(true) - $start < 0.5) {
      +        $file = DOCROOT . $file;
      +        switch (pathinfo($file, PATHINFO_EXTENSION)) {
      +        case "php":
      +          l10n_scanner::scan_php_file($file, $cache);
      +          break;
      +
      +        case "info":
      +          l10n_scanner::scan_info_file($file, $cache);
      +          break;
      +        }
      +      }
      +
      +      $total_files = $task->get("total_files");
      +      $task->status = t2("Scanning files: scanned 1 file",
      +                         "Scanning files: scanned %count files", $total_files - count($files));
      +
      +      $task->percent_complete = 10 + 80 * ($total_files - count($files)) / $total_files;
      +      if (empty($files)) {
      +        $task->set("mode", "fetch_updates");
      +        $task->status = t("Fetching updates");
      +        $task->percent_complete = 90;
      +      }
      +      break;
      +
      +    case "fetch_updates":  // 90% - 100%
      +      l10n_client::fetch_updates();
      +      $task->done = true;
      +      $task->state = "success";
      +      $task->status = t("Translations installed/updated");
      +      $task->percent_complete = 100;
      +    }
      +
      +    $task->set("files", $files);
      +    $task->set("dirs", $dirs);
      +    $task->set("cache", $cache);
      +  }
      +}
      \ No newline at end of file
      diff --git a/modules/gallery/helpers/core_theme.php b/modules/gallery/helpers/core_theme.php
      new file mode 100644
      index 00000000..28f544a1
      --- /dev/null
      +++ b/modules/gallery/helpers/core_theme.php
      @@ -0,0 +1,137 @@
      +get("debug")) {
      +      $buf .= "";
      +    }
      +    if (($theme->page_type == "album" || $theme->page_type == "photo")
      +        && access::can("edit", $theme->item())) {
      +      $buf .= "";
      +      $buf .= html::script("core/js/quick.js");
      +    }
      +    if ($theme->page_type == "photo" && access::can("view_full", $theme->item())) {
      +      $buf .= "";
      +      $buf .= html::script("core/js/fullsize.js");
      +    }
      +
      +    if ($session->get("l10n_mode", false)) {
      +      $buf .= "";
      +      $buf .= html::script("lib/jquery.cookie.js");
      +      $buf .= html::script("core/js/l10n_client.js");
      +    }
      +
      +    return $buf;
      +  }
      +
      +  static function resize_top($theme, $item) {
      +    if (access::can("edit", $item)) {
      +      $edit_link = url::site("quick/pane/$item->id?page_type=photo");
      +      return "
      "; + } + } + + static function resize_bottom($theme, $item) { + if (access::can("edit", $item)) { + return "
      "; + } + } + + static function thumb_top($theme, $child) { + if (access::can("edit", $child)) { + $edit_link = url::site("quick/pane/$child->id?page_type=album"); + return "
      "; + } + } + + static function thumb_bottom($theme, $child) { + if (access::can("edit", $child)) { + return "
      "; + } + } + + static function admin_head($theme) { + $session = Session::instance(); + $buf = ""; + if ($session->get("debug")) { + $buf .= ""; + } + + if ($session->get("l10n_mode", false)) { + $buf .= ""; + $buf .= html::script("lib/jquery.cookie.js"); + $buf .= html::script("core/js/l10n_client.js"); + } + + return $buf; + } + + static function page_bottom($theme) { + $session = Session::instance(); + if ($session->get("profiler", false)) { + $profiler = new Profiler(); + $profiler->render(); + } + if ($session->get("l10n_mode", false)) { + return L10n_Client_Controller::l10n_form(); + } + + if ($session->get("after_install")) { + $session->delete("after_install"); + return new View("after_install_loader.html"); + } + } + + static function admin_page_bottom($theme) { + $session = Session::instance(); + if ($session->get("profiler", false)) { + $profiler = new Profiler(); + $profiler->render(); + } + if ($session->get("l10n_mode", false)) { + return L10n_Client_Controller::l10n_form(); + } + } + + static function credits() { + return "
    • " . + t("Powered by Gallery %version", + array("url" => "http://gallery.menalto.com", + "version" => module::get_var("core", "version"))) . + "
    • "; + } + + static function admin_credits() { + return core_theme::credits(); + } +} \ No newline at end of file diff --git a/modules/gallery/helpers/dir.php b/modules/gallery/helpers/dir.php new file mode 100644 index 00000000..1717bdd9 --- /dev/null +++ b/modules/gallery/helpers/dir.php @@ -0,0 +1,40 @@ +isDot()) { + unset($resource); + continue; + } else if ($resource->isFile()) { + unlink($resource->getPathName()); + } else if ($resource->isDir()) { + dir::unlink($resource->getRealPath()); + } + unset($resource); + } + return @rmdir($path); + } + return false; + } + + +} diff --git a/modules/gallery/helpers/graphics.php b/modules/gallery/helpers/graphics.php new file mode 100644 index 00000000..805a95c0 --- /dev/null +++ b/modules/gallery/helpers/graphics.php @@ -0,0 +1,387 @@ + 200, "height" => 200, "master" => Image::AUTO), 100); + * + * Specifies that "core" is adding a rule to resize thumbnails down to a max of 200px on + * the longest side. The core module adds default rules at a priority of 100. You can set + * higher and lower priorities to perform operations before or after this fires. + * + * @param string $module_name the module that added the rule + * @param string $target the target for this operation ("thumb" or "resize") + * @param string $operation the name of the operation + * @param array $args arguments to the operation + * @param integer $priority the priority for this rule (lower priorities are run first) + */ + static function add_rule($module_name, $target, $operation, $args, $priority) { + $rule = ORM::factory("graphics_rule"); + $rule->module_name = $module_name; + $rule->target = $target; + $rule->operation = $operation; + $rule->priority = $priority; + $rule->args = serialize($args); + $rule->active = true; + $rule->save(); + + self::mark_dirty($target == "thumb", $target == "resize"); + } + + /** + * Remove any matching graphics rules + * @param string $module_name the module that added the rule + * @param string $target the target for this operation ("thumb" or "resize") + * @param string $operation the name of the operation + */ + static function remove_rule($module_name, $target, $operation) { + ORM::factory("graphics_rule") + ->where("module_name", $module_name) + ->where("target", $target) + ->where("operation", $operation) + ->delete_all(); + + self::mark_dirty($target == "thumb", $target == "resize"); + } + + /** + * Remove all rules for this module + * @param string $module_name + */ + static function remove_rules($module_name) { + $status = Database::instance()->delete("graphics_rules", array("module_name" => $module_name)); + if (count($status)) { + self::mark_dirty(true, true); + } + } + + /** + * Activate the rules for this module, typically done when the module itself is deactivated. + * Note that this does not mark images as dirty so that if you deactivate and reactivate a + * module it won't cause all of your images to suddenly require a rebuild. + */ + static function activate_rules($module_name) { + Database::instance() + ->update("graphics_rules",array("active" => true), array("module_name" => $module_name)); + } + + /** + * Deactivate the rules for this module, typically done when the module itself is deactivated. + * Note that this does not mark images as dirty so that if you deactivate and reactivate a + * module it won't cause all of your images to suddenly require a rebuild. + */ + static function deactivate_rules($module_name) { + Database::instance() + ->update("graphics_rules",array("active" => false), array("module_name" => $module_name)); + } + + /** + * Rebuild the thumb and resize for the given item. + * @param Item_Model $item + */ + static function generate($item) { + if ($item->is_album()) { + if (!$cover = $item->album_cover()) { + return; + } + $input_file = $cover->file_path(); + $input_item = $cover; + } else { + $input_file = $item->file_path(); + $input_item = $item; + } + + if ($item->thumb_dirty) { + $ops["thumb"] = $item->thumb_path(); + } + if ($item->resize_dirty && !$item->is_album() && !$item->is_movie()) { + $ops["resize"] = $item->resize_path(); + } + + if (empty($ops)) { + return; + } + + try { + foreach ($ops as $target => $output_file) { + if ($input_item->is_movie()) { + // Convert the movie to a JPG first + $output_file = preg_replace("/...$/", "jpg", $output_file); + movie::extract_frame($input_file, $output_file); + $working_file = $output_file; + } else { + $working_file = $input_file; + } + + foreach (ORM::factory("graphics_rule") + ->where("target", $target) + ->where("active", true) + ->orderby("priority", "asc") + ->find_all() as $rule) { + $args = array($working_file, $output_file, unserialize($rule->args)); + call_user_func_array(array("graphics", $rule->operation), $args); + $working_file = $output_file; + } + } + + if (!empty($ops["thumb"])) { + $dims = getimagesize($item->thumb_path()); + $item->thumb_width = $dims[0]; + $item->thumb_height = $dims[1]; + $item->thumb_dirty = 0; + } + + if (!empty($ops["resize"])) { + $dims = getimagesize($item->resize_path()); + $item->resize_width = $dims[0]; + $item->resize_height = $dims[1]; + $item->resize_dirty = 0; + } + $item->save(); + } catch (Kohana_Exception $e) { + // Something went wrong rebuilding the image. Leave it dirty and move on. + // @todo we should handle this better. + Kohana::log("error", "Caught exception rebuilding image: {$item->title}\n" . + $e->getTraceAsString()); + } + } + + /** + * Resize an image. Valid options are width, height and master. Master is one of the Image + * master dimension constants. + * + * @param string $input_file + * @param string $output_file + * @param array $options + */ + static function resize($input_file, $output_file, $options) { + if (!self::$init) { + self::init_toolkit(); + } + + if (filesize($input_file) == 0) { + throw new Exception("@todo MALFORMED_INPUT_FILE"); + } + + $dims = getimagesize($input_file); + if (max($dims[0], $dims[1]) < min($options["width"], $options["height"])) { + // Image would get upscaled; do nothing + copy($input_file, $output_file); + } else { + Image::factory($input_file) + ->resize($options["width"], $options["height"], $options["master"]) + ->quality(module::get_var("core", "image_quality")) + ->save($output_file); + } + } + + /** + * Rotate an image. Valid options are degrees + * + * @param string $input_file + * @param string $output_file + * @param array $options + */ + static function rotate($input_file, $output_file, $options) { + if (!self::$init) { + self::init_toolkit(); + } + + Image::factory($input_file) + ->quality(module::get_var("core", "image_quality")) + ->rotate($options["degrees"]) + ->save($output_file); + } + + /** + * Overlay an image on top of the input file. + * + * Valid options are: file, mime_type, position, transparency_percent, padding + * + * Valid positions: northwest, north, northeast, + * west, center, east, + * southwest, south, southeast + * + * padding is in pixels + * + * @param string $input_file + * @param string $output_file + * @param array $options + */ + static function composite($input_file, $output_file, $options) { + if (!self::$init) { + self::init_toolkit(); + } + + list ($width, $height) = getimagesize($input_file); + list ($w_width, $w_height) = getimagesize($options["file"]); + + $pad = isset($options["padding"]) ? $options["padding"] : 10; + $top = $pad; + $left = $pad; + $y_center = max($height / 2 - $w_height / 2, $pad); + $x_center = max($width / 2 - $w_width / 2, $pad); + $bottom = max($height - $w_height - $pad, $pad); + $right = max($width - $w_width - $pad, $pad); + + switch ($options["position"]) { + case "northwest": $x = $left; $y = $top; break; + case "north": $x = $x_center; $y = $top; break; + case "northeast": $x = $right; $y = $top; break; + case "west": $x = $left; $y = $y_center; break; + case "center": $x = $x_center; $y = $y_center; break; + case "east": $x = $right; $y = $y_center; break; + case "southwest": $x = $left; $y = $bottom; break; + case "south": $x = $x_center; $y = $bottom; break; + case "southeast": $x = $right; $y = $bottom; break; + } + + Image::factory($input_file) + ->composite($options["file"], $x, $y, $options["transparency"]) + ->quality(module::get_var("core", "image_quality")) + ->save($output_file); + } + + /** + * Return a query result that locates all items with dirty images. + * @return Database_Result Query result + */ + static function find_dirty_images_query() { + return Database::instance()->query( + "SELECT `id` FROM {items} " . + "WHERE ((`thumb_dirty` = 1 AND (`type` <> 'album' OR `album_cover_item_id` IS NOT NULL))" . + " OR (`resize_dirty` = 1 AND `type` = 'photo')) " . + " AND `id` != 1"); + } + + /** + * Mark thumbnails and resizes as dirty. They will have to be rebuilt. + */ + static function mark_dirty($thumbs, $resizes) { + if ($thumbs || $resizes) { + $db = Database::instance(); + $fields = array(); + if ($thumbs) { + $fields["thumb_dirty"] = 1; + } + if ($resizes) { + $fields["resize_dirty"] = 1; + } + $db->update("items", $fields, true); + } + + $count = self::find_dirty_images_query()->count(); + if ($count) { + site_status::warning( + t2("One of your photos is out of date. Click here to fix it", + "%count of your photos are out of date. Click here to fix them", + $count, + array("attrs" => sprintf( + 'href="%s" class="gDialogLink"', + url::site("admin/maintenance/start/core_task::rebuild_dirty_images?csrf=__CSRF__")))), + "graphics_dirty"); + } + } + + /** + * Detect which graphics toolkits are available on this system. Return an array of key value + * pairs where the key is one of gd, imagemagick, graphicsmagick and the value is information + * about that toolkit. For GD we return the version string, and for ImageMagick and + * GraphicsMagick we return the path to the directory containing the appropriate binaries. + */ + static function detect_toolkits() { + $gd = function_exists("gd_info") ? gd_info() : array(); + $exec = function_exists("exec"); + if (!isset($gd["GD Version"])) { + $gd["GD Version"] = false; + } + return array("gd" => $gd, + "imagemagick" => $exec ? dirname(exec("which convert")) : false, + "graphicsmagick" => $exec ? dirname(exec("which gm")) : false); + } + + /** + * This needs to be run once, after the initial install, to choose a graphics toolkit. + */ + static function choose_default_toolkit() { + // Detect a graphics toolkit + $toolkits = graphics::detect_toolkits(); + foreach (array("imagemagick", "graphicsmagick", "gd") as $tk) { + if ($toolkits[$tk]) { + module::set_var("core", "graphics_toolkit", $tk); + module::set_var("core", "graphics_toolkit_path", $tk == "gd" ? "" : $toolkits[$tk]); + break; + } + } + if (!module::get_var("core", "graphics_toolkit")) { + site_status::warning( + t("Graphics toolkit missing! Please choose a toolkit", + array("url" => url::site("admin/graphics"))), + "missing_graphics_toolkit"); + } + } + + /** + * Choose which driver the Kohana Image library uses. + */ + static function init_toolkit() { + switch(module::get_var("core", "graphics_toolkit")) { + case "gd": + Kohana::config_set("image.driver", "GD"); + break; + + case "imagemagick": + Kohana::config_set("image.driver", "ImageMagick"); + Kohana::config_set( + "image.params.directory", module::get_var("core", "graphics_toolkit_path")); + break; + + case "graphicsmagick": + Kohana::config_set("image.driver", "GraphicsMagick"); + Kohana::config_set( + "image.params.directory", module::get_var("core", "graphics_toolkit_path")); + break; + } + + self::$init = 1; + } + + /** + * Verify that a specific graphics function is available with the active toolkit. + * @param string $func (eg rotate, resize) + * @return boolean + */ + static function can($func) { + if (module::get_var("core", "graphics_toolkit") == "gd" && + $func == "rotate" && + !function_exists("imagerotate")) { + return false; + } + + return true; + } +} diff --git a/modules/gallery/helpers/item.php b/modules/gallery/helpers/item.php new file mode 100644 index 00000000..7daaf1e1 --- /dev/null +++ b/modules/gallery/helpers/item.php @@ -0,0 +1,105 @@ +parent(); + if ($parent->album_cover_item_id == $source->id) { + if ($parent->children_count() > 1) { + foreach ($parent->children(2) as $child) { + if ($child->id != $source->id) { + $new_cover_item = $child; + break; + } + } + item::make_album_cover($new_cover_item); + } else { + item::remove_album_cover($parent); + } + } + + $source->move_to($target); + + // If the target has no cover item, make this it. + if ($target->album_cover_item_id == null) { + item::make_album_cover($source); + } + } + + static function make_album_cover($item) { + $parent = $item->parent(); + access::required("edit", $parent); + + model_cache::clear("item", $parent->album_cover_item_id); + $parent->album_cover_item_id = $item->is_album() ? $item->album_cover_item_id : $item->id; + $parent->thumb_dirty = 1; + $parent->save(); + graphics::generate($parent); + $grand_parent = $parent->parent(); + if ($grand_parent && $grand_parent->album_cover_item_id == null) { + item::make_album_cover($parent); + } + } + + static function remove_album_cover($album) { + access::required("edit", $album); + @unlink($album->thumb_path()); + + model_cache::clear("item", $album->album_cover_item_id) ; + $album->album_cover_item_id = null; + $album->thumb_width = 0; + $album->thumb_height = 0; + $album->thumb_dirty = 1; + $album->save(); + graphics::generate($album); + } + + static function validate_no_slashes($input) { + if (strpos($input->value, "/") !== false) { + $input->add_error("no_slashes", 1); + } + } + + static function validate_no_trailing_period($input) { + if (rtrim($input->value, ".") !== $input->value) { + $input->add_error("no_trailing_period", 1); + } + } + + static function validate_no_name_conflict($input) { + $itemid = Input::instance()->post("item"); + if (is_array($itemid)) { + $itemid = $itemid[0]; + } + $item = ORM::factory("item") + ->in("id", $itemid) + ->find(); + if (Database::instance() + ->from("items") + ->where("parent_id", $item->parent_id) + ->where("id <>", $item->id) + ->where("name", $input->value) + ->count_records()) { + $input->add_error("conflict", 1); + } + } +} \ No newline at end of file diff --git a/modules/gallery/helpers/l10n_client.php b/modules/gallery/helpers/l10n_client.php new file mode 100644 index 00000000..ec4c5429 --- /dev/null +++ b/modules/gallery/helpers/l10n_client.php @@ -0,0 +1,203 @@ + $version, + "client_token" => self::client_token(), + "signature" => $signature, + "uid" => self::server_uid($api_key))); + if (!remote::success($response_status)) { + return false; + } + return true; + } + + static function fetch_updates() { + $request->locales = array(); + $request->messages = new stdClass(); + + $locales = locale::installed(); + foreach ($locales as $locale => $locale_data) { + $request->locales[] = $locale; + } + + // @todo Batch requests (max request size) + foreach (Database::instance() + ->select("key", "locale", "revision", "translation") + ->from("incoming_translations") + ->get() + ->as_array() as $row) { + if (!isset($request->messages->{$row->key})) { + $request->messages->{$row->key} = 1; + } + if (!empty($row->revision) && !empty($row->translation)) { + if (!is_object($request->messages->{$row->key})) { + $request->messages->{$row->key} = new stdClass(); + } + $request->messages->{$row->key}->{$row->locale} = $row->revision; + } + } + // @todo Include messages from outgoing_translations? + + $request_data = json_encode($request); + $url = self::_server_url() . "?q=translations/fetch"; + list ($response_data, $response_status) = remote::post($url, array("data" => $request_data)); + if (!remote::success($response_status)) { + throw new Exception("@todo TRANSLATIONS_FETCH_REQUEST_FAILED " . $response_status); + } + if (empty($response_data)) { + log::info("translations", "Translations fetch request resulted in an empty response"); + return; + } + + $response = json_decode($response_data); + + // Response format (JSON payload): + // [{key:, translation: , rev:, locale:}, + // {key:, ...} + // ] + $count = count($response); + log::info("translations", "Installed $count new / updated translation messages"); + + foreach ($response as $message_data) { + // @todo Better input validation + if (empty($message_data->key) || empty($message_data->translation) || + empty($message_data->locale) || empty($message_data->rev)) { + throw new Exception("@todo TRANSLATIONS_FETCH_REQUEST_FAILED: Invalid response data"); + } + $key = $message_data->key; + $locale = $message_data->locale; + $revision = $message_data->rev; + $translation = serialize(json_decode($message_data->translation)); + + // @todo Should we normalize the incoming_translations table into messages(id, key, message) + // and incoming_translations(id, translation, locale, revision)? Or just allow + // incoming_translations.message to be NULL? + $locale = $message_data->locale; + $entry = ORM::factory("incoming_translation") + ->where(array("key" => $key, "locale" => $locale)) + ->find(); + if (!$entry->loaded) { + // @todo Load a message key -> message (text) dict into memory outside of this loop + $root_entry = ORM::factory("incoming_translation") + ->where(array("key" => $key, "locale" => "root")) + ->find(); + $entry->key = $key; + $entry->message = $root_entry->message; + $entry->locale = $locale; + } + $entry->revision = $revision; + $entry->translation = $translation; + $entry->save(); + } + } + + static function submit_translations() { + // Request format (HTTP POST): + // client_token = + // uid = + // signature = md5(user_api_key($uid, $client_token) . $data . $client_token)) + // data = // JSON payload + // + // {: {message: + // translations: {: , + // : ...}}, + // : {...} + // } + + // @todo Batch requests (max request size) + // @todo include base_revision in submission / how to handle resubmissions / edit fights? + foreach (Database::instance() + ->select("key", "message", "locale", "base_revision", "translation") + ->from("outgoing_translations") + ->get() as $row) { + $key = $row->key; + if (!isset($request->{$key})) { + $request->{$key}->message = json_encode(unserialize($row->message)); + } + $request->{$key}->translations->{$row->locale} = json_encode(unserialize($row->translation)); + } + + // @todo reduce memory consumpotion, e.g. free $request + $request_data = json_encode($request); + $url = self::_server_url() . "?q=translations/submit"; + $signature = self::_sign($request_data); + + list ($response_data, $response_status) = remote::post( + $url, array("data" => $request_data, + "client_token" => self::client_token(), + "signature" => $signature, + "uid" => self::server_uid())); + + if (!remote::success($response_status)) { + throw new Exception("@todo TRANSLATIONS_SUBMISSION_FAILED " . $response_status); + } + if (empty($response_data)) { + return; + } + + $response = json_decode($response_data); + // Response format (JSON payload): + // [{key:, locale:, rev:, status:}, + // {key:, ...} + // ] + + // @todo Move messages out of outgoing into incoming, using new rev? + // @todo show which messages have been rejected / are pending? + } +} \ No newline at end of file diff --git a/modules/gallery/helpers/l10n_scanner.php b/modules/gallery/helpers/l10n_scanner.php new file mode 100644 index 00000000..80b6f01c --- /dev/null +++ b/modules/gallery/helpers/l10n_scanner.php @@ -0,0 +1,154 @@ +select("key") + ->from("incoming_translations") + ->where("locale", "root") + ->get() as $row) { + $cache[$row->key] = true; + } + } + + $key = I18n::get_message_key($message); + if (array_key_exists($key, $cache)) { + return $cache[$key]; + } + + $entry = ORM::factory("incoming_translation", array("key" => $key)); + if (!$entry->loaded) { + $entry->key = $key; + $entry->message = serialize($message); + $entry->locale = "root"; + $entry->save(); + } + } + + static function scan_php_file($file, &$cache) { + $code = file_get_contents($file); + $raw_tokens = token_get_all($code); + unset($code); + + $tokens = array(); + $func_token_list = array("t" => array(), "t2" => array()); + $token_number = 0; + // Filter out HTML / whitespace, and build a lookup for global function calls. + foreach ($raw_tokens as $token) { + if ((!is_array($token)) || (($token[0] != T_WHITESPACE) && ($token[0] != T_INLINE_HTML))) { + if (is_array($token)) { + if ($token[0] == T_STRING && in_array($token[1], array("t", "t2"))) { + $func_token_list[$token[1]][] = $token_number; + } + } + $tokens[] = $token; + $token_number++; + } + } + unset($raw_tokens); + + if (!empty($func_token_list["t"])) { + l10n_scanner::_parse_t_calls($tokens, $func_token_list["t"], $cache); + } + if (!empty($func_token_list["t2"])) { + l10n_scanner::_parse_plural_calls($tokens, $func_token_list["t2"], $cache); + } + } + + static function scan_info_file($file, &$cache) { + $code = file_get_contents($file); + if (preg_match("#name\s*?=\s*(.*?)\ndescription\s*?=\s*(.*)\n#", $code, $matches)) { + unset($matches[0]); + foreach ($matches as $string) { + l10n_scanner::process_message($string, $cache); + } + } + } + + private static function _parse_t_calls(&$tokens, &$call_list, &$cache) { + foreach ($call_list as $index) { + $function_name = $tokens[$index++]; + $parens = $tokens[$index++]; + $first_param = $tokens[$index++]; + $next_token = $tokens[$index]; + + if ($parens == "(") { + if (in_array($next_token, array(")", ",")) + && (is_array($first_param) && ($first_param[0] == T_CONSTANT_ENCAPSED_STRING))) { + $message = self::_escape_quoted_string($first_param[1]); + l10n_scanner::process_message($message, $cache); + } else { + // t() found, but inside is something which is not a string literal. + // @todo Call status callback with error filename/line. + } + } + } + } + + private static function _parse_plural_calls(&$tokens, &$call_list, &$cache) { + foreach ($call_list as $index) { + $function_name = $tokens[$index++]; + $parens = $tokens[$index++]; + $first_param = $tokens[$index++]; + $first_separator = $tokens[$index++]; + $second_param = $tokens[$index++]; + $next_token = $tokens[$index]; + + if ($parens == "(") { + if ($first_separator == "," && $next_token == "," + && is_array($first_param) && $first_param[0] == T_CONSTANT_ENCAPSED_STRING + && is_array($second_param) && $second_param[0] == T_CONSTANT_ENCAPSED_STRING) { + $singular = self::_escape_quoted_string($first_param[1]); + $plural = self::_escape_quoted_string($first_param[1]); + l10n_scanner::process_message(array("one" => $singular, "other" => $plural), $cache); + } else { + // t2() found, but inside is something which is not a string literal. + // @todo Call status callback with error filename/line. + } + } + } + } + + /** + * Escape quotes in a strings depending on the surrounding + * quote type used. + * + * @param $str The strings to escape + */ + private static function _escape_quoted_string($str) { + $quo = substr($str, 0, 1); + $str = substr($str, 1, -1); + if ($quo == '"') { + $str = stripcslashes($str); + } else { + $str = strtr($str, array("\\'" => "'", "\\\\" => "\\")); + } + return addcslashes($str, "\0..\37\\\""); + } +} diff --git a/modules/gallery/helpers/locale.php b/modules/gallery/helpers/locale.php new file mode 100644 index 00000000..b707637f --- /dev/null +++ b/modules/gallery/helpers/locale.php @@ -0,0 +1,119 @@ +$code)) { + $installed[$code] = $available[$code]; + } + } + return $installed; + } + + static function update_installed($locales) { + // Ensure that the default is included... + $default = module::get_var("core", "default_locale"); + $locales = array_merge($locales, array($default)); + + module::set_var("core", "installed_locales", join("|", $locales)); + } + + // @todo Might want to add a localizable language name as well. + private static function _init_language_data() { + $l["af_ZA"] = "Afrikaans"; // Afrikaans + $l["ar_SA"] = "العربية"; // Arabic + $l["bg_BG"] = "Български"; // Bulgarian + $l["ca_ES"] = "Catalan"; // Catalan + $l["cs_CZ"] = "Česky"; // Czech + $l["da_DK"] = "Dansk"; // Danish + $l["de_DE"] = "Deutsch"; // German + $l["el_GR"] = "Greek"; // Greek + $l["en_GB"] = "English (UK)"; // English (UK) + $l["en_US"] = "English (US)"; // English (US) + $l["es_AR"] = "Español (AR)"; // Spanish (AR) + $l["es_ES"] = "Español"; // Spanish (ES) + $l["es_MX"] = "Español (MX)"; // Spanish (MX) + $l["et_EE"] = "Eesti"; // Estonian + $l["eu_ES"] = "Euskara"; // Basque + $l["fa_IR"] = "فارسي"; // Farsi + $l["fi_FI"] = "Suomi"; // Finnish + $l["fr_FR"] = "Français"; // French + $l["ga_IE"] = "Gaeilge"; // Irish + $l["he_IL"] = "עברית"; // Hebrew + $l["hu_HU"] = "Magyar"; // Hungarian + $l["is_IS"] = "Icelandic"; // Icelandic + $l["it_IT"] = "Italiano"; // Italian + $l["ja_JP"] = "日本語"; // Japanese + $l["ko_KR"] = "한국말"; // Korean + $l["lt_LT"] = "Lietuvių"; // Lithuanian + $l["lv_LV"] = "Latviešu"; // Latvian + $l["nl_NL"] = "Nederlands"; // Dutch + $l["no_NO"] = "Norsk bokmål"; // Norwegian + $l["pl_PL"] = "Polski"; // Polish + $l["pt_BR"] = "Português Brasileiro"; // Portuguese (BR) + $l["pt_PT"] = "Português"; // Portuguese (PT) + $l["ro_RO"] = "Română"; // Romanian + $l["ru_RU"] = "Русский"; // Russian + $l["sk_SK"] = "Slovenčina"; // Slovak + $l["sl_SI"] = "Slovenščina"; // Slovenian + $l["sr_CS"] = "Srpski"; // Serbian + $l["sv_SE"] = "Svenska"; // Swedish + $l["tr_TR"] = "Türkçe"; // Turkish + $l["uk_UA"] = "Українська"; // Ukrainian + $l["vi_VN"] = "Tiếng Việt"; // Vietnamese + $l["zh_CN"] = "简体中文"; // Chinese (CN) + $l["zh_TW"] = "繁體中文"; // Chinese (TW) + asort($l, SORT_LOCALE_STRING); + self::$locales = $l; + } + + static function display_name($locale=null) { + if (empty(self::$locales)) { + self::_init_language_data(); + } + $locale or $locale = I18n::instance()->locale(); + + return self::$locales["$locale"]; + } + + static function is_rtl($locale) { + return in_array($locale, array("he_IL", "fa_IR", "ar_SA")); + } +} \ No newline at end of file diff --git a/modules/gallery/helpers/log.php b/modules/gallery/helpers/log.php new file mode 100644 index 00000000..451f985a --- /dev/null +++ b/modules/gallery/helpers/log.php @@ -0,0 +1,108 @@ +category = $category; + $log->message = $message; + $log->severity = $severity; + $log->html = $html; + $log->url = substr(url::abs_current(true), 0, 255); + $log->referer = request::referrer(null); + $log->timestamp = time(); + $log->user_id = user::active()->id; + $log->save(); + } + + + /** + * Convert a message severity to a CSS class + * @param integer $severity + * @return string + */ + static function severity_class($severity) { + switch($severity) { + case self::SUCCESS: + return "gSuccess"; + + case self::INFO: + return "gInfo"; + + case self::WARNING: + return "gWarning"; + + case self::ERROR: + return "gError"; + } + } +} diff --git a/modules/gallery/helpers/message.php b/modules/gallery/helpers/message.php new file mode 100644 index 00000000..af3b96cc --- /dev/null +++ b/modules/gallery/helpers/message.php @@ -0,0 +1,108 @@ +get("messages"); + $status[] = array($msg, $severity); + $session->set("messages", $status); + } + + /** + * Get any pending messages. There are two types of messages, transient and permanent. + * Permanent messages are used to let the admin know that there are pending administrative + * issues that need to be resolved. Transient ones are only displayed once. + * @return html text + */ + static function get() { + $buf = array(); + + $messages = Session::instance()->get_once("messages", array()); + foreach ($messages as $msg) { + $buf[] = "
    • $msg[0]
    • "; + } + if ($buf) { + return "
        " . implode("", $buf) . "
      "; + } + } + + /** + * Convert a message severity to a CSS class + * @param integer $severity + * @return string + */ + static function severity_class($severity) { + switch($severity) { + case self::SUCCESS: + return "gSuccess"; + + case self::INFO: + return "gInfo"; + + case self::WARNING: + return "gWarning"; + + case self::ERROR: + return "gError"; + } + } +} diff --git a/modules/gallery/helpers/model_cache.php b/modules/gallery/helpers/model_cache.php new file mode 100644 index 00000000..2649fdbd --- /dev/null +++ b/modules/gallery/helpers/model_cache.php @@ -0,0 +1,46 @@ +$model_name->$field_name->$id)) { + $model = ORM::factory($model_name)->where($field_name, $id)->find(); + if (!$model->loaded) { + throw new Exception("@todo MISSING_MODEL $model_name:$id"); + } + self::$cache->$model_name->$field_name->$id = $model; + } + + return self::$cache->$model_name->$field_name->$id; + } + + static function clear($model_name, $id, $field_name="id") { + if (!empty(self::$cache->$model_name->$field_name->$id)) { + unset(self::$cache->$model_name->$field_name->$id); + } + } + + static function set($model) { + self::$cache->{$model->object_name} + ->{$model->primary_key} + ->{$model->{$model->primary_key}} = $model; + } +} diff --git a/modules/gallery/helpers/module.php b/modules/gallery/helpers/module.php new file mode 100644 index 00000000..a48c89ed --- /dev/null +++ b/modules/gallery/helpers/module.php @@ -0,0 +1,357 @@ +loaded) { + $module->name = $module_name; + $module->active = $module_name == "core"; // only core is active by default + } + $module->version = 1; + $module->save(); + Kohana::log("debug", "$module_name: version is now $version"); + } + + /** + * Load the corresponding Module_Model + * @param string $module_name + */ + static function get($module_name) { + // @todo can't easily use model_cache here because it throw an exception on missing models. + return ORM::factory("module", array("name" => $module_name)); + } + + /** + * Check to see if a module is installed + * @param string $module_name + */ + static function is_installed($module_name) { + return array_key_exists($module_name, self::$modules); + } + + /** + * Check to see if a module is active + * @param string $module_name + */ + static function is_active($module_name) { + return array_key_exists($module_name, self::$modules) && + self::$modules[$module_name]->active; + } + + /** + * Return the list of available modules, including uninstalled modules. + */ + static function available() { + $modules = new ArrayObject(array(), ArrayObject::ARRAY_AS_PROPS); + foreach (array_merge(array("core/module.info"), glob(MODPATH . "*/module.info")) as $file) { + $module_name = basename(dirname($file)); + $modules->$module_name = new ArrayObject(parse_ini_file($file), ArrayObject::ARRAY_AS_PROPS); + $modules->$module_name->installed = self::is_installed($module_name); + $modules->$module_name->active = self::is_active($module_name); + $modules->$module_name->version = self::get_version($module_name); + $modules->$module_name->locked = false; + } + + // Lock certain modules + $modules->core->locked = true; + $modules->user->locked = true; + $modules->ksort(); + + return $modules; + } + + /** + * Return a list of all the active modules in no particular order. + */ + static function active() { + return self::$active; + } + + /** + * Install a module. This will call _installer::install(), which is responsible for + * creating database tables, setting module variables and and calling module::set_version(). + * Note that after installing, the module must be activated before it is available for use. + * @param string $module_name + */ + static function install($module_name) { + $kohana_modules = Kohana::config("core.modules"); + $kohana_modules[] = MODPATH . $module_name; + Kohana::config_set("core.modules", $kohana_modules); + + $installer_class = "{$module_name}_installer"; + if (method_exists($installer_class, "install")) { + call_user_func_array(array($installer_class, "install"), array()); + } + + // Now the module is installed but inactive, so don't leave it in the active path + array_pop($kohana_modules); + Kohana::config_set("core.modules", $kohana_modules); + + log::success( + "module", t("Installed module %module_name", array("module_name" => $module_name))); + } + + /** + * Activate an installed module. This will call _installer::activate() which should take + * any steps to make sure that the module is ready for use. This will also activate any + * existing graphics rules for this module. + * @param string $module_name + */ + static function activate($module_name) { + $kohana_modules = Kohana::config("core.modules"); + $kohana_modules[] = MODPATH . $module_name; + Kohana::config_set("core.modules", $kohana_modules); + + $installer_class = "{$module_name}_installer"; + if (method_exists($installer_class, "activate")) { + call_user_func_array(array($installer_class, "activate"), array()); + } + + $module = self::get($module_name); + if ($module->loaded) { + $module->active = true; + $module->save(); + } + + self::load_modules(); + graphics::activate_rules($module_name); + log::success( + "module", t("Activated module %module_name", array("module_name" => $module_name))); + } + + /** + * Deactivate an installed module. This will call _installer::deactivate() which + * should take any cleanup steps to make sure that the module isn't visible in any way. + * @param string $module_name + */ + static function deactivate($module_name) { + $installer_class = "{$module_name}_installer"; + if (method_exists($installer_class, "deactivate")) { + call_user_func_array(array($installer_class, "deactivate"), array()); + } + + $module = self::get($module_name); + if ($module->loaded) { + $module->active = false; + $module->save(); + } + + self::load_modules(); + graphics::deactivate_rules($module_name); + log::success( + "module", t("Deactivated module %module_name", array("module_name" => $module_name))); + } + + /** + * Uninstall a deactivated module. This will call _installer::uninstall() which should + * take whatever steps necessary to make sure that all traces of a module are gone. + * @param string $module_name + */ + static function uninstall($module_name) { + $installer_class = "{$module_name}_installer"; + if (method_exists($installer_class, "uninstall")) { + call_user_func(array($installer_class, "uninstall")); + } + + graphics::remove_rule($module_name); + $module = self::get($module_name); + if ($module->loaded) { + $module->delete(); + } + + // We could delete the module vars here too, but it's nice to leave them around + // in case the module gets reinstalled. + + self::load_modules(); + log::success( + "module", t("Uninstalled module %module_name", array("module_name" => $module_name))); + } + + /** + * Load the active modules. This is called at bootstrap time. + */ + static function load_modules() { + // Reload module list from the config file since we'll do a refresh after calling install() + $core = Kohana::config_load("core"); + $kohana_modules = $core["modules"]; + $modules = ORM::factory("module")->find_all(); + + self::$modules = array(); + self::$active = array(); + foreach ($modules as $module) { + self::$modules[$module->name] = $module; + if ($module->active) { + self::$active[] = $module; + } + if ($module->name != "core") { + $kohana_modules[] = MODPATH . $module->name; + } + } + Kohana::config_set("core.modules", $kohana_modules); + } + + /** + * Run a specific event on all active modules. + * @param string $name the event name + * @param mixed $data data to pass to each event handler + */ + static function event($name, &$data=null) { + $args = func_get_args(); + array_shift($args); + $function = str_replace(".", "_", $name); + + foreach (self::$modules as $module) { + if (!$module->active) { + continue; + } + + $class = "{$module->name}_event"; + if (method_exists($class, $function)) { + call_user_func_array(array($class, $function), $args); + } + } + } + + /** + * Get a variable from this module + * @param string $module_name + * @param string $name + * @param string $default_value + * @return the value + */ + static function get_var($module_name, $name, $default_value=null) { + // We cache all vars in core._cache so that we can load all vars at once for + // performance. + if (empty(self::$var_cache)) { + $row = Database::instance() + ->select("value") + ->from("vars") + ->where(array("module_name" => "core", "name" => "_cache")) + ->get() + ->current(); + if ($row) { + self::$var_cache = unserialize($row->value); + } else { + // core._cache doesn't exist. Create it now. + foreach (Database::instance() + ->select("module_name", "name", "value") + ->from("vars") + ->orderby("module_name", "name") + ->get() as $row) { + if ($row->module_name == "core" && $row->name == "_cache") { + // This could happen if there's a race condition + continue; + } + self::$var_cache->{$row->module_name}->{$row->name} = $row->value; + } + $cache = ORM::factory("var"); + $cache->module_name = "core"; + $cache->name = "_cache"; + $cache->value = serialize(self::$var_cache); + $cache->save(); + } + } + + if (isset(self::$var_cache->$module_name->$name)) { + return self::$var_cache->$module_name->$name; + } else { + return $default_value; + } + } + + /** + * Store a variable for this module + * @param string $module_name + * @param string $name + * @param string $value + */ + static function set_var($module_name, $name, $value) { + $var = ORM::factory("var") + ->where("module_name", $module_name) + ->where("name", $name) + ->find(); + if (!$var->loaded) { + $var->module_name = $module_name; + $var->name = $name; + } + $var->value = $value; + $var->save(); + + Database::instance()->delete("vars", array("module_name" => "core", "name" => "_cache")); + self::$var_cache = null; + } + + /** + * Increment the value of a variable for this module + * @param string $module_name + * @param string $name + * @param string $increment (optional, default is 1) + */ + static function incr_var($module_name, $name, $increment=1) { + Database::instance()->query( + "UPDATE {vars} SET `value` = `value` + $increment " . + "WHERE `module_name` = '$module_name' " . + "AND `name` = '$name'"); + + Database::instance()->delete("vars", array("module_name" => "core", "name" => "_cache")); + self::$var_cache = null; + } + + /** + * Remove a variable for this module. + * @param string $module_name + * @param string $name + */ + static function clear_var($module_name, $name) { + $var = ORM::factory("var") + ->where("module_name", $module_name) + ->where("name", $name) + ->find(); + if ($var->loaded) { + $var->delete(); + } + + Database::instance()->delete("vars", array("module_name" => "core", "name" => "_cache")); + self::$var_cache = null; + } + + /** + * Return the version of the installed module. + * @param string $module_name + */ + static function get_version($module_name) { + return self::get($module_name)->version; + } +} diff --git a/modules/gallery/helpers/movie.php b/modules/gallery/helpers/movie.php new file mode 100644 index 00000000..3293d4ac --- /dev/null +++ b/modules/gallery/helpers/movie.php @@ -0,0 +1,153 @@ +loaded || !$parent->is_album()) { + throw new Exception("@todo INVALID_PARENT"); + } + + if (!is_file($filename)) { + throw new Exception("@todo MISSING_MOVIE_FILE"); + } + + if (strpos($name, "/")) { + throw new Exception("@todo NAME_CANNOT_CONTAIN_SLASH"); + } + + // We don't allow trailing periods as a security measure + // ref: http://dev.kohanaphp.com/issues/684 + if (rtrim($name, ".") != $name) { + throw new Exception("@todo NAME_CANNOT_END_IN_PERIOD"); + } + + $movie_info = movie::getmoviesize($filename); + + // Force an extension onto the name + $pi = pathinfo($filename); + if (empty($pi["extension"])) { + $pi["extension"] = image_type_to_extension($movie_info[2], false); + $name .= "." . $pi["extension"]; + } + + $movie = ORM::factory("item"); + $movie->type = "movie"; + $movie->title = $title; + $movie->description = $description; + $movie->name = $name; + $movie->owner_id = $owner_id ? $owner_id : user::active(); + $movie->width = $movie_info[0]; + $movie->height = $movie_info[1]; + $movie->mime_type = strtolower($pi["extension"]) == "mp4" ? "video/mp4" : "video/x-flv"; + $movie->thumb_dirty = 1; + $movie->resize_dirty = 1; + $movie->sort_column = "weight"; + $movie->rand_key = ((float)mt_rand()) / (float)mt_getrandmax(); + + // Randomize the name if there's a conflict + while (ORM::Factory("item") + ->where("parent_id", $parent->id) + ->where("name", $movie->name) + ->find()->id) { + // @todo Improve this. Random numbers are not user friendly + $movie->name = rand() . "." . $pi["extension"]; + } + + // This saves the photo + $movie->add_to_parent($parent); + + // If the thumb or resize already exists then rename it + if (file_exists($movie->resize_path()) || + file_exists($movie->thumb_path())) { + $movie->name = $pi["filename"] . "-" . rand() . "." . $pi["extension"]; + $movie->save(); + } + + copy($filename, $movie->file_path()); + + module::event("item_created", $movie); + + // Build our thumbnail + graphics::generate($movie); + + // If the parent has no cover item, make this it. + if (access::can("edit", $parent) && $parent->album_cover_item_id == null) { + item::make_album_cover($movie); + } + + return $movie; + } + + static function getmoviesize($filename) { + $ffmpeg = self::find_ffmpeg(); + if (empty($ffmpeg)) { + throw new Exception("@todo MISSING_FFMPEG"); + } + + $cmd = escapeshellcmd($ffmpeg) . " -i " . escapeshellarg($filename) . " 2>&1"; + $result = `$cmd`; + if (preg_match("/Stream.*?Video:.*?(\d+)x(\d+).*\ +([0-9\.]+) (fps|tb).*/", + $result, $regs)) { + list ($width, $height) = array($regs[1], $regs[2]); + } else { + list ($width, $height) = array(0, 0); + } + return array($width, $height); + } + + static function extract_frame($input_file, $output_file) { + $ffmpeg = self::find_ffmpeg(); + if (empty($ffmpeg)) { + throw new Exception("@todo MISSING_FFMPEG"); + } + + $cmd = escapeshellcmd($ffmpeg) . " -i " . escapeshellarg($input_file) . + " -an -ss 00:00:03 -an -r 1 -vframes 1" . + " -y -f mjpeg " . escapeshellarg($output_file); + exec($cmd); + } + + static function find_ffmpeg() { + if (!$ffmpeg_path = module::get_var("core", "ffmpeg_path")) { + if (function_exists("exec")) { + $ffmpeg_path = exec("which ffmpeg"); + if ($ffmpeg_path) { + module::set_var("core", "ffmpeg_path", $ffmpeg_path); + } + } + } + return $ffmpeg_path; + } +} diff --git a/modules/gallery/helpers/photo.php b/modules/gallery/helpers/photo.php new file mode 100644 index 00000000..c1c005f5 --- /dev/null +++ b/modules/gallery/helpers/photo.php @@ -0,0 +1,171 @@ +loaded || !$parent->is_album()) { + throw new Exception("@todo INVALID_PARENT"); + } + + if (!is_file($filename)) { + throw new Exception("@todo MISSING_IMAGE_FILE"); + } + + if (strpos($name, "/")) { + throw new Exception("@todo NAME_CANNOT_CONTAIN_SLASH"); + } + + // We don't allow trailing periods as a security measure + // ref: http://dev.kohanaphp.com/issues/684 + if (rtrim($name, ".") != $name) { + throw new Exception("@todo NAME_CANNOT_END_IN_PERIOD"); + } + + $image_info = getimagesize($filename); + + // Force an extension onto the name + $pi = pathinfo($filename); + if (empty($pi["extension"])) { + $pi["extension"] = image_type_to_extension($image_info[2], false); + $name .= "." . $pi["extension"]; + } + + $photo = ORM::factory("item"); + $photo->type = "photo"; + $photo->title = $title; + $photo->description = $description; + $photo->name = $name; + $photo->owner_id = $owner_id ? $owner_id : user::active(); + $photo->width = $image_info[0]; + $photo->height = $image_info[1]; + $photo->mime_type = empty($image_info['mime']) ? "application/unknown" : $image_info['mime']; + $photo->thumb_dirty = 1; + $photo->resize_dirty = 1; + $photo->sort_column = "weight"; + $photo->rand_key = ((float)mt_rand()) / (float)mt_getrandmax(); + + // Randomize the name if there's a conflict + while (ORM::Factory("item") + ->where("parent_id", $parent->id) + ->where("name", $photo->name) + ->find()->id) { + // @todo Improve this. Random numbers are not user friendly + $photo->name = rand() . "." . $pi["extension"]; + } + + // This saves the photo + $photo->add_to_parent($parent); + + /* + * If the thumb or resize already exists then rename it. We need to do this after the save + * because the resize_path and thumb_path both call relative_path which caches the + * path. Before add_to_parent the relative path will be incorrect. + */ + if (file_exists($photo->resize_path()) || + file_exists($photo->thumb_path())) { + $photo->name = $pi["filename"] . "-" . rand() . "." . $pi["extension"]; + $photo->save(); + } + + copy($filename, $photo->file_path()); + + module::event("item_created", $photo); + + // Build our thumbnail/resizes + graphics::generate($photo); + + // If the parent has no cover item, make this it. + if (access::can("edit", $parent) && $parent->album_cover_item_id == null) { + item::make_album_cover($photo); + } + + return $photo; + } + + static function get_add_form($parent) { + $form = new Forge("albums/{$parent->id}", "", "post", array("id" => "gAddPhotoForm")); + $group = $form->group("add_photo")->label( + t("Add Photo to %album_title", array("album_title" =>$parent->title))); + $group->input("title")->label(t("Title")); + $group->textarea("description")->label(t("Description")); + $group->input("name")->label(t("Filename")); + $group->upload("file")->label(t("File"))->rules("required|allow[jpg,png,gif,flv,mp4]"); + $group->hidden("type")->value("photo"); + $group->submit("")->value(t("Upload")); + $form->add_rules_from(ORM::factory("item")); + return $form; + } + + static function get_edit_form($photo) { + $form = new Forge("photos/$photo->id", "", "post", array("id" => "gEditPhotoForm")); + $form->hidden("_method")->value("put"); + $group = $form->group("edit_photo")->label(t("Edit Photo")); + $group->input("title")->label(t("Title"))->value($photo->title); + $group->textarea("description")->label(t("Description"))->value($photo->description); + $group->input("filename")->label(t("Filename"))->value($photo->name) + ->error_messages("conflict", t("There is already a file with this name")) + ->callback("item::validate_no_slashes") + ->error_messages("no_slashes", t("The photo name can't contain a \"/\"")) + ->callback("item::validate_no_trailing_period") + ->error_messages("no_trailing_period", t("The photo name can't end in \".\"")); + + $group->submit("")->value(t("Modify")); + $form->add_rules_from(ORM::factory("item")); + return $form; + } + + /** + * Return scaled width and height. + * + * @param integer $width + * @param integer $height + * @param integer $max the target size for the largest dimension + * @param string $format the output format using %d placeholders for width and height + */ + static function img_dimensions($width, $height, $max, $format="width=\"%d\" height=\"%d\"") { + if (!$width || !$height) { + return ""; + } + + if ($width > $height) { + $new_width = $max; + $new_height = (int)$max * ($height / $width); + } else { + $new_height = $max; + $new_width = (int)$max * ($width / $height); + } + return sprintf($format, $new_width, $new_height); + } +} diff --git a/modules/gallery/helpers/rest.php b/modules/gallery/helpers/rest.php new file mode 100644 index 00000000..a63b94c8 --- /dev/null +++ b/modules/gallery/helpers/rest.php @@ -0,0 +1,116 @@ +post("_method", $input->get("_method", request::method())))) { + case "put": return "put"; + case "delete": return "delete"; + default: return "post"; + } + } + } + + /** + * Choose an output format based on what the client prefers to accept. + * @return string "html", "xml" or "json" + */ + static function output_format() { + // Pick a format, but let it be overridden. + $input = Input::instance(); + $fmt = $input->get( + "_format", $input->post( + "_format", request::preferred_accept( + array("xhtml", "html", "xml", "json")))); + + // Some browsers (Chrome!) prefer xhtml over html, but we'll normalize this to html for now. + if ($fmt == "xhtml") { + $fmt = "html"; + } + return $fmt; + } + + /** + * Set HTTP response code. + * @param string Use one of the status code constants defined in this class. + */ + static function http_status($status_code) { + header("HTTP/1.1 " . $status_code); + } + + /** + * Set HTTP Location header. + * @param string URL + */ + static function http_location($url) { + header("Location: " . $url); + } + + /** + * Set HTTP Content-Type header. + * @param string content type + */ + static function http_content_type($type) { + header("Content-Type: " . $type); + } +} diff --git a/modules/gallery/helpers/site_status.php b/modules/gallery/helpers/site_status.php new file mode 100644 index 00000000..6d47e565 --- /dev/null +++ b/modules/gallery/helpers/site_status.php @@ -0,0 +1,132 @@ +where("key", $permanent_key) + ->find(); + if (!$message->loaded) { + $message->key = $permanent_key; + } + $message->severity = $severity; + $message->value = $msg; + $message->save(); + } + + /** + * Remove any permanent message by key. + * @param string $permanent_key + */ + static function clear($permanent_key) { + $message = ORM::factory("message")->where("key", $permanent_key)->find(); + if ($message->loaded) { + $message->delete(); + } + } + + /** + * Get any pending messages. There are two types of messages, transient and permanent. + * Permanent messages are used to let the admin know that there are pending administrative + * issues that need to be resolved. Transient ones are only displayed once. + * @return html text + */ + static function get() { + if (!user::active()->admin) { + return; + } + $buf = array(); + foreach (ORM::factory("message")->find_all() as $msg) { + $value = str_replace('__CSRF__', access::csrf_token(), $msg->value); + $buf[] = "
    • severity) . "\">$value
    • "; + } + + if ($buf) { + return "
        " . implode("", $buf) . "
      "; + } + } + + /** + * Convert a message severity to a CSS class + * @param integer $severity + * @return string + */ + static function severity_class($severity) { + switch($severity) { + case self::SUCCESS: + return "gSuccess"; + + case self::INFO: + return "gInfo"; + + case self::WARNING: + return "gWarning"; + + case self::ERROR: + return "gError"; + } + } +} diff --git a/modules/gallery/helpers/task.php b/modules/gallery/helpers/task.php new file mode 100644 index 00000000..a8a004ab --- /dev/null +++ b/modules/gallery/helpers/task.php @@ -0,0 +1,83 @@ +name}_task"; + if (method_exists($class_name, "available_tasks")) { + foreach (call_user_func(array($class_name, "available_tasks")) as $task) { + $tasks[$task->callback] = $task; + } + } + } + + return $tasks; + } + + static function create($task_def, $context) { + $task = ORM::factory("task"); + $task->callback = $task_def->callback; + $task->name = $task_def->name; + $task->percent_complete = 0; + $task->status = ""; + $task->state = "started"; + $task->owner_id = user::active()->id; + $task->context = serialize($context); + $task->save(); + + return $task; + } + + static function cancel($task_id) { + $task = ORM::factory("task", $task_id); + if (!$task->loaded) { + throw new Exception("@todo MISSING_TASK"); + } + $task->done = 1; + $task->state = "cancelled"; + $task->save(); + + return $task; + } + + static function remove($task_id) { + $task = ORM::factory("task", $task_id); + if ($task->loaded) { + $task->delete(); + } + } + + static function run($task_id) { + $task = ORM::factory("task", $task_id); + if (!$task->loaded) { + throw new Exception("@todo MISSING_TASK"); + } + + $task->state = "running"; + call_user_func_array($task->callback, array(&$task)); + $task->save(); + + return $task; + } +} \ No newline at end of file diff --git a/modules/gallery/helpers/theme.php b/modules/gallery/helpers/theme.php new file mode 100644 index 00000000..cbe224db --- /dev/null +++ b/modules/gallery/helpers/theme.php @@ -0,0 +1,61 @@ +"gThemeDetailsForm")); + $group = $form->group("edit_theme"); + $group->input("page_size")->label(t("Items per page"))->id("gPageSize") + ->rules("required|valid_digit") + ->value(module::get_var("core", "page_size")); + $group->input("thumb_size")->label(t("Thumbnail size (in pixels)"))->id("gThumbSize") + ->rules("required|valid_digit") + ->value(module::get_var("core", "thumb_size")); + $group->input("resize_size")->label(t("Resized image size (in pixels)"))->id("gResizeSize") + ->rules("required|valid_digit") + ->value(module::get_var("core", "resize_size")); + $group->textarea("header_text")->label(t("Header text"))->id("gHeaderText") + ->value(module::get_var("core", "header_text")); + $group->textarea("footer_text")->label(t("Footer text"))->id("gFooterText") + ->value(module::get_var("core", "footer_text")); + $group->submit("")->value(t("Save")); + return $form; + } +} + diff --git a/modules/gallery/helpers/xml.php b/modules/gallery/helpers/xml.php new file mode 100644 index 00000000..e734e90c --- /dev/null +++ b/modules/gallery/helpers/xml.php @@ -0,0 +1,35 @@ +\n"; + foreach ($array as $key => $value) { + if (is_array($value)) { + $xml .= xml::to_xml($value, array_slice($element_names, 1)); + } else if (is_object($value)) { + $xml .= xml::to_xml($value->as_array(), array_slice($element_names, 1)); + } else { + $xml .= "<$key>$value\n"; + } + } + $xml .= "\n"; + return $xml; + } +} diff --git a/modules/gallery/hooks/init_gallery.php b/modules/gallery/hooks/init_gallery.php new file mode 100644 index 00000000..2c36795a --- /dev/null +++ b/modules/gallery/hooks/init_gallery.php @@ -0,0 +1,44 @@ +post("g3sid", $input->get("g3sid"))) { + $_COOKIE["g3sid"] = $g3sid; +} + +if ($user_agent = $input->post("user_agent", $input->get("user_agent"))) { + Kohana::$user_agent = $user_agent; +} diff --git a/modules/gallery/images/gallery.png b/modules/gallery/images/gallery.png new file mode 100644 index 00000000..ca8e0e95 Binary files /dev/null and b/modules/gallery/images/gallery.png differ diff --git a/modules/gallery/images/gd.png b/modules/gallery/images/gd.png new file mode 100644 index 00000000..b341d71c Binary files /dev/null and b/modules/gallery/images/gd.png differ diff --git a/modules/gallery/images/graphicsmagick.png b/modules/gallery/images/graphicsmagick.png new file mode 100644 index 00000000..3d1d77e9 Binary files /dev/null and b/modules/gallery/images/graphicsmagick.png differ diff --git a/modules/gallery/images/imagemagick.jpg b/modules/gallery/images/imagemagick.jpg new file mode 100644 index 00000000..d83c4509 Binary files /dev/null and b/modules/gallery/images/imagemagick.jpg differ diff --git a/modules/gallery/js/albums_form_add.js b/modules/gallery/js/albums_form_add.js new file mode 100644 index 00000000..06a364f3 --- /dev/null +++ b/modules/gallery/js/albums_form_add.js @@ -0,0 +1,12 @@ +$("#gAddAlbumForm input[name=title]").change( + function() { + $("#gAddAlbumForm input[name=name]").attr( + "value", $("#gAddAlbumForm input[name=title]").attr("value"). + replace(/\s+/g, "_").replace(/\.+$/, "")); + }); +$("#gAddAlbumForm input[name=title]").keyup( + function() { + $("#gAddAlbumForm input[name=name]").attr( + "value", $("#gAddAlbumForm input[name=title]").attr("value"). + replace(/\s+/g, "_").replace(/\.+$/, "")); + }); diff --git a/modules/gallery/js/fullsize.js b/modules/gallery/js/fullsize.js new file mode 100644 index 00000000..7428adb5 --- /dev/null +++ b/modules/gallery/js/fullsize.js @@ -0,0 +1,78 @@ +/** + * @todo Move inline CSS out to external style sheet (theme style sheet) + */ +$(document).ready(function() { + $(".gFullSizeLink").click(function() { + var width = $(document).width(); + var height = $(document).height(); + + $("body").append('
      '); + + var image_size = _auto_fit(fullsize_detail.width, fullsize_detail.height); + + $("body").append('
      ' + + '
      '); + + $("#gFullsize").append(''); + $("#gFullsizeClose").click(function() { + $("#gFullsizeOverlay*").remove(); + $("#gFullsize").remove(); + }); + $(window).resize(function() { + $("#gFullsizeOverlay").width($(document).width()); + $("#gFullsizeOverlay").height($(document).height()); + image_size = _auto_fit(fullsize_detail.width, fullsize_detail.height); + $("#gFullsize").height(image_size.height); + $("#gFullsize").width(image_size.width); + $("#gFullsize").css("top", image_size.top); + $("#gFullsize").css("left", image_size.left); + $("#gFullSizeImage").height(image_size.height); + $("#gFullSizeImage").width(image_size.width); + }); + }); +}); + +/* + * Calculate the size of the image panel based on the size of the image and the size of the + * window. Scale the image so the entire panel fits in the view port. + */ +function _auto_fit(imageWidth, imageHeight) { + // ui-dialog gives a padding of 2 pixels + var windowWidth = $(window).width() - 10; + var windowHeight = $(window).height() - 10; + + /* If the width is greater then scale the image width first */ + if (imageWidth > windowWidth) { + var ratio = windowWidth / imageWidth; + imageWidth *= ratio; + imageHeight *= ratio; + } + /* after scaling the width, check that the height fits */ + if (imageHeight > windowHeight) { + var ratio = windowHeight / imageHeight; + imageWidth *= ratio; + imageHeight *= ratio; + } + + // handle the case where the calculation is almost zero (2.14e-14) + return { + top: ((windowHeight - imageHeight) / 2).toFixed(2), + left: ((windowWidth - imageWidth) / 2).toFixed(2), + width: imageWidth.toFixed(2), + height: imageHeight.toFixed(2) + }; +} diff --git a/modules/gallery/js/l10n_client.js b/modules/gallery/js/l10n_client.js new file mode 100644 index 00000000..f43671f1 --- /dev/null +++ b/modules/gallery/js/l10n_client.js @@ -0,0 +1,195 @@ +// Fork from Drupal's l10n_client module, originally written by: +// G‡bor Hojtsy http://drupal.org/user/4166 (original author) +// Young Hahn / Development Seed - http://developmentseed.org/ (friendly user interface) + +var Gallery = Gallery || { 'behaviors': {} }; + +Gallery.attachBehaviors = function(context) { + context = context || document; + // Execute all of them. + jQuery.each(Gallery.behaviors, + function() { + this(context); + }); +}; + +$(document).ready(function() { + Gallery.attachBehaviors(this); +}); + + +// Store all l10n_client related data + methods in its own object +jQuery.extend(Gallery, { + l10nClient: new (function() { + // Set "selected" string to unselected, i.e. -1 + this.selected = -1; + // Keybindings + this.keys = {'toggle':'ctrl+shift+s', 'clear': 'esc'}; // Keybindings + // Keybinding functions + this.key = function(pressed) { + switch(pressed) { + case 'toggle': + // Grab user-hilighted text & send it into the search filter + userSelection = window.getSelection ? window.getSelection() : document.getSelection ? document.getSelection() : document.selection.createRange().text; + userSelection = String(userSelection); + if(userSelection.length > 0) { + Gallery.l10nClient.filter(userSelection); + Gallery.l10nClient.toggle(1); + $('#l10n-client #gL10nSearch').focus(); + } else { + if($('#l10n-client').is('.hidden')) { + Gallery.l10nClient.toggle(1); + if(!$.browser.safari) { + $('#l10n-client #gL10nSearch').focus(); + } + } else { + Gallery.l10nClient.toggle(0); + } + } + break; + case 'clear': + this.filter(false); + break; + } + } + // Toggle the l10nclient + this.toggle = function(state) { + switch(state) { + case 1: + $('#l10n-client-string-select, #l10n-client-string-editor, #l10n-client .labels .label').show(); + $('#l10n-client').height('22em').removeClass('hidden'); + $('#l10n-client .labels .toggle').text('X'); + /* + * This CSS clashes with Gallery's CSS, probably due to + * YUI's grid / floats. + if(!$.browser.msie) { + $('body').css('border-bottom', '22em solid #fff'); + } + */ + $.cookie('Gallery_l10n_client', '1', {expires: 7, path: '/'}); + break; + case 0: + $('#l10n-client-string-select, #l10n-client-string-editor, #l10n-client .labels .label').hide(); + $('#l10n-client').height('2em').addClass('hidden'); + // TODO: Localize this message + $('#l10n-client .labels .toggle').text('Translate Text'); + /* + if(!$.browser.msie) { + $('body').css('border-bottom', '0px'); + } + */ + $.cookie('Gallery_l10n_client', '0', {expires: 7, path: '/'}); + break; + } + } + // Get a string from the DOM tree + this.getString = function(index, type) { + return l10n_client_data[index][type]; + } + // Set a string in the DOM tree + this.setString = function(index, data) { + l10n_client_data[index]['translation'] = data; + } + // Filter the the string list by a search string + this.filter = function(search) { + if(search == false || search == '') { + $('#l10n-client #l10n-search-filter-clear').focus(); + $('#l10n-client-string-select li').show(); + $('#l10n-client #gL10nSearch').val(''); + $('#l10n-client #gL10nSearch').focus(); + } else { + if(search.length > 0) { + $('#l10n-client-string-select li').hide(); + $('#l10n-client-string-select li:contains('+search+')').show(); + $('#l10n-client #gL10nSearch').val(search); + } + } + } + }) +}); + +// Attaches the localization editor behavior to all required fields. +Gallery.behaviors.l10nClient = function(context) { + + switch($.cookie('Gallery_l10n_client')) { + case '1': + Gallery.l10nClient.toggle(1); + break; + default: + Gallery.l10nClient.toggle(0); + break; + } + + // If the selection changes, copy string values to the source and target fields. + // Add class to indicate selected string in list widget. + $('#l10n-client-string-select li').click(function() { + $('#l10n-client-string-select li').removeClass('active'); + $(this).addClass('active'); + var index = $('#l10n-client-string-select li').index(this); + + $('#l10n-client-string-editor .source-text').text(Gallery.l10nClient.getString(index, 'source')); + $("#gL10nClientSaveForm input[name='l10n-message-source']").val(Gallery.l10nClient.getString(index, 'source')); + $('#gL10nClientSaveForm #l10n-edit-target').val(Gallery.l10nClient.getString(index, 'translation')); + + Gallery.l10nClient.selected = index; + }); + + // When l10n_client window is clicked, toggle based on current state. + $('#l10n-client .labels .toggle').click(function() { + if($('#l10n-client').is('.hidden')) { + Gallery.l10nClient.toggle(1); + } else { + Gallery.l10nClient.toggle(0); + } + }); + + // Register keybindings using jQuery hotkeys + // TODO: Either remove hotkeys code or add query.hotkeys.js. + if($.hotkeys) { + $.hotkeys.add(Gallery.l10nClient.keys['toggle'], function(){Gallery.l10nClient.key('toggle')}); + $.hotkeys.add(Gallery.l10nClient.keys['clear'], {target:'#l10n-client #gL10nSearch', type:'keyup'}, function(){Gallery.l10nClient.key('clear')}); + } + + // Custom listener for l10n_client livesearch + $('#l10n-client #gL10nSearch').keyup(function(key) { + Gallery.l10nClient.filter($('#l10n-client #gL10nSearch').val()); + }); + + // Clear search + $('#l10n-client #l10n-search-filter-clear').click(function() { + Gallery.l10nClient.filter(false); + return false; + }); + + // Send AJAX POST data on form submit. + $('#gL10nClientSaveForm').ajaxForm({ + dataType: "json", + success: function(data) { + // Store string in local js + Gallery.l10nClient.setString(Gallery.l10nClient.selected, $('#gL10nClientSaveForm #l10n-edit-target').val()); + + // Mark string as translated. + $('#l10n-client-string-select li').eq(Gallery.l10nClient.selected).removeClass('untranslated').removeClass('active').addClass('translated').text($('#gL10nClientSaveForm #l10n-edit-target').val()); + + // Empty input fields. + $('#l10n-client-string-editor .source-text').html(''); + $('#gL10nClientSaveForm #l10n-edit-target').val(''); + $("#gL10nClientSaveForm input[name='l10n-message-source']").val(''); + }, + error: function(xmlhttp) { + // TODO: Localize this message + alert('An HTTP error @status occured (or empty response).'.replace('@status', xmlhttp.status)); + } + }); + + + // Copy source text to translation field on button click. + $('#gL10nClientSaveForm #l10n-edit-copy').click(function() { + $('#gL10nClientSaveForm #l10n-edit-target').val($('#l10n-client-string-editor .source-text').text()); + }); + + // Clear translation field on button click. + $('#gL10nClientSaveForm #l10n-edit-clear').click(function() { + $('#gL10nClientSaveForm #l10n-edit-target').val(''); + }); +}; diff --git a/modules/gallery/js/quick.js b/modules/gallery/js/quick.js new file mode 100644 index 00000000..e7f35cea --- /dev/null +++ b/modules/gallery/js/quick.js @@ -0,0 +1,95 @@ +$(document).ready(function() { + if ($("#gAlbumGrid").length) { + // @todo Add quick edit pane for album (meta, move, permissions, delete) + $(".gItem").hover(show_quick, function() {}); + } + if ($("#gPhoto").length) { + $("#gPhoto").hover(show_quick, function() {}); + } +}); + +var show_quick = function() { + var cont = $(this); + var quick = $(this).find(".gQuick"); + $("#gQuickPane").remove(); + cont.append("
      "); + var img = cont.find(".gThumbnail,.gResize"); + var pos = cont.position(); + $("#gQuickPane").css({ + "position": "absolute", + "top": pos.top, + "left": pos.left, + "text-align": "center", + "width": cont.innerWidth() + 1, + "height": "auto" + }).hide(); + cont.hover(function() {}, hide_quick); + $.get( + quick.attr("href"), + {}, + function(data, textStatus) { + $("#gQuickPane").html(data).slideDown("fast"); + $(".ui-state-default").hover( + function(){ + $(this).addClass("ui-state-hover"); + }, + function(){ + $(this).removeClass("ui-state-hover"); + } + ); + $("#gQuickPane a:not(.options)").click(function(e) { + e.preventDefault(); + if ($(this).attr("id") == "gQuickDelete" && + !confirm($(this).attr("ref"))) { + return; + } + quick_do(cont, $(this), img); + }); + $("#gQuickPane a.options").click(function(e) { + e.preventDefault(); + $("#gQuickPaneOptions").slideToggle("fast"); + }); + } + ); +}; + +var quick_do = function(cont, pane, img) { + if (pane.hasClass("ui-state-disabled")) { + return false; + } + if (pane.hasClass("gDialogLink")) { + openDialog(pane, function() { window.location.reload(); }); + } else { + img.css("opacity", "0.1"); + cont.addClass("gLoadingLarge"); + $.ajax({ + type: "GET", + url: pane.attr("href"), + dataType: "json", + success: function(data) { + img.css("opacity", "1"); + cont.removeClass("gLoadingLarge"); + if (data.src) { + img.attr("width", data.width); + img.attr("height", data.height); + img.attr("src", data.src); + if (data.height > data.width) { + img.css("margin-top", -32); + } else { + img.css("margin-top", 0); + } + } else if (data.location) { + window.location = data.location; + } else if (data.reload) { + window.location.reload(); + } + } + }); + } + return false; +}; + +var hide_quick = function() { + $("#gQuickPane").remove(); +}; + diff --git a/modules/gallery/libraries/Admin_View.php b/modules/gallery/libraries/Admin_View.php new file mode 100644 index 00000000..acc3f8ec --- /dev/null +++ b/modules/gallery/libraries/Admin_View.php @@ -0,0 +1,126 @@ +theme_name = module::get_var("core", "active_admin_theme"); + if (user::active()->admin) { + $this->theme_name = Input::instance()->get("theme", $this->theme_name); + } + $this->sidebar = ""; + $this->set_global("theme", $this); + $this->set_global("user", user::active()); + } + + public function url($path, $absolute_url=false) { + $arg = "themes/{$this->theme_name}/$path"; + return $absolute_url ? url::abs_file($arg) : url::file($arg); + } + + public function display($page_name, $view_class="View") { + return new $view_class($page_name); + } + + public function admin_menu() { + $menu = Menu::factory("root"); + core_menu::admin($menu, $this); + + foreach (module::active() as $module) { + if ($module->name == "core") { + continue; + } + $class = "{$module->name}_menu"; + if (method_exists($class, "admin")) { + call_user_func_array(array($class, "admin"), array(&$menu, $this)); + } + } + + print $menu; + } + + /** + * Print out any site wide status information. + */ + public function site_status() { + return site_status::get(); + } + + /** + * Print out any messages waiting for this user. + */ + public function messages() { + return message::get(); + } + + /** + * Handle all theme functions that insert module content. + */ + public function __call($function, $args) { + switch ($function) { + case "admin_credits"; + case "admin_footer": + case "admin_header_top": + case "admin_header_bottom": + case "admin_page_bottom": + case "admin_page_top": + case "admin_head": + $blocks = array(); + foreach (module::active() as $module) { + $helper_class = "{$module->name}_theme"; + if (method_exists($helper_class, $function)) { + $blocks[] = call_user_func_array( + array($helper_class, $function), + array_merge(array($this), $args)); + } + } + + if (Session::instance()->get("debug")) { + if ($function != "admin_head") { + array_unshift( + $blocks, "
      " . + "
      $function
      "); + $blocks[] = "
      "; + } + } + + return implode("\n", $blocks); + + default: + throw new Exception("@todo UNKNOWN_THEME_FUNCTION: $function"); + } + } +} \ No newline at end of file diff --git a/modules/gallery/libraries/Block.php b/modules/gallery/libraries/Block.php new file mode 100644 index 00000000..6fe679f1 --- /dev/null +++ b/modules/gallery/libraries/Block.php @@ -0,0 +1,30 @@ +__toString(); + } +} diff --git a/modules/gallery/libraries/I18n.php b/modules/gallery/libraries/I18n.php new file mode 100644 index 00000000..c936be88 --- /dev/null +++ b/modules/gallery/libraries/I18n.php @@ -0,0 +1,410 @@ +translate($message, $options); +} + +/** + * Translates a localizable message with plural forms. + * @param $singular String The message to be translated. E.g. "There is one album." + * @param $plural String The plural message to be translated. E.g. + * "There are %count albums." + * @param $count Number The number which is inserted for the %count placeholder and + * which is used to select the proper plural form ($singular or $plural). + * @param $options array (optional) Options array for key value pairs which are used + * for pluralization and interpolation. Special key: "locale" to override the + * currently configured locale. + * @return String The translated message string. + */ +function t2($singular, $plural, $count, $options=array()) { + return I18n::instance()->translate(array("one" => $singular, "other" => $plural), + array_merge($options, array("count" => $count))); +} + +class I18n_Core { + private static $_instance; + private $_config = array(); + private $_call_log = array(); + private $_cache = array(); + + private function __construct($config) { + $this->_config = $config; + $this->locale($config['default_locale']); + } + + public static function instance($config=null) { + if (self::$_instance == NULL || isset($config)) { + $config = isset($config) ? $config : Kohana::config('locale'); + if (empty($config['default_locale'])) { + $config['default_locale'] = module::get_var('core', 'default_locale'); + } + self::$_instance = new I18n_Core($config); + } + + return self::$_instance; + } + + public function locale($locale=null) { + if ($locale) { + $this->_config['default_locale'] = $locale; + // Attempt to set PHP's locale as well (for number formatting, collation, etc.) + // TODO: See G2 for better fallack code. + $locale_prefs = array($locale); + $locale_prefs[] = 'en_US'; + setlocale(LC_ALL, $locale_prefs); + } + return $this->_config['default_locale']; + } + + /** + * Translates a localizable message. + * @param $message String|array The message to be translated. E.g. "Hello world" + * or array("one" => "One album", "other" => "%count albums") + * @param $options array (optional) Options array for key value pairs which are used + * for pluralization and interpolation. Special keys are "count" and "locale", + * the latter to override the currently configured locale. + * @return String The translated message string. + */ + public function translate($message, $options=array()) { + $locale = empty($options['locale']) ? $this->_config['default_locale'] : $options['locale']; + $count = isset($options['count']) ? $options['count'] : null; + $values = $options; + unset($values['locale']); + $this->log($message, $options); + + $entry = $this->lookup($locale, $message); + + if (null === $entry) { + // Default to the root locale. + $entry = $message; + $locale = $this->_config['root_locale']; + } + + $entry = $this->pluralize($locale, $entry, $count); + + $entry = $this->interpolate($locale, $entry, $values); + + return $entry; + } + + private function lookup($locale, $message) { + if (!isset($this->_cache[$locale])) { + $this->_cache[$locale] = array(); + // TODO: Load data from locale file instead of the DB. + foreach (Database::instance() + ->select("key", "translation") + ->from("incoming_translations") + ->where(array("locale" => $locale)) + ->get() + ->as_array() as $row) { + $this->_cache[$locale][$row->key] = unserialize($row->translation); + } + + // Override incoming with outgoing... + foreach (Database::instance() + ->select("key", "translation") + ->from("outgoing_translations") + ->where(array("locale" => $locale)) + ->get() + ->as_array() as $row) { + $this->_cache[$locale][$row->key] = unserialize($row->translation); + } + } + + $key = self::get_message_key($message); + + if (isset($this->_cache[$locale][$key])) { + return $this->_cache[$locale][$key]; + } else { + return null; + } + } + + public function has_translation($message, $options=null) { + $locale = empty($options['locale']) ? $this->_config['default_locale'] : $options['locale']; + $count = empty($options['count']) ? null : $options['count']; + $values = $options; + unset($values['locale']); + $this->log($message, $options); + + $entry = $this->lookup($locale, $message); + + if (null === $entry) { + return false; + } else if (!is_array($entry)) { + return $entry !== ''; + } else { + $plural_key = self::get_plural_key($locale, $count); + return isset($entry[$plural_key]) + && $entry[$plural_key] !== null + && $entry[$plural_key] !== ''; + } + } + + public static function get_message_key($message) { + $as_string = is_array($message) ? implode('|', $message) : $message; + return md5($as_string); + } + + private function interpolate($locale, $string, $values) { + // TODO: Handle locale specific number formatting. + + // Replace x_y before replacing x. + krsort($values, SORT_STRING); + + $keys = array(); + foreach (array_keys($values) as $key) { + $keys[] = "%$key"; + } + return str_replace($keys, array_values($values), $string); + } + + private function pluralize($locale, $entry, $count) { + if (!is_array($entry)) { + return $entry; + } + + $plural_key = self::get_plural_key($locale, $count); + if (!isset($entry[$plural_key])) { + // Fallback to the default plural form. + $plural_key = 'other'; + } + + if (isset($entry[$plural_key])) { + return $entry[$plural_key]; + } else { + // Fallback to just any plural form. + list ($plural_key, $string) = each($entry); + return $string; + } + } + + private function log($message, $options) { + $key = self::get_message_key($message); + isset($this->_call_log[$key]) or $this->_call_log[$key] = array($message, $options); + } + + public function call_log() { + return $this->_call_log; + } + + private static function get_plural_key($locale, $count) { + $parts = explode('_', $locale); + $language = $parts[0]; + + // Data from CLDR 1.6 (http://unicode.org/cldr/data/common/supplemental/plurals.xml). + // Docs: http://www.unicode.org/cldr/data/charts/supplemental/language_plural_rules.html + switch ($language) { + case 'az': + case 'fa': + case 'hu': + case 'ja': + case 'ko': + case 'my': + case 'to': + case 'tr': + case 'vi': + case 'yo': + case 'zh': + case 'bo': + case 'dz': + case 'id': + case 'jv': + case 'ka': + case 'km': + case 'kn': + case 'ms': + case 'th': + return 'other'; + + case 'ar': + if ($count == 0) { + return 'zero'; + } else if ($count == 1) { + return 'one'; + } else if ($count == 2) { + return 'two'; + } else if (is_int($count) && ($i = $count % 100) >= 3 && $i <= 10) { + return 'few'; + } else if (is_int($count) && ($i = $count % 100) >= 11 && $i <= 99) { + return 'many'; + } else { + return 'other'; + } + + case 'pt': + case 'am': + case 'bh': + case 'fil': + case 'tl': + case 'guw': + case 'hi': + case 'ln': + case 'mg': + case 'nso': + case 'ti': + case 'wa': + if ($count == 0 || $count == 1) { + return 'one'; + } else { + return 'other'; + } + + case 'fr': + if ($count >= 0 and $count < 2) { + return 'one'; + } else { + return 'other'; + } + + case 'lv': + if ($count == 0) { + return 'zero'; + } else if ($count % 10 == 1 && $count % 100 != 11) { + return 'one'; + } else { + return 'other'; + } + + case 'ga': + case 'se': + case 'sma': + case 'smi': + case 'smj': + case 'smn': + case 'sms': + if ($count == 1) { + return 'one'; + } else if ($count == 2) { + return 'two'; + } else { + return 'other'; + } + + case 'ro': + case 'mo': + if ($count == 1) { + return 'one'; + } else if (is_int($count) && $count == 0 && ($i = $count % 100) >= 1 && $i <= 19) { + return 'few'; + } else { + return 'other'; + } + + case 'lt': + if (is_int($count) && $count % 10 == 1 && $count % 100 != 11) { + return 'one'; + } else if (is_int($count) && ($i = $count % 10) >= 2 && $i <= 9 && ($i = $count % 100) < 11 && $i > 19) { + return 'few'; + } else { + return 'other'; + } + + case 'hr': + case 'ru': + case 'sr': + case 'uk': + case 'be': + case 'bs': + case 'sh': + if (is_int($count) && $count % 10 == 1 && $count % 100 != 11) { + return 'one'; + } else if (is_int($count) && ($i = $count % 10) >= 2 && $i <= 4 && ($i = $count % 100) < 12 && $i > 14) { + return 'few'; + } else if (is_int($count) && ($count % 10 == 0 || (($i = $count % 10) >= 5 && $i <= 9) || (($i = $count % 100) >= 11 && $i <= 14))) { + return 'many'; + } else { + return 'other'; + } + + case 'cs': + case 'sk': + if ($count == 1) { + return 'one'; + } else if (is_int($count) && $count >= 2 && $count <= 4) { + return 'few'; + } else { + return 'other'; + } + + case 'pl': + if ($count == 1) { + return 'one'; + } else if (is_int($count) && ($i = $count % 10) >= 2 && $i <= 4 && + ($i = $count % 100) < 12 && $i > 14 && ($i = $count % 100) < 22 && $i > 24) { + return 'few'; + } else { + return 'other'; + } + + case 'sl': + if ($count % 100 == 1) { + return 'one'; + } else if ($count % 100 == 2) { + return 'two'; + } else if (is_int($count) && ($i = $count % 100) >= 3 && $i <= 4) { + return 'few'; + } else { + return 'other'; + } + + case 'mt': + if ($count == 1) { + return 'one'; + } else if ($count == 0 || is_int($count) && ($i = $count % 100) >= 2 && $i <= 10) { + return 'few'; + } else if (is_int($count) && ($i = $count % 100) >= 11 && $i <= 19) { + return 'many'; + } else { + return 'other'; + } + + case 'mk': + if ($count % 10 == 1) { + return 'one'; + } else { + return 'other'; + } + + case 'cy': + if ($count == 1) { + return 'one'; + } else if ($count == 2) { + return 'two'; + } else if ($count == 8 || $count == 11) { + return 'many'; + } else { + return 'other'; + } + + default: // en, de, etc. + return $count == 1 ? 'one' : 'other'; + } + } +} \ No newline at end of file diff --git a/modules/gallery/libraries/MY_Database.php b/modules/gallery/libraries/MY_Database.php new file mode 100644 index 00000000..c56f16e8 --- /dev/null +++ b/modules/gallery/libraries/MY_Database.php @@ -0,0 +1,92 @@ +where[] = "("; + return $this; + } + + public function close_paren() { + // Search backwards for the last opening paren and resolve it + $i = count($this->where) - 1; + $this->where[$i] .= ")"; + while (--$i >= 0) { + if ($this->where[$i] == "(") { + // Remove the paren from the where clauses, and add it to the right of the operator of the + // next where clause. If removing the paren makes the next where clause the first element + // in the where list, then the operator shouldn't be there. It's there because we + // calculate whether or not we need an operator based on the number of where clauses, and + // the open paren seems like a where clause even though it isn't. + array_splice($this->where, $i, 1); + $this->where[$i] = preg_replace("/^(AND|OR) /", $i ? "\\1 (" : "(", $this->where[$i]); + return $this; + } + } + + throw new Kohana_Database_Exception('database.missing_open_paren'); + } + + /** + * Parse the query string and convert any strings of the form `\([a-zA-Z0-9_]*?)\] + * table prefix . $1 + */ + public function query($sql = '') { + if (!empty($sql)) { + $sql = $this->add_table_prefixes($sql); + } + return parent::query($sql); + } + + public function add_table_prefixes($sql) { + $prefix = $this->config["table_prefix"]; + if (strpos($sql, "SHOW TABLES") === 0) { + /* + * Don't ignore "show tables", otherwise we could have a infinite + * @todo this may have to be changed if we support more than mysql + */ + return $sql; + } else if (strpos($sql, "CREATE TABLE") === 0) { + // Creating a new table add it to the table cache. + $open_brace = strpos($sql, "{") + 1; + $close_brace = strpos($sql, "}", $open_brace); + $name = substr($sql, $open_brace, $close_brace - $open_brace); + $this->_table_names["{{$name}}"] = "{$prefix}$name"; + } + + if (!isset($this->_table_names)) { + // This should only run once on the first query + $this->_table_names =array(); + $len = strlen($prefix); + foreach($this->list_tables() as $table_name) { + if ($len > 0) { + $naked_name = strpos($table_name, $prefix) !== 0 ? + $table_name : substr($table_name, $len); + } else { + $naked_name = $table_name; + } + $this->_table_names["{{$naked_name}}"] = $table_name; + } + } + + return empty($this->_table_names) ? $sql : strtr($sql, $this->_table_names); + } +} \ No newline at end of file diff --git a/modules/gallery/libraries/MY_Forge.php b/modules/gallery/libraries/MY_Forge.php new file mode 100644 index 00000000..17d0465b --- /dev/null +++ b/modules/gallery/libraries/MY_Forge.php @@ -0,0 +1,59 @@ +hidden("csrf")->value(""); + } + /** + * Use our own template + */ + public function render($template="form.html", $custom=false) { + $this->hidden["csrf"]->value(access::csrf_token()); + return parent::render($template, $custom); + } + + /** + * Associate validation rules defined in the model with this form. + */ + public function add_rules_from($model) { + foreach ($this->inputs as $name => $input) { + if (isset($input->inputs)) { + $input->add_rules_from($model); + } + if (isset($model->rules[$name])) { + $input->rules($model->rules[$name]); + } + } + } + + /** + * Validate our CSRF value as a mandatory part of all form validation. + */ + public function validate() { + $status = parent::validate(); + access::verify_csrf(); + return $status; + } +} \ No newline at end of file diff --git a/modules/gallery/libraries/MY_ORM.php b/modules/gallery/libraries/MY_ORM.php new file mode 100644 index 00000000..fb2f80a7 --- /dev/null +++ b/modules/gallery/libraries/MY_ORM.php @@ -0,0 +1,46 @@ +db->open_paren(); + return $this; + } + + public function close_paren() { + $this->db->close_paren(); + return $this; + } +} + +/** + * Slide this in here for convenience. We won't ever be overloading ORM_Iterator without ORM. + */ +class ORM_Iterator extends ORM_Iterator_Core { + /** + * Cache the result row + */ + public function current() { + $row = parent::current(); + if (is_object($row)) { + model_cache::set($row); + } + return $row; + } +} \ No newline at end of file diff --git a/modules/gallery/libraries/MY_Pagination.php b/modules/gallery/libraries/MY_Pagination.php new file mode 100644 index 00000000..d06a974f --- /dev/null +++ b/modules/gallery/libraries/MY_Pagination.php @@ -0,0 +1,35 @@ +auto_hide === TRUE AND $this->total_pages <= 1) { + return ""; + } + + if ($style === NULL) { + // Use default style + $style = $this->style; + } + + // Return rendered pagination view + return View::factory("pager.html", get_object_vars($this))->render(); + } +} diff --git a/modules/gallery/libraries/MY_View.php b/modules/gallery/libraries/MY_View.php new file mode 100644 index 00000000..836d1087 --- /dev/null +++ b/modules/gallery/libraries/MY_View.php @@ -0,0 +1,46 @@ +set_global("csrf", access::csrf_token()); + } + + /** + * Override View_Core::render so that we trap errors stemming from bad PHP includes and show a + * visible stack trace to help developers. + * + * @see View_Core::render + */ + public function render($print=false, $renderer=false) { + try { + return parent::render($print, $renderer); + } catch (Exception $e) { + Kohana::Log('error', $e->getTraceAsString()); + Kohana::Log('debug', $e->getMessage()); + return ""; + } + } +} diff --git a/modules/gallery/libraries/Menu.php b/modules/gallery/libraries/Menu.php new file mode 100644 index 00000000..d19d8b1e --- /dev/null +++ b/modules/gallery/libraries/Menu.php @@ -0,0 +1,187 @@ +id = $id; + return $this; + } + + /** + * Set the label + * @chainable + */ + public function label($label) { + $this->label = $label; + return $this; + } + + /** + * Set the url + * @chainable + */ + public function url($url) { + $this->url = $url; + return $this; + } + + /** + * Set the css id + * @chainable + */ + public function css_id($css_id) { + $this->css_id = $css_id; + return $this; + } + + /** + * Set the css class + * @chainable + */ + public function css_class($css_class) { + $this->css_class = $css_class; + return $this; + } + +} + +/** + * Menu element that provides a link to a new page. + */ +class Menu_Element_Link extends Menu_Element { + public function __toString() { + if (isset($this->css_id) && !empty($this->css_id)) { + $css_id = " id=\"$this->css_id\""; + } else { + $css_id = ""; + } + if (isset($this->css_class) && !empty($this->css_class)) { + $css_class = " $this->css_class"; + } else { + $css_class = ""; + } + return "
    • url\" " . + "title=\"$this->label\">$this->label
    • "; + } +} + +/** + * Menu element that provides a pop-up dialog + */ +class Menu_Element_Dialog extends Menu_Element { + public function __toString() { + if (isset($this->css_id) && !empty($this->css_id)) { + $css_id = " id=\"$this->css_id\""; + } else { + $css_id = ""; + } + if (isset($this->css_class) && !empty($this->css_class)) { + $css_class = " $this->css_class"; + } else { + $css_class = ""; + } + return "
    • url\" " . + "title=\"$this->label\">$this->label
    • "; + } +} + +/** + * Root menu or submenu + */ +class Menu_Core extends Menu_Element { + public $elements; + public $is_root = false; + + /** + * Return an instance of a Menu_Element + * @chainable + */ + public static function factory($type) { + switch($type) { + case "link": + return new Menu_Element_Link(); + + case "dialog": + return new Menu_Element_Dialog(); + + case "root": + $menu = new Menu(); + $menu->is_root = true; + return $menu; + + case "submenu": + return new Menu(); + + default: + throw Exception("@todo UNKNOWN_MENU_TYPE"); + } + } + + public function __construct() { + $this->elements = array(); + } + + /** + * Add a new element to this menu + */ + public function append($menu_element) { + $this->elements[$menu_element->id] = $menu_element; + return $this; + } + + /** + * Add a new element to this menu + */ + public function add_after($target_id, $new_menu_element) { + $copy = array(); + foreach ($this->elements as $id => $menu_element) { + $copy[$id] = $menu_element; + if ($id == $target_id) { + $copy[$new_menu_element->id] = $new_menu_element; + } + } + $this->elements = $copy; + return $this; + } + + /** + * Retrieve a Menu_Element by id + */ + public function get($id) { + return $this->elements[$id]; + } + + public function __toString() { + $html = $this->is_root ? "
        " : + "
      • $this->label
          "; + $html .= implode("\n", $this->elements); + $html .= $this->is_root ? "
        " : "
      "; + return $html; + } +} diff --git a/modules/gallery/libraries/ORM_MPTT.php b/modules/gallery/libraries/ORM_MPTT.php new file mode 100644 index 00000000..46280d95 --- /dev/null +++ b/modules/gallery/libraries/ORM_MPTT.php @@ -0,0 +1,307 @@ +model_name = inflector::singular($this->table_name); + } + + /** + * Add this node as a child of the parent provided. + * + * @chainable + * @param integer $parent_id the id of the parent node + * @return ORM + */ + function add_to_parent($parent) { + $this->lock(); + + try { + // Make a hole in the parent for this new item + $this->db->query( + "UPDATE {{$this->table_name}} SET `left` = `left` + 2 WHERE `left` >= {$parent->right}"); + $this->db->query( + "UPDATE {{$this->table_name}} SET `right` = `right` + 2 WHERE `right` >= {$parent->right}"); + $parent->right += 2; + + // Insert this item into the hole + $this->left = $parent->right - 2; + $this->right = $parent->right - 1; + $this->parent_id = $parent->id; + $this->level = $parent->level + 1; + $this->save(); + $parent->reload(); + } catch (Exception $e) { + $this->unlock(); + throw $e; + } + + $this->unlock(); + return $this; + } + + /** + * Delete this node and all of its children. + */ + public function delete() { + $children = $this->children(); + if ($children) { + foreach ($this->children() as $item) { + // Deleting children affects the MPTT tree, so we have to reload each child before we + // delete it so that we have current left/right pointers. This is inefficient. + // @todo load each child once, not twice. + $item->reload()->delete(); + } + + // Deleting children has affected this item + $this->reload(); + } + + $this->lock(); + try { + $this->db->query( + "UPDATE {{$this->table_name}} SET `left` = `left` - 2 WHERE `left` > {$this->right}"); + $this->db->query( + "UPDATE {{$this->table_name}} SET `right` = `right` - 2 WHERE `right` > {$this->right}"); + } catch (Exception $e) { + $this->unlock(); + throw $e; + } + + $this->unlock(); + parent::delete(); + } + + /** + * Return true if the target is descendant of this item. + * @param ORM $target + * @return boolean + */ + function is_descendant($target) { + return ($this->left <= $target->left && $this->right >= $target->right); + } + + /** + * Return the parent of this node + * + * @return ORM + */ + function parent() { + if (!$this->parent_id) { + return null; + } + return model_cache::get($this->model_name, $this->parent_id); + } + + /** + * Return all the parents of this node, in order from root to this node's immediate parent. + * + * @return array ORM + */ + function parents() { + return $this + ->where("`left` <= {$this->left}") + ->where("`right` >= {$this->right}") + ->where("id <> {$this->id}") + ->orderby("left", "ASC") + ->find_all(); + } + + /** + * Return all of the children of this node, ordered by id. + * + * @chainable + * @param integer SQL limit + * @param integer SQL offset + * @param array orderby + * @return array ORM + */ + function children($limit=null, $offset=0, $orderby=null) { + $this->where("parent_id", $this->id); + if (empty($orderby)) { + $this->orderby("id", "ASC"); + } else { + $this->orderby($orderby); + } + return $this->find_all($limit, $offset); + } + + /** + * Return all of the children of this node, ordered by id. + * + * @chainable + * @param integer SQL limit + * @param integer SQL offset + * @return array ORM + */ + function children_count() { + return $this->where("parent_id", $this->id)->count_all(); + } + + /** + * Return all of the children of the specified type, ordered by id. + * + * @param integer SQL limit + * @param integer SQL offset + * @param string type to return + * @param array orderby + * @return object ORM_Iterator + */ + function descendants($limit=null, $offset=0, $type=null, $orderby=null) { + $this->where("left >", $this->left) + ->where("right <=", $this->right); + if ($type) { + $this->where("type", $type); + } + + if (empty($orderby)) { + $this->orderby("id", "ASC"); + } else { + $this->orderby($orderby); + } + + return $this->find_all($limit, $offset); + } + + /** + * Return the count of all the children of the specified type. + * + * @param string type to count + * @return integer child count + */ + function descendants_count($type=null) { + $this->where("left >", $this->left) + ->where("right <=", $this->right); + if ($type) { + $this->where("type", $type); + } + return $this->count_all(); + } + + /** + * Move this item to the specified target. + * + * @chainable + * @param Item_Model $target Target node + * @return ORM_MTPP + */ + function move_to($target) { + if ($this->left <= $target->left && + $this->right >= $target->right) { + throw new Exception("@todo INVALID_TARGET can't move item inside itself"); + } + + $number_to_move = (int)(($this->right - $this->left) / 2 + 1); + $size_of_hole = $number_to_move * 2; + $original_left = $this->left; + $original_right = $this->right; + $target_right = $target->right; + $level_delta = ($target->level + 1) - $this->level; + + $this->lock(); + try { + if ($level_delta) { + // Update the levels for the to-be-moved items + $this->db->query( + "UPDATE {{$this->table_name}} SET `level` = `level` + $level_delta" . + " WHERE `left` >= $original_left AND `right` <= $original_right"); + } + + // Make a hole in the target for the move + $target->db->query( + "UPDATE {{$this->table_name}} SET `left` = `left` + $size_of_hole" . + " WHERE `left` >= $target_right"); + $target->db->query( + "UPDATE {{$this->table_name}} SET `right` = `right` + $size_of_hole" . + " WHERE `right` >= $target_right"); + + // Change the parent. + $this->db->query( + "UPDATE {{$this->table_name}} SET `parent_id` = {$target->id}" . + " WHERE `id` = {$this->id}"); + + // If the source is to the right of the target then we just adjusted its left and right above. + $left = $original_left; + $right = $original_right; + if ($original_left > $target_right) { + $left += $size_of_hole; + $right += $size_of_hole; + } + + $new_offset = $target->right - $left; + $this->db->query( + "UPDATE {{$this->table_name}}" . + " SET `left` = `left` + $new_offset," . + " `right` = `right` + $new_offset" . + " WHERE `left` >= $left" . + " AND `right` <= $right"); + + // Close the hole in the source's parent after the move + $this->db->query( + "UPDATE {{$this->table_name}} SET `left` = `left` - $size_of_hole" . + " WHERE `left` > $right"); + $this->db->query( + "UPDATE {{$this->table_name}} SET `right` = `right` - $size_of_hole" . + " WHERE `right` > $right"); + } catch (Exception $e) { + $this->unlock(); + throw $e; + } + + $this->unlock(); + + // Lets reload to get the changes. + $this->reload(); + return $this; + } + + /** + * Lock the tree to prevent concurrent modification. + */ + protected function lock() { + $result = $this->db->query("SELECT GET_LOCK('{$this->table_name}', 1) AS l")->current(); + if (empty($result->l)) { + throw new Exception("@todo UNABLE_TO_LOCK_EXCEPTION"); + } + } + + /** + * Unlock the tree. + */ + protected function unlock() { + $this->db->query("SELECT RELEASE_LOCK('{$this->table_name}')"); + } +} diff --git a/modules/gallery/libraries/Sendmail.php b/modules/gallery/libraries/Sendmail.php new file mode 100644 index 00000000..90998457 --- /dev/null +++ b/modules/gallery/libraries/Sendmail.php @@ -0,0 +1,97 @@ +headers = array(); + $config = Kohana::config("sendmail"); + foreach ($config as $key => $value) { + $this->$key($value); + } + } + + public function __get($key) { + return null; + } + + public function __call($key, $value) { + switch ($key) { + case "to": + $this->to = is_array($value[0]) ? $value[0] : array($value[0]); + break; + case "header": + if (count($value) != 2) { + throw new Exception("@todo INVALID_HEADER_PARAMETERS"); + } + $this->headers[$value[0]] = $value[1]; + break; + case "from": + $this->headers["From"] = $value[0]; + break; + case "reply_to": + $this->headers["Reply-To"] = $value[0]; + break; + default: + $this->$key = $value[0]; + } + return $this; + } + + public function send() { + if (empty($this->to)) { + throw new Exception("@todo TO_IS_REQUIRED_FOR_MAIL"); + } + $to = implode(", ", $this->to); + $headers = array(); + foreach ($this->headers as $key => $value) { + $key = ucfirst($key); + $headers[] = "$key: $value"; + } + + // The docs say headers should be separated by \r\n, but occasionaly that doesn't work and you + // need to use a single \n. This can be set in config/sendmail.php + $headers = implode($this->header_separator, $headers); + $message = wordwrap($this->message, $this->line_length, "\n"); + if (!$this->mail($to, $this->subject, $message, $headers)) { + Kohana::log("error", wordwrap("Sending mail failed:\nTo: $to\n $this->subject\n" . + "Headers: $headers\n $this->message")); + throw new Exception("@todo SEND_MAIL_FAILED"); + } + return $this; + } + + public function mail($to, $subject, $message, $headers) { + return mail($to, $subject, $message, $headers); + } +} diff --git a/modules/gallery/libraries/Task_Definition.php b/modules/gallery/libraries/Task_Definition.php new file mode 100644 index 00000000..8d9c5922 --- /dev/null +++ b/modules/gallery/libraries/Task_Definition.php @@ -0,0 +1,50 @@ +callback = $callback; + return $this; + } + + function description($description) { + $this->description = $description; + return $this; + } + + function name($name) { + $this->name = $name; + return $this; + } + + function severity($severity) { + $this->severity = $severity; + return $this; + } +} diff --git a/modules/gallery/libraries/Theme_View.php b/modules/gallery/libraries/Theme_View.php new file mode 100644 index 00000000..b5b97666 --- /dev/null +++ b/modules/gallery/libraries/Theme_View.php @@ -0,0 +1,221 @@ +theme_name = module::get_var("core", "active_site_theme"); + if (user::active()->admin) { + $this->theme_name = Input::instance()->get("theme", $this->theme_name); + } + $this->item = null; + $this->tag = null; + $this->set_global("theme", $this); + $this->set_global("user", user::active()); + $this->set_global("page_type", $page_type); + if ($page_type == "album") { + $this->set_global("thumb_proportion", $this->thumb_proportion()); + } + + $maintenance_mode = Kohana::config("core.maintenance_mode", false, false); + if ($maintenance_mode) { + message::warning(t("This site is currently in maintenance mode")); + } + } + + /** + * Proportion of the current thumb_size's to default + * @return int + */ + public function thumb_proportion() { + // @TODO change the 200 to a theme supplied value when and if we come up with an + // API to allow the theme to set defaults. + return module::get_var("core", "thumb_size", 200) / 200; + } + + public function url($path, $absolute_url=false) { + $arg = "themes/{$this->theme_name}/$path"; + return $absolute_url ? url::abs_file($arg) : url::file($arg); + } + + public function item() { + return $this->item; + } + + public function tag() { + return $this->tag; + } + + public function page_type() { + return $this->page_type; + } + + public function display($page_name, $view_class="View") { + return new $view_class($page_name); + } + + public function site_menu() { + $menu = Menu::factory("root"); + if ($this->page_type != "login") { + core_menu::site($menu, $this); + + foreach (module::active() as $module) { + if ($module->name == "core") { + continue; + } + $class = "{$module->name}_menu"; + if (method_exists($class, "site")) { + call_user_func_array(array($class, "site"), array(&$menu, $this)); + } + } + } + + print $menu; + } + + public function album_menu() { + $menu = Menu::factory("root"); + core_menu::album($menu, $this); + + foreach (module::active() as $module) { + if ($module->name == "core") { + continue; + } + $class = "{$module->name}_menu"; + if (method_exists($class, "album")) { + call_user_func_array(array($class, "album"), array(&$menu, $this)); + } + } + + print $menu; + } + + public function photo_menu() { + $menu = Menu::factory("root"); + core_menu::photo($menu, $this); + + foreach (module::active() as $module) { + if ($module->name == "core") { + continue; + } + $class = "{$module->name}_menu"; + if (method_exists($class, "photo")) { + call_user_func_array(array($class, "photo"), array(&$menu, $this)); + } + } + + print $menu; + } + + public function pager() { + if ($this->children_count) { + $this->pagination = new Pagination(); + $this->pagination->initialize( + array('query_string' => 'page', + 'total_items' => $this->children_count, + 'items_per_page' => $this->page_size, + 'style' => 'classic')); + return $this->pagination->render(); + } + } + + /** + * Print out any site wide status information. + */ + public function site_status() { + return site_status::get(); + } + + /** + * Print out any messages waiting for this user. + */ + public function messages() { + return message::get(); + } + + /** + * Handle all theme functions that insert module content. + */ + public function __call($function, $args) { + switch ($function) { + case "album_blocks": + case "album_bottom": + case "album_top": + case "credits"; + case "dynamic_bottom": + case "dynamic_top": + case "footer": + case "head": + case "header_bottom": + case "header_top": + case "page_bottom": + case "page_top": + case "photo_blocks": + case "photo_bottom": + case "photo_top": + case "resize_bottom": + case "resize_top": + case "sidebar_blocks": + case "sidebar_bottom": + case "sidebar_top": + case "thumb_bottom": + case "thumb_info": + case "thumb_top": + $blocks = array(); + foreach (module::active() as $module) { + $helper_class = "{$module->name}_theme"; + if (method_exists($helper_class, $function)) { + $blocks[] = call_user_func_array( + array($helper_class, $function), + array_merge(array($this), $args)); + } + } + if (Session::instance()->get("debug")) { + if ($function != "head") { + array_unshift( + $blocks, "
      " . + "
      $function
      "); + $blocks[] = "
      "; + } + } + return implode("\n", $blocks); + + default: + throw new Exception("@todo UNKNOWN_THEME_FUNCTION: $function"); + } + } +} \ No newline at end of file diff --git a/modules/gallery/models/access_cache.php b/modules/gallery/models/access_cache.php new file mode 100644 index 00000000..10d05df7 --- /dev/null +++ b/modules/gallery/models/access_cache.php @@ -0,0 +1,21 @@ + "required|length[0,255]", + "title" => "required|length[0,255]", + "description" => "length[0,65535]" + ); + + /** + * Add a set of restrictions to any following queries to restrict access only to items + * viewable by the active user. + * @chainable + */ + public function viewable() { + if (is_null($this->view_restrictions)) { + if (user::active()->admin) { + $this->view_restrictions = array(); + } else { + foreach (user::group_ids() as $id) { + // Separate the first restriction from the rest to make it easier for us to formulate + // our where clause below + if (empty($this->view_restrictions)) { + $this->view_restrictions[0] = "view_$id"; + } else { + $this->view_restrictions[1]["view_$id"] = access::ALLOW; + } + } + } + } + switch (count($this->view_restrictions)) { + case 0: + break; + + case 1: + $this->where($this->view_restrictions[0], access::ALLOW); + break; + + default: + $this->open_paren(); + $this->where($this->view_restrictions[0], access::ALLOW); + $this->orwhere($this->view_restrictions[1]); + $this->close_paren(); + break; + } + + return $this; + } + + /** + * Is this item an album? + * @return true if it's an album + */ + public function is_album() { + return $this->type == 'album'; + } + + /** + * Is this item a photo? + * @return true if it's a photo + */ + public function is_photo() { + return $this->type == 'photo'; + } + + /** + * Is this item a movie? + * @return true if it's a movie + */ + public function is_movie() { + return $this->type == 'movie'; + } + + public function delete() { + module::event("item_before_delete", $this); + + $parent = $this->parent(); + if ($parent->album_cover_item_id == $this->id) { + item::remove_album_cover($parent); + } + + $path = $this->file_path(); + $resize_path = $this->resize_path(); + $thumb_path = $this->thumb_path(); + + parent::delete(); + if (is_dir($path)) { + @dir::unlink($path); + @dir::unlink(dirname($resize_path)); + @dir::unlink(dirname($thumb_path)); + } else { + @unlink($path); + @unlink($resize_path); + @unlink($thumb_path); + } + } + + /** + * Move this item to the specified target. + * @chainable + * @param Item_Model $target Target item (must be an album + * @return ORM_MTPP + */ + function move_to($target) { + if (!$target->is_album()) { + throw new Exception("@todo INVALID_MOVE_TYPE $target->type"); + } + + if ($this->id == 1) { + throw new Exception("@todo INVALID_SOURCE root album"); + } + + $original_path = $this->file_path(); + $original_resize_path = $this->resize_path(); + $original_thumb_path = $this->thumb_path(); + + parent::move_to($target, true); + $this->relative_path_cache = null; + + rename($original_path, $this->file_path()); + if ($this->is_album()) { + @rename(dirname($original_resize_path), dirname($this->resize_path())); + @rename(dirname($original_thumb_path), dirname($this->thumb_path())); + Database::instance() + ->update("items", + array("relative_path_cache" => null), + array("left >" => $this->left, "right <" => $this->right)); + } else { + @rename($original_resize_path, $this->resize_path()); + @rename($original_thumb_path, $this->thumb_path()); + } + + return $this; + } + + /** + * Rename the underlying file for this item to a new name. Move all the files. This requires a + * save. + * + * @chainable + */ + public function rename($new_name) { + if ($new_name == $this->name) { + return; + } + + if (strpos($new_name, "/")) { + throw new Exception("@todo NAME_CANNOT_CONTAIN_SLASH"); + } + + $old_relative_path = $this->relative_path(); + $new_relative_path = dirname($old_relative_path) . "/" . $new_name; + @rename(VARPATH . "albums/$old_relative_path", VARPATH . "albums/$new_relative_path"); + @rename(VARPATH . "resizes/$old_relative_path", VARPATH . "resizes/$new_relative_path"); + @rename(VARPATH . "thumbs/$old_relative_path", VARPATH . "thumbs/$new_relative_path"); + $this->name = $new_name; + + if ($this->is_album()) { + Database::instance() + ->update("items", + array("relative_path_cache" => null), + array("left >" => $this->left, "right <" => $this->right)); + } + + return $this; + } + + /** + * album: url::site("albums/2") + * photo: url::site("photos/3") + * + * @param string $query the query string (eg "show=3") + */ + public function url($query=array(), $full_uri=false) { + $url = ($full_uri ? url::abs_site("{$this->type}s/$this->id") + : url::site("{$this->type}s/$this->id")); + if ($query) { + $url .= "?$query"; + } + return $url; + } + + /** + * album: /var/albums/album1/album2 + * photo: /var/albums/album1/album2/photo.jpg + */ + public function file_path() { + return VARPATH . "albums/" . $this->relative_path(); + } + + /** + * album: http://example.com/gallery3/var/resizes/album1/ + * photo: http://example.com/gallery3/var/albums/album1/photo.jpg + */ + public function file_url($full_uri=false) { + return $full_uri ? + url::abs_file("var/albums/" . $this->relative_path()) : + url::file("var/albums/" . $this->relative_path()); + } + + /** + * album: /var/resizes/album1/.thumb.jpg + * photo: /var/albums/album1/photo.thumb.jpg + */ + public function thumb_path() { + $base = VARPATH . "thumbs/" . $this->relative_path(); + if ($this->is_photo()) { + return $base; + } else if ($this->is_album()) { + return $base . "/.album.jpg"; + } else if ($this->is_movie()) { + // Replace the extension with jpg + return preg_replace("/...$/", "jpg", $base); + } + } + + /** + * Return true if there is a thumbnail for this item. + */ + public function has_thumb() { + return $this->thumb_width && $this->thumb_height; + } + + /** + * album: http://example.com/gallery3/var/resizes/album1/.thumb.jpg + * photo: http://example.com/gallery3/var/albums/album1/photo.thumb.jpg + */ + public function thumb_url($full_uri=false) { + $cache_buster = "?m=" . $this->updated; + $base = ($full_uri ? + url::abs_file("var/thumbs/" . $this->relative_path()) : + url::file("var/thumbs/" . $this->relative_path())); + if ($this->is_photo()) { + return $base . $cache_buster; + } else if ($this->is_album()) { + return $base . "/.album.jpg" . $cache_buster; + } else if ($this->is_movie()) { + // Replace the extension with jpg + $base = preg_replace("/...$/", "jpg", $base); + return $base . $cache_buster; + } + } + + /** + * album: /var/resizes/album1/.resize.jpg + * photo: /var/albums/album1/photo.resize.jpg + */ + public function resize_path() { + return VARPATH . "resizes/" . $this->relative_path() . + ($this->is_album() ? "/.album.jpg" : ""); + } + + /** + * album: http://example.com/gallery3/var/resizes/album1/.resize.jpg + * photo: http://example.com/gallery3/var/albums/album1/photo.resize.jpg + */ + public function resize_url($full_uri=false) { + return ($full_uri ? + url::abs_file("var/resizes/" . $this->relative_path()) : + url::file("var/resizes/" . $this->relative_path())) . + ($this->is_album() ? "/.album.jpg" : ""); + } + + /** + * Return the relative path to this item's file. + * @return string + */ + public function relative_path() { + if (!isset($this->relative_path_cache)) { + $paths = array(); + foreach (Database::instance() + ->select("name") + ->from("items") + ->where("left <=", $this->left) + ->where("right >=", $this->right) + ->where("id <>", 1) + ->orderby("left", "ASC") + ->get() as $row) { + $paths[] = $row->name; + } + $this->relative_path_cache = implode($paths, "/"); + $this->save(); + } + return $this->relative_path_cache; + } + + /** + * @see ORM::__get() + */ + public function __get($column) { + if ($column == "owner") { + // This relationship depends on an outside module, which may not be present so handle + // failures gracefully. + try { + return model_cache::get("user", $this->owner_id); + } catch (Exception $e) { + return null; + } + } else { + return parent::__get($column); + } + } + + /** + * @see ORM::__set() + */ + public function __set($column, $value) { + if ($column == "name") { + // Clear the relative path as it is no longer valid. + $this->relative_path_cache = null; + } + parent::__set($column, $value); + } + + /** + * @see ORM::save() + */ + public function save() { + if (!empty($this->changed) && $this->changed != array("view_count" => "view_count")) { + $this->updated = time(); + if (!$this->loaded) { + $this->created = $this->updated; + $r = ORM::factory("item")->select("MAX(weight) as max_weight")->find(); + $this->weight = $r->max_weight + 1; + } + } + return parent::save(); + } + + /** + * Return the Item_Model representing the cover for this album. + * @return Item_Model or null if there's no cover + */ + public function album_cover() { + if (!$this->is_album()) { + return null; + } + + if (empty($this->album_cover_item_id)) { + return null; + } + + try { + return model_cache::get("item", $this->album_cover_item_id); + } catch (Exception $e) { + // It's possible (unlikely) that the item was deleted, if so keep going. + return null; + } + } + + /** + * Find the position of the given child id in this album. The resulting value is 1-indexed, so + * the first child in the album is at position 1. + */ + public function get_position($child_id) { + $result = Database::instance()->query(" + SELECT COUNT(*) AS position FROM {items} + WHERE parent_id = {$this->parent_id} + AND {$this->sort_column} <= (SELECT {$this->sort_column} + FROM {items} WHERE id = $child_id) + ORDER BY {$this->sort_column} {$this->sort_order}"); + + return $result->current()->position; + } + + /** + * Return an tag for the thumbnail. + * @param array $extra_attrs Extra attributes to add to the img tag + * @param int (optional) $max Maximum size of the thumbnail (default: null) + * @param boolean (optional) $center_vertically Center vertically (default: false) + * @return string + */ + public function thumb_tag($extra_attrs=array(), $max=null, $center_vertically=false) { + list ($height, $width) = $this->scale_dimensions($max); + if ($center_vertically && $max) { + // The constant is divide by 2 to calculate the file and 10 to convert to em + $margin_top = ($max - $height) / 20; + $extra_attrs["style"] = "margin-top: {$margin_top}em"; + $extra_attrs["title"] = $this->title; + } + $attrs = array_merge($extra_attrs, + array( + "src" => $this->thumb_url(), + "alt" => $this->title, + "width" => $width, + "height" => $height) + ); + // html::image forces an absolute url which we don't want + return ""; + } + + /** + * Calculate the largest width/height that fits inside the given maximum, while preserving the + * aspect ratio. + * @param int $max Maximum size of the largest dimension + * @return array + */ + public function scale_dimensions($max) { + $width = $this->thumb_width; + $height = $this->thumb_height; + + if ($height) { + if (isset($max)) { + if ($width > $height) { + $height = (int)($max * ($height / $width)); + $width = $max; + } else { + $width = (int)($max * ($width / $height)); + $height = $max; + } + } + } else { + // Missing thumbnail, can happen on albums with no photos yet. + // @todo we should enforce a placeholder for those albums. + $width = 0; + $height = 0; + } + return array($height, $width); + } + + /** + * Return an tag for the resize. + * @param array $extra_attrs Extra attributes to add to the img tag + * @return string + */ + public function resize_tag($extra_attrs) { + $attrs = array_merge($extra_attrs, + array("src" => $this->resize_url(), + "alt" => $this->title, + "width" => $this->resize_width, + "height" => $this->resize_height) + ); + // html::image forces an absolute url which we don't want + return ""; + } + + /** + * Return a flowplayer "; + } + + /** + * Return all of the children of this node, ordered by the defined sort order. + * + * @chainable + * @param integer SQL limit + * @param integer SQL offset + * @return array ORM + */ + function children($limit=null, $offset=0) { + return parent::children($limit, $offset, array($this->sort_column => $this->sort_order)); + } + + /** + * Return all of the children of the specified type, ordered by the defined sort order. + * @param integer SQL limit + * @param integer SQL offset + * @param string type to return + * @return object ORM_Iterator + */ + function descendants($limit=null, $offset=0, $type=null) { + return parent::descendants($limit, $offset, $type, + array($this->sort_column => $this->sort_order)); + } +} diff --git a/modules/gallery/models/log.php b/modules/gallery/models/log.php new file mode 100644 index 00000000..6734afb8 --- /dev/null +++ b/modules/gallery/models/log.php @@ -0,0 +1,22 @@ +context); + if (array_key_exists($key, $context)) { + return $context[$key]; + } else { + return $default; + } + } + + public function set($key, $value) { + $context = unserialize($this->context); + $context[$key] = $value; + $this->context = serialize($context); + } + + public function save() { + if (!empty($this->changed)) { + $this->updated = time(); + } + return parent::save(); + } + + public function owner() { + return user::lookup($this->owner_id); + } +} \ No newline at end of file diff --git a/modules/gallery/models/theme.php b/modules/gallery/models/theme.php new file mode 100644 index 00000000..f479fd5a --- /dev/null +++ b/modules/gallery/models/theme.php @@ -0,0 +1,21 @@ +where("name", "access_test")->find(); + if ($group->loaded) { + $group->delete(); + } + } catch (Exception $e) { } + + try { + access::delete_permission("access_test"); + } catch (Exception $e) { } + + try { + $user = ORM::factory("user")->where("name", "access_test")->find(); + if ($user->loaded) { + $user->delete(); + } + } catch (Exception $e) { } + } + + public function setup() { + user::set_active(user::guest()); + } + + public function groups_and_permissions_are_bound_to_columns_test() { + access::register_permission("access_test", "Access Test"); + $group = group::create("access_test"); + + // We have a new column for this perm / group combo + $fields = Database::instance()->list_fields("access_caches"); + $this->assert_true(array_key_exists("access_test_{$group->id}", $fields)); + + access::delete_permission("access_test"); + $group->delete(); + + // Now the column has gone away + $fields = Database::instance()->list_fields("access_caches"); + $this->assert_false(array_key_exists("access_test_{$group->id}", $fields)); + } + + public function adding_and_removing_items_adds_ands_removes_rows_test() { + $root = ORM::factory("item", 1); + $item = album::create($root, rand(), "test album"); + + // New rows exist + $this->assert_true(ORM::factory("access_cache")->where("item_id", $item->id)->find()->loaded); + $this->assert_true(ORM::factory("access_intent")->where("item_id", $item->id)->find()->loaded); + + // Delete the item + $item->delete(); + + // Rows are gone + $this->assert_false(ORM::factory("access_cache")->where("item_id", $item->id)->find()->loaded); + $this->assert_false(ORM::factory("access_intent")->where("item_id", $item->id)->find()->loaded); + } + + public function new_photos_inherit_parent_permissions_test() { + $root = ORM::factory("item", 1); + + $album = album::create($root, rand(), "test album"); + access::allow(group::everybody(), "view", $album); + + $photo = ORM::factory("item"); + $photo->type = "photo"; + $photo->add_to_parent($album); + access::add_item($photo); + + $this->assert_true($photo->__get("view_" . group::everybody()->id)); + } + + public function can_allow_deny_and_reset_intent_test() { + $root = ORM::factory("item", 1); + $album = album::create($root, rand(), "test album"); + $intent = ORM::factory("access_intent")->where("item_id", $album)->find(); + + // Allow + access::allow(group::everybody(), "view", $album); + $this->assert_same(access::ALLOW, $intent->reload()->view_1); + + // Deny + access::deny(group::everybody(), "view", $album); + $this->assert_same( + access::DENY, + ORM::factory("access_intent")->where("item_id", $album)->find()->view_1); + + // Allow again. If the initial value was allow, then the first Allow clause above may not + // have actually changed any values. + access::allow(group::everybody(), "view", $album); + $this->assert_same( + access::ALLOW, + ORM::factory("access_intent")->where("item_id", $album)->find()->view_1); + + access::reset(group::everybody(), "view", $album); + $this->assert_same( + null, + ORM::factory("access_intent")->where("item_id", $album)->find()->view_1); + } + + public function cant_reset_root_item_test() { + try { + access::reset(group::everybody(), "view", ORM::factory("item", 1)); + } catch (Exception $e) { + return; + } + $this->assert_true(false, "Should not be able to reset root intent"); + } + + public function can_view_item_test() { + $root = ORM::factory("item", 1); + access::allow(group::everybody(), "view", $root); + $this->assert_true(access::group_can(group::everybody(), "view", $root)); + } + + public function can_always_fails_on_unloaded_items_test() { + $root = ORM::factory("item", 1); + access::allow(group::everybody(), "view", $root); + $this->assert_true(access::group_can(group::everybody(), "view", $root)); + + $bogus = ORM::factory("item", -1); + $this->assert_false(access::group_can(group::everybody(), "view", $bogus)); + } + + public function cant_view_child_of_hidden_parent_test() { + $root = ORM::factory("item", 1); + $album = album::create($root, rand(), "test album"); + + $root->reload(); + access::deny(group::everybody(), "view", $root); + access::reset(group::everybody(), "view", $album); + + $album->reload(); + $this->assert_false(access::group_can(group::everybody(), "view", $album)); + } + + public function view_permissions_propagate_down_test() { + $root = ORM::factory("item", 1); + $album = album::create($root, rand(), "test album"); + + access::allow(group::everybody(), "view", $root); + access::reset(group::everybody(), "view", $album); + $album->reload(); + $this->assert_true(access::group_can(group::everybody(), "view", $album)); + } + + public function can_toggle_view_permissions_propagate_down_test() { + $root = ORM::factory("item", 1); + $album1 = album::create($root, rand(), "test album"); + $album2 = album::create($album1, rand(), "test album"); + $album3 = album::create($album2, rand(), "test album"); + $album4 = album::create($album3, rand(), "test album"); + + $album1->reload(); + $album2->reload(); + $album3->reload(); + $album4->reload(); + + access::allow(group::everybody(), "view", $root); + access::deny(group::everybody(), "view", $album1); + access::reset(group::everybody(), "view", $album2); + access::reset(group::everybody(), "view", $album3); + access::reset(group::everybody(), "view", $album4); + + $album4->reload(); + $this->assert_false(access::group_can(group::everybody(), "view", $album4)); + + access::allow(group::everybody(), "view", $album1); + $album4->reload(); + $this->assert_true(access::group_can(group::everybody(), "view", $album4)); + } + + public function revoked_view_permissions_cant_be_allowed_lower_down_test() { + $root = ORM::factory("item", 1); + $album1 = album::create($root, rand(), "test album"); + $album2 = album::create($album1, rand(), "test album"); + + $root->reload(); + access::deny(group::everybody(), "view", $root); + access::allow(group::everybody(), "view", $album2); + + $album1->reload(); + $this->assert_false(access::group_can(group::everybody(), "view", $album1)); + + $album2->reload(); + $this->assert_false(access::group_can(group::everybody(), "view", $album2)); + } + + public function can_edit_item_test() { + $root = ORM::factory("item", 1); + access::allow(group::everybody(), "edit", $root); + $this->assert_true(access::group_can(group::everybody(), "edit", $root)); + } + + public function non_view_permissions_propagate_down_test() { + $root = ORM::factory("item", 1); + $album = album::create($root, rand(), "test album"); + + access::allow(group::everybody(), "edit", $root); + access::reset(group::everybody(), "edit", $album); + $this->assert_true(access::group_can(group::everybody(), "edit", $album)); + } + + public function non_view_permissions_can_be_revoked_lower_down_test() { + $root = ORM::factory("item", 1); + $outer = album::create($root, rand(), "test album"); + $outer_photo = ORM::factory("item"); + $outer_photo->type = "photo"; + $outer_photo->add_to_parent($outer); + access::add_item($outer_photo); + + $inner = album::create($outer, rand(), "test album"); + $inner_photo = ORM::factory("item"); + $inner_photo->type = "photo"; + $inner_photo->add_to_parent($inner); + access::add_item($inner_photo); + + $outer->reload(); + $inner->reload(); + + access::allow(group::everybody(), "edit", $root); + access::deny(group::everybody(), "edit", $outer); + access::allow(group::everybody(), "edit", $inner); + + // Outer album is not editable, inner one is. + $this->assert_false(access::group_can(group::everybody(), "edit", $outer_photo)); + $this->assert_true(access::group_can(group::everybody(), "edit", $inner_photo)); + } + + public function i_can_edit_test() { + // Create a new user that belongs to no groups + $user = user::create("access_test", "Access Test", ""); + foreach ($user->groups as $group) { + $user->remove($group); + } + $user->save(); + user::set_active($user); + + // This user can't edit anything + $root = ORM::factory("item", 1); + $this->assert_false(access::can("edit", $root)); + + // Now add them to a group that has edit permission + $group = group::create("access_test"); + $group->add($user); + $group->save(); + access::allow($group, "edit", $root); + + $user = ORM::factory("user", $user->id); // reload() does not flush related columns + user::set_active($user); + + // And verify that the user can edit. + $this->assert_true(access::can("edit", $root)); + } + + public function everybody_view_permission_maintains_htaccess_files_test() { + $root = ORM::factory("item", 1); + $album = album::create($root, rand(), "test album"); + + $this->assert_false(file_exists($album->file_path() . "/.htaccess")); + + access::deny(group::everybody(), "view", $album); + $this->assert_true(file_exists($album->file_path() . "/.htaccess")); + + access::allow(group::everybody(), "view", $album); + $this->assert_false(file_exists($album->file_path() . "/.htaccess")); + + access::deny(group::everybody(), "view", $album); + $this->assert_true(file_exists($album->file_path() . "/.htaccess")); + + access::reset(group::everybody(), "view", $album); + $this->assert_false(file_exists($album->file_path() . "/.htaccess")); + } + + public function everybody_view_full_permission_maintains_htaccess_files_test() { + $root = ORM::factory("item", 1); + $album = album::create($root, rand(), "test album"); + + $this->assert_false(file_exists($album->file_path() . "/.htaccess")); + $this->assert_false(file_exists($album->resize_path() . "/.htaccess")); + $this->assert_false(file_exists($album->thumb_path() . "/.htaccess")); + + access::deny(group::everybody(), "view_full", $album); + $this->assert_true(file_exists($album->file_path() . "/.htaccess")); + $this->assert_false(file_exists($album->resize_path() . "/.htaccess")); + $this->assert_false(file_exists($album->thumb_path() . "/.htaccess")); + + access::allow(group::everybody(), "view_full", $album); + $this->assert_false(file_exists($album->file_path() . "/.htaccess")); + $this->assert_false(file_exists($album->resize_path() . "/.htaccess")); + $this->assert_false(file_exists($album->thumb_path() . "/.htaccess")); + + access::deny(group::everybody(), "view_full", $album); + $this->assert_true(file_exists($album->file_path() . "/.htaccess")); + $this->assert_false(file_exists($album->resize_path() . "/.htaccess")); + $this->assert_false(file_exists($album->thumb_path() . "/.htaccess")); + + access::reset(group::everybody(), "view_full", $album); + $this->assert_false(file_exists($album->file_path() . "/.htaccess")); + $this->assert_false(file_exists($album->resize_path() . "/.htaccess")); + $this->assert_false(file_exists($album->thumb_path() . "/.htaccess")); + } +} diff --git a/modules/gallery/tests/Album_Helper_Test.php b/modules/gallery/tests/Album_Helper_Test.php new file mode 100644 index 00000000..80afa8d1 --- /dev/null +++ b/modules/gallery/tests/Album_Helper_Test.php @@ -0,0 +1,87 @@ +assert_equal(VARPATH . "albums/$rand", $album->file_path()); + $this->assert_equal(VARPATH . "thumbs/$rand/.album.jpg", $album->thumb_path()); + $this->assert_true(is_dir(VARPATH . "thumbs/$rand"), "missing thumb dir"); + + // It's unclear that a resize makes sense for an album. But we have one. + $this->assert_equal(VARPATH . "resizes/$rand/.album.jpg", $album->resize_path()); + $this->assert_true(is_dir(VARPATH . "resizes/$rand"), "missing resizes dir"); + + $this->assert_equal(1, $album->parent_id); // MPTT tests will cover other hierarchy checks + $this->assert_equal($rand, $album->name); + $this->assert_equal($rand, $album->title); + $this->assert_equal($rand, $album->description); + } + + public function create_conflicting_album_test() { + $rand = rand(); + $root = ORM::factory("item", 1); + $album1 = album::create($root, $rand, $rand, $rand); + $album2 = album::create($root, $rand, $rand, $rand); + $this->assert_true($album1->name != $album2->name); + } + + public function thumb_url_test() { + $rand = rand(); + $root = ORM::factory("item", 1); + $album = album::create($root, $rand, $rand, $rand); + $this->assert_equal("http://./var/thumbs/$rand/.album.jpg", $album->thumb_url()); + } + + public function resize_url_test() { + $rand = rand(); + $root = ORM::factory("item", 1); + $album = album::create($root, $rand, $rand, $rand); + $this->assert_equal("http://./var/resizes/$rand/.album.jpg", $album->resize_url()); + } + + public function create_album_shouldnt_allow_names_with_slash_test() { + $rand = rand(); + $root = ORM::factory("item", 1); + try { + $album = album::create($root, $rand . "/", $rand, $rand); + } catch (Exception $e) { + // pass + return; + } + + $this->assert_true(false, "Shouldn't create an album with / in the name"); + } + + public function create_album_silently_trims_trailing_periods_test() { + $rand = rand(); + $root = ORM::factory("item", 1); + try { + $album = album::create($root, $rand . "..", $rand, $rand); + } catch (Exception $e) { + $this->assert_equal("@todo NAME_CANNOT_END_IN_PERIOD", $e->getMessage()); + return; + } + + $this->assert_true(false, "Shouldn't create an album with trailing . in the name"); + } +} diff --git a/modules/gallery/tests/Albums_Controller_Test.php b/modules/gallery/tests/Albums_Controller_Test.php new file mode 100644 index 00000000..ef1fac77 --- /dev/null +++ b/modules/gallery/tests/Albums_Controller_Test.php @@ -0,0 +1,76 @@ +_post = $_POST; + } + + public function teardown() { + $_POST = $this->_post; + } + + public function change_album_test() { + $controller = new Albums_Controller(); + $root = ORM::factory("item", 1); + $album = album::create($root, "test", "test", "test"); + $orig_name = $album->name; + + $_POST["dirname"] = "test"; + $_POST["name"] = "new name"; + $_POST["title"] = "new title"; + $_POST["description"] = "new description"; + $_POST["column"] = "weight"; + $_POST["direction"] = "ASC"; + $_POST["csrf"] = access::csrf_token(); + $_POST["_method"] = "put"; + access::allow(group::everybody(), "edit", $root); + + ob_start(); + $controller->_update($album); + $results = ob_get_contents(); + ob_end_clean(); + + $this->assert_equal( + json_encode(array("result" => "success", "location" => "http://./index.php/test")), + $results); + $this->assert_equal("new title", $album->title); + $this->assert_equal("new description", $album->description); + + // We don't change the name, yet. + $this->assert_equal($orig_name, $album->name); + } + + public function change_album_no_csrf_fails_test() { + $controller = new Albums_Controller(); + $root = ORM::factory("item", 1); + $album = album::create($root, "test", "test", "test"); + $_POST["name"] = "new name"; + $_POST["title"] = "new title"; + $_POST["description"] = "new description"; + access::allow(group::everybody(), "edit", $root); + + try { + $controller->_update($album); + $this->assert_true(false, "This should fail"); + } catch (Exception $e) { + // pass + } + } +} diff --git a/modules/gallery/tests/Core_Installer_Test.php b/modules/gallery/tests/Core_Installer_Test.php new file mode 100644 index 00000000..f7036286 --- /dev/null +++ b/modules/gallery/tests/Core_Installer_Test.php @@ -0,0 +1,50 @@ +assert_true(file_exists(VARPATH . "albums")); + $this->assert_true(file_exists(VARPATH . "resizes")); + } + + public function install_registers_core_module_test() { + $core = ORM::factory("module")->where("name", "core")->find(); + $this->assert_equal("core", $core->name); + + // This is probably too volatile to keep for long + $this->assert_equal(1, $core->version); + } + + public function install_creates_root_item_test() { + $max_right = ORM::factory("item") + ->select("MAX(`right`) AS `right`") + ->find()->right; + $root = ORM::factory('item')->find(1); + $this->assert_equal("Gallery", $root->title); + $this->assert_equal(1, $root->left); + $this->assert_equal($max_right, $root->right); + $this->assert_equal(null, $root->parent_id); + $this->assert_equal(1, $root->level); + } +} diff --git a/modules/gallery/tests/Database_Test.php b/modules/gallery/tests/Database_Test.php new file mode 100644 index 00000000..bd3d2f53 --- /dev/null +++ b/modules/gallery/tests/Database_Test.php @@ -0,0 +1,134 @@ +where("a", 1) + ->where("b", 2) + ->compile(); + $sql = str_replace("\n", " ", $sql); + $this->assert_same("SELECT * WHERE `a` = 1 AND `b` = 2", $sql); + } + + function compound_where_test() { + $sql = Database::instance() + ->where("outer1", 1) + ->open_paren() + ->where("inner1", 1) + ->orwhere("inner2", 2) + ->close_paren() + ->where("outer2", 2) + ->compile(); + $sql = str_replace("\n", " ", $sql); + $this->assert_same( + "SELECT * WHERE `outer1` = 1 AND (`inner1` = 1 OR `inner2` = 2) AND `outer2` = 2", + $sql); + } + + function group_first_test() { + $sql = Database::instance() + ->open_paren() + ->where("inner1", 1) + ->orwhere("inner2", 2) + ->close_paren() + ->where("outer1", 1) + ->where("outer2", 2) + ->compile(); + $sql = str_replace("\n", " ", $sql); + $this->assert_same( + "SELECT * WHERE (`inner1` = 1 OR `inner2` = 2) AND `outer1` = 1 AND `outer2` = 2", + $sql); + } + + function where_array_test() { + $sql = Database::instance() + ->where("outer1", 1) + ->open_paren() + ->where("inner1", 1) + ->orwhere(array("inner2" => 2, "inner3" => 3)) + ->close_paren() + ->compile(); + $sql = str_replace("\n", " ", $sql); + $this->assert_same( + "SELECT * WHERE `outer1` = 1 AND (`inner1` = 1 OR `inner2` = 2 OR `inner3` = 3)", + $sql); + } + + function notlike_test() { + $sql = Database::instance() + ->where("outer1", 1) + ->open_paren() + ->ornotlike("inner1", 1) + ->close_paren() + ->compile(); + $sql = str_replace("\n", " ", $sql); + $this->assert_same( + "SELECT * WHERE `outer1` = 1 OR ( `inner1` NOT LIKE '%1%')", + $sql); + } + + function prefix_replacement_test() { + $db = Database_For_Test::instance(); + $converted = $db->add_table_prefixes("CREATE TABLE IF NOT EXISTS {test_tables} ( + `id` int(9) NOT NULL auto_increment, + `name` varchar(32) NOT NULL, + PRIMARY KEY (`id`), + UNIQUE KEY(`name`)) + ENGINE=InnoDB DEFAULT CHARSET=utf8"); + $expected = "CREATE TABLE IF NOT EXISTS g3test_test_tables ( + `id` int(9) NOT NULL auto_increment, + `name` varchar(32) NOT NULL, + PRIMARY KEY (`id`), + UNIQUE KEY(`name`)) + ENGINE=InnoDB DEFAULT CHARSET=utf8"; + $this->assert_same($expected, $converted); + + $sql = "UPDATE {test_tables} SET `name` = '{test string}' " . + "WHERE `item_id` IN " . + " (SELECT `id` FROM {items} " . + " WHERE `left` >= 1 " . + " AND `right` <= 6)"; + $sql = $db->add_table_prefixes($sql); + + $expected = "UPDATE g3test_test_tables SET `name` = '{test string}' " . + "WHERE `item_id` IN " . + " (SELECT `id` FROM g3test_items " . + " WHERE `left` >= 1 " . + " AND `right` <= 6)"; + + $this->assert_same($expected, $sql); + } + + public function setup() { + } + + public function teardown() { + } + +} + +class Database_For_Test extends Database { + static function instance() { + $db = new Database_For_Test(); + $db->_table_names["{items}"] = "g3test_items"; + $db->config["table_prefix"] = "g3test_"; + return $db; + } +} diff --git a/modules/gallery/tests/Dir_Helper_Test.php b/modules/gallery/tests/Dir_Helper_Test.php new file mode 100644 index 00000000..46bb871c --- /dev/null +++ b/modules/gallery/tests/Dir_Helper_Test.php @@ -0,0 +1,32 @@ +assert_boolean(!file_exists($filename), "File not deleted"); + $this->assert_boolean(!file_exists($dirname), "Directory not deleted"); + } +} diff --git a/modules/gallery/tests/DrawForm_Test.php b/modules/gallery/tests/DrawForm_Test.php new file mode 100644 index 00000000..2c5aaba4 --- /dev/null +++ b/modules/gallery/tests/DrawForm_Test.php @@ -0,0 +1,84 @@ + "gTestGroupForm")); + $form->input("title")->label(t("Title")); + $form->textarea("description")->label(t("Text Area")); + $form->submit("")->value(t("Submit")); + $rendered = $form->__toString(); + + $expected = "
      \n" . + "\n" . + "
        \n" . + "
      • \n" . + " \n" . + " \n" . + "
      • \n" . + "
      • \n" . + " \n" . + " \n" . + "
      • \n" . + "
      • \n" . + " \n" . + "
      • \n" . + "
      \n" . + "
      \n"; + $this->assert_same($expected, $rendered); + } + + function group_test() { + $form = new Forge("test/controller", "", "post", array("id" => "gTestGroupForm")); + $group = $form->group("test_group")->label(t("Test Group")); + $group->input("title")->label(t("Title")); + $group->textarea("description")->label(t("Text Area")); + $group->submit("")->value(t("Submit")); + $rendered = $form->__toString(); + + $expected = "
      \n" . + "\n" . + "
      \n" . + " Test Group\n" . + "
        \n" . + "
      • \n" . + " \n" . + " \n" . + "
      • \n" . + "
      • \n" . + " \n" . + " \n" . + "
      • \n" . + "
      • \n" . + " \n" . + "
      • \n" . + "
      \n" . + "
      \n" . + "
      \n"; + $this->assert_same($expected, $rendered); + } + +} + diff --git a/modules/gallery/tests/File_Structure_Test.php b/modules/gallery/tests/File_Structure_Test.php new file mode 100644 index 00000000..1caa82ba --- /dev/null +++ b/modules/gallery/tests/File_Structure_Test.php @@ -0,0 +1,235 @@ +getPathname())) { + $this->assert_false( + preg_match('/\?\>\s*$/', file_get_contents($file)), + "{$file->getPathname()} ends in ?>"); + } + } + } + + public function view_files_correct_suffix_test() { + $dir = new GalleryCodeFilterIterator( + new RecursiveIteratorIterator(new RecursiveDirectoryIterator(DOCROOT))); + foreach ($dir as $file) { + if (strpos($file, "views")) { + $this->assert_true( + preg_match("#/views/.*?(\.html|mrss|txt)\.php$#", $file->getPathname()), + "{$file->getPathname()} should end in .{html,mrss,txt}.php"); + } + } + } + + public function no_windows_line_endings_test() { + $dir = new GalleryCodeFilterIterator( + new RecursiveIteratorIterator(new RecursiveDirectoryIterator(DOCROOT))); + foreach ($dir as $file) { + if (preg_match("/\.(php|css|html|js)$/", $file)) { + foreach (file($file) as $line) { + $this->assert_true(substr($line, -2) != "\r\n", "$file has windows style line endings"); + } + } + } + } + + private function _check_view_preamble($path, &$errors) { + // The preamble for views is a single line that prevents direct script access + if (strpos($path, SYSPATH) === 0) { + // Kohana preamble + $expected = "\n"; + } else { + // Gallery preamble + // @todo use the same preamble for both! + $expected = "\n"; + } + + $fp = fopen($path, "r"); + $actual = fgets($fp); + fclose($fp); + + if ($expected != $actual) { + $errors[] = "$path:1\n expected:\n\t$expected\n actual:\n\t$actual"; + } + } + + private function _check_php_preamble($path, &$errors) { + if (strpos($path, SYSPATH) === 0 || + strpos($path, MODPATH . "unit_test") === 0) { + // Kohana: we only care about the first line + $fp = fopen($path, "r"); + $actual = array(fgets($fp)); + fclose($fp); + $expected = array("_get_preamble($path); + $expected = array( + "getPathname(); + switch ($path) { + case DOCROOT . "installer/database_config.php": + case DOCROOT . "installer/init_var.php": + // Special case views + $this->_check_view_preamble($path, $errors); + break; + + case DOCROOT . "index.php": + case DOCROOT . "installer/index.php": + // Front controllers + break; + + case DOCROOT . "index.local.php": + // Special case optional file, not part of the codebase + break; + + default: + if (strpos($path, DOCROOT . "var/logs") === 0) { + continue; + } else if (preg_match("/views/", $path)) { + $this->_check_view_preamble($path, $errors); + } else { + $this->_check_php_preamble($path, $errors); + } + } + } + + if ($errors) { + $this->assert_false(true, "Preamble errors:\n" . join("\n", $errors)); + } + } + + public function no_tabs_in_our_code_test() { + $dir = new PhpCodeFilterIterator( + new GalleryCodeFilterIterator( + new RecursiveIteratorIterator( + new RecursiveDirectoryIterator(DOCROOT)))); + foreach ($dir as $file) { + $this->assert_false( + preg_match('/\t/', file_get_contents($file)), + "{$file->getPathname()} has tabs in it"); + } + } + + private function _get_preamble($file) { + $lines = file($file); + $copy = array(); + for ($i = 0; $i < count($lines); $i++) { + $copy[] = rtrim($lines[$i]); + if (!strncmp($lines[$i], ' */', 3)) { + return $copy; + } + } + return $copy; + } + + public function helpers_are_static_test() { + $dir = new PhpCodeFilterIterator( + new GalleryCodeFilterIterator( + new RecursiveIteratorIterator( + new RecursiveDirectoryIterator(DOCROOT)))); + foreach ($dir as $file) { + if (basename(dirname($file)) == "helpers") { + foreach (file($file) as $line) { + $this->assert_true( + !preg_match("/\sfunction\s.*\(/", $line) || + preg_match("/^\s*(private static function _|static function)/", $line), + "should be \"static function foo\" or \"private static function _foo\":\n" . + "$file\n$line\n"); + } + } + } + } +} + +class PhpCodeFilterIterator extends FilterIterator { + public function accept() { + $path_name = $this->getInnerIterator()->getPathName(); + return (substr($path_name, -4) == ".php" && + !(strpos($path_name, VARPATH) === 0)); + } +} + +class GalleryCodeFilterIterator extends FilterIterator { + public function accept() { + // Skip anything that we didn"t write + $path_name = $this->getInnerIterator()->getPathName(); + return !( + strpos($path_name, ".svn") || + strpos($path_name, "core/views/kohana_profiler.php") !== false || + strpos($path_name, DOCROOT . "test") !== false || + strpos($path_name, DOCROOT . "var") !== false || + strpos($path_name, MODPATH . "forge") !== false || + strpos($path_name, APPPATH . "views/kohana_error_page.php") !== false || + strpos($path_name, MODPATH . "gallery_unit_test/views/kohana_error_page.php") !== false || + strpos($path_name, MODPATH . "gallery_unit_test/views/kohana_unit_test_cli.php") !== false || + strpos($path_name, MODPATH . "unit_test") !== false || + strpos($path_name, MODPATH . "exif/lib") !== false || + strpos($path_name, MODPATH . "user/lib/PasswordHash") !== false || + strpos($path_name, DOCROOT . "lib/swfupload") !== false || + strpos($path_name, SYSPATH) !== false || + substr($path_name, -1, 1) == "~"); + } +} diff --git a/modules/gallery/tests/I18n_Test.php b/modules/gallery/tests/I18n_Test.php new file mode 100644 index 00000000..9010606a --- /dev/null +++ b/modules/gallery/tests/I18n_Test.php @@ -0,0 +1,108 @@ + 'en', + 'default_locale' => 'te_ST', + 'locale_dir' => VARPATH . 'locale/'); + $this->i18n = I18n::instance($config); + + ORM::factory("incoming_translation") + ->where("locale", "te_ST") + ->delete_all(); + + $messages_te_ST = array( + array('Hello world', 'Hallo Welt'), + array(array('one' => 'One item has been added', + 'other' => '%count elements have been added'), + array('one' => 'Ein Element wurde hinzugefuegt.', + 'other' => '%count Elemente wurden hinzugefuegt.')), + array('Hello %name, how are you today?', 'Hallo %name, wie geht es Dir heute?')); + + foreach ($messages_te_ST as $data) { + list ($message, $translation) = $data; + $entry = ORM::factory("incoming_translation"); + $entry->key = I18n::get_message_key($message); + $entry->message = serialize($message); + $entry->translation = serialize($translation); + $entry->locale = 'te_ST'; + $entry->revision = null; + $entry->save(); + } + } + + public function get_locale_test() { + $locale = $this->i18n->locale(); + $this->assert_equal("te_ST", $locale); + } + + public function set_locale_test() { + $this->i18n->locale("de_DE"); + $locale = $this->i18n->locale(); + $this->assert_equal("de_DE", $locale); + } + + public function translate_simple_test() { + $result = $this->i18n->translate('Hello world'); + $this->assert_equal('Hallo Welt', $result); + } + + public function translate_simple_root_fallback_test() { + $result = $this->i18n->translate('Hello world zzz'); + $this->assert_equal('Hello world zzz', $result); + } + + public function translate_plural_other_test() { + $result = $this->i18n->translate(array('one' => 'One item has been added', + 'other' => '%count elements have been added'), + array('count' => 5)); + $this->assert_equal('5 Elemente wurden hinzugefuegt.', $result); + } + + public function translate_plural_one_test() { + $result = $this->i18n->translate(array('one' => 'One item has been added', + 'other' => '%count elements have been added'), + array('count' => 1)); + $this->assert_equal('Ein Element wurde hinzugefuegt.', $result); + } + + public function translate_interpolate_test() { + $result = $this->i18n->translate('Hello %name, how are you today?', array('name' => 'John')); + $this->assert_equal('Hallo John, wie geht es Dir heute?', $result); + } + + public function translate_interpolate_missing_value_test() { + $result = $this->i18n->translate('Hello %name, how are you today?', array('foo' => 'bar')); + $this->assert_equal('Hallo %name, wie geht es Dir heute?', $result); + } + + public function translate_plural_zero_test() { + // te_ST has the same plural rules as en and de. + // For count 0, plural form "other" should be used. + $result = $this->i18n->translate(array('one' => 'One item has been added', + 'other' => '%count elements have been added'), + array('count' => 0)); + $this->assert_equal('0 Elemente wurden hinzugefuegt.', $result); + } +} \ No newline at end of file diff --git a/modules/gallery/tests/Item_Model_Test.php b/modules/gallery/tests/Item_Model_Test.php new file mode 100644 index 00000000..615b8997 --- /dev/null +++ b/modules/gallery/tests/Item_Model_Test.php @@ -0,0 +1,143 @@ +assert_true(!empty($item->created)); + $this->assert_true(!empty($item->updated)); + } + + private function create_random_item() { + $item = ORM::factory("item"); + /* Set all required fields (values are irrelevant) */ + $item->name = rand(); + $item->type = "photo"; + return $item->add_to_parent(ORM::factory("item", 1)); + } + + public function updating_doesnt_change_created_date_test() { + $item = self::create_random_item(); + + // Force the creation date to something well known + $db = Database::instance(); + $db->update("items", array("created" => 0, "updated" => 0), array("id" => $item->id)); + $item->reload(); + $item->title = "foo"; // force a change + $item->save(); + + $this->assert_true(empty($item->created)); + $this->assert_true(!empty($item->updated)); + } + + public function updating_view_count_only_doesnt_change_updated_date_test() { + $item = self::create_random_item(); + $item->reload(); + $this->assert_same(0, $item->view_count); + + // Force the updated date to something well known + $db = Database::instance(); + $db->update("items", array("updated" => 0), array("id" => $item->id)); + $item->reload(); + $item->view_count++; + $item->save(); + + $this->assert_same(1, $item->view_count); + $this->assert_true(empty($item->updated)); + } + + public function move_photo_test() { + // Create a test photo + $item = self::create_random_item(); + + file_put_contents($item->thumb_path(), "thumb"); + file_put_contents($item->resize_path(), "resize"); + file_put_contents($item->file_path(), "file"); + + $original_name = $item->name; + $new_name = rand(); + + // Now rename it + $item->rename($new_name)->save(); + + // Expected: the name changed, the name is now baked into all paths, and all files were moved. + $this->assert_equal($new_name, $item->name); + $this->assert_equal($new_name, basename($item->file_path())); + $this->assert_equal($new_name, basename($item->thumb_path())); + $this->assert_equal($new_name, basename($item->resize_path())); + $this->assert_equal("thumb", file_get_contents($item->thumb_path())); + $this->assert_equal("resize", file_get_contents($item->resize_path())); + $this->assert_equal("file", file_get_contents($item->file_path())); + } + + public function move_album_test() { + // Create an album with a photo in it + $root = ORM::factory("item", 1); + $album = album::create($root, rand(), rand(), rand()); + $photo = ORM::factory("item"); + $photo->name = rand(); + $photo->type = "photo"; + $photo->add_to_parent($album); + + file_put_contents($photo->thumb_path(), "thumb"); + file_put_contents($photo->resize_path(), "resize"); + file_put_contents($photo->file_path(), "file"); + + $original_album_name = $album->name; + $original_photo_name = $photo->name; + $new_album_name = rand(); + + // Now rename the album + $album->rename($new_album_name)->save(); + $photo->reload(); + + // Expected: + // * the album name changed. + // * the album dirs are all moved + // * the photo's paths are all inside the albums paths + // * the photo files are all still intact and accessible + $this->assert_equal($new_album_name, $album->name); + $this->assert_equal($new_album_name, basename($album->file_path())); + $this->assert_equal($new_album_name, basename(dirname($album->thumb_path()))); + $this->assert_equal($new_album_name, basename(dirname($album->resize_path()))); + + $this->assert_same(0, strpos($photo->file_path(), $album->file_path())); + $this->assert_same(0, strpos($photo->thumb_path(), dirname($album->thumb_path()))); + $this->assert_same(0, strpos($photo->resize_path(), dirname($album->resize_path()))); + + $this->assert_equal("thumb", file_get_contents($photo->thumb_path())); + $this->assert_equal("resize", file_get_contents($photo->resize_path())); + $this->assert_equal("file", file_get_contents($photo->file_path())); + } + + public function item_rename_wont_accept_slash_test() { + // Create a test photo + $item = self::create_random_item(); + + $new_name = rand() . "/"; + + try { + $item->rename($new_name)->save(); + } catch (Exception $e) { + // pass + return; + } + $this->assert_false(true, "Item_Model::rename should not accept / characters"); + } +} diff --git a/modules/gallery/tests/Menu_Test.php b/modules/gallery/tests/Menu_Test.php new file mode 100644 index 00000000..c91aee0b --- /dev/null +++ b/modules/gallery/tests/Menu_Test.php @@ -0,0 +1,32 @@ +append(Menu::factory("link")->id("element_1")) + ->append(Menu::factory("dialog")->id("element_2")) + ->append(Menu::factory("submenu")->id("element_3") + ->append(Menu::factory("link")->id("element_3_1"))); + + $this->assert_equal("element_2", $menu->get("element_2")->id); + $this->assert_equal("element_3_1", $menu->get("element_3")->get("element_3_1")->id); + } +} \ No newline at end of file diff --git a/modules/gallery/tests/Movie_Helper_Test.php b/modules/gallery/tests/Movie_Helper_Test.php new file mode 100644 index 00000000..b92ef3f8 --- /dev/null +++ b/modules/gallery/tests/Movie_Helper_Test.php @@ -0,0 +1,46 @@ +assert_true(false, "Shouldn't create a movie with / in the name"); + } + + public function create_movie_shouldnt_allow_names_with_trailing_periods_test() { + $rand = rand(); + $root = ORM::factory("item", 1); + try { + $movie = movie::create($root, DOCROOT . "core/tests/test.jpg", "$rand.jpg.", $rand, $rand); + } catch (Exception $e) { + $this->assert_equal("@todo NAME_CANNOT_END_IN_PERIOD", $e->getMessage()); + return; + } + + $this->assert_true(false, "Shouldn't create a movie with trailing . in the name"); + } +} diff --git a/modules/gallery/tests/ORM_MPTT_Test.php b/modules/gallery/tests/ORM_MPTT_Test.php new file mode 100644 index 00000000..200c8a74 --- /dev/null +++ b/modules/gallery/tests/ORM_MPTT_Test.php @@ -0,0 +1,221 @@ +type = "album"; + $album->rand_key = ((float)mt_rand()) / (float)mt_getrandmax(); + $album->sort_column = "weight"; + $album->sort_order = "ASC"; + $album->add_to_parent($root); + + $this->assert_equal($album->parent()->right - 2, $album->left); + $this->assert_equal($album->parent()->right - 1, $album->right); + $this->assert_equal($album->parent()->level + 1, $album->level); + $this->assert_equal($album->parent()->id, $album->parent_id); + } + + public function add_hierarchy_test() { + $root = ORM::factory("item", 1); + $album1 = self::create_item_and_add_to_parent($root); + $album1_1 = self::create_item_and_add_to_parent($album1); + $album1_2 = self::create_item_and_add_to_parent($album1); + $album1_1_1 = self::create_item_and_add_to_parent($album1_1); + $album1_1_2 = self::create_item_and_add_to_parent($album1_1); + + $album1->reload(); + $this->assert_equal(9, $album1->right - $album1->left); + + $album1_1->reload(); + $this->assert_equal(5, $album1_1->right - $album1_1->left); + } + + public function delete_hierarchy_test() { + $root = ORM::factory("item", 1); + $album1 = self::create_item_and_add_to_parent($root); + $album1_1 = self::create_item_and_add_to_parent($album1); + $album1_2 = self::create_item_and_add_to_parent($album1); + $album1_1_1 = self::create_item_and_add_to_parent($album1_1); + $album1_1_2 = self::create_item_and_add_to_parent($album1_1); + + $album1_1->delete(); + $album1->reload(); + + // Now album1 contains only album1_2 + $this->assert_equal(3, $album1->right - $album1->left); + } + + public function move_to_test() { + $root = ORM::factory("item", 1); + $album1 = album::create($root, "move_to_test_1", "move_to_test_1"); + $album1_1 = album::create($album1, "move_to_test_1_1", "move_to_test_1_1"); + $album1_2 = album::create($album1, "move_to_test_1_2", "move_to_test_1_2"); + $album1_1_1 = album::create($album1_1, "move_to_test_1_1_1", "move_to_test_1_1_1"); + $album1_1_2 = album::create($album1_1, "move_to_test_1_1_2", "move_to_test_1_1_2"); + + $album1_2->reload(); + $album1_1_1->reload(); + + $album1_1_1->move_to($album1_2); + + $album1_1->reload(); + $album1_2->reload(); + + $this->assert_equal(3, $album1_1->right - $album1_1->left); + $this->assert_equal(3, $album1_2->right - $album1_2->left); + + $this->assert_equal( + array($album1_1_2->id => "move_to_test_1_1_2"), + $album1_1->children()->select_list()); + + $this->assert_equal( + array($album1_1_1->id => "move_to_test_1_1_1"), + $album1_2->children()->select_list()); + } + + public function parent_test() { + $root = ORM::factory("item", 1); + $album = self::create_item_and_add_to_parent($root); + + $parent = ORM::factory("item", 1); + $this->assert_equal($parent->id, $album->parent()->id); + } + + public function parents_test() { + $root = ORM::factory("item", 1); + $outer = self::create_item_and_add_to_parent($root); + $inner = self::create_item_and_add_to_parent($outer); + + $parent_ids = array(); + foreach ($inner->parents() as $parent) { + $parent_ids[] = $parent->id; + } + $this->assert_equal(array(1, $outer->id), $parent_ids); + } + + public function children_test() { + $root = ORM::factory("item", 1); + $outer = self::create_item_and_add_to_parent($root); + $inner1 = self::create_item_and_add_to_parent($outer); + $inner2 = self::create_item_and_add_to_parent($outer); + + $child_ids = array(); + foreach ($outer->children() as $child) { + $child_ids[] = $child->id; + } + $this->assert_equal(array($inner1->id, $inner2->id), $child_ids); + } + + public function children_limit_test() { + $root = ORM::factory("item", 1); + $outer = self::create_item_and_add_to_parent($root); + $inner1 = self::create_item_and_add_to_parent($outer); + $inner2 = self::create_item_and_add_to_parent($outer); + + $this->assert_equal(array($inner2->id => $inner2->name), + $outer->children(1, 1)->select_list('id')); + } + + public function children_count_test() { + $root = ORM::factory("item", 1); + $outer = self::create_item_and_add_to_parent($root); + $inner1 = self::create_item_and_add_to_parent($outer); + $inner2 = self::create_item_and_add_to_parent($outer); + + $this->assert_equal(2, $outer->children_count()); + } + + public function descendant_test() { + $root = ORM::factory("item", 1); + + $parent = ORM::factory("item"); + $parent->type = "album"; + $parent->rand_key = ((float)mt_rand()) / (float)mt_getrandmax(); + $parent->sort_column = "weight"; + $parent->sort_order = "ASC"; + $parent->add_to_parent($root); + + $photo = ORM::factory("item"); + $photo->type = "photo"; + $photo->add_to_parent($parent); + + $album1 = ORM::factory("item"); + $album1->type = "album"; + $album1->rand_key = ((float)mt_rand()) / (float)mt_getrandmax(); + $album1->sort_column = "weight"; + $album1->sort_order = "ASC"; + $album1->add_to_parent($parent); + + $photo1 = ORM::factory("item"); + $photo1->type = "photo"; + $photo1->add_to_parent($album1); + + $parent->reload(); + + $this->assert_equal(3, $parent->descendants()->count()); + $this->assert_equal(2, $parent->descendants(null, 0, "photo")->count()); + $this->assert_equal(1, $parent->descendants(null, 0, "album")->count()); + } + + public function descendant_limit_test() { + $root = ORM::factory("item", 1); + + $parent = self::create_item_and_add_to_parent($root); + $album1 = self::create_item_and_add_to_parent($parent); + $album2 = self::create_item_and_add_to_parent($parent); + $album3 = self::create_item_and_add_to_parent($parent); + + $parent->reload(); + $this->assert_equal(2, $parent->descendants(2)->count()); + } + + public function descendant_count_test() { + $root = ORM::factory("item", 1); + + $parent = ORM::factory("item"); + $parent->type = "album"; + $parent->add_to_parent($root); + + $photo = ORM::factory("item"); + $photo->type = "photo"; + $photo->add_to_parent($parent); + + $album1 = ORM::factory("item"); + $album1->type = "album"; + $album1->add_to_parent($parent); + + $photo1 = ORM::factory("item"); + $photo1->type = "photo"; + $photo1->add_to_parent($album1); + + $parent->reload(); + + $this->assert_equal(3, $parent->descendants_count()); + $this->assert_equal(2, $parent->descendants_count("photo")); + $this->assert_equal(1, $parent->descendants_count("album")); + } +} diff --git a/modules/gallery/tests/Photo_Helper_Test.php b/modules/gallery/tests/Photo_Helper_Test.php new file mode 100644 index 00000000..deb11bb9 --- /dev/null +++ b/modules/gallery/tests/Photo_Helper_Test.php @@ -0,0 +1,109 @@ +assert_equal(VARPATH . "albums/$rand.jpg", $photo->file_path()); + $this->assert_equal(VARPATH . "thumbs/{$rand}.jpg", $photo->thumb_path()); + $this->assert_equal(VARPATH . "resizes/{$rand}.jpg", $photo->resize_path()); + + $this->assert_true(is_file($photo->file_path()), "missing: {$photo->file_path()}"); + $this->assert_true(is_file($photo->resize_path()), "missing: {$photo->resize_path()}"); + $this->assert_true(is_file($photo->thumb_path()), "missing: {$photo->thumb_path()}"); + + $this->assert_equal($root->id, $photo->parent_id); // MPTT tests cover other hierarchy checks + $this->assert_equal("$rand.jpg", $photo->name); + $this->assert_equal($rand, $photo->title); + $this->assert_equal($rand, $photo->description); + $this->assert_equal("image/jpeg", $photo->mime_type); + $this->assert_equal($image_info[0], $photo->width); + $this->assert_equal($image_info[1], $photo->height); + + $this->assert_equal($photo->parent()->right - 2, $photo->left); + $this->assert_equal($photo->parent()->right - 1, $photo->right); + } + + public function create_conflicting_photo_test() { + $rand = rand(); + $root = ORM::factory("item", 1); + $photo1 = photo::create($root, DOCROOT . "core/tests/test.jpg", "$rand.jpg", $rand, $rand); + $photo2 = photo::create($root, DOCROOT . "core/tests/test.jpg", "$rand.jpg", $rand, $rand); + $this->assert_true($photo1->name != $photo2->name); + } + + public function create_photo_with_no_extension_test() { + $root = ORM::factory("item", 1); + try { + photo::create($root, "/tmp", "name", "title", "description"); + $this->assert_false("should fail with an exception"); + } catch (Exception $e) { + // pass + } + } + + public function thumb_url_test() { + $rand = rand(); + $root = ORM::factory("item", 1); + $photo = photo::create($root, DOCROOT . "core/tests/test.jpg", "$rand.jpg", $rand, $rand); + $this->assert_equal("http://./var/thumbs/{$rand}.jpg", $photo->thumb_url()); + } + + public function resize_url_test() { + $rand = rand(); + $root = ORM::factory("item", 1); + $album = album::create($root, $rand, $rand, $rand); + $photo = photo::create($album, DOCROOT . "core/tests/test.jpg", "$rand.jpg", $rand, $rand); + + $this->assert_equal("http://./var/resizes/{$rand}/{$rand}.jpg", $photo->resize_url()); + } + + public function create_photo_shouldnt_allow_names_with_slash_test() { + $rand = rand(); + $root = ORM::factory("item", 1); + try { + $photo = photo::create($root, DOCROOT . "core/tests/test.jpg", "$rand/.jpg", $rand, $rand); + } catch (Exception $e) { + // pass + return; + } + + $this->assert_true(false, "Shouldn't create a photo with / in the name"); + } + + public function create_photo_silently_trims_trailing_periods_test() { + $rand = rand(); + $root = ORM::factory("item", 1); + try { + $photo = photo::create($root, DOCROOT . "core/tests/test.jpg", "$rand.jpg.", $rand, $rand); + } catch (Exception $e) { + $this->assert_equal("@todo NAME_CANNOT_END_IN_PERIOD", $e->getMessage()); + return; + } + + $this->assert_true(false, "Shouldn't create a photo with trailing . in the name"); + } +} diff --git a/modules/gallery/tests/Photos_Controller_Test.php b/modules/gallery/tests/Photos_Controller_Test.php new file mode 100644 index 00000000..71319315 --- /dev/null +++ b/modules/gallery/tests/Photos_Controller_Test.php @@ -0,0 +1,74 @@ +_post = $_POST; + } + + public function teardown() { + $_POST = $this->_post; + } + + public function change_photo_test() { + $controller = new Photos_Controller(); + $root = ORM::factory("item", 1); + $photo = photo::create($root, DOCROOT . "core/tests/test.jpg", "test.jpeg", "test", "test"); + $orig_name = $photo->name; + + $_POST["filename"] = "test.jpeg"; + $_POST["name"] = "new name"; + $_POST["title"] = "new title"; + $_POST["description"] = "new description"; + $_POST["csrf"] = access::csrf_token(); + access::allow(group::everybody(), "edit", $root); + + ob_start(); + $controller->_update($photo); + $results = ob_get_contents(); + ob_end_clean(); + + $this->assert_equal( + json_encode(array("result" => "success", + "location" => "http://./index.php/test.jpeg")), + $results); + $this->assert_equal("new title", $photo->title); + $this->assert_equal("new description", $photo->description); + + // We don't change the name, yet. + $this->assert_equal($orig_name, $photo->name); + } + + public function change_photo_no_csrf_fails_test() { + $controller = new Photos_Controller(); + $root = ORM::factory("item", 1); + $photo = photo::create($root, DOCROOT . "core/tests/test.jpg", "test", "test", "test"); + $_POST["name"] = "new name"; + $_POST["title"] = "new title"; + $_POST["description"] = "new description"; + access::allow(group::everybody(), "edit", $root); + + try { + $controller->_update($photo); + $this->assert_true(false, "This should fail"); + } catch (Exception $e) { + // pass + } + } +} diff --git a/modules/gallery/tests/REST_Controller_Test.php b/modules/gallery/tests/REST_Controller_Test.php new file mode 100644 index 00000000..8fb04d86 --- /dev/null +++ b/modules/gallery/tests/REST_Controller_Test.php @@ -0,0 +1,197 @@ +_post = $_POST; + $this->mock_controller = new Mock_RESTful_Controller("mock"); + $this->mock_not_loaded_controller = new Mock_RESTful_Controller("mock_not_loaded"); + $_POST = array(); + } + + public function teardown() { + $_POST = $this->_post; + } + + public function dispatch_index_test() { + $_SERVER["REQUEST_METHOD"] = "GET"; + $_POST["_method"] = ""; + $this->mock_controller->__call("index", ""); + $this->assert_equal("index", $this->mock_controller->method_called); + } + + public function dispatch_show_test() { + $_SERVER["REQUEST_METHOD"] = "GET"; + $_POST["_method"] = ""; + $this->mock_controller->__call("3", ""); + $this->assert_equal("show", $this->mock_controller->method_called); + $this->assert_equal("Mock_Model", get_class($this->mock_controller->resource)); + } + + public function dispatch_update_test() { + $_SERVER["REQUEST_METHOD"] = "POST"; + $_POST["_method"] = "PUT"; + $_POST["csrf"] = access::csrf_token(); + $this->mock_controller->__call("3", ""); + $this->assert_equal("update", $this->mock_controller->method_called); + $this->assert_equal("Mock_Model", get_class($this->mock_controller->resource)); + } + + public function dispatch_update_fails_without_csrf_test() { + $_SERVER["REQUEST_METHOD"] = "POST"; + $_POST["_method"] = "PUT"; + try { + $this->mock_controller->__call("3", ""); + $this->assert_false(true, "this should fail with a forbidden exception"); + } catch (Exception $e) { + // pass + } + } + + public function dispatch_delete_test() { + $_SERVER["REQUEST_METHOD"] = "POST"; + $_POST["_method"] = "DELETE"; + $_POST["csrf"] = access::csrf_token(); + $this->mock_controller->__call("3", ""); + $this->assert_equal("delete", $this->mock_controller->method_called); + $this->assert_equal("Mock_Model", get_class($this->mock_controller->resource)); + } + + public function dispatch_delete_fails_without_csrf_test() { + $_SERVER["REQUEST_METHOD"] = "POST"; + $_POST["_method"] = "DELETE"; + try { + $this->mock_controller->__call("3", ""); + $this->assert_false(true, "this should fail with a forbidden exception"); + } catch (Exception $e) { + // pass + } + } + + public function dispatch_404_test() { + /* The dispatcher should throw a 404 if the resource isn't loaded and the method isn't POST. */ + $methods = array( + array("GET", ""), + array("POST", "PUT"), + array("POST", "DELETE")); + + foreach ($methods as $method) { + $_SERVER["REQUEST_METHOD"] = $method[0]; + $_POST["_method"] = $method[1]; + $exception_caught = false; + try { + $this->mock_not_loaded_controller->__call(rand(), ""); + } catch (Kohana_404_Exception $e) { + $exception_caught = true; + } + $this->assert_true($exception_caught, "$method[0], $method[1]"); + } + } + + public function dispatch_create_test() { + $_SERVER["REQUEST_METHOD"] = "POST"; + $_POST["_method"] = ""; + $_POST["csrf"] = access::csrf_token(); + $this->mock_not_loaded_controller->__call("", ""); + $this->assert_equal("create", $this->mock_not_loaded_controller->method_called); + $this->assert_equal( + "Mock_Not_Loaded_Model", get_class($this->mock_not_loaded_controller->resource)); + } + + public function dispatch_create_fails_without_csrf_test() { + $_SERVER["REQUEST_METHOD"] = "POST"; + $_POST["_method"] = ""; + try { + $this->mock_not_loaded_controller->__call("", ""); + $this->assert_false(true, "this should fail with a forbidden exception"); + } catch (Exception $e) { + // pass + } + } + + public function dispatch_form_test_add() { + $this->mock_controller->form_add("args"); + $this->assert_equal("form_add", $this->mock_controller->method_called); + $this->assert_equal("args", $this->mock_controller->resource); + } + + public function dispatch_form_test_edit() { + $this->mock_controller->form_edit("1"); + $this->assert_equal("form_edit", $this->mock_controller->method_called); + $this->assert_equal("Mock_Model", get_class($this->mock_controller->resource)); + } + + public function routes_test() { + $this->assert_equal("mock/form_add/args", router::routed_uri("form/add/mock/args")); + $this->assert_equal("mock/form_edit/args", router::routed_uri("form/edit/mock/args")); + $this->assert_equal(null, router::routed_uri("rest/args")); + } +} + +class Mock_RESTful_Controller extends REST_Controller { + public $method_called; + public $resource; + + public function __construct($type) { + $this->resource_type = $type; + parent::__construct(); + } + + public function _index() { + $this->method_called = "index"; + } + + public function _create($resource) { + $this->method_called = "create"; + $this->resource = $resource; + } + + public function _show($resource) { + $this->method_called = "show"; + $this->resource = $resource; + } + + public function _update($resource) { + $this->method_called = "update"; + $this->resource = $resource; + } + + public function _delete($resource) { + $this->method_called = "delete"; + $this->resource = $resource; + } + + public function _form_add($args) { + $this->method_called = "form_add"; + $this->resource = $args; + } + + public function _form_edit($resource) { + $this->method_called = "form_edit"; + $this->resource = $resource; + } +} + +class Mock_Model { + public $loaded = true; +} + +class Mock_Not_Loaded_Model { + public $loaded = false; +} diff --git a/modules/gallery/tests/REST_Helper_Test.php b/modules/gallery/tests/REST_Helper_Test.php new file mode 100644 index 00000000..1bfc63ab --- /dev/null +++ b/modules/gallery/tests/REST_Helper_Test.php @@ -0,0 +1,45 @@ +_post = $_POST; + } + + public function teardown() { + $_POST = $this->_post; + } + + public function request_method_test() { + foreach (array("GET", "POST") as $method) { + foreach (array("", "PUT", "DELETE") as $tunnel) { + if ($method == "GET") { + $expected = "GET"; + } else { + $expected = $tunnel == "" ? $method : $tunnel; + } + $_SERVER["REQUEST_METHOD"] = $method; + $_POST["_method"] = $tunnel; + + $this->assert_equal(strtolower(rest::request_method()), strtolower($expected), + "Request method: {$method}, tunneled: {$tunnel}"); + } + } + } +} diff --git a/modules/gallery/tests/Sendmail_Test.php b/modules/gallery/tests/Sendmail_Test.php new file mode 100644 index 00000000..64c1fff0 --- /dev/null +++ b/modules/gallery/tests/Sendmail_Test.php @@ -0,0 +1,115 @@ +to("receiver@someemail.com") + /* + * @todo figure out why this test fails so badly, when the following + * line is not supplied. It doesn't seem to be set by setup method + * as you would expect. + */ + ->from("from@gallery3.com") + ->subject("Test Email Unit test") + ->message("The mail message body") + ->send() + ->send_text; + + $this->assert_equal($expected, $result); + } + + public function sendmail_reply_to_test() { + $expected = "To: receiver@someemail.com\r\n" . + "From: from@gallery3.com\n" . + "Reply-To: reply-to@gallery3.com\r\n" . + "Subject: Test Email Unit test\r\n\r\n" . + "The mail message body"; + $result = Sendmail_For_Test::factory() + ->to("receiver@someemail.com") + ->subject("Test Email Unit test") + ->reply_to("reply-to@gallery3.com") + ->message("The mail message body") + ->send() + ->send_text; + $this->assert_equal($expected, $result); + } + + public function sendmail_html_message_test() { + $expected = "To: receiver@someemail.com\r\n" . + "From: from@gallery3.com\n" . + "Reply-To: public@gallery3.com\n" . + "MIME-Version: 1.0\n" . + "Content-type: text/html; charset=iso-8859-1\r\n" . + "Subject: Test Email Unit test\r\n\r\n" . + "

      This is an html msg

      "; + $result = Sendmail_For_Test::factory() + ->to("receiver@someemail.com") + ->subject("Test Email Unit test") + ->header("MIME-Version", "1.0") + ->header("Content-type", "text/html; charset=iso-8859-1") + ->message("

      This is an html msg

      ") + ->send() + ->send_text; + $this->assert_equal($expected, $result); + } + + public function sendmail_wrapped_message_test() { + $expected = "To: receiver@someemail.com\r\n" . + "From: from@gallery3.com\n" . + "Reply-To: public@gallery3.com\r\n" . + "Subject: Test Email Unit test\r\n\r\n" . + "This is a long message that needs to go\n" . + "over forty characters If we get lucky we\n" . + "might make it long enought to wrap a\n" . + "couple of times."; + $result = Sendmail_For_Test::factory() + ->to("receiver@someemail.com") + ->subject("Test Email Unit test") + ->line_length(40) + ->message("This is a long message that needs to go over forty characters " . + "If we get lucky we might make it long enought to wrap a couple " . + "of times.") + ->send() + ->send_text; + $this->assert_equal($expected, $result); + } +} + +class Sendmail_For_Test extends Sendmail { + static function factory() { + return new Sendmail_For_Test(); + } + + public function mail($to, $subject, $message, $headers) { + $this->send_text = "To: $to\r\n{$headers}\r\nSubject: $this->subject\r\n\r\n$message"; + return true; + } +} \ No newline at end of file diff --git a/modules/gallery/tests/Var_Test.php b/modules/gallery/tests/Var_Test.php new file mode 100644 index 00000000..82370631 --- /dev/null +++ b/modules/gallery/tests/Var_Test.php @@ -0,0 +1,49 @@ +assert_equal("original value", module::get_var("core", "Parameter")); + + module::set_var("core", "Parameter", "updated value"); + $this->assert_equal("updated value", module::get_var("core", "Parameter")); + } + + public function clear_parameter_test() { + module::set_var("core", "Parameter", "original value"); + $this->assert_equal("original value", module::get_var("core", "Parameter")); + + module::clear_var("core", "Parameter"); + $this->assert_equal(null, module::get_var("core", "Parameter")); + } + + public function incr_parameter_test() { + module::set_var("core", "Parameter", "original value"); + module::incr_var("core", "Parameter"); + $this->assert_equal("1", module::get_var("core", "Parameter")); + + module::set_var("core", "Parameter", "2"); + module::incr_var("core", "Parameter", "9"); + $this->assert_equal("11", module::get_var("core", "Parameter")); + + module::incr_var("core", "NonExistent", "9"); + $this->assert_equal(null, module::get_var("core", "NonExistent")); + } +} \ No newline at end of file diff --git a/modules/gallery/tests/images/DSC_0003.jpg b/modules/gallery/tests/images/DSC_0003.jpg new file mode 100644 index 00000000..5780d9d8 Binary files /dev/null and b/modules/gallery/tests/images/DSC_0003.jpg differ diff --git a/modules/gallery/tests/images/DSC_0005.jpg b/modules/gallery/tests/images/DSC_0005.jpg new file mode 100644 index 00000000..4d2b53a9 Binary files /dev/null and b/modules/gallery/tests/images/DSC_0005.jpg differ diff --git a/modules/gallery/tests/images/DSC_0017.jpg b/modules/gallery/tests/images/DSC_0017.jpg new file mode 100644 index 00000000..b7f7bb90 Binary files /dev/null and b/modules/gallery/tests/images/DSC_0017.jpg differ diff --git a/modules/gallery/tests/images/DSC_0019.jpg b/modules/gallery/tests/images/DSC_0019.jpg new file mode 100644 index 00000000..0ce25aa4 Binary files /dev/null and b/modules/gallery/tests/images/DSC_0019.jpg differ diff --git a/modules/gallery/tests/images/DSC_0067.jpg b/modules/gallery/tests/images/DSC_0067.jpg new file mode 100644 index 00000000..84f134cb Binary files /dev/null and b/modules/gallery/tests/images/DSC_0067.jpg differ diff --git a/modules/gallery/tests/images/DSC_0072.jpg b/modules/gallery/tests/images/DSC_0072.jpg new file mode 100644 index 00000000..dfad82b0 Binary files /dev/null and b/modules/gallery/tests/images/DSC_0072.jpg differ diff --git a/modules/gallery/tests/images/P4050088.jpg b/modules/gallery/tests/images/P4050088.jpg new file mode 100644 index 00000000..62f4749d Binary files /dev/null and b/modules/gallery/tests/images/P4050088.jpg differ diff --git a/modules/gallery/tests/selenium/Add_Album.html b/modules/gallery/tests/selenium/Add_Album.html new file mode 100644 index 00000000..ccd4d0b7 --- /dev/null +++ b/modules/gallery/tests/selenium/Add_Album.html @@ -0,0 +1,52 @@ + + + + + + +AddAlbum + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      AddAlbum
      open/index.php/albums/1
      clicklink=Add album
      typenameseleniumtest
      typetitleSelenium Test Album
      typedescriptionTest
      click//button[@type='button']
      assertTextPresentSelenium Test Album
      + + diff --git a/modules/gallery/tests/selenium/Add_Comment.html b/modules/gallery/tests/selenium/Add_Comment.html new file mode 100644 index 00000000..b4b96ed2 --- /dev/null +++ b/modules/gallery/tests/selenium/Add_Comment.html @@ -0,0 +1,52 @@ + + + + + + +Add comment + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      Add comment
      open/index.php/albums/1
      clickAndWaitgPhotoId-2
      typegAuthorTest
      typegEmailtest@gmail.com
      typegTextThis is a selenium test comment.
      click//button[@type='submit']
      assertTextPresentThis is a selenium test comment.
      + + diff --git a/modules/gallery/tests/selenium/Add_Item.html b/modules/gallery/tests/selenium/Add_Item.html new file mode 100644 index 00000000..741dff65 --- /dev/null +++ b/modules/gallery/tests/selenium/Add_Item.html @@ -0,0 +1,62 @@ + + + + + + +AddItem + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      AddItem
      open/index.php/albums/1
      clicklink=Add an item
      typenameseleniumitem.jpg
      typetitleSelenium Item
      typedescriptionTest item
      typefile/Users/ckieffer/Sites/gallery3.0/core/tests/images/DSC_0003.jpg
      click//button[@type='button']
      clicklink=X
      assertTextPresentSelenium Item
      + + diff --git a/modules/gallery/tests/selenium/Login.html b/modules/gallery/tests/selenium/Login.html new file mode 100644 index 00000000..5e17a3c7 --- /dev/null +++ b/modules/gallery/tests/selenium/Login.html @@ -0,0 +1,47 @@ + + + + + + +Login + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      Login
      open/index.php/albums/1
      clickgLoginLink
      typegNameadmin
      typegPasswordadmin
      clickAndWait//button[@type='button']
      clickAndWaitgUserProfileLink
      + + diff --git a/modules/gallery/tests/test.jpg b/modules/gallery/tests/test.jpg new file mode 100644 index 00000000..1f3525e5 Binary files /dev/null and b/modules/gallery/tests/test.jpg differ diff --git a/modules/gallery/views/admin_advanced_settings.html.php b/modules/gallery/views/admin_advanced_settings.html.php new file mode 100644 index 00000000..1f3825bd --- /dev/null +++ b/modules/gallery/views/admin_advanced_settings.html.php @@ -0,0 +1,34 @@ + +
      +

      +

      + +

      +
        +
      • + ") ?> +
      • +
      + + + + + + + + + module_name == "core" && $var->name == "_cache") continue ?> + + + + + + +
      module_name ?> name ?> + module_name/$var->name") ?>" + class="gDialogLink" + title=" $var->name, "module_name" => $var->module_name)) ?>"> + value ?> + +
      +
      diff --git a/modules/gallery/views/admin_block_log_entries.html.php b/modules/gallery/views/admin_block_log_entries.html.php new file mode 100644 index 00000000..db6313e1 --- /dev/null +++ b/modules/gallery/views/admin_block_log_entries.html.php @@ -0,0 +1,11 @@ + + diff --git a/modules/gallery/views/admin_block_news.html.php b/modules/gallery/views/admin_block_news.html.php new file mode 100644 index 00000000..cb276ae5 --- /dev/null +++ b/modules/gallery/views/admin_block_news.html.php @@ -0,0 +1,11 @@ + +
        + +
      • + "> +

        + +

        +
      • + +
      diff --git a/modules/gallery/views/admin_block_photo_stream.html.php b/modules/gallery/views/admin_block_photo_stream.html.php new file mode 100644 index 00000000..e8a4d933 --- /dev/null +++ b/modules/gallery/views/admin_block_photo_stream.html.php @@ -0,0 +1,14 @@ + + +

      + +

      diff --git a/modules/gallery/views/admin_block_platform.html.php b/modules/gallery/views/admin_block_platform.html.php new file mode 100644 index 00000000..6b79f047 --- /dev/null +++ b/modules/gallery/views/admin_block_platform.html.php @@ -0,0 +1,18 @@ + +
        +
      • + PHP_OS)) ?> +
      • +
      • + function_exists("apache_get_version") ? apache_get_version() : t("Unknown"))) ?> +
      • +
      • + phpversion())) ?> +
      • +
      • + Database::instance()->query("SELECT version() as v")->current()->v)) ?> +
      • +
      • + $load_average)) ?> +
      • +
      diff --git a/modules/gallery/views/admin_block_stats.html.php b/modules/gallery/views/admin_block_stats.html.php new file mode 100644 index 00000000..2d975073 --- /dev/null +++ b/modules/gallery/views/admin_block_stats.html.php @@ -0,0 +1,12 @@ + +
        +
      • + module::get_var("core", "version"))) ?> +
      • +
      • + $album_count)) ?> +
      • +
      • + $photo_count)) ?> +
      • +
      diff --git a/modules/gallery/views/admin_block_welcome.html.php b/modules/gallery/views/admin_block_welcome.html.php new file mode 100644 index 00000000..488fa908 --- /dev/null +++ b/modules/gallery/views/admin_block_welcome.html.php @@ -0,0 +1,20 @@ + +

      + +

      +
        +
      • + graphics and language settings.", + array("graphics_url" => url::site("admin/graphics"), + "language_url" => url::site("admin/languages"))) ?> +
      • +
      • + choose a theme, or customize the way it looks.", + array("theme_url" => url::site("admin/theme"), + "theme_details_url" => url::site("admin/theme_details"))) ?> +
      • +
      • + install modules to add cool features!", + array("modules_url" => url::site("admin/modules"))) ?> +
      • +
      diff --git a/modules/gallery/views/admin_dashboard.html.php b/modules/gallery/views/admin_dashboard.html.php new file mode 100644 index 00000000..c266d7e1 --- /dev/null +++ b/modules/gallery/views/admin_dashboard.html.php @@ -0,0 +1,38 @@ + + +
      + +
      diff --git a/modules/gallery/views/admin_graphics.html.php b/modules/gallery/views/admin_graphics.html.php new file mode 100644 index 00000000..08374471 --- /dev/null +++ b/modules/gallery/views/admin_graphics.html.php @@ -0,0 +1,28 @@ + + +
      +

      +

      + +

      + +

      + + +
      +

      + +
      +
      + diff --git a/modules/gallery/views/admin_graphics_gd.html.php b/modules/gallery/views/admin_graphics_gd.html.php new file mode 100644 index 00000000..cae68b74 --- /dev/null +++ b/modules/gallery/views/admin_graphics_gd.html.php @@ -0,0 +1,29 @@ + +
      gd["GD Version"] ? " gInstalledToolkit" : " gUnavailable" ?>"> + " alt="" /> +

      +

      + GD website for more information.", + array("url" => "http://www.boutell.com/gd")) ?> +

      + gd["GD Version"] && function_exists('imagerotate')): ?> +

      + $tk->gd["GD Version"])) ?> +

      +

      + +

      + gd["GD Version"]): ?> +

      + $tk->gd["GD Version"])) ?> +

      +

      + +

      + +

      + +

      + +
      diff --git a/modules/gallery/views/admin_graphics_graphicsmagick.html.php b/modules/gallery/views/admin_graphics_graphicsmagick.html.php new file mode 100644 index 00000000..720a9459 --- /dev/null +++ b/modules/gallery/views/admin_graphics_graphicsmagick.html.php @@ -0,0 +1,21 @@ + +
      graphicsmagick ? " gInstalledToolkit" : " gUnavailable" ?>"> +

      + " alt="" /> +

      + GraphicsMagick website for more information.", + array("url" => "http://www.graphicsmagick.org")) ?> +

      + graphicsmagick): ?> +

      + $tk->graphicsmagick)) ?> +

      +

      + +

      + +

      + +

      + +
      diff --git a/modules/gallery/views/admin_graphics_imagemagick.html.php b/modules/gallery/views/admin_graphics_imagemagick.html.php new file mode 100644 index 00000000..c7468eed --- /dev/null +++ b/modules/gallery/views/admin_graphics_imagemagick.html.php @@ -0,0 +1,21 @@ + +
      imagemagick ? " gInstalledToolkit" : " gUnavailable" ?>"> +

      + " alt="" /> +

      + ImageMagick website for more information.", + array("url" => "http://www.imagemagick.org")) ?> +

      + imagemagick): ?> +

      + $tk->imagemagick)) ?> +

      +

      + +

      + +

      + +

      + +
      diff --git a/modules/gallery/views/admin_graphics_none.html.php b/modules/gallery/views/admin_graphics_none.html.php new file mode 100644 index 00000000..5306a70d --- /dev/null +++ b/modules/gallery/views/admin_graphics_none.html.php @@ -0,0 +1,7 @@ + +
      +

      +

      + +

      +
      diff --git a/modules/gallery/views/admin_languages.html.php b/modules/gallery/views/admin_languages.html.php new file mode 100644 index 00000000..2b43f1b4 --- /dev/null +++ b/modules/gallery/views/admin_languages.html.php @@ -0,0 +1,15 @@ + +
      +

      + + + +

      + " + class="gDialogLink"> + + + +

      + +
      diff --git a/modules/gallery/views/admin_maintenance.html.php b/modules/gallery/views/admin_maintenance.html.php new file mode 100644 index 00000000..bc060a7b --- /dev/null +++ b/modules/gallery/views/admin_maintenance.html.php @@ -0,0 +1,181 @@ + +
      +

      +

      + +

      + +
      +

      + + + + + + + + + + + + + +
      + + + + + +
      + name ?> + + description ?> + + callback?csrf=$csrf") ?>" + class="gDialogLink"> + + +
      +
      + + count()): ?> +
      +

      + " + class="gButtonLink ui-icon-left ui-state-default ui-corner-all right"> + + + + + + + + + + + + + "> + + + + + + + + +
      + + + + + + + + + + + +
      + updated) ?> + + name ?> + + done): ?> + state == "cancelled"): ?> + + + + state == "stalled"): ?> + + + $task->percent_complete)) ?> + + + status ?> + + owner()->name ?> + + state == "stalled"): ?> + id?csrf=$csrf") ?>"> + + + + id?csrf=$csrf") ?>"> + + +
      +
      + + + count()): ?> +
      + " + class="gButtonLink ui-icon-left ui-state-default ui-corner-all right"> + + +

      + + + + + + + + + + + "> + + + + + + + + +
      + + + + + + + + + + + +
      + updated) ?> + + name ?> + + state == "success"): ?> + + state == "error"): ?> + + state == "cancelled"): ?> + + + + status ?> + + owner()->name ?> + + done): ?> + id?csrf=$csrf") ?>"> + + + + id?csrf=$csrf") ?>"> + + + id?csrf=$csrf") ?>"> + + + +
      +
      + +
      diff --git a/modules/gallery/views/admin_maintenance_task.html.php b/modules/gallery/views/admin_maintenance_task.html.php new file mode 100644 index 00000000..1ee02311 --- /dev/null +++ b/modules/gallery/views/admin_maintenance_task.html.php @@ -0,0 +1,32 @@ + + +
      +
      +
      +
      + + +
      +
      diff --git a/modules/gallery/views/admin_modules.html.php b/modules/gallery/views/admin_modules.html.php new file mode 100644 index 00000000..3fddd6cd --- /dev/null +++ b/modules/gallery/views/admin_modules.html.php @@ -0,0 +1,32 @@ + +
      +

      +

      + +

      + +
      "> + + + + + + + + + + $module_info): ?> + "> + $module_name); ?> + locked) $data["disabled"] = 1; ?> + + + + + + + +
      name) ?> version ?> description) ?>
      + "/> +
      +
      diff --git a/modules/gallery/views/admin_theme_details.html.php b/modules/gallery/views/admin_theme_details.html.php new file mode 100644 index 00000000..eb450b16 --- /dev/null +++ b/modules/gallery/views/admin_theme_details.html.php @@ -0,0 +1,6 @@ + +
      +

      + + +
      diff --git a/modules/gallery/views/admin_themes.html.php b/modules/gallery/views/admin_themes.html.php new file mode 100644 index 00000000..f85bce70 --- /dev/null +++ b/modules/gallery/views/admin_themes.html.php @@ -0,0 +1,89 @@ + + + +

      +

      + +

      + +
      +

      +
      + " + alt="name ?>" /> +

      name ?>

      +

      + description ?> +

      +
      + +

      + +
      + +
      +

      +
      + " + alt="name ?>" /> +

      name ?>

      +

      + description ?> +

      +
      + +

      + +
      \ No newline at end of file diff --git a/modules/gallery/views/admin_themes_preview.html.php b/modules/gallery/views/admin_themes_preview.html.php new file mode 100644 index 00000000..a7aea172 --- /dev/null +++ b/modules/gallery/views/admin_themes_preview.html.php @@ -0,0 +1,7 @@ + +

      + "> + %theme_name", array("theme_name" => $info->name)) ?> + +

      + diff --git a/modules/gallery/views/after_install.html.php b/modules/gallery/views/after_install.html.php new file mode 100644 index 00000000..aa26858a --- /dev/null +++ b/modules/gallery/views/after_install.html.php @@ -0,0 +1,29 @@ + +

      + +

      + +

      + +

      + +

      + %user_name account. The very first thing you should do is to change your password to something that you'll remember.", array("user_name" => $user->name)) ?> +

      + +

      + id}") ?>" + title="" + id="gAfterInstallChangePasswordLink" class="gButtonLink ui-state-default ui-corners-all"> + +

      + +

      + Gallery website has news and information about Gallery Project and community.", array("url" => "http://gallery.menalto.com")) ?> +

      + +

      + documentation site or you can ask for help in the forums!", array("codex_url" => "http://codex.gallery2.org/Main_Page", "forum_url" => "http://gallery.menalto.com/forum")) ?> +

    diff --git a/modules/gallery/views/after_install_loader.html.php b/modules/gallery/views/after_install_loader.html.php new file mode 100644 index 00000000..baf91eed --- /dev/null +++ b/modules/gallery/views/after_install_loader.html.php @@ -0,0 +1,7 @@ + +" + href=""/> + diff --git a/modules/gallery/views/form.html.php b/modules/gallery/views/form.html.php new file mode 100644 index 00000000..ec2a56a9 --- /dev/null +++ b/modules/gallery/views/form.html.php @@ -0,0 +1,75 @@ + +"; +} +if ($title) { + print $title; +} + +if (!function_exists("DrawForm")) { + function DrawForm($inputs, $level=1) { + $error_messages = array(); + $prefix = str_repeat(" ", $level); + $haveGroup = false; + // On the first level, make sure we have a group if not add the
      tag now + if ($level == 1) { + foreach ($inputs as $input) { + $haveGroup |= $input->type == 'group'; + } + if (!$haveGroup) { + print "$prefix
        \n"; + } + } + + foreach ($inputs as $input) { + if ($input->type == 'group') { + print "$prefix
        \n"; + print "$prefix {$input->label}\n"; + print "$prefix
          \n"; + + DrawForm($input->inputs, $level + 2); + print "$prefix
        \n"; + + // Since hidden fields can only have name and value attributes lets just render it now + $hidden_prefix = "$prefix "; + foreach ($input->hidden as $hidden) { + print "$prefix {$hidden->render()}\n"; + } + print "$prefix
        \n"; + } else { + if ($input->error_messages()) { + print "$prefix
      • \n"; + } else { + print "$prefix
      • \n"; + } + + if ($input->label()) { + print "$prefix {$input->label()}\n"; + } + print "$prefix {$input->render()}\n"; + if ($input->message()) { + print "$prefix

        {$input->message()}

        \n"; + } + if ($input->error_messages()) { + foreach ($input->error_messages() as $error_message) { + print "$prefix

        \n"; + print "$prefix $error_message\n"; + print "$prefix

        \n"; + } + } + print "$prefix
      • \n"; + } + } + if ($level == 1 && !$haveGroup) { + print "$prefix
      \n"; + } + } +} +DrawForm($inputs); + +print($close); +?> diff --git a/modules/gallery/views/kohana_error_page.php b/modules/gallery/views/kohana_error_page.php new file mode 100644 index 00000000..d9bf9698 --- /dev/null +++ b/modules/gallery/views/kohana_error_page.php @@ -0,0 +1,118 @@ + + + + + + + <?= t("Something went wrong!") ?> + + + + admin ?> +
      +

      + +

      +

      + +

      + +

      + +

      + +
      + +
      +

      + +

      + + + + + + + diff --git a/modules/gallery/views/kohana_profiler.php b/modules/gallery/views/kohana_profiler.php new file mode 100644 index 00000000..c7534349 --- /dev/null +++ b/modules/gallery/views/kohana_profiler.php @@ -0,0 +1,35 @@ + + + +
      + + render(); ?> + +

      s

      +
      diff --git a/modules/gallery/views/l10n_client.html.php b/modules/gallery/views/l10n_client.html.php new file mode 100644 index 00000000..8f4092c7 --- /dev/null +++ b/modules/gallery/views/l10n_client.html.php @@ -0,0 +1,31 @@ + + diff --git a/modules/gallery/views/maintenance.html.php b/modules/gallery/views/maintenance.html.php new file mode 100644 index 00000000..f80b6e7a --- /dev/null +++ b/modules/gallery/views/maintenance.html.php @@ -0,0 +1,50 @@ + + + + + <?= t("Gallery - Maintenance Mode") ?> + + + + +

      + +

      +

      + +

      + + + + + diff --git a/modules/gallery/views/move_browse.html.php b/modules/gallery/views/move_browse.html.php new file mode 100644 index 00000000..4f69c0e9 --- /dev/null +++ b/modules/gallery/views/move_browse.html.php @@ -0,0 +1,47 @@ + + +

      + type == "photo"): ?> + + type == "movie"): ?> + + type == "album"): ?> + + +

      +
      +
        +
      • + +
      • +
      +
      id") ?>"> + + + " disabled="disabled"/> +
      +
      diff --git a/modules/gallery/views/move_tree.html.php b/modules/gallery/views/move_tree.html.php new file mode 100644 index 00000000..a3a4bc8f --- /dev/null +++ b/modules/gallery/views/move_tree.html.php @@ -0,0 +1,19 @@ + +thumb_tag(array(), 25); ?> +is_descendant($parent)): ?> + title ?> + + title ?> + + diff --git a/modules/gallery/views/permissions_browse.html.php b/modules/gallery/views/permissions_browse.html.php new file mode 100644 index 00000000..afd87c2b --- /dev/null +++ b/modules/gallery/views/permissions_browse.html.php @@ -0,0 +1,56 @@ + + +
      + +
        +
      • + AllowOverride FileInfo Options to fix this.", array("url" => "http://httpd.apache.org/docs/2.0/mod/core.html#allowoverride")) ?> +
      • +
      + + + +
      diff --git a/modules/gallery/views/permissions_form.html.php b/modules/gallery/views/permissions_form.html.php new file mode 100644 index 00000000..3dbd0d98 --- /dev/null +++ b/modules/gallery/views/permissions_form.html.php @@ -0,0 +1,94 @@ + +
      + +
      + + + + + + + + + + + + + + + name, $item) ?> + name, $item) ?> + name, $item) ?> + + + + + + + + + + + + + + + + + + + + + +
      name ?>
      display_name) ?> + <?= t('denied icon') ?> + + <?= t('locked icon') ?> + + + + <?= t('passive allowed icon') ?> + + + <?= t('inactive denied icon') ?> + + + + <?= t('inactive allowed icon') ?> + + + <?= t('passive denied icon') ?> + + + + <?= t('inactive allowed icon') ?> + + id == 1): ?> + <?= t('denied icon') ?> + + + <?= t('denied icon') ?> + + + + id == 1): ?> + <?= t('allowed icon') ?> + + + <?= t('allowed icon') ?> + + + + <?= t('inactive denied icon') ?> + +
      +
      +
      diff --git a/modules/gallery/views/quick_pane.html.php b/modules/gallery/views/quick_pane.html.php new file mode 100644 index 00000000..95de972b --- /dev/null +++ b/modules/gallery/views/quick_pane.html.php @@ -0,0 +1,108 @@ + +type == "photo"): ?> + +type == "movie"): ?> + +type == "album"): ?> + + +id?page_type=$page_type") ?>" + title=""> + + + + + +is_photo() && graphics::can("rotate")): ?> +id/ccw?csrf=$csrf&page_type=$page_type") ?>" + title=""> + + + + + +id/cw?csrf=$csrf&page_type=$page_type") ?>" + title=""> + + + + + + + + +type == "photo"): ?> + +type == "movie"): ?> + +type == "album"): ?> + + +id") ?>" + title=""> + + + + + + + +parent())): ?> +type == "photo"): ?> + +type == "movie"): ?> + +type == "album"): ?> +album_cover_item_id)): ?> +album_cover_item_id) ? " ui-state-disabled" : "" ?> + + + +id?csrf=$csrf&page_type=$page_type") ?>" + title=""> + + + + + +type == "photo"): ?> + + +type == "movie"): ?> + + +type == "album"): ?> + + + +id?csrf=$csrf&page_type=$page_type") ?>" ref="" id="gQuickDelete" title=""> + + + + + + +is_album()): ?> +"> + + + + + + + diff --git a/modules/gallery/views/scaffold.html.php b/modules/gallery/views/scaffold.html.php new file mode 100644 index 00000000..765464b5 --- /dev/null +++ b/modules/gallery/views/scaffold.html.php @@ -0,0 +1,169 @@ + + + + Gallery3 Scaffold + + + +
      +
      + "/> +
      +
      +

      Gallery3 Scaffold

      +

      + This is + a scaffold: + a temporary structure built to support the developers as + they create the real product. As we flesh out Gallery 3, + we'll make it possible for you to peer inside and see the + application taking shape. Eventually, this page will go + away and you'll start in the application itself. In the + meantime, here are some useful links to get you started. +

      + + 0): ?> +
      +

      + + ( albums, photos, comments, tags) +

      +
      + + +
      +
      + Generate Test Data +

      + add: [ + + + + ] photos and albums +

      +

      + add: [ + + + + ] albums only +

      +

      + add: [ + + + + ] comments +

      +

      + add: [ + + + + ] tags +

      +
      +
      + Packaging + ">Make Package +
      +
      +
      +
      + + diff --git a/modules/gallery/views/simple_uploader.html.php b/modules/gallery/views/simple_uploader.html.php new file mode 100644 index 00000000..b6725c31 --- /dev/null +++ b/modules/gallery/views/simple_uploader.html.php @@ -0,0 +1,249 @@ + + + + + +
      "> +
      + $item->title)) ?> +
      +
      + +
      + +
        +
      • + suhosin.session.encrypt setting from Suhosin. You must disable this setting to upload photos.", + array("encrypt_url" => "http://www.hardened-php.net/suhosin/configuration.html#suhosin.session.encrypt", + "suhosin_url" => "http://www.hardened-php.net/suhosin/")) ?> +
      • +
      + + +

      + +

      +
        + parents() as $parent): ?> +
      • title ?>
      • + +
      • title ?>
      • +
      + +

      +
      +
      +
      + +
      + + + + +
      + + + + -- cgit v1.2.3