Example #1
0
def init_addon(app, addon_name, routes=True):
    """Load addon module return its create configuration object.

    If `log_fp` is provided, the addon's log templates will be appended
    to the file.

    :param app: Flask app object
    :param addon_name: Name of addon directory
    :param file log_fp: File pointer for the built logs file.
    :param bool routes: Add routes
    :return AddonConfig: AddonConfig configuration object if module found,
        else None

    """
    import_path = "website.addons.{0}".format(addon_name)

    # Import addon module
    addon_module = importlib.import_module(import_path)

    data = vars(addon_module)
    data["description"] = settings.ADDONS_DESCRIPTION.get(addon_name, "")
    data["url"] = settings.ADDONS_URL.get(addon_name, None)

    # Add routes
    if routes:
        for route_group in getattr(addon_module, "ROUTES", []):
            process_rules(app, **route_group)

    # Build AddonConfig object
    return AddonConfig(**{key.lower(): value for key, value in data.iteritems()})
Example #2
0
def init_addon(app, addon_name, routes=True):
    """Load addon module return its create configuration object.

    If `log_fp` is provided, the addon's log templates will be appended
    to the file.

    :param app: Flask app object
    :param addon_name: Name of addon directory
    :param file log_fp: File pointer for the built logs file.
    :param bool routes: Add routes
    :return AddonConfig: AddonConfig configuration object if module found,
        else None

    """
    import_path = 'website.addons.{0}'.format(addon_name)

    # Import addon module
    addon_module = importlib.import_module(import_path)

    data = vars(addon_module)
    data['description'] = settings.ADDONS_DESCRIPTION.get(addon_name, '')
    data['url'] = settings.ADDONS_URL.get(addon_name, None)

    # Add routes
    if routes:
        for route_group in getattr(addon_module, 'ROUTES', []):
            process_rules(app, **route_group)

    # Build AddonConfig object
    return AddonConfig(
        **{
            key.lower(): value
            for key, value in data.iteritems()
        }
    )
Example #3
0
 def test_url_for_simple(self):
     r = Rule(["/project/"],
              "get",
              view_func_or_data=dummy_view,
              renderer=json_renderer)
     process_rules(self.app, [r])
     with self.app.test_request_context():
         assert_equal(url_for("JSONRenderer__dummy_view"), "/project/")
Example #4
0
 def test_error_handling_with_message(self):
     rule = Rule(['/error/'], 'get', error_with_msg, renderer=json_renderer)
     process_rules(self.app, [rule])
     res = self.wt.get('/error/', expect_errors=True)
     assert_equal(res.status_code, 400)
     data = res.json
     assert_equal(data['message_short'], 'Invalid')
     assert_equal(data['message_long'], 'Invalid request')
Example #5
0
 def test_url_for_simple(self):
     r = Rule(['/project/'],
              'get',
              view_func_or_data=dummy_view,
              renderer=json_renderer)
     process_rules(self.app, [r])
     with self.app.test_request_context():
         assert_equal(url_for('JSONRenderer__dummy_view'), '/project/')
Example #6
0
 def test_url_for_with_argument(self):
     r = Rule(['/project/<pid>/'],
              "get",
              view_func_or_data=dummy_view2,
              renderer=json_renderer)
     process_rules(self.app, [r])
     with self.app.test_request_context():
         assert_equal(url_for("JSONRenderer__dummy_view2", pid=123),
                      "/project/123/")
Example #7
0
 def test_url_for_with_prefix(self):
     api_rule = Rule(["/project/"],
                     "get",
                     view_func_or_data=dummy_view3,
                     renderer=json_renderer)
     process_rules(self.app, [api_rule], prefix="/api/v1")
     with self.app.test_request_context():
         assert_equal(url_for("JSONRenderer__dummy_view3"),
                      "/api/v1/project/")
Example #8
0
 def test_url_for_with_prefix(self):
     api_rule = Rule(['/project/'],
                     'get',
                     view_func_or_data=dummy_view3,
                     renderer=json_renderer)
     process_rules(self.app, [api_rule], prefix='/api/v1')
     with self.app.test_request_context():
         assert_equal(url_for('JSONRenderer__dummy_view3'),
                      '/api/v1/project/')
