Changeset - 6104dfd35b16
[Not reviewed]
rhodecode/config/routing.py
Show inline comments
 
"""
 
Routes configuration
 

	
 
The more specific and detailed routes should be defined first so they
 
may take precedent over the more generic routes. For more information
 
refer to the routes manual at http://routes.groovie.org/docs/
 
"""
 
from __future__ import with_statement
 
from routes import Mapper
 

	
 
# prefix for non repository related links needs to be prefixed with `/`
 
ADMIN_PREFIX = '/_admin'
 

	
 

	
 
def make_map(config):
 
    """Create, configure and return the routes Mapper"""
 
    rmap = Mapper(directory=config['pylons.paths']['controllers'],
 
                 always_scan=config['debug'])
 
    rmap.minimization = False
 
    rmap.explicit = False
 

	
 
    from rhodecode.lib.utils import is_valid_repo
 
    from rhodecode.lib.utils import is_valid_repos_group
 

	
 
    def check_repo(environ, match_dict):
 
        """
 
        check for valid repository for proper 404 handling
 

	
 
        :param environ:
 
        :param match_dict:
 
        """
 
        from rhodecode.model.db import Repository
 
        repo_name = match_dict.get('repo_name')
 

	
 
        if match_dict.get('f_path'):
 
            #fix for multiple initial slashes that causes errors
 
            match_dict['f_path'] = match_dict['f_path'].lstrip('/')
 

	
 
        try:
 
            by_id = repo_name.split('_')
 
            if len(by_id) == 2 and by_id[1].isdigit() and by_id[0] == '':
 
                repo_name = Repository.get(by_id[1]).repo_name
 
                match_dict['repo_name'] = repo_name
 
        except:
 
            pass
 

	
 
        return is_valid_repo(repo_name, config['base_path'])
 

	
 
    def check_group(environ, match_dict):
 
        """
 
        check for valid repositories group for proper 404 handling
 

	
 
        :param environ:
 
        :param match_dict:
 
        """
 
        repos_group_name = match_dict.get('group_name')
 

	
 
        return is_valid_repos_group(repos_group_name, config['base_path'])
 

	
 
    def check_int(environ, match_dict):
 
        return match_dict.get('id').isdigit()
 

	
 
    # The ErrorController route (handles 404/500 error pages); it should
 
    # likely stay at the top, ensuring it can always be resolved
 
    rmap.connect('/error/{action}', controller='error')
 
    rmap.connect('/error/{action}/{id}', controller='error')
 

	
 
    #==========================================================================
 
    # CUSTOM ROUTES HERE
 
    #==========================================================================
 

	
 
    #MAIN PAGE
 
    rmap.connect('home', '/', controller='home', action='index')
 
    rmap.connect('repo_switcher', '/repos', controller='home',
 
                 action='repo_switcher')
 
    rmap.connect('branch_tag_switcher', '/branches-tags/{repo_name:.*?}',
 
                 controller='home', action='branch_tag_switcher')
 
    rmap.connect('bugtracker',
 
                 "http://bitbucket.org/marcinkuzminski/rhodecode/issues",
 
                 _static=True)
 
    rmap.connect('rst_help',
 
                 "http://docutils.sourceforge.net/docs/user/rst/quickref.html",
 
                 _static=True)
 
    rmap.connect('rhodecode_official', "http://rhodecode.org", _static=True)
 

	
 
    #ADMIN REPOSITORY REST ROUTES
 
    with rmap.submapper(path_prefix=ADMIN_PREFIX,
 
                        controller='admin/repos') as m:
 
        m.connect("repos", "/repos",
 
             action="create", conditions=dict(method=["POST"]))
 
        m.connect("repos", "/repos",
 
             action="index", conditions=dict(method=["GET"]))
 
        m.connect("formatted_repos", "/repos.{format}",
 
             action="index",
 
            conditions=dict(method=["GET"]))
 
        m.connect("new_repo", "/repos/new",
 
             action="new", conditions=dict(method=["GET"]))
 
        m.connect("formatted_new_repo", "/repos/new.{format}",
 
             action="new", conditions=dict(method=["GET"]))
 
        m.connect("/repos/{repo_name:.*?}",
 
             action="update", conditions=dict(method=["PUT"],
 
                                              function=check_repo))
 
        m.connect("/repos/{repo_name:.*?}",
 
             action="delete", conditions=dict(method=["DELETE"],
 
                                              function=check_repo))
 
        m.connect("edit_repo", "/repos/{repo_name:.*?}/edit",
 
             action="edit", conditions=dict(method=["GET"],
 
                                            function=check_repo))
 
        m.connect("formatted_edit_repo", "/repos/{repo_name:.*?}.{format}/edit",
 
             action="edit", conditions=dict(method=["GET"],
 
                                            function=check_repo))
 
        m.connect("repo", "/repos/{repo_name:.*?}",
 
             action="show", conditions=dict(method=["GET"],
 
                                            function=check_repo))
 
        m.connect("formatted_repo", "/repos/{repo_name:.*?}.{format}",
 
             action="show", conditions=dict(method=["GET"],
 
                                            function=check_repo))
 
        #ajax delete repo perm user
 
        m.connect('delete_repo_user', "/repos_delete_user/{repo_name:.*?}",
 
             action="delete_perm_user",
 
             conditions=dict(method=["DELETE"], function=check_repo))
 

	
 
        #ajax delete repo perm users_group
 
        m.connect('delete_repo_users_group',
 
                  "/repos_delete_users_group/{repo_name:.*?}",
 
                  action="delete_perm_users_group",
 
                  conditions=dict(method=["DELETE"], function=check_repo))
 

	
 
        #settings actions
 
        m.connect('repo_stats', "/repos_stats/{repo_name:.*?}",
 
                  action="repo_stats", conditions=dict(method=["DELETE"],
 
                                                       function=check_repo))
 
        m.connect('repo_cache', "/repos_cache/{repo_name:.*?}",
 
                  action="repo_cache", conditions=dict(method=["DELETE"],
 
                                                       function=check_repo))
 
        m.connect('repo_public_journal', "/repos_public_journal/{repo_name:.*?}",
 
                  action="repo_public_journal", conditions=dict(method=["PUT"],
 
                                                        function=check_repo))
 
        m.connect('repo_pull', "/repo_pull/{repo_name:.*?}",
 
                  action="repo_pull", conditions=dict(method=["PUT"],
 
                                                      function=check_repo))
 
        m.connect('repo_as_fork', "/repo_as_fork/{repo_name:.*?}",
 
                  action="repo_as_fork", conditions=dict(method=["PUT"],
 
                                                      function=check_repo))
 
        m.connect('repo_locking', "/repo_locking/{repo_name:.*?}",
 
                  action="repo_locking", conditions=dict(method=["PUT"],
 
                                                      function=check_repo))
 

	
 
    with rmap.submapper(path_prefix=ADMIN_PREFIX,
 
                        controller='admin/repos_groups') as m:
 
        m.connect("repos_groups", "/repos_groups",
 
                  action="create", conditions=dict(method=["POST"]))
 
        m.connect("repos_groups", "/repos_groups",
 
                  action="index", conditions=dict(method=["GET"]))
 
        m.connect("formatted_repos_groups", "/repos_groups.{format}",
 
                  action="index", conditions=dict(method=["GET"]))
 
        m.connect("new_repos_group", "/repos_groups/new",
 
                  action="new", conditions=dict(method=["GET"]))
 
        m.connect("formatted_new_repos_group", "/repos_groups/new.{format}",
 
                  action="new", conditions=dict(method=["GET"]))
 
        m.connect("update_repos_group", "/repos_groups/{id}",
 
                  action="update", conditions=dict(method=["PUT"],
 
                                                   function=check_int))
 
        m.connect("delete_repos_group", "/repos_groups/{id}",
 
                  action="delete", conditions=dict(method=["DELETE"],
 
                                                   function=check_int))
 
        m.connect("edit_repos_group", "/repos_groups/{id:.*?}/edit",
 
                  action="edit", conditions=dict(method=["GET"],))
 
        m.connect("formatted_edit_repos_group",
 
                  "/repos_groups/{id}.{format}/edit",
 
                  action="edit", conditions=dict(method=["GET"],
 
                                                 function=check_int))
 
        m.connect("repos_group", "/repos_groups/{id}",
 
                  action="show", conditions=dict(method=["GET"],
 
                                                 function=check_int))
 
        m.connect("formatted_repos_group", "/repos_groups/{id}.{format}",
 
                  action="show", conditions=dict(method=["GET"],
 
                                                 function=check_int))
 
        # ajax delete repos group perm user
 
        m.connect('delete_repos_group_user_perm',
 
                  "/delete_repos_group_user_perm/{group_name:.*}",
 
             action="delete_repos_group_user_perm",
 
             conditions=dict(method=["DELETE"], function=check_group))
 

	
 
        # ajax delete repos group perm users_group
 
        m.connect('delete_repos_group_users_group_perm',
 
                  "/delete_repos_group_users_group_perm/{group_name:.*}",
 
                  action="delete_repos_group_users_group_perm",
 
                  conditions=dict(method=["DELETE"], function=check_group))
 

	
 
    #ADMIN USER REST ROUTES
 
    with rmap.submapper(path_prefix=ADMIN_PREFIX,
 
                        controller='admin/users') as m:
 
        m.connect("users", "/users",
 
                  action="create", conditions=dict(method=["POST"]))
 
        m.connect("users", "/users",
 
                  action="index", conditions=dict(method=["GET"]))
 
        m.connect("formatted_users", "/users.{format}",
 
                  action="index", conditions=dict(method=["GET"]))
 
        m.connect("new_user", "/users/new",
 
                  action="new", conditions=dict(method=["GET"]))
 
        m.connect("formatted_new_user", "/users/new.{format}",
 
                  action="new", conditions=dict(method=["GET"]))
 
        m.connect("update_user", "/users/{id}",
 
                  action="update", conditions=dict(method=["PUT"]))
 
        m.connect("delete_user", "/users/{id}",
 
                  action="delete", conditions=dict(method=["DELETE"]))
 
        m.connect("edit_user", "/users/{id}/edit",
 
                  action="edit", conditions=dict(method=["GET"]))
 
        m.connect("formatted_edit_user",
 
                  "/users/{id}.{format}/edit",
 
                  action="edit", conditions=dict(method=["GET"]))
 
        m.connect("user", "/users/{id}",
 
                  action="show", conditions=dict(method=["GET"]))
 
        m.connect("formatted_user", "/users/{id}.{format}",
 
                  action="show", conditions=dict(method=["GET"]))
 

	
 
        #EXTRAS USER ROUTES
 
        m.connect("user_perm", "/users_perm/{id}",
 
                  action="update_perm", conditions=dict(method=["PUT"]))
 
        m.connect("user_emails", "/users_emails/{id}",
 
                  action="add_email", conditions=dict(method=["PUT"]))
 
        m.connect("user_emails_delete", "/users_emails/{id}",
 
                  action="delete_email", conditions=dict(method=["DELETE"]))
 

	
 
    #ADMIN USERS GROUPS REST ROUTES
 
    with rmap.submapper(path_prefix=ADMIN_PREFIX,
 
                        controller='admin/users_groups') as m:
 
        m.connect("users_groups", "/users_groups",
 
                  action="create", conditions=dict(method=["POST"]))
 
        m.connect("users_groups", "/users_groups",
 
                  action="index", conditions=dict(method=["GET"]))
 
        m.connect("formatted_users_groups", "/users_groups.{format}",
 
                  action="index", conditions=dict(method=["GET"]))
 
        m.connect("new_users_group", "/users_groups/new",
 
                  action="new", conditions=dict(method=["GET"]))
 
        m.connect("formatted_new_users_group", "/users_groups/new.{format}",
 
                  action="new", conditions=dict(method=["GET"]))
 
        m.connect("update_users_group", "/users_groups/{id}",
 
                  action="update", conditions=dict(method=["PUT"]))
 
        m.connect("delete_users_group", "/users_groups/{id}",
 
                  action="delete", conditions=dict(method=["DELETE"]))
 
        m.connect("edit_users_group", "/users_groups/{id}/edit",
 
                  action="edit", conditions=dict(method=["GET"]))
 
        m.connect("formatted_edit_users_group",
 
                  "/users_groups/{id}.{format}/edit",
 
                  action="edit", conditions=dict(method=["GET"]))
 
        m.connect("users_group", "/users_groups/{id}",
 
                  action="show", conditions=dict(method=["GET"]))
 
        m.connect("formatted_users_group", "/users_groups/{id}.{format}",
 
                  action="show", conditions=dict(method=["GET"]))
 

	
 
        #EXTRAS USER ROUTES
 
        m.connect("users_group_perm", "/users_groups_perm/{id}",
 
                  action="update_perm", conditions=dict(method=["PUT"]))
 

	
 
    #ADMIN GROUP REST ROUTES
 
    rmap.resource('group', 'groups',
 
                  controller='admin/groups', path_prefix=ADMIN_PREFIX)
 

	
 
    #ADMIN PERMISSIONS REST ROUTES
 
    rmap.resource('permission', 'permissions',
 
                  controller='admin/permissions', path_prefix=ADMIN_PREFIX)
 

	
 
    #ADMIN DEFAULTS REST ROUTES
 
    rmap.resource('default', 'defaults',
 
                  controller='admin/defaults', path_prefix=ADMIN_PREFIX)
 

	
 
    ##ADMIN LDAP SETTINGS
 
    rmap.connect('ldap_settings', '%s/ldap' % ADMIN_PREFIX,
 
                 controller='admin/ldap_settings', action='ldap_settings',
 
                 conditions=dict(method=["POST"]))
 

	
 
    rmap.connect('ldap_home', '%s/ldap' % ADMIN_PREFIX,
 
                 controller='admin/ldap_settings')
 

	
 
    #ADMIN SETTINGS REST ROUTES
 
    with rmap.submapper(path_prefix=ADMIN_PREFIX,
 
                        controller='admin/settings') as m:
 
        m.connect("admin_settings", "/settings",
 
                  action="create", conditions=dict(method=["POST"]))
 
        m.connect("admin_settings", "/settings",
 
                  action="index", conditions=dict(method=["GET"]))
 
        m.connect("formatted_admin_settings", "/settings.{format}",
 
                  action="index", conditions=dict(method=["GET"]))
 
        m.connect("admin_new_setting", "/settings/new",
 
                  action="new", conditions=dict(method=["GET"]))
 
        m.connect("formatted_admin_new_setting", "/settings/new.{format}",
 
                  action="new", conditions=dict(method=["GET"]))
 
        m.connect("/settings/{setting_id}",
 
                  action="update", conditions=dict(method=["PUT"]))
 
        m.connect("/settings/{setting_id}",
 
                  action="delete", conditions=dict(method=["DELETE"]))
 
        m.connect("admin_edit_setting", "/settings/{setting_id}/edit",
 
                  action="edit", conditions=dict(method=["GET"]))
 
        m.connect("formatted_admin_edit_setting",
 
                  "/settings/{setting_id}.{format}/edit",
 
                  action="edit", conditions=dict(method=["GET"]))
 
        m.connect("admin_setting", "/settings/{setting_id}",
 
                  action="show", conditions=dict(method=["GET"]))
 
        m.connect("formatted_admin_setting", "/settings/{setting_id}.{format}",
 
                  action="show", conditions=dict(method=["GET"]))
 
        m.connect("admin_settings_my_account", "/my_account",
 
                  action="my_account", conditions=dict(method=["GET"]))
 
        m.connect("admin_settings_my_account_update", "/my_account_update",
 
                  action="my_account_update", conditions=dict(method=["PUT"]))
 
        m.connect("admin_settings_create_repository", "/create_repository",
 
                  action="create_repository", conditions=dict(method=["GET"]))
 
        m.connect("admin_settings_my_repos", "/my_account/repos",
 
                  action="my_account_my_repos", conditions=dict(method=["GET"]))
 
        m.connect("admin_settings_my_pullrequests", "/my_account/pull_requests",
 
                  action="my_account_my_pullrequests", conditions=dict(method=["GET"]))
 

	
 
    #NOTIFICATION REST ROUTES
 
    with rmap.submapper(path_prefix=ADMIN_PREFIX,
 
                        controller='admin/notifications') as m:
 
        m.connect("notifications", "/notifications",
 
                  action="create", conditions=dict(method=["POST"]))
 
        m.connect("notifications", "/notifications",
 
                  action="index", conditions=dict(method=["GET"]))
 
        m.connect("notifications_mark_all_read", "/notifications/mark_all_read",
 
                  action="mark_all_read", conditions=dict(method=["GET"]))
 
        m.connect("formatted_notifications", "/notifications.{format}",
 
                  action="index", conditions=dict(method=["GET"]))
 
        m.connect("new_notification", "/notifications/new",
 
                  action="new", conditions=dict(method=["GET"]))
 
        m.connect("formatted_new_notification", "/notifications/new.{format}",
 
                  action="new", conditions=dict(method=["GET"]))
 
        m.connect("/notification/{notification_id}",
 
                  action="update", conditions=dict(method=["PUT"]))
 
        m.connect("/notification/{notification_id}",
 
                  action="delete", conditions=dict(method=["DELETE"]))
 
        m.connect("edit_notification", "/notification/{notification_id}/edit",
 
                  action="edit", conditions=dict(method=["GET"]))
 
        m.connect("formatted_edit_notification",
 
                  "/notification/{notification_id}.{format}/edit",
 
                  action="edit", conditions=dict(method=["GET"]))
 
        m.connect("notification", "/notification/{notification_id}",
 
                  action="show", conditions=dict(method=["GET"]))
 
        m.connect("formatted_notification", "/notifications/{notification_id}.{format}",
 
                  action="show", conditions=dict(method=["GET"]))
 

	
 
    #ADMIN MAIN PAGES
 
    with rmap.submapper(path_prefix=ADMIN_PREFIX,
 
                        controller='admin/admin') as m:
 
        m.connect('admin_home', '', action='index')
 
        m.connect('admin_add_repo', '/add_repo/{new_repo:[a-z0-9\. _-]*}',
 
                  action='add_repo')
 

	
 
    #==========================================================================
 
    # API V2
 
    #==========================================================================
 
    with rmap.submapper(path_prefix=ADMIN_PREFIX,
 
                        controller='api/api') as m:
 
        m.connect('api', '/api')
 

	
 
    #USER JOURNAL
 
    rmap.connect('journal_my_repos', '%s/journal_my_repos' % ADMIN_PREFIX,
 
                 controller='journal', action='index_my_repos')
 
    rmap.connect('journal', '%s/journal' % ADMIN_PREFIX,
 
                 controller='journal', action='index')
 
    rmap.connect('journal_rss', '%s/journal/rss' % ADMIN_PREFIX,
 
                 controller='journal', action='journal_rss')
 
    rmap.connect('journal_atom', '%s/journal/atom' % ADMIN_PREFIX,
 
                 controller='journal', action='journal_atom')
 

	
 
    rmap.connect('public_journal', '%s/public_journal' % ADMIN_PREFIX,
 
                 controller='journal', action="public_journal")
 

	
 
    rmap.connect('public_journal_rss', '%s/public_journal/rss' % ADMIN_PREFIX,
 
                 controller='journal', action="public_journal_rss")
 

	
 
    rmap.connect('public_journal_rss_old', '%s/public_journal_rss' % ADMIN_PREFIX,
 
                 controller='journal', action="public_journal_rss")
 

	
 
    rmap.connect('public_journal_atom',
 
                 '%s/public_journal/atom' % ADMIN_PREFIX, controller='journal',
 
                 action="public_journal_atom")
 

	
 
    rmap.connect('public_journal_atom_old',
 
                 '%s/public_journal_atom' % ADMIN_PREFIX, controller='journal',
 
                 action="public_journal_atom")
 

	
 
    rmap.connect('toggle_following', '%s/toggle_following' % ADMIN_PREFIX,
 
                 controller='journal', action='toggle_following',
 
                 conditions=dict(method=["POST"]))
 

	
 
    #SEARCH
 
    rmap.connect('search', '%s/search' % ADMIN_PREFIX, controller='search',)
 
    rmap.connect('search_repo', '%s/search/{search_repo:.*}' % ADMIN_PREFIX,
 
                  controller='search')
 

	
 
    #LOGIN/LOGOUT/REGISTER/SIGN IN
 
    rmap.connect('login_home', '%s/login' % ADMIN_PREFIX, controller='login')
 
    rmap.connect('logout_home', '%s/logout' % ADMIN_PREFIX, controller='login',
 
                 action='logout')
 

	
 
    rmap.connect('register', '%s/register' % ADMIN_PREFIX, controller='login',
 
                 action='register')
 

	
 
    rmap.connect('reset_password', '%s/password_reset' % ADMIN_PREFIX,
 
                 controller='login', action='password_reset')
 

	
 
    rmap.connect('reset_password_confirmation',
 
                 '%s/password_reset_confirmation' % ADMIN_PREFIX,
 
                 controller='login', action='password_reset_confirmation')
 

	
 
    #FEEDS
 
    rmap.connect('rss_feed_home', '/{repo_name:.*?}/feed/rss',
 
                controller='feed', action='rss',
 
                conditions=dict(function=check_repo))
 

	
 
    rmap.connect('atom_feed_home', '/{repo_name:.*?}/feed/atom',
 
                controller='feed', action='atom',
 
                conditions=dict(function=check_repo))
 

	
 
    #==========================================================================
 
    # REPOSITORY ROUTES
 
    #==========================================================================
 
    rmap.connect('summary_home', '/{repo_name:.*?}',
 
                controller='summary',
 
                conditions=dict(function=check_repo))
 

	
 
    rmap.connect('repos_group_home', '/{group_name:.*}',
 
                controller='admin/repos_groups', action="show_by_name",
 
                conditions=dict(function=check_group))
 

	
 
    rmap.connect('changeset_home', '/{repo_name:.*?}/changeset/{revision}',
 
                controller='changeset', revision='tip',
 
                conditions=dict(function=check_repo))
 

	
 
    #still working url for backward compat.
 
    rmap.connect('raw_changeset_home_depraced',
 
                 '/{repo_name:.*?}/raw-changeset/{revision}',
 
                 controller='changeset', action='changeset_raw',
 
                 revision='tip', conditions=dict(function=check_repo))
 

	
 
    ## new URLs
 
    rmap.connect('changeset_raw_home',
 
                 '/{repo_name:.*?}/changeset-diff/{revision}',
 
                 controller='changeset', action='changeset_raw',
 
                 revision='tip', conditions=dict(function=check_repo))
 

	
 
    rmap.connect('changeset_patch_home',
 
                 '/{repo_name:.*?}/changeset-patch/{revision}',
 
                 controller='changeset', action='changeset_patch',
 
                 revision='tip', conditions=dict(function=check_repo))
 

	
 
    rmap.connect('changeset_download_home',
 
                 '/{repo_name:.*?}/changeset-download/{revision}',
 
                 controller='changeset', action='changeset_download',
 
                 revision='tip', conditions=dict(function=check_repo))
 

	
 
    rmap.connect('changeset_comment',
 
                 '/{repo_name:.*?}/changeset/{revision}/comment',
 
                controller='changeset', revision='tip', action='comment',
 
                conditions=dict(function=check_repo))
 

	
 
    rmap.connect('changeset_comment_delete',
 
                 '/{repo_name:.*?}/changeset/comment/{comment_id}/delete',
 
                controller='changeset', action='delete_comment',
 
                conditions=dict(function=check_repo, method=["DELETE"]))
 

	
 
    rmap.connect('changeset_info', '/changeset_info/{repo_name:.*?}/{revision}',
 
                 controller='changeset', action='changeset_info')
 

	
 
    rmap.connect('compare_url',
 
                 '/{repo_name:.*?}/compare/{org_ref_type}@{org_ref:.*?}...{other_ref_type}@{other_ref:.*?}',
 
                 controller='compare', action='index',
 
                 conditions=dict(function=check_repo),
 
                 requirements=dict(
 
                            org_ref_type='(branch|book|tag|rev|org_ref_type)',
 
                            other_ref_type='(branch|book|tag|rev|other_ref_type)')
 
                 )
 

	
 
    rmap.connect('pullrequest_home',
 
                 '/{repo_name:.*?}/pull-request/new', controller='pullrequests',
 
                 action='index', conditions=dict(function=check_repo,
 
                                                 method=["GET"]))
 

	
 
    rmap.connect('pullrequest',
 
                 '/{repo_name:.*?}/pull-request/new', controller='pullrequests',
 
                 action='create', conditions=dict(function=check_repo,
 
                                                  method=["POST"]))
 

	
 
    rmap.connect('pullrequest_show',
 
                 '/{repo_name:.*?}/pull-request/{pull_request_id}',
 
                 controller='pullrequests',
 
                 action='show', conditions=dict(function=check_repo,
 
                                                method=["GET"]))
 
    rmap.connect('pullrequest_update',
 
                 '/{repo_name:.*?}/pull-request/{pull_request_id}',
 
                 controller='pullrequests',
 
                 action='update', conditions=dict(function=check_repo,
 
                                                method=["PUT"]))
 
    rmap.connect('pullrequest_delete',
 
                 '/{repo_name:.*?}/pull-request/{pull_request_id}',
 
                 controller='pullrequests',
 
                 action='delete', conditions=dict(function=check_repo,
 
                                                method=["DELETE"]))
 

	
 
    rmap.connect('pullrequest_show_all',
 
                 '/{repo_name:.*?}/pull-request',
 
                 controller='pullrequests',
 
                 action='show_all', conditions=dict(function=check_repo,
 
                                                method=["GET"]))
 

	
 
    rmap.connect('pullrequest_comment',
 
                 '/{repo_name:.*?}/pull-request-comment/{pull_request_id}',
 
                 controller='pullrequests',
 
                 action='comment', conditions=dict(function=check_repo,
 
                                                method=["POST"]))
 

	
 
    rmap.connect('pullrequest_comment_delete',
 
                 '/{repo_name:.*?}/pull-request-comment/{comment_id}/delete',
 
                controller='pullrequests', action='delete_comment',
 
                conditions=dict(function=check_repo, method=["DELETE"]))
 

	
 
    rmap.connect('summary_home', '/{repo_name:.*?}/summary',
 
                controller='summary', conditions=dict(function=check_repo))
 

	
 
    rmap.connect('shortlog_home', '/{repo_name:.*?}/shortlog',
 
                controller='shortlog', conditions=dict(function=check_repo))
 

	
 
    rmap.connect('shortlog_file_home', '/{repo_name:.*?}/shortlog/{revision}/{f_path:.*}',
 
                controller='shortlog', f_path=None,
 
                conditions=dict(function=check_repo))
 

	
 
    rmap.connect('branches_home', '/{repo_name:.*?}/branches',
 
                controller='branches', conditions=dict(function=check_repo))
 

	
 
    rmap.connect('tags_home', '/{repo_name:.*?}/tags',
 
                controller='tags', conditions=dict(function=check_repo))
 

	
 
    rmap.connect('bookmarks_home', '/{repo_name:.*?}/bookmarks',
 
                controller='bookmarks', conditions=dict(function=check_repo))
 

	
 
    rmap.connect('changelog_home', '/{repo_name:.*?}/changelog',
 
                controller='changelog', conditions=dict(function=check_repo))
 

	
 
    rmap.connect('changelog_details', '/{repo_name:.*?}/changelog_details/{cs}',
 
                controller='changelog', action='changelog_details',
 
                conditions=dict(function=check_repo))
 

	
 
    rmap.connect('files_home', '/{repo_name:.*?}/files/{revision}/{f_path:.*}',
 
                controller='files', revision='tip', f_path='',
 
                conditions=dict(function=check_repo))
 

	
 
    rmap.connect('files_history_home',
 
                 '/{repo_name:.*?}/history/{revision}/{f_path:.*}',
 
                 controller='files', action='history', revision='tip', f_path='',
 
                 conditions=dict(function=check_repo))
 

	
 
    rmap.connect('files_diff_home', '/{repo_name:.*?}/diff/{f_path:.*}',
 
                controller='files', action='diff', revision='tip', f_path='',
 
                conditions=dict(function=check_repo))
 

	
 
    rmap.connect('files_rawfile_home',
 
                 '/{repo_name:.*?}/rawfile/{revision}/{f_path:.*}',
 
                 controller='files', action='rawfile', revision='tip',
 
                 f_path='', conditions=dict(function=check_repo))
 

	
 
    rmap.connect('files_raw_home',
 
                 '/{repo_name:.*?}/raw/{revision}/{f_path:.*}',
 
                 controller='files', action='raw', revision='tip', f_path='',
 
                 conditions=dict(function=check_repo))
 

	
 
    rmap.connect('files_annotate_home',
 
                 '/{repo_name:.*?}/annotate/{revision}/{f_path:.*}',
 
                 controller='files', action='index', revision='tip',
 
                 f_path='', annotate=True, conditions=dict(function=check_repo))
 

	
 
    rmap.connect('files_edit_home',
 
                 '/{repo_name:.*?}/edit/{revision}/{f_path:.*}',
 
                 controller='files', action='edit', revision='tip',
 
                 f_path='', conditions=dict(function=check_repo))
 

	
 
    rmap.connect('files_add_home',
 
                 '/{repo_name:.*?}/add/{revision}/{f_path:.*}',
 
                 controller='files', action='add', revision='tip',
 
                 f_path='', conditions=dict(function=check_repo))
 

	
 
    rmap.connect('files_archive_home', '/{repo_name:.*?}/archive/{fname}',
 
                controller='files', action='archivefile',
 
                conditions=dict(function=check_repo))
 

	
 
    rmap.connect('files_nodelist_home',
 
                 '/{repo_name:.*?}/nodelist/{revision}/{f_path:.*}',
 
                controller='files', action='nodelist',
 
                conditions=dict(function=check_repo))
 

	
 
    rmap.connect('repo_settings_delete', '/{repo_name:.*?}/settings',
 
                controller='settings', action="delete",
 
                conditions=dict(method=["DELETE"], function=check_repo))
 

	
 
    rmap.connect('repo_settings_update', '/{repo_name:.*?}/settings',
 
                controller='settings', action="update",
 
                conditions=dict(method=["PUT"], function=check_repo))
 

	
 
    rmap.connect('repo_settings_home', '/{repo_name:.*?}/settings',
 
                controller='settings', action='index',
 
                conditions=dict(function=check_repo))
 

	
 
    rmap.connect('toggle_locking', "/{repo_name:.*?}/locking_toggle",
 
                 controller='settings', action="toggle_locking",
 
                 conditions=dict(method=["GET"], function=check_repo))
 

	
 
    rmap.connect('repo_fork_create_home', '/{repo_name:.*?}/fork',
 
                controller='forks', action='fork_create',
 
                conditions=dict(function=check_repo, method=["POST"]))
 

	
 
    rmap.connect('repo_fork_home', '/{repo_name:.*?}/fork',
 
                controller='forks', action='fork',
 
                conditions=dict(function=check_repo))
 

	
 
    rmap.connect('repo_forks_home', '/{repo_name:.*?}/forks',
 
                 controller='forks', action='forks',
 
                 conditions=dict(function=check_repo))
 

	
 
    rmap.connect('repo_followers_home', '/{repo_name:.*?}/followers',
 
                 controller='followers', action='followers',
 
                 conditions=dict(function=check_repo))
 

	
 
    return rmap
rhodecode/controllers/admin/defaults.py
Show inline comments
 
new file 100644
 
# -*- coding: utf-8 -*-
 
"""
 
    rhodecode.controllers.admin.defaults
 
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 

	
 
    default settings controller for Rhodecode
 

	
 
    :created_on: Apr 27, 2010
 
    :author: marcink
 
    :copyright: (C) 2010-2012 Marcin Kuzminski <marcin@python-works.com>
 
    :license: GPLv3, see COPYING for more details.
 
"""
 
