platform 3.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.gitignore +21 -0
- data/.rspec +2 -0
- data/Gemfile +14 -0
- data/Gemfile.lock +191 -0
- data/MIT-LICENSE +20 -0
- data/README.rdoc +5 -0
- data/Rakefile +37 -0
- data/app/assets/images/platform/.gitkeep +0 -0
- data/app/assets/images/platform/accept.png +0 -0
- data/app/assets/images/platform/action_tab_bkgd.gif +0 -0
- data/app/assets/images/platform/action_tab_white_bkgd.gif +0 -0
- data/app/assets/images/platform/add.png +0 -0
- data/app/assets/images/platform/apps/app_icon.gif +0 -0
- data/app/assets/images/platform/apps/app_logo.gif +0 -0
- data/app/assets/images/platform/arrow_down.gif +0 -0
- data/app/assets/images/platform/arrow_down.png +0 -0
- data/app/assets/images/platform/arrow_down_grey.png +0 -0
- data/app/assets/images/platform/arrow_right.gif +0 -0
- data/app/assets/images/platform/arrow_up.png +0 -0
- data/app/assets/images/platform/arrow_up_grey.png +0 -0
- data/app/assets/images/platform/bullet_go.png +0 -0
- data/app/assets/images/platform/buttons.png +0 -0
- data/app/assets/images/platform/cancel.png +0 -0
- data/app/assets/images/platform/clipboard_icon.gif +0 -0
- data/app/assets/images/platform/close.gif +0 -0
- data/app/assets/images/platform/cross.png +0 -0
- data/app/assets/images/platform/default_app_icon.gif +0 -0
- data/app/assets/images/platform/default_app_logo.gif +0 -0
- data/app/assets/images/platform/delete.png +0 -0
- data/app/assets/images/platform/disk.png +0 -0
- data/app/assets/images/platform/exclamation.png +0 -0
- data/app/assets/images/platform/eye.png +0 -0
- data/app/assets/images/platform/eye_not.png +0 -0
- data/app/assets/images/platform/field_sprite.gif +0 -0
- data/app/assets/images/platform/find.png +0 -0
- data/app/assets/images/platform/globe.gif +0 -0
- data/app/assets/images/platform/help.png +0 -0
- data/app/assets/images/platform/help/app_reg.png +0 -0
- data/app/assets/images/platform/help/app_reg_ext.png +0 -0
- data/app/assets/images/platform/help/app_reg_web.png +0 -0
- data/app/assets/images/platform/help/auth_desktop.png +0 -0
- data/app/assets/images/platform/help/auth_iframe.png +0 -0
- data/app/assets/images/platform/help/auth_iphone.png +0 -0
- data/app/assets/images/platform/help/auth_web.png +0 -0
- data/app/assets/images/platform/help/authorize.png +0 -0
- data/app/assets/images/platform/help/ext.png +0 -0
- data/app/assets/images/platform/help/login.png +0 -0
- data/app/assets/images/platform/help/login_desktop.png +0 -0
- data/app/assets/images/platform/help/login_iphone.png +0 -0
- data/app/assets/images/platform/help/login_web.png +0 -0
- data/app/assets/images/platform/help2.png +0 -0
- data/app/assets/images/platform/information.png +0 -0
- data/app/assets/images/platform/keyboard.png +0 -0
- data/app/assets/images/platform/language_selector_arrow.gif +0 -0
- data/app/assets/images/platform/left_quote.png +0 -0
- data/app/assets/images/platform/lightning.png +0 -0
- data/app/assets/images/platform/loading.gif +0 -0
- data/app/assets/images/platform/loading2.gif +0 -0
- data/app/assets/images/platform/loading3.gif +0 -0
- data/app/assets/images/platform/loading_animation.gif +0 -0
- data/app/assets/images/platform/loading_large.gif +0 -0
- data/app/assets/images/platform/lock.png +0 -0
- data/app/assets/images/platform/lock_add.png +0 -0
- data/app/assets/images/platform/lock_delete.png +0 -0
- data/app/assets/images/platform/lock_open.png +0 -0
- data/app/assets/images/platform/medals/bronze.png +0 -0
- data/app/assets/images/platform/medals/gold.png +0 -0
- data/app/assets/images/platform/medals/runner.png +0 -0
- data/app/assets/images/platform/medals/silver.png +0 -0
- data/app/assets/images/platform/minus_node.png +0 -0
- data/app/assets/images/platform/oauth/perm_tile.gif +0 -0
- data/app/assets/images/platform/oauth/right_grey.png +0 -0
- data/app/assets/images/platform/pencil.png +0 -0
- data/app/assets/images/platform/photo_silhouette.gif +0 -0
- data/app/assets/images/platform/pixel.gif +0 -0
- data/app/assets/images/platform/platform.png +0 -0
- data/app/assets/images/platform/platform2.png +0 -0
- data/app/assets/images/platform/platform3.png +0 -0
- data/app/assets/images/platform/platform4.png +0 -0
- data/app/assets/images/platform/platform5.png +0 -0
- data/app/assets/images/platform/plus.png +0 -0
- data/app/assets/images/platform/plus_node.png +0 -0
- data/app/assets/images/platform/random.png +0 -0
- data/app/assets/images/platform/random2.png +0 -0
- data/app/assets/images/platform/rating_star0.png +0 -0
- data/app/assets/images/platform/rating_star05.png +0 -0
- data/app/assets/images/platform/rating_star1.png +0 -0
- data/app/assets/images/platform/rating_stars.gif +0 -0
- data/app/assets/images/platform/rating_stars.psd +0 -0
- data/app/assets/images/platform/reply.png +0 -0
- data/app/assets/images/platform/right_quote.png +0 -0
- data/app/assets/images/platform/rotating_world.gif +0 -0
- data/app/assets/images/platform/script.png +0 -0
- data/app/assets/images/platform/script_edit.png +0 -0
- data/app/assets/images/platform/script_gear.png +0 -0
- data/app/assets/images/platform/site_sprite.gif +0 -0
- data/app/assets/images/platform/spinner.gif +0 -0
- data/app/assets/images/platform/star.png +0 -0
- data/app/assets/images/platform/table_edit.png +0 -0
- data/app/assets/images/platform/table_gear.png +0 -0
- data/app/assets/images/platform/table_multiple.png +0 -0
- data/app/assets/images/platform/thumb_down.png +0 -0
- data/app/assets/images/platform/thumb_up.png +0 -0
- data/app/assets/images/platform/top_left_stem.png +0 -0
- data/app/assets/images/platform/top_right_stem.png +0 -0
- data/app/assets/images/platform/translate_icn.gif +0 -0
- data/app/assets/images/platform/treeview/diffDoc.gif +0 -0
- data/app/assets/images/platform/treeview/diffFolder.gif +0 -0
- data/app/assets/images/platform/treeview/ftv2blank.gif +0 -0
- data/app/assets/images/platform/treeview/ftv2doc.gif +0 -0
- data/app/assets/images/platform/treeview/ftv2folderclosed.gif +0 -0
- data/app/assets/images/platform/treeview/ftv2folderopen.gif +0 -0
- data/app/assets/images/platform/treeview/ftv2lastnode.gif +0 -0
- data/app/assets/images/platform/treeview/ftv2link.gif +0 -0
- data/app/assets/images/platform/treeview/ftv2mlastnode.gif +0 -0
- data/app/assets/images/platform/treeview/ftv2mnode.gif +0 -0
- data/app/assets/images/platform/treeview/ftv2node.gif +0 -0
- data/app/assets/images/platform/treeview/ftv2plastnode.gif +0 -0
- data/app/assets/images/platform/treeview/ftv2pnode.gif +0 -0
- data/app/assets/images/platform/treeview/ftv2vertline.gif +0 -0
- data/app/assets/images/platform/wizard.png +0 -0
- data/app/assets/images/platform/world_link.png +0 -0
- data/app/assets/javascripts/platform/api_explorer.js +628 -0
- data/app/assets/javascripts/platform/application.js +9 -0
- data/app/assets/javascripts/platform/ftiens4.js +1197 -0
- data/app/assets/javascripts/platform/jsdk.js +539 -0
- data/app/assets/javascripts/platform/platform.js +447 -0
- data/app/assets/javascripts/platform/shortcut.js +223 -0
- data/app/assets/javascripts/platform/ua.js +147 -0
- data/app/assets/stylesheets/platform/api_explorer.css.scss +140 -0
- data/app/assets/stylesheets/platform/application.css.scss +6 -0
- data/app/assets/stylesheets/platform/components.css.scss +208 -0
- data/app/assets/stylesheets/platform/layout.css.scss +119 -0
- data/app/assets/stylesheets/platform/oauth.css +51 -0
- data/app/assets/stylesheets/platform/platform.css.scss +311 -0
- data/app/controllers/platform/admin/apps_controller.rb +99 -0
- data/app/controllers/platform/admin/base_controller.rb +60 -0
- data/app/controllers/platform/admin/categories_controller.rb +132 -0
- data/app/controllers/platform/admin/clientsdk_controller.rb +30 -0
- data/app/controllers/platform/admin/developers_controller.rb +30 -0
- data/app/controllers/platform/admin/exceptions_controller.rb +30 -0
- data/app/controllers/platform/admin/forum_controller.rb +34 -0
- data/app/controllers/platform/admin/metrics_controller.rb +42 -0
- data/app/controllers/platform/api/apps_controller.rb +40 -0
- data/app/controllers/platform/api/base_controller.rb +541 -0
- data/app/controllers/platform/apps_controller.rb +142 -0
- data/app/controllers/platform/base_controller.rb +127 -0
- data/app/controllers/platform/developer/api_explorer_controller.rb +56 -0
- data/app/controllers/platform/developer/apps_controller.rb +161 -0
- data/app/controllers/platform/developer/base_controller.rb +51 -0
- data/app/controllers/platform/developer/blog_controller.rb +29 -0
- data/app/controllers/platform/developer/dashboard_controller.rb +63 -0
- data/app/controllers/platform/developer/forum_controller.rb +85 -0
- data/app/controllers/platform/developer/help_controller.rb +113 -0
- data/app/controllers/platform/developer/info_controller.rb +41 -0
- data/app/controllers/platform/developer/registration_controller.rb +39 -0
- data/app/controllers/platform/developer/resources_controller.rb +30 -0
- data/app/controllers/platform/forum_controller.rb +74 -0
- data/app/controllers/platform/oauth_controller.rb +421 -0
- data/app/controllers/platform/ratings_controller.rb +61 -0
- data/app/helpers/platform/admin/categories_helper.rb +54 -0
- data/app/helpers/platform/apps_helper.rb +26 -0
- data/app/helpers/platform/developer/dashboard_helper.rb +42 -0
- data/app/helpers/platform/developer/help_helper.rb +45 -0
- data/app/helpers/platform_helper.rb +26 -0
- data/app/models/platform/application.rb +394 -0
- data/app/models/platform/application_category.rb +34 -0
- data/app/models/platform/application_developer.rb +30 -0
- data/app/models/platform/application_filter.rb +30 -0
- data/app/models/platform/application_log.rb +32 -0
- data/app/models/platform/application_log_filter.rb +34 -0
- data/app/models/platform/application_metric.rb +58 -0
- data/app/models/platform/application_metric_filter.rb +34 -0
- data/app/models/platform/application_permission.rb +30 -0
- data/app/models/platform/application_permission_filter.rb +30 -0
- data/app/models/platform/application_usage_metric.rb +58 -0
- data/app/models/platform/application_usage_metric_filter.rb +34 -0
- data/app/models/platform/application_user.rb +45 -0
- data/app/models/platform/application_user_filter.rb +34 -0
- data/app/models/platform/base_filter.rb +46 -0
- data/app/models/platform/category.rb +64 -0
- data/app/models/platform/daily_application_metric.rb +31 -0
- data/app/models/platform/developer.rb +45 -0
- data/app/models/platform/developer_filter.rb +26 -0
- data/app/models/platform/forum_message.rb +35 -0
- data/app/models/platform/forum_message_filter.rb +26 -0
- data/app/models/platform/forum_topic.rb +38 -0
- data/app/models/platform/forum_topic_filter.rb +26 -0
- data/app/models/platform/logged_exception.rb +290 -0
- data/app/models/platform/logged_exception_filter.rb +58 -0
- data/app/models/platform/media/image.rb +26 -0
- data/app/models/platform/media/media.rb +58 -0
- data/app/models/platform/monthly_application_metric.rb +31 -0
- data/app/models/platform/oauth/access_token.rb +57 -0
- data/app/models/platform/oauth/client_token.rb +38 -0
- data/app/models/platform/oauth/oauth_model_methods.rb +41 -0
- data/app/models/platform/oauth/oauth_token.rb +57 -0
- data/app/models/platform/oauth/oauth_token_filter.rb +34 -0
- data/app/models/platform/oauth/refresh_token.rb +47 -0
- data/app/models/platform/oauth/request_token.rb +50 -0
- data/app/models/platform/permission.rb +27 -0
- data/app/models/platform/rating.rb +43 -0
- data/app/models/platform/rating_filter.rb +30 -0
- data/app/models/platform/rollup_log.rb +27 -0
- data/app/models/platform/rollup_log_filter.rb +30 -0
- data/app/models/platform/total_application_metric.rb +40 -0
- data/app/models/platform/weekly_application_metric.rb +31 -0
- data/app/views/platform/admin/apps/_categories.html.erb +17 -0
- data/app/views/platform/admin/apps/_categories_scripts.html.erb +17 -0
- data/app/views/platform/admin/apps/_tabs.html.erb +25 -0
- data/app/views/platform/admin/apps/index.html.erb +32 -0
- data/app/views/platform/admin/apps/permissions.html.erb +7 -0
- data/app/views/platform/admin/apps/ratings.html.erb +7 -0
- data/app/views/platform/admin/apps/tokens.html.erb +18 -0
- data/app/views/platform/admin/apps/users.html.erb +7 -0
- data/app/views/platform/admin/apps/view.html.erb +170 -0
- data/app/views/platform/admin/categories/_tabs.html.erb +22 -0
- data/app/views/platform/admin/categories/category_assigner.html.erb +9 -0
- data/app/views/platform/admin/categories/category_assigner_tree.html.erb +81 -0
- data/app/views/platform/admin/categories/index.html.erb +106 -0
- data/app/views/platform/admin/categories/items.html.erb +153 -0
- data/app/views/platform/admin/categories/lb_update_application_category.html.erb +54 -0
- data/app/views/platform/admin/categories/lb_update_category.html.erb +64 -0
- data/app/views/platform/admin/categories/tree.html.erb +64 -0
- data/app/views/platform/admin/clientsdk/index.html.erb +89 -0
- data/app/views/platform/admin/common/_footer.html.erb +1 -0
- data/app/views/platform/admin/common/_header.html.erb +32 -0
- data/app/views/platform/admin/common/_lightbox_buttons.html.erb +5 -0
- data/app/views/platform/admin/common/_paginator.html.erb +20 -0
- data/app/views/platform/admin/developers/_tabs.html.erb +22 -0
- data/app/views/platform/admin/developers/index.html.erb +7 -0
- data/app/views/platform/admin/exceptions/_tabs.html.erb +22 -0
- data/app/views/platform/admin/exceptions/index.html.erb +7 -0
- data/app/views/platform/admin/forum/_tabs.html.erb +22 -0
- data/app/views/platform/admin/forum/index.html.erb +7 -0
- data/app/views/platform/admin/forum/messages.html.erb +7 -0
- data/app/views/platform/admin/metrics/_tabs.html.erb +25 -0
- data/app/views/platform/admin/metrics/application_log.html.erb +7 -0
- data/app/views/platform/admin/metrics/index.html.erb +9 -0
- data/app/views/platform/admin/metrics/rollup_log.html.erb +7 -0
- data/app/views/platform/admin/metrics/usage.html.erb +7 -0
- data/app/views/platform/apps/_actions_module.html.erb +3 -0
- data/app/views/platform/apps/_app_footer.html.erb +8 -0
- data/app/views/platform/apps/_app_header.html.erb +25 -0
- data/app/views/platform/apps/_apps_module.html.erb +42 -0
- data/app/views/platform/apps/_authorize_form.html.erb +11 -0
- data/app/views/platform/apps/_categories_module.html.erb +11 -0
- data/app/views/platform/apps/_featured_apps_module.html.erb +40 -0
- data/app/views/platform/apps/_left.html.erb +20 -0
- data/app/views/platform/apps/_monthly_users_module.html.erb +8 -0
- data/app/views/platform/apps/_paginator.html.erb +13 -0
- data/app/views/platform/apps/_rank_module.html.erb +18 -0
- data/app/views/platform/apps/_search_apps_module.html.erb +35 -0
- data/app/views/platform/apps/canvas_app.html.erb +15 -0
- data/app/views/platform/apps/index.html.erb +86 -0
- data/app/views/platform/apps/view.html.erb +71 -0
- data/app/views/platform/apps/xd.html.erb +11 -0
- data/app/views/platform/common/_footer.html.erb +1 -0
- data/app/views/platform/common/_header.html.erb +4 -0
- data/app/views/platform/common/_paginator.html.erb +32 -0
- data/app/views/platform/common/_scripts.html.erb +7 -0
- data/app/views/platform/common/_user_login.html.erb +11 -0
- data/app/views/platform/developer/api_explorer/history.html.erb +31 -0
- data/app/views/platform/developer/api_explorer/index.html.erb +134 -0
- data/app/views/platform/developer/api_explorer/oauth_lander.html.erb +4 -0
- data/app/views/platform/developer/api_explorer/options.html.erb +44 -0
- data/app/views/platform/developer/apps/_form.html.erb +340 -0
- data/app/views/platform/developer/apps/create_version.html.erb +19 -0
- data/app/views/platform/developer/apps/edit.html.erb +21 -0
- data/app/views/platform/developer/apps/index.html.erb +375 -0
- data/app/views/platform/developer/apps/new.html.erb +20 -0
- data/app/views/platform/developer/blog/index.html.erb +7 -0
- data/app/views/platform/developer/common/_footer.html.erb +1 -0
- data/app/views/platform/developer/common/_header.html.erb +34 -0
- data/app/views/platform/developer/dashboard/_apps_info.html.erb +84 -0
- data/app/views/platform/developer/dashboard/_discussions.html.erb +68 -0
- data/app/views/platform/developer/dashboard/_header.html.erb +12 -0
- data/app/views/platform/developer/dashboard/_reviews.html.erb +53 -0
- data/app/views/platform/developer/dashboard/_statistics.html.erb +105 -0
- data/app/views/platform/developer/dashboard/index.html.erb +85 -0
- data/app/views/platform/developer/dashboard/settings.html.erb +23 -0
- data/app/views/platform/developer/forum/_message.html.erb +17 -0
- data/app/views/platform/developer/forum/_messages.html.erb +14 -0
- data/app/views/platform/developer/forum/_new_message.html.erb +28 -0
- data/app/views/platform/developer/forum/_new_topic.html.erb +39 -0
- data/app/views/platform/developer/forum/index.html.erb +89 -0
- data/app/views/platform/developer/forum/topic.html.erb +28 -0
- data/app/views/platform/developer/help/_footer.html.erb +4 -0
- data/app/views/platform/developer/help/_header.html.erb +95 -0
- data/app/views/platform/developer/help/_navigation.html.erb +99 -0
- data/app/views/platform/developer/help/api.html.erb +120 -0
- data/app/views/platform/developer/help/credits.html.erb +77 -0
- data/app/views/platform/developer/help/index.html.erb +19 -0
- data/app/views/platform/developer/help/license.html.erb +586 -0
- data/app/views/platform/developer/help/oauth_app_login.html.erb +177 -0
- data/app/views/platform/developer/help/oauth_client_side.html.erb +264 -0
- data/app/views/platform/developer/help/oauth_desktop.html.erb +191 -0
- data/app/views/platform/developer/help/oauth_extensions.html.erb +342 -0
- data/app/views/platform/developer/help/oauth_intro.html.erb +371 -0
- data/app/views/platform/developer/help/oauth_mobile.html.erb +292 -0
- data/app/views/platform/developer/help/oauth_server_side.html.erb +603 -0
- data/app/views/platform/developer/help/oauth_trusted_client.html.erb +202 -0
- data/app/views/platform/developer/help/reference.html.erb +42 -0
- data/app/views/platform/developer/help/sdk_ios.html.erb +31 -0
- data/app/views/platform/developer/help/sdk_js.html.erb +202 -0
- data/app/views/platform/developer/info/_basic_info.html.erb +74 -0
- data/app/views/platform/developer/info/_header.html.erb +12 -0
- data/app/views/platform/developer/info/index.html.erb +23 -0
- data/app/views/platform/developer/registration/index.html.erb +134 -0
- data/app/views/platform/developer/resources/index.html.erb +23 -0
- data/app/views/platform/forum/_message.html.erb +17 -0
- data/app/views/platform/forum/_messages.html.erb +14 -0
- data/app/views/platform/forum/_new_message.html.erb +26 -0
- data/app/views/platform/forum/_new_topic.html.erb +38 -0
- data/app/views/platform/forum/_topic.html.erb +18 -0
- data/app/views/platform/forum/_topics.html.erb +74 -0
- data/app/views/platform/login/index.html.erb +31 -0
- data/app/views/platform/login/register.html.erb +55 -0
- data/app/views/platform/oauth/_authorization_box.html.erb +75 -0
- data/app/views/platform/oauth/_authorization_popup.html.erb +38 -0
- data/app/views/platform/oauth/_authorize_form.html.erb +11 -0
- data/app/views/platform/oauth/auth_failed.html.erb +0 -0
- data/app/views/platform/oauth/auth_success.html.erb +0 -0
- data/app/views/platform/oauth/authorize_desktop.html.erb +76 -0
- data/app/views/platform/oauth/authorize_failure_iframe.html.erb +1 -0
- data/app/views/platform/oauth/authorize_failure_mobile.html.erb +24 -0
- data/app/views/platform/oauth/authorize_failure_popup.html.erb +24 -0
- data/app/views/platform/oauth/authorize_failure_web.html.erb +1 -0
- data/app/views/platform/oauth/authorize_iframe.html.erb +16 -0
- data/app/views/platform/oauth/authorize_mobile.html.erb +1 -0
- data/app/views/platform/oauth/authorize_popup.html.erb +1 -0
- data/app/views/platform/oauth/authorize_success_iframe.html.erb +1 -0
- data/app/views/platform/oauth/authorize_success_mobile.html.erb +24 -0
- data/app/views/platform/oauth/authorize_success_popup.html.erb +24 -0
- data/app/views/platform/oauth/authorize_success_web.html.erb +1 -0
- data/app/views/platform/oauth/authorize_web.html.erb +3 -0
- data/app/views/platform/oauth/xd.html.erb +13 -0
- data/app/views/platform/ratings/_list.html.erb +30 -0
- data/app/views/platform/ratings/_new.html.erb +70 -0
- data/app/views/platform/ratings/_rating.html.erb +17 -0
- data/config/platform/config.yml +133 -0
- data/config/platform/data/default_applications.yml +39 -0
- data/config/platform/data/default_categories.yml +56 -0
- data/config/platform/data/default_permissions.yml +0 -0
- data/config/platform/site/features.yml +66 -0
- data/config/routes.rb +59 -0
- data/db/migrate/20110602232141_create_platform_tables.rb +262 -0
- data/docs/Classes.graffle +7315 -0
- data/docs/Classes.pdf +0 -0
- data/lib/generators/platform/platform_generator.rb +56 -0
- data/lib/generators/platform/templates/db/create_platform_tables.rb +262 -0
- data/lib/generators/platform/templates/layouts/platform.html.erb +49 -0
- data/lib/generators/platform/templates/layouts/platform_admin.html.erb +60 -0
- data/lib/platform.rb +6 -0
- data/lib/platform/api/already_jsoned_string.rb +9 -0
- data/lib/platform/api/proxy.rb +45 -0
- data/lib/platform/api/proxy/base.rb +62 -0
- data/lib/platform/cache.rb +78 -0
- data/lib/platform/config.rb +666 -0
- data/lib/platform/engine.rb +5 -0
- data/lib/platform/exception.rb +27 -0
- data/lib/platform/extensions/action_controller_extension.rb +65 -0
- data/lib/platform/extensions/action_view_extension.rb +168 -0
- data/lib/platform/extensions/object_extension.rb +51 -0
- data/lib/platform/helper.rb +33 -0
- data/lib/platform/logger.rb +62 -0
- data/lib/platform/railtie.rb +52 -0
- data/lib/platform/random_password_generator.rb +76 -0
- data/lib/platform/simple_string_permissions.rb +40 -0
- data/lib/platform/version.rb +3 -0
- data/lib/tasks/platform.rake +119 -0
- data/platform.gemspec +45 -0
- data/script/rails +6 -0
- data/spec/config/config_spec.rb +10 -0
- data/spec/dummy_app.rb +52 -0
- data/spec/models/application_spec.rb +53 -0
- data/spec/models/developer_spec.rb +23 -0
- data/spec/spec_helper.rb +29 -0
- data/test/dummy/Rakefile +7 -0
- data/test/dummy/app/assets/javascripts/application.js +7 -0
- data/test/dummy/app/assets/stylesheets/admin.css +200 -0
- data/test/dummy/app/assets/stylesheets/application.css +47 -0
- data/test/dummy/app/assets/stylesheets/components.css.scss +211 -0
- data/test/dummy/app/assets/stylesheets/layout.css.scss +143 -0
- data/test/dummy/app/controllers/admin/admins_controller.rb +7 -0
- data/test/dummy/app/controllers/admin/base_controller.rb +12 -0
- data/test/dummy/app/controllers/admin/bookmarks_controller.rb +7 -0
- data/test/dummy/app/controllers/admin/users_controller.rb +19 -0
- data/test/dummy/app/controllers/api/base_controller.rb +5 -0
- data/test/dummy/app/controllers/api/bookmarks_controller.rb +35 -0
- data/test/dummy/app/controllers/api/users_controller.rb +19 -0
- data/test/dummy/app/controllers/application_controller.rb +31 -0
- data/test/dummy/app/controllers/home_controller.rb +7 -0
- data/test/dummy/app/controllers/login_controller.rb +65 -0
- data/test/dummy/app/helpers/application_helper.rb +9 -0
- data/test/dummy/app/helpers/home_helper.rb +2 -0
- data/test/dummy/app/mailers/.gitkeep +0 -0
- data/test/dummy/app/models/.gitkeep +0 -0
- data/test/dummy/app/models/admin.rb +4 -0
- data/test/dummy/app/models/admin_filter.rb +7 -0
- data/test/dummy/app/models/bookmark.rb +7 -0
- data/test/dummy/app/models/user.rb +34 -0
- data/test/dummy/app/views/admin/admins/index.html.erb +7 -0
- data/test/dummy/app/views/admin/bookmarks/index.html.erb +5 -0
- data/test/dummy/app/views/admin/users/index.html.erb +10 -0
- data/test/dummy/app/views/demo/index.rhtml +108 -0
- data/test/dummy/app/views/demo/tokens.rhtml +35 -0
- data/test/dummy/app/views/home/index.html.erb +43 -0
- data/test/dummy/app/views/layouts/_footer.html.erb +16 -0
- data/test/dummy/app/views/layouts/_header.html.erb +22 -0
- data/test/dummy/app/views/layouts/admin.html.erb +97 -0
- data/test/dummy/app/views/layouts/application.html.erb +25 -0
- data/test/dummy/app/views/layouts/minimal.html.erb +37 -0
- data/test/dummy/app/views/layouts/popup.html.erb +43 -0
- data/test/dummy/app/views/login/index.html.erb +34 -0
- data/test/dummy/app/views/login/register.html.erb +51 -0
- data/test/dummy/config.ru +4 -0
- data/test/dummy/config/application.rb +51 -0
- data/test/dummy/config/boot.rb +10 -0
- data/test/dummy/config/database.yml +25 -0
- data/test/dummy/config/environment.rb +5 -0
- data/test/dummy/config/environments/development.rb +30 -0
- data/test/dummy/config/environments/production.rb +60 -0
- data/test/dummy/config/environments/test.rb +42 -0
- data/test/dummy/config/initializers/backtrace_silencers.rb +7 -0
- data/test/dummy/config/initializers/inflections.rb +10 -0
- data/test/dummy/config/initializers/mime_types.rb +5 -0
- data/test/dummy/config/initializers/secret_token.rb +7 -0
- data/test/dummy/config/initializers/session_store.rb +8 -0
- data/test/dummy/config/initializers/wrap_parameters.rb +14 -0
- data/test/dummy/config/locales/en.yml +5 -0
- data/test/dummy/config/platform/api/0/bookmark.yml +18 -0
- data/test/dummy/config/platform/api/0/user.yml +17 -0
- data/test/dummy/config/platform/api/1/bookmark.yml +58 -0
- data/test/dummy/config/platform/api/1/user.yml +36 -0
- data/test/dummy/config/platform/config.yml +135 -0
- data/test/dummy/config/platform/data/default_applications.yml +39 -0
- data/test/dummy/config/platform/data/default_categories.yml +56 -0
- data/test/dummy/config/platform/data/default_permissions.yml +0 -0
- data/test/dummy/config/platform/site/features.yml +66 -0
- data/test/dummy/config/platform/site/sample_apps.yml +100 -0
- data/test/dummy/config/routes.rb +30 -0
- data/test/dummy/config/tr8n/config.yml +247 -0
- data/test/dummy/config/tr8n/data/ip_locations.csv +93460 -0
- data/test/dummy/config/tr8n/rules/default_date_rules.yml +20 -0
- data/test/dummy/config/tr8n/rules/default_gender_list_rules.yml +82 -0
- data/test/dummy/config/tr8n/rules/default_gender_rules.yml +20 -0
- data/test/dummy/config/tr8n/rules/default_language_cases.yml +272 -0
- data/test/dummy/config/tr8n/rules/default_list_rules.yml +19 -0
- data/test/dummy/config/tr8n/rules/default_numeric_rules.yml +42 -0
- data/test/dummy/config/tr8n/rules/default_value_rules.yml +18 -0
- data/test/dummy/config/tr8n/site/default_glossary.yml +18 -0
- data/test/dummy/config/tr8n/site/default_languages.yml +1591 -0
- data/test/dummy/config/tr8n/site/features.yml +111 -0
- data/test/dummy/config/tr8n/site/shortcuts.yml +55 -0
- data/test/dummy/config/tr8n/site/sitemap.json +42 -0
- data/test/dummy/config/tr8n/tokens/data.yml +19 -0
- data/test/dummy/config/tr8n/tokens/decorations.yml +19 -0
- data/test/dummy/config/will_filter/config.yml +99 -0
- data/test/dummy/db/migrate/20101207014543_create_users.rb +23 -0
- data/test/dummy/db/migrate/20110113223509_create_admins.rb +15 -0
- data/test/dummy/db/migrate/20110930041143_create_will_filter_filters.rb +15 -0
- data/test/dummy/db/migrate/20110930041150_create_tr8n_tables.rb +350 -0
- data/test/dummy/db/migrate/20111004075531_create_platform_tables.rb +262 -0
- data/test/dummy/db/migrate/20111012055603_create_bookmarks.rb +10 -0
- data/test/dummy/db/schema.rb +683 -0
- data/test/dummy/lib/assets/.gitkeep +0 -0
- data/test/dummy/lib/platform/api/bookmark_proxy_0.rb +12 -0
- data/test/dummy/lib/platform/api/bookmark_proxy_1.rb +12 -0
- data/test/dummy/lib/platform/api/user_proxy_0.rb +12 -0
- data/test/dummy/lib/platform/api/user_proxy_1.rb +12 -0
- data/test/dummy/log/.gitkeep +0 -0
- data/test/dummy/public/404.html +26 -0
- data/test/dummy/public/422.html +26 -0
- data/test/dummy/public/500.html +26 -0
- data/test/dummy/public/favicon.ico +0 -0
- data/test/dummy/script/rails +6 -0
- data/test/dummy/test/fixtures/documents.yml +11 -0
- data/test/dummy/test/unit/document_test.rb +7 -0
- metadata +886 -0
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
#--
|
|
2
|
+
# Copyright (c) 2011 Michael Berkovich
|
|
3
|
+
#
|
|
4
|
+
# Permission is hereby granted, free of charge, to any person obtaining
|
|
5
|
+
# a copy of this software and associated documentation files (the
|
|
6
|
+
# "Software"), to deal in the Software without restriction, including
|
|
7
|
+
# without limitation the rights to use, copy, modify, merge, publish,
|
|
8
|
+
# distribute, sublicense, and/or sell copies of the Software, and to
|
|
9
|
+
# permit persons to whom the Software is furnished to do so, subject to
|
|
10
|
+
# the following conditions:
|
|
11
|
+
#
|
|
12
|
+
# The above copyright notice and this permission notice shall be
|
|
13
|
+
# included in all copies or substantial portions of the Software.
|
|
14
|
+
#
|
|
15
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
16
|
+
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
17
|
+
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
18
|
+
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
|
19
|
+
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
|
20
|
+
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
|
21
|
+
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
22
|
+
#++
|
|
23
|
+
|
|
24
|
+
module Platform
|
|
25
|
+
module Api
|
|
26
|
+
class AppsController < Platform::Api::BaseController
|
|
27
|
+
|
|
28
|
+
def index
|
|
29
|
+
render_response(Platform::Application.all)
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
private
|
|
33
|
+
|
|
34
|
+
def model_class
|
|
35
|
+
Platform::Application
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
@@ -0,0 +1,541 @@
|
|
|
1
|
+
#--
|
|
2
|
+
# Copyright (c) 2011 Michael Berkovich
|
|
3
|
+
#
|
|
4
|
+
# Permission is hereby granted, free of charge, to any person obtaining
|
|
5
|
+
# a copy of this software and associated documentation files (the
|
|
6
|
+
# "Software"), to deal in the Software without restriction, including
|
|
7
|
+
# without limitation the rights to use, copy, modify, merge, publish,
|
|
8
|
+
# distribute, sublicense, and/or sell copies of the Software, and to
|
|
9
|
+
# permit persons to whom the Software is furnished to do so, subject to
|
|
10
|
+
# the following conditions:
|
|
11
|
+
#
|
|
12
|
+
# The above copyright notice and this permission notice shall be
|
|
13
|
+
# included in all copies or substantial portions of the Software.
|
|
14
|
+
#
|
|
15
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
16
|
+
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
17
|
+
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
18
|
+
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
|
19
|
+
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
|
20
|
+
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
|
21
|
+
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
22
|
+
#++
|
|
23
|
+
|
|
24
|
+
module Platform
|
|
25
|
+
module Api
|
|
26
|
+
class BaseController < ActionController::Base
|
|
27
|
+
before_filter :ensure_api_enabled
|
|
28
|
+
before_filter :set_default_format
|
|
29
|
+
before_filter :authenticate
|
|
30
|
+
after_filter :log_api_call
|
|
31
|
+
|
|
32
|
+
class ApiError < StandardError
|
|
33
|
+
def status
|
|
34
|
+
@status ||= self.class.name.split('::').last.sub('Error','').underscore.to_sym
|
|
35
|
+
end
|
|
36
|
+
def init_cause(cause)
|
|
37
|
+
@cause = cause
|
|
38
|
+
self
|
|
39
|
+
end
|
|
40
|
+
def message
|
|
41
|
+
@cause.try(:message) || super
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
class BadRequestError < ApiError ; end
|
|
46
|
+
class ForbiddenError < ApiError ; end
|
|
47
|
+
class MethodNotAllowedError < ApiError ; end
|
|
48
|
+
class ServiceUnavailableError < ApiError ; end
|
|
49
|
+
class UnauthorizedError < ApiError ; end
|
|
50
|
+
class JSONPError < ApiError ; end
|
|
51
|
+
class InvalidTokenError < ApiError ; end
|
|
52
|
+
class ResponseStructureError < ApiError ; end
|
|
53
|
+
|
|
54
|
+
class LoginError < StandardError ; end
|
|
55
|
+
|
|
56
|
+
PLATFORM_NON_LOGGED_EXCEPTIONS = [
|
|
57
|
+
ActionController::MethodNotAllowed,
|
|
58
|
+
ActionController::UnknownAction,
|
|
59
|
+
ActiveRecord::RecordNotFound,
|
|
60
|
+
ForbiddenError,
|
|
61
|
+
MethodNotAllowedError,
|
|
62
|
+
ServiceUnavailableError,
|
|
63
|
+
UnauthorizedError
|
|
64
|
+
]
|
|
65
|
+
|
|
66
|
+
rescue_from StandardError do |e|
|
|
67
|
+
pp e.backtrace
|
|
68
|
+
log_exception(e) if should_log_error?(e)
|
|
69
|
+
render_exception(e)
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
protected
|
|
73
|
+
|
|
74
|
+
def log_exception(e)
|
|
75
|
+
Platform::LoggedException.create_from_exception(self, e, nil)
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
private
|
|
79
|
+
|
|
80
|
+
############################################################################
|
|
81
|
+
#### General Methods
|
|
82
|
+
############################################################################
|
|
83
|
+
def enabled?
|
|
84
|
+
Platform::Config.enable_api?
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
def allow_public?
|
|
88
|
+
Platform::Config.api_allow_public?
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
def ensure_api_enabled
|
|
92
|
+
raise ServiceUnavailableError.new('API Disabled') unless enabled?
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
def client_app
|
|
96
|
+
@client_app ||= access_token.try(:application)
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
def set_default_format
|
|
100
|
+
request.format = :json if params[:format].nil?
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
def all?
|
|
104
|
+
params[:all].to_s.param_true?
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
def cookies_enabled?
|
|
108
|
+
Platform::Config.api_cookies_enabled?
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
############################################################################
|
|
112
|
+
#### Authentication Methods
|
|
113
|
+
############################################################################
|
|
114
|
+
def authenticate
|
|
115
|
+
authenticate_via_oauth
|
|
116
|
+
authenticate_via_cookie if cookies_enabled? and (not jsonp?)
|
|
117
|
+
|
|
118
|
+
if oauth_attempted?
|
|
119
|
+
raise InvalidTokenError.new('Invalid access token') if oauth_failed?
|
|
120
|
+
else
|
|
121
|
+
redirect_to_login unless allow_public?
|
|
122
|
+
end
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
def authenticate_via_oauth
|
|
126
|
+
user = access_token.try(:user)
|
|
127
|
+
Platform::Config.init(user) if user
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
# should be overloaded by the extending class
|
|
131
|
+
def authenticate_via_cookie
|
|
132
|
+
pp :cookies, session[:user_id]
|
|
133
|
+
user = Platform::Config.user_class.find_by_id(session[:user_id])
|
|
134
|
+
Platform::Config.init(user) if user
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
def access_token
|
|
138
|
+
unless defined?(@access_token)
|
|
139
|
+
@access_token = nil
|
|
140
|
+
if access_token_header
|
|
141
|
+
parts = access_token_header.split(' ')
|
|
142
|
+
if parts.first == 'Bearer'
|
|
143
|
+
@access_token = Platform::Application.find_token(parts.last)
|
|
144
|
+
end
|
|
145
|
+
elsif access_token_param
|
|
146
|
+
@access_token = Platform::Application.find_token(access_token_param)
|
|
147
|
+
end
|
|
148
|
+
end
|
|
149
|
+
@access_token
|
|
150
|
+
end
|
|
151
|
+
|
|
152
|
+
def access_token_header
|
|
153
|
+
@access_token_header ||= request.headers["Authorization"]
|
|
154
|
+
end
|
|
155
|
+
|
|
156
|
+
def access_token_param
|
|
157
|
+
@access_token_param ||= params[:access_token] || params[:oauth_token]
|
|
158
|
+
end
|
|
159
|
+
|
|
160
|
+
def logged_in?
|
|
161
|
+
not Platform::Config.current_user_is_guest?
|
|
162
|
+
end
|
|
163
|
+
|
|
164
|
+
def oauth_attempted_and_failed?
|
|
165
|
+
oauth_attempted? and oauth_failed?
|
|
166
|
+
end
|
|
167
|
+
|
|
168
|
+
def oauth_failed?
|
|
169
|
+
access_token.nil?
|
|
170
|
+
end
|
|
171
|
+
|
|
172
|
+
def oauth_attempted?
|
|
173
|
+
access_token_param or (access_token_header and access_token_header.index('Bearer'))
|
|
174
|
+
end
|
|
175
|
+
|
|
176
|
+
def current_user
|
|
177
|
+
Platform::Config.current_user
|
|
178
|
+
end
|
|
179
|
+
|
|
180
|
+
############################################################################
|
|
181
|
+
#### Response Methods
|
|
182
|
+
############################################################################
|
|
183
|
+
def render_response(obj, opts={})
|
|
184
|
+
to_opts = params.merge(:max_models => limit, :viewer => current_user, :api_version => api_version)
|
|
185
|
+
|
|
186
|
+
if obj.is_a?(Array)
|
|
187
|
+
hash = {'results' => obj.collect{|o| o.to_api_hash(to_opts)}}
|
|
188
|
+
hash['page'] = page if page > 1 || limit == obj.size
|
|
189
|
+
hash['previous_page'] = prev_page if page > 1
|
|
190
|
+
hash['next_page'] = next_page if limit == obj.size
|
|
191
|
+
obj = hash
|
|
192
|
+
end
|
|
193
|
+
|
|
194
|
+
respond_to do |format|
|
|
195
|
+
format.json do
|
|
196
|
+
json = obj.to_json(to_opts)
|
|
197
|
+
validate_response_structure(json)
|
|
198
|
+
|
|
199
|
+
if jsonp?
|
|
200
|
+
script = "#{params[:callback].strip}(#{json})"
|
|
201
|
+
render(:text => script)
|
|
202
|
+
else
|
|
203
|
+
render(opts.merge(:json => json))
|
|
204
|
+
end
|
|
205
|
+
end
|
|
206
|
+
|
|
207
|
+
format.xml do
|
|
208
|
+
if obj.is_a?(Hash) && obj.has_key?('error')
|
|
209
|
+
obj = obj['error']
|
|
210
|
+
opts[:xml_root] = 'error'
|
|
211
|
+
end
|
|
212
|
+
render opts.merge(:text => obj.to_xml(to_opts.merge(:root => opts[:xml_root] || xml_root)))
|
|
213
|
+
end
|
|
214
|
+
end
|
|
215
|
+
|
|
216
|
+
add_response_headers
|
|
217
|
+
|
|
218
|
+
true
|
|
219
|
+
end
|
|
220
|
+
|
|
221
|
+
def add_response_headers
|
|
222
|
+
return unless enabled?
|
|
223
|
+
return unless rate_limited?
|
|
224
|
+
response.headers['X-API-Rate-Limit'] = request_limit.to_s
|
|
225
|
+
response.headers['X-API-Rate-Remaining'] = (request_limit - request_count.to_i).to_s
|
|
226
|
+
response.headers['X-API-Rate-Window'] = request_window.to_s
|
|
227
|
+
end
|
|
228
|
+
|
|
229
|
+
def max_models
|
|
230
|
+
Platform::Config.api_max_models
|
|
231
|
+
end
|
|
232
|
+
|
|
233
|
+
def page
|
|
234
|
+
(params[:page] || 1).to_i
|
|
235
|
+
end
|
|
236
|
+
|
|
237
|
+
def offset
|
|
238
|
+
(params[:offset] || limit * (page - 1)).to_i
|
|
239
|
+
end
|
|
240
|
+
|
|
241
|
+
# make this configurable
|
|
242
|
+
def limit
|
|
243
|
+
@limit ||= begin
|
|
244
|
+
lmt = params[:limit].to_i
|
|
245
|
+
if 0 == lmt || (lmt > max_models && limited_models?)
|
|
246
|
+
lmt = max_models
|
|
247
|
+
end
|
|
248
|
+
lmt
|
|
249
|
+
end
|
|
250
|
+
end
|
|
251
|
+
|
|
252
|
+
def limited_models?
|
|
253
|
+
not client_app.try(:allow_unlimited_models?)
|
|
254
|
+
end
|
|
255
|
+
|
|
256
|
+
def model_class
|
|
257
|
+
raise Exception.new("must be implemented in the extanding class")
|
|
258
|
+
end
|
|
259
|
+
|
|
260
|
+
def page_models
|
|
261
|
+
@page_models ||= model_class.where(page_model_conditions).limit(limit).offset(offset).order('id ASC')
|
|
262
|
+
end
|
|
263
|
+
|
|
264
|
+
def page_model
|
|
265
|
+
@page_model ||= model_class.where(page_model_conditions).first || raise(ActiveRecord::RecordNotFound)
|
|
266
|
+
end
|
|
267
|
+
|
|
268
|
+
def page_model_conditions(id_fields=nil)
|
|
269
|
+
id_fields ||= self.class.id_fields
|
|
270
|
+
{:id => ids(id_fields)}
|
|
271
|
+
end
|
|
272
|
+
|
|
273
|
+
# default id fields
|
|
274
|
+
def self.id_fields
|
|
275
|
+
[:id, :ids]
|
|
276
|
+
end
|
|
277
|
+
|
|
278
|
+
def ids(id_fields=nil)
|
|
279
|
+
id_fields ||= self.class.id_fields
|
|
280
|
+
ids = []
|
|
281
|
+
id_fields.each do |field|
|
|
282
|
+
ids << params[field].split(',') if params[field]
|
|
283
|
+
end
|
|
284
|
+
ids = ids.flatten.compact.uniq.collect{|id| id.to_i}
|
|
285
|
+
ids = default_model_ids if ids.empty?
|
|
286
|
+
|
|
287
|
+
ids
|
|
288
|
+
end
|
|
289
|
+
|
|
290
|
+
def default_model_ids
|
|
291
|
+
default_models.ids
|
|
292
|
+
end
|
|
293
|
+
|
|
294
|
+
def default_models
|
|
295
|
+
raise Exception.new("must be implemented in the extanding class")
|
|
296
|
+
end
|
|
297
|
+
|
|
298
|
+
def success_message
|
|
299
|
+
{:result => "Ok"}
|
|
300
|
+
end
|
|
301
|
+
|
|
302
|
+
############################################################################
|
|
303
|
+
#### JSONP Methods
|
|
304
|
+
############################################################################
|
|
305
|
+
def jsonp?
|
|
306
|
+
not params[:callback].blank?
|
|
307
|
+
end
|
|
308
|
+
|
|
309
|
+
############################################################################
|
|
310
|
+
#### XML Methods
|
|
311
|
+
############################################################################
|
|
312
|
+
def xml_root
|
|
313
|
+
model_class.to_s.underscore.pluralize
|
|
314
|
+
end
|
|
315
|
+
|
|
316
|
+
############################################################################
|
|
317
|
+
#### Date/Time Methods
|
|
318
|
+
############################################################################
|
|
319
|
+
def start_time
|
|
320
|
+
parse_time(params[:since], '2007-01-01')
|
|
321
|
+
end
|
|
322
|
+
|
|
323
|
+
def end_time
|
|
324
|
+
parse_time(params[:until], Date.tomorrow.to_s(:db))
|
|
325
|
+
end
|
|
326
|
+
|
|
327
|
+
def parse_time(string, default)
|
|
328
|
+
case string
|
|
329
|
+
when nil then default
|
|
330
|
+
when /today/i then Date.today.to_s(:db)
|
|
331
|
+
when /yesterday/i then Date.yesterday.to_s(:db)
|
|
332
|
+
else Time.parse(string).to_s(:db)
|
|
333
|
+
end
|
|
334
|
+
end
|
|
335
|
+
|
|
336
|
+
############################################################################
|
|
337
|
+
#### Rate Limits
|
|
338
|
+
############################################################################
|
|
339
|
+
def check_rate_limit
|
|
340
|
+
return unless rate_limited?
|
|
341
|
+
|
|
342
|
+
if request_count
|
|
343
|
+
if request_count >= request_limit
|
|
344
|
+
# Over the limit.
|
|
345
|
+
raise ForbiddenError.new('Rate limit exceeded.')
|
|
346
|
+
else
|
|
347
|
+
# Under the limit.
|
|
348
|
+
Platform::Cache.increment(cache_key)
|
|
349
|
+
end
|
|
350
|
+
else
|
|
351
|
+
# First request in time frame.
|
|
352
|
+
Platform::Cache.set(cache_key, '1', :expiry => request_window, :raw => true)
|
|
353
|
+
end
|
|
354
|
+
end
|
|
355
|
+
|
|
356
|
+
def rate_limited?
|
|
357
|
+
client_app.nil? || client_app.rate_limited?
|
|
358
|
+
end
|
|
359
|
+
|
|
360
|
+
def cache_key
|
|
361
|
+
@cache_key ||= if logged_in?
|
|
362
|
+
"api_rate_limit_u_#{current_user.id}"
|
|
363
|
+
else
|
|
364
|
+
"api_rate_limit_ip_#{request.ip}"
|
|
365
|
+
end
|
|
366
|
+
end
|
|
367
|
+
|
|
368
|
+
def request_limit
|
|
369
|
+
@request_limit ||= Platform::Config.api_request_limit
|
|
370
|
+
end
|
|
371
|
+
|
|
372
|
+
def request_count
|
|
373
|
+
@request_count ||= begin
|
|
374
|
+
count = Platform::Cache.get(cache_key, :raw => true)
|
|
375
|
+
count && count.to_i
|
|
376
|
+
end
|
|
377
|
+
end
|
|
378
|
+
|
|
379
|
+
def request_window
|
|
380
|
+
@request_window ||= Platform::Config.api_request_window
|
|
381
|
+
end
|
|
382
|
+
|
|
383
|
+
############################################################################
|
|
384
|
+
#### Navigation Params
|
|
385
|
+
############################################################################
|
|
386
|
+
def prev_page
|
|
387
|
+
url_for(params.merge(navigation_params(page - 1)))
|
|
388
|
+
end
|
|
389
|
+
|
|
390
|
+
def next_page
|
|
391
|
+
url_for(params.merge(navigation_params(page + 1)))
|
|
392
|
+
end
|
|
393
|
+
|
|
394
|
+
def navigation_params(page)
|
|
395
|
+
{
|
|
396
|
+
:controller => "api/#{controller_name}",
|
|
397
|
+
:action => action_name,
|
|
398
|
+
:page => page,
|
|
399
|
+
:format => 'json' == params[:format] ? nil : params[:format]
|
|
400
|
+
}
|
|
401
|
+
end
|
|
402
|
+
############################################################################
|
|
403
|
+
|
|
404
|
+
############################################################################
|
|
405
|
+
#### Ensurance
|
|
406
|
+
############################################################################
|
|
407
|
+
def ensure_post
|
|
408
|
+
raise MethodNotAllowedError.new('POST required') unless request.post?
|
|
409
|
+
end
|
|
410
|
+
|
|
411
|
+
def ensure_get
|
|
412
|
+
raise MethodNotAllowedError.new('GET required') unless request.get?
|
|
413
|
+
end
|
|
414
|
+
|
|
415
|
+
def ensure_put
|
|
416
|
+
raise MethodNotAllowedError.new('PUT required') unless request.put?
|
|
417
|
+
end
|
|
418
|
+
|
|
419
|
+
def ensure_delete
|
|
420
|
+
raise MethodNotAllowedError.new('DELETE required') unless request.delete?
|
|
421
|
+
end
|
|
422
|
+
|
|
423
|
+
def ensure_logged_in
|
|
424
|
+
raise LoginError unless logged_in?
|
|
425
|
+
end
|
|
426
|
+
|
|
427
|
+
# should be overwritten by the implementing class - this is cutsom stuff for some apps
|
|
428
|
+
def ensure_ownership(user=current_user, models=page_models)
|
|
429
|
+
raise ForbiddenError.new('Permission denied') unless models.all? { |ii| ii.user == current_user }
|
|
430
|
+
end
|
|
431
|
+
############################################################################
|
|
432
|
+
|
|
433
|
+
def split_param(name)
|
|
434
|
+
params[name].to_s.split(/\s*,\s*/)
|
|
435
|
+
end
|
|
436
|
+
|
|
437
|
+
def redirect_to_login
|
|
438
|
+
redirect_to(:controller => Platform::Config.login_url)
|
|
439
|
+
end
|
|
440
|
+
|
|
441
|
+
def log_api_call
|
|
442
|
+
return unless Platform::Config.api_logging_enabled?
|
|
443
|
+
|
|
444
|
+
duration = response.headers['X-Runtime']
|
|
445
|
+
Platform::ApplicationLog.create(
|
|
446
|
+
:application => client_app,
|
|
447
|
+
:user_id => current_user.try(:id),
|
|
448
|
+
:event => "#{params[:controller]}-#{params[:action]}",
|
|
449
|
+
:data => params,
|
|
450
|
+
:request_method => request.request_method,
|
|
451
|
+
:user_agent => request.user_agent,
|
|
452
|
+
:ip => request.remote_ip,
|
|
453
|
+
:duration => (duration =~ /[.0-9]/) ? duration.to_f / 1000 : nil
|
|
454
|
+
)
|
|
455
|
+
end
|
|
456
|
+
|
|
457
|
+
############################################################################
|
|
458
|
+
#### Exceptions
|
|
459
|
+
############################################################################
|
|
460
|
+
|
|
461
|
+
def should_log_error?(ex)
|
|
462
|
+
return true if Rails.env.development?
|
|
463
|
+
not PLATFORM_NON_LOGGED_EXCEPTIONS.include?(ex.class)
|
|
464
|
+
end
|
|
465
|
+
|
|
466
|
+
def render_exception(ex)
|
|
467
|
+
error = {
|
|
468
|
+
'type' => 'ApiException'
|
|
469
|
+
}
|
|
470
|
+
case ex
|
|
471
|
+
when ActiveRecord::RecordNotFound
|
|
472
|
+
status = :not_found
|
|
473
|
+
error['message'] = 'Not Found'
|
|
474
|
+
when ActiveRecord::StatementInvalid
|
|
475
|
+
status = :bad_request
|
|
476
|
+
error['message'] = 'Bad Request'
|
|
477
|
+
when ApiError
|
|
478
|
+
error['type'] = 'OAuthException' if ex.is_a?(UnauthorizedError)
|
|
479
|
+
error['message'] = ex.message
|
|
480
|
+
status = ex.status
|
|
481
|
+
else
|
|
482
|
+
error['message'] = ex.message
|
|
483
|
+
status = :internal_server_error
|
|
484
|
+
end
|
|
485
|
+
params[:only_list] = nil
|
|
486
|
+
render_response({'error' => error}, :status => status)
|
|
487
|
+
end
|
|
488
|
+
|
|
489
|
+
############################################################################
|
|
490
|
+
#### Response Validation
|
|
491
|
+
############################################################################
|
|
492
|
+
|
|
493
|
+
def api_version
|
|
494
|
+
@api_version ||= params[:api_version] || client_app.try(:api_version) || Platform::Config.api_default_version
|
|
495
|
+
end
|
|
496
|
+
|
|
497
|
+
def api_reference_for_path(ref, path)
|
|
498
|
+
parts = path.split("/")
|
|
499
|
+
return ref[parts.first] if parts.length == 1
|
|
500
|
+
return nil if ref[parts.first].nil? or ref[parts.first][:actions].nil?
|
|
501
|
+
ref[parts.first][:actions][parts.last]
|
|
502
|
+
end
|
|
503
|
+
|
|
504
|
+
def handle_document_structure_error(msg)
|
|
505
|
+
pp msg
|
|
506
|
+
log_exception(ResponseStructureError.new(msg))
|
|
507
|
+
end
|
|
508
|
+
|
|
509
|
+
def validate_response_structure(json)
|
|
510
|
+
return unless Platform::Config.enable_api_verification?
|
|
511
|
+
|
|
512
|
+
path = request.url.split(Platform::Config.api_base_url).last.split('?').first.split("-").first
|
|
513
|
+
# pp request.url, path
|
|
514
|
+
|
|
515
|
+
path = 'profile' if path.blank? # make this configurable option
|
|
516
|
+
|
|
517
|
+
hash = JSON.parse(json)
|
|
518
|
+
# pp hash
|
|
519
|
+
|
|
520
|
+
ref = Platform::Config.api_reference(api_version)
|
|
521
|
+
return handle_document_structure_error("Unsupported API version: #{api_version}") if ref.nil?
|
|
522
|
+
|
|
523
|
+
ref = api_reference_for_path(ref, path)
|
|
524
|
+
return handle_document_structure_error("Unsupported API path: #{path}") if ref.nil?
|
|
525
|
+
|
|
526
|
+
fields = ref[:fields]
|
|
527
|
+
# pp fields
|
|
528
|
+
|
|
529
|
+
undocumented_fields = []
|
|
530
|
+
hash.keys.each do |key|
|
|
531
|
+
if fields[key].nil?
|
|
532
|
+
undocumented_fields << key
|
|
533
|
+
end
|
|
534
|
+
end
|
|
535
|
+
|
|
536
|
+
handle_document_structure_error("Unsupported or undocumented fields for API version #{api_version}, path #{path}: #{undocumented_fields.join(', ')}") if undocumented_fields.any?
|
|
537
|
+
end
|
|
538
|
+
|
|
539
|
+
end
|
|
540
|
+
end
|
|
541
|
+
end
|