Example #9
0
def make_url_map(app):
    """Set up all the routes for the OSF app.

    :param app: A Flask/Werkzeug app to bind the rules to.
    """

    # Set default views to 404, using URL-appropriate renderers
    process_rules(app, [
        Rule('/<path:_>', ['get', 'post'], HTTPError(http.NOT_FOUND),
             OsfWebRenderer('', render_mako_string)),
        Rule('/api/v1/<path:_>', ['get', 'post'], HTTPError(http.NOT_FOUND),
             json_renderer),
    ])

    ### GUID ###
    process_rules(app, [
        Rule(
            [
                '/<guid>/',
                '/<guid>/<path:suffix>',
            ],
            ['get', 'post', 'put', 'patch', 'delete'],
            website_views.resolve_guid,
            notemplate,
        ),
        Rule(
            [
                '/api/v1/<guid>/',
                '/api/v1/<guid>/<path:suffix>',
            ],
            ['get', 'post', 'put', 'patch', 'delete'],
            website_views.resolve_guid,
            json_renderer,
        ),
    ])

    # Static files
    process_rules(app, [
        Rule('/favicon.ico', 'get', favicon, json_renderer),
        Rule('/robots.txt', 'get', robots, json_renderer),
    ])

    ### Base ###

    process_rules(app, [
        Rule('/dashboard/', 'get', website_views.dashboard,
             OsfWebRenderer('dashboard.mako')),
        Rule('/reproducibility/', 'get', website_views.reproducibility,
             OsfWebRenderer('', render_mako_string)),
        Rule(
            '/about/',
            'get',
            website_views.redirect_about,
            json_renderer,
        ),
        Rule(
            '/howosfworks/',
            'get',
            website_views.redirect_howosfworks,
            json_renderer,
        ),
        Rule('/faq/', 'get', {}, OsfWebRenderer('public/pages/faq.mako')),
        Rule('/getting-started/', 'get', {},
             OsfWebRenderer('public/pages/getting_started.mako')),
        Rule('/explore/', 'get', {}, OsfWebRenderer('public/explore.mako')),
        Rule(['/messages/', '/help/'], 'get', {},
             OsfWebRenderer('public/comingsoon.mako')),
        Rule(
            '/view/<meeting>/',
            'get',
            conference_views.conference_results,
            OsfWebRenderer('public/pages/meeting.mako'),
        ),
        Rule(
            '/view/<meeting>/plain/',
            'get',
            conference_views.conference_results,
            OsfWebRenderer('public/pages/meeting_plain.mako'),
            endpoint_suffix='__plain',
        ),
        Rule(
            '/api/v1/view/<meeting>/',
            'get',
            conference_views.conference_data,
            json_renderer,
        ),
        Rule(
            '/meetings/',
            'get',
            conference_views.conference_view,
            OsfWebRenderer('public/pages/meeting_landing.mako'),
        ),
        Rule(
            '/presentations/',
            'get',
            conference_views.redirect_to_meetings,
            json_renderer,
        ),
        Rule('/news/', 'get', {}, OsfWebRenderer('public/pages/news.mako')),
    ])

    # Site-wide API routes

    process_rules(app, [
        Rule(
            '/citations/styles/',
            'get',
            citation_views.list_citation_styles,
            json_renderer,
        ),
    ],
                  prefix='/api/v1')

    process_rules(app, [
        Rule(
            [
                '/project/<pid>/<addon>/settings/disable/',
                '/project/<pid>/node/<nid>/<addon>/settings/disable/',
            ],
            'post',
            addon_views.disable_addon,
            json_renderer,
        ),
        Rule(
            '/profile/<uid>/<addon>/settings/',
            'get',
            addon_views.get_addon_user_config,
            json_renderer,
        ),
    ],
                  prefix='/api/v1')

    # OAuth

    process_rules(app, [
        Rule(
            '/oauth/connect/<service_name>/',
            'get',
            oauth_views.oauth_connect,
            json_renderer,
        ),
        Rule(
            '/oauth/callback/<service_name>/',
            'get',
            oauth_views.oauth_callback,
            OsfWebRenderer('util/oauth_complete.mako'),
        ),
    ])

    process_rules(app, [
        Rule(
            [
                '/oauth/accounts/<external_account_id>/',
            ],
            'delete',
            oauth_views.oauth_disconnect,
            json_renderer,
        )
    ],
                  prefix='/api/v1')

    process_rules(app, [
        Rule('/dashboard/get_nodes/', 'get', website_views.get_dashboard_nodes,
             json_renderer),
        Rule([
            '/dashboard/<nid>',
            '/dashboard/',
        ], 'get', website_views.get_dashboard, json_renderer),
    ],
                  prefix='/api/v1')

    ### Metadata ###

    process_rules(app, [
        Rule(
            [
                '/project/<pid>/comments/',
                '/project/<pid>/node/<nid>/comments/',
            ],
            'get',
            project_views.comment.list_comments,
            json_renderer,
        ),
        Rule(
            [
                '/project/<pid>/comments/discussion/',
                '/project/<pid>/node/<nid>/comments/discussion/',
            ],
            'get',
            project_views.comment.comment_discussion,
            json_renderer,
        ),
        Rule(
            [
                '/project/<pid>/comment/',
                '/project/<pid>/node/<nid>/comment/',
            ],
            'post',
            project_views.comment.add_comment,
            json_renderer,
        ),
        Rule(
            [
                '/project/<pid>/comment/<cid>/',
                '/project/<pid>/node/<nid>/comment/<cid>/',
            ],
            'put',
            project_views.comment.edit_comment,
            json_renderer,
        ),
        Rule(
            [
                '/project/<pid>/comment/<cid>/',
                '/project/<pid>/node/<nid>/comment/<cid>/',
            ],
            'delete',
            project_views.comment.delete_comment,
            json_renderer,
        ),
        Rule(
            [
                '/project/<pid>/comment/<cid>/undelete/',
                '/project/<pid>/node/<nid>/comment/<cid>/undelete/',
            ],
            'put',
            project_views.comment.undelete_comment,
            json_renderer,
        ),
        Rule(
            [
                '/project/<pid>/comments/timestamps/',
                '/project/<pid>/node/<nid>/comments/timestamps/',
            ],
            'put',
            project_views.comment.update_comments_timestamp,
            json_renderer,
        ),
        Rule(
            [
                '/project/<pid>/comment/<cid>/report/',
                '/project/<pid>/node/<nid>/comment/<cid>/report/',
            ],
            'post',
            project_views.comment.report_abuse,
            json_renderer,
        ),
        Rule(
            [
                '/project/<pid>/comment/<cid>/unreport/',
                '/project/<pid>/node/<nid>/comment/<cid>/unreport/',
            ],
            'post',
            project_views.comment.unreport_abuse,
            json_renderer,
        ),
        Rule(
            [
                '/project/<pid>/citation/',
                '/project/<pid>/node/<nid>/citation/',
            ],
            'get',
            citation_views.node_citation,
            json_renderer,
        ),
    ],
                  prefix='/api/v1')

    ### Forms ###

    process_rules(app, [
        Rule('/forms/registration/', 'get', website_views.registration_form,
             json_renderer),
        Rule('/forms/signin/', 'get', website_views.signin_form,
             json_renderer),
        Rule('/forms/forgot_password/', 'get',
             website_views.forgot_password_form, json_renderer),
        Rule('/forms/reset_password/', 'get',
             website_views.reset_password_form, json_renderer),
    ],
                  prefix='/api/v1')

    ### Discovery ###

    process_rules(app, [
        Rule('/explore/activity/', 'get', discovery_views.activity,
             OsfWebRenderer('public/pages/active_nodes.mako', trust=False)),
    ])

    ### Auth ###

    # Web

    process_rules(
        app,
        [
            Rule(
                '/confirm/<uid>/<token>/',
                'get',
                auth_views.confirm_email_get,
                # View will either redirect or display error message
                OsfWebRenderer('error.mako', render_mako_string)),
            Rule(
                '/resetpassword/<verification_key>/', ['get', 'post'],
                auth_views.reset_password,
                OsfWebRenderer('public/resetpassword.mako',
                               render_mako_string)),

            # Resend confirmation URL linked to in CAS login page
            Rule('/resend/', ['get', 'post'], auth_views.resend_confirmation,
                 OsfWebRenderer('resend.mako', render_mako_string)),

            # TODO: Remove `auth_register_post`
            Rule('/register/', 'post', auth_views.auth_register_post,
                 OsfWebRenderer('public/login.mako')),
            Rule('/api/v1/register/', 'post', auth_views.register_user,
                 json_renderer),
            Rule(['/login/', '/account/'], 'get', auth_views.auth_login,
                 OsfWebRenderer('public/login.mako')),
            Rule('/login/first/',
                 'get',
                 auth_views.auth_login,
                 OsfWebRenderer('public/login.mako'),
                 endpoint_suffix='__first',
                 view_kwargs={'first': True}),
            Rule('/logout/', 'get', auth_views.auth_logout, notemplate),
            Rule('/forgotpassword/', 'get', auth_views.forgot_password_get,
                 OsfWebRenderer('public/forgot_password.mako')),
            Rule('/forgotpassword/', 'post', auth_views.forgot_password_post,
                 OsfWebRenderer('public/login.mako')),
            Rule(['/midas/', '/summit/', '/accountbeta/', '/decline/'], 'get',
                 auth_views.auth_registerbeta,
                 OsfWebRenderer('', render_mako_string)),
            Rule('/login/connected_tools/', 'get',
                 landing_page_views.connected_tools,
                 OsfWebRenderer('public/login_landing.mako')),
            Rule('/login/enriched_profile/', 'get',
                 landing_page_views.enriched_profile,
                 OsfWebRenderer('public/login_landing.mako')),
        ])

    ### Profile ###

    # Web

    process_rules(
        app,
        [
            Rule('/profile/', 'get', profile_views.profile_view,
                 OsfWebRenderer('profile.mako', trust=False)),
            Rule('/profile/<uid>/', 'get', profile_views.profile_view_id,
                 OsfWebRenderer('profile.mako', trust=False)),
            Rule(["/user/merge/"], 'get', auth_views.merge_user_get,
                 OsfWebRenderer("merge_accounts.mako", trust=False)),
            Rule(["/user/merge/"], 'post', auth_views.merge_user_post,
                 OsfWebRenderer("merge_accounts.mako", trust=False)),
            # Route for claiming and setting email and password.
            # Verification token must be querystring argument
            Rule(['/user/<uid>/<pid>/claim/'], ['get', 'post'],
                 project_views.contributor.claim_user_form,
                 OsfWebRenderer('claim_account.mako', trust=False)),
            Rule(['/user/<uid>/<pid>/claim/verify/<token>/'], ['get', 'post'],
                 project_views.contributor.claim_user_registered,
                 OsfWebRenderer('claim_account_registered.mako', trust=False)),
            Rule(
                '/settings/',
                'get',
                profile_views.user_profile,
                OsfWebRenderer('profile/settings.mako', trust=False),
            ),
            Rule(
                '/settings/account/',
                'get',
                profile_views.user_account,
                OsfWebRenderer('profile/account.mako', trust=False),
            ),
            Rule(
                '/settings/account/password',
                'post',
                profile_views.user_account_password,
                OsfWebRenderer('profile/account.mako', trust=False),
            ),
            Rule(
                '/settings/addons/',
                'get',
                profile_views.user_addons,
                OsfWebRenderer('profile/addons.mako', trust=False),
            ),
            Rule(
                '/settings/notifications/',
                'get',
                profile_views.user_notifications,
                OsfWebRenderer('profile/notifications.mako', trust=False),
            ),

            # TODO: Uncomment once outstanding issues with this feature are addressed
            # Rule(
            #     '/@<twitter_handle>/',
            #     'get',
            #     profile_views.redirect_to_twitter,
            #     OsfWebRenderer('error.mako', render_mako_string, trust=False)
            # ),
        ])

    # API

    process_rules(
        app,
        [
            Rule('/profile/', 'get', profile_views.profile_view,
                 json_renderer),
            Rule('/profile/', 'put', profile_views.update_user, json_renderer),
            Rule('/resend/', 'put', profile_views.resend_confirmation,
                 json_renderer),
            Rule('/profile/<uid>/', 'get', profile_views.profile_view_id,
                 json_renderer),

            # Used by profile.html
            Rule('/profile/<uid>/edit/', 'post', profile_views.edit_profile,
                 json_renderer),
            Rule('/profile/<uid>/public_projects/', 'get',
                 profile_views.get_public_projects, json_renderer),
            Rule('/profile/<uid>/public_components/', 'get',
                 profile_views.get_public_components, json_renderer),
            Rule('/profile/<user_id>/summary/', 'get',
                 profile_views.get_profile_summary, json_renderer),
            Rule('/user/<uid>/<pid>/claim/email/', 'post',
                 project_views.contributor.claim_user_post, json_renderer),
            Rule(
                '/profile/export/',
                'post',
                profile_views.request_export,
                json_renderer,
            ),
            Rule(
                '/profile/deactivate/',
                'post',
                profile_views.request_deactivation,
                json_renderer,
            ),
            Rule(
                [
                    '/profile/gravatar/',
                    '/users/gravatar/',
                    '/profile/gravatar/<size>',
                    '/users/gravatar/<size>',
                ],
                'get',
                profile_views.current_user_gravatar,
                json_renderer,
            ),
            Rule(
                [
                    '/profile/<uid>/gravatar/',
                    '/users/<uid>/gravatar/',
                    '/profile/<uid>/gravatar/<size>',
                    '/users/<uid>/gravatar/<size>',
                ],
                'get',
                profile_views.get_gravatar,
                json_renderer,
            ),

            # Rules for user profile configuration
            Rule('/settings/names/', 'get', profile_views.serialize_names,
                 json_renderer),
            Rule('/settings/names/', 'put', profile_views.unserialize_names,
                 json_renderer),
            Rule('/settings/names/impute/', 'get', profile_views.impute_names,
                 json_renderer),
            Rule(
                [
                    '/settings/social/',
                    '/settings/social/<uid>/',
                ],
                'get',
                profile_views.serialize_social,
                json_renderer,
            ),
            Rule(
                [
                    '/settings/jobs/',
                    '/settings/jobs/<uid>/',
                ],
                'get',
                profile_views.serialize_jobs,
                json_renderer,
            ),
            Rule(
                [
                    '/settings/schools/',
                    '/settings/schools/<uid>/',
                ],
                'get',
                profile_views.serialize_schools,
                json_renderer,
            ),
            Rule([
                '/settings/social/',
                '/settings/social/<uid>/',
            ], 'put', profile_views.unserialize_social, json_renderer),
            Rule([
                '/settings/jobs/',
                '/settings/jobs/<uid>/',
            ], 'put', profile_views.unserialize_jobs, json_renderer),
            Rule([
                '/settings/schools/',
                '/settings/schools/<uid>/',
            ], 'put', profile_views.unserialize_schools, json_renderer),
        ],
        prefix='/api/v1',
    )

    ### Search ###

    # Web

    process_rules(app, [
        Rule('/search/', 'get', {}, OsfWebRenderer('search.mako')),
        Rule('/share/', 'get', {}, OsfWebRenderer('share_search.mako')),
        Rule('/share/registration/', 'get',
             {'register': settings.SHARE_REGISTRATION_URL},
             OsfWebRenderer('share_registration.mako')),
        Rule('/share/help/', 'get', {'help': settings.SHARE_API_DOCS_URL},
             OsfWebRenderer('share_api_docs.mako')),
        Rule('/share_dashboard/', 'get', {},
             OsfWebRenderer('share_dashboard.mako')),
        Rule('/share/atom/', 'get', search_views.search_share_atom,
             xml_renderer),
        Rule('/api/v1/user/search/', 'get', search_views.search_contributor,
             json_renderer),
        Rule(
            '/api/v1/search/node/',
            'post',
            project_views.node.search_node,
            json_renderer,
        ),
    ])

    # API

    process_rules(app, [
        Rule(['/search/', '/search/<type>/'], ['get', 'post'],
             search_views.search_search, json_renderer),
        Rule('/search/projects/', 'get', search_views.search_projects_by_title,
             json_renderer),
        Rule('/share/search/', ['get', 'post'], search_views.search_share,
             json_renderer),
        Rule('/share/stats/', 'get', search_views.search_share_stats,
             json_renderer),
        Rule('/share/providers/', 'get', search_views.search_share_providers,
             json_renderer),
    ],
                  prefix='/api/v1')

    # Project

    # Web

    process_rules(
        app,
        [
            Rule('/', 'get', website_views.index,
                 OsfWebRenderer('index.mako')),
            Rule('/goodbye/', 'get', goodbye, OsfWebRenderer('index.mako')),
            Rule([
                '/project/<pid>/',
                '/project/<pid>/node/<nid>/',
            ], 'get', project_views.node.view_project,
                 OsfWebRenderer('project/project.mako', trust=False)),

            # Create a new subproject/component
            Rule('/project/<pid>/newnode/', 'post',
                 project_views.node.project_new_node, notemplate),

            # # TODO: Add API endpoint for tags
            # Rule('/tags/<tag>/', 'get', project_views.tag.project_tag, OsfWebRenderer('tags.mako')),
            Rule('/api/v1/folder/<nid>', 'post',
                 project_views.node.folder_new_post, json_renderer),
            Rule('/project/new/<pid>/beforeTemplate/', 'get',
                 project_views.node.project_before_template, json_renderer),
            Rule(
                [
                    '/project/<pid>/contributors/',
                    '/project/<pid>/node/<nid>/contributors/',
                ],
                'get',
                project_views.node.node_contributors,
                OsfWebRenderer('project/contributors.mako', trust=False),
            ),
            Rule([
                '/project/<pid>/settings/',
                '/project/<pid>/node/<nid>/settings/',
            ], 'get', project_views.node.node_setting,
                 OsfWebRenderer('project/settings.mako', trust=False)),

            # Permissions
            Rule(
                [
                    '/project/<pid>/permissions/<permissions>/',
                    '/project/<pid>/node/<nid>/permissions/<permissions>/',
                ],
                'post',
                project_views.node.project_set_privacy,
                OsfWebRenderer(
                    'project/project.mako'
                )  # TODO: Should this be notemplate? (post request)
            ),

            ### Logs ###

            # View forks
            Rule([
                '/project/<pid>/forks/',
                '/project/<pid>/node/<nid>/forks/',
            ], 'get', project_views.node.node_forks,
                 OsfWebRenderer('project/forks.mako', trust=False)),

            # Registrations
            Rule([
                '/project/<pid>/register/',
                '/project/<pid>/node/<nid>/register/',
            ], 'get', project_views.register.node_register_page,
                 OsfWebRenderer('project/register.mako', trust=False)),
            Rule([
                '/project/<pid>/register/<template>/',
                '/project/<pid>/node/<nid>/register/<template>/',
            ], 'get', project_views.register.node_register_template_page,
                 OsfWebRenderer('project/register.mako', trust=False)),
            Rule([
                '/project/<pid>/registrations/',
                '/project/<pid>/node/<nid>/registrations/',
            ], 'get', project_views.node.node_registrations,
                 OsfWebRenderer('project/registrations.mako', trust=False)),

            # TODO: Can't create a registration locally, so can't test this one..?
            Rule([
                '/project/<pid>/retraction/',
                '/project/<pid>/node/<nid>/retraction/',
            ], 'get', project_views.register.node_registration_retraction_get,
                 OsfWebRenderer('project/retract_registration.mako',
                                trust=False)),
            Rule([
                '/project/<pid>/retraction/approve/<token>/',
                '/project/<pid>/node/<nid>/retraction/approve/<token>/',
            ], 'get',
                 project_views.register.node_registration_retraction_approve,
                 OsfWebRenderer('error.mako', trust=False)),
            Rule(
                [
                    '/project/<pid>/retraction/disapprove/<token>/',
                    '/project/<pid>/node/<nid>/retraction/disapprove/<token>/',
                ], 'get',
                project_views.register.node_registration_retraction_disapprove,
                OsfWebRenderer('error.mako', trust=False)),
            Rule([
                '/project/<pid>/embargo/approve/<token>/',
                '/project/<pid>/node/<nid>/embargo/approve/<token>/',
            ], 'get', project_views.register.node_registration_embargo_approve,
                 OsfWebRenderer('error.mako', trust=False)),
            Rule([
                '/project/<pid>/embargo/disapprove/<token>/',
                '/project/<pid>/node/<nid>/embargo/disapprove/<token>/',
            ], 'get',
                 project_views.register.node_registration_embargo_disapprove,
                 OsfWebRenderer('error.mako', trust=False)),
            Rule(
                '/ids/<category>/<path:value>/',
                'get',
                project_views.register.get_referent_by_identifier,
                notemplate,
            ),

            # Statistics
            Rule([
                '/project/<pid>/statistics/',
                '/project/<pid>/node/<nid>/statistics/',
            ], 'get', project_views.node.project_statistics,
                 OsfWebRenderer('project/statistics.mako', trust=False)),

            ### Files ###

            # Note: Web endpoint for files view must pass `mode` = `page` to
            # include project view data and JS includes
            # TODO: Start waterbutler to test
            Rule(
                [
                    '/project/<pid>/files/',
                    '/project/<pid>/node/<nid>/files/',
                ],
                'get',
                project_views.file.collect_file_trees,
                OsfWebRenderer('project/files.mako', trust=False),
                view_kwargs={'mode': 'page'},
            ),
            Rule([
                '/project/<pid>/files/<provider>/<path:path>/',
                '/project/<pid>/node/<nid>/files/<provider>/<path:path>/',
            ], 'get', addon_views.addon_view_or_download_file,
                 OsfWebRenderer('project/view_file.mako', trust=False)),
            Rule(
                [
                    # Legacy Addon view file paths
                    '/project/<pid>/<provider>/files/<path:path>/',
                    '/project/<pid>/node/<nid>/<provider>/files/<path:path>/',
                    '/project/<pid>/<provider>/files/<path:path>/download/',
                    '/project/<pid>/node/<nid>/<provider>/files/<path:path>/download/',

                    # Legacy routes for `download_file`
                    '/project/<pid>/osffiles/<fid>/download/',
                    '/project/<pid>/node/<nid>/osffiles/<fid>/download/',

                    # Legacy routes for `view_file`
                    '/project/<pid>/osffiles/<fid>/',
                    '/project/<pid>/node/<nid>/osffiles/<fid>/',

                    # Note: Added these old URLs for backwards compatibility with
                    # hard-coded links.
                    '/project/<pid>/osffiles/download/<fid>/',
                    '/project/<pid>/node/<nid>/osffiles/download/<fid>/',
                    '/project/<pid>/files/<fid>/',
                    '/project/<pid>/node/<nid>/files/<fid>/',
                    '/project/<pid>/files/download/<fid>/',
                    '/project/<pid>/node/<nid>/files/download/<fid>/',

                    # Legacy routes for `download_file_by_version`
                    '/project/<pid>/osffiles/<fid>/version/<vid>/download/',
                    '/project/<pid>/node/<nid>/osffiles/<fid>/version/<vid>/download/',
                    # Note: Added these old URLs for backwards compatibility with
                    # hard-coded links.
                    '/project/<pid>/osffiles/<fid>/version/<vid>/',
                    '/project/<pid>/node/<nid>/osffiles/<fid>/version/<vid>/',
                    '/project/<pid>/osffiles/download/<fid>/version/<vid>/',
                    '/project/<pid>/node/<nid>/osffiles/download/<fid>/version/<vid>/',
                    '/project/<pid>/files/<fid>/version/<vid>/',
                    '/project/<pid>/node/<nid>/files/<fid>/version/<vid>/',
                    '/project/<pid>/files/download/<fid>/version/<vid>/',
                    '/project/<pid>/node/<nid>/files/download/<fid>/version/<vid>/',
                ],
                'get',
                addon_views.addon_view_or_download_file_legacy,
                OsfWebRenderer('project/view_file.mako', trust=False),
            ),
            Rule(
                [
                    # api/v1 Legacy routes for `download_file`
                    '/api/v1/project/<pid>/osffiles/<fid>/',
                    '/api/v1/project/<pid>/node/<nid>/osffiles/<fid>/',
                    '/api/v1/project/<pid>/files/download/<fid>/',
                    '/api/v1/project/<pid>/node/<nid>/files/download/<fid>/',

                    #api/v1 Legacy routes for `download_file_by_version`
                    '/api/v1/project/<pid>/osffiles/<fid>/version/<vid>/',
                    '/api/v1/project/<pid>/node/<nid>/osffiles/<fid>/version/<vid>/',
                    '/api/v1/project/<pid>/files/download/<fid>/version/<vid>/',
                    '/api/v1/project/<pid>/node/<nid>/files/download/<fid>/version/<vid>/',
                ],
                'get',
                addon_views.addon_view_or_download_file_legacy,
                json_renderer),
        ])

    # API

    process_rules(
        app,
        [
            Rule(
                '/email/meeting/',
                'post',
                conference_views.meeting_hook,
                json_renderer,
            ),
            Rule('/mailchimp/hooks/', 'get',
                 profile_views.mailchimp_get_endpoint, json_renderer),
            Rule('/mailchimp/hooks/', 'post',
                 profile_views.sync_data_from_mailchimp, json_renderer),

            # Create project, used by projectCreator.js
            Rule('/project/new/', 'post', project_views.node.project_new_post,
                 json_renderer),
            Rule([
                '/project/<pid>/contributors_abbrev/',
                '/project/<pid>/node/<nid>/contributors_abbrev/',
            ], 'get', project_views.contributor.get_node_contributors_abbrev,
                 json_renderer),
            Rule('/tags/<tag>/', 'get', project_views.tag.project_tag,
                 json_renderer),
            Rule([
                '/project/<pid>/',
                '/project/<pid>/node/<nid>/',
            ], 'get', project_views.node.view_project, json_renderer),
            Rule([
                '/project/<pid>/expand/',
                '/project/<pid>/node/<nid>/expand/',
            ], 'post', project_views.node.expand, json_renderer),
            Rule([
                '/project/<pid>/collapse/',
                '/project/<pid>/node/<nid>/collapse/',
            ], 'post', project_views.node.collapse, json_renderer),
            Rule(
                [
                    '/project/<pid>/pointer/',
                    '/project/<pid>/node/<nid>/pointer/',
                ],
                'get',
                project_views.node.get_pointed,
                json_renderer,
            ),
            Rule(
                [
                    '/project/<pid>/pointer/',
                    '/project/<pid>/node/<nid>/pointer/',
                ],
                'post',
                project_views.node.add_pointers,
                json_renderer,
            ),
            Rule(
                [
                    '/pointer/',
                ],
                'post',
                project_views.node.add_pointer,
                json_renderer,
            ),
            Rule(
                [
                    '/pointers/move/',
                ],
                'post',
                project_views.node.move_pointers,
                json_renderer,
            ),
            Rule(
                [
                    '/project/<pid>/pointer/',
                    '/project/<pid>/node/<nid>pointer/',
                ],
                'delete',
                project_views.node.remove_pointer,
                json_renderer,
            ),
            Rule(
                [
                    '/folder/<pid>/pointer/<pointer_id>',
                ],
                'delete',
                project_views.node.remove_pointer_from_folder,
                json_renderer,
            ),
            Rule(
                [
                    '/folder/<pid>/pointers/',
                ],
                'delete',
                project_views.node.remove_pointers_from_folder,
                json_renderer,
            ),
            Rule(
                [
                    '/folder/<pid>',
                ],
                'delete',
                project_views.node.delete_folder,
                json_renderer,
            ),
            Rule('/folder/', 'put', project_views.node.add_folder,
                 json_renderer),
            Rule([
                '/project/<pid>/get_summary/',
                '/project/<pid>/node/<nid>/get_summary/',
            ], 'get', project_views.node.get_summary, json_renderer),
            Rule([
                '/project/<pid>/get_children/',
                '/project/<pid>/node/<nid>/get_children/',
            ], 'get', project_views.node.get_children, json_renderer),
            Rule(['/project/<pid>/get_folder_pointers/'], 'get',
                 project_views.node.get_folder_pointers, json_renderer),
            Rule([
                '/project/<pid>/get_forks/',
                '/project/<pid>/node/<nid>/get_forks/',
            ], 'get', project_views.node.get_forks, json_renderer),
            Rule([
                '/project/<pid>/get_registrations/',
                '/project/<pid>/node/<nid>/get_registrations/',
            ], 'get', project_views.node.get_registrations, json_renderer),
            Rule('/log/<log_id>/', 'get', project_views.log.get_log,
                 json_renderer),
            Rule([
                '/project/<pid>/log/',
                '/project/<pid>/node/<nid>/log/',
            ], 'get', project_views.log.get_logs, json_renderer),
            Rule([
                '/project/<pid>/get_contributors/',
                '/project/<pid>/node/<nid>/get_contributors/',
            ], 'get', project_views.contributor.get_contributors,
                 json_renderer),
            Rule([
                '/project/<pid>/get_contributors_from_parent/',
                '/project/<pid>/node/<nid>/get_contributors_from_parent/',
            ], 'get', project_views.contributor.get_contributors_from_parent,
                 json_renderer),

            # Reorder contributors
            Rule(
                [
                    '/project/<pid>/contributors/manage/',
                    '/project/<pid>/node/<nid>/contributors/manage/',
                ],
                'POST',
                project_views.contributor.project_manage_contributors,
                json_renderer,
            ),
            Rule([
                '/project/<pid>/get_most_in_common_contributors/',
                '/project/<pid>/node/<nid>/get_most_in_common_contributors/',
            ], 'get',
                 project_views.contributor.get_most_in_common_contributors,
                 json_renderer),
            Rule([
                '/project/<pid>/get_recently_added_contributors/',
                '/project/<pid>/node/<nid>/get_recently_added_contributors/',
            ], 'get',
                 project_views.contributor.get_recently_added_contributors,
                 json_renderer),
            Rule([
                '/project/<pid>/get_editable_children/',
                '/project/<pid>/node/<nid>/get_editable_children/',
            ], 'get', project_views.node.get_editable_children, json_renderer),

            # Private Link
            Rule([
                '/project/<pid>/private_link/',
                '/project/<pid>/node/<nid>/private_link/',
            ], 'post', project_views.node.project_generate_private_link_post,
                 json_renderer),
            Rule([
                '/project/<pid>/private_link/edit/',
                '/project/<pid>/node/<nid>/private_link/edit/',
            ], 'put', project_views.node.project_private_link_edit,
                 json_renderer),
            Rule([
                '/project/<pid>/private_link/',
                '/project/<pid>/node/<nid>/private_link/',
            ], 'delete', project_views.node.remove_private_link,
                 json_renderer),
            Rule([
                '/project/<pid>/private_link/',
                '/project/<pid>/node/<nid>/private_link/',
            ], 'get', project_views.node.private_link_table, json_renderer),

            # Create, using existing project as a template
            Rule([
                '/project/new/<nid>/',
            ], 'post', project_views.node.project_new_from_template,
                 json_renderer),

            # Update
            Rule(
                [
                    '/project/<pid>/',
                    '/project/<pid>/node/<nid>/',
                ],
                'put',
                project_views.node.update_node,
                json_renderer,
            ),

            # Remove
            Rule(
                [
                    '/project/<pid>/',
                    '/project/<pid>/node/<nid>/',
                ],
                'delete',
                project_views.node.component_remove,
                json_renderer,
            ),

            # Reorder components
            Rule('/project/<pid>/reorder_components/', 'post',
                 project_views.node.project_reorder_components, json_renderer),

            # Edit node
            Rule([
                '/project/<pid>/edit/',
                '/project/<pid>/node/<nid>/edit/',
            ], 'post', project_views.node.edit_node, json_renderer),

            # Add / remove tags
            Rule([
                '/project/<pid>/tags/',
                '/project/<pid>/node/<nid>/tags/',
                '/project/<pid>/tags/<tag>/',
                '/project/<pid>/node/<nid>/tags/<tag>/',
            ], 'post', project_views.tag.project_add_tag, json_renderer),
            Rule([
                '/project/<pid>/tags/',
                '/project/<pid>/node/<nid>/tags/',
                '/project/<pid>/tags/<tag>/',
                '/project/<pid>/node/<nid>/tags/<tag>/',
            ], 'delete', project_views.tag.project_remove_tag, json_renderer),

            # Add / remove contributors
            Rule([
                '/project/<pid>/contributors/',
                '/project/<pid>/node/<nid>/contributors/',
            ], 'post', project_views.contributor.project_contributors_post,
                 json_renderer),
            Rule([
                '/project/<pid>/beforeremovecontributors/',
                '/project/<pid>/node/<nid>/beforeremovecontributors/',
            ], 'post',
                 project_views.contributor.project_before_remove_contributor,
                 json_renderer),
            # TODO(sloria): should be a delete request to /contributors/
            Rule([
                '/project/<pid>/removecontributors/',
                '/project/<pid>/node/<nid>/removecontributors/',
            ], 'post', project_views.contributor.project_removecontributor,
                 json_renderer),

            # Forks
            Rule(
                [
                    '/project/<pid>/fork/before/',
                    '/project/<pid>/node/<nid>/fork/before/',
                ],
                'get',
                project_views.node.project_before_fork,
                json_renderer,
            ),
            Rule(
                [
                    '/project/<pid>/fork/',
                    '/project/<pid>/node/<nid>/fork/',
                ],
                'post',
                project_views.node.node_fork_page,
                json_renderer,
            ),
            Rule(
                [
                    '/project/<pid>/pointer/fork/',
                    '/project/<pid>/node/<nid>/pointer/fork/',
                ],
                'post',
                project_views.node.fork_pointer,
                json_renderer,
            ),

            # View forks
            Rule([
                '/project/<pid>/forks/',
                '/project/<pid>/node/<nid>/forks/',
            ], 'get', project_views.node.node_forks, json_renderer),

            # Registrations
            Rule([
                '/project/<pid>/beforeregister/',
                '/project/<pid>/node/<nid>/beforeregister',
            ], 'get', project_views.register.project_before_register,
                 json_renderer),
            Rule([
                '/project/<pid>/register/<template>/',
                '/project/<pid>/node/<nid>/register/<template>/',
            ], 'get', project_views.register.node_register_template_page,
                 json_renderer),
            Rule([
                '/project/<pid>/retraction/',
                '/project/<pid>/node/<nid>/retraction/'
            ], 'post',
                 project_views.register.node_registration_retraction_post,
                 json_renderer),
            Rule([
                '/project/<pid>/register/<template>/',
                '/project/<pid>/node/<nid>/register/<template>/',
            ], 'post', project_views.register.node_register_template_page_post,
                 json_renderer),
            Rule(
                [
                    '/project/<pid>/identifiers/',
                    '/project/<pid>/node/<nid>/identifiers/',
                ],
                'get',
                project_views.register.node_identifiers_get,
                json_renderer,
            ),
            Rule(
                [
                    '/project/<pid>/identifiers/',
                    '/project/<pid>/node/<nid>/identifiers/',
                ],
                'post',
                project_views.register.node_identifiers_post,
                json_renderer,
            ),

            # Statistics
            Rule([
                '/project/<pid>/statistics/',
                '/project/<pid>/node/<nid>/statistics/',
            ], 'get', project_views.node.project_statistics, json_renderer),

            # Permissions
            Rule([
                '/project/<pid>/permissions/<permissions>/',
                '/project/<pid>/node/<nid>/permissions/<permissions>/',
            ], 'post', project_views.node.project_set_privacy, json_renderer),
            Rule([
                '/project/<pid>/permissions/beforepublic/',
                '/project/<pid>/node/<nid>/permissions/beforepublic/',
            ], 'get', project_views.node.project_before_set_public,
                 json_renderer),

            ### Wiki ###

            ### Watching ###
            Rule(['/project/<pid>/watch/', '/project/<pid>/node/<nid>/watch/'],
                 'post', project_views.node.watch_post, json_renderer),
            Rule([
                '/project/<pid>/unwatch/', '/project/<pid>/node/<nid>/unwatch/'
            ], 'post', project_views.node.unwatch_post, json_renderer),
            Rule([
                '/project/<pid>/togglewatch/',
                '/project/<pid>/node/<nid>/togglewatch/'
            ], 'post', project_views.node.togglewatch_post, json_renderer),
            Rule(['/watched/logs/'], 'get', website_views.watched_logs_get,
                 json_renderer),
            ### Accounts ###
            Rule(['/user/merge/'], 'post', auth_views.merge_user_post,
                 json_renderer),

            # Combined files
            Rule(
                ['/project/<pid>/files/', '/project/<pid>/node/<nid>/files/'],
                'get',
                project_views.file.collect_file_trees,
                json_renderer,
            ),

            # Endpoint to fetch Rubeus.JS/Hgrid-formatted data
            Rule([
                '/project/<pid>/files/grid/',
                '/project/<pid>/node/<nid>/files/grid/'
            ], 'get', project_views.file.grid_data, json_renderer),

            # Settings
            Rule(
                '/files/auth/',
                'get',
                addon_views.get_auth,
                json_renderer,
            ),
            Rule(
                [
                    '/project/<pid>/waterbutler/logs/',
                    '/project/<pid>/node/<nid>/waterbutler/logs/',
                ],
                'put',
                addon_views.create_waterbutler_log,
                json_renderer,
            ),
            Rule(
                [
                    '/registration/<pid>/callbacks/',
                ],
                'put',
                project_views.register.registration_callbacks,
                json_renderer,
            ),
            Rule(
                '/settings/addons/',
                'post',
                profile_views.user_choose_addons,
                json_renderer,
            ),
            Rule(
                '/settings/notifications/',
                'get',
                profile_views.user_notifications,
                json_renderer,
            ),
            Rule(
                '/settings/notifications/',
                'post',
                profile_views.user_choose_mailing_lists,
                json_renderer,
            ),
            Rule(
                '/subscriptions/',
                'get',
                notification_views.get_subscriptions,
                json_renderer,
            ),
            Rule(
                [
                    '/project/<pid>/subscriptions/',
                    '/project/<pid>/node/<nid>/subscriptions/'
                ],
                'get',
                notification_views.get_node_subscriptions,
                json_renderer,
            ),
            Rule(
                '/subscriptions/',
                'post',
                notification_views.configure_subscription,
                json_renderer,
            ),
            Rule(
                [
                    '/project/<pid>/settings/addons/',
                    '/project/<pid>/node/<nid>/settings/addons/',
                ],
                'post',
                project_views.node.node_choose_addons,
                json_renderer,
            ),
            Rule(
                [
                    '/project/<pid>/settings/comments/',
                    '/project/<pid>/node/<nid>/settings/comments/',
                ],
                'post',
                project_views.node.configure_comments,
                json_renderer,
            ),

            # Invite Users
            Rule([
                '/project/<pid>/invite_contributor/',
                '/project/<pid>/node/<nid>/invite_contributor/'
            ], 'post', project_views.contributor.invite_contributor_post,
                 json_renderer),
        ],
        prefix='/api/v1')

    # Set up static routing for addons
    # NOTE: We use nginx to serve static addon assets in production
    addon_base_path = os.path.abspath('website/addons')
    if settings.DEV_MODE:

        @app.route('/static/addons/<addon>/<path:filename>')
        def addon_static(addon, filename):
            addon_path = os.path.join(addon_base_path, addon, 'static')
            return send_from_directory(addon_path, filename)