# This program is free software: you can redistribute it and/or modify
 
# it under the terms of the GNU General Public License as published by
 
# the Free Software Foundation, either version 3 of the License, or
 
# (at your option) any later version.
 
#
 
# This program is distributed in the hope that it will be useful,
 
# but WITHOUT ANY WARRANTY; without even the implied warranty of
 
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
# GNU General Public License for more details.
 
#
 
# You should have received a copy of the GNU General Public License
 
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
 

	
 
import logging
 
import traceback
 
import formencode
 
from formencode import htmlfill
 

	
 
from pylons import request, session, tmpl_context as c, url
 
from pylons.controllers.util import abort, redirect
 
from pylons.i18n.translation import _
 

	
 
from rhodecode.lib import helpers as h
 
from rhodecode.lib.auth import LoginRequired, HasPermissionAllDecorator
 
from rhodecode.lib.base import BaseController, render
 
from rhodecode.model.forms import DefaultsForm
 
from rhodecode.model.meta import Session
 
from rhodecode import BACKENDS
 
from rhodecode.model.db import RhodeCodeSetting
 

	
 
log = logging.getLogger(__name__)
 

	
 

	
 
class DefaultsController(BaseController):
 
    """REST Controller styled on the Atom Publishing Protocol"""
 
    # To properly map this controller, ensure your config/routing.py
 
    # file has a resource setup:
 
    #     map.resource('default', 'defaults')
 

	
 
    @LoginRequired()
 
    @HasPermissionAllDecorator('hg.admin')
 
    def __before__(self):
 
        super(DefaultsController, self).__before__()
 

	
 
    def index(self, format='html'):
 
        """GET /defaults: All items in the collection"""
 
        # url('defaults')
 
        c.backends = BACKENDS.keys()
 
        defaults = RhodeCodeSetting.get_default_repo_settings()
 

	
 
        return htmlfill.render(
 
            render('admin/defaults/defaults.html'),
 
            defaults=defaults,
 
            encoding="UTF-8",
 
            force_defaults=False
 
        )
 

	
 
    def create(self):
 
        """POST /defaults: Create a new item"""
 
        # url('defaults')
 

	
 
    def new(self, format='html'):
 
        """GET /defaults/new: Form to create a new item"""
 
        # url('new_default')
 

	
 
    def update(self, id):
 
        """PUT /defaults/id: Update an existing item"""
 
        # Forms posted to this method should contain a hidden field:
 
        #    <input type="hidden" name="_method" value="PUT" />
 
        # Or using helpers:
 
        #    h.form(url('default', id=ID),
 
        #           method='put')
 
        # url('default', id=ID)
 

	
 
        _form = DefaultsForm()()
 

	
 
        try:
 
            form_result = _form.to_python(dict(request.POST))
 
            for k, v in form_result.iteritems():
 
                setting = RhodeCodeSetting.get_by_name_or_create(k)
 
                setting.app_settings_value = v
 
                Session().add(setting)
 
            Session().commit()
 
            h.flash(_('Default settings updated successfully'),
 
                    category='success')
 

	
 
        except formencode.Invalid, errors:
 
            defaults = errors.value
 

	
 
            return htmlfill.render(
 
                render('admin/defaults/defaults.html'),
 
                defaults=defaults,
 
                errors=errors.error_dict or {},
 
                prefix_error=False,
 
                encoding="UTF-8")
 
        except Exception:
 
            log.error(traceback.format_exc())
 
            h.flash(_('error occurred during update of defaults'),
 
                    category='error')
 

	
 
        return redirect(url('defaults'))
 

	
 
    def delete(self, id):
 
        """DELETE /defaults/id: Delete an existing item"""
 
        # Forms posted to this method should contain a hidden field:
 
        #    <input type="hidden" name="_method" value="DELETE" />
 
        # Or using helpers:
 
        #    h.form(url('default', id=ID),
 
        #           method='delete')
 
        # url('default', id=ID)
 

	
 
    def show(self, id, format='html'):
 
        """GET /defaults/id: Show a specific item"""
 
        # url('default', id=ID)
 

	
 
    def edit(self, id, format='html'):
 
        """GET /defaults/id/edit: Form to edit an existing item"""
 
        # url('edit_default', id=ID)
rhodecode/controllers/admin/repos.py
Show inline comments
 
# -*- coding: utf-8 -*-
 
"""
 
    rhodecode.controllers.admin.repos
 
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 

	
 
    Repositories controller for RhodeCode
 

	
 
    :created_on: Apr 7, 2010
 
    :author: marcink
 
    :copyright: (C) 2010-2012 Marcin Kuzminski <marcin@python-works.com>
 
    :license: GPLv3, see COPYING for more details.
 
"""
 
# This program is free software: you can redistribute it and/or modify
 
# it under the terms of the GNU General Public License as published by
 
# the Free Software Foundation, either version 3 of the License, or
 
# (at your option) any later version.
 
#
 
# This program is distributed in the hope that it will be useful,
 
# but WITHOUT ANY WARRANTY; without even the implied warranty of
 
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
# GNU General Public License for more details.
 
#
 
# You should have received a copy of the GNU General Public License
 
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
 

	
 
import logging
 
import traceback
 
import formencode
 
from formencode import htmlfill
 

	
 
from webob.exc import HTTPInternalServerError
 
from pylons import request, session, tmpl_context as c, url
 
from pylons.controllers.util import redirect
 
from pylons.i18n.translation import _
 
from sqlalchemy.exc import IntegrityError
 

	
 
import rhodecode
 
from rhodecode.lib import helpers as h
 
from rhodecode.lib.auth import LoginRequired, HasPermissionAllDecorator, \
 
    HasPermissionAnyDecorator, HasRepoPermissionAllDecorator
 
from rhodecode.lib.base import BaseController, render
 
from rhodecode.lib.utils import invalidate_cache, action_logger, repo_name_slug
 
from rhodecode.lib.helpers import get_token
 
from rhodecode.model.meta import Session
 
from rhodecode.model.db import User, Repository, UserFollowing, RepoGroup
 
from rhodecode.model.db import User, Repository, UserFollowing, RepoGroup,\
 
    RhodeCodeSetting
 
from rhodecode.model.forms import RepoForm
 
from rhodecode.model.scm import ScmModel
 
from rhodecode.model.repo import RepoModel
 
from rhodecode.lib.compat import json
 
from sqlalchemy.sql.expression import func
 

	
 
log = logging.getLogger(__name__)
 

	
 

	
 
class ReposController(BaseController):
 
    """
 
    REST Controller styled on the Atom Publishing Protocol"""
 
    # To properly map this controller, ensure your config/routing.py
 
    # file has a resource setup:
 
    #     map.resource('repo', 'repos')
 

	
 
    @LoginRequired()
 
    @HasPermissionAnyDecorator('hg.admin', 'hg.create.repository')
 
    def __before__(self):
 
        c.admin_user = session.get('admin_user')
 
        c.admin_username = session.get('admin_username')
 
        super(ReposController, self).__before__()
 

	
 
    def __load_defaults(self):
 
        c.repo_groups = RepoGroup.groups_choices(check_perms=True)
 
        c.repo_groups_choices = map(lambda k: unicode(k[0]), c.repo_groups)
 

	
 
        repo_model = RepoModel()
 
        c.users_array = repo_model.get_users_js()
 
        c.users_groups_array = repo_model.get_users_groups_js()
 
        choices, c.landing_revs = ScmModel().get_repo_landing_revs()
 
        c.landing_revs_choices = choices
 

	
 
    def __load_data(self, repo_name=None):
 
        """
 
        Load defaults settings for edit, and update
 

	
 
        :param repo_name:
 
        """
 
        self.__load_defaults()
 

	
 
        c.repo_info = db_repo = Repository.get_by_repo_name(repo_name)
 
        repo = db_repo.scm_instance
 

	
 
        if c.repo_info is None:
 
            h.flash(_('%s repository is not mapped to db perhaps'
 
                      ' it was created or renamed from the filesystem'
 
                      ' please run the application again'
 
                      ' in order to rescan repositories') % repo_name,
 
                      category='error')
 

	
 
            return redirect(url('repos'))
 

	
 
        choices, c.landing_revs = ScmModel().get_repo_landing_revs(c.repo_info)
 
        c.landing_revs_choices = choices
 

	
 
        c.default_user_id = User.get_by_username('default').user_id
 
        c.in_public_journal = UserFollowing.query()\
 
            .filter(UserFollowing.user_id == c.default_user_id)\
 
            .filter(UserFollowing.follows_repository == c.repo_info).scalar()
 

	
 
        if c.repo_info.stats:
 
            # this is on what revision we ended up so we add +1 for count
 
            last_rev = c.repo_info.stats.stat_on_revision + 1
 
        else:
 
            last_rev = 0
 
        c.stats_revision = last_rev
 

	
 
        c.repo_last_rev = repo.count() if repo.revisions else 0
 

	
 
        if last_rev == 0 or c.repo_last_rev == 0:
 
            c.stats_percentage = 0
 
        else:
 
            c.stats_percentage = '%.2f' % ((float((last_rev)) /
 
                                            c.repo_last_rev) * 100)
 

	
 
        defaults = RepoModel()._get_defaults(repo_name)
 

	
 
        c.repos_list = [('', _('--REMOVE FORK--'))]
 
        c.repos_list += [(x.repo_id, x.repo_name) for x in
 
                    Repository.query().order_by(Repository.repo_name).all()
 
                    if x.repo_id != c.repo_info.repo_id]
 

	
 
        defaults['id_fork_of'] = db_repo.fork.repo_id if db_repo.fork else ''
 
        return defaults
 

	
 
    @HasPermissionAllDecorator('hg.admin')
 
    def index(self, format='html'):
 
        """GET /repos: All items in the collection"""
 
        # url('repos')
 

	
 
        c.repos_list = Repository.query()\
 
                        .order_by(func.lower(Repository.repo_name))\
 
                        .all()
 

	
 
        repos_data = []
 
        total_records = len(c.repos_list)
 

	
 
        _tmpl_lookup = rhodecode.CONFIG['pylons.app_globals'].mako_lookup
 
        template = _tmpl_lookup.get_template('data_table/_dt_elements.html')
 

	
 
        quick_menu = lambda repo_name: (template.get_def("quick_menu")
 
                                        .render(repo_name, _=_, h=h, c=c))
 
        repo_lnk = lambda name, rtype, private, fork_of: (
 
            template.get_def("repo_name")
 
            .render(name, rtype, private, fork_of, short_name=False,
 
                    admin=True, _=_, h=h, c=c))
 

	
 
        repo_actions = lambda repo_name: (template.get_def("repo_actions")
 
                                       .render(repo_name, _=_, h=h, c=c))
 

	
 
        for repo in c.repos_list:
 
            repos_data.append({
 
                "menu": quick_menu(repo.repo_name),
 
                "raw_name": repo.repo_name.lower(),
 
                "name": repo_lnk(repo.repo_name, repo.repo_type,
 
                                 repo.private, repo.fork),
 
                "desc": repo.description,
 
                "owner": repo.user.username,
 
                "action": repo_actions(repo.repo_name),
 
            })
 

	
 
        c.data = json.dumps({
 
            "totalRecords": total_records,
 
            "startIndex": 0,
 
            "sort": "name",
 
            "dir": "asc",
 
            "records": repos_data
 
        })
 

	
 
        return render('admin/repos/repos.html')
 

	
 
    @HasPermissionAnyDecorator('hg.admin', 'hg.create.repository')
 
    def create(self):
 
        """
 
        POST /repos: Create a new item"""
 
        # url('repos')
 

	
 
        self.__load_defaults()
 
        form_result = {}
 
        try:
 
            form_result = RepoForm(repo_groups=c.repo_groups_choices,
 
                                   landing_revs=c.landing_revs_choices)()\
 
                            .to_python(dict(request.POST))
 
            new_repo = RepoModel().create(form_result,
 
                                          self.rhodecode_user.user_id)
 
            if form_result['clone_uri']:
 
                h.flash(_('created repository %s from %s') \
 
                    % (form_result['repo_name'], form_result['clone_uri']),
 
                    category='success')
 
            else:
 
                h.flash(_('created repository %s') % form_result['repo_name'],
 
                    category='success')
 

	
 
            if request.POST.get('user_created'):
 
                # created by regular non admin user
 
                action_logger(self.rhodecode_user, 'user_created_repo',
 
                              form_result['repo_name_full'], self.ip_addr,
 
                              self.sa)
 
            else:
 
                action_logger(self.rhodecode_user, 'admin_created_repo',
 
                              form_result['repo_name_full'], self.ip_addr,
 
                              self.sa)
 
            Session().commit()
 
        except formencode.Invalid, errors:
 

	
 
            c.new_repo = errors.value['repo_name']
 

	
 
            if request.POST.get('user_created'):
 
                r = render('admin/repos/repo_add_create_repository.html')
 
            else:
 
                r = render('admin/repos/repo_add.html')
 

	
 
            return htmlfill.render(
 
                r,
 
                defaults=errors.value,
 
                errors=errors.error_dict or {},
 
                prefix_error=False,
 
                encoding="UTF-8")
 

	
 
        except Exception:
 
            log.error(traceback.format_exc())
 
            msg = _('error occurred during creation of repository %s') \
 
                    % form_result.get('repo_name')
 
            h.flash(msg, category='error')
 
            return redirect(url('repos'))
 
        #redirect to our new repo !
 
        return redirect(url('summary_home', repo_name=new_repo.repo_name))
 

	
 
    @HasPermissionAllDecorator('hg.admin')
 
    def new(self, format='html'):
 
        """GET /repos/new: Form to create a new item"""
 
        new_repo = request.GET.get('repo', '')
 
        c.new_repo = repo_name_slug(new_repo)
 
        self.__load_defaults()
 
        return render('admin/repos/repo_add.html')
 

	
 
    @HasPermissionAllDecorator('hg.admin')
 
    def update(self, repo_name):
 
        """
 
        PUT /repos/repo_name: Update an existing item"""
 
        # Forms posted to this method should contain a hidden field:
 
        #    <input type="hidden" name="_method" value="PUT" />
 
        # Or using helpers:
 
        #    h.form(url('repo', repo_name=ID),
 
        #           method='put')
 
        # url('repo', repo_name=ID)
 
        self.__load_defaults()
 
        repo_model = RepoModel()
 
        changed_name = repo_name
 
        #override the choices with extracted revisions !
 
        choices, c.landing_revs = ScmModel().get_repo_landing_revs(repo_name)
 
        c.landing_revs_choices = choices
 

	
 
        _form = RepoForm(edit=True, old_data={'repo_name': repo_name},
 
                         repo_groups=c.repo_groups_choices,
 
                         landing_revs=c.landing_revs_choices)()
 
        try:
 
            form_result = _form.to_python(dict(request.POST))
 
            repo = repo_model.update(repo_name, form_result)
 
            invalidate_cache('get_repo_cached_%s' % repo_name)
 
            h.flash(_('Repository %s updated successfully') % repo_name,
 
                    category='success')
 
            changed_name = repo.repo_name
 
            action_logger(self.rhodecode_user, 'admin_updated_repo',
 
                              changed_name, self.ip_addr, self.sa)
 
            Session().commit()
 
        except formencode.Invalid, errors:
 
            defaults = self.__load_data(repo_name)
 
            defaults.update(errors.value)
 
            return htmlfill.render(
 
                render('admin/repos/repo_edit.html'),
 
                defaults=defaults,
 
                errors=errors.error_dict or {},
 
                prefix_error=False,
 
                encoding="UTF-8")
 

	
 
        except Exception:
 
            log.error(traceback.format_exc())
 
            h.flash(_('error occurred during update of repository %s') \
 
                    % repo_name, category='error')
 
        return redirect(url('edit_repo', repo_name=changed_name))
 

	
 
    @HasPermissionAllDecorator('hg.admin')
 
    def delete(self, repo_name):
 
        """
 
        DELETE /repos/repo_name: Delete an existing item"""
 
        # Forms posted to this method should contain a hidden field:
 
        #    <input type="hidden" name="_method" value="DELETE" />
 
        # Or using helpers:
 
        #    h.form(url('repo', repo_name=ID),
 
        #           method='delete')
 
        # url('repo', repo_name=ID)
 

	
 
        repo_model = RepoModel()
 
        repo = repo_model.get_by_repo_name(repo_name)
 
        if not repo:
 
            h.flash(_('%s repository is not mapped to db perhaps'
 
                      ' it was moved or renamed  from the filesystem'
 
                      ' please run the application again'
 
                      ' in order to rescan repositories') % repo_name,
 
                      category='error')
 

	
 
            return redirect(url('repos'))
 
        try:
 
            action_logger(self.rhodecode_user, 'admin_deleted_repo',
 
                              repo_name, self.ip_addr, self.sa)
 
            repo_model.delete(repo)
 
            invalidate_cache('get_repo_cached_%s' % repo_name)
 
            h.flash(_('deleted repository %s') % repo_name, category='success')
 
            Session().commit()
 
        except IntegrityError, e:
 
            if e.message.find('repositories_fork_id_fkey') != -1:
 
                log.error(traceback.format_exc())
 
                h.flash(_('Cannot delete %s it still contains attached '
 
                          'forks') % repo_name,
 
                        category='warning')
 
            else:
 
                log.error(traceback.format_exc())
 
                h.flash(_('An error occurred during '
 
                          'deletion of %s') % repo_name,
 
                        category='error')
 

	
 
        except Exception, e:
 
            log.error(traceback.format_exc())
 
            h.flash(_('An error occurred during deletion of %s') % repo_name,
 
                    category='error')
 

	
 
        return redirect(url('repos'))
 

	
 
    @HasRepoPermissionAllDecorator('repository.admin')
 
    def delete_perm_user(self, repo_name):
 
        """
 
        DELETE an existing repository permission user
 

	
 
        :param repo_name:
 
        """
 
        try:
 
            RepoModel().revoke_user_permission(repo=repo_name,
 
                                               user=request.POST['user_id'])
 
            Session().commit()
 
        except Exception:
 
            log.error(traceback.format_exc())
 
            h.flash(_('An error occurred during deletion of repository user'),
 
                    category='error')
 
            raise HTTPInternalServerError()
 

	
 
    @HasRepoPermissionAllDecorator('repository.admin')
 
    def delete_perm_users_group(self, repo_name):
 
        """
 
        DELETE an existing repository permission users group
 

	
 
        :param repo_name:
 
        """
 

	
 
        try:
 
            RepoModel().revoke_users_group_permission(
 
                repo=repo_name, group_name=request.POST['users_group_id']
 
            )
 
            Session().commit()
 
        except Exception:
 
            log.error(traceback.format_exc())
 
            h.flash(_('An error occurred during deletion of repository'
 
                      ' users groups'),
 
                    category='error')
 
            raise HTTPInternalServerError()
 

	
 
    @HasPermissionAllDecorator('hg.admin')
 
    def repo_stats(self, repo_name):
 
        """
 
        DELETE an existing repository statistics
 

	
 
        :param repo_name:
 
        """
 

	
 
        try:
 
            RepoModel().delete_stats(repo_name)
 
            Session().commit()
 
        except Exception, e:
 
            log.error(traceback.format_exc())
 
            h.flash(_('An error occurred during deletion of repository stats'),
 
                    category='error')
 
        return redirect(url('edit_repo', repo_name=repo_name))
 

	
 
    @HasPermissionAllDecorator('hg.admin')
 
    def repo_cache(self, repo_name):
 
        """
 
        INVALIDATE existing repository cache
 

	
 
        :param repo_name:
 
        """
 

	
 
        try:
 
            ScmModel().mark_for_invalidation(repo_name)
 
            Session().commit()
 
        except Exception, e:
 
            log.error(traceback.format_exc())
 
            h.flash(_('An error occurred during cache invalidation'),
 
                    category='error')
 
        return redirect(url('edit_repo', repo_name=repo_name))
 

	
 
    @HasPermissionAllDecorator('hg.admin')
 
    def repo_locking(self, repo_name):
 
        """
 
        Unlock repository when it is locked !
 

	
 
        :param repo_name:
 
        """
 

	
 
        try:
 
            repo = Repository.get_by_repo_name(repo_name)
 
            if request.POST.get('set_lock'):
 
                Repository.lock(repo, c.rhodecode_user.user_id)
 
            elif request.POST.get('set_unlock'):
 
                Repository.unlock(repo)
 
        except Exception, e:
 
            log.error(traceback.format_exc())
 
            h.flash(_('An error occurred during unlocking'),
 
                    category='error')
 
        return redirect(url('edit_repo', repo_name=repo_name))
 

	
 
    @HasPermissionAllDecorator('hg.admin')
 
    def repo_public_journal(self, repo_name):
 
        """
rhodecode/controllers/admin/settings.py
Show inline comments
 
@@ -100,409 +100,417 @@ class SettingsController(BaseController)
 
        """GET /admin/settings/new: Form to create a new item"""
 
        # url('admin_new_setting')
 

	
 
    @HasPermissionAllDecorator('hg.admin')
 
    def update(self, setting_id):
 
        """PUT /admin/settings/setting_id: Update an existing item"""
 
        # Forms posted to this method should contain a hidden field:
 
        #    <input type="hidden" name="_method" value="PUT" />
 
        # Or using helpers:
 
        #    h.form(url('admin_setting', setting_id=ID),
 
        #           method='put')
 
        # url('admin_setting', setting_id=ID)
 

	
 
        if setting_id == 'mapping':
 
            rm_obsolete = request.POST.get('destroy', False)
 
            log.debug('Rescanning directories with destroy=%s' % rm_obsolete)
 
            initial = ScmModel().repo_scan()
 
            log.debug('invalidating all repositories')
 
            for repo_name in initial.keys():
 
                invalidate_cache('get_repo_cached_%s' % repo_name)
 

	
 
            added, removed = repo2db_mapper(initial, rm_obsolete)
 

	
 
            h.flash(_('Repositories successfully'
 
                      ' rescanned added: %s,removed: %s') % (added, removed),
 
                      category='success')
 

	
 
        if setting_id == 'whoosh':
 
            repo_location = self._get_hg_ui_settings()['paths_root_path']
 
            full_index = request.POST.get('full_index', False)
 
            run_task(tasks.whoosh_index, repo_location, full_index)
 
            h.flash(_('Whoosh reindex task scheduled'), category='success')
 

	
 
        if setting_id == 'global':
 

	
 
            application_form = ApplicationSettingsForm()()
 
            try:
 
                form_result = application_form.to_python(dict(request.POST))
 
            except formencode.Invalid, errors:
 
                return htmlfill.render(
 
                     render('admin/settings/settings.html'),
 
                     defaults=errors.value,
 
                     errors=errors.error_dict or {},
 
                     prefix_error=False,
 
                     encoding="UTF-8"
 
                )
 

	
 
            try:
 
                sett1 = RhodeCodeSetting.get_by_name_or_create('title')
 
                sett1.app_settings_value = form_result['rhodecode_title']
 
                Session().add(sett1)
 

	
 
                sett2 = RhodeCodeSetting.get_by_name_or_create('realm')
 
                sett2.app_settings_value = form_result['rhodecode_realm']
 
                Session().add(sett2)
 

	
 
                sett3 = RhodeCodeSetting.get_by_name_or_create('ga_code')
 
                sett3.app_settings_value = form_result['rhodecode_ga_code']
 
                Session().add(sett3)
 

	
 
                Session().commit()
 
                set_rhodecode_config(config)
 
                h.flash(_('Updated application settings'), category='success')
 

	
 
            except Exception:
 
                log.error(traceback.format_exc())
 
                h.flash(_('error occurred during updating '
 
                          'application settings'),
 
                          category='error')
 

	
 
        if setting_id == 'visual':
 

	
 
            application_form = ApplicationVisualisationForm()()
 
            try:
 
                form_result = application_form.to_python(dict(request.POST))
 
            except formencode.Invalid, errors:
 
                return htmlfill.render(
 
                     render('admin/settings/settings.html'),
 
                     defaults=errors.value,
 
                     errors=errors.error_dict or {},
 
                     prefix_error=False,
 
                     encoding="UTF-8"
 
                )
 

	
 
            try:
 
                sett1 = RhodeCodeSetting.get_by_name_or_create('show_public_icon')
 
                sett1.app_settings_value = \
 
                    form_result['rhodecode_show_public_icon']
 
                Session().add(sett1)
 

	
 
                sett2 = RhodeCodeSetting.get_by_name_or_create('show_private_icon')
 
                sett2.app_settings_value = \
 
                    form_result['rhodecode_show_private_icon']
 
                Session().add(sett2)
 

	
 
                sett3 = RhodeCodeSetting.get_by_name_or_create('stylify_metatags')
 
                sett3.app_settings_value = \
 
                    form_result['rhodecode_stylify_metatags']
 
                Session().add(sett3)
 

	
 
                sett4 = RhodeCodeSetting.get_by_name_or_create('lightweight_dashboard')
 
                sett4.app_settings_value = \
 
                    form_result['rhodecode_lightweight_dashboard']
 
                Session().add(sett4)
 

	
 
                Session().commit()
 
                set_rhodecode_config(config)
 
                h.flash(_('Updated visualisation settings'),
 
                        category='success')
 

	
 
            except Exception:
 
                log.error(traceback.format_exc())
 
                h.flash(_('error occurred during updating '
 
                          'visualisation settings'),
 
                        category='error')
 

	
 
        if setting_id == 'vcs':
 
            application_form = ApplicationUiSettingsForm()()
 
            try:
 
                form_result = application_form.to_python(dict(request.POST))
 
            except formencode.Invalid, errors:
 
                return htmlfill.render(
 
                     render('admin/settings/settings.html'),
 
                     defaults=errors.value,
 
                     errors=errors.error_dict or {},
 
                     prefix_error=False,
 
                     encoding="UTF-8"
 
                )
 

	
 
            try:
 
                # fix namespaces for hooks and extensions
 
                _f = lambda s: s.replace('.', '_')
 

	
 
                sett = RhodeCodeUi.get_by_key('push_ssl')
 
                sett.ui_value = form_result['web_push_ssl']
 
                Session().add(sett)
 

	
 
                sett = RhodeCodeUi.get_by_key('/')
 
                sett.ui_value = form_result['paths_root_path']
 
                Session().add(sett)
 

	
 
                #HOOKS
 
                sett = RhodeCodeUi.get_by_key(RhodeCodeUi.HOOK_UPDATE)
 
                sett.ui_active = form_result[_f('hooks_%s' %
 
                                                RhodeCodeUi.HOOK_UPDATE)]
 
                Session().add(sett)
 

	
 
                sett = RhodeCodeUi.get_by_key(RhodeCodeUi.HOOK_REPO_SIZE)
 
                sett.ui_active = form_result[_f('hooks_%s' %
 
                                                RhodeCodeUi.HOOK_REPO_SIZE)]
 
                Session().add(sett)
 

	
 
                sett = RhodeCodeUi.get_by_key(RhodeCodeUi.HOOK_PUSH)
 
                sett.ui_active = form_result[_f('hooks_%s' %
 
                                                RhodeCodeUi.HOOK_PUSH)]
 
                Session().add(sett)
 

	
 
                sett = RhodeCodeUi.get_by_key(RhodeCodeUi.HOOK_PULL)
 
                sett.ui_active = form_result[_f('hooks_%s' %
 
                                                 RhodeCodeUi.HOOK_PULL)]
 

	
 
                Session().add(sett)
 

	
 
                ## EXTENSIONS
 
                sett = RhodeCodeUi.get_by_key('largefiles')
 
                if not sett:
 
                    #make one if it's not there !
 
                    sett = RhodeCodeUi()
 
                    sett.ui_key = 'largefiles'
 
                    sett.ui_section = 'extensions'
 
                sett.ui_active = form_result[_f('extensions_largefiles')]
 
                Session().add(sett)
 

	
 
                sett = RhodeCodeUi.get_by_key('hgsubversion')
 
                if not sett:
 
                    #make one if it's not there !
 
                    sett = RhodeCodeUi()
 
                    sett.ui_key = 'hgsubversion'
 
                    sett.ui_section = 'extensions'
 

	
 
                sett.ui_active = form_result[_f('extensions_hgsubversion')]
 
                Session().add(sett)
 

	
 
#                sett = RhodeCodeUi.get_by_key('hggit')
 
#                if not sett:
 
#                    #make one if it's not there !
 
#                    sett = RhodeCodeUi()
 
#                    sett.ui_key = 'hggit'
 
#                    sett.ui_section = 'extensions'
 
#
 
#                sett.ui_active = form_result[_f('extensions_hggit')]
 
#                Session().add(sett)
 

	
 
                Session().commit()
 

	
 
                h.flash(_('Updated VCS settings'), category='success')
 

	
 
            except Exception:
 
                log.error(traceback.format_exc())
 
                h.flash(_('error occurred during updating '
 
                          'application settings'), category='error')
 

	
 
        if setting_id == 'hooks':
 
            ui_key = request.POST.get('new_hook_ui_key')
 
            ui_value = request.POST.get('new_hook_ui_value')
 
            try:
 

	
 
                if ui_value and ui_key:
 
                    RhodeCodeUi.create_or_update_hook(ui_key, ui_value)
 
                    h.flash(_('Added new hook'),
 
                            category='success')
 

	
 
                # check for edits
 
                update = False
 
                _d = request.POST.dict_of_lists()
 
                for k, v in zip(_d.get('hook_ui_key', []),
 
                                _d.get('hook_ui_value_new', [])):
 
                    RhodeCodeUi.create_or_update_hook(k, v)
 
                    update = True
 

	
 
                if update:
 
                    h.flash(_('Updated hooks'), category='success')
 
                Session().commit()
 
            except Exception:
 
                log.error(traceback.format_exc())
 
                h.flash(_('error occurred during hook creation'),
 
                        category='error')
 

	
 
            return redirect(url('admin_edit_setting', setting_id='hooks'))
 

	
 
        if setting_id == 'email':
 
            test_email = request.POST.get('test_email')
 
            test_email_subj = 'RhodeCode TestEmail'
 
            test_email_body = 'RhodeCode Email test'
 

	
 
            test_email_html_body = EmailNotificationModel()\
 
                .get_email_tmpl(EmailNotificationModel.TYPE_DEFAULT,
 
                                body=test_email_body)
 

	
 
            recipients = [test_email] if [test_email] else None
 

	
 
            run_task(tasks.send_email, recipients, test_email_subj,
 
                     test_email_body, test_email_html_body)
 

	
 
            h.flash(_('Email task created'), category='success')
 
        return redirect(url('admin_settings'))
 

	
 
    @HasPermissionAllDecorator('hg.admin')
 
    def delete(self, setting_id):
 
        """DELETE /admin/settings/setting_id: Delete an existing item"""
 
        # Forms posted to this method should contain a hidden field:
 
        #    <input type="hidden" name="_method" value="DELETE" />
 
        # Or using helpers:
 
        #    h.form(url('admin_setting', setting_id=ID),
 
        #           method='delete')
 
        # url('admin_setting', setting_id=ID)
 
        if setting_id == 'hooks':
 
            hook_id = request.POST.get('hook_id')
 
            RhodeCodeUi.delete(hook_id)
 
            Session().commit()
 

	
 
    @HasPermissionAllDecorator('hg.admin')
 
    def show(self, setting_id, format='html'):
 
        """
 
        GET /admin/settings/setting_id: Show a specific item"""
 
        # url('admin_setting', setting_id=ID)
 

	
 
    @HasPermissionAllDecorator('hg.admin')
 
    def edit(self, setting_id, format='html'):
 
        """
 
        GET /admin/settings/setting_id/edit: Form to
 
        edit an existing item"""
 
        # url('admin_edit_setting', setting_id=ID)
 

	
 
        c.hooks = RhodeCodeUi.get_builtin_hooks()
 
        c.custom_hooks = RhodeCodeUi.get_custom_hooks()
 

	
 
        return htmlfill.render(
 
            render('admin/settings/hooks.html'),
 
            defaults={},
 
            encoding="UTF-8",
 
            force_defaults=False
 
        )
 

	
 
    @NotAnonymous()
 
    def my_account(self):
 
        """
 
        GET /_admin/my_account Displays info about my account
 
        """
 
        # url('admin_settings_my_account')
 

	
 
        c.user = User.get(self.rhodecode_user.user_id)
 
        all_repos = Session().query(Repository)\
 
                     .filter(Repository.user_id == c.user.user_id)\
 
                     .order_by(func.lower(Repository.repo_name)).all()
 

	
 
        c.user_repos = ScmModel().get_repos(all_repos)
 

	
 
        if c.user.username == 'default':
 
            h.flash(_("You can't edit this user since it's"
 
              " crucial for entire application"), category='warning')
 
            return redirect(url('users'))
 

	
 
        defaults = c.user.get_dict()
 

	
 
        c.form = htmlfill.render(
 
            render('admin/users/user_edit_my_account_form.html'),
 
            defaults=defaults,
 
            encoding="UTF-8",
 
            force_defaults=False
 
        )
 
        return render('admin/users/user_edit_my_account.html')
 

	
 
    @NotAnonymous()
 
    def my_account_update(self):
 
        """PUT /_admin/my_account_update: Update an existing item"""
 
        # Forms posted to this method should contain a hidden field:
 
        #    <input type="hidden" name="_method" value="PUT" />
 
        # Or using helpers:
 
        #    h.form(url('admin_settings_my_account_update'),
 
        #           method='put')
 
        # url('admin_settings_my_account_update', id=ID)
 
        uid = self.rhodecode_user.user_id
 
        email = self.rhodecode_user.email
 
        _form = UserForm(edit=True,
 
                         old_data={'user_id': uid, 'email': email})()
 
        form_result = {}
 
        try:
 
            form_result = _form.to_python(dict(request.POST))
 
            UserModel().update_my_account(uid, form_result)
 
            h.flash(_('Your account was updated successfully'),
 
                    category='success')
 
            Session().commit()
 
        except formencode.Invalid, errors:
 
            c.user = User.get(self.rhodecode_user.user_id)
 

	
 
            c.form = htmlfill.render(
 
                render('admin/users/user_edit_my_account_form.html'),
 
                defaults=errors.value,
 
                errors=errors.error_dict or {},
 
                prefix_error=False,
 
                encoding="UTF-8")
 
            return render('admin/users/user_edit_my_account.html')
 
        except Exception:
 
            log.error(traceback.format_exc())
 
            h.flash(_('error occurred during update of user %s') \
 
                    % form_result.get('username'), category='error')
 

	
 
        return redirect(url('my_account'))
 

	
 
    @NotAnonymous()
 
    def my_account_my_repos(self):
 
        all_repos = Session().query(Repository)\
 
            .filter(Repository.user_id == self.rhodecode_user.user_id)\
 
            .order_by(func.lower(Repository.repo_name))\
 
            .all()
 
        c.user_repos = ScmModel().get_repos(all_repos)
 
        return render('admin/users/user_edit_my_account_repos.html')
 

	
 
    @NotAnonymous()
 
    def my_account_my_pullrequests(self):
 
        c.my_pull_requests = PullRequest.query()\
 
                                .filter(PullRequest.user_id==
 
                                        self.rhodecode_user.user_id)\
 
                                .all()
 
        c.participate_in_pull_requests = \
 
            [x.pull_request for x in PullRequestReviewers.query()\
 
                                    .filter(PullRequestReviewers.user_id==
 
                                            self.rhodecode_user.user_id)\
 
                                    .all()]
 
        return render('admin/users/user_edit_my_account_pullrequests.html')
 

	
 
    @NotAnonymous()
 
    @HasPermissionAnyDecorator('hg.admin', 'hg.create.repository')
 
    def create_repository(self):
 
        """GET /_admin/create_repository: Form to create a new item"""
 

	
 
        c.repo_groups = RepoGroup.groups_choices(check_perms=True)
 
        c.repo_groups_choices = map(lambda k: unicode(k[0]), c.repo_groups)
 
        choices, c.landing_revs = ScmModel().get_repo_landing_revs()
 

	
 
        new_repo = request.GET.get('repo', '')
 
        c.new_repo = repo_name_slug(new_repo)
 

	
 
        return render('admin/repos/repo_add_create_repository.html')
 
        ## apply the defaults from defaults page
 
        defaults = RhodeCodeSetting.get_default_repo_settings(strip_prefix=True)
 
        return htmlfill.render(
 
            render('admin/repos/repo_add_create_repository.html'),
 
            defaults=defaults,
 
            errors={},
 
            prefix_error=False,
 
            encoding="UTF-8"
 
        )
 

	
 
    def _get_hg_ui_settings(self):
 
        ret = RhodeCodeUi.query().all()
 

	
 
        if not ret:
 
            raise Exception('Could not get application ui settings !')
 
        settings = {}
 
        for each in ret:
 
            k = each.ui_key
 
            v = each.ui_value
 
            if k == '/':
 
                k = 'root_path'
 

	
 
            if k == 'push_ssl':
 
                v = str2bool(v)
 

	
 
            if k.find('.') != -1:
 
                k = k.replace('.', '_')
 

	
 
            if each.ui_section in ['hooks', 'extensions']:
 
                v = each.ui_active
 

	
 
            settings[each.ui_section + '_' + k] = v
 
        return settings
rhodecode/lib/db_manage.py
Show inline comments
 
# -*- coding: utf-8 -*-
 
"""
 
    rhodecode.lib.db_manage
 
    ~~~~~~~~~~~~~~~~~~~~~~~
 

	
 
    Database creation, and setup module for RhodeCode. Used for creation
 
    of database as well as for migration operations
 

	
 
    :created_on: Apr 10, 2010
 
    :author: marcink
 
    :copyright: (C) 2010-2012 Marcin Kuzminski <marcin@python-works.com>
 
    :license: GPLv3, see COPYING for more details.
 