Example #10
0
 def ready(self):
     # Set up Flask routes
     for route_group in self.routes:
         process_rules(app, **route_group)
Example #11
0
 def ready(self):
     # Set up Flask routes
     for route_group in self.routes:
         process_rules(app, **route_group)
Example #12
0
 def test_error_handling(self):
     rule = Rule(['/error/'], 'get', error_view, renderer=json_renderer)
     process_rules(self.app, [rule])
     res = self.wt.get('/error/', expect_errors=True)
     assert_equal(res.status_code, 400)
     assert_true(isinstance(res.json, dict))
Example #13
0
 def test_url_for_with_prefix(self):
     api_rule = Rule(["/project/"], "get", view_func_or_data=dummy_view3,
             renderer=json_renderer)
     process_rules(self.app, [api_rule], prefix="/api/v1")
     with self.app.test_request_context():
         assert_equal(url_for("JSONRenderer__dummy_view3"), "/api/v1/project/")
 def test_url_for_simple(self):
     r = Rule(['/project/'], 'get', view_func_or_data=dummy_view, renderer=json_renderer)
     process_rules(self.app, [r])
     with self.app.test_request_context():
         assert_equal(url_for('JSONRenderer__dummy_view'), '/project/')
Example #15
0
def make_url_map(app):
    """Set up all the routes for the OSF app.

    :param app: A Flask/Werkzeug app to bind the rules to.
    """

    # Set default views to 404, using URL-appropriate renderers
    process_rules(app, [
        Rule(
            '/<path:_>',
            ['get', 'post'],
            HTTPError(http.NOT_FOUND),
            OsfWebRenderer('', render_mako_string, trust=False)
        ),
        Rule(
            '/api/v1/<path:_>',
            ['get', 'post'],
            HTTPError(http.NOT_FOUND),
            json_renderer
        ),
    ])

    ### GUID ###
    process_rules(app, [

        Rule(
            [
                '/<guid>/',
                '/<guid>/<path:suffix>',
            ],
            ['get', 'post', 'put', 'patch', 'delete'],
            website_views.resolve_guid,
            notemplate,
        ),

        Rule(
            [
                '/api/v1/<guid>/',
                '/api/v1/<guid>/<path:suffix>',
            ],
            ['get', 'post', 'put', 'patch', 'delete'],
            website_views.resolve_guid,
            json_renderer,
        ),

    ])

    # Static files
    process_rules(app, [
        Rule('/favicon.ico', 'get', favicon, json_renderer),
        Rule('/robots.txt', 'get', robots, json_renderer),
    ])

    ### Base ###

    process_rules(app, [

        Rule(
            '/dashboard/',
            'get',
            website_views.dashboard,
            OsfWebRenderer('home.mako', trust=False)
        ),

        Rule(
            '/myprojects/',
            'get',
            website_views.my_projects,
            OsfWebRenderer('my_projects.mako', trust=False)
        ),

        Rule(
            '/reproducibility/',
            'get',
            website_views.reproducibility,
            notemplate
        ),
        Rule('/about/', 'get', website_views.redirect_about, notemplate),
        Rule('/help/', 'get', website_views.redirect_help, notemplate),
        Rule('/faq/', 'get', {}, OsfWebRenderer('public/pages/faq.mako', trust=False)),
        Rule(['/getting-started/', '/getting-started/email/', '/howosfworks/'], 'get', website_views.redirect_getting_started, notemplate),
        Rule('/support/', 'get', {}, OsfWebRenderer('public/pages/support.mako', trust=False)),

        Rule(
            '/explore/',
            'get',
            {},
            OsfWebRenderer('public/explore.mako', trust=False)
        ),

        Rule(
            [
                '/messages/',
            ],
            'get',
            {},
            OsfWebRenderer('public/comingsoon.mako', trust=False)
        ),

        Rule(
            '/view/<meeting>/',
            'get',
            conference_views.conference_results,
            OsfWebRenderer('public/pages/meeting.mako', trust=False),
        ),

        Rule(
            '/view/<meeting>/plain/',
            'get',
            conference_views.conference_results,
            OsfWebRenderer('public/pages/meeting_plain.mako', trust=False),
            endpoint_suffix='__plain',
        ),

        Rule(
            '/api/v1/view/<meeting>/',
            'get',
            conference_views.conference_data,
            json_renderer,
        ),

        Rule(
            '/meetings/',
            'get',
            conference_views.conference_view,
            OsfWebRenderer('public/pages/meeting_landing.mako', trust=False),
        ),

        Rule(
            '/api/v1/meetings/submissions/',
            'get',
            conference_views.conference_submissions,
            json_renderer,
        ),

        Rule(
            '/presentations/',
            'get',
            conference_views.redirect_to_meetings,
            json_renderer,
        ),

        Rule(
            '/news/',
            'get',
            website_views.redirect_to_cos_news,
            notemplate
        ),

        Rule(
            '/prereg/',
            'get',
            prereg.prereg_landing_page,
            OsfWebRenderer('prereg_landing_page.mako', trust=False)
        ),

        Rule(
            '/preprints/',
            'get',
            preprint_views.preprint_landing_page,
            OsfWebRenderer('public/pages/preprint_landing.mako', trust=False),
        ),

        Rule(
            '/preprint/',
            'get',
            preprint_views.preprint_redirect,
            notemplate,
        ),

        Rule(
            '/api/v1/prereg/draft_registrations/',
            'get',
            prereg.prereg_draft_registrations,
            json_renderer,
        ),
    ])

    # Site-wide API routes

    process_rules(app, [
        Rule(
            '/citations/styles/',
            'get',
            citation_views.list_citation_styles,
            json_renderer,
        ),
    ], prefix='/api/v1')

    process_rules(app, [
        Rule(
            [
                '/project/<pid>/<addon>/settings/disable/',
                '/project/<pid>/node/<nid>/<addon>/settings/disable/',
            ],
            'post',
            addon_views.disable_addon,
            json_renderer,
        ),

        Rule(
            '/profile/<uid>/<addon>/settings/',
            'get',
            addon_views.get_addon_user_config,
            json_renderer,
        ),
    ], prefix='/api/v1')

    # OAuth

    process_rules(app, [
        Rule(
            '/oauth/connect/<service_name>/',
            'get',
            oauth_views.oauth_connect,
            json_renderer,
        ),

        Rule(
            '/oauth/callback/<service_name>/',
            'get',
            oauth_views.oauth_callback,
            OsfWebRenderer('util/oauth_complete.mako', trust=False),
        ),
    ])
    process_rules(app, [
        Rule(
            [
                '/oauth/accounts/<external_account_id>/',
            ],
            'delete',
            oauth_views.oauth_disconnect,
            json_renderer,
        )
    ], prefix='/api/v1')

    process_rules(app, [
        Rule('/confirmed_emails/', 'put', auth_views.unconfirmed_email_add, json_renderer),
        Rule('/confirmed_emails/', 'delete', auth_views.unconfirmed_email_remove, json_renderer)

    ], prefix='/api/v1')

    ### Metadata ###
    process_rules(app, [

        Rule(
            [
                '/project/<pid>/comments/timestamps/',
                '/project/<pid>/node/<nid>/comments/timestamps/',
            ],
            'put',
            project_views.comment.update_comments_timestamp,
            json_renderer,
        ),

        Rule(
            [
                '/project/<pid>/citation/',
                '/project/<pid>/node/<nid>/citation/',
            ],
            'get',
            citation_views.node_citation,
            json_renderer,
        ),

    ], prefix='/api/v1')

    ### Forms ###

    process_rules(app, [
        Rule('/forms/signin/', 'get', website_views.signin_form, json_renderer),
        Rule('/forms/forgot_password/', 'get', website_views.forgot_password_form, json_renderer),
        Rule('/forms/reset_password/', 'get', website_views.reset_password_form, json_renderer),
    ], prefix='/api/v1')

    ### Discovery ###

    process_rules(app, [

        Rule(
            '/explore/activity/',
            'get',
            discovery_views.activity,
            OsfWebRenderer('public/pages/active_nodes.mako', trust=False)
        ),
    ])

    ### Auth ###

    process_rules(app, [

        # confirm email
        Rule(
            '/confirm/<uid>/<token>/',
            'get',
            auth_views.confirm_email_get,
            notemplate
        ),

        # reset password get
        Rule(
            '/resetpassword/<verification_key>/',
            'get',
            auth_views.reset_password_get,
            OsfWebRenderer('public/resetpassword.mako', render_mako_string, trust=False)
        ),

        # reset password post
        Rule(
            '/resetpassword/<verification_key>/',
            'post',
            auth_views.reset_password_post,
            OsfWebRenderer('public/resetpassword.mako', render_mako_string, trust=False)
        ),

        # resend confirmation get
        Rule(
            '/resend/',
            'get',
            auth_views.resend_confirmation_get,
            OsfWebRenderer('resend.mako', render_mako_string, trust=False)
        ),

        # resend confirmation post
        Rule(
            '/resend/',
            'post',
            auth_views.resend_confirmation_post,
            OsfWebRenderer('resend.mako', render_mako_string, trust=False)

        ),

        # user sign up page
        Rule(
            '/register/',
            'get',
            auth_views.auth_register,
            OsfWebRenderer('public/login.mako', trust=False)
        ),

        # create user account via api
        Rule(
            '/api/v1/register/',
            'post',
            auth_views.register_user,
            json_renderer
        ),

        # osf login and campaign login
        Rule(
            [
                '/login/',
                '/account/'
            ],
            'get',
            auth_views.auth_login,
            OsfWebRenderer('public/login.mako', trust=False)
        ),

        # osf logout and cas logout
        Rule(
            '/logout/',
            'get',
            auth_views.auth_logout,
            notemplate
        ),

        # forgot password get
        Rule(
            '/forgotpassword/',
            'get',
            auth_views.forgot_password_get,
            OsfWebRenderer('public/forgot_password.mako', trust=False)
        ),

        # forgot password post
        Rule(
            '/forgotpassword/',
            'post',
            auth_views.forgot_password_post,
            OsfWebRenderer('public/forgot_password.mako', trust=False)
        ),

        Rule(
            '/login/connected_tools/',
            'get',
            landing_page_views.connected_tools,
            notemplate
        ),

        Rule(
            '/login/enriched_profile/',
            'get',
            landing_page_views.enriched_profile,
            notemplate
        ),

    ])

    ### Profile ###

    # Web

    process_rules(app, [
        Rule(
            '/profile/',
            'get',
            profile_views.profile_view,
            OsfWebRenderer('profile.mako', trust=False)
        ),

        Rule(
            '/profile/<uid>/',
            'get',
            profile_views.profile_view_id,
            OsfWebRenderer('profile.mako', trust=False)
        ),

        # Route for claiming and setting email and password.
        # Verification token must be querystring argument
        Rule(
            ['/user/<uid>/<pid>/claim/'],
            ['get', 'post'],
            project_views.contributor.claim_user_form,
            OsfWebRenderer('claim_account.mako', trust=False)
        ),

        Rule(
            ['/user/<uid>/<pid>/claim/verify/<token>/'],
            ['get', 'post'],
            project_views.contributor.claim_user_registered,
            OsfWebRenderer('claim_account_registered.mako', trust=False)
        ),

        Rule(
            '/settings/',
            'get',
            profile_views.user_profile,
            OsfWebRenderer('profile/settings.mako', trust=False),
        ),

        Rule(
            '/settings/account/',
            'get',
            profile_views.user_account,
            OsfWebRenderer('profile/account.mako', trust=False),
        ),

        Rule(
            '/settings/account/password',
            'post',
            profile_views.user_account_password,
            OsfWebRenderer('profile/account.mako', trust=False),
        ),

        Rule(
            '/settings/addons/',
            'get',
            profile_views.user_addons,
            OsfWebRenderer('profile/addons.mako', trust=False),
        ),

        Rule(
            '/settings/notifications/',
            'get',
            profile_views.user_notifications,
            OsfWebRenderer('profile/notifications.mako', trust=False),
        ),

        Rule(
            '/settings/applications/',
            'get',
            profile_views.oauth_application_list,
            OsfWebRenderer('profile/oauth_app_list.mako', trust=False)
        ),

        Rule(
            '/settings/applications/create/',
            'get',
            profile_views.oauth_application_register,
            OsfWebRenderer('profile/oauth_app_detail.mako', trust=False)
        ),

        Rule(
            '/settings/applications/<client_id>/',
            'get',
            profile_views.oauth_application_detail,
            OsfWebRenderer('profile/oauth_app_detail.mako', trust=False)
        ),

        Rule(
            '/settings/tokens/',
            'get',
            profile_views.personal_access_token_list,
            OsfWebRenderer('profile/personal_tokens_list.mako', trust=False)
        ),

        Rule(
            '/settings/tokens/create/',
            'get',
            profile_views.personal_access_token_register,
            OsfWebRenderer('profile/personal_tokens_detail.mako', trust=False)
        ),

        Rule(
            '/settings/tokens/<_id>/',
            'get',
            profile_views.personal_access_token_detail,
            OsfWebRenderer('profile/personal_tokens_detail.mako', trust=False)
        ),


        # TODO: Uncomment once outstanding issues with this feature are addressed
        # Rule(
        #     '/@<twitter_handle>/',
        #     'get',
        #     profile_views.redirect_to_twitter,
        #     OsfWebRenderer('error.mako', render_mako_string, trust=False)
        # ),
    ])

    # API

    process_rules(app, [

        Rule('/profile/', 'get', profile_views.profile_view, json_renderer),
        Rule('/profile/', 'put', profile_views.update_user, json_renderer),
        Rule('/resend/', 'put', profile_views.resend_confirmation, json_renderer),
        Rule('/profile/<uid>/', 'get', profile_views.profile_view_id, json_renderer),

        # Used by profile.html
        Rule('/profile/<uid>/edit/', 'post', profile_views.edit_profile, json_renderer),
        Rule('/profile/<uid>/public_projects/', 'get',
             profile_views.get_public_projects, json_renderer),
        Rule('/profile/<uid>/public_components/', 'get',
             profile_views.get_public_components, json_renderer),

        Rule('/profile/<user_id>/summary/', 'get',
             profile_views.get_profile_summary, json_renderer),
        Rule('/user/<uid>/<pid>/claim/email/', 'post',
             project_views.contributor.claim_user_post, json_renderer),

        Rule(
            '/profile/export/',
            'post',
            profile_views.request_export,
            json_renderer,
        ),

        Rule(
            '/profile/deactivate/',
            'post',
            profile_views.request_deactivation,
            json_renderer,
        ),

        Rule(
            [
                '/profile/gravatar/',
                '/users/gravatar/',
                '/profile/gravatar/<size>',
                '/users/gravatar/<size>',
            ],
            'get',
            profile_views.current_user_gravatar,
            json_renderer,
        ),

        Rule(
            [
                '/profile/<uid>/gravatar/',
                '/users/<uid>/gravatar/',
                '/profile/<uid>/gravatar/<size>',
                '/users/<uid>/gravatar/<size>',
            ],
            'get',
            profile_views.get_gravatar,
            json_renderer,
        ),


        # Rules for user profile configuration
        Rule('/settings/names/', 'get', profile_views.serialize_names, json_renderer),
        Rule('/settings/names/', 'put', profile_views.unserialize_names, json_renderer),
        Rule('/settings/names/impute/', 'get', profile_views.impute_names, json_renderer),

        Rule(
            [
                '/settings/social/',
                '/settings/social/<uid>/',
            ],
            'get',
            profile_views.serialize_social,
            json_renderer,
        ),

        Rule(
            [
                '/settings/jobs/',
                '/settings/jobs/<uid>/',
            ],
            'get',
            profile_views.serialize_jobs,
            json_renderer,
        ),

        Rule(
            [
                '/settings/schools/',
                '/settings/schools/<uid>/',
            ],
            'get',
            profile_views.serialize_schools,
            json_renderer,
        ),

        Rule(
            [
                '/settings/social/',
                '/settings/social/<uid>/',
            ],
            'put',
            profile_views.unserialize_social,
            json_renderer
        ),

        Rule(
            [
                '/settings/jobs/',
                '/settings/jobs/<uid>/',
            ],
            'put',
            profile_views.unserialize_jobs,
            json_renderer
        ),

        Rule(
            [
                '/settings/schools/',
                '/settings/schools/<uid>/',
            ],
            'put',
            profile_views.unserialize_schools,
            json_renderer
        ),

    ], prefix='/api/v1',)

    ### Search ###

    # Web

    process_rules(app, [

        Rule(
            '/search/',
            'get',
            {},
            OsfWebRenderer('search.mako', trust=False)
        ),
        Rule(
            '/share/',
            'get',
            {},
            OsfWebRenderer('share_search.mako', trust=False)
        ),
        Rule(
            '/share/registration/',
            'get',
            {'register': settings.SHARE_REGISTRATION_URL},
            OsfWebRenderer('share_registration.mako', trust=False)
        ),
        Rule(
            '/share/help/',
            'get',
            {'help': settings.SHARE_API_DOCS_URL},
            OsfWebRenderer('share_api_docs.mako', trust=False)
        ),
        Rule(  # FIXME: Dead route; possible that template never existed; confirm deletion candidate with ErinB
            '/share_dashboard/',
            'get',
            {},
            OsfWebRenderer('share_dashboard.mako', trust=False)
        ),
        Rule(
            '/share/atom/',
            'get',
            search_views.search_share_atom,
            xml_renderer
        ),
        Rule('/api/v1/user/search/', 'get', search_views.search_contributor, json_renderer),

        Rule(
            '/api/v1/search/node/',
            'post',
            project_views.node.search_node,
            json_renderer,
        ),

    ])

    # API

    process_rules(app, [

        Rule(['/search/', '/search/<type>/'], ['get', 'post'], search_views.search_search, json_renderer),
        Rule('/search/projects/', 'get', search_views.search_projects_by_title, json_renderer),
        Rule('/share/search/', ['get', 'post'], search_views.search_share, json_renderer),
        Rule('/share/stats/', 'get', search_views.search_share_stats, json_renderer),
        Rule('/share/providers/', 'get', search_views.search_share_providers, json_renderer),

    ], prefix='/api/v1')

    # Institution

    process_rules(app, [
        Rule('/institutions/<inst_id>/', 'get', institution_views.view_institution, OsfWebRenderer('institution.mako', trust=False))
    ])

    # Project

    # Web

    process_rules(app, [
        # '/' route loads home.mako if logged in, otherwise loads landing.mako
        Rule('/', 'get', website_views.index, OsfWebRenderer('index.mako', trust=False)),

        Rule('/goodbye/', 'get', goodbye, OsfWebRenderer('landing.mako', trust=False)),

        Rule(
            [
                '/project/<pid>/',
                '/project/<pid>/node/<nid>/',
            ],
            'get',
            project_views.node.view_project,
            OsfWebRenderer('project/project.mako', trust=False)
        ),

        # Create a new subproject/component
        Rule(
            '/project/<pid>/newnode/',
            'post',
            project_views.node.project_new_node,
            notemplate
        ),

        # # TODO: Add API endpoint for tags
        # Rule('/tags/<tag>/', 'get', project_views.tag.project_tag, OsfWebRenderer('tags.mako', trust=False)),
        Rule('/project/new/<pid>/beforeTemplate/', 'get',
             project_views.node.project_before_template, json_renderer),

        Rule(
            [
                '/project/<pid>/contributors/',
                '/project/<pid>/node/<nid>/contributors/',
            ],
            'get',
            project_views.node.node_contributors,
            OsfWebRenderer('project/contributors.mako', trust=False),
        ),

        Rule(
            [
                '/project/<pid>/settings/',
                '/project/<pid>/node/<nid>/settings/',
            ],
            'get',
            project_views.node.node_setting,
            OsfWebRenderer('project/settings.mako', trust=False)
        ),

        # Permissions
        Rule(  # TODO: Where, if anywhere, is this route used?
            [
                '/project/<pid>/permissions/<permissions>/',
                '/project/<pid>/node/<nid>/permissions/<permissions>/',
            ],
            'post',
            project_views.node.project_set_privacy,
            OsfWebRenderer('project/project.mako', trust=False)
        ),

        ### Logs ###

        # View forks
        Rule(
            [
                '/project/<pid>/forks/',
                '/project/<pid>/node/<nid>/forks/',
            ],
            'get',
            project_views.node.node_forks,
            OsfWebRenderer('project/forks.mako', trust=False)
        ),

        # Registrations
        Rule(
            [
                '/project/<pid>/register/',
                '/project/<pid>/node/<nid>/register/',
            ],
            'get',
            project_views.register.node_register_page,
            OsfWebRenderer('project/register.mako', trust=False)
        ),

        Rule(
            [
                '/project/<pid>/register/<metaschema_id>/',
                '/project/<pid>/node/<nid>/register/<metaschema_id>/',
            ],
            'get',
            project_views.register.node_register_template_page,
            OsfWebRenderer('project/register.mako', trust=False)
        ),
        Rule(
            [
                '/project/<pid>/registrations/',
                '/project/<pid>/node/<nid>/registrations/',
            ],
            'get',
            project_views.node.node_registrations,
            OsfWebRenderer('project/registrations.mako', trust=False)
        ),
        Rule(
            [
                '/project/<pid>/registrations/',
                '/project/<pid>/node/<nid>/registrations/',
            ],
            'post',
            project_views.drafts.new_draft_registration,
            OsfWebRenderer('project/edit_draft_registration.mako', trust=False)),
        Rule(
            [
                '/project/<pid>/drafts/<draft_id>/',
                '/project/<pid>/node/<nid>/drafts/<draft_id>/',
            ],
            'get',
            project_views.drafts.edit_draft_registration_page,
            OsfWebRenderer('project/edit_draft_registration.mako', trust=False)),
        Rule(
            [
                '/project/<pid>/drafts/<draft_id>/register/',
                '/project/<pid>/node/<nid>/drafts/<draft_id>/register/',
            ],
            'get',
            project_views.drafts.draft_before_register_page,
            OsfWebRenderer('project/register_draft.mako', trust=False)),

        Rule(
            [
                '/project/<pid>/retraction/',
                '/project/<pid>/node/<nid>/retraction/',
            ],
            'get',
            project_views.register.node_registration_retraction_redirect,
            notemplate,
        ),

        Rule(
            [
                '/project/<pid>/withdraw/',
                '/project/<pid>/node/<nid>/withdraw/',
            ],
            'get',
            project_views.register.node_registration_retraction_get,
            OsfWebRenderer('project/retract_registration.mako', trust=False)
        ),

        Rule(
            '/ids/<category>/<path:value>/',
            'get',
            project_views.register.get_referent_by_identifier,
            notemplate,
        ),

        # Statistics
        Rule(
            [
                '/project/<pid>/statistics/',
                '/project/<pid>/node/<nid>/statistics/',
            ],
            'get',
            project_views.node.project_statistics_redirect,
            notemplate,
        ),

        Rule(
            [
                '/project/<pid>/analytics/',
                '/project/<pid>/node/<nid>/analytics/',
            ],
            'get',
            project_views.node.project_statistics,
            OsfWebRenderer('project/statistics.mako', trust=False)
        ),

        ### Files ###

        # Note: Web endpoint for files view must pass `mode` = `page` to
        # include project view data and JS includes
        # TODO: Start waterbutler to test
        Rule(
            [
                '/project/<pid>/files/',
                '/project/<pid>/node/<nid>/files/',
            ],
            'get',
            project_views.file.collect_file_trees,
            OsfWebRenderer('project/files.mako', trust=False),
            view_kwargs={'mode': 'page'},
        ),
        Rule(
            [
                '/project/<pid>/files/<provider>/<path:path>/',
                '/project/<pid>/node/<nid>/files/<provider>/<path:path>/',
            ],
            'get',
            addon_views.addon_view_or_download_file,
            OsfWebRenderer('project/view_file.mako', trust=False)
        ),
        Rule(
            [
                '/project/<pid>/files/deleted/<trashed_id>/',
                '/project/<pid>/node/<nid>/files/deleted/<trashed_id>/',
            ],
            'get',
            addon_views.addon_deleted_file,
            OsfWebRenderer('project/view_file.mako', trust=False)
        ),
        Rule(
            [
                # Legacy Addon view file paths
                '/project/<pid>/<provider>/files/<path:path>/',
                '/project/<pid>/node/<nid>/<provider>/files/<path:path>/',

                '/project/<pid>/<provider>/files/<path:path>/download/',
                '/project/<pid>/node/<nid>/<provider>/files/<path:path>/download/',

                # Legacy routes for `download_file`
                '/project/<pid>/osffiles/<fid>/download/',
                '/project/<pid>/node/<nid>/osffiles/<fid>/download/',

                # Legacy routes for `view_file`
                '/project/<pid>/osffiles/<fid>/',
                '/project/<pid>/node/<nid>/osffiles/<fid>/',

                # Note: Added these old URLs for backwards compatibility with
                # hard-coded links.
                '/project/<pid>/osffiles/download/<fid>/',
                '/project/<pid>/node/<nid>/osffiles/download/<fid>/',
                '/project/<pid>/files/<fid>/',
                '/project/<pid>/node/<nid>/files/<fid>/',
                '/project/<pid>/files/download/<fid>/',
                '/project/<pid>/node/<nid>/files/download/<fid>/',

                # Legacy routes for `download_file_by_version`
                '/project/<pid>/osffiles/<fid>/version/<vid>/download/',
                '/project/<pid>/node/<nid>/osffiles/<fid>/version/<vid>/download/',
                # Note: Added these old URLs for backwards compatibility with
                # hard-coded links.
                '/project/<pid>/osffiles/<fid>/version/<vid>/',
                '/project/<pid>/node/<nid>/osffiles/<fid>/version/<vid>/',
                '/project/<pid>/osffiles/download/<fid>/version/<vid>/',
                '/project/<pid>/node/<nid>/osffiles/download/<fid>/version/<vid>/',
                '/project/<pid>/files/<fid>/version/<vid>/',
                '/project/<pid>/node/<nid>/files/<fid>/version/<vid>/',
                '/project/<pid>/files/download/<fid>/version/<vid>/',
                '/project/<pid>/node/<nid>/files/download/<fid>/version/<vid>/',
            ],
            'get',
            addon_views.addon_view_or_download_file_legacy,
            OsfWebRenderer('project/view_file.mako', trust=False),
        ),
        Rule(
            [
                # api/v1 Legacy routes for `download_file`
                '/api/v1/project/<pid>/osffiles/<fid>/',
                '/api/v1/project/<pid>/node/<nid>/osffiles/<fid>/',
                '/api/v1/project/<pid>/files/download/<fid>/',
                '/api/v1/project/<pid>/node/<nid>/files/download/<fid>/',

                #api/v1 Legacy routes for `download_file_by_version`
                '/api/v1/project/<pid>/osffiles/<fid>/version/<vid>/',
                '/api/v1/project/<pid>/node/<nid>/osffiles/<fid>/version/<vid>/',
                '/api/v1/project/<pid>/files/download/<fid>/version/<vid>/',
                '/api/v1/project/<pid>/node/<nid>/files/download/<fid>/version/<vid>/',
            ],
            'get',
            addon_views.addon_view_or_download_file_legacy,
            json_renderer
        ),
    ])

    # API

    process_rules(app, [

        Rule(
            '/email/meeting/',
            'post',
            conference_views.meeting_hook,
            json_renderer,
        ),
        Rule('/mailchimp/hooks/', 'get', profile_views.mailchimp_get_endpoint, json_renderer),

        Rule('/mailchimp/hooks/', 'post', profile_views.sync_data_from_mailchimp, json_renderer),

        # Create project, used by [coming replacement]
        Rule('/project/new/', 'post', project_views.node.project_new_post, json_renderer),

        Rule([
            '/project/<pid>/contributors_abbrev/',
            '/project/<pid>/node/<nid>/contributors_abbrev/',
        ], 'get', project_views.contributor.get_node_contributors_abbrev, json_renderer),

        Rule('/tags/<tag>/', 'get', project_views.tag.project_tag, json_renderer),

        Rule([
            '/project/<pid>/',
            '/project/<pid>/node/<nid>/',
        ], 'get', project_views.node.view_project, json_renderer),
        Rule(
            [
                '/project/<pid>/pointer/',
                '/project/<pid>/node/<nid>/pointer/',
            ],
            'get',
            project_views.node.get_pointed,
            json_renderer,
        ),
        Rule(
            [
                '/project/<pid>/pointer/',
                '/project/<pid>/node/<nid>/pointer/',
            ],
            'post',
            project_views.node.add_pointers,
            json_renderer,
        ),
        Rule(
            [
                '/pointer/',
            ],
            'post',
            project_views.node.add_pointer,
            json_renderer,
        ),
        Rule(
            [
                '/pointers/move/',
            ],
            'post',
            project_views.node.move_pointers,
            json_renderer,
        ),
        Rule(
            [
                '/project/<pid>/pointer/',
                '/project/<pid>/node/<nid>pointer/',
            ],
            'delete',
            project_views.node.remove_pointer,
            json_renderer,
        ),
        Rule(
            [
                '/folder/<pid>/pointer/<pointer_id>',
            ],
            'delete',
            project_views.node.remove_pointer_from_folder,
            json_renderer,
        ),
        Rule([
            '/project/<pid>/get_summary/',
            '/project/<pid>/node/<nid>/get_summary/',
        ], 'get', project_views.node.get_summary, json_renderer),
        # TODO: [#OSF-6557] Route "get_children" is deprecated. Use get_readable_descendants.
        Rule([
            '/project/<pid>/get_children/',
            '/project/<pid>/node/<nid>/get_children/',
            '/project/<pid>/get_readable_descendants/',
            '/project/<pid>/node/<nid>/get_readable_descendants/',
        ], 'get', project_views.node.get_readable_descendants, json_renderer),
        Rule([
            '/project/<pid>/get_forks/',
            '/project/<pid>/node/<nid>/get_forks/',
        ], 'get', project_views.node.get_forks, json_renderer),
        Rule([
            '/project/<pid>/get_registrations/',
            '/project/<pid>/node/<nid>/get_registrations/',
        ], 'get', project_views.node.get_registrations, json_renderer),

        # Draft Registrations
        Rule([
            '/project/<pid>/drafts/',
        ], 'get', project_views.drafts.get_draft_registrations, json_renderer),
        Rule([
            '/project/<pid>/drafts/<draft_id>/',
        ], 'get', project_views.drafts.get_draft_registration, json_renderer),
        Rule([
            '/project/<pid>/drafts/<draft_id>/',
        ], 'put', project_views.drafts.update_draft_registration, json_renderer),
        Rule([
            '/project/<pid>/drafts/<draft_id>/',
        ], 'delete', project_views.drafts.delete_draft_registration, json_renderer),
        Rule([
            '/project/<pid>/drafts/<draft_id>/submit/',
        ], 'post', project_views.drafts.submit_draft_for_review, json_renderer),

        # Meta Schemas
        Rule([
            '/project/drafts/schemas/',
        ], 'get', project_views.drafts.get_metaschemas, json_renderer),

        Rule([
            '/project/<pid>/get_contributors/',
            '/project/<pid>/node/<nid>/get_contributors/',
        ], 'get', project_views.contributor.get_contributors, json_renderer),

        Rule([
            '/project/<pid>/get_contributors_from_parent/',
            '/project/<pid>/node/<nid>/get_contributors_from_parent/',
        ], 'get', project_views.contributor.get_contributors_from_parent, json_renderer),

        # Reorder contributors
        Rule(
            [
                '/project/<pid>/contributors/manage/',
                '/project/<pid>/node/<nid>/contributors/manage/',
            ],
            'POST',
            project_views.contributor.project_manage_contributors,
            json_renderer,
        ),

        Rule(
            [
                '/project/<pid>/contributor/remove/',
                '/project/<pid>/node/<nid>/contributor/remove/',
            ],
            'POST',
            project_views.contributor.project_remove_contributor,
            json_renderer,
        ),

        Rule([
            '/project/<pid>/get_editable_children/',
            '/project/<pid>/node/<nid>/get_editable_children/',
        ], 'get', project_views.node.get_editable_children, json_renderer),


        # Private Link
        Rule([
            '/project/<pid>/private_link/',
            '/project/<pid>/node/<nid>/private_link/',
        ], 'post', project_views.node.project_generate_private_link_post, json_renderer),

        Rule([
            '/project/<pid>/private_link/edit/',
            '/project/<pid>/node/<nid>/private_link/edit/',
        ], 'put', project_views.node.project_private_link_edit, json_renderer),

        Rule([
            '/project/<pid>/private_link/',
            '/project/<pid>/node/<nid>/private_link/',
        ], 'delete', project_views.node.remove_private_link, json_renderer),

        Rule([
            '/project/<pid>/private_link/',
            '/project/<pid>/node/<nid>/private_link/',
        ], 'get', project_views.node.private_link_table, json_renderer),

        # Create, using existing project as a template
        Rule([
            '/project/new/<nid>/',
        ], 'post', project_views.node.project_new_from_template, json_renderer),

        # Update
        Rule(
            [
                '/project/<pid>/',
                '/project/<pid>/node/<nid>/',
            ],
            'put',
            project_views.node.update_node,
            json_renderer,
        ),

        # Remove
        Rule(
            [
                '/project/<pid>/',
                '/project/<pid>/node/<nid>/',
            ],
            'delete',
            project_views.node.component_remove,
            json_renderer,
        ),

        # Reorder components
        Rule('/project/<pid>/reorder_components/', 'post',
             project_views.node.project_reorder_components, json_renderer),

        # Edit node
        Rule([
            '/project/<pid>/edit/',
            '/project/<pid>/node/<nid>/edit/',
        ], 'post', project_views.node.edit_node, json_renderer),

        # Add / remove tags
        Rule([
            '/project/<pid>/tags/',
            '/project/<pid>/node/<nid>/tags/',
            '/project/<pid>/tags/<tag>/',
            '/project/<pid>/node/<nid>/tags/<tag>/',
        ], 'post', project_views.tag.project_add_tag, json_renderer),
        Rule([
            '/project/<pid>/tags/',
            '/project/<pid>/node/<nid>/tags/',
            '/project/<pid>/tags/<tag>/',
            '/project/<pid>/node/<nid>/tags/<tag>/',
        ], 'delete', project_views.tag.project_remove_tag, json_renderer),

        # Add / remove contributors
        Rule([
            '/project/<pid>/contributors/',
            '/project/<pid>/node/<nid>/contributors/',
        ], 'post', project_views.contributor.project_contributors_post, json_renderer),
        # Forks
        Rule(
            [
                '/project/<pid>/fork/before/',
                '/project/<pid>/node/<nid>/fork/before/',
            ], 'get', project_views.node.project_before_fork, json_renderer,
        ),
        Rule(
            [
                '/project/<pid>/fork/',
                '/project/<pid>/node/<nid>/fork/',
            ], 'post', project_views.node.node_fork_page, json_renderer,
        ),
        Rule(
            [
                '/project/<pid>/pointer/fork/',
                '/project/<pid>/node/<nid>/pointer/fork/',
            ], 'post', project_views.node.fork_pointer, json_renderer,
        ),
        # View forks
        Rule([
            '/project/<pid>/forks/',
            '/project/<pid>/node/<nid>/forks/',
        ], 'get', project_views.node.node_forks, json_renderer),

        # Registrations
        Rule([
            '/project/<pid>/beforeregister/',
            '/project/<pid>/node/<nid>/beforeregister',
        ], 'get', project_views.register.project_before_register, json_renderer),
        Rule([
            '/project/<pid>/drafts/<draft_id>/register/',
            '/project/<pid>/node/<nid>/drafts/<draft_id>/register/',
        ], 'post', project_views.drafts.register_draft_registration, json_renderer),
        Rule([
            '/project/<pid>/register/<template>/',
            '/project/<pid>/node/<nid>/register/<template>/',
        ], 'get', project_views.register.node_register_template_page, json_renderer),
        Rule([
            '/project/<pid>/withdraw/',
            '/project/<pid>/node/<nid>/withdraw/'
        ], 'post', project_views.register.node_registration_retraction_post, json_renderer),

        Rule(
            [
                '/project/<pid>/identifiers/',
                '/project/<pid>/node/<nid>/identifiers/',
            ],
            'get',
            project_views.register.node_identifiers_get,
            json_renderer,
        ),

        Rule(
            [
                '/project/<pid>/identifiers/',
                '/project/<pid>/node/<nid>/identifiers/',
            ],
            'post',
            project_views.register.node_identifiers_post,
            json_renderer,
        ),

        # Statistics
        Rule([
            '/project/<pid>/statistics/',
            '/project/<pid>/node/<nid>/statistics/',
        ], 'get', project_views.node.project_statistics, json_renderer),

        # Permissions
        Rule([
            '/project/<pid>/permissions/<permissions>/',
            '/project/<pid>/node/<nid>/permissions/<permissions>/',
        ], 'post', project_views.node.project_set_privacy, json_renderer),

        Rule([
            '/project/<pid>/permissions/beforepublic/',
            '/project/<pid>/node/<nid>/permissions/beforepublic/',
        ], 'get', project_views.node.project_before_set_public, json_renderer),

        ### Watching ###
        Rule([
            '/project/<pid>/watch/',
            '/project/<pid>/node/<nid>/watch/'
        ], 'post', project_views.node.watch_post, json_renderer),

        Rule([
            '/project/<pid>/unwatch/',
            '/project/<pid>/node/<nid>/unwatch/'
        ], 'post', project_views.node.unwatch_post, json_renderer),

        Rule([
            '/project/<pid>/togglewatch/',
            '/project/<pid>/node/<nid>/togglewatch/'
        ], 'post', project_views.node.togglewatch_post, json_renderer),

        # Combined files
        Rule(
            [
                '/project/<pid>/files/',
                '/project/<pid>/node/<nid>/files/'
            ],
            'get',
            project_views.file.collect_file_trees,
            json_renderer,
        ),

        # Endpoint to fetch Rubeus.JS/Hgrid-formatted data
        Rule(
            [
                '/project/<pid>/files/grid/',
                '/project/<pid>/node/<nid>/files/grid/'
            ],
            'get',
            project_views.file.grid_data,
            json_renderer
        ),

        # Settings

        Rule(
            '/files/auth/',
            'get',
            addon_views.get_auth,
            json_renderer,
        ),

        Rule(
            [
                '/project/<pid>/waterbutler/logs/',
                '/project/<pid>/node/<nid>/waterbutler/logs/',
            ],
            'put',
            addon_views.create_waterbutler_log,
            json_renderer,
        ),
        Rule(
            [
                '/registration/<pid>/callbacks/',
            ],
            'put',
            project_views.register.registration_callbacks,
            json_renderer,
        ),
        Rule(
            '/settings/addons/',
            'post',
            profile_views.user_choose_addons,
            json_renderer,
        ),

        Rule(
            '/settings/notifications/',
            'get',
            profile_views.user_notifications,
            json_renderer,
        ),

        Rule(
            '/settings/notifications/',
            'post',
            profile_views.user_choose_mailing_lists,
            json_renderer,
        ),

        Rule(
            '/subscriptions/',
            'get',
            notification_views.get_subscriptions,
            json_renderer,
        ),

        Rule(
            [
                '/project/<pid>/subscriptions/',
                '/project/<pid>/node/<nid>/subscriptions/'
            ],
            'get',
            notification_views.get_node_subscriptions,
            json_renderer,
        ),

        Rule(
            [
                '/project/<pid>/tree/',
                '/project/<pid>/node/<nid>/tree/'
            ],
            'get',
            project_views.node.get_node_tree,
            json_renderer,
        ),

        Rule(
            '/subscriptions/',
            'post',
            notification_views.configure_subscription,
            json_renderer,
        ),

        Rule(
            [
                '/project/<pid>/settings/addons/',
                '/project/<pid>/node/<nid>/settings/addons/',
            ],
            'post',
            project_views.node.node_choose_addons,
            json_renderer,
        ),

        Rule(
            [
                '/project/<pid>/settings/comments/',
                '/project/<pid>/node/<nid>/settings/comments/',
            ],
            'post',
            project_views.node.configure_comments,
            json_renderer,
        ),

        # Invite Users
        Rule(
            [
                '/project/<pid>/invite_contributor/',
                '/project/<pid>/node/<nid>/invite_contributor/'
            ],
            'post',
            project_views.contributor.invite_contributor_post,
            json_renderer
        )
    ], prefix='/api/v1')

    # Set up static routing for addons
    # NOTE: We use nginx to serve static addon assets in production
    addon_base_path = os.path.abspath('website/addons')
    if settings.DEV_MODE:
        @app.route('/static/addons/<addon>/<path:filename>')
        def addon_static(addon, filename):
            addon_path = os.path.join(addon_base_path, addon, 'static')
            return send_from_directory(addon_path, filename)
 def test_url_for_with_prefix(self):
     api_rule = Rule(['/project/'], 'get', view_func_or_data=dummy_view3,
             renderer=json_renderer)
     process_rules(self.app, [api_rule], prefix='/api/v1')
     with self.app.test_request_context():
         assert_equal(url_for('JSONRenderer__dummy_view3'), '/api/v1/project/')
 def test_url_for_with_argument(self):
     r = Rule(['/project/<pid>/'], 'get', view_func_or_data=dummy_view2, renderer=json_renderer)
     process_rules(self.app, [r])
     with self.app.test_request_context():
         assert_equal(url_for('JSONRenderer__dummy_view2', pid=123), '/project/123/')