"""
 
# This program is free software: you can redistribute it and/or modify
 
# it under the terms of the GNU General Public License as published by
 
# the Free Software Foundation, either version 3 of the License, or
 
# (at your option) any later version.
 
#
 
# This program is distributed in the hope that it will be useful,
 
# but WITHOUT ANY WARRANTY; without even the implied warranty of
 
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
# GNU General Public License for more details.
 
#
 
# You should have received a copy of the GNU General Public License
 
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
 

	
 
import os
 
import sys
 
import uuid
 
import logging
 
from os.path import dirname as dn, join as jn
 

	
 
from rhodecode import __dbversion__, __py_version__
 

	
 
from rhodecode.model.user import UserModel
 
from rhodecode.lib.utils import ask_ok
 
from rhodecode.model import init_model
 
from rhodecode.model.db import User, Permission, RhodeCodeUi, \
 
    RhodeCodeSetting, UserToPerm, DbMigrateVersion, RepoGroup, \
 
    UserRepoGroupToPerm
 

	
 
from sqlalchemy.engine import create_engine
 
from rhodecode.model.repos_group import ReposGroupModel
 
#from rhodecode.model import meta
 
from rhodecode.model.meta import Session, Base
 

	
 

	
 
log = logging.getLogger(__name__)
 

	
 

	
 
def notify(msg):
 
    """
 
    Notification for migrations messages
 
    """
 
    ml = len(msg) + (4 * 2)
 
    print >> sys.stdout, ('*** %s ***\n%s' % (msg, '*' * ml)).upper()
 

	
 

	
 
class DbManage(object):
 
    def __init__(self, log_sql, dbconf, root, tests=False, cli_args={}):
 
        self.dbname = dbconf.split('/')[-1]
 
        self.tests = tests
 
        self.root = root
 
        self.dburi = dbconf
 
        self.log_sql = log_sql
 
        self.db_exists = False
 
        self.cli_args = cli_args
 
        self.init_db()
 
        global ask_ok
 

	
 
        if self.cli_args.get('force_ask') is True:
 
            ask_ok = lambda *args, **kwargs: True
 
        elif self.cli_args.get('force_ask') is False:
 
            ask_ok = lambda *args, **kwargs: False
 

	
 
    def init_db(self):
 
        engine = create_engine(self.dburi, echo=self.log_sql)
 
        init_model(engine)
 
        self.sa = Session()
 

	
 
    def create_tables(self, override=False):
 
        """
 
        Create a auth database
 
        """
 

	
 
        log.info("Any existing database is going to be destroyed")
 
        if self.tests:
 
            destroy = True
 
        else:
 
            destroy = ask_ok('Are you sure to destroy old database ? [y/n]')
 
        if not destroy:
 
            sys.exit('Nothing done')
 
        if destroy:
 
            Base.metadata.drop_all()
 

	
 
        checkfirst = not override
 
        Base.metadata.create_all(checkfirst=checkfirst)
 
        log.info('Created tables for %s' % self.dbname)
 

	
 
    def set_db_version(self):
 
        ver = DbMigrateVersion()
 
        ver.version = __dbversion__
 
        ver.repository_id = 'rhodecode_db_migrations'
 
        ver.repository_path = 'versions'
 
        self.sa.add(ver)
 
        log.info('db version set to: %s' % __dbversion__)
 

	
 
    def upgrade(self):
 
        """
 
        Upgrades given database schema to given revision following
 
        all needed steps, to perform the upgrade
 

	
 
        """
 

	
 
        from rhodecode.lib.dbmigrate.migrate.versioning import api
 
        from rhodecode.lib.dbmigrate.migrate.exceptions import \
 
            DatabaseNotControlledError
 

	
 
        if 'sqlite' in self.dburi:
 
            print (
 
               '********************** WARNING **********************\n'
 
               'Make sure your version of sqlite is at least 3.7.X.  \n'
 
               'Earlier versions are known to fail on some migrations\n'
 
               '*****************************************************\n'
 
            )
 
        upgrade = ask_ok('You are about to perform database upgrade, make '
 
                         'sure You backed up your database before. '
 
                         'Continue ? [y/n]')
 
        if not upgrade:
 
            sys.exit('Nothing done')
 

	
 
        repository_path = jn(dn(dn(dn(os.path.realpath(__file__)))),
 
                             'rhodecode/lib/dbmigrate')
 
        db_uri = self.dburi
 

	
 
        try:
 
            curr_version = api.db_version(db_uri, repository_path)
 
            msg = ('Found current database under version'
 
                 ' control with version %s' % curr_version)
 

	
 
        except (RuntimeError, DatabaseNotControlledError):
 
            curr_version = 1
 
            msg = ('Current database is not under version control. Setting'
 
                   ' as version %s' % curr_version)
 
            api.version_control(db_uri, repository_path, curr_version)
 

	
 
        notify(msg)
 

	
 
        if curr_version == __dbversion__:
 
            sys.exit('This database is already at the newest version')
 

	
 
        #======================================================================
 
        # UPGRADE STEPS
 
        #======================================================================
 

	
 
        class UpgradeSteps(object):
 
            """
 
            Those steps follow schema versions so for example schema
 
            for example schema with seq 002 == step_2 and so on.
 
            """
 

	
 
            def __init__(self, klass):
 
                self.klass = klass
 

	
 
            def step_0(self):
 
                # step 0 is the schema upgrade, and than follow proper upgrades
 
                notify('attempting to do database upgrade to version %s' \
 
                                % __dbversion__)
 
                api.upgrade(db_uri, repository_path, __dbversion__)
 
                notify('Schema upgrade completed')
 

	
 
            def step_1(self):
 
                pass
 

	
 
            def step_2(self):
 
                notify('Patching repo paths for newer version of RhodeCode')
 
                self.klass.fix_repo_paths()
 

	
 
                notify('Patching default user of RhodeCode')
 
                self.klass.fix_default_user()
 

	
 
                log.info('Changing ui settings')
 
                self.klass.create_ui_settings()
 

	
 
            def step_3(self):
 
                notify('Adding additional settings into RhodeCode db')
 
                self.klass.fix_settings()
 
                notify('Adding ldap defaults')
 
                self.klass.create_ldap_options(skip_existing=True)
 

	
 
            def step_4(self):
 
                notify('create permissions and fix groups')
 
                self.klass.create_permissions()
 
                self.klass.fixup_groups()
 

	
 
            def step_5(self):
 
                pass
 

	
 
            def step_6(self):
 

	
 
                notify('re-checking permissions')
 
                self.klass.create_permissions()
 

	
 
                notify('installing new UI options')
 
                sett4 = RhodeCodeSetting('show_public_icon', True)
 
                Session().add(sett4)
 
                sett5 = RhodeCodeSetting('show_private_icon', True)
 
                Session().add(sett5)
 
                sett6 = RhodeCodeSetting('stylify_metatags', False)
 
                Session().add(sett6)
 

	
 
                notify('fixing old PULL hook')
 
                _pull = RhodeCodeUi.get_by_key('preoutgoing.pull_logger')
 
                if _pull:
 
                    _pull.ui_key = RhodeCodeUi.HOOK_PULL
 
                    Session().add(_pull)
 

	
 
                notify('fixing old PUSH hook')
 
                _push = RhodeCodeUi.get_by_key('pretxnchangegroup.push_logger')
 
                if _push:
 
                    _push.ui_key = RhodeCodeUi.HOOK_PUSH
 
                    Session().add(_push)
 

	
 
                notify('installing new pre-push hook')
 
                hooks4 = RhodeCodeUi()
 
                hooks4.ui_section = 'hooks'
 
                hooks4.ui_key = RhodeCodeUi.HOOK_PRE_PUSH
 
                hooks4.ui_value = 'python:rhodecode.lib.hooks.pre_push'
 
                Session().add(hooks4)
 

	
 
                notify('installing new pre-pull hook')
 
                hooks6 = RhodeCodeUi()
 
                hooks6.ui_section = 'hooks'
 
                hooks6.ui_key = RhodeCodeUi.HOOK_PRE_PULL
 
                hooks6.ui_value = 'python:rhodecode.lib.hooks.pre_pull'
 
                Session().add(hooks6)
 

	
 
                notify('installing hgsubversion option')
 
                # enable hgsubversion disabled by default
 
                hgsubversion = RhodeCodeUi()
 
                hgsubversion.ui_section = 'extensions'
 
                hgsubversion.ui_key = 'hgsubversion'
 
                hgsubversion.ui_value = ''
 
                hgsubversion.ui_active = False
 
                Session().add(hgsubversion)
 

	
 
                notify('installing hg git option')
 
                # enable hggit disabled by default
 
                hggit = RhodeCodeUi()
 
                hggit.ui_section = 'extensions'
 
                hggit.ui_key = 'hggit'
 
                hggit.ui_value = ''
 
                hggit.ui_active = False
 
                Session().add(hggit)
 

	
 
                notify('re-check default permissions')
 
                default_user = User.get_by_username(User.DEFAULT_USER)
 
                perm = Permission.get_by_key('hg.fork.repository')
 
                reg_perm = UserToPerm()
 
                reg_perm.user = default_user
 
                reg_perm.permission = perm
 
                Session().add(reg_perm)
 

	
 
            def step_7(self):
 
                perm_fixes = self.klass.reset_permissions(User.DEFAULT_USER)
 
                Session().commit()
 
                if perm_fixes:
 
                    notify('There was an inconsistent state of permissions '
 
                           'detected for default user. Permissions are now '
 
                           'reset to the default value for default user. '
 
                           'Please validate and check default permissions '
 
                           'in admin panel')
 

	
 
            def step_8(self):
 
                self.klass.populate_default_permissions()
 
                self.klass.create_default_options(skip_existing=True)
 
                Session().commit()
 

	
 
        upgrade_steps = [0] + range(curr_version + 1, __dbversion__ + 1)
 

	
 
        # CALL THE PROPER ORDER OF STEPS TO PERFORM FULL UPGRADE
 
        _step = None
 
        for step in upgrade_steps:
 
            notify('performing upgrade step %s' % step)
 
            getattr(UpgradeSteps(self), 'step_%s' % step)()
 
            self.sa.commit()
 
            _step = step
 

	
 
        notify('upgrade to version %s successful' % _step)
 

	
 
    def fix_repo_paths(self):
 
        """
 
        Fixes a old rhodecode version path into new one without a '*'
 
        """
 

	
 
        paths = self.sa.query(RhodeCodeUi)\
 
                .filter(RhodeCodeUi.ui_key == '/')\
 
                .scalar()
 

	
 
        paths.ui_value = paths.ui_value.replace('*', '')
 

	
 
        try:
 
            self.sa.add(paths)
 
            self.sa.commit()
 
        except:
 
            self.sa.rollback()
 
            raise
 

	
 
    def fix_default_user(self):
 
        """
 
        Fixes a old default user with some 'nicer' default values,
 
        used mostly for anonymous access
 
        """
 
        def_user = self.sa.query(User)\
 
                .filter(User.username == 'default')\
 
                .one()
 

	
 
        def_user.name = 'Anonymous'
 
        def_user.lastname = 'User'
 
        def_user.email = 'anonymous@rhodecode.org'
 

	
 
        try:
 
            self.sa.add(def_user)
 
            self.sa.commit()
 
        except:
 
            self.sa.rollback()
 
            raise
 

	
 
    def fix_settings(self):
 
        """
 
        Fixes rhodecode settings adds ga_code key for google analytics
 
        """
 

	
 
        hgsettings3 = RhodeCodeSetting('ga_code', '')
 

	
 
        try:
 
            self.sa.add(hgsettings3)
 
            self.sa.commit()
 
        except:
 
            self.sa.rollback()
 
            raise
 

	
 
    def admin_prompt(self, second=False):
 
        if not self.tests:
 
            import getpass
 

	
 
            # defaults
 
            defaults = self.cli_args
 
            username = defaults.get('username')
 
            password = defaults.get('password')
 
            email = defaults.get('email')
 

	
 
            def get_password():
 
                password = getpass.getpass('Specify admin password '
 
                                           '(min 6 chars):')
 
                confirm = getpass.getpass('Confirm password:')
 

	
 
                if password != confirm:
 
                    log.error('passwords mismatch')
 
                    return False
 
                if len(password) < 6:
 
                    log.error('password is to short use at least 6 characters')
 
                    return False
 

	
 
                return password
 
            if username is None:
 
                username = raw_input('Specify admin username:')
 
            if password is None:
 
                password = get_password()
 
                if not password:
 
                    #second try
 
                    password = get_password()
 
                    if not password:
 
                        sys.exit()
 
            if email is None:
 
                email = raw_input('Specify admin email:')
 
            self.create_user(username, password, email, True)
 
        else:
 
            log.info('creating admin and regular test users')
 
            from rhodecode.tests import TEST_USER_ADMIN_LOGIN, \
 
            TEST_USER_ADMIN_PASS, TEST_USER_ADMIN_EMAIL, \
 
            TEST_USER_REGULAR_LOGIN, TEST_USER_REGULAR_PASS, \
 
            TEST_USER_REGULAR_EMAIL, TEST_USER_REGULAR2_LOGIN, \
 
            TEST_USER_REGULAR2_PASS, TEST_USER_REGULAR2_EMAIL
 

	
 
            self.create_user(TEST_USER_ADMIN_LOGIN, TEST_USER_ADMIN_PASS,
 
                             TEST_USER_ADMIN_EMAIL, True)
 

	
 
            self.create_user(TEST_USER_REGULAR_LOGIN, TEST_USER_REGULAR_PASS,
 
                             TEST_USER_REGULAR_EMAIL, False)
 

	
 
            self.create_user(TEST_USER_REGULAR2_LOGIN, TEST_USER_REGULAR2_PASS,
 
                             TEST_USER_REGULAR2_EMAIL, False)
 

	
 
    def create_ui_settings(self):
 
        """
 
        Creates ui settings, fills out hooks
 
        and disables dotencode
 
        """
 

	
 
        #HOOKS
 
        hooks1_key = RhodeCodeUi.HOOK_UPDATE
 
        hooks1_ = self.sa.query(RhodeCodeUi)\
 
            .filter(RhodeCodeUi.ui_key == hooks1_key).scalar()
 

	
 
        hooks1 = RhodeCodeUi() if hooks1_ is None else hooks1_
 
        hooks1.ui_section = 'hooks'
 
        hooks1.ui_key = hooks1_key
 
        hooks1.ui_value = 'hg update >&2'
 
        hooks1.ui_active = False
 
        self.sa.add(hooks1)
 

	
 
        hooks2_key = RhodeCodeUi.HOOK_REPO_SIZE
 
        hooks2_ = self.sa.query(RhodeCodeUi)\
 
            .filter(RhodeCodeUi.ui_key == hooks2_key).scalar()
 
        hooks2 = RhodeCodeUi() if hooks2_ is None else hooks2_
 
        hooks2.ui_section = 'hooks'
 
        hooks2.ui_key = hooks2_key
 
        hooks2.ui_value = 'python:rhodecode.lib.hooks.repo_size'
 
        self.sa.add(hooks2)
 

	
 
        hooks3 = RhodeCodeUi()
 
        hooks3.ui_section = 'hooks'
 
        hooks3.ui_key = RhodeCodeUi.HOOK_PUSH
 
        hooks3.ui_value = 'python:rhodecode.lib.hooks.log_push_action'
 
        self.sa.add(hooks3)
 

	
 
        hooks4 = RhodeCodeUi()
 
        hooks4.ui_section = 'hooks'
 
        hooks4.ui_key = RhodeCodeUi.HOOK_PRE_PUSH
 
        hooks4.ui_value = 'python:rhodecode.lib.hooks.pre_push'
 
        self.sa.add(hooks4)
 

	
 
        hooks5 = RhodeCodeUi()
 
        hooks5.ui_section = 'hooks'
 
        hooks5.ui_key = RhodeCodeUi.HOOK_PULL
 
        hooks5.ui_value = 'python:rhodecode.lib.hooks.log_pull_action'
 
        self.sa.add(hooks5)
 

	
 
        hooks6 = RhodeCodeUi()
 
        hooks6.ui_section = 'hooks'
 
        hooks6.ui_key = RhodeCodeUi.HOOK_PRE_PULL
 
        hooks6.ui_value = 'python:rhodecode.lib.hooks.pre_pull'
 
        self.sa.add(hooks6)
 

	
 
        # enable largefiles
 
        largefiles = RhodeCodeUi()
 
        largefiles.ui_section = 'extensions'
 
        largefiles.ui_key = 'largefiles'
 
        largefiles.ui_value = ''
 
        self.sa.add(largefiles)
 

	
 
        # enable hgsubversion disabled by default
 
        hgsubversion = RhodeCodeUi()
 
        hgsubversion.ui_section = 'extensions'
 
        hgsubversion.ui_key = 'hgsubversion'
 
        hgsubversion.ui_value = ''
 
        hgsubversion.ui_active = False
 
        self.sa.add(hgsubversion)
 

	
 
        # enable hggit disabled by default
 
        hggit = RhodeCodeUi()
 
        hggit.ui_section = 'extensions'
 
        hggit.ui_key = 'hggit'
 
        hggit.ui_value = ''
 
        hggit.ui_active = False
 
        self.sa.add(hggit)
 

	
 
    def create_ldap_options(self, skip_existing=False):
 
        """Creates ldap settings"""
 

	
 
        for k, v in [('ldap_active', 'false'), ('ldap_host', ''),
 
                    ('ldap_port', '389'), ('ldap_tls_kind', 'PLAIN'),
 
                    ('ldap_tls_reqcert', ''), ('ldap_dn_user', ''),
 
                    ('ldap_dn_pass', ''), ('ldap_base_dn', ''),
 
                    ('ldap_filter', ''), ('ldap_search_scope', ''),
 
                    ('ldap_attr_login', ''), ('ldap_attr_firstname', ''),
 
                    ('ldap_attr_lastname', ''), ('ldap_attr_email', '')]:
 

	
 
            if skip_existing and RhodeCodeSetting.get_by_name(k) != None:
 
                log.debug('Skipping option %s' % k)
 
                continue
 
            setting = RhodeCodeSetting(k, v)
 
            self.sa.add(setting)
 

	
 
    def create_default_options(self, skip_existing=False):
 
        """Creates default settings"""
 

	
 
        for k, v in [
 
            ('default_repo_enable_locking',  False),
 
            ('default_repo_enable_downloads', False),
 
            ('default_repo_enable_statistics', False),
 
            ('default_repo_private', False),
 
            ('default_repo_type', 'hg')]:
 

	
 
            if skip_existing and RhodeCodeSetting.get_by_name(k) != None:
 
                log.debug('Skipping option %s' % k)
 
                continue
 
            setting = RhodeCodeSetting(k, v)
 
            self.sa.add(setting)
 

	
 
    def fixup_groups(self):
 
        def_usr = User.get_by_username('default')
 
        for g in RepoGroup.query().all():
 
            g.group_name = g.get_new_name(g.name)
 
            self.sa.add(g)
 
            # get default perm
 
            default = UserRepoGroupToPerm.query()\
 
                .filter(UserRepoGroupToPerm.group == g)\
 
                .filter(UserRepoGroupToPerm.user == def_usr)\
 
                .scalar()
 

	
 
            if default is None:
 
                log.debug('missing default permission for group %s adding' % g)
 
                ReposGroupModel()._create_default_perms(g)
 

	
 
    def reset_permissions(self, username):
 
        """
 
        Resets permissions to default state, usefull when old systems had
 
        bad permissions, we must clean them up
 

	
 
        :param username:
 
        :type username:
 
        """
 
        default_user = User.get_by_username(username)
 
        if not default_user:
 
            return
 

	
 
        u2p = UserToPerm.query()\
 
            .filter(UserToPerm.user == default_user).all()
 
        fixed = False
 
        if len(u2p) != len(User.DEFAULT_PERMISSIONS):
 
            for p in u2p:
 
                Session().delete(p)
 
            fixed = True
 
            self.populate_default_permissions()
 
        return fixed
 

	
 
    def config_prompt(self, test_repo_path='', retries=3):
 
        defaults = self.cli_args
 
        _path = defaults.get('repos_location')
 
        if retries == 3:
 
            log.info('Setting up repositories config')
 

	
 
        if _path is not None:
 
            path = _path
 
        elif not self.tests and not test_repo_path:
 
            path = raw_input(
 
                 'Enter a valid absolute path to store repositories. '
 
                 'All repositories in that path will be added automatically:'
 
            )
 
        else:
 
            path = test_repo_path
 
        path_ok = True
 

	
 
        # check proper dir
 
        if not os.path.isdir(path):
 
            path_ok = False
 
            log.error('Given path %s is not a valid directory' % path)
 

	
 
        elif not os.path.isabs(path):
 
            path_ok = False
 
            log.error('Given path %s is not an absolute path' % path)
 

	
 
        # check write access
 
        elif not os.access(path, os.W_OK) and path_ok:
 
            path_ok = False
 
            log.error('No write permission to given path %s' % path)
 

	
 
        if retries == 0:
 
            sys.exit('max retries reached')
 
        if path_ok is False:
 
            retries -= 1
 
            return self.config_prompt(test_repo_path, retries)
 

	
 
        real_path = os.path.normpath(os.path.realpath(path))
 

	
 
        if real_path != os.path.normpath(path):
 
            if not ask_ok(('Path looks like a symlink, Rhodecode will store '
 
                           'given path as %s ? [y/n]') % (real_path)):
 
                log.error('Canceled by user')
 
                sys.exit(-1)
 

	
 
        return real_path
 

	
 
    def create_settings(self, path):
 

	
 
        self.create_ui_settings()
 

	
 
        #HG UI OPTIONS
 
        web1 = RhodeCodeUi()
 
        web1.ui_section = 'web'
 
        web1.ui_key = 'push_ssl'
 
        web1.ui_value = 'false'
 

	
 
        web2 = RhodeCodeUi()
 
        web2.ui_section = 'web'
 
        web2.ui_key = 'allow_archive'
 
        web2.ui_value = 'gz zip bz2'
 

	
 
        web3 = RhodeCodeUi()
 
        web3.ui_section = 'web'
 
        web3.ui_key = 'allow_push'
 
        web3.ui_value = '*'
 

	
 
        web4 = RhodeCodeUi()
 
        web4.ui_section = 'web'
 
        web4.ui_key = 'baseurl'
 
        web4.ui_value = '/'
 

	
 
        paths = RhodeCodeUi()
 
        paths.ui_section = 'paths'
 
        paths.ui_key = '/'
 
        paths.ui_value = path
 

	
 
        phases = RhodeCodeUi()
 
        phases.ui_section = 'phases'
 
        phases.ui_key = 'publish'
 
        phases.ui_value = False
 

	
 
        sett1 = RhodeCodeSetting('realm', 'RhodeCode authentication')
 
        sett2 = RhodeCodeSetting('title', 'RhodeCode')
 
        sett3 = RhodeCodeSetting('ga_code', '')
 

	
 
        sett4 = RhodeCodeSetting('show_public_icon', True)
 
        sett5 = RhodeCodeSetting('show_private_icon', True)
 
        sett6 = RhodeCodeSetting('stylify_metatags', False)
 

	
 
        self.sa.add(web1)
 
        self.sa.add(web2)
 
        self.sa.add(web3)
 
        self.sa.add(web4)
 
        self.sa.add(paths)
 
        self.sa.add(sett1)
 
        self.sa.add(sett2)
 
        self.sa.add(sett3)
 
        self.sa.add(sett4)
 
        self.sa.add(sett5)
 
        self.sa.add(sett6)
 

	
 
        self.create_ldap_options()
 
        self.create_default_options()
 

	
 
        log.info('created ui config')
 

	
 
    def create_user(self, username, password, email='', admin=False):
 
        log.info('creating user %s' % username)
 
        UserModel().create_or_update(username, password, email,
 
                                     firstname='RhodeCode', lastname='Admin',
 
                                     active=True, admin=admin)
 

	
 
    def create_default_user(self):
 
        log.info('creating default user')
 
        # create default user for handling default permissions.
 
        UserModel().create_or_update(username='default',
 
                              password=str(uuid.uuid1())[:8],
 
                              email='anonymous@rhodecode.org',
 
                              firstname='Anonymous', lastname='User')
 

	
 
    def create_permissions(self):
 
        # module.(access|create|change|delete)_[name]
 
        # module.(none|read|write|admin)
 

	
 
        for p in Permission.PERMS:
 
            if not Permission.get_by_key(p[0]):
 
                new_perm = Permission()
 
                new_perm.permission_name = p[0]
 
                new_perm.permission_longname = p[0]
 
                self.sa.add(new_perm)
 

	
 
    def populate_default_permissions(self):
 
        log.info('creating default user permissions')
 

	
 
        default_user = User.get_by_username('default')
 

	
 
        for def_perm in User.DEFAULT_PERMISSIONS:
 

	
 
            perm = self.sa.query(Permission)\
 
             .filter(Permission.permission_name == def_perm)\
 
             .scalar()
 
            if not perm:
 
                raise Exception(
 
                  'CRITICAL: permission %s not found inside database !!'
 
                  % def_perm
 
                )
 
            if not UserToPerm.query()\
 
                .filter(UserToPerm.permission == perm)\
 
                .filter(UserToPerm.user == default_user).scalar():
 
                reg_perm = UserToPerm()
 
                reg_perm.user = default_user
 
                reg_perm.permission = perm
 
                self.sa.add(reg_perm)
 

	
 
    def finish(self):
 
        """
 
        Function executed at the end of setup
 
        """
 
        if not __py_version__ >= (2, 6):
 
            notify('Python2.5 detected, please switch '
 
                   'egg:waitress#main -> egg:Paste#http '
 
                   'in your .ini file')
rhodecode/lib/dbmigrate/versions/008_version_1_5_0.py
Show inline comments
 
import logging
 
import datetime
 

	
 
from sqlalchemy import *
 
from sqlalchemy.exc import DatabaseError
 
from sqlalchemy.orm import relation, backref, class_mapper
 
from sqlalchemy.orm.session import Session
 
from sqlalchemy.ext.declarative import declarative_base
 

	
 
from rhodecode.lib.dbmigrate.migrate import *
 
from rhodecode.lib.dbmigrate.migrate.changeset import *
 

	
 
from rhodecode.model.meta import Base
 
from rhodecode.model import meta
 

	
 
log = logging.getLogger(__name__)
 

	
 

	
 
def upgrade(migrate_engine):
 
    """
 
    Upgrade operations go here.
 
    Don't create your own engine; bind migrate_engine to your metadata
 
    """
 
    pass
 

	
 

	
 
def downgrade(migrate_engine):
 
    meta = MetaData()
 
    meta.bind = migrate_engine
rhodecode/lib/utils2.py
Show inline comments
 
# -*- coding: utf-8 -*-
 
"""
 
    rhodecode.lib.utils
 
    ~~~~~~~~~~~~~~~~~~~
 

	
 
    Some simple helper functions
 

	
 
    :created_on: Jan 5, 2011
 
    :author: marcink
 
    :copyright: (C) 2011-2012 Marcin Kuzminski <marcin@python-works.com>
 
    :license: GPLv3, see COPYING for more details.
 
"""
 
# This program is free software: you can redistribute it and/or modify
 
# it under the terms of the GNU General Public License as published by
 
# the Free Software Foundation, either version 3 of the License, or
 
# (at your option) any later version.
 
#
 
# This program is distributed in the hope that it will be useful,
 
# but WITHOUT ANY WARRANTY; without even the implied warranty of
 
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
# GNU General Public License for more details.
 
#
 
# You should have received a copy of the GNU General Public License
 
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
 

	
 
import re
 
import time
 
import datetime
 
import webob
 

	
 
from pylons.i18n.translation import _, ungettext
 
from rhodecode.lib.vcs.utils.lazy import LazyProperty
 

	
 

	
 
def __get_lem():
 
    """
 
    Get language extension map based on what's inside pygments lexers
 
    """
 
    from pygments import lexers
 
    from string import lower
 
    from collections import defaultdict
 

	
 
    d = defaultdict(lambda: [])
 

	
 
    def __clean(s):
 
        s = s.lstrip('*')
 
        s = s.lstrip('.')
 

	
 
        if s.find('[') != -1:
 
            exts = []
 
            start, stop = s.find('['), s.find(']')
 

	
 
            for suffix in s[start + 1:stop]:
 
                exts.append(s[:s.find('[')] + suffix)
 
            return map(lower, exts)
 
        else:
 
            return map(lower, [s])
 

	
 
    for lx, t in sorted(lexers.LEXERS.items()):
 
        m = map(__clean, t[-2])
 
        if m:
 
            m = reduce(lambda x, y: x + y, m)
 
            for ext in m:
 
                desc = lx.replace('Lexer', '')
 
                d[ext].append(desc)
 

	
 
    return dict(d)
 

	
 

	
 
def str2bool(_str):
 
    """
 
    returs True/False value from given string, it tries to translate the
 
    string into boolean
 

	
 
    :param _str: string value to translate into boolean
 
    :rtype: boolean
 
    :returns: boolean from given string
 
    """
 
    if _str is None:
 
        return False
 
    if _str in (True, False):
 
        return _str
 
    _str = str(_str).strip().lower()
 
    return _str in ('t', 'true', 'y', 'yes', 'on', '1')
 

	
 

	
 
def aslist(obj, sep=None, strip=True):
 
    """
 
    Returns given string separated by sep as list
 

	
 
    :param obj:
 
    :param sep:
 
    :param strip:
 
    """
 
    if isinstance(obj, (basestring)):
 
        lst = obj.split(sep)
 
        if strip:
 
            lst = [v.strip() for v in lst]
 
        return lst
 
    elif isinstance(obj, (list, tuple)):
 
        return obj
 
    elif obj is None:
 
        return []
 
    else:
 
        return [obj]
 

	
 

	
 
def convert_line_endings(line, mode):
 
    """
 
    Converts a given line  "line end" accordingly to given mode
 

	
 
    Available modes are::
 
        0 - Unix
 
        1 - Mac
 
        2 - DOS
 

	
 
    :param line: given line to convert
 
    :param mode: mode to convert to
 
    :rtype: str
 
    :return: converted line according to mode
 
    """
 
    from string import replace
 

	
 
    if mode == 0:
 
            line = replace(line, '\r\n', '\n')
 
            line = replace(line, '\r', '\n')
 
    elif mode == 1:
 
            line = replace(line, '\r\n', '\r')
 
            line = replace(line, '\n', '\r')
 
    elif mode == 2:
 
            line = re.sub("\r(?!\n)|(?<!\r)\n", "\r\n", line)
 
    return line
 

	
 

	
 
def detect_mode(line, default):
 
    """
 
    Detects line break for given line, if line break couldn't be found
 
    given default value is returned
 

	
 
    :param line: str line
 
    :param default: default
 
    :rtype: int
 
    :return: value of line end on of 0 - Unix, 1 - Mac, 2 - DOS
 
    """
 
    if line.endswith('\r\n'):
 
        return 2
 
    elif line.endswith('\n'):
 
        return 0
 
    elif line.endswith('\r'):
 
        return 1
 
    else:
 
        return default
 

	
 

	
 
def generate_api_key(username, salt=None):
 
    """
 
    Generates unique API key for given username, if salt is not given
 
    it'll be generated from some random string
 

	
 
    :param username: username as string
 
    :param salt: salt to hash generate KEY
 
    :rtype: str
 
    :returns: sha1 hash from username+salt
 
    """
 
    from tempfile import _RandomNameSequence
 
    import hashlib
 

	
 
    if salt is None:
 
        salt = _RandomNameSequence().next()
 

	
 
    return hashlib.sha1(username + salt).hexdigest()
 

	
 

	
 
def safe_int(val, default=None):
 
    """
 
    Returns int() of val if val is not convertable to int use default
 
    instead
 

	
 
    :param val:
 
    :param default:
 
    """
 

	
 
    try:
 
        val = int(val)
 
    except ValueError:
 
        val = default
 

	
 
    return val
 

	
 

	
 
def safe_unicode(str_, from_encoding=None):
 
    """
 
    safe unicode function. Does few trick to turn str_ into unicode
 

	
 
    In case of UnicodeDecode error we try to return it with encoding detected
 
    by chardet library if it fails fallback to unicode with errors replaced
 

	
 
    :param str_: string to decode
 
    :rtype: unicode
 
    :returns: unicode object
 
    """
 
    if isinstance(str_, unicode):
 
        return str_
 

	
 
    if not from_encoding:
 
        import rhodecode
 
        DEFAULT_ENCODINGS = aslist(rhodecode.CONFIG.get('default_encoding',
 
                                                        'utf8'), sep=',')
 
        from_encoding = DEFAULT_ENCODINGS
 

	
 
    if not isinstance(from_encoding, (list, tuple)):
 
        from_encoding = [from_encoding]
 

	
 
    try:
 
        return unicode(str_)
 
    except UnicodeDecodeError:
 
        pass
 

	
 
    for enc in from_encoding:
 
        try:
 
            return unicode(str_, enc)
 
        except UnicodeDecodeError:
 
            pass
 

	
 
    try:
 
        import chardet
 
        encoding = chardet.detect(str_)['encoding']
 
        if encoding is None:
 
            raise Exception()
 
        return str_.decode(encoding)
 
    except (ImportError, UnicodeDecodeError, Exception):
 
        return unicode(str_, from_encoding[0], 'replace')
 

	
 

	
 
def safe_str(unicode_, to_encoding=None):
 
    """
 
    safe str function. Does few trick to turn unicode_ into string
 

	
 
    In case of UnicodeEncodeError we try to return it with encoding detected
 
    by chardet library if it fails fallback to string with errors replaced
 

	
 
    :param unicode_: unicode to encode
 
    :rtype: str
 
    :returns: str object
 
    """
 

	
 
    # if it's not basestr cast to str
 
    if not isinstance(unicode_, basestring):
 
        return str(unicode_)
 

	
 
    if isinstance(unicode_, str):
 
        return unicode_
 

	
 
    if not to_encoding:
 
        import rhodecode
 
        DEFAULT_ENCODINGS = aslist(rhodecode.CONFIG.get('default_encoding',
 
                                                        'utf8'), sep=',')
 
        to_encoding = DEFAULT_ENCODINGS
 

	
 
    if not isinstance(to_encoding, (list, tuple)):
 
        to_encoding = [to_encoding]
 

	
 
    for enc in to_encoding:
 
        try:
 
            return unicode_.encode(enc)
 
        except UnicodeEncodeError:
 
            pass
 

	
 
    try:
 
        import chardet
 
        encoding = chardet.detect(unicode_)['encoding']
 
        if encoding is None:
 
            raise UnicodeEncodeError()
 

	
 
        return unicode_.encode(encoding)
 
    except (ImportError, UnicodeEncodeError):
 
        return unicode_.encode(to_encoding[0], 'replace')
 

	
 
    return safe_str
 

	
 

	
 
def remove_suffix(s, suffix):
 
    if s.endswith(suffix):
 
        s = s[:-1 * len(suffix)]
 
    return s
 

	
 

	
 
def remove_prefix(s, prefix):
 
    if s.startswith(prefix):
 
        s = s[:-1 * len(prefix)]
 
        s = s[len(prefix):]
 
    return s
 

	
 

	
 
def engine_from_config(configuration, prefix='sqlalchemy.', **kwargs):
 
    """
 
    Custom engine_from_config functions that makes sure we use NullPool for
 
    file based sqlite databases. This prevents errors on sqlite. This only
 
    applies to sqlalchemy versions < 0.7.0
 

	
 
    """
 
    import sqlalchemy
 
    from sqlalchemy import engine_from_config as efc
 
    import logging
 

	
 
    if int(sqlalchemy.__version__.split('.')[1]) < 7:
 

	
 
        # This solution should work for sqlalchemy < 0.7.0, and should use
 
        # proxy=TimerProxy() for execution time profiling
 

	
 
        from sqlalchemy.pool import NullPool
 
        url = configuration[prefix + 'url']
 

	
 
        if url.startswith('sqlite'):
 
            kwargs.update({'poolclass': NullPool})
 
        return efc(configuration, prefix, **kwargs)
 
    else:
 
        import time
 
        from sqlalchemy import event
 
        from sqlalchemy.engine import Engine
 

	
 
        log = logging.getLogger('sqlalchemy.engine')
 
        BLACK, RED, GREEN, YELLOW, BLUE, MAGENTA, CYAN, WHITE = xrange(30, 38)
 
        engine = efc(configuration, prefix, **kwargs)
 

	
 
        def color_sql(sql):
 
            COLOR_SEQ = "\033[1;%dm"
 
            COLOR_SQL = YELLOW
 
            normal = '\x1b[0m'
 
            return ''.join([COLOR_SEQ % COLOR_SQL, sql, normal])
 

	
 
        if configuration['debug']:
 
            #attach events only for debug configuration
 

	
 
            def before_cursor_execute(conn, cursor, statement,
 
                                    parameters, context, executemany):
 
                context._query_start_time = time.time()
 
                log.info(color_sql(">>>>> STARTING QUERY >>>>>"))
 

	
 
            def after_cursor_execute(conn, cursor, statement,
 
                                    parameters, context, executemany):
 
                total = time.time() - context._query_start_time
 
                log.info(color_sql("<<<<< TOTAL TIME: %f <<<<<" % total))
 

	
 
            event.listen(engine, "before_cursor_execute",
 
                         before_cursor_execute)
 
            event.listen(engine, "after_cursor_execute",
 
                         after_cursor_execute)
 

	
 
    return engine
 

	
 

	
 
def age(prevdate):
 
    """
 
    turns a datetime into an age string.
 

	
 
    :param prevdate: datetime object
 
    :rtype: unicode
 
    :returns: unicode words describing age
 
    """
 

	
 
    order = ['year', 'month', 'day', 'hour', 'minute', 'second']
 
    deltas = {}
 
    future = False
 

	
 
    # Get date parts deltas
 
    now = datetime.datetime.now()
 
    if prevdate > now:
 
        now, prevdate = prevdate, now
 
        future = True
 

	
 
    for part in order:
 
        deltas[part] = getattr(now, part) - getattr(prevdate, part)
 

	
 
    # Fix negative offsets (there is 1 second between 10:59:59 and 11:00:00,
 
    # not 1 hour, -59 minutes and -59 seconds)
 

	
 
    for num, length in [(5, 60), (4, 60), (3, 24)]:  # seconds, minutes, hours
 
        part = order[num]
 
        carry_part = order[num - 1]
 

	
 
        if deltas[part] < 0:
 
            deltas[part] += length
 
            deltas[carry_part] -= 1
 

	
 
    # Same thing for days except that the increment depends on the (variable)
 
    # number of days in the month
 
    month_lengths = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
 
    if deltas['day'] < 0:
 
        if prevdate.month == 2 and (prevdate.year % 4 == 0 and
 
            (prevdate.year % 100 != 0 or prevdate.year % 400 == 0)):
 
            deltas['day'] += 29
 
        else:
 
            deltas['day'] += month_lengths[prevdate.month - 1]
 

	
 
        deltas['month'] -= 1
 

	
 
    if deltas['month'] < 0:
 
        deltas['month'] += 12
 
        deltas['year'] -= 1
 

	
 
    # Format the result
 
    fmt_funcs = {
 
        'year': lambda d: ungettext(u'%d year', '%d years', d) % d,
 
        'month': lambda d: ungettext(u'%d month', '%d months', d) % d,
 
        'day': lambda d: ungettext(u'%d day', '%d days', d) % d,
 
        'hour': lambda d: ungettext(u'%d hour', '%d hours', d) % d,
 
        'minute': lambda d: ungettext(u'%d minute', '%d minutes', d) % d,
 
        'second': lambda d: ungettext(u'%d second', '%d seconds', d) % d,
 
    }
 

	
 
    for i, part in enumerate(order):
 
        value = deltas[part]
 
        if value == 0:
 
            continue
 

	
 
        if i < 5:
 
            sub_part = order[i + 1]
 
            sub_value = deltas[sub_part]
 
        else:
 
            sub_value = 0
 

	
 
        if sub_value == 0:
 
            if future:
 
                return _(u'in %s') % fmt_funcs[part](value)
 
            else:
 
                return _(u'%s ago') % fmt_funcs[part](value)
 
        if future:
 
            return _(u'in %s and %s') % (fmt_funcs[part](value),
 
                fmt_funcs[sub_part](sub_value))
 
        else:
 
            return _(u'%s and %s ago') % (fmt_funcs[part](value),
 
                fmt_funcs[sub_part](sub_value))
 

	
 
    return _(u'just now')
 

	
 

	
 
def uri_filter(uri):
 
    """
 
    Removes user:password from given url string
 

	
 
    :param uri:
 
    :rtype: unicode
 
    :returns: filtered list of strings
 
    """
 
    if not uri:
 
        return ''
 

	
 
    proto = ''
 

	
 
    for pat in ('https://', 'http://'):
 
        if uri.startswith(pat):
 
            uri = uri[len(pat):]
 
            proto = pat
 
            break
 

	
 
    # remove passwords and username
 
    uri = uri[uri.find('@') + 1:]
 

	
 
    # get the port
 
    cred_pos = uri.find(':')
 
    if cred_pos == -1:
 
        host, port = uri, None
 
    else:
 
        host, port = uri[:cred_pos], uri[cred_pos + 1:]
 

	
 
    return filter(None, [proto, host, port])
 

	
 

	
 
def credentials_filter(uri):
 
    """
 
    Returns a url with removed credentials
 

	
 
    :param uri:
 
    """
 

	
 
    uri = uri_filter(uri)
 
    #check if we have port
 
    if len(uri) > 2 and uri[2]:
 
        uri[2] = ':' + uri[2]
 

	
 
    return ''.join(uri)
 

	
 

	
 
def get_changeset_safe(repo, rev):
 
    """
 
    Safe version of get_changeset if this changeset doesn't exists for a
 
    repo it returns a Dummy one instead
 

	
 
    :param repo:
 
    :param rev:
 
    """
 
    from rhodecode.lib.vcs.backends.base import BaseRepository
 
    from rhodecode.lib.vcs.exceptions import RepositoryError
 
    from rhodecode.lib.vcs.backends.base import EmptyChangeset
 
    if not isinstance(repo, BaseRepository):
 
        raise Exception('You must pass an Repository '
 
                        'object as first argument got %s', type(repo))
 

	
 
    try:
 
        cs = repo.get_changeset(rev)
 
    except RepositoryError:
 
        cs = EmptyChangeset(requested_revision=rev)
 
    return cs
 

	
 

	
 
def datetime_to_time(dt):
 
    if dt:
 
        return time.mktime(dt.timetuple())
 

	
 

	
 
def time_to_datetime(tm):
 
    if tm:
 
        if isinstance(tm, basestring):
 
            try:
 
                tm = float(tm)
 
            except ValueError:
 
                return
 
        return datetime.datetime.fromtimestamp(tm)
 

	
 
MENTIONS_REGEX = r'(?:^@|\s@)([a-zA-Z0-9]{1}[a-zA-Z0-9\-\_\.]+)(?:\s{1})'
 

	
 

	
 
def extract_mentioned_users(s):
 
    """
 
    Returns unique usernames from given string s that have @mention
 

	
 
    :param s: string to get mentions
 
    """
 
    usrs = set()
 
    for username in re.findall(MENTIONS_REGEX, s):
 
        usrs.add(username)
 

	
 
    return sorted(list(usrs), key=lambda k: k.lower())
 

	
 

	
 
class AttributeDict(dict):
 
    def __getattr__(self, attr):
 
        return self.get(attr, None)
 
    __setattr__ = dict.__setitem__
 
    __delattr__ = dict.__delitem__
 

	
 

	
 
def fix_PATH(os_=None):
 
    """
 
    Get current active python path, and append it to PATH variable to fix issues
 
    of subprocess calls and different python versions
 
    """
 
    import sys
 
    if os_ is None:
 
        import os
 
    else:
 
        os = os_
 

	
 
    cur_path = os.path.split(sys.executable)[0]
 
    if not os.environ['PATH'].startswith(cur_path):
 
        os.environ['PATH'] = '%s:%s' % (cur_path, os.environ['PATH'])
 

	
 

	
 
def obfuscate_url_pw(engine):
 
    from sqlalchemy.engine import url
 
    url = url.make_url(engine)
 
    if url.password:
 
        url.password = 'XXXXX'
 
    return str(url)
 

	
 

	
 
def get_server_url(environ):
 
    req = webob.Request(environ)
 
    return req.host_url + req.script_name
rhodecode/model/db.py
Show inline comments
 
# -*- coding: utf-8 -*-
 
"""
 
    rhodecode.model.db
 
    ~~~~~~~~~~~~~~~~~~
 

	
 
    Database Models for RhodeCode
 

	
 
    :created_on: Apr 08, 2010
 
    :author: marcink
 
    :copyright: (C) 2010-2012 Marcin Kuzminski <marcin@python-works.com>
 
    :license: GPLv3, see COPYING for more details.
 
"""
 
# This program is free software: you can redistribute it and/or modify
 
# it under the terms of the GNU General Public License as published by
 
# the Free Software Foundation, either version 3 of the License, or
 
# (at your option) any later version.
 
#
 
# This program is distributed in the hope that it will be useful,
 
# but WITHOUT ANY WARRANTY; without even the implied warranty of
 
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
# GNU General Public License for more details.
 
#
 
# You should have received a copy of the GNU General Public License
 
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
 

	
 
import os
 
import logging
 
import datetime
 
import traceback
 
import hashlib
 
import time
 
from collections import defaultdict
 

	
 
from sqlalchemy import *
 
from sqlalchemy.ext.hybrid import hybrid_property
 
from sqlalchemy.orm import relationship, joinedload, class_mapper, validates
 
from sqlalchemy.exc import DatabaseError
 
from beaker.cache import cache_region, region_invalidate
 
from webob.exc import HTTPNotFound
 

	
 
from pylons.i18n.translation import lazy_ugettext as _
 

	
 
from rhodecode.lib.vcs import get_backend
 
from rhodecode.lib.vcs.utils.helpers import get_scm
 
from rhodecode.lib.vcs.exceptions import VCSError
 
from rhodecode.lib.vcs.utils.lazy import LazyProperty
 

	
 
from rhodecode.lib.utils2 import str2bool, safe_str, get_changeset_safe, \
 
    safe_unicode, remove_suffix
 
    safe_unicode, remove_suffix, remove_prefix
 
from rhodecode.lib.compat import json
 
from rhodecode.lib.caching_query import FromCache
 

	
 
from rhodecode.model.meta import Base, Session
 

	
 
URL_SEP = '/'
 
log = logging.getLogger(__name__)
 

	
 
#==============================================================================
 
# BASE CLASSES
 
#==============================================================================
 

	
 
_hash_key = lambda k: hashlib.md5(safe_str(k)).hexdigest()
 

	
 

	
 
class BaseModel(object):
 
    """
 
    Base Model for all classess
 
    """
 

	
 
    @classmethod
 
    def _get_keys(cls):
 
        """return column names for this model """
 
        return class_mapper(cls).c.keys()
 

	
 
    def get_dict(self):
 
        """
 
        return dict with keys and values corresponding
 
        to this model data """
 

	
 
        d = {}
 
        for k in self._get_keys():
 
            d[k] = getattr(self, k)
 

	
 
        # also use __json__() if present to get additional fields
 
        _json_attr = getattr(self, '__json__', None)
 
        if _json_attr:
 
            # update with attributes from __json__
 
            if callable(_json_attr):
 
                _json_attr = _json_attr()
 
            for k, val in _json_attr.iteritems():
 
                d[k] = val
 
        return d
 

	
 
    def get_appstruct(self):
 
        """return list with keys and values tupples corresponding
 
        to this model data """
 

	
 
        l = []
 
        for k in self._get_keys():
 
            l.append((k, getattr(self, k),))
 
        return l
 

	
 
    def populate_obj(self, populate_dict):
 
        """populate model with data from given populate_dict"""
 

	
 
        for k in self._get_keys():
 
            if k in populate_dict:
 
                setattr(self, k, populate_dict[k])
 

	
 
    @classmethod
 
    def query(cls):
 
        return Session().query(cls)
 

	
 
    @classmethod
 
    def get(cls, id_):
 
        if id_:
 
            return cls.query().get(id_)
 

	
 
    @classmethod
 
    def get_or_404(cls, id_):
 
        try:
 
            id_ = int(id_)
 
        except (TypeError, ValueError):
 
            raise HTTPNotFound
 

	
 
        res = cls.query().get(id_)
 
        if not res:
 
            raise HTTPNotFound
 
        return res
 

	
 
    @classmethod
 
    def getAll(cls):
 
        return cls.query().all()
 

	
 
    @classmethod
 
    def delete(cls, id_):
 
        obj = cls.query().get(id_)
 
        Session().delete(obj)
 

	
 
    def __repr__(self):
 
        if hasattr(self, '__unicode__'):
 
            # python repr needs to return str
 
            return safe_str(self.__unicode__())
 
        return '<DB:%s>' % (self.__class__.__name__)
 

	
 

	
 
class RhodeCodeSetting(Base, BaseModel):
 
    __tablename__ = 'rhodecode_settings'
 
    __table_args__ = (
 
        UniqueConstraint('app_settings_name'),
 
        {'extend_existing': True, 'mysql_engine': 'InnoDB',
 
         'mysql_charset': 'utf8'}
 
    )
 
    app_settings_id = Column("app_settings_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
 
    app_settings_name = Column("app_settings_name", String(255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
 
    _app_settings_value = Column("app_settings_value", String(255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
 

	
 
    def __init__(self, k='', v=''):
 
        self.app_settings_name = k
 
        self.app_settings_value = v
 

	
 
    @validates('_app_settings_value')
 
    def validate_settings_value(self, key, val):
 
        assert type(val) == unicode
 
        return val
 

	
 
    @hybrid_property
 
    def app_settings_value(self):
 
        v = self._app_settings_value
 
        if self.app_settings_name == 'ldap_active':
 
        if self.app_settings_name in ["ldap_active",
 
                                      "default_repo_enable_statistics",
 
                                      "default_repo_enable_locking",
 
                                      "default_repo_private",
 
                                      "default_repo_enable_downloads"]:
 
            v = str2bool(v)
 
        return v
 

	
 
    @app_settings_value.setter
 
    def app_settings_value(self, val):
 
        """
 
        Setter that will always make sure we use unicode in app_settings_value
 

	
 
        :param val:
 
        """
 
        self._app_settings_value = safe_unicode(val)
 

	
 
    def __unicode__(self):
 
        return u"<%s('%s:%s')>" % (
 
            self.__class__.__name__,
 
            self.app_settings_name, self.app_settings_value
 
        )
 

	
 
    @classmethod
 
    def get_by_name(cls, key):
 
        return cls.query()\
 
            .filter(cls.app_settings_name == key).scalar()
 

	
 
    @classmethod
 
    def get_by_name_or_create(cls, key):
 
        res = cls.get_by_name(key)
 
        if not res:
 
            res = cls(key)
 
        return res
 

	
 
    @classmethod
 
    def get_app_settings(cls, cache=False):
 

	
 
        ret = cls.query()
 

	
 
        if cache:
 
            ret = ret.options(FromCache("sql_cache_short", "get_hg_settings"))
 

	
 
        if not ret:
 
            raise Exception('Could not get application settings !')
 
        settings = {}
 
        for each in ret:
 
            settings['rhodecode_' + each.app_settings_name] = \
 
                each.app_settings_value
 

	
 
        return settings
 

	
 
    @classmethod
 
    def get_ldap_settings(cls, cache=False):
 
        ret = cls.query()\
 
                .filter(cls.app_settings_name.startswith('ldap_')).all()
 
        fd = {}
 
        for row in ret:
 
            fd.update({row.app_settings_name: row.app_settings_value})
 

	
 
        return fd
 

	
 
    @classmethod
 
    def get_default_repo_settings(cls, cache=False, strip_prefix=False):
 
        ret = cls.query()\
 
                .filter(cls.app_settings_name.startswith('default_')).all()
 
        fd = {}
 
        for row in ret:
 
            key = row.app_settings_name
 
            if strip_prefix:
 
                key = remove_prefix(key, prefix='default_')
 
            fd.update({key: row.app_settings_value})
 

	
 
        return fd
 

	
 

	
 
class RhodeCodeUi(Base, BaseModel):
 
    __tablename__ = 'rhodecode_ui'
 
    __table_args__ = (
 
        UniqueConstraint('ui_key'),
 
        {'extend_existing': True, 'mysql_engine': 'InnoDB',
 
         'mysql_charset': 'utf8'}
 
    )
 

	
 
    HOOK_UPDATE = 'changegroup.update'
 
    HOOK_REPO_SIZE = 'changegroup.repo_size'
 
    HOOK_PUSH = 'changegroup.push_logger'
 
    HOOK_PRE_PUSH = 'prechangegroup.pre_push'
 
    HOOK_PULL = 'outgoing.pull_logger'
 
    HOOK_PRE_PULL = 'preoutgoing.pre_pull'
 

	
 
    ui_id = Column("ui_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
 
    ui_section = Column("ui_section", String(255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
 
    ui_key = Column("ui_key", String(255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
 
    ui_value = Column("ui_value", String(255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
 
    ui_active = Column("ui_active", Boolean(), nullable=True, unique=None, default=True)
 

	
 
    @classmethod
 
    def get_by_key(cls, key):
 
        return cls.query().filter(cls.ui_key == key).scalar()
 

	
 
    @classmethod
 
    def get_builtin_hooks(cls):
 
        q = cls.query()
 
        q = q.filter(cls.ui_key.in_([cls.HOOK_UPDATE, cls.HOOK_REPO_SIZE,
 
                                     cls.HOOK_PUSH, cls.HOOK_PRE_PUSH,
 
                                     cls.HOOK_PULL, cls.HOOK_PRE_PULL]))
 
        return q.all()
 

	
 
    @classmethod
 
    def get_custom_hooks(cls):
 
        q = cls.query()
 
        q = q.filter(~cls.ui_key.in_([cls.HOOK_UPDATE, cls.HOOK_REPO_SIZE,
 
                                      cls.HOOK_PUSH, cls.HOOK_PRE_PUSH,
 
                                      cls.HOOK_PULL, cls.HOOK_PRE_PULL]))
 
        q = q.filter(cls.ui_section == 'hooks')
 
        return q.all()
 

	
 
    @classmethod
 
    def get_repos_location(cls):
 
        return cls.get_by_key('/').ui_value
 

	
 
    @classmethod
 
    def create_or_update_hook(cls, key, val):
 
        new_ui = cls.get_by_key(key) or cls()
 
        new_ui.ui_section = 'hooks'
 
        new_ui.ui_active = True
 
        new_ui.ui_key = key
 
        new_ui.ui_value = val
 

	
 
        Session().add(new_ui)
 

	
 
    def __repr__(self):
 
        return '<DB:%s[%s:%s]>' % (self.__class__.__name__, self.ui_key,
 
                                   self.ui_value)
 

	
 

	
 
class User(Base, BaseModel):
 
    __tablename__ = 'users'
 
    __table_args__ = (
 
        UniqueConstraint('username'), UniqueConstraint('email'),
 
        Index('u_username_idx', 'username'),
 
        Index('u_email_idx', 'email'),
 
        {'extend_existing': True, 'mysql_engine': 'InnoDB',
 
         'mysql_charset': 'utf8'}
 
    )
 
    DEFAULT_USER = 'default'
 
    DEFAULT_PERMISSIONS = [
 
        'hg.register.manual_activate', 'hg.create.repository',
 
        'hg.fork.repository', 'repository.read', 'group.read'
 
    ]
 
    user_id = Column("user_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
 
    username = Column("username", String(255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
 
    password = Column("password", String(255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
 
    active = Column("active", Boolean(), nullable=True, unique=None, default=True)
 
    admin = Column("admin", Boolean(), nullable=True, unique=None, default=False)
 
    name = Column("firstname", String(255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
 
    lastname = Column("lastname", String(255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
 
    _email = Column("email", String(255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
 
    last_login = Column("last_login", DateTime(timezone=False), nullable=True, unique=None, default=None)
 
    ldap_dn = Column("ldap_dn", String(255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
 
    api_key = Column("api_key", String(255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
 
    inherit_default_permissions = Column("inherit_default_permissions", Boolean(), nullable=False, unique=None, default=True)
 

	
 
    user_log = relationship('UserLog', cascade='all')
 
    user_perms = relationship('UserToPerm', primaryjoin="User.user_id==UserToPerm.user_id", cascade='all')
 

	
 
    repositories = relationship('Repository')
 
    user_followers = relationship('UserFollowing', primaryjoin='UserFollowing.follows_user_id==User.user_id', cascade='all')
 
    repo_to_perm = relationship('UserRepoToPerm', primaryjoin='UserRepoToPerm.user_id==User.user_id', cascade='all')
 
    repo_group_to_perm = relationship('UserRepoGroupToPerm', primaryjoin='UserRepoGroupToPerm.user_id==User.user_id', cascade='all')
 

	
 
    group_member = relationship('UsersGroupMember', cascade='all')
 

	
 
    notifications = relationship('UserNotification', cascade='all')
 
    # notifications assigned to this user
 
    user_created_notifications = relationship('Notification', cascade='all')
 
    # comments created by this user
 
    user_comments = relationship('ChangesetComment', cascade='all')
 
    #extra emails for this user
 
    user_emails = relationship('UserEmailMap', cascade='all')
 

	
 
    @hybrid_property
 
    def email(self):
 
        return self._email
 

	
 
    @email.setter
 
    def email(self, val):
 
        self._email = val.lower() if val else None
 

	
 
    @property
 
    def firstname(self):
 
        # alias for future
 
        return self.name
 

	
 
    @property
 
    def emails(self):
 
        other = UserEmailMap.query().filter(UserEmailMap.user==self).all()
 
        return [self.email] + [x.email for x in other]
 

	
 
    @property
 
    def username_and_name(self):
 
        return '%s (%s %s)' % (self.username, self.firstname, self.lastname)
 

	
 
    @property
 
    def full_name(self):
 
        return '%s %s' % (self.firstname, self.lastname)
 

	
 
    @property
 
    def full_name_or_username(self):
 
        return ('%s %s' % (self.firstname, self.lastname)
 
                if (self.firstname and self.lastname) else self.username)
 

	
 
    @property
 
    def full_contact(self):
 
        return '%s %s <%s>' % (self.firstname, self.lastname, self.email)
 

	
 
    @property
 
    def short_contact(self):
 
        return '%s %s' % (self.firstname, self.lastname)
 

	
 
    @property
 
    def is_admin(self):
 
        return self.admin
 

	
 
    def __unicode__(self):
 
        return u"<%s('id:%s:%s')>" % (self.__class__.__name__,
 
                                     self.user_id, self.username)
 

	
 
    @classmethod
 
    def get_by_username(cls, username, case_insensitive=False, cache=False):
 
        if case_insensitive:
 
            q = cls.query().filter(cls.username.ilike(username))
 
        else:
 
            q = cls.query().filter(cls.username == username)
 

	
 
        if cache:
 
            q = q.options(FromCache(
 
                            "sql_cache_short",
 
                            "get_user_%s" % _hash_key(username)
 
                          )
 
            )
 
        return q.scalar()
 

	
 
    @classmethod
 
    def get_by_api_key(cls, api_key, cache=False):
 
        q = cls.query().filter(cls.api_key == api_key)
 

	
 
        if cache:
 
            q = q.options(FromCache("sql_cache_short",
 
                                    "get_api_key_%s" % api_key))
 
        return q.scalar()
 

	
 
    @classmethod
 
    def get_by_email(cls, email, case_insensitive=False, cache=False):
 
        if case_insensitive:
 
            q = cls.query().filter(cls.email.ilike(email))
 
        else:
 
            q = cls.query().filter(cls.email == email)
 

	
 
        if cache:
 
            q = q.options(FromCache("sql_cache_short",
 
                                    "get_email_key_%s" % email))
 

	
 
        ret = q.scalar()
 
        if ret is None:
 
            q = UserEmailMap.query()
 
            # try fetching in alternate email map
 
            if case_insensitive:
 
                q = q.filter(UserEmailMap.email.ilike(email))
 
            else:
 
                q = q.filter(UserEmailMap.email == email)
 
            q = q.options(joinedload(UserEmailMap.user))
 
            if cache:
 
                q = q.options(FromCache("sql_cache_short",
 
                                        "get_email_map_key_%s" % email))
 
            ret = getattr(q.scalar(), 'user', None)
 

	
 
        return ret
 

	
 
    def update_lastlogin(self):
 
        """Update user lastlogin"""
 
        self.last_login = datetime.datetime.now()
 
        Session().add(self)
 
        log.debug('updated user %s lastlogin' % self.username)
 

	
 
    def get_api_data(self):
 
        """
 
        Common function for generating user related data for API
 
        """
 
        user = self
 
        data = dict(
 
            user_id=user.user_id,
 
            username=user.username,
 
            firstname=user.name,
 
            lastname=user.lastname,
 
            email=user.email,
 
            emails=user.emails,
 
            api_key=user.api_key,
 
            active=user.active,
 
            admin=user.admin,
 
            ldap_dn=user.ldap_dn,
 
            last_login=user.last_login,
 
        )
 
        return data
 

	
 
    def __json__(self):
 
        data = dict(
 
            full_name=self.full_name,
 
            full_name_or_username=self.full_name_or_username,
 
            short_contact=self.short_contact,
 
            full_contact=self.full_contact
 
        )
 
        data.update(self.get_api_data())
 
        return data
 

	
 

	
 
class UserEmailMap(Base, BaseModel):
 
    __tablename__ = 'user_email_map'
 
    __table_args__ = (
 
        Index('uem_email_idx', 'email'),
 
        UniqueConstraint('email'),
 
        {'extend_existing': True, 'mysql_engine': 'InnoDB',
 
         'mysql_charset': 'utf8'}
 
    )
 
    __mapper_args__ = {}
 

	
 
    email_id = Column("email_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
 
    user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=True, unique=None, default=None)
 
    _email = Column("email", String(255, convert_unicode=False, assert_unicode=None), nullable=True, unique=False, default=None)
 
    user = relationship('User', lazy='joined')
 

	
 
    @validates('_email')
 
    def validate_email(self, key, email):
 
        # check if this email is not main one
 
        main_email = Session().query(User).filter(User.email == email).scalar()
 
        if main_email is not None:
 
            raise AttributeError('email %s is present is user table' % email)
 
        return email
 

	
 
    @hybrid_property
 
    def email(self):
 
        return self._email
 

	
 
    @email.setter
 
    def email(self, val):
 
        self._email = val.lower() if val else None
 

	
 

	
 
class UserLog(Base, BaseModel):
 
    __tablename__ = 'user_logs'
 
    __table_args__ = (
 
        {'extend_existing': True, 'mysql_engine': 'InnoDB',
 
         'mysql_charset': 'utf8'},
 
    )
 
    user_log_id = Column("user_log_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
 
    user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
 
    repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=True)
 
    repository_name = Column("repository_name", String(255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
 
    user_ip = Column("user_ip", String(255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
 
    action = Column("action", UnicodeText(1200000, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
 
    action_date = Column("action_date", DateTime(timezone=False), nullable=True, unique=None, default=None)
 

	
 
    @property
 
    def action_as_day(self):
 
        return datetime.date(*self.action_date.timetuple()[:3])
 

	
 
    user = relationship('User')
 
    repository = relationship('Repository', cascade='')
 

	
 

	
 
class UsersGroup(Base, BaseModel):
 
    __tablename__ = 'users_groups'
 
    __table_args__ = (
 
        {'extend_existing': True, 'mysql_engine': 'InnoDB',
 
         'mysql_charset': 'utf8'},
 
    )
 

	
 
    users_group_id = Column("users_group_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
 
    users_group_name = Column("users_group_name", String(255, convert_unicode=False, assert_unicode=None), nullable=False, unique=True, default=None)
 
    users_group_active = Column("users_group_active", Boolean(), nullable=True, unique=None, default=None)
 
    inherit_default_permissions = Column("users_group_inherit_default_permissions", Boolean(), nullable=False, unique=None, default=True)
 

	
 
    members = relationship('UsersGroupMember', cascade="all, delete, delete-orphan", lazy="joined")
 
    users_group_to_perm = relationship('UsersGroupToPerm', cascade='all')
 
    users_group_repo_to_perm = relationship('UsersGroupRepoToPerm', cascade='all')
 

	
 
    def __unicode__(self):
 
        return u'<userGroup(%s)>' % (self.users_group_name)
 

	
 
    @classmethod
 
    def get_by_group_name(cls, group_name, cache=False,
 
                          case_insensitive=False):
 
        if case_insensitive:
 
            q = cls.query().filter(cls.users_group_name.ilike(group_name))
 
        else:
 
            q = cls.query().filter(cls.users_group_name == group_name)
 
        if cache:
 
            q = q.options(FromCache(
 
                            "sql_cache_short",
 
                            "get_user_%s" % _hash_key(group_name)
 
                          )
 
            )
 
        return q.scalar()
 

	
 
    @classmethod
 
    def get(cls, users_group_id, cache=False):
 
        users_group = cls.query()
 
        if cache:
 
            users_group = users_group.options(FromCache("sql_cache_short",
 
                                    "get_users_group_%s" % users_group_id))
 
        return users_group.get(users_group_id)
 

	
 
    def get_api_data(self):
 
        users_group = self
 

	
 
        data = dict(
 
            users_group_id=users_group.users_group_id,
 
            group_name=users_group.users_group_name,
 
            active=users_group.users_group_active,
 
        )
 

	
 
        return data
 

	
 

	
 
class UsersGroupMember(Base, BaseModel):
 
    __tablename__ = 'users_groups_members'
 
    __table_args__ = (
 
        {'extend_existing': True, 'mysql_engine': 'InnoDB',
 
         'mysql_charset': 'utf8'},
 
    )
 

	
 
    users_group_member_id = Column("users_group_member_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
 
    users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None)
 
    user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
 

	
 
    user = relationship('User', lazy='joined')
 
    users_group = relationship('UsersGroup')
 

	
 
    def __init__(self, gr_id='', u_id=''):
 
        self.users_group_id = gr_id
 
        self.user_id = u_id
 

	
 

	
 
class Repository(Base, BaseModel):
 
    __tablename__ = 'repositories'
 
    __table_args__ = (
 
        UniqueConstraint('repo_name'),
 
        Index('r_repo_name_idx', 'repo_name'),
 
        {'extend_existing': True, 'mysql_engine': 'InnoDB',
 
         'mysql_charset': 'utf8'},
 
    )
 

	
 
    repo_id = Column("repo_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
 
    repo_name = Column("repo_name", String(255, convert_unicode=False, assert_unicode=None), nullable=False, unique=True, default=None)
 
    clone_uri = Column("clone_uri", String(255, convert_unicode=False, assert_unicode=None), nullable=True, unique=False, default=None)
 
    repo_type = Column("repo_type", String(255, convert_unicode=False, assert_unicode=None), nullable=False, unique=False, default=None)
 
    user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=False, default=None)
 
    private = Column("private", Boolean(), nullable=True, unique=None, default=None)
rhodecode/model/forms.py
Show inline comments
 
""" this is forms validation classes
 