Example #18
0
def make_url_map(app):
    '''Set up all the routes for the OSF app.

    :param app: A Flask/Werkzeug app to bind the rules to.
    '''

    # Set default views to 404, using URL-appropriate renderers
    process_rules(app, [
        Rule('/<path:_>', ['get', 'post'], HTTPError(http.NOT_FOUND),
             OsfWebRenderer('', render_mako_string)),
        Rule('/api/v1/<path:_>', ['get', 'post'],
             HTTPError(http.NOT_FOUND), json_renderer),
    ])

    ### GUID ###
    process_rules(app, [

        Rule(
            [
                '/<guid>/',
                '/<guid>/<path:suffix>',
            ],
            ['get', 'post', 'put', 'patch', 'delete'],
            website_views.resolve_guid,
            notemplate,
        ),

        Rule(
            [
                '/api/v1/<guid>/',
                '/api/v1/<guid>/<path:suffix>',
            ],
            ['get', 'post', 'put', 'patch', 'delete'],
            website_views.resolve_guid,
            json_renderer,
        ),

    ])

    # Static files
    process_rules(app, [
        Rule('/favicon.ico', 'get', favicon, json_renderer),
        Rule('/robots.txt', 'get', robots, json_renderer),
    ])

    ### Base ###

    process_rules(app, [

        Rule('/dashboard/', 'get', website_views.dashboard, OsfWebRenderer('dashboard.mako')),
        Rule('/reproducibility/', 'get',
             website_views.reproducibility, OsfWebRenderer('', render_mako_string)),

        Rule('/about/', 'get', {}, OsfWebRenderer('public/pages/about.mako')),
        Rule('/howosfworks/', 'get', {}, OsfWebRenderer('public/pages/howosfworks.mako')),
        Rule('/faq/', 'get', {}, OsfWebRenderer('public/pages/faq.mako')),
        Rule('/getting-started/', 'get', {}, OsfWebRenderer('public/pages/getting_started.mako')),
        Rule('/explore/', 'get', {}, OsfWebRenderer('public/explore.mako')),
        Rule(['/messages/', '/help/'], 'get', {}, OsfWebRenderer('public/comingsoon.mako')),

        Rule(
            '/view/<meeting>/',
            'get',
            conference_views.conference_results,
            OsfWebRenderer('public/pages/meeting.mako'),
        ),

        Rule(
            '/view/<meeting>/plain/',
            'get',
            conference_views.conference_results,
            OsfWebRenderer('public/pages/meeting_plain.mako'),
            endpoint_suffix='__plain',
        ),

        Rule(
            '/api/v1/view/<meeting>/',
            'get',
            conference_views.conference_data,
            json_renderer,
        ),

        Rule(
            '/meetings/',
            'get',
            conference_views.conference_view,
            OsfWebRenderer('public/pages/meeting_landing.mako'),
        ),

        Rule(
            '/presentations/',
            'get',
            conference_views.redirect_to_meetings,
            json_renderer,
        ),

        Rule('/news/', 'get', {}, OsfWebRenderer('public/pages/news.mako')),

    ])

    # Site-wide API routes

    process_rules(app, [
        Rule(
            '/citations/styles/',
            'get',
            citation_views.list_citation_styles,
            json_renderer,
        ),
    ], prefix='/api/v1')

    process_rules(app, [
        Rule(
            [
                '/project/<pid>/<addon>/settings/disable/',
                '/project/<pid>/node/<nid>/<addon>/settings/disable/',
            ],
            'post',
            addon_views.disable_addon,
            json_renderer,
        ),

        Rule(
            '/profile/<uid>/<addon>/settings/',
            'get',
            addon_views.get_addon_user_config,
            json_renderer,
        ),
    ], prefix='/api/v1')

    # OAuth

    process_rules(app, [
        Rule(
            '/oauth/connect/<service_name>/',
            'get',
            oauth_views.oauth_connect,
            json_renderer,
        ),

        Rule(
            '/oauth/callback/<service_name>/',
            'get',
            oauth_views.oauth_callback,
            OsfWebRenderer('util/oauth_complete.mako'),
        ),
    ])

    process_rules(app, [
        Rule(
            [
                '/oauth/accounts/<external_account_id>/',
            ],
            'delete',
            oauth_views.oauth_disconnect,
            json_renderer,
        )
    ], prefix='/api/v1')

    process_rules(app, [
        Rule('/dashboard/get_nodes/', 'get', website_views.get_dashboard_nodes, json_renderer),
        Rule(
            [
                '/dashboard/<nid>',
                '/dashboard/',
            ],
            'get', website_views.get_dashboard, json_renderer),
    ], prefix='/api/v1')

    ### Meta-data ###

    process_rules(app, [

        Rule(
            [
                '/project/<pid>/comments/',
                '/project/<pid>/node/<nid>/comments/',
            ],
            'get',
            project_views.comment.list_comments,
            json_renderer,
        ),

        Rule(
            [
                '/project/<pid>/comments/discussion/',
                '/project/<pid>/node/<nid>/comments/discussion/',
            ],
            'get',
            project_views.comment.comment_discussion,
            json_renderer,
        ),

        Rule(
            [
                '/project/<pid>/comment/',
                '/project/<pid>/node/<nid>/comment/',
            ],
            'post',
            project_views.comment.add_comment,
            json_renderer,
        ),

        Rule(
            [
                '/project/<pid>/comment/<cid>/',
                '/project/<pid>/node/<nid>/comment/<cid>/',
            ],
            'put',
            project_views.comment.edit_comment,
            json_renderer,
        ),

        Rule(
            [
                '/project/<pid>/comment/<cid>/',
                '/project/<pid>/node/<nid>/comment/<cid>/',
            ],
            'delete',
            project_views.comment.delete_comment,
            json_renderer,
        ),

        Rule(
            [
                '/project/<pid>/comment/<cid>/undelete/',
                '/project/<pid>/node/<nid>/comment/<cid>/undelete/',
            ],
            'put',
            project_views.comment.undelete_comment,
            json_renderer,
        ),

        Rule(
            [
                '/project/<pid>/comments/timestamps/',
                '/project/<pid>/node/<nid>/comments/timestamps/',
            ],
            'put',
            project_views.comment.update_comments_timestamp,
            json_renderer,
        ),

        Rule(
            [
                '/project/<pid>/comment/<cid>/report/',
                '/project/<pid>/node/<nid>/comment/<cid>/report/',
            ],
            'post',
            project_views.comment.report_abuse,
            json_renderer,
        ),

        Rule(
            [
                '/project/<pid>/comment/<cid>/unreport/',
                '/project/<pid>/node/<nid>/comment/<cid>/unreport/',
            ],
            'post',
            project_views.comment.unreport_abuse,
            json_renderer,
        ),

        Rule(
            [
                '/project/<pid>/citation/',
                '/project/<pid>/node/<nid>/citation/',
            ],
            'get',
            citation_views.node_citation,
            json_renderer,
        ),

    ], prefix='/api/v1')

    ### Forms ###

    process_rules(app, [
        Rule('/forms/registration/', 'get', website_views.registration_form, json_renderer),
        Rule('/forms/signin/', 'get', website_views.signin_form, json_renderer),
        Rule('/forms/forgot_password/', 'get', website_views.forgot_password_form, json_renderer),
        Rule('/forms/reset_password/', 'get', website_views.reset_password_form, json_renderer),
    ], prefix='/api/v1')

    ### Discovery ###

    process_rules(app, [

        Rule('/explore/activity/', 'get', discovery_views.activity,
             OsfWebRenderer('public/pages/active_nodes.mako')),

    ])

    ### Auth ###

    # Web

    process_rules(app, [

        Rule(
            '/confirm/<uid>/<token>/',
            'get',
            auth_views.confirm_email_get,
            # View will either redirect or display error message
            OsfWebRenderer('error.mako', render_mako_string)
        ),

        Rule(
            '/resetpassword/<verification_key>/',
            ['get', 'post'],
            auth_views.reset_password,
            OsfWebRenderer('public/resetpassword.mako', render_mako_string)
        ),

        # Resend confirmation URL linked to in CAS login page
        Rule(
            '/resend/',
            ['get', 'post'],
            auth_views.resend_confirmation,
            OsfWebRenderer('resend.mako', render_mako_string)
        ),

        # TODO: Remove `auth_register_post`
        Rule('/register/', 'post', auth_views.auth_register_post,
             OsfWebRenderer('public/login.mako')),
        Rule('/api/v1/register/', 'post', auth_views.register_user, json_renderer),

        Rule(['/login/', '/account/'], 'get',
             auth_views.auth_login, OsfWebRenderer('public/login.mako')),
        Rule('/login/first/', 'get', auth_views.auth_login,
             OsfWebRenderer('public/login.mako'),
             endpoint_suffix='__first', view_kwargs={'first': True}),
        Rule('/logout/', 'get', auth_views.auth_logout, notemplate),
        Rule('/forgotpassword/', 'get', auth_views.forgot_password_get,
             OsfWebRenderer('public/forgot_password.mako')),
        Rule('/forgotpassword/', 'post', auth_views.forgot_password_post,
             OsfWebRenderer('public/login.mako')),

        Rule([
            '/midas/', '/summit/', '/accountbeta/', '/decline/'
        ], 'get', auth_views.auth_registerbeta, OsfWebRenderer('', render_mako_string)),

        Rule('/login/connected_tools/',
             'get',
             landing_page_views.connected_tools,
             OsfWebRenderer('public/login_landing.mako')),

        Rule('/login/enriched_profile/',
             'get',
             landing_page_views.enriched_profile,
             OsfWebRenderer('public/login_landing.mako')),

    ])

    ### Profile ###

    # Web

    process_rules(app, [
        Rule('/profile/', 'get', profile_views.profile_view, OsfWebRenderer('profile.mako')),
        Rule('/profile/<uid>/', 'get', profile_views.profile_view_id,
             OsfWebRenderer('profile.mako')),
        Rule('/settings/key_history/<kid>/', 'get', profile_views.user_key_history,
             OsfWebRenderer('profile/key_history.mako')),
        Rule(["/user/merge/"], 'get', auth_views.merge_user_get,
             OsfWebRenderer("merge_accounts.mako")),
        Rule(["/user/merge/"], 'post', auth_views.merge_user_post,
             OsfWebRenderer("merge_accounts.mako")),
        # Route for claiming and setting email and password.
        # Verification token must be querystring argument
        Rule(['/user/<uid>/<pid>/claim/'], ['get', 'post'],
             project_views.contributor.claim_user_form, OsfWebRenderer('claim_account.mako')),
        Rule(['/user/<uid>/<pid>/claim/verify/<token>/'], ['get', 'post'],
             project_views.contributor.claim_user_registered,
             OsfWebRenderer('claim_account_registered.mako')),


        Rule(
            '/settings/',
            'get',
            profile_views.user_profile,
            OsfWebRenderer('profile/settings.mako'),
        ),

        Rule(
            '/settings/account/',
            'get',
            profile_views.user_account,
            OsfWebRenderer('profile/account.mako'),
        ),

        Rule(
            '/settings/account/password',
            'post',
            profile_views.user_account_password,
            OsfWebRenderer('profile/account.mako'),
        ),

        Rule(
            '/settings/addons/',
            'get',
            profile_views.user_addons,
            OsfWebRenderer('profile/addons.mako'),
        ),

        Rule(
            '/settings/notifications/',
            'get',
            profile_views.user_notifications,
            OsfWebRenderer('profile/notifications.mako'),
        ),

    ])

    # API

    process_rules(app, [

        Rule('/profile/', 'get', profile_views.profile_view, json_renderer),
        Rule('/profile/', 'put', profile_views.update_user, json_renderer),
        Rule('/resend/', 'put', profile_views.resend_confirmation, json_renderer),
        Rule('/profile/<uid>/', 'get', profile_views.profile_view_id, json_renderer),

        # Used by profile.html
        Rule('/profile/<uid>/edit/', 'post', profile_views.edit_profile, json_renderer),
        Rule('/profile/<uid>/public_projects/', 'get',
             profile_views.get_public_projects, json_renderer),
        Rule('/profile/<uid>/public_components/', 'get',
             profile_views.get_public_components, json_renderer),

        Rule('/settings/keys/', 'get', profile_views.get_keys, json_renderer),
        Rule('/settings/create_key/', 'post', profile_views.create_user_key, json_renderer),
        Rule('/settings/revoke_key/', 'post', profile_views.revoke_user_key, json_renderer),
        Rule('/settings/key_history/<kid>/', 'get', profile_views.user_key_history, json_renderer),

        Rule('/profile/<user_id>/summary/', 'get',
             profile_views.get_profile_summary, json_renderer),
        Rule('/user/<uid>/<pid>/claim/email/', 'post',
             project_views.contributor.claim_user_post, json_renderer),

        Rule(
            '/profile/export/',
            'post',
            profile_views.request_export,
            json_renderer,
        ),

        Rule(
            '/profile/deactivate/',
            'post',
            profile_views.request_deactivation,
            json_renderer,
        ),

        Rule(
            [
                '/profile/gravatar/',
                '/users/gravatar/',
                '/profile/gravatar/<size>',
                '/users/gravatar/<size>',
            ],
            'get',
            profile_views.current_user_gravatar,
            json_renderer,
        ),

        Rule(
            [
                '/profile/<uid>/gravatar/',
                '/users/<uid>/gravatar/',
                '/profile/<uid>/gravatar/<size>',
                '/users/<uid>/gravatar/<size>',
            ],
            'get',
            profile_views.get_gravatar,
            json_renderer,
        ),


        # Rules for user profile configuration
        Rule('/settings/names/', 'get', profile_views.serialize_names, json_renderer),
        Rule('/settings/names/', 'put', profile_views.unserialize_names, json_renderer),
        Rule('/settings/names/impute/', 'get', profile_views.impute_names, json_renderer),

        Rule(
            [
                '/settings/social/',
                '/settings/social/<uid>/',
            ],
            'get',
            profile_views.serialize_social,
            json_renderer,
        ),

        Rule(
            [
                '/settings/jobs/',
                '/settings/jobs/<uid>/',
            ],
            'get',
            profile_views.serialize_jobs,
            json_renderer,
        ),

        Rule(
            [
                '/settings/schools/',
                '/settings/schools/<uid>/',
            ],
            'get',
            profile_views.serialize_schools,
            json_renderer,
        ),

        Rule(
            [
                '/settings/social/',
                '/settings/social/<uid>/',
            ],
            'put',
            profile_views.unserialize_social,
            json_renderer
        ),

        Rule(
            [
                '/settings/jobs/',
                '/settings/jobs/<uid>/',
            ],
            'put',
            profile_views.unserialize_jobs,
            json_renderer
        ),

        Rule(
            [
                '/settings/schools/',
                '/settings/schools/<uid>/',
            ],
            'put',
            profile_views.unserialize_schools,
            json_renderer
        ),

    ], prefix='/api/v1',)

    ### Search ###

    # Web

    process_rules(app, [

        Rule('/search/', 'get', {}, OsfWebRenderer('search.mako')),
        Rule('/share/', 'get', {}, OsfWebRenderer('share_search.mako')),
        Rule('/share/registration/', 'get', {'register': settings.SHARE_REGISTRATION_URL}, OsfWebRenderer('share_registration.mako')),
        Rule('/share/help/', 'get', {'help': settings.SHARE_API_DOCS_URL}, OsfWebRenderer('share_api_docs.mako')),
        Rule('/share_dashboard/', 'get', {}, OsfWebRenderer('share_dashboard.mako')),
        Rule('/share/atom/', 'get', search_views.search_share_atom, xml_renderer),
        Rule('/api/v1/user/search/', 'get', search_views.search_contributor, json_renderer),

        Rule(
            '/api/v1/search/node/',
            'post',
            project_views.node.search_node,
            json_renderer,
        ),

    ])

    # API

    process_rules(app, [

        Rule(['/search/', '/search/<type>/'], ['get', 'post'], search_views.search_search, json_renderer),
        Rule('/search/projects/', 'get', search_views.search_projects_by_title, json_renderer),
        Rule('/share/search/', ['get', 'post'], search_views.search_share, json_renderer),
        Rule('/share/stats/', 'get', search_views.search_share_stats, json_renderer),
        Rule('/share/providers/', 'get', search_views.search_share_providers, json_renderer),

    ], prefix='/api/v1')

    # Project

    # Web

    process_rules(app, [

        Rule('/', 'get', website_views.index, OsfWebRenderer('index.mako')),
        Rule('/goodbye/', 'get', goodbye, OsfWebRenderer('index.mako')),

        Rule([
            '/project/<pid>/',
            '/project/<pid>/node/<nid>/',
        ], 'get', project_views.node.view_project, OsfWebRenderer('project/project.mako')),

        # Create a new subproject/component
        Rule('/project/<pid>/newnode/', 'post', project_views.node.project_new_node,
             OsfWebRenderer('', render_mako_string)),

        Rule([
            '/project/<pid>/key_history/<kid>/',
            '/project/<pid>/node/<nid>/key_history/<kid>/',
        ], 'get', project_views.key.node_key_history, OsfWebRenderer('project/key_history.mako')),

        # # TODO: Add API endpoint for tags
        # Rule('/tags/<tag>/', 'get', project_views.tag.project_tag, OsfWebRenderer('tags.mako')),

        Rule('/folder/<nid>', 'get', project_views.node.folder_new,
             OsfWebRenderer('project/new_folder.mako')),
        Rule('/api/v1/folder/<nid>', 'post', project_views.node.folder_new_post, json_renderer),
        Rule('/project/new/<pid>/beforeTemplate/', 'get',
             project_views.node.project_before_template, json_renderer),

        Rule(
            [
                '/project/<pid>/contributors/',
                '/project/<pid>/node/<nid>/contributors/',
            ],
            'get',
            project_views.node.node_contributors,
            OsfWebRenderer('project/contributors.mako'),
        ),

        Rule(
            [
                '/project/<pid>/settings/',
                '/project/<pid>/node/<nid>/settings/',
            ],
            'get',
            project_views.node.node_setting,
            OsfWebRenderer('project/settings.mako')
        ),

        # Permissions
        Rule(
            [
                '/project/<pid>/permissions/<permissions>/',
                '/project/<pid>/node/<nid>/permissions/<permissions>/',
            ],
            'post',
            project_views.node.project_set_privacy,
            OsfWebRenderer('project/project.mako')
        ),

        ### Logs ###

        # View forks
        Rule([
            '/project/<pid>/forks/',
            '/project/<pid>/node/<nid>/forks/',
        ], 'get', project_views.node.node_forks, OsfWebRenderer('project/forks.mako')),

        # Registrations
        Rule([
            '/project/<pid>/register/',
            '/project/<pid>/node/<nid>/register/',
        ], 'get', project_views.register.node_register_page,
            OsfWebRenderer('project/register.mako')),

        Rule([
            '/project/<pid>/register/<template>/',
            '/project/<pid>/node/<nid>/register/<template>/',
        ], 'get', project_views.register.node_register_template_page,
            OsfWebRenderer('project/register.mako')),

        Rule([
            '/project/<pid>/registrations/',
            '/project/<pid>/node/<nid>/registrations/',
        ], 'get', project_views.node.node_registrations,
            OsfWebRenderer('project/registrations.mako')),

        Rule(
            '/ids/<category>/<path:value>/',
            'get',
            project_views.register.get_referent_by_identifier,
            notemplate,
        ),

        # Statistics
        Rule([
            '/project/<pid>/statistics/',
            '/project/<pid>/node/<nid>/statistics/',
        ], 'get', project_views.node.project_statistics,
            OsfWebRenderer('project/statistics.mako')),

        ### Files ###

        # Note: Web endpoint for files view must pass `mode` = `page` to
        # include project view data and JS includes
        Rule(
            [
                '/project/<pid>/files/',
                '/project/<pid>/node/<nid>/files/',
            ],
            'get',
            project_views.file.collect_file_trees,
            OsfWebRenderer('project/files.mako'),
            view_kwargs={'mode': 'page'},
        ),
        Rule(
            [
                '/project/<pid>/files/<provider>/<path:path>/',
                '/project/<pid>/node/<nid>/files/<provider>/<path:path>/',
            ],
            'get',
            addon_views.addon_view_or_download_file,
            OsfWebRenderer('project/view_file.mako')
        ),
        Rule(
            [

                # Legacy Addon view file paths
                '/project/<pid>/<provider>/files/<path:path>/',
                '/project/<pid>/node/<nid>/<provider>/files/<path:path>/',

                '/project/<pid>/<provider>/files/<path:path>/download/',
                '/project/<pid>/node/<nid>/<provider>/files/<path:path>/download/',

                # Legacy routes for `download_file`
                '/project/<pid>/osffiles/<fid>/download/',
                '/project/<pid>/node/<nid>/osffiles/<fid>/download/',

                # Legacy routes for `view_file`
                '/project/<pid>/osffiles/<fid>/',
                '/project/<pid>/node/<nid>/osffiles/<fid>/',

                # Note: Added these old URLs for backwards compatibility with
                # hard-coded links.
                '/project/<pid>/osffiles/download/<fid>/',
                '/project/<pid>/node/<nid>/osffiles/download/<fid>/',
                '/project/<pid>/files/<fid>/',
                '/project/<pid>/node/<nid>/files/<fid>/',
                '/project/<pid>/files/download/<fid>/',
                '/project/<pid>/node/<nid>/files/download/<fid>/',

                # Legacy routes for `download_file_by_version`
                '/project/<pid>/osffiles/<fid>/version/<vid>/download/',
                '/project/<pid>/node/<nid>/osffiles/<fid>/version/<vid>/download/',
                # Note: Added these old URLs for backwards compatibility with
                # hard-coded links.
                '/project/<pid>/osffiles/<fid>/version/<vid>/',
                '/project/<pid>/node/<nid>/osffiles/<fid>/version/<vid>/',
                '/project/<pid>/osffiles/download/<fid>/version/<vid>/',
                '/project/<pid>/node/<nid>/osffiles/download/<fid>/version/<vid>/',
                '/project/<pid>/files/<fid>/version/<vid>/',
                '/project/<pid>/node/<nid>/files/<fid>/version/<vid>/',
                '/project/<pid>/files/download/<fid>/version/<vid>/',
                '/project/<pid>/node/<nid>/files/download/<fid>/version/<vid>/',
            ],
            'get',
            addon_views.addon_view_or_download_file_legacy,
            OsfWebRenderer('project/view_file.mako'),
        ),
        Rule(
            [
                # api/v1 Legacy routes for `download_file`
                '/api/v1/project/<pid>/osffiles/<fid>/',
                '/api/v1/project/<pid>/node/<nid>/osffiles/<fid>/',
                '/api/v1/project/<pid>/files/download/<fid>/',
                '/api/v1/project/<pid>/node/<nid>/files/download/<fid>/',

                #api/v1 Legacy routes for `download_file_by_version`
                '/api/v1/project/<pid>/osffiles/<fid>/version/<vid>/',
                '/api/v1/project/<pid>/node/<nid>/osffiles/<fid>/version/<vid>/',
                '/api/v1/project/<pid>/files/download/<fid>/version/<vid>/',
                '/api/v1/project/<pid>/node/<nid>/files/download/<fid>/version/<vid>/',
            ],
            'get',
            addon_views.addon_view_or_download_file_legacy,
            json_renderer
        ),



    ])

    # API

    process_rules(app, [

        Rule(
            '/email/meeting/',
            'post',
            conference_views.meeting_hook,
            json_renderer,
        ),
        Rule('/mailchimp/hooks/', 'get', profile_views.mailchimp_get_endpoint, json_renderer),

        Rule('/mailchimp/hooks/', 'post', profile_views.sync_data_from_mailchimp, json_renderer),

        # Create project, used by projectCreator.js
        Rule('/project/new/', 'post', project_views.node.project_new_post, json_renderer),

        Rule([
            '/project/<pid>/contributors_abbrev/',
            '/project/<pid>/node/<nid>/contributors_abbrev/',
        ], 'get', project_views.contributor.get_node_contributors_abbrev, json_renderer),

        Rule('/tags/<tag>/', 'get', project_views.tag.project_tag, json_renderer),

        Rule([
            '/project/<pid>/',
            '/project/<pid>/node/<nid>/',
        ], 'get', project_views.node.view_project, json_renderer),
        Rule([
            '/project/<pid>/expand/',
            '/project/<pid>/node/<nid>/expand/',
        ], 'post', project_views.node.expand, json_renderer),
        Rule([
            '/project/<pid>/collapse/',
            '/project/<pid>/node/<nid>/collapse/',
        ], 'post', project_views.node.collapse, json_renderer),

        Rule(
            [
                '/project/<pid>/pointer/',
                '/project/<pid>/node/<nid>/pointer/',
            ],
            'get',
            project_views.node.get_pointed,
            json_renderer,
        ),
        Rule(
            [
                '/project/<pid>/pointer/',
                '/project/<pid>/node/<nid>/pointer/',
            ],
            'post',
            project_views.node.add_pointers,
            json_renderer,
        ),
        Rule(
            [
                '/pointer/',
            ],
            'post',
            project_views.node.add_pointer,
            json_renderer,
        ),
        Rule(
            [
                '/pointers/move/',
            ],
            'post',
            project_views.node.move_pointers,
            json_renderer,
        ),
        Rule(
            [
                '/project/<pid>/pointer/',
                '/project/<pid>/node/<nid>pointer/',
            ],
            'delete',
            project_views.node.remove_pointer,
            json_renderer,
        ),
        Rule(
            [
                '/folder/<pid>/pointer/<pointer_id>',
            ],
            'delete',
            project_views.node.remove_pointer_from_folder,
            json_renderer,
        ),
        Rule(
            [
                '/folder/<pid>/pointers/',
            ],
            'delete',
            project_views.node.remove_pointers_from_folder,
            json_renderer,
        ),
        Rule(
            [
                '/folder/<pid>',
            ],
            'delete',
            project_views.node.delete_folder,
            json_renderer,
        ),
        Rule('/folder/', 'put', project_views.node.add_folder, json_renderer),
        Rule([
            '/project/<pid>/get_summary/',
            '/project/<pid>/node/<nid>/get_summary/',
        ], 'get', project_views.node.get_summary, json_renderer),

        Rule([
            '/project/<pid>/get_children/',
            '/project/<pid>/node/<nid>/get_children/',
        ], 'get', project_views.node.get_children, json_renderer),
        Rule([
            '/project/<pid>/get_folder_pointers/'
        ], 'get', project_views.node.get_folder_pointers, json_renderer),
        Rule([
            '/project/<pid>/get_forks/',
            '/project/<pid>/node/<nid>/get_forks/',
        ], 'get', project_views.node.get_forks, json_renderer),
        Rule([
            '/project/<pid>/get_registrations/',
            '/project/<pid>/node/<nid>/get_registrations/',
        ], 'get', project_views.node.get_registrations, json_renderer),

        Rule('/log/<log_id>/', 'get', project_views.log.get_log, json_renderer),

        Rule([
            '/project/<pid>/log/',
            '/project/<pid>/node/<nid>/log/',
        ], 'get', project_views.log.get_logs, json_renderer),

        Rule([
            '/project/<pid>/get_contributors/',
            '/project/<pid>/node/<nid>/get_contributors/',
        ], 'get', project_views.contributor.get_contributors, json_renderer),

        Rule([
            '/project/<pid>/get_contributors_from_parent/',
            '/project/<pid>/node/<nid>/get_contributors_from_parent/',
        ], 'get', project_views.contributor.get_contributors_from_parent, json_renderer),

        # Reorder contributors
        Rule(
            [
                '/project/<pid>/contributors/manage/',
                '/project/<pid>/node/<nid>/contributors/manage/',
            ],
            'POST',
            project_views.contributor.project_manage_contributors,
            json_renderer,
        ),

        Rule([
            '/project/<pid>/get_most_in_common_contributors/',
            '/project/<pid>/node/<nid>/get_most_in_common_contributors/',
        ], 'get', project_views.contributor.get_most_in_common_contributors, json_renderer),

        Rule([
            '/project/<pid>/get_recently_added_contributors/',
            '/project/<pid>/node/<nid>/get_recently_added_contributors/',
        ], 'get', project_views.contributor.get_recently_added_contributors, json_renderer),

        Rule([
            '/project/<pid>/get_editable_children/',
            '/project/<pid>/node/<nid>/get_editable_children/',
        ], 'get', project_views.node.get_editable_children, json_renderer),


        # Private Link
        Rule([
            '/project/<pid>/private_link/',
            '/project/<pid>/node/<nid>/private_link/',
        ], 'post', project_views.node.project_generate_private_link_post, json_renderer),

        Rule([
            '/project/<pid>/private_link/edit/',
            '/project/<pid>/node/<nid>/private_link/edit/',
        ], 'put', project_views.node.project_private_link_edit, json_renderer),

        Rule([
            '/project/<pid>/private_link/',
            '/project/<pid>/node/<nid>/private_link/',
        ], 'delete', project_views.node.remove_private_link, json_renderer),

        Rule([
            '/project/<pid>/private_link/',
            '/project/<pid>/node/<nid>/private_link/',
        ], 'get', project_views.node.private_link_table, json_renderer),

        # Create, using existing project as a template
        Rule([
            '/project/new/<nid>/',
        ], 'post', project_views.node.project_new_from_template, json_renderer),

        # Update
        Rule(
            [
                '/project/<pid>/',
                '/project/<pid>/node/<nid>/',
            ],
            'put',
            project_views.node.update_node,
            json_renderer,
        ),

        # Remove
        Rule(
            [
                '/project/<pid>/',
                '/project/<pid>/node/<nid>/',
            ],
            'delete',
            project_views.node.component_remove,
            json_renderer,
        ),

        # API keys
        Rule([
            '/project/<pid>/create_key/',
            '/project/<pid>/node/<nid>/create_key/',
        ], 'post', project_views.key.create_node_key, json_renderer),
        Rule([
            '/project/<pid>/revoke_key/',
            '/project/<pid>/node/<nid>/revoke_key/'
        ], 'post', project_views.key.revoke_node_key, json_renderer),
        Rule([
            '/project/<pid>/keys/',
            '/project/<pid>/node/<nid>/keys/',
        ], 'get', project_views.key.get_node_keys, json_renderer),

        # Reorder components
        Rule('/project/<pid>/reorder_components/', 'post',
             project_views.node.project_reorder_components, json_renderer),

        # Edit node
        Rule([
            '/project/<pid>/edit/',
            '/project/<pid>/node/<nid>/edit/',
        ], 'post', project_views.node.edit_node, json_renderer),

        # Tags
        Rule([
            '/project/<pid>/addtag/<tag>/',
            '/project/<pid>/node/<nid>/addtag/<tag>/',
        ], 'post', project_views.tag.project_addtag, json_renderer),
        Rule([
            '/project/<pid>/removetag/<tag>/',
            '/project/<pid>/node/<nid>/removetag/<tag>/',
        ], 'post', project_views.tag.project_removetag, json_renderer),

        # Add / remove contributors
        Rule([
            '/project/<pid>/contributors/',
            '/project/<pid>/node/<nid>/contributors/',
        ], 'post', project_views.contributor.project_contributors_post, json_renderer),
        Rule([
            '/project/<pid>/beforeremovecontributors/',
            '/project/<pid>/node/<nid>/beforeremovecontributors/',
        ], 'post', project_views.contributor.project_before_remove_contributor, json_renderer),
        # TODO(sloria): should be a delete request to /contributors/
        Rule([
            '/project/<pid>/removecontributors/',
            '/project/<pid>/node/<nid>/removecontributors/',
        ], 'post', project_views.contributor.project_removecontributor, json_renderer),

        # Forks
        Rule(
            [
                '/project/<pid>/fork/before/',
                '/project/<pid>/node/<nid>/fork/before/',
            ], 'get', project_views.node.project_before_fork, json_renderer,
        ),
        Rule(
            [
                '/project/<pid>/fork/',
                '/project/<pid>/node/<nid>/fork/',
            ], 'post', project_views.node.node_fork_page, json_renderer,
        ),
        Rule(
            [
                '/project/<pid>/pointer/fork/',
                '/project/<pid>/node/<nid>/pointer/fork/',
            ], 'post', project_views.node.fork_pointer, json_renderer,
        ),

        # View forks
        Rule([
            '/project/<pid>/forks/',
            '/project/<pid>/node/<nid>/forks/',
        ], 'get', project_views.node.node_forks, json_renderer),

        # Registrations
        Rule([
            '/project/<pid>/beforeregister/',
            '/project/<pid>/node/<nid>/beforeregister',
        ], 'get', project_views.register.project_before_register, json_renderer),
        Rule([
            '/project/<pid>/register/<template>/',
            '/project/<pid>/node/<nid>/register/<template>/',
        ], 'get', project_views.register.node_register_template_page, json_renderer),

        Rule([
            '/project/<pid>/register/<template>/',
            '/project/<pid>/node/<nid>/register/<template>/',
        ], 'post', project_views.register.node_register_template_page_post, json_renderer),

        Rule(
            [
                '/project/<pid>/identifiers/',
                '/project/<pid>/node/<nid>/identifiers/',
            ],
            'get',
            project_views.register.node_identifiers_get,
            json_renderer,
        ),

        Rule(
            [
                '/project/<pid>/identifiers/',
                '/project/<pid>/node/<nid>/identifiers/',
            ],
            'post',
            project_views.register.node_identifiers_post,
            json_renderer,
        ),

        # Statistics
        Rule([
            '/project/<pid>/statistics/',
            '/project/<pid>/node/<nid>/statistics/',
        ], 'get', project_views.node.project_statistics, json_renderer),

        # Permissions
        Rule([
            '/project/<pid>/permissions/<permissions>/',
            '/project/<pid>/node/<nid>/permissions/<permissions>/',
        ], 'post', project_views.node.project_set_privacy, json_renderer),

        Rule([
            '/project/<pid>/permissions/beforepublic/',
            '/project/<pid>/node/<nid>/permissions/beforepublic/',
        ], 'get', project_views.node.project_before_set_public, json_renderer),

        ### Wiki ###

        ### Watching ###
        Rule([
            '/project/<pid>/watch/',
            '/project/<pid>/node/<nid>/watch/'
        ], 'post', project_views.node.watch_post, json_renderer),

        Rule([
            '/project/<pid>/unwatch/',
            '/project/<pid>/node/<nid>/unwatch/'
        ], 'post', project_views.node.unwatch_post, json_renderer),

        Rule([
            '/project/<pid>/togglewatch/',
            '/project/<pid>/node/<nid>/togglewatch/'
        ], 'post', project_views.node.togglewatch_post, json_renderer),

        Rule([
            '/watched/logs/'
        ], 'get', website_views.watched_logs_get, json_renderer),
        ### Accounts ###
        Rule([
            '/user/merge/'
        ], 'post', auth_views.merge_user_post, json_renderer),

        # Combined files
        Rule(
            [
                '/project/<pid>/files/',
                '/project/<pid>/node/<nid>/files/'
            ],
            'get',
            project_views.file.collect_file_trees,
            json_renderer,
        ),

        # Endpoint to fetch Rubeus.JS/Hgrid-formatted data
        Rule(
            [
                '/project/<pid>/files/grid/',
                '/project/<pid>/node/<nid>/files/grid/'
            ],
            'get',
            project_views.file.grid_data,
            json_renderer
        ),

        # Settings

        Rule(
            '/files/auth/',
            'get',
            addon_views.get_auth,
            json_renderer,
        ),

        Rule(
            [
                '/project/<pid>/waterbutler/logs/',
                '/project/<pid>/node/<nid>/waterbutler/logs/',
            ],
            'put',
            addon_views.create_waterbutler_log,
            json_renderer,
        ),
        Rule(
            '/settings/addons/',
            'post',
            profile_views.user_choose_addons,
            json_renderer,
        ),

        Rule(
            '/settings/notifications/',
            'get',
            profile_views.user_notifications,
            json_renderer,
        ),

        Rule(
            '/settings/notifications/',
            'post',
            profile_views.user_choose_mailing_lists,
            json_renderer,
        ),

        Rule(
            '/subscriptions/',
            'get',
            notification_views.get_subscriptions,
            json_renderer,
        ),

        Rule(
            [
                '/project/<pid>/subscriptions/',
                '/project/<pid>/node/<nid>/subscriptions/'
            ],
            'get',
            notification_views.get_node_subscriptions,
            json_renderer,
        ),

        Rule(
            '/subscriptions/',
            'post',
            notification_views.configure_subscription,
            json_renderer,
        ),

        Rule(
            [
                '/project/<pid>/settings/addons/',
                '/project/<pid>/node/<nid>/settings/addons/',
            ],
            'post',
            project_views.node.node_choose_addons,
            json_renderer,
        ),

        Rule(
            [
                '/project/<pid>/settings/comments/',
                '/project/<pid>/node/<nid>/settings/comments/',
            ],
            'post',
            project_views.node.configure_comments,
            json_renderer,
        ),

        # Invite Users
        Rule(
            [
                '/project/<pid>/invite_contributor/',
                '/project/<pid>/node/<nid>/invite_contributor/'
            ],
            'post',
            project_views.contributor.invite_contributor_post,
            json_renderer
        ),
    ], prefix='/api/v1')

    # Set up static routing for addons
    # NOTE: We use nginx to serve static addon assets in production
    addon_base_path = os.path.abspath('website/addons')
    if settings.DEV_MODE:
        @app.route('/static/addons/<addon>/<path:filename>')
        def addon_static(addon, filename):
            addon_path = os.path.join(addon_base_path, addon, 'static')
            return send_from_directory(addon_path, filename)
Example #19
0
 def test_url_for_simple(self):
     r = Rule(["/project/"], "get", view_func_or_data=dummy_view, renderer=json_renderer)
     process_rules(self.app, [r])
     with self.app.test_request_context():
         assert_equal(url_for("JSONRenderer__dummy_view"), "/project/")