http://formencode.org/module-formencode.validators.html
 
for list off all availible validators
 

	
 
we can create our own validators
 

	
 
The table below outlines the options which can be used in a schema in addition to the validators themselves
 
pre_validators          []     These validators will be applied before the schema
 
chained_validators      []     These validators will be applied after the schema
 
allow_extra_fields      False     If True, then it is not an error when keys that aren't associated with a validator are present
 
filter_extra_fields     False     If True, then keys that aren't associated with a validator are removed
 
if_key_missing          NoDefault If this is given, then any keys that aren't available but are expected will be replaced with this value (and then validated). This does not override a present .if_missing attribute on validators. NoDefault is a special FormEncode class to mean that no default values has been specified and therefore missing keys shouldn't take a default value.
 
ignore_key_missing      False     If True, then missing keys will be missing in the result, if the validator doesn't have .if_missing on it already
 

	
 

	
 
<name> = formencode.validators.<name of validator>
 
<name> must equal form name
 
list=[1,2,3,4,5]
 
for SELECT use formencode.All(OneOf(list), Int())
 

	
 
"""
 
import logging
 

	
 
import formencode
 
from formencode import All
 

	
 
from pylons.i18n.translation import _
 

	
 
from rhodecode.model import validators as v
 
from rhodecode import BACKENDS
 

	
 
log = logging.getLogger(__name__)
 

	
 

	
 
class LoginForm(formencode.Schema):
 
    allow_extra_fields = True
 
    filter_extra_fields = True
 
    username = v.UnicodeString(
 
        strip=True,
 
        min=1,
 
        not_empty=True,
 
        messages={
 
           'empty': _(u'Please enter a login'),
 
           'tooShort': _(u'Enter a value %(min)i characters long or more')}
 
    )
 

	
 
    password = v.UnicodeString(
 
        strip=False,
 
        min=3,
 
        not_empty=True,
 
        messages={
 
            'empty': _(u'Please enter a password'),
 
            'tooShort': _(u'Enter %(min)i characters or more')}
 
    )
 

	
 
    remember = v.StringBoolean(if_missing=False)
 

	
 
    chained_validators = [v.ValidAuth()]
 

	
 

	
 
def UserForm(edit=False, old_data={}):
 
    class _UserForm(formencode.Schema):
 
        allow_extra_fields = True
 
        filter_extra_fields = True
 
        username = All(v.UnicodeString(strip=True, min=1, not_empty=True),
 
                       v.ValidUsername(edit, old_data))
 
        if edit:
 
            new_password = All(
 
                v.ValidPassword(),
 
                v.UnicodeString(strip=False, min=6, not_empty=False)
 
            )
 
            password_confirmation = All(
 
                v.ValidPassword(),
 
                v.UnicodeString(strip=False, min=6, not_empty=False),
 
            )
 
            admin = v.StringBoolean(if_missing=False)
 
        else:
 
            password = All(
 
                v.ValidPassword(),
 
                v.UnicodeString(strip=False, min=6, not_empty=True)
 
            )
 
            password_confirmation = All(
 
                v.ValidPassword(),
 
                v.UnicodeString(strip=False, min=6, not_empty=False)
 
            )
 

	
 
        active = v.StringBoolean(if_missing=False)
 
        firstname = v.UnicodeString(strip=True, min=1, not_empty=False)
 
        lastname = v.UnicodeString(strip=True, min=1, not_empty=False)
 
        email = All(v.Email(not_empty=True), v.UniqSystemEmail(old_data))
 

	
 
        chained_validators = [v.ValidPasswordsMatch()]
 

	
 
    return _UserForm
 

	
 

	
 
def UsersGroupForm(edit=False, old_data={}, available_members=[]):
 
    class _UsersGroupForm(formencode.Schema):
 
        allow_extra_fields = True
 
        filter_extra_fields = True
 

	
 
        users_group_name = All(
 
            v.UnicodeString(strip=True, min=1, not_empty=True),
 
            v.ValidUsersGroup(edit, old_data)
 
        )
 

	
 
        users_group_active = v.StringBoolean(if_missing=False)
 

	
 
        if edit:
 
            users_group_members = v.OneOf(
 
                available_members, hideList=False, testValueList=True,
 
                if_missing=None, not_empty=False
 
            )
 

	
 
    return _UsersGroupForm
 

	
 

	
 
def ReposGroupForm(edit=False, old_data={}, available_groups=[]):
 
    class _ReposGroupForm(formencode.Schema):
 
        allow_extra_fields = True
 
        filter_extra_fields = False
 

	
 
        group_name = All(v.UnicodeString(strip=True, min=1, not_empty=True),
 
                               v.SlugifyName())
 
        group_description = v.UnicodeString(strip=True, min=1,
 
                                                not_empty=True)
 
        group_parent_id = v.OneOf(available_groups, hideList=False,
 
                                        testValueList=True,
 
                                        if_missing=None, not_empty=False)
 
        enable_locking = v.StringBoolean(if_missing=False)
 
        recursive = v.StringBoolean(if_missing=False)
 
        chained_validators = [v.ValidReposGroup(edit, old_data),
 
                              v.ValidPerms('group')]
 

	
 
    return _ReposGroupForm
 

	
 

	
 
def RegisterForm(edit=False, old_data={}):
 
    class _RegisterForm(formencode.Schema):
 
        allow_extra_fields = True
 
        filter_extra_fields = True
 
        username = All(
 
            v.ValidUsername(edit, old_data),
 
            v.UnicodeString(strip=True, min=1, not_empty=True)
 
        )
 
        password = All(
 
            v.ValidPassword(),
 
            v.UnicodeString(strip=False, min=6, not_empty=True)
 
        )
 
        password_confirmation = All(
 
            v.ValidPassword(),
 
            v.UnicodeString(strip=False, min=6, not_empty=True)
 
        )
 
        active = v.StringBoolean(if_missing=False)
 
        firstname = v.UnicodeString(strip=True, min=1, not_empty=False)
 
        lastname = v.UnicodeString(strip=True, min=1, not_empty=False)
 
        email = All(v.Email(not_empty=True), v.UniqSystemEmail(old_data))
 

	
 
        chained_validators = [v.ValidPasswordsMatch()]
 

	
 
    return _RegisterForm
 

	
 

	
 
def PasswordResetForm():
 
    class _PasswordResetForm(formencode.Schema):
 
        allow_extra_fields = True
 
        filter_extra_fields = True
 
        email = All(v.ValidSystemEmail(), v.Email(not_empty=True))
 
    return _PasswordResetForm
 

	
 

	
 
def RepoForm(edit=False, old_data={}, supported_backends=BACKENDS.keys(),
 
             repo_groups=[], landing_revs=[]):
 
    class _RepoForm(formencode.Schema):
 
        allow_extra_fields = True
 
        filter_extra_fields = False
 
        filter_extra_fields = True
 
        repo_name = All(v.UnicodeString(strip=True, min=1, not_empty=True),
 
                        v.SlugifyName())
 
        clone_uri = All(v.UnicodeString(strip=True, min=1, not_empty=False))
 
        repo_group = All(v.CanWriteGroup(),
 
                         v.OneOf(repo_groups, hideList=True))
 
        repo_type = v.OneOf(supported_backends)
 
        description = v.UnicodeString(strip=True, min=1, not_empty=False)
 
        private = v.StringBoolean(if_missing=False)
 
        enable_statistics = v.StringBoolean(if_missing=False)
 
        enable_downloads = v.StringBoolean(if_missing=False)
 
        enable_locking = v.StringBoolean(if_missing=False)
 
        landing_rev = v.OneOf(landing_revs, hideList=True)
 
        repo_description = v.UnicodeString(strip=True, min=1, not_empty=False)
 
        repo_private = v.StringBoolean(if_missing=False)
 
        repo_enable_statistics = v.StringBoolean(if_missing=False)
 
        repo_enable_downloads = v.StringBoolean(if_missing=False)
 
        repo_enable_locking = v.StringBoolean(if_missing=False)
 
        repo_landing_rev = v.OneOf(landing_revs, hideList=True)
 
        clone_uri = All(v.UnicodeString(strip=True, min=1, not_empty=False))
 

	
 
        if edit:
 
            #this is repo owner
 
            user = All(v.UnicodeString(not_empty=True), v.ValidRepoUser())
 

	
 
        chained_validators = [v.ValidCloneUri(),
 
                              v.ValidRepoName(edit, old_data),
 
                              v.ValidPerms()]
 
    return _RepoForm
 

	
 

	
 
def RepoForkForm(edit=False, old_data={}, supported_backends=BACKENDS.keys(),
 
                 repo_groups=[], landing_revs=[]):
 
    class _RepoForkForm(formencode.Schema):
 
        allow_extra_fields = True
 
        filter_extra_fields = False
 
        repo_name = All(v.UnicodeString(strip=True, min=1, not_empty=True),
 
                        v.SlugifyName())
 
        repo_group = All(v.CanWriteGroup(),
 
                         v.OneOf(repo_groups, hideList=True))
 
        repo_type = All(v.ValidForkType(old_data), v.OneOf(supported_backends))
 
        description = v.UnicodeString(strip=True, min=1, not_empty=True)
 
        private = v.StringBoolean(if_missing=False)
 
        copy_permissions = v.StringBoolean(if_missing=False)
 
        update_after_clone = v.StringBoolean(if_missing=False)
 
        fork_parent_id = v.UnicodeString()
 
        chained_validators = [v.ValidForkName(edit, old_data)]
 
        landing_rev = v.OneOf(landing_revs, hideList=True)
 

	
 
    return _RepoForkForm
 

	
 

	
 
def RepoSettingsForm(edit=False, old_data={},
 
                     supported_backends=BACKENDS.keys(), repo_groups=[],
 
                     landing_revs=[]):
 
def RepoSettingsForm(edit=False, old_data={}, supported_backends=BACKENDS.keys(),
 
                     repo_groups=[], landing_revs=[]):
 
    class _RepoForm(formencode.Schema):
 
        allow_extra_fields = True
 
        filter_extra_fields = False
 
        repo_name = All(v.UnicodeString(strip=True, min=1, not_empty=True),
 
                        v.SlugifyName())
 
        description = v.UnicodeString(strip=True, min=1, not_empty=True)
 
        repo_group = All(v.CanWriteGroup(),
 
                         v.OneOf(repo_groups, hideList=True))
 
        private = v.StringBoolean(if_missing=False)
 
        landing_rev = v.OneOf(landing_revs, hideList=True)
 
        chained_validators = [v.ValidRepoName(edit, old_data), v.ValidPerms(),
 
                              v.ValidSettings()]
 
    return _RepoForm
 

	
 

	
 
def ApplicationSettingsForm():
 
    class _ApplicationSettingsForm(formencode.Schema):
 
        allow_extra_fields = True
 
        filter_extra_fields = False
 
        rhodecode_title = v.UnicodeString(strip=True, min=1, not_empty=True)
 
        rhodecode_realm = v.UnicodeString(strip=True, min=1, not_empty=True)
 
        rhodecode_ga_code = v.UnicodeString(strip=True, min=1, not_empty=False)
 

	
 
    return _ApplicationSettingsForm
 

	
 

	
 
def ApplicationVisualisationForm():
 
    class _ApplicationVisualisationForm(formencode.Schema):
 
        allow_extra_fields = True
 
        filter_extra_fields = False
 
        rhodecode_show_public_icon = v.StringBoolean(if_missing=False)
 
        rhodecode_show_private_icon = v.StringBoolean(if_missing=False)
 
        rhodecode_stylify_metatags = v.StringBoolean(if_missing=False)
 

	
 
        rhodecode_lightweight_dashboard = v.StringBoolean(if_missing=False)
 
        rhodecode_lightweight_journal = v.StringBoolean(if_missing=False)
 

	
 
    return _ApplicationVisualisationForm
 

	
 

	
 
def ApplicationUiSettingsForm():
 
    class _ApplicationUiSettingsForm(formencode.Schema):
 
        allow_extra_fields = True
 
        filter_extra_fields = False
 
        web_push_ssl = v.StringBoolean(if_missing=False)
 
        paths_root_path = All(
 
            v.ValidPath(),
 
            v.UnicodeString(strip=True, min=1, not_empty=True)
 
        )
 
        hooks_changegroup_update = v.StringBoolean(if_missing=False)
 
        hooks_changegroup_repo_size = v.StringBoolean(if_missing=False)
 
        hooks_changegroup_push_logger = v.StringBoolean(if_missing=False)
 
        hooks_outgoing_pull_logger = v.StringBoolean(if_missing=False)
 

	
 
        extensions_largefiles = v.StringBoolean(if_missing=False)
 
        extensions_hgsubversion = v.StringBoolean(if_missing=False)
 
        extensions_hggit = v.StringBoolean(if_missing=False)
 

	
 
    return _ApplicationUiSettingsForm
 

	
 

	
 
def DefaultPermissionsForm(repo_perms_choices, group_perms_choices, register_choices, create_choices,
 
                           fork_choices):
 
def DefaultPermissionsForm(repo_perms_choices, group_perms_choices,
 
                           register_choices, create_choices, fork_choices):
 
    class _DefaultPermissionsForm(formencode.Schema):
 
        allow_extra_fields = True
 
        filter_extra_fields = True
 
        overwrite_default_repo = v.StringBoolean(if_missing=False)
 
        overwrite_default_group = v.StringBoolean(if_missing=False)
 
        anonymous = v.StringBoolean(if_missing=False)
 
        default_repo_perm = v.OneOf(repo_perms_choices)
 
        default_group_perm = v.OneOf(group_perms_choices)
 
        default_register = v.OneOf(register_choices)
 
        default_create = v.OneOf(create_choices)
 
        default_fork = v.OneOf(fork_choices)
 

	
 
    return _DefaultPermissionsForm
 

	
 

	
 
def DefaultsForm(edit=False, old_data={}, supported_backends=BACKENDS.keys()):
 
    class _DefaultsForm(formencode.Schema):
 
        allow_extra_fields = True
 
        filter_extra_fields = True
 
        default_repo_type = v.OneOf(supported_backends)
 
        default_repo_private = v.StringBoolean(if_missing=False)
 
        default_repo_enable_statistics = v.StringBoolean(if_missing=False)
 
        default_repo_enable_downloads = v.StringBoolean(if_missing=False)
 
        default_repo_enable_locking = v.StringBoolean(if_missing=False)
 

	
 
    return _DefaultsForm
 

	
 

	
 
def LdapSettingsForm(tls_reqcert_choices, search_scope_choices,
 
                     tls_kind_choices):
 
    class _LdapSettingsForm(formencode.Schema):
 
        allow_extra_fields = True
 
        filter_extra_fields = True
 
        #pre_validators = [LdapLibValidator]
 
        ldap_active = v.StringBoolean(if_missing=False)
 
        ldap_host = v.UnicodeString(strip=True,)
 
        ldap_port = v.Number(strip=True,)
 
        ldap_tls_kind = v.OneOf(tls_kind_choices)
 
        ldap_tls_reqcert = v.OneOf(tls_reqcert_choices)
 
        ldap_dn_user = v.UnicodeString(strip=True,)
 
        ldap_dn_pass = v.UnicodeString(strip=True,)
 
        ldap_base_dn = v.UnicodeString(strip=True,)
 
        ldap_filter = v.UnicodeString(strip=True,)
 
        ldap_search_scope = v.OneOf(search_scope_choices)
 
        ldap_attr_login = All(
 
            v.AttrLoginValidator(),
 
            v.UnicodeString(strip=True,)
 
        )
 
        ldap_attr_firstname = v.UnicodeString(strip=True,)
 
        ldap_attr_lastname = v.UnicodeString(strip=True,)
 
        ldap_attr_email = v.UnicodeString(strip=True,)
 

	
 
    return _LdapSettingsForm
 

	
 

	
 
def UserExtraEmailForm():
 
    class _UserExtraEmailForm(formencode.Schema):
 
        email = All(v.UniqSystemEmail(), v.Email)
 

	
 
    return _UserExtraEmailForm
 

	
 

	
 
def PullRequestForm(repo_id):
 
    class _PullRequestForm(formencode.Schema):
 
        allow_extra_fields = True
 
        filter_extra_fields = True
 

	
 
        user = v.UnicodeString(strip=True, required=True)
 
        org_repo = v.UnicodeString(strip=True, required=True)
 
        org_ref = v.UnicodeString(strip=True, required=True)
 
        other_repo = v.UnicodeString(strip=True, required=True)
 
        other_ref = v.UnicodeString(strip=True, required=True)
 
        revisions = All(v.NotReviewedRevisions(repo_id)(), v.UniqueList(not_empty=True))
 
        review_members = v.UniqueList(not_empty=True)
 

	
 
        pullrequest_title = v.UnicodeString(strip=True, required=True, min=3)
 
        pullrequest_desc = v.UnicodeString(strip=True, required=False)
 

	
 
    return _PullRequestForm
rhodecode/model/repo.py
Show inline comments
 
# -*- coding: utf-8 -*-
 
"""
 
    rhodecode.model.repo
 
    ~~~~~~~~~~~~~~~~~~~~
 

	
 
    Repository model for rhodecode
 

	
 
    :created_on: Jun 5, 2010
 
    :author: marcink
 
    :copyright: (C) 2010-2012 Marcin Kuzminski <marcin@python-works.com>
 
    :license: GPLv3, see COPYING for more details.
 
"""
 
# This program is free software: you can redistribute it and/or modify
 
# it under the terms of the GNU General Public License as published by
 
# the Free Software Foundation, either version 3 of the License, or
 
# (at your option) any later version.
 
#
 
# This program is distributed in the hope that it will be useful,
 
# but WITHOUT ANY WARRANTY; without even the implied warranty of
 
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
# GNU General Public License for more details.
 
#
 
# You should have received a copy of the GNU General Public License
 
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
from __future__ import with_statement
 
import os
 
import shutil
 
import logging
 
import traceback
 
from datetime import datetime
 

	
 
from rhodecode.lib.vcs.backends import get_backend
 
from rhodecode.lib.compat import json
 
from rhodecode.lib.utils2 import LazyProperty, safe_str, safe_unicode
 
from rhodecode.lib.caching_query import FromCache
 
from rhodecode.lib.hooks import log_create_repository, log_delete_repository
 

	
 
from rhodecode.model import BaseModel
 
from rhodecode.model.db import Repository, UserRepoToPerm, User, Permission, \
 
    Statistics, UsersGroup, UsersGroupRepoToPerm, RhodeCodeUi, RepoGroup
 
    Statistics, UsersGroup, UsersGroupRepoToPerm, RhodeCodeUi, RepoGroup,\
 
    RhodeCodeSetting
 
from rhodecode.lib import helpers as h
 

	
 

	
 
log = logging.getLogger(__name__)
 

	
 

	
 
class RepoModel(BaseModel):
 

	
 
    cls = Repository
 
    URL_SEPARATOR = Repository.url_sep()
 

	
 
    def __get_users_group(self, users_group):
 
        return self._get_instance(UsersGroup, users_group,
 
                                  callback=UsersGroup.get_by_group_name)
 

	
 
    def _get_repos_group(self, repos_group):
 
        return self._get_instance(RepoGroup, repos_group,
 
                                  callback=RepoGroup.get_by_group_name)
 

	
 
    @LazyProperty
 
    def repos_path(self):
 
        """
 
        Get's the repositories root path from database
 
        """
 

	
 
        q = self.sa.query(RhodeCodeUi).filter(RhodeCodeUi.ui_key == '/').one()
 
        return q.ui_value
 

	
 
    def get(self, repo_id, cache=False):
 
        repo = self.sa.query(Repository)\
 
            .filter(Repository.repo_id == repo_id)
 

	
 
        if cache:
 
            repo = repo.options(FromCache("sql_cache_short",
 
                                          "get_repo_%s" % repo_id))
 
        return repo.scalar()
 

	
 
    def get_repo(self, repository):
 
        return self._get_repo(repository)
 

	
 
    def get_by_repo_name(self, repo_name, cache=False):
 
        repo = self.sa.query(Repository)\
 
            .filter(Repository.repo_name == repo_name)
 

	
 
        if cache:
 
            repo = repo.options(FromCache("sql_cache_short",
 
                                          "get_repo_%s" % repo_name))
 
        return repo.scalar()
 

	
 
    def get_users_js(self):
 
        users = self.sa.query(User).filter(User.active == True).all()
 
        return json.dumps([
 
            {
 
             'id': u.user_id,
 
             'fname': u.name,
 
             'lname': u.lastname,
 
             'nname': u.username,
 
             'gravatar_lnk': h.gravatar_url(u.email, 14)
 
            } for u in users]
 
        )
 

	
 
    def get_users_groups_js(self):
 
        users_groups = self.sa.query(UsersGroup)\
 
            .filter(UsersGroup.users_group_active == True).all()
 

	
 
        return json.dumps([
 
            {
 
             'id': gr.users_group_id,
 
             'grname': gr.users_group_name,
 
             'grmembers': len(gr.members),
 
            } for gr in users_groups]
 
        )
 

	
 
    def _get_defaults(self, repo_name):
 
        """
 
        Get's information about repository, and returns a dict for
 
        usage in forms
 

	
 
        :param repo_name:
 
        """
 

	
 
        repo_info = Repository.get_by_repo_name(repo_name)
 

	
 
        if repo_info is None:
 
            return None
 

	
 
        defaults = repo_info.get_dict()
 
        group, repo_name = repo_info.groups_and_repo
 
        defaults['repo_name'] = repo_name
 
        defaults['repo_group'] = getattr(group[-1] if group else None,
 
                                         'group_id', None)
 

	
 
        # fill owner
 
        if repo_info.user:
 
            defaults.update({'user': repo_info.user.username})
 
        else:
 
            replacement_user = User.query().filter(User.admin ==
 
                                                   True).first().username
 
            defaults.update({'user': replacement_user})
 

	
 
        # fill repository users
 
        for p in repo_info.repo_to_perm:
 
            defaults.update({'u_perm_%s' % p.user.username:
 
                             p.permission.permission_name})
 

	
 
        # fill repository groups
 
        for p in repo_info.users_group_to_perm:
 
            defaults.update({'g_perm_%s' % p.users_group.users_group_name:
 
                             p.permission.permission_name})
 

	
 
        return defaults
 

	
 
    def update(self, repo_name, form_data):
 
        try:
 
            cur_repo = self.get_by_repo_name(repo_name, cache=False)
 

	
 
            # update permissions
 
            for member, perm, member_type in form_data['perms_updates']:
 
                if member_type == 'user':
 
                    # this updates existing one
 
                    RepoModel().grant_user_permission(
 
                        repo=cur_repo, user=member, perm=perm
 
                    )
 
                else:
 
                    RepoModel().grant_users_group_permission(
 
                        repo=cur_repo, group_name=member, perm=perm
 
                    )
 
            # set new permissions
 
            for member, perm, member_type in form_data['perms_new']:
 
                if member_type == 'user':
 
                    RepoModel().grant_user_permission(
 
                        repo=cur_repo, user=member, perm=perm
 
                    )
 
                else:
 
                    RepoModel().grant_users_group_permission(
 
                        repo=cur_repo, group_name=member, perm=perm
 
                    )
 

	
 
            # update current repo
 
            for k, v in form_data.items():
 
                if k == 'user':
 
                    cur_repo.user = User.get_by_username(v)
 
                elif k == 'repo_name':
 
                    pass
 
                elif k == 'repo_group':
 
                    cur_repo.group = RepoGroup.get(v)
 

	
 
                else:
 
                    setattr(cur_repo, k, v)
 

	
 
            new_name = cur_repo.get_new_name(form_data['repo_name'])
 
            cur_repo.repo_name = new_name
 

	
 
            self.sa.add(cur_repo)
 

	
 
            if repo_name != new_name:
 
                # rename repository
 
                self.__rename_repo(old=repo_name, new=new_name)
 

	
 
            return cur_repo
 
        except:
 
            log.error(traceback.format_exc())
 
            raise
 

	
 
    def create_repo(self, repo_name, repo_type, description, owner,
 
                    private=False, clone_uri=None, repos_group=None,
 
                    landing_rev='tip', just_db=False, fork_of=None,
 
                    copy_fork_permissions=False):
 
                    copy_fork_permissions=False, enable_statistics=False,
 
                    enable_locking=False, enable_downloads=False):
 
        """
 
        Create repository
 

	
 
        """
 
        from rhodecode.model.scm import ScmModel
 

	
 
        owner = self._get_user(owner)
 
        fork_of = self._get_repo(fork_of)
 
        repos_group = self._get_repos_group(repos_group)
 
        try:
 

	
 
            # repo name is just a name of repository
 
            # while repo_name_full is a full qualified name that is combined
 
            # with name and path of group
 
            repo_name_full = repo_name
 
            repo_name = repo_name.split(self.URL_SEPARATOR)[-1]
 

	
 
            new_repo = Repository()
 
            new_repo.enable_statistics = False
 
            new_repo.repo_name = repo_name_full
 
            new_repo.repo_type = repo_type
 
            new_repo.user = owner
 
            new_repo.group = repos_group
 
            new_repo.description = description or repo_name
 
            new_repo.private = private
 
            new_repo.clone_uri = clone_uri
 
            new_repo.landing_rev = landing_rev
 

	
 
            new_repo.enable_statistics = enable_statistics
 
            new_repo.enable_locking = enable_locking
 
            new_repo.enable_downloads = enable_downloads
 

	
 
            if repos_group:
 
                new_repo.enable_locking = repos_group.enable_locking
 

	
 
            if fork_of:
 
                parent_repo = fork_of
 
                new_repo.fork = parent_repo
 

	
 
            self.sa.add(new_repo)
 

	
 
            def _create_default_perms():
 
                # create default permission
 
                repo_to_perm = UserRepoToPerm()
 
                default = 'repository.read'
 
                for p in User.get_by_username('default').user_perms:
 
                    if p.permission.permission_name.startswith('repository.'):
 
                        default = p.permission.permission_name
 
                        break
 

	
 
                default_perm = 'repository.none' if private else default
 

	
 
                repo_to_perm.permission_id = self.sa.query(Permission)\
 
                        .filter(Permission.permission_name == default_perm)\
 
                        .one().permission_id
 

	
 
                repo_to_perm.repository = new_repo
 
                repo_to_perm.user_id = User.get_by_username('default').user_id
 

	
 
                self.sa.add(repo_to_perm)
 

	
 
            if fork_of:
 
                if copy_fork_permissions:
 
                    repo = fork_of
 
                    user_perms = UserRepoToPerm.query()\
 
                        .filter(UserRepoToPerm.repository == repo).all()
 
                    group_perms = UsersGroupRepoToPerm.query()\
 
                        .filter(UsersGroupRepoToPerm.repository == repo).all()
 

	
 
                    for perm in user_perms:
 
                        UserRepoToPerm.create(perm.user, new_repo,
 
                                              perm.permission)
 

	
 
                    for perm in group_perms:
 
                        UsersGroupRepoToPerm.create(perm.users_group, new_repo,
 
                                                    perm.permission)
 
                else:
 
                    _create_default_perms()
 
            else:
 
                _create_default_perms()
 

	
 
            if not just_db:
 
                self.__create_repo(repo_name, repo_type,
 
                                   repos_group,
 
                                   clone_uri)
 
                log_create_repository(new_repo.get_dict(),
 
                                      created_by=owner.username)
 

	
 
            # now automatically start following this repository as owner
 
            ScmModel(self.sa).toggle_following_repo(new_repo.repo_id,
 
                                                    owner.user_id)
 
            return new_repo
 
        except:
 
            log.error(traceback.format_exc())
 
            raise
 

	
 
    def create(self, form_data, cur_user, just_db=False, fork=None):
 
        """
 
        Backward compatibility function, just a wrapper on top of create_repo
 

	
 
        :param form_data:
 
        :param cur_user:
 
        :param just_db:
 
        :param fork:
 
        """
 

	
 
        owner = cur_user
 
        repo_name = form_data['repo_name_full']
 
        repo_type = form_data['repo_type']
 
        description = form_data['description']
 
        owner = cur_user
 
        private = form_data['private']
 
        description = form_data['repo_description']
 
        private = form_data['repo_private']
 
        clone_uri = form_data.get('clone_uri')
 
        repos_group = form_data['repo_group']
 
        landing_rev = form_data['landing_rev']
 
        landing_rev = form_data['repo_landing_rev']
 
        copy_fork_permissions = form_data.get('copy_permissions')
 
        fork_of = form_data.get('fork_parent_id')
 

	
 
        ##defaults
 
        defs = RhodeCodeSetting.get_default_repo_settings(strip_prefix=True)
 
        enable_statistics = defs.get('repo_enable_statistic')
 
        enable_locking = defs.get('repo_enable_locking')
 
        enable_downloads = defs.get('repo_enable_downloads')
 

	
 
        return self.create_repo(
 
            repo_name, repo_type, description, owner, private, clone_uri,
 
            repos_group, landing_rev, just_db, fork_of, copy_fork_permissions
 
            repos_group, landing_rev, just_db, fork_of, copy_fork_permissions,
 
            enable_statistics, enable_locking, enable_downloads
 
        )
 

	
 
    def create_fork(self, form_data, cur_user):
 
        """
 
        Simple wrapper into executing celery task for fork creation
 

	
 
        :param form_data:
 
        :param cur_user:
 
        """
 
        from rhodecode.lib.celerylib import tasks, run_task
 
        run_task(tasks.create_repo_fork, form_data, cur_user)
 

	
 
    def delete(self, repo):
 
        repo = self._get_repo(repo)
 
        if repo:
 
            old_repo_dict = repo.get_dict()
 
            owner = repo.user
 
            try:
 
                self.sa.delete(repo)
 
                self.__delete_repo(repo)
 
                log_delete_repository(old_repo_dict,
 
                                      deleted_by=owner.username)
 
            except:
 
                log.error(traceback.format_exc())
 
                raise
 

	
 
    def grant_user_permission(self, repo, user, perm):
 
        """
 
        Grant permission for user on given repository, or update existing one
 
        if found
 

	
 
        :param repo: Instance of Repository, repository_id, or repository name
 
        :param user: Instance of User, user_id or username
 
        :param perm: Instance of Permission, or permission_name
 
        """
 
        user = self._get_user(user)
 
        repo = self._get_repo(repo)
 
        permission = self._get_perm(perm)
 

	
 
        # check if we have that permission already
 
        obj = self.sa.query(UserRepoToPerm)\
 
            .filter(UserRepoToPerm.user == user)\
 
            .filter(UserRepoToPerm.repository == repo)\
 
            .scalar()
 
        if obj is None:
 
            # create new !
 
            obj = UserRepoToPerm()
 
        obj.repository = repo
 
        obj.user = user
 
        obj.permission = permission
 
        self.sa.add(obj)
 
        log.debug('Granted perm %s to %s on %s' % (perm, user, repo))
 

	
 
    def revoke_user_permission(self, repo, user):
 
        """
 
        Revoke permission for user on given repository
 

	
 
        :param repo: Instance of Repository, repository_id, or repository name
 
        :param user: Instance of User, user_id or username
 
        """
 

	
 
        user = self._get_user(user)
 
        repo = self._get_repo(repo)
 

	
 
        obj = self.sa.query(UserRepoToPerm)\
 
            .filter(UserRepoToPerm.repository == repo)\
 
            .filter(UserRepoToPerm.user == user)\
 
            .scalar()
 
        if obj:
 
            self.sa.delete(obj)
 
            log.debug('Revoked perm on %s on %s' % (repo, user))
 

	
 
    def grant_users_group_permission(self, repo, group_name, perm):
 
        """
 
        Grant permission for users group on given repository, or update
 
        existing one if found
 

	
 
        :param repo: Instance of Repository, repository_id, or repository name
 
        :param group_name: Instance of UserGroup, users_group_id,
 
            or users group name
 
        :param perm: Instance of Permission, or permission_name
 
        """
 
        repo = self._get_repo(repo)
 
        group_name = self.__get_users_group(group_name)
 
        permission = self._get_perm(perm)
 

	
 
        # check if we have that permission already
 
        obj = self.sa.query(UsersGroupRepoToPerm)\
 
            .filter(UsersGroupRepoToPerm.users_group == group_name)\
 
            .filter(UsersGroupRepoToPerm.repository == repo)\
 
            .scalar()
 

	
 
        if obj is None:
 
            # create new
 
            obj = UsersGroupRepoToPerm()
 

	
 
        obj.repository = repo
 
        obj.users_group = group_name
 
        obj.permission = permission
 
        self.sa.add(obj)
 
        log.debug('Granted perm %s to %s on %s' % (perm, group_name, repo))
 

	
 
    def revoke_users_group_permission(self, repo, group_name):
 
        """
 
        Revoke permission for users group on given repository
 

	
 
        :param repo: Instance of Repository, repository_id, or repository name
 
        :param group_name: Instance of UserGroup, users_group_id,
 
            or users group name
 
        """
 
        repo = self._get_repo(repo)
 
        group_name = self.__get_users_group(group_name)
 

	
 
        obj = self.sa.query(UsersGroupRepoToPerm)\
 
            .filter(UsersGroupRepoToPerm.repository == repo)\
 
            .filter(UsersGroupRepoToPerm.users_group == group_name)\
 
            .scalar()
 
        if obj:
 
            self.sa.delete(obj)
 
            log.debug('Revoked perm to %s on %s' % (repo, group_name))
 

	
 
    def delete_stats(self, repo_name):
 
        """
 
        removes stats for given repo
 

	
 
        :param repo_name:
 
        """
 
        try:
 
            obj = self.sa.query(Statistics)\
 
                    .filter(Statistics.repository ==
 
                            self.get_by_repo_name(repo_name))\
 
                    .one()
 
            self.sa.delete(obj)
 
        except:
 
            log.error(traceback.format_exc())
 
            raise
 

	
 
    def __create_repo(self, repo_name, alias, parent, clone_uri=False):
 
        """
 
        makes repository on filesystem. It's group aware means it'll create
 
        a repository within a group, and alter the paths accordingly of
 
        group location
 

	
 
        :param repo_name:
 
        :param alias:
 
        :param parent_id:
 
        :param clone_uri:
 
        """
 
        from rhodecode.lib.utils import is_valid_repo, is_valid_repos_group
 
        from rhodecode.model.scm import ScmModel
 

	
 
        if parent:
 
            new_parent_path = os.sep.join(parent.full_path_splitted)
 
        else:
 
            new_parent_path = ''
 

	
 
        # we need to make it str for mercurial
 
        repo_path = os.path.join(*map(lambda x: safe_str(x),
 
                                [self.repos_path, new_parent_path, repo_name]))
 

	
 
        # check if this path is not a repository
 
        if is_valid_repo(repo_path, self.repos_path):
 
            raise Exception('This path %s is a valid repository' % repo_path)
 

	
 
        # check if this path is a group
 
        if is_valid_repos_group(repo_path, self.repos_path):
 
            raise Exception('This path %s is a valid group' % repo_path)
 

	
 
        log.info('creating repo %s in %s @ %s' % (
 
                     repo_name, safe_unicode(repo_path), clone_uri
 
                )
 
        )
 
        backend = get_backend(alias)
 
        if alias == 'hg':
 
            backend(repo_path, create=True, src_url=clone_uri)
 
        elif alias == 'git':
 
            r = backend(repo_path, create=True, src_url=clone_uri, bare=True)
 
            # add rhodecode hook into this repo
 
            ScmModel().install_git_hook(repo=r)
 
        else:
 
            raise Exception('Undefined alias %s' % alias)
 

	
 
    def __rename_repo(self, old, new):
 
        """
 
        renames repository on filesystem
 

	
 
        :param old: old name
 
        :param new: new name
 
        """
 
        log.info('renaming repo from %s to %s' % (old, new))
 

	
 
        old_path = os.path.join(self.repos_path, old)
 
        new_path = os.path.join(self.repos_path, new)
 
        if os.path.isdir(new_path):
 
            raise Exception(
 
                'Was trying to rename to already existing dir %s' % new_path
 
            )
 
        shutil.move(old_path, new_path)
 

	
 
    def __delete_repo(self, repo):
 
        """
 
        removes repo from filesystem, the removal is acctually made by
 
        added rm__ prefix into dir, and rename internat .hg/.git dirs so this
 
        repository is no longer valid for rhodecode, can be undeleted later on
 
        by reverting the renames on this repository
 

	
 
        :param repo: repo object
 
        """
 
        rm_path = os.path.join(self.repos_path, repo.repo_name)
 
        log.info("Removing %s" % (rm_path))
 
        # disable hg/git internal that it doesn't get detected as repo
 
        alias = repo.repo_type
 

	
 
        bare = getattr(repo.scm_instance, 'bare', False)
 

	
 
        if not bare:
 
            # skip this for bare git repos
 
            shutil.move(os.path.join(rm_path, '.%s' % alias),
 
                        os.path.join(rm_path, 'rm__.%s' % alias))
 
        # disable repo
 
        _now = datetime.now()
 
        _ms = str(_now.microsecond).rjust(6, '0')
 
        _d = 'rm__%s__%s' % (_now.strftime('%Y%m%d_%H%M%S_' + _ms),
 
                             repo.just_name)
 
        if repo.group:
 
            args = repo.group.full_path_splitted + [_d]
 
            _d = os.path.join(*args)
 
        shutil.move(rm_path, os.path.join(self.repos_path, _d))
rhodecode/public/css/style.css
Show inline comments
 
@@ -245,768 +245,776 @@ div:hover > a.permalink {
 
 
#header {
 
	margin: 0;
 
	padding: 0 10px;
 
}
 
 
#header ul#logged-user {
 
	margin-bottom: 5px !important;
 
	-webkit-border-radius: 0px 0px 8px 8px;
 
	-khtml-border-radius: 0px 0px 8px 8px;
 
	-moz-border-radius: 0px 0px 8px 8px;
 
	border-radius: 0px 0px 8px 8px;
 
	height: 37px;
 
    background-color: #003B76;    
 
    background-repeat: repeat-x;
 
    background-image: -khtml-gradient(linear, left top, left bottom, from(#003B76), to(#00376E) );
 
    background-image: -moz-linear-gradient(top, #003b76, #00376e);
 
    background-image: -ms-linear-gradient(top, #003b76, #00376e);
 
    background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #003b76), color-stop(100%, #00376e) );
 
    background-image: -webkit-linear-gradient(top, #003b76, #00376e);
 
    background-image: -o-linear-gradient(top, #003b76, #00376e);
 
    background-image: linear-gradient(top, #003b76, #00376e);
 
    filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#003b76',endColorstr='#00376e', GradientType=0 );
 
	box-shadow: 0 2px 2px rgba(0, 0, 0, 0.6);
 
}
 
 
#header ul#logged-user li {
 
	list-style: none;
 
	float: left;
 
	margin: 8px 0 0;
 
	padding: 4px 12px;
 
	border-left: 1px solid #316293;
 
}
 
 
#header ul#logged-user li.first {
 
	border-left: none;
 
	margin: 4px;
 
}
 
 
#header ul#logged-user li.first div.gravatar {
 
	margin-top: -2px;
 
}
 
 
#header ul#logged-user li.first div.account {
 
	padding-top: 4px;
 
	float: left;
 
}
 
 
#header ul#logged-user li.last {
 
	border-right: none;
 
}
 
 
#header ul#logged-user li a {
 
	color: #fff;
 
	font-weight: 700;
 
	text-decoration: none;
 
}
 
 
#header ul#logged-user li a:hover {
 
	text-decoration: underline;
 
}
 
 
#header ul#logged-user li.highlight a {
 
	color: #fff;
 
}
 
 
#header ul#logged-user li.highlight a:hover {
 
	color: #FFF;
 
}
 
 
#header #header-inner {
 
	min-height: 44px;
 
	clear: both;
 
	position: relative;
 
    background-color: #003B76;
 
    background-repeat: repeat-x;
 
    background-image: -khtml-gradient(linear, left top, left bottom, from(#003B76), to(#00376E) );
 
    background-image: -moz-linear-gradient(top, #003b76, #00376e);
 
    background-image: -ms-linear-gradient(top, #003b76, #00376e);
 
    background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #003b76),color-stop(100%, #00376e) );
 
    background-image: -webkit-linear-gradient(top, #003b76, #00376e);
 
    background-image: -o-linear-gradient(top, #003b76, #00376e);
 
    background-image: linear-gradient(top, #003b76, #00376e);
 
    filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#003b76',endColorstr='#00376e', GradientType=0 );
 
	margin: 0;
 
	padding: 0;
 
	display: block;
 
	box-shadow: 0 2px 2px rgba(0, 0, 0, 0.6);
 
	-webkit-border-radius: 4px 4px 4px 4px;
 
	-khtml-border-radius: 4px 4px 4px 4px;
 
	-moz-border-radius: 4px 4px 4px 4px;
 
	border-radius: 4px 4px 4px 4px;
 
}
 
#header #header-inner.hover{
 
	position: fixed !important;
 
	width: 100% !important;
 
	margin-left: -10px !important;
 
	z-index: 10000;
 
    -webkit-border-radius: 0px 0px 0px 0px;
 
    -khtml-border-radius: 0px 0px 0px 0px;
 
    -moz-border-radius: 0px 0px 0px 0px;
 
    border-radius: 0px 0px 0px 0px;	
 
}
 
 
.ie7 #header #header-inner.hover,
 
.ie8 #header #header-inner.hover,
 
.ie9 #header #header-inner.hover
 
{
 
    z-index: auto !important;
 
}
 
 
.header-pos-fix, .anchor{
 
	margin-top: -46px;
 
	padding-top: 46px;
 
}
 
 
#header #header-inner #home a {
 
	height: 40px;
 
	width: 46px;
 
	display: block;
 
	background: url("../images/button_home.png");
 
	background-position: 0 0;
 
	margin: 0;
 
	padding: 0;
 
}
 
 
#header #header-inner #home a:hover {
 
	background-position: 0 -40px;
 
}
 
 
#header #header-inner #logo {
 
	float: left;
 
	position: absolute;
 
}
 
 
#header #header-inner #logo h1 {
 
	color: #FFF;
 
	font-size: 20px;
 
	margin: 12px 0 0 13px;
 
	padding: 0;
 
}
 
 
#header #header-inner #logo a {
 
	color: #fff;
 
	text-decoration: none;
 
}
 
 
#header #header-inner #logo a:hover {
 
	color: #bfe3ff;
 
}
 
 
#header #header-inner #quick,#header #header-inner #quick ul {
 
	position: relative;
 
	float: right;
 
	list-style-type: none;
 
	list-style-position: outside;
 
	margin: 8px 8px 0 0;
 
	padding: 0;
 
}
 
 
#header #header-inner #quick li {
 
	position: relative;
 
	float: left;
 
	margin: 0 5px 0 0;
 
	padding: 0;
 
}
 
 
#header #header-inner #quick li a.menu_link {
 
	top: 0;
 
	left: 0;
 
	height: 1%;
 
	display: block;
 
	clear: both;
 
	overflow: hidden;
 
	color: #FFF;
 
	font-weight: 700;
 
	text-decoration: none;
 
	background: #369;
 
	padding: 0;
 
	-webkit-border-radius: 4px 4px 4px 4px;
 
	-khtml-border-radius: 4px 4px 4px 4px;
 
	-moz-border-radius: 4px 4px 4px 4px;
 
	border-radius: 4px 4px 4px 4px;
 
}
 
 
#header #header-inner #quick li span.short {
 
	padding: 9px 6px 8px 6px;
 
}
 
 
#header #header-inner #quick li span {
 
	top: 0;
 
	right: 0;
 
	height: 1%;
 
	display: block;
 
	float: left;
 
	border-left: 1px solid #3f6f9f;
 
	margin: 0;
 
	padding: 10px 12px 8px 10px;
 
}
 
 
#header #header-inner #quick li span.normal {
 
	border: none;
 
	padding: 10px 12px 8px;
 
}
 
 
#header #header-inner #quick li span.icon {
 
	top: 0;
 
	left: 0;
 
	border-left: none;
 
	border-right: 1px solid #2e5c89;
 
	padding: 8px 6px 4px;
 
}
 
 
#header #header-inner #quick li span.icon_short {
 
	top: 0;
 
	left: 0;
 
	border-left: none;
 
	border-right: 1px solid #2e5c89;
 
	padding: 8px 6px 4px;
 
}
 
 
#header #header-inner #quick li span.icon img,#header #header-inner #quick li span.icon_short img
 
	{
 
	margin: 0px -2px 0px 0px;
 
}
 
 
#header #header-inner #quick li a:hover {
 
	background: #4e4e4e no-repeat top left;
 
}
 
 
#header #header-inner #quick li a:hover span {
 
	border-left: 1px solid #545454;
 
}
 
 
#header #header-inner #quick li a:hover span.icon,#header #header-inner #quick li a:hover span.icon_short
 
	{
 
	border-left: none;
 
	border-right: 1px solid #464646;
 
}
 
 
#header #header-inner #quick ul {
 
	top: 29px;
 
	right: 0;
 
	min-width: 200px;
 
	display: none;
 
	position: absolute;
 
	background: #FFF;
 
	border: 1px solid #666;
 
	border-top: 1px solid #003367;
 
	z-index: 100;
 
	margin: 0px 0px 0px 0px;
 
	padding: 0;
 
}
 
 
#header #header-inner #quick ul.repo_switcher {
 
	max-height: 275px;
 
	overflow-x: hidden;
 
	overflow-y: auto;
 
}
 
 
#header #header-inner #quick ul.repo_switcher li.qfilter_rs {
 
	float: none;
 
	margin: 0;
 
	border-bottom: 2px solid #003367;
 
}
 
 
#header #header-inner #quick .repo_switcher_type {
 
	position: absolute;
 
	left: 0;
 
	top: 9px;
 
}
 
 
#header #header-inner #quick li ul li {
 
	border-bottom: 1px solid #ddd;
 
}
 
 
#header #header-inner #quick li ul li a {
 
	width: 182px;
 
	height: auto;
 
	display: block;
 
	float: left;
 
	background: #FFF;
 
	color: #003367;
 
	font-weight: 400;
 
	margin: 0;
 
	padding: 7px 9px;
 
}
 
 
#header #header-inner #quick li ul li a:hover {
 
	color: #000;
 
	background: #FFF;
 
}
 
 
#header #header-inner #quick ul ul {
 
	top: auto;
 
}
 
 
#header #header-inner #quick li ul ul {
 
	right: 200px;
 
	max-height: 275px;
 
	overflow: auto;
 
	overflow-x: hidden;
 
	white-space: normal;
 
}
 
 
#header #header-inner #quick li ul li a.journal,#header #header-inner #quick li ul li a.journal:hover
 
	{
 
	background: url("../images/icons/book.png") no-repeat scroll 4px 9px
 
		#FFF;
 
	width: 167px;
 
	margin: 0;
 
	padding: 12px 9px 7px 24px;
 
}
 
 
#header #header-inner #quick li ul li a.private_repo,#header #header-inner #quick li ul li a.private_repo:hover
 
	{
 
	background: url("../images/icons/lock.png") no-repeat scroll 4px 9px
 
		#FFF;
 
	min-width: 167px;
 
	margin: 0;
 
	padding: 12px 9px 7px 24px;
 
}
 
 
#header #header-inner #quick li ul li a.public_repo,#header #header-inner #quick li ul li a.public_repo:hover
 
	{
 
	background: url("../images/icons/lock_open.png") no-repeat scroll 4px
 
		9px #FFF;
 
	min-width: 167px;
 
	margin: 0;
 
	padding: 12px 9px 7px 24px;
 
}
 
 
#header #header-inner #quick li ul li a.hg,#header #header-inner #quick li ul li a.hg:hover
 
	{
 
	background: url("../images/icons/hgicon.png") no-repeat scroll 4px 9px
 
		#FFF;
 
	min-width: 167px;
 
	margin: 0 0 0 14px;
 
	padding: 12px 9px 7px 24px;
 
}
 
 
#header #header-inner #quick li ul li a.git,#header #header-inner #quick li ul li a.git:hover
 
	{
 
	background: url("../images/icons/giticon.png") no-repeat scroll 4px 9px
 
		#FFF;
 
	min-width: 167px;
 
	margin: 0 0 0 14px;
 
	padding: 12px 9px 7px 24px;
 
}
 
 
#header #header-inner #quick li ul li a.repos,#header #header-inner #quick li ul li a.repos:hover
 
	{
 
	background: url("../images/icons/database_edit.png") no-repeat scroll
 
		4px 9px #FFF;
 
	width: 167px;
 
	margin: 0;
 
	padding: 12px 9px 7px 24px;
 
}
 
 
#header #header-inner #quick li ul li a.repos_groups,#header #header-inner #quick li ul li a.repos_groups:hover
 
	{
 
	background: url("../images/icons/database_link.png") no-repeat scroll
 
		4px 9px #FFF;
 
	width: 167px;
 
	margin: 0;
 
	padding: 12px 9px 7px 24px;
 
}
 
 
#header #header-inner #quick li ul li a.users,#header #header-inner #quick li ul li a.users:hover
 
	{
 
	background: #FFF url("../images/icons/user_edit.png") no-repeat 4px 9px;
 
	width: 167px;
 
	margin: 0;
 
	padding: 12px 9px 7px 24px;
 
}
 
 
#header #header-inner #quick li ul li a.groups,#header #header-inner #quick li ul li a.groups:hover
 
	{
 
	background: #FFF url("../images/icons/group_edit.png") no-repeat 4px 9px;
 
	width: 167px;
 
	margin: 0;
 
	padding: 12px 9px 7px 24px;
 
}
 
 
#header #header-inner #quick li ul li a.defaults,#header #header-inner #quick li ul li a.defaults:hover
 
    {
 
    background: #FFF url("../images/icons/wrench.png") no-repeat 4px 9px;
 
    width: 167px;
 
    margin: 0;
 
    padding: 12px 9px 7px 24px;
 
}
 
 
#header #header-inner #quick li ul li a.settings,#header #header-inner #quick li ul li a.settings:hover
 
	{
 
	background: #FFF url("../images/icons/cog.png") no-repeat 4px 9px;
 
	width: 167px;
 
	margin: 0;
 
	padding: 12px 9px 7px 24px;
 
}
 
 
#header #header-inner #quick li ul li a.permissions,#header #header-inner #quick li ul li a.permissions:hover
 
	{
 
	background: #FFF url("../images/icons/key.png") no-repeat 4px 9px;
 
	width: 167px;
 
	margin: 0;
 
	padding: 12px 9px 7px 24px;
 
}
 
 
#header #header-inner #quick li ul li a.ldap,#header #header-inner #quick li ul li a.ldap:hover
 
	{
 
	background: #FFF url("../images/icons/server_key.png") no-repeat 4px 9px;
 
	width: 167px;
 
	margin: 0;
 
	padding: 12px 9px 7px 24px;
 
}
 
 
#header #header-inner #quick li ul li a.fork,#header #header-inner #quick li ul li a.fork:hover
 
	{
 
	background: #FFF url("../images/icons/arrow_divide.png") no-repeat 4px
 
		9px;
 
	width: 167px;
 
	margin: 0;
 
	padding: 12px 9px 7px 24px;
 
}
 
 
#header #header-inner #quick li ul li a.locking_add,#header #header-inner #quick li ul li a.locking_add:hover
 
    {
 
    background: #FFF url("../images/icons/lock_add.png") no-repeat 4px
 
        9px;
 
    width: 167px;
 
    margin: 0;
 
    padding: 12px 9px 7px 24px;
 
}
 
 
#header #header-inner #quick li ul li a.locking_del,#header #header-inner #quick li ul li a.locking_del:hover
 
    {
 
    background: #FFF url("../images/icons/lock_delete.png") no-repeat 4px
 
        9px;
 
    width: 167px;
 
    margin: 0;
 
    padding: 12px 9px 7px 24px;
 
}
 
 
#header #header-inner #quick li ul li a.pull_request,#header #header-inner #quick li ul li a.pull_request:hover
 
    {
 
    background: #FFF url("../images/icons/arrow_join.png") no-repeat 4px
 
        9px;
 
    width: 167px;
 
    margin: 0;
 
    padding: 12px 9px 7px 24px;
 
}
 
 
#header #header-inner #quick li ul li a.compare_request,#header #header-inner #quick li ul li a.compare_request:hover
 
    {
 
    background: #FFF url("../images/icons/arrow_inout.png") no-repeat 4px
 
        9px;
 
    width: 167px;
 
    margin: 0;
 
    padding: 12px 9px 7px 24px;
 
}
 
 
#header #header-inner #quick li ul li a.search,#header #header-inner #quick li ul li a.search:hover
 
	{
 
	background: #FFF url("../images/icons/search_16.png") no-repeat 4px 9px;
 
	width: 167px;
 
	margin: 0;
 
	padding: 12px 9px 7px 24px;
 
}
 
 
#header #header-inner #quick li ul li a.delete,#header #header-inner #quick li ul li a.delete:hover
 
	{
 
	background: #FFF url("../images/icons/delete.png") no-repeat 4px 9px;
 
	width: 167px;
 
	margin: 0;
 
	padding: 12px 9px 7px 24px;
 
}
 
 
#header #header-inner #quick li ul li a.branches,#header #header-inner #quick li ul li a.branches:hover
 
	{
 
	background: #FFF url("../images/icons/arrow_branch.png") no-repeat 4px
 
		9px;
 
	width: 167px;
 
	margin: 0;
 
	padding: 12px 9px 7px 24px;
 
}
 
 
#header #header-inner #quick li ul li a.tags,
 
#header #header-inner #quick li ul li a.tags:hover{
 
	background: #FFF url("../images/icons/tag_blue.png") no-repeat 4px 9px;
 
	width: 167px;
 
	margin: 0;
 
	padding: 12px 9px 7px 24px;
 
}
 
 
#header #header-inner #quick li ul li a.bookmarks,
 
#header #header-inner #quick li ul li a.bookmarks:hover{
 
    background: #FFF url("../images/icons/tag_green.png") no-repeat 4px 9px;
 
    width: 167px;
 
    margin: 0;
 
    padding: 12px 9px 7px 24px;
 
}
 
 
#header #header-inner #quick li ul li a.admin,
 
#header #header-inner #quick li ul li a.admin:hover{
 
	background: #FFF url("../images/icons/cog_edit.png") no-repeat 4px 9px;
 
	width: 167px;
 
	margin: 0;
 
	padding: 12px 9px 7px 24px;
 
}
 
 
.groups_breadcrumbs a {
 
	color: #fff;
 
}
 
 
.groups_breadcrumbs a:hover {
 
	color: #bfe3ff;
 
	text-decoration: none;
 
}
 
 
td.quick_repo_menu {
 
	background: #FFF url("../images/vertical-indicator.png") 8px 50% no-repeat !important;
 
	cursor: pointer;
 
	width: 8px;
 
	border: 1px solid transparent;
 
}
 
 
td.quick_repo_menu.active {
 
    background: url("../images/dt-arrow-dn.png") no-repeat scroll 5px 50% #FFFFFF !important;
 
    border: 1px solid #003367;
 
    box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2);
 
    cursor: pointer;
 
}
 
 
td.quick_repo_menu .menu_items {
 
	margin-top: 10px;
 
	margin-left:-6px;
 
	width: 150px;
 
	position: absolute;
 
	background-color: #FFF;
 
	background: none repeat scroll 0 0 #FFFFFF;
 
	border-color: #003367 #666666 #666666;
 
	border-right: 1px solid #666666;
 
	border-style: solid;
 
	border-width: 1px;
 
	box-shadow: 2px 8px 4px rgba(0, 0, 0, 0.2);
 
	border-top-style: none;
 
}
 
 
td.quick_repo_menu .menu_items li {
 
	padding: 0 !important;
 
}
 
 
td.quick_repo_menu .menu_items a {
 
	display: block;
 
	padding: 4px 12px 4px 8px;
 
}
 
 
td.quick_repo_menu .menu_items a:hover {
 
	background-color: #EEE;
 
	text-decoration: none;
 
}
 
 
td.quick_repo_menu .menu_items .icon img {
 
	margin-bottom: -2px;
 
}
 
 
td.quick_repo_menu .menu_items.hidden {
 
	display: none;
 
}
 
 
.yui-dt-first th {
 
	text-align: left;
 
}
 
 
/*
 
Copyright (c) 2011, Yahoo! Inc. All rights reserved.
 
Code licensed under the BSD License:
 
http://developer.yahoo.com/yui/license.html
 
version: 2.9.0
 
*/
 
.yui-skin-sam .yui-dt-mask {
 
    position: absolute;
 
    z-index: 9500;
 
}
 
.yui-dt-tmp {
 
    position: absolute;
 
    left: -9000px;
 
}
 
.yui-dt-scrollable .yui-dt-bd { overflow: auto }
 
.yui-dt-scrollable .yui-dt-hd {
 
    overflow: hidden;
 
    position: relative;
 
}
 
.yui-dt-scrollable .yui-dt-bd thead tr,
 
.yui-dt-scrollable .yui-dt-bd thead th {
 
    position: absolute;
 
    left: -1500px;
 
}
 
.yui-dt-scrollable tbody { -moz-outline: 0 }
 
.yui-skin-sam thead .yui-dt-sortable { cursor: pointer }
 
.yui-skin-sam thead .yui-dt-draggable { cursor: move }
 
.yui-dt-coltarget {
 
    position: absolute;
 
    z-index: 999;
 
}
 
.yui-dt-hd { zoom: 1 }
 
th.yui-dt-resizeable .yui-dt-resizerliner { position: relative }
 
.yui-dt-resizer {
 
    position: absolute;
 
    right: 0;
 
    bottom: 0;
 
    height: 100%;
 
    cursor: e-resize;
 
    cursor: col-resize;
 
    background-color: #CCC;
 
    opacity: 0;
 
    filter: alpha(opacity=0);
 
}
 
.yui-dt-resizerproxy {
 
    visibility: hidden;
 
    position: absolute;
 
    z-index: 9000;
 
    background-color: #CCC;
 
    opacity: 0;
 
    filter: alpha(opacity=0);
 
}
 
th.yui-dt-hidden .yui-dt-liner,
 
td.yui-dt-hidden .yui-dt-liner,
 
th.yui-dt-hidden .yui-dt-resizer { display: none }
 
.yui-dt-editor,
 
.yui-dt-editor-shim {
 
    position: absolute;
 
    z-index: 9000;
 
}
 
.yui-skin-sam .yui-dt table {
 
    margin: 0;
 
    padding: 0;
 
    font-family: arial;
 
    font-size: inherit;
 
    border-collapse: separate;
 
    *border-collapse: collapse;
 
    border-spacing: 0;
 
    border: 1px solid #7f7f7f;
 
}
 
.yui-skin-sam .yui-dt thead { border-spacing: 0 }
 
.yui-skin-sam .yui-dt caption {
 
    color: #000;
 
    font-size: 85%;
 
    font-weight: normal;
 
    font-style: italic;
 
    line-height: 1;
 
    padding: 1em 0;
 
    text-align: center;
 
}
 
.yui-skin-sam .yui-dt th { background: #d8d8da url(../images/sprite.png) repeat-x 0 0 }
 
.yui-skin-sam .yui-dt th,
 
.yui-skin-sam .yui-dt th a {
 
    font-weight: normal;
 
    text-decoration: none;
 
    color: #000;
 
    vertical-align: bottom;
 
}
 
.yui-skin-sam .yui-dt th {
 
    margin: 0;
 
    padding: 0;
 
    border: 0;
 
    border-right: 1px solid #cbcbcb;
 
}
 
.yui-skin-sam .yui-dt tr.yui-dt-first td { border-top: 1px solid #7f7f7f }
 
.yui-skin-sam .yui-dt th .yui-dt-liner { white-space: nowrap }
 
.yui-skin-sam .yui-dt-liner {
 
    margin: 0;
 
    padding: 0;
 
}
 
.yui-skin-sam .yui-dt-coltarget {
 
    width: 5px;
 
    background-color: red;
 
}
 
.yui-skin-sam .yui-dt td {
 
    margin: 0;
 
    padding: 0;
 
    border: 0;
 
    border-right: 1px solid #cbcbcb;
 
    text-align: left;
 
}
 
.yui-skin-sam .yui-dt-list td { border-right: 0 }
 
.yui-skin-sam .yui-dt-resizer { width: 6px }
 
.yui-skin-sam .yui-dt-mask {
 
    background-color: #000;
 
    opacity: .25;
 
    filter: alpha(opacity=25);
 
}
 
.yui-skin-sam .yui-dt-message { background-color: #FFF }
 
.yui-skin-sam .yui-dt-scrollable table { border: 0 }
 
.yui-skin-sam .yui-dt-scrollable .yui-dt-hd {
 
    border-left: 1px solid #7f7f7f;
 
    border-top: 1px solid #7f7f7f;
 
    border-right: 1px solid #7f7f7f;
 
}
 
.yui-skin-sam .yui-dt-scrollable .yui-dt-bd {
 
    border-left: 1px solid #7f7f7f;
 
    border-bottom: 1px solid #7f7f7f;
 
    border-right: 1px solid #7f7f7f;
 
    background-color: #FFF;
 
}
 
.yui-skin-sam .yui-dt-scrollable .yui-dt-data tr.yui-dt-last td { border-bottom: 1px solid #7f7f7f }
 
.yui-skin-sam th.yui-dt-asc,
 
.yui-skin-sam th.yui-dt-desc { background: url(../images/sprite.png) repeat-x 0 -100px }
 
.yui-skin-sam th.yui-dt-sortable .yui-dt-label { margin-right: 10px }
 
.yui-skin-sam th.yui-dt-asc .yui-dt-liner { background: url(../images/dt-arrow-up.png) no-repeat right }
 
.yui-skin-sam th.yui-dt-desc .yui-dt-liner { background: url(../images/dt-arrow-dn.png) no-repeat right }
 
tbody .yui-dt-editable { cursor: pointer }
 
.yui-dt-editor {
 
    text-align: left;
 
    background-color: #f2f2f2;
 
    border: 1px solid #808080;
 
    padding: 6px;
 
}
 
.yui-dt-editor label {
 
    padding-left: 4px;
 
    padding-right: 6px;
 
}
 
.yui-dt-editor .yui-dt-button {
 
    padding-top: 6px;
 
    text-align: right;
 
}
 
.yui-dt-editor .yui-dt-button button {
 
    background: url(../images/sprite.png) repeat-x 0 0;
 
    border: 1px solid #999;
 
    width: 4em;
 
    height: 1.8em;
 
    margin-left: 6px;
 
}
 
.yui-dt-editor .yui-dt-button button.yui-dt-default {
 
    background: url(../images/sprite.png) repeat-x 0 -1400px;
 
    background-color: #5584e0;
 
    border: 1px solid #304369;
 
    color: #FFF;
 
}
 
.yui-dt-editor .yui-dt-button button:hover {
 
    background: url(../images/sprite.png) repeat-x 0 -1300px;
 
    color: #000;
 
}
 
.yui-dt-editor .yui-dt-button button:active {
 
    background: url(../images/sprite.png) repeat-x 0 -1700px;
 
    color: #000;
 
}
 
.yui-skin-sam tr.yui-dt-even { background-color: #FFF }
 
.yui-skin-sam tr.yui-dt-odd { background-color: #edf5ff }
 
.yui-skin-sam tr.yui-dt-even td.yui-dt-asc,
 
.yui-skin-sam tr.yui-dt-even td.yui-dt-desc { background-color: #edf5ff }
 
.yui-skin-sam tr.yui-dt-odd td.yui-dt-asc,
 
.yui-skin-sam tr.yui-dt-odd td.yui-dt-desc { background-color: #dbeaff }
 
.yui-skin-sam .yui-dt-list tr.yui-dt-even { background-color: #FFF }
 
.yui-skin-sam .yui-dt-list tr.yui-dt-odd { background-color: #FFF }
 
.yui-skin-sam .yui-dt-list tr.yui-dt-even td.yui-dt-asc,
 
.yui-skin-sam .yui-dt-list tr.yui-dt-even td.yui-dt-desc { background-color: #edf5ff }
 
.yui-skin-sam .yui-dt-list tr.yui-dt-odd td.yui-dt-asc,
 
.yui-skin-sam .yui-dt-list tr.yui-dt-odd td.yui-dt-desc { background-color: #edf5ff }
 
.yui-skin-sam th.yui-dt-highlighted,
 
.yui-skin-sam th.yui-dt-highlighted a { background-color: #b2d2ff }
 
.yui-skin-sam tr.yui-dt-highlighted,
 
.yui-skin-sam tr.yui-dt-highlighted td.yui-dt-asc,
 
.yui-skin-sam tr.yui-dt-highlighted td.yui-dt-desc,
 
.yui-skin-sam tr.yui-dt-even td.yui-dt-highlighted,
 
.yui-skin-sam tr.yui-dt-odd td.yui-dt-highlighted {
 
    cursor: pointer;
 
    background-color: #b2d2ff;
 
}
 
.yui-skin-sam .yui-dt-list th.yui-dt-highlighted,
 
.yui-skin-sam .yui-dt-list th.yui-dt-highlighted a { background-color: #b2d2ff }
 
.yui-skin-sam .yui-dt-list tr.yui-dt-highlighted,
 
.yui-skin-sam .yui-dt-list tr.yui-dt-highlighted td.yui-dt-asc,
 
.yui-skin-sam .yui-dt-list tr.yui-dt-highlighted td.yui-dt-desc,
 
.yui-skin-sam .yui-dt-list tr.yui-dt-even td.yui-dt-highlighted,
 
.yui-skin-sam .yui-dt-list tr.yui-dt-odd td.yui-dt-highlighted {
rhodecode/templates/admin/defaults/defaults.html
Show inline comments
 
new file 100644
 
## -*- coding: utf-8 -*-
 
<%inherit file="/base/base.html"/>
 

	
 
<%def name="title()">
 
    ${_('Repositories defaults')} - ${c.rhodecode_name}
 
</%def>
 

	
 
<%def name="breadcrumbs_links()">
 
    ${h.link_to(_('Admin'),h.url('admin_home'))}
 
    &raquo;
 
    ${_('Defaults')}
 
</%def>
 

	
 
<%def name="page_nav()">
 
	${self.menu('admin')}
 
</%def>
 

	
 
<%def name="main()">
 
<div class="box">
 
    <!-- box / title -->
 
    <div class="title">
 
        ${self.breadcrumbs()}
 
    </div>
 
    
 
    <h3>${_('Repositories defaults')}</h3>
 

	
 
    ${h.form(url('default', id='defaults'),method='put')}
 
    <div class="form">
 
        <!-- fields -->
 

	
 
        <div class="fields">
 
        
 
            <div class="field">
 
                <div class="label">
 
                    <label for="default_repo_type">${_('Type')}:</label>
 
                </div>
 
                <div class="input">
 
                    ${h.select('default_repo_type','hg',c.backends,class_="medium")}
 
                </div>
 
            </div>        
 

	
 
            <div class="field">
 
                <div class="label label-checkbox">
 
                    <label for="default_repo_private">${_('Private repository')}:</label>
 
                </div>
 
                <div class="checkboxes">
 
                    ${h.checkbox('default_repo_private',value="True")}
 
                    <span class="help-block">${_('Private repositories are only visible to people explicitly added as collaborators.')}</span>
 
                </div>
 
            </div>
 

	
 

	
 
            <div class="field">
 
                <div class="label label-checkbox">
 
                    <label for="default_repo_enable_statistics">${_('Enable statistics')}:</label>
 
                </div>
 
                <div class="checkboxes">
 
                    ${h.checkbox('default_repo_enable_statistics',value="True")}
 
                    <span class="help-block">${_('Enable statistics window on summary page.')}</span>
 
                </div>
 
            </div>
 

	
 
            <div class="field">
 
                <div class="label label-checkbox">
 
                    <label for="default_repo_enable_downloads">${_('Enable downloads')}:</label>
 
                </div>
 
                <div class="checkboxes">
 
                    ${h.checkbox('default_repo_enable_downloads',value="True")}
 
                    <span class="help-block">${_('Enable download menu on summary page.')}</span>
 
                </div>
 
            </div>
 

	
 
            <div class="field">
 
                <div class="label label-checkbox">
 
                    <label for="default_repo_enable_locking">${_('Enable locking')}:</label>
 
                </div>
 
                <div class="checkboxes">
 
                    ${h.checkbox('default_repo_enable_locking',value="True")}
 
                    <span class="help-block">${_('Enable lock-by-pulling on repository.')}</span>
 
                </div>
 
            </div>
 

	
 
            <div class="buttons">
 
            ${h.submit('save',_('Save'),class_="ui-btn large")}
 
            </div>
 
        </div>
 
    </div>
 
    ${h.end_form()}
 
    
 
    ##<h3>${_('Groups defaults')}</h3>
 
    
 
</div>
 
</%def>
rhodecode/templates/admin/repos/repo_add_base.html
Show inline comments
 
## -*- coding: utf-8 -*-
 

	
 
${h.form(url('repos'))}
 
<div class="form">
 
    <!-- fields -->
 
    <div class="fields">
 
        <div class="field">
 
            <div class="label">
 
                <label for="repo_name">${_('Name')}:</label>
 
            </div>
 
            <div class="input">
 
                ${h.text('repo_name',c.new_repo,class_="small")}
 
                %if not h.HasPermissionAll('hg.admin')('repo create form'):
 
                    ${h.hidden('user_created',True)}
 
                %endif
 
                %endif                
 
            </div>
 
         </div>
 
        <div class="field">
 
            <div class="label">
 
                <label for="clone_uri">${_('Clone from')}:</label>
 
            </div>
 
            <div class="input">
 
                ${h.text('clone_uri',class_="small")}
 
                <span class="help-block">${_('Optional http[s] url from which repository should be cloned.')}</span>
 
            </div>
 
         </div>
 
         <div class="field">
 
             <div class="label">
 
                 <label for="repo_group">${_('Repository group')}:</label>
 
             </div>
 
             <div class="input">
 
                 ${h.select('repo_group',request.GET.get('parent_group'),c.repo_groups,class_="medium")}
 
                 <span class="help-block">${_('Optionaly select a group to put this repository into.')}</span>
 
             </div>
 
         </div>
 
        <div class="field">
 
            <div class="label">
 
                <label for="repo_type">${_('Type')}:</label>
 
            </div>
 
            <div class="input">
 
                ${h.select('repo_type','hg',c.backends,class_="small")}
 
                <span class="help-block">${_('Type of repository to create.')}</span>
 
            </div>
 
         </div>
 
         <div class="field">
 
            <div class="label">
 
                <label for="landing_rev">${_('Landing revision')}:</label>
 
                <label for="repo_landing_rev">${_('Landing revision')}:</label>
 
            </div>
 
            <div class="input">
 
                ${h.select('landing_rev','',c.landing_revs,class_="medium")}
 
                ${h.select('repo_landing_rev','',c.landing_revs,class_="medium")}
 
                <span class="help-block">${_('Default revision for files page, downloads, whoosh and readme')}</span>
 
            </div>
 
        </div>
 
        <div class="field">
 
            <div class="label label-textarea">
 
                <label for="description">${_('Description')}:</label>
 
                <label for="repo_description">${_('Description')}:</label>
 
            </div>
 
            <div class="textarea text-area editor">
 
                ${h.textarea('description')}
 
                ${h.textarea('repo_description')}
 
                <span class="help-block">${_('Keep it short and to the point. Use a README file for longer descriptions.')}</span>
 
            </div>
 
         </div>
 
        <div class="field">
 
            <div class="label label-checkbox">
 
                <label for="private">${_('Private repository')}:</label>
 
                <label for="repo_private">${_('Private repository')}:</label>
 
            </div>
 
            <div class="checkboxes">
 
                ${h.checkbox('private',value="True")}
 
                ${h.checkbox('repo_private',value="True")}
 
                <span class="help-block">${_('Private repositories are only visible to people explicitly added as collaborators.')}</span>
 
            </div>
 
         </div>
 
        <div class="buttons">
 
          ${h.submit('add',_('add'),class_="ui-btn large")}
 
        </div>
 
    </div>
 
</div>
 
${h.end_form()}
rhodecode/templates/base/base.html
Show inline comments
 
## -*- coding: utf-8 -*-
 
<%inherit file="root.html"/>
 

	
 
<!-- HEADER -->
 
<div id="header">
 
    <div id="header-inner" class="title hover">
 
        <div id="logo">
 
            <h1><a href="${h.url('home')}">${c.rhodecode_name}</a></h1>
 
        </div>
 
        <!-- MENU -->
 
        ${self.page_nav()}
 
        <!-- END MENU -->
 
        ${self.body()}
 
    </div>
 
</div>
 
<!-- END HEADER -->
 

	
 
<!-- CONTENT -->
 
<div id="content">
 
    <div class="flash_msg">
 
        <% messages = h.flash.pop_messages() %>
 
        % if messages:
 
        <ul id="flash-messages">
 
            % for message in messages:
 
            <li class="${message.category}_msg">${message}</li>
 
            % endfor
 
        </ul>
 
        % endif
 
    </div>
 
    <div id="main">
 
        ${next.main()}
 
    </div>
 
</div>
 
<!-- END CONTENT -->
 

	
 
<!-- FOOTER -->
 
<div id="footer">
 
   <div id="footer-inner" class="title">
 
       <div>
 
           <p class="footer-link">
 
                <a href="${h.url('bugtracker')}">${_('Submit a bug')}</a>
 
           </p>
 
	       <p class="footer-link-right">
 
	           <a href="${h.url('rhodecode_official')}">RhodeCode${'-%s' % c.rhodecode_instanceid if c.rhodecode_instanceid else ''}</a>
 
	           ${c.rhodecode_version} &copy; 2010-${h.datetime.today().year} by Marcin Kuzminski
 
	       </p>
 
       </div>
 
   </div>
 
</div>
 
<!-- END FOOTER -->
 

	
 
### MAKO DEFS ###
 
<%def name="page_nav()">
 
    ${self.menu()}
 
</%def>
 

	
 
<%def name="breadcrumbs()">
 
    <div class="breadcrumbs">
 
    ${self.breadcrumbs_links()}
 
    </div>
 
</%def>
 

	
 
<%def name="usermenu()">
 
  <div class="user-menu">
 
      <div class="container">
 
       <div class="gravatar" id="quick_login_link">
 
           <img alt="gravatar" src="${h.gravatar_url(c.rhodecode_user.email,24)}" />
 
       </div>
 
       %if c.rhodecode_user.username != 'default' and c.unread_notifications != 0:
 
        <div class="notifications">
 
          <a id="notification_counter" href="${h.url('notifications')}">${c.unread_notifications}</a>
 
        </div>
 
       %endif
 
      </div>
 
      <div id="quick_login" style="display:none">
 
        %if c.rhodecode_user.username == 'default':
 
            <h4>${_('Login to your account')}</h4>
 
            ${h.form(h.url('login_home',came_from=h.url.current()))}
 
            <div class="form">
 
                <div class="fields">
 
                    <div class="field">
 
                        <div class="label">
 
                            <label for="username">${_('Username')}:</label>
 
                        </div>
 
                        <div class="input">
 
                            ${h.text('username',class_='focus',size=40)}
 
                        </div>
 

	
 
                    </div>
 
                    <div class="field">
 
                        <div class="label">
 
                            <label for="password">${_('Password')}:</label>
 
                        </div>
 
                        <div class="input">
 
                            ${h.password('password',class_='focus',size=40)}
 
                        </div>
 

	
 
                    </div>
 
                    <div class="buttons">
 
                        <div class="password_forgoten">${h.link_to(_('Forgot password ?'),h.url('reset_password'))}</div>
 
                        <div class="register">
 
                        %if h.HasPermissionAny('hg.admin', 'hg.register.auto_activate', 'hg.register.manual_activate')():
 
                         ${h.link_to(_("Don't have an account ?"),h.url('register'))}
 
                        %endif
 
                        </div>
 
                        <div class="submit">
 
                            ${h.submit('sign_in',_('Log In'),class_="ui-btn xsmall")}
 
                        </div>
 
                    </div>
 
                </div>
 
            </div>
 
            ${h.end_form()}
 
        %else:
 
            <div class="links_left">
 
                <div class="full_name">${c.rhodecode_user.full_name_or_username}</div>
 
                <div class="email">${c.rhodecode_user.email}</div>
 
                <div class="big_gravatar"><img alt="gravatar" src="${h.gravatar_url(c.rhodecode_user.email,48)}" /></div>
 
                <div class="inbox"><a href="${h.url('notifications')}">${_('Inbox')}: ${c.unread_notifications}</a></div>
 
            </div>
 
            <div class="links_right">
 
            <ol class="links">
 
              <li>${h.link_to(_(u'Home'),h.url('home'))}</li>
 
              <li>${h.link_to(_(u'Journal'),h.url('journal'))}</li>
 
              <li>${h.link_to(_(u'My account'),h.url('admin_settings_my_account'))}</li>
 
              <li class="logout">${h.link_to(_(u'Log Out'),h.url('logout_home'))}</li>
 
            </ol>
 
            </div>
 
        %endif
 
      </div>
 
 </div>
 
</%def>
 

	
 
<%def name="menu(current=None)">
 
		<%
 
		def is_current(selected):
 
			if selected == current:
 
				return h.literal('class="current"')
 
		%>
 
		%if current not in ['home','admin']:
 
		   ##REGULAR MENU
 
	        <ul id="quick">
 
				<!-- repo switcher -->
 
				<li>
 
					<a class="menu_link" id="repo_switcher" title="${_('Switch repository')}" href="#">
 
                    <span class="icon">
 
                        <img src="${h.url('/images/icons/database.png')}" alt="${_('Products')}" />
 
                    </span>
 
                    <span>&darr;</span>
 
					</a>
 
					<ul id="repo_switcher_list" class="repo_switcher">
 
                        <li>
 
                            <a href="#">${_('loading...')}</a>
 
                        </li>
 
					</ul>
 
				</li>
 

	
 
	            <li ${is_current('summary')}>
 
	               <a class="menu_link" title="${_('Summary')}" href="${h.url('summary_home',repo_name=c.repo_name)}">
 
	               <span class="icon">
 
	                   <img src="${h.url('/images/icons/clipboard_16.png')}" alt="${_('Summary')}" />
 
	               </span>
 
	               <span>${_('Summary')}</span>
 
	               </a>
 
	            </li>
 
                <li ${is_current('changelog')}>
 
                   <a class="menu_link" title="${_('Changelog')}" href="${h.url('changelog_home',repo_name=c.repo_name)}">
 
                   <span class="icon">
 
                       <img src="${h.url('/images/icons/time.png')}" alt="${_('Changelog')}" />
 
                   </span>
 
                   <span>${_('Changelog')}</span>
 
                   </a>
 
                </li>
 

	
 
                <li ${is_current('switch_to')}>
 
                   <a class="menu_link" id="branch_tag_switcher" title="${_('Switch to')}" href="#">
 
                   <span class="icon">
 
                       <img src="${h.url('/images/icons/arrow_switch.png')}" alt="${_('Switch to')}" />
 
                   </span>
 
                   <span>${_('Switch to')}</span>
 
                   </a>
 
                    <ul id="switch_to_list" class="switch_to">
 
                        <li><a href="#">${_('loading...')}</a></li>
 
                    </ul>
 
                </li>
 
                <li ${is_current('files')}>
 
                   <a class="menu_link" title="${_('Files')}" href="${h.url('files_home',repo_name=c.repo_name)}">
 
                   <span class="icon">
 
                       <img src="${h.url('/images/icons/file.png')}" alt="${_('Files')}" />
 
                   </span>
 
                   <span>${_('Files')}</span>
 
                   </a>
 
                </li>
 

	
 
                <li ${is_current('options')}>
 
                   <a class="menu_link" title="${_('Options')}" href="#">
 
                   <span class="icon">
 
                       <img src="${h.url('/images/icons/table_gear.png')}" alt="${_('Admin')}" />
 
                   </span>
 
                   <span>${_('Options')}</span>
 
                   </a>
 
                   <ul>
 
                   %if h.HasRepoPermissionAll('repository.admin')(c.repo_name):
 
                     %if h.HasPermissionAll('hg.admin')('access settings on repository'):
 
                         <li>${h.link_to(_('repository settings'),h.url('edit_repo',repo_name=c.repo_name),class_='settings')}</li>
 
                     %else:
 
                         <li>${h.link_to(_('repository settings'),h.url('repo_settings_home',repo_name=c.repo_name),class_='settings')}</li>
 
                     %endif
 
                   %endif
 

	
 
                   	<li>${h.link_to(_('fork'),h.url('repo_fork_home',repo_name=c.repo_name),class_='fork')}</li>
 
                    %if h.is_hg(c.rhodecode_repo):
 
                     <li>${h.link_to(_('Open new pull request'),h.url('pullrequest_home',repo_name=c.repo_name),class_='pull_request')}</li>
 
                    %endif
 
                    %if c.rhodecode_db_repo.fork:
 
                     <li>${h.link_to(_('Compare fork'),h.url('compare_url',repo_name=c.repo_name,org_ref_type='branch',org_ref=request.GET.get('branch') or 'default',other_ref_type='branch',other_ref='default',repo=c.rhodecode_db_repo.fork.repo_name),class_='compare_request')}</li>
 
                    %endif
 
                   	<li>${h.link_to(_('search'),h.url('search_repo',search_repo=c.repo_name),class_='search')}</li>
 

	
 
                    %if h.HasRepoPermissionAny('repository.write','repository.admin')(c.repo_name) and c.rhodecode_db_repo.enable_locking:
 
                      %if c.rhodecode_db_repo.locked[0]:
 
                        <li>${h.link_to(_('unlock'), h.url('toggle_locking',repo_name=c.repo_name),class_='locking_del')}</li>
 
                      %else:
 
                        <li>${h.link_to(_('lock'), h.url('toggle_locking',repo_name=c.repo_name),class_='locking_add')}</li>
 
                      %endif
 
                    %endif
 

	
 
                    % if h.HasPermissionAll('hg.admin')('access admin main page'):
 
                     <li>
 
                       ${h.link_to(_('admin'),h.url('admin_home'),class_='admin')}
 
                        <%def name="admin_menu()">
 
                        <ul>
 
                            <li>${h.link_to(_('journal'),h.url('admin_home'),class_='journal')}</li>
 
                            <li>${h.link_to(_('repositories'),h.url('repos'),class_='repos')}</li>
 
                            <li>${h.link_to(_('repositories groups'),h.url('repos_groups'),class_='repos_groups')}</li>
 
                            <li>${h.link_to(_('users'),h.url('users'),class_='users')}</li>
 
                            <li>${h.link_to(_('users groups'),h.url('users_groups'),class_='groups')}</li>
 
                            <li>${h.link_to(_('permissions'),h.url('edit_permission',id='default'),class_='permissions')}</li>
 
                            <li>${h.link_to(_('ldap'),h.url('ldap_home'),class_='ldap')}</li>
 
                            <li>${h.link_to(_('defaults'),h.url('defaults'),class_='defaults')}</li>
 
                            <li class="last">${h.link_to(_('settings'),h.url('admin_settings'),class_='settings')}</li>
 
                        </ul>
 
                        </%def>
 
                        ## ADMIN MENU
 
                        ${admin_menu()}
 
                     </li>
 
                    % endif
 
                   </ul>
 
                </li>
 

	
 
                <li>
 
                    <a class="menu_link" title="${_('Followers')}" href="${h.url('repo_followers_home',repo_name=c.repo_name)}">
 
                    <span class="icon_short">
 
                        <img src="${h.url('/images/icons/heart.png')}" alt="${_('Followers')}" />
 
                    </span>
 
                    <span id="current_followers_count" class="short">${c.repository_followers}</span>
 
                    </a>
 
                </li>
 
                <li>
 
                    <a class="menu_link" title="${_('Forks')}" href="${h.url('repo_forks_home',repo_name=c.repo_name)}">
 
                    <span class="icon_short">
 
                        <img src="${h.url('/images/icons/arrow_divide.png')}" alt="${_('Forks')}" />
 
                    </span>
 
                    <span class="short">${c.repository_forks}</span>
 
                    </a>
 
                </li>
 
                <li>
 
                    <a class="menu_link" title="${_('Pull requests')}" href="${h.url('pullrequest_show_all',repo_name=c.repo_name)}">
 
                    <span class="icon_short">
 
                        <img src="${h.url('/images/icons/arrow_join.png')}" alt="${_('Pull requests')}" />
 
                    </span>
 
                    <span class="short">${c.repository_pull_requests}</span>
 
                    </a>
 
                </li>
 
                ${usermenu()}
 
	        </ul>
 
            <script type="text/javascript">
 
               YUE.on('repo_switcher','mouseover',function(){
 
                      function qfilter(){
 
                          var nodes = YUQ('ul#repo_switcher_list li a.repo_name');
 
                          var target = 'q_filter_rs';
 
                          var func = function(node){
 
                              return node.parentNode;
 
                          }
 
                          q_filter(target,nodes,func);
 
                      }
 
                   var loaded = YUD.hasClass('repo_switcher','loaded');
 
                   if(!loaded){
 
                       YUD.addClass('repo_switcher','loaded');
 
                       ypjax("${h.url('repo_switcher')}",'repo_switcher_list',
 
                           function(o){qfilter();},
 
                           function(o){YUD.removeClass('repo_switcher','loaded');}
 
                           ,null);
 
                   }
 
                   return false;
 
               });
 

	
 
              YUE.on('branch_tag_switcher','mouseover',function(){
 
                 var loaded = YUD.hasClass('branch_tag_switcher','loaded');
 
                 if(!loaded){
 
                     YUD.addClass('branch_tag_switcher','loaded');
 
                     ypjax("${h.url('branch_tag_switcher',repo_name=c.repo_name)}",'switch_to_list',
 
                         function(o){},
 
                         function(o){YUD.removeClass('branch_tag_switcher','loaded');}
 
                         ,null);
 
                 }
 
                 return false;
 
              });
 
            </script>
 
		%else:
 
		    ##ROOT MENU
 
            <ul id="quick">
 
                <li>
 
                    <a class="menu_link" title="${_('Home')}"  href="${h.url('home')}">
 
                    <span class="icon">
 
                        <img src="${h.url('/images/icons/home_16.png')}" alt="${_('Home')}" />
 
                    </span>
 
                    <span>${_('Home')}</span>
 
                    </a>
 
                </li>
 
                %if c.rhodecode_user.username != 'default':
 
                 <li>
 
                    <a class="menu_link" title="${_('Journal')}"  href="${h.url('journal')}">
 
                    <span class="icon">
 
                        <img src="${h.url('/images/icons/book.png')}" alt="${_('Journal')}" />
 
                    </span>
 
                    <span>${_('Journal')}</span>
 
                    </a>
 
                 </li>
 
                %else:
 
                 <li>
 
                    <a class="menu_link" title="${_('Public journal')}"  href="${h.url('public_journal')}">
 
                    <span class="icon">
 
                        <img src="${h.url('/images/icons/book.png')}" alt="${_('Public journal')}" />
 
                    </span>
 
                    <span>${_('Public journal')}</span>
 
                    </a>
 
                 </li>
 
                %endif
 
                <li>
 
                    <a class="menu_link" title="${_('Search')}"  href="${h.url('search')}">
 
                    <span class="icon">
 
                        <img src="${h.url('/images/icons/search_16.png')}" alt="${_('Search')}" />
 
                    </span>
 
                    <span>${_('Search')}</span>
 
                    </a>
 
                </li>
 

	
 
				%if h.HasPermissionAll('hg.admin')('access admin main page'):
 
                <li ${is_current('admin')}>
 
                   <a class="menu_link" title="${_('Admin')}" href="${h.url('admin_home')}">
 
                   <span class="icon">
 
                       <img src="${h.url('/images/icons/cog_edit.png')}" alt="${_('Admin')}" />
 
                   </span>
 
                   <span>${_('Admin')}</span>
 
                   </a>
 
                    ${admin_menu()}
 
                </li>
 
				%endif
 
                ${usermenu()}
 
			</ul>
 
		%endif
 
</%def>
rhodecode/tests/__init__.py
Show inline comments
 
"""Pylons application test package
 

	
 
This package assumes the Pylons environment is already loaded, such as
 
when this script is imported from the `nosetests --with-pylons=test.ini`
 
command.
 

	
 
This module initializes the application via ``websetup`` (`paster
 
setup-app`) and provides the base testing objects.
 
"""
 
import os
 
import time
 
import logging
 
import datetime
 
import hashlib
 
import tempfile
 
from os.path import join as jn
 

	
 
from unittest import TestCase
 
from tempfile import _RandomNameSequence
 

	
 
from paste.deploy import loadapp
 
from paste.script.appinstall import SetupCommand
 
from pylons import config, url
 
from routes.util import URLGenerator
 
from webtest import TestApp
 

	
 
from rhodecode import is_windows
 
from rhodecode.model.meta import Session
 
from rhodecode.model.db import User
 
from rhodecode.tests.nose_parametrized import parameterized
 

	
 
import pylons.test
 

	
 

	
 
os.environ['TZ'] = 'UTC'
 
if not is_windows:
 
    time.tzset()
 

	
 
log = logging.getLogger(__name__)
 

	
 
__all__ = [
 
    'parameterized', 'environ', 'url', 'get_new_dir', 'TestController',
 
    'TESTS_TMP_PATH', 'HG_REPO', 'GIT_REPO', 'NEW_HG_REPO', 'NEW_GIT_REPO',
 
    'HG_FORK', 'GIT_FORK', 'TEST_USER_ADMIN_LOGIN', 'TEST_USER_ADMIN_PASS',
 
    'TEST_USER_REGULAR_LOGIN', 'TEST_USER_REGULAR_PASS',
 
    'TEST_USER_REGULAR_EMAIL', 'TEST_USER_REGULAR2_LOGIN',
 
    'TEST_USER_REGULAR2_PASS', 'TEST_USER_REGULAR2_EMAIL', 'TEST_HG_REPO',
 
    'TEST_HG_REPO_CLONE', 'TEST_HG_REPO_PULL', 'TEST_GIT_REPO',
 
    'TEST_GIT_REPO_CLONE', 'TEST_GIT_REPO_PULL', 'HG_REMOTE_REPO',
 
    'GIT_REMOTE_REPO', 'SCM_TESTS',
 
    'GIT_REMOTE_REPO', 'SCM_TESTS', '_get_repo_create_params'
 
]
 

	
 
# Invoke websetup with the current config file
 
# SetupCommand('setup-app').run([config_file])
 

	
 
##RUNNING DESIRED TESTS
 
# nosetests -x rhodecode.tests.functional.test_admin_settings:TestSettingsController.test_my_account
 
# nosetests --pdb --pdb-failures
 
# nosetests --with-coverage --cover-package=rhodecode.model.validators rhodecode.tests.test_validators
 
environ = {}
 

	
 
#SOME GLOBALS FOR TESTS
 

	
 
TESTS_TMP_PATH = jn('/', 'tmp', 'rc_test_%s' % _RandomNameSequence().next())
 
TEST_USER_ADMIN_LOGIN = 'test_admin'
 
TEST_USER_ADMIN_PASS = 'test12'
 
TEST_USER_ADMIN_EMAIL = 'test_admin@mail.com'
 

	
 
TEST_USER_REGULAR_LOGIN = 'test_regular'
 
TEST_USER_REGULAR_PASS = 'test12'
 
TEST_USER_REGULAR_EMAIL = 'test_regular@mail.com'
 

	
 
TEST_USER_REGULAR2_LOGIN = 'test_regular2'
 
TEST_USER_REGULAR2_PASS = 'test12'
 
TEST_USER_REGULAR2_EMAIL = 'test_regular2@mail.com'
 

	
 
HG_REPO = 'vcs_test_hg'
 
GIT_REPO = 'vcs_test_git'
 

	
 
NEW_HG_REPO = 'vcs_test_hg_new'
 
NEW_GIT_REPO = 'vcs_test_git_new'
 

	
 
HG_FORK = 'vcs_test_hg_fork'
 
GIT_FORK = 'vcs_test_git_fork'
 

	
 
## VCS
 
SCM_TESTS = ['hg', 'git']
 
uniq_suffix = str(int(time.mktime(datetime.datetime.now().timetuple())))
 

	
 
GIT_REMOTE_REPO = 'git://github.com/codeinn/vcs.git'
 

	
 
TEST_GIT_REPO = jn(TESTS_TMP_PATH, GIT_REPO)
 
TEST_GIT_REPO_CLONE = jn(TESTS_TMP_PATH, 'vcsgitclone%s' % uniq_suffix)
 
TEST_GIT_REPO_PULL = jn(TESTS_TMP_PATH, 'vcsgitpull%s' % uniq_suffix)
 

	
 

	
 
HG_REMOTE_REPO = 'http://bitbucket.org/marcinkuzminski/vcs'
 

	
 
TEST_HG_REPO = jn(TESTS_TMP_PATH, HG_REPO)
 
TEST_HG_REPO_CLONE = jn(TESTS_TMP_PATH, 'vcshgclone%s' % uniq_suffix)
 
TEST_HG_REPO_PULL = jn(TESTS_TMP_PATH, 'vcshgpull%s' % uniq_suffix)
 

	
 
TEST_DIR = tempfile.gettempdir()
 
TEST_REPO_PREFIX = 'vcs-test'
 

	
 
# cached repos if any !
 
# comment out to get some other repos from bb or github
 
GIT_REMOTE_REPO = jn(TESTS_TMP_PATH, GIT_REPO)
 
HG_REMOTE_REPO = jn(TESTS_TMP_PATH, HG_REPO)
 

	
 

	
 
def get_new_dir(title):
 
    """
 
    Returns always new directory path.
 
    """
 
    from rhodecode.tests.vcs.utils import get_normalized_path
 
    name = TEST_REPO_PREFIX
 
    if title:
 
        name = '-'.join((name, title))
 
    hex = hashlib.sha1(str(time.time())).hexdigest()
 
    name = '-'.join((name, hex))
 
    path = os.path.join(TEST_DIR, name)
 
    return get_normalized_path(path)
 

	
 

	
 
class TestController(TestCase):
 

	
 
    def __init__(self, *args, **kwargs):
 
        wsgiapp = pylons.test.pylonsapp
 
        config = wsgiapp.config
 

	
 
        self.app = TestApp(wsgiapp)
 
        url._push_object(URLGenerator(config['routes.map'], environ))
 
        self.Session = Session
 
        self.index_location = config['app_conf']['index_dir']
 
        TestCase.__init__(self, *args, **kwargs)
 

	
 
    def log_user(self, username=TEST_USER_ADMIN_LOGIN,
 
                 password=TEST_USER_ADMIN_PASS):
 
        self._logged_username = username
 
        response = self.app.post(url(controller='login', action='index'),
 
                                 {'username': username,
 
                                  'password': password})
 

	
 
        if 'invalid user name' in response.body:
 
            self.fail('could not login using %s %s' % (username, password))
 

	
 
        self.assertEqual(response.status, '302 Found')
 
        ses = response.session['rhodecode_user']
 
        self.assertEqual(ses.get('username'), username)
 
        response = response.follow()
 
        self.assertEqual(ses.get('is_authenticated'), True)
 

	
 
        return response.session['rhodecode_user']
 

	
 
    def _get_logged_user(self):
 
        return User.get_by_username(self._logged_username)
 

	
 
    def checkSessionFlash(self, response, msg):
 
        self.assertTrue('flash' in response.session)
 
        if not msg in response.session['flash'][0][1]:
 
            self.fail(
 
                'msg `%s` not found in session flash: got `%s` instead' % (
 
                      msg, response.session['flash'])
 
            )
 

	
 

	
 
## HELPERS ##
 

	
 
def _get_repo_create_params(**custom):
 
    defs = {
 
        'repo_name': None,
 
        'repo_type': 'hg',
 
        'clone_uri': '',
 
        'repo_group': '',
 
        'repo_description': 'DESC',
 
        'repo_private': False,
 
        'repo_landing_rev': 'tip'
 
    }
 
    defs.update(custom)
 
    if 'repo_name_full' not in custom:
 
        defs.update({'repo_name_full': defs['repo_name']})
 

	
 
    return defs
 

	
 

	
rhodecode/tests/api/api_base.py
Show inline comments
 
from __future__ import with_statement
 
import random
 
import mock
 

	
 
from rhodecode.tests import *
 
from rhodecode.lib.compat import json
 
from rhodecode.lib.auth import AuthUser
 
from rhodecode.model.user import UserModel
 
from rhodecode.model.users_group import UsersGroupModel
 
from rhodecode.model.repo import RepoModel
 
from rhodecode.model.meta import Session
 
from rhodecode.model.scm import ScmModel
 
from rhodecode.model.db import Repository
 

	
 
API_URL = '/_admin/api'
 

	
 

	
 
def _build_data(apikey, method, **kw):
 
    """
 
    Builds API data with given random ID
 

	
 
    :param random_id:
 
    :type random_id:
 
    """
 
    random_id = random.randrange(1, 9999)
 
    return random_id, json.dumps({
 
        "id": random_id,
 
        "api_key": apikey,
 
        "method": method,
 
        "args": kw
 
    })
 

	
 
jsonify = lambda obj: json.loads(json.dumps(obj))
 

	
 

	
 
def crash(*args, **kwargs):
 
    raise Exception('Total Crash !')
 

	
 

	
 
def api_call(test_obj, params):
 
    response = test_obj.app.post(API_URL, content_type='application/json',
 
                                 params=params)
 
    return response
 

	
 

	
 
TEST_USERS_GROUP = 'test_users_group'
 

	
 

	
 
def make_users_group(name=TEST_USERS_GROUP):
 
    gr = UsersGroupModel().create(name=name)
 
    UsersGroupModel().add_user_to_group(users_group=gr,
 
                                        user=TEST_USER_ADMIN_LOGIN)
 
    Session().commit()
 
    return gr
 

	
 

	
 
def destroy_users_group(name=TEST_USERS_GROUP):
 
    UsersGroupModel().delete(users_group=name, force=True)
 
    Session().commit()
 

	
 

	
 
def create_repo(repo_name, repo_type):
 
    # create new repo
 
    form_data = dict(repo_name=repo_name,
 
                     repo_name_full=repo_name,
 
                     fork_name=None,
 
                     description='description %s' % repo_name,
 
                     repo_group=None,
 
                     private=False,
 
                     repo_type=repo_type,
 
                     clone_uri=None,
 
                     landing_rev='tip')
 
    form_data = _get_repo_create_params(
 
                    repo_name_full=repo_name,
 
                    repo_description='description %s' % repo_name,
 
                )
 
    cur_user = UserModel().get_by_username(TEST_USER_ADMIN_LOGIN)
 
    r = RepoModel().create(form_data, cur_user)
 
    Session().commit()
 
    return r
 

	
 

	
 
def create_fork(fork_name, fork_type, fork_of):
 
    fork = RepoModel(Session())._get_repo(fork_of)
 
    r = create_repo(fork_name, fork_type)
 
    r.fork = fork
 
    Session().add(r)
 
    Session().commit()
 
    return r
 

	
 

	
 
def destroy_repo(repo_name):
 
    RepoModel().delete(repo_name)
 
    Session().commit()
 

	
 

	
 
class BaseTestApi(object):
 
    REPO = None
 
    REPO_TYPE = None
 

	
 
    @classmethod
 
    def setUpClass(self):
 
        self.usr = UserModel().get_by_username(TEST_USER_ADMIN_LOGIN)
 
        self.apikey = self.usr.api_key
 
        self.TEST_USER = UserModel().create_or_update(
 
            username='test-api',
 
            password='test',
 
            email='test@api.rhodecode.org',
 
            firstname='first',
 
            lastname='last'
 
        )
 
        Session().commit()
 
        self.TEST_USER_LOGIN = self.TEST_USER.username
 

	
 
    @classmethod
 
    def teardownClass(self):
 
        pass
 

	
 
    def setUp(self):
 
        self.maxDiff = None
 
        make_users_group()
 

	
 
    def tearDown(self):
 
        destroy_users_group()
 

	
 
    def _compare_ok(self, id_, expected, given):
 
        expected = jsonify({
 
            'id': id_,
 
            'error': None,
 
            'result': expected
 
        })
 
        given = json.loads(given)
 
        self.assertEqual(expected, given)
 

	
 
    def _compare_error(self, id_, expected, given):
 
        expected = jsonify({
 
            'id': id_,
 
            'error': expected,
 
            'result': None
 
        })
 
        given = json.loads(given)
 
        self.assertEqual(expected, given)
 

	
 
#    def test_Optional(self):
 
#        from rhodecode.controllers.api.api import Optional
 
#        option1 = Optional(None)
 
#        self.assertEqual('<Optional:%s>' % None, repr(option1))
 
#
 
#        self.assertEqual(1, Optional.extract(Optional(1)))
 
#        self.assertEqual('trololo', Optional.extract('trololo'))
 

	
 
    def test_api_wrong_key(self):
 
        id_, params = _build_data('trololo', 'get_user')
 
        response = api_call(self, params)
 

	
 
        expected = 'Invalid API KEY'
 
        self._compare_error(id_, expected, given=response.body)
 

	
 
    def test_api_missing_non_optional_param(self):
 
        id_, params = _build_data(self.apikey, 'get_user')
 
        response = api_call(self, params)
 

	
 
        expected = 'Missing non optional `userid` arg in JSON DATA'
 
        self._compare_error(id_, expected, given=response.body)
 

	
 
    def test_api_get_users(self):
 
        id_, params = _build_data(self.apikey, 'get_users',)
 
        response = api_call(self, params)
 
        ret_all = []
 
        for usr in UserModel().get_all():
 
            ret = usr.get_api_data()
 
            ret_all.append(jsonify(ret))
 
        expected = ret_all
 
        self._compare_ok(id_, expected, given=response.body)
 

	
 
    def test_api_get_user(self):
 
        id_, params = _build_data(self.apikey, 'get_user',
 
                                  userid=TEST_USER_ADMIN_LOGIN)
 
        response = api_call(self, params)
 

	
 
        usr = UserModel().get_by_username(TEST_USER_ADMIN_LOGIN)
 
        ret = usr.get_api_data()
 
        ret['permissions'] = AuthUser(usr.user_id).permissions
 

	
 
        expected = ret
 
        self._compare_ok(id_, expected, given=response.body)
 

	
 
    def test_api_get_user_that_does_not_exist(self):
 
        id_, params = _build_data(self.apikey, 'get_user',
 
                                  userid='trololo')
 
        response = api_call(self, params)
 

	
 
        expected = "user `%s` does not exist" % 'trololo'
 
        self._compare_error(id_, expected, given=response.body)
 

	
 
    def test_api_pull(self):
 
        #TODO: issues with rhodecode_extras here.. not sure why !
 
        pass
 

	
 
#        repo_name = 'test_pull'
 
#        r = create_repo(repo_name, self.REPO_TYPE)
 
#        r.clone_uri = TEST_self.REPO
 
#        Session.add(r)
 
#        Session.commit()
 
#
 
#        id_, params = _build_data(self.apikey, 'pull',
 
#                                  repoid=repo_name,)
 
#        response = self.app.post(API_URL, content_type='application/json',
 
#                                 params=params)
 
#
 
#        expected = 'Pulled from `%s`' % repo_name
 
#        self._compare_ok(id_, expected, given=response.body)
 
#
 
#        destroy_repo(repo_name)
 

	
 
    def test_api_pull_error(self):
 
        id_, params = _build_data(self.apikey, 'pull',
 
                                  repoid=self.REPO,)
 
        response = api_call(self, params)
 

	
 
        expected = 'Unable to pull changes from `%s`' % self.REPO
 
        self._compare_error(id_, expected, given=response.body)
 

	
 
    def test_api_rescan_repos(self):
 
        id_, params = _build_data(self.apikey, 'rescan_repos')
 
        response = api_call(self, params)
 

	
 
        expected = {'added': [], 'removed': []}
 
        self._compare_ok(id_, expected, given=response.body)
 

	
 
    @mock.patch.object(ScmModel, 'repo_scan', crash)
 
    def test_api_rescann_error(self):
 
        id_, params = _build_data(self.apikey, 'rescan_repos',)
 
        response = api_call(self, params)
 

	
 
        expected = 'Error occurred during rescan repositories action'
 
        self._compare_error(id_, expected, given=response.body)
 

	
 
    def test_api_lock_repo_lock_aquire(self):
 
        id_, params = _build_data(self.apikey, 'lock',
 
                                  userid=TEST_USER_ADMIN_LOGIN,
 
                                  repoid=self.REPO,
 
                                  locked=True)
 
        response = api_call(self, params)
 
        expected = ('User `%s` set lock state for repo `%s` to `%s`'
 
                   % (TEST_USER_ADMIN_LOGIN, self.REPO, True))
 
        self._compare_ok(id_, expected, given=response.body)
 

	
 
    def test_api_lock_repo_lock_release(self):
 
        id_, params = _build_data(self.apikey, 'lock',
 
                                  userid=TEST_USER_ADMIN_LOGIN,
 
                                  repoid=self.REPO,
 
                                  locked=False)
 
        response = api_call(self, params)
 
        expected = ('User `%s` set lock state for repo `%s` to `%s`'
 
                   % (TEST_USER_ADMIN_LOGIN, self.REPO, False))
 
        self._compare_ok(id_, expected, given=response.body)
 

	
 
    @mock.patch.object(Repository, 'lock', crash)
 
    def test_api_lock_error(self):
 
        id_, params = _build_data(self.apikey, 'lock',
 
                                  userid=TEST_USER_ADMIN_LOGIN,
 
                                  repoid=self.REPO,
 
                                  locked=True)
 
        response = api_call(self, params)
 

	
 
        expected = 'Error occurred locking repository `%s`' % self.REPO
 
        self._compare_error(id_, expected, given=response.body)
 

	
 
    def test_api_create_existing_user(self):
 
        id_, params = _build_data(self.apikey, 'create_user',
 
                                  username=TEST_USER_ADMIN_LOGIN,
 
                                  email='test@foo.com',
 
                                  password='trololo')
 
        response = api_call(self, params)
 

	
 
        expected = "user `%s` already exist" % TEST_USER_ADMIN_LOGIN
 
        self._compare_error(id_, expected, given=response.body)
 

	
 
    def test_api_create_user_with_existing_email(self):
 
        id_, params = _build_data(self.apikey, 'create_user',
 
                                  username=TEST_USER_ADMIN_LOGIN + 'new',
 
                                  email=TEST_USER_REGULAR_EMAIL,
 
                                  password='trololo')
 
        response = api_call(self, params)
 

	
 
        expected = "email `%s` already exist" % TEST_USER_REGULAR_EMAIL
 
        self._compare_error(id_, expected, given=response.body)
 

	
 
    def test_api_create_user(self):
 
        username = 'test_new_api_user'
 
        email = username + "@foo.com"
 

	
 
        id_, params = _build_data(self.apikey, 'create_user',
 
                                  username=username,
 
                                  email=email,
 
                                  password='trololo')
 
        response = api_call(self, params)
 

	
 
        usr = UserModel().get_by_username(username)
 
        ret = dict(
 
            msg='created new user `%s`' % username,
 
            user=jsonify(usr.get_api_data())
 
        )
 

	
 
        expected = ret
 
        self._compare_ok(id_, expected, given=response.body)
 

	
 
        UserModel().delete(usr.user_id)
 
        Session().commit()
 

	
 
    @mock.patch.object(UserModel, 'create_or_update', crash)
 
    def test_api_create_user_when_exception_happened(self):
 

	
 
        username = 'test_new_api_user'
 
        email = username + "@foo.com"
 

	
 
        id_, params = _build_data(self.apikey, 'create_user',
 
                                  username=username,
 
                                  email=email,
 
                                  password='trololo')
 
        response = api_call(self, params)
 
        expected = 'failed to create user `%s`' % username
 
        self._compare_error(id_, expected, given=response.body)
 

	
 
    def test_api_delete_user(self):
 
        usr = UserModel().create_or_update(username=u'test_user',
 
                                           password=u'qweqwe',
 
                                           email=u'u232@rhodecode.org',
 
                                           firstname=u'u1', lastname=u'u1')
 
        Session().commit()
 
        username = usr.username
 
        email = usr.email
 
        usr_id = usr.user_id
 
        ## DELETE THIS USER NOW
 

	
 
        id_, params = _build_data(self.apikey, 'delete_user',
 
                                  userid=username,)
 
        response = api_call(self, params)
 

	
 
        ret = {'msg': 'deleted user ID:%s %s' % (usr_id, username),
 
               'user': None}
 
        expected = ret
 
        self._compare_ok(id_, expected, given=response.body)
 

	
 
    @mock.patch.object(UserModel, 'delete', crash)
 
    def test_api_delete_user_when_exception_happened(self):
 
        usr = UserModel().create_or_update(username=u'test_user',
 
                                           password=u'qweqwe',
 
                                           email=u'u232@rhodecode.org',
 
                                           firstname=u'u1', lastname=u'u1')
 
        Session().commit()
 
        username = usr.username
 

	
 
        id_, params = _build_data(self.apikey, 'delete_user',
 
                                  userid=username,)
 
        response = api_call(self, params)
 
        ret = 'failed to delete ID:%s %s' % (usr.user_id,
 
                                             usr.username)
 
        expected = ret
 
        self._compare_error(id_, expected, given=response.body)
 

	
 
    @parameterized.expand([('firstname', 'new_username'),
 
                           ('lastname', 'new_username'),
 
                           ('email', 'new_username'),
 
                           ('admin', True),
 
                           ('admin', False),
 
                           ('ldap_dn', 'test'),
 
                           ('ldap_dn', None),
 
                           ('active', False),
 
                           ('active', True),
 
                           ('password', 'newpass')
 
                           ])
 
    def test_api_update_user(self, name, expected):
 
        usr = UserModel().get_by_username(self.TEST_USER_LOGIN)
 
        kw = {name: expected,
 
              'userid': usr.user_id}
 
        id_, params = _build_data(self.apikey, 'update_user', **kw)
 
        response = api_call(self, params)
 

	
 
        ret = {
 
        'msg': 'updated user ID:%s %s' % (usr.user_id, self.TEST_USER_LOGIN),
 
        'user': jsonify(UserModel()\
 
                            .get_by_username(self.TEST_USER_LOGIN)\
 
                            .get_api_data())
 
        }
 

	
 
        expected = ret
 
        self._compare_ok(id_, expected, given=response.body)
 

	
 
    def test_api_update_user_no_changed_params(self):
 
        usr = UserModel().get_by_username(TEST_USER_ADMIN_LOGIN)
 
        ret = jsonify(usr.get_api_data())
 
        id_, params = _build_data(self.apikey, 'update_user',
 
                                  userid=TEST_USER_ADMIN_LOGIN)
 

	
 
        response = api_call(self, params)
 
        ret = {
 
        'msg': 'updated user ID:%s %s' % (usr.user_id, TEST_USER_ADMIN_LOGIN),
 
        'user': ret
 
        }
 
        expected = ret
 
        self._compare_ok(id_, expected, given=response.body)
 

	
 
    def test_api_update_user_by_user_id(self):
 
        usr = UserModel().get_by_username(TEST_USER_ADMIN_LOGIN)
 
        ret = jsonify(usr.get_api_data())
 
        id_, params = _build_data(self.apikey, 'update_user',
 
                                  userid=usr.user_id)
 

	
 
        response = api_call(self, params)
 
        ret = {
 
        'msg': 'updated user ID:%s %s' % (usr.user_id, TEST_USER_ADMIN_LOGIN),
 
        'user': ret
 
        }
 
        expected = ret
 
        self._compare_ok(id_, expected, given=response.body)
 

	
 
    @mock.patch.object(UserModel, 'update_user', crash)
 
    def test_api_update_user_when_exception_happens(self):
 
        usr = UserModel().get_by_username(TEST_USER_ADMIN_LOGIN)
 
        ret = jsonify(usr.get_api_data())
 
        id_, params = _build_data(self.apikey, 'update_user',
 
                                  userid=usr.user_id)
 

	
 
        response = api_call(self, params)
 
        ret = 'failed to update user `%s`' % usr.user_id
 

	
 
        expected = ret
 
        self._compare_error(id_, expected, given=response.body)
 

	
 
    def test_api_get_repo(self):
 
        new_group = 'some_new_group'
 
        make_users_group(new_group)
 
        RepoModel().grant_users_group_permission(repo=self.REPO,
 
                                                 group_name=new_group,
 
                                                 perm='repository.read')
 
        Session().commit()
 
        id_, params = _build_data(self.apikey, 'get_repo',
 
                                  repoid=self.REPO)
 
        response = api_call(self, params)
 

	
 
        repo = RepoModel().get_by_repo_name(self.REPO)
 
        ret = repo.get_api_data()
 

	
 
        members = []
 
        for user in repo.repo_to_perm:
 
            perm = user.permission.permission_name
 
            user = user.user
 
            user_data = user.get_api_data()
 
            user_data['type'] = "user"
 
            user_data['permission'] = perm
 
            members.append(user_data)
 

	
 
        for users_group in repo.users_group_to_perm:
 
            perm = users_group.permission.permission_name
 
            users_group = users_group.users_group
 
            users_group_data = users_group.get_api_data()
 
            users_group_data['type'] = "users_group"
 
            users_group_data['permission'] = perm
rhodecode/tests/functional/test_admin_defaults.py
Show inline comments
 
new file 100644
 
from rhodecode.tests import *
 
from rhodecode.model.db import RhodeCodeSetting
 

	
 

	
 
class TestDefaultsController(TestController):
 

	
 
    def test_index(self):
 
        self.log_user()
 
        response = self.app.get(url('defaults'))
 
        response.mustcontain('default_repo_private')
 
        response.mustcontain('default_repo_enable_statistics')
 
        response.mustcontain('default_repo_enable_downloads')
 
        response.mustcontain('default_repo_enable_locking')
 

	
 
    def test_index_as_xml(self):
 
        response = self.app.get(url('formatted_defaults', format='xml'))
 

	
 
    def test_create(self):
 
        response = self.app.post(url('defaults'))
 

	
 
    def test_new(self):
 
        response = self.app.get(url('new_default'))
 

	
 
    def test_new_as_xml(self):
 
        response = self.app.get(url('formatted_new_default', format='xml'))
 

	
 
    def test_update(self):
 
        self.log_user()
 
        params = {
 
            'default_repo_enable_locking': True,
 
            'default_repo_enable_downloads': True,
 
            'default_repo_enable_statistics': True,
 
            'default_repo_private': True,
 
            'default_repo_type': 'hg',
 
        }
 
        response = self.app.put(url('default', id='default'), params=params)
 
        self.checkSessionFlash(response, 'Default settings updated successfully')
 
        defs = RhodeCodeSetting.get_default_repo_settings()
 
        self.assertEqual(params, defs)
 

	
 
        params = {
 
            'default_repo_enable_locking': False,
 
            'default_repo_enable_downloads': False,
 
            'default_repo_enable_statistics': False,
 
            'default_repo_private': False,
 
            'default_repo_type': 'git',
 
        }
 
        response = self.app.put(url('default', id='default'), params=params)
 
        self.checkSessionFlash(response, 'Default settings updated successfully')
 
        defs = RhodeCodeSetting.get_default_repo_settings()
 
        self.assertEqual(params, defs)
 

	
 
    def test_update_browser_fakeout(self):
 
        response = self.app.post(url('default', id=1), params=dict(_method='put'))
 

	
 
    def test_delete(self):
 
        response = self.app.delete(url('default', id=1))
 

	
 
    def test_delete_browser_fakeout(self):
 
        response = self.app.post(url('default', id=1), params=dict(_method='delete'))
 

	
 
    def test_show(self):
 
        response = self.app.get(url('default', id=1))
 

	
 
    def test_show_as_xml(self):
 
        response = self.app.get(url('formatted_default', id=1, format='xml'))
 

	
 
    def test_edit(self):
 
        response = self.app.get(url('edit_default', id=1))
 

	
 
    def test_edit_as_xml(self):
 
        response = self.app.get(url('formatted_edit_default', id=1, format='xml'))

Changeset was too big and was cut off... Show full diff anyway

0 comments (0 inline, 0 general)