##// END OF EJS Templates
merge with beta
marcink -
r2825:f7a52d54 merge default
parent child Browse files
Show More
@@ -0,0 +1,51 b''
1 import logging
2 import datetime
3
4 from sqlalchemy import *
5 from sqlalchemy.exc import DatabaseError
6 from sqlalchemy.orm import relation, backref, class_mapper
7 from sqlalchemy.orm.session import Session
8 from sqlalchemy.ext.declarative import declarative_base
9
10 from rhodecode.lib.dbmigrate.migrate import *
11 from rhodecode.lib.dbmigrate.migrate.changeset import *
12
13 from rhodecode.model.meta import Base
14 from rhodecode.model import meta
15
16 log = logging.getLogger(__name__)
17
18
19 def upgrade(migrate_engine):
20 """
21 Upgrade operations go here.
22 Don't create your own engine; bind migrate_engine to your metadata
23 """
24
25 #==========================================================================
26 # CHANGESET_COMMENTS
27 #==========================================================================
28 from rhodecode.lib.dbmigrate.schema.db_1_4_0 import ChangesetComment
29 tbl_name = ChangesetComment.__tablename__
30 tbl = Table(tbl_name,
31 MetaData(bind=migrate_engine), autoload=True,
32 autoload_with=migrate_engine)
33 col = tbl.columns.revision
34
35 # remove nullability from revision field
36 col.alter(nullable=True)
37
38 #==========================================================================
39 # REPOSITORY
40 #==========================================================================
41 from rhodecode.lib.dbmigrate.schema.db_1_4_0 import Repository
42 tbl = Repository.__table__
43 updated_on = Column('updated_on', DateTime(timezone=False),
44 nullable=True, unique=None)
45 # create created on column for future lightweight main page
46 updated_on.create(table=tbl)
47
48
49 def downgrade(migrate_engine):
50 meta = MetaData()
51 meta.bind = migrate_engine
@@ -0,0 +1,20 b''
1 ## -*- coding: utf-8 -*-
2 <%inherit file="main.html"/>
3
4 User <b>${pr_user_created}</b> opened pull request for repository
5 ${pr_repo_url} and wants you to review changes.
6
7 <div>title: ${pr_title}</div>
8 <div>description:</div>
9 <p>
10 ${body}
11 </p>
12
13 <div>revisions for reviewing</div>
14 <ul>
15 %for r in pr_revisions:
16 <li>${r}</li>
17 %endfor
18 </ul>
19
20 View this pull request here: ${pr_url}
@@ -0,0 +1,15 b''
1 ## -*- coding: utf-8 -*-
2 <%inherit file="main.html"/>
3
4 User <b>${pr_comment_user}</b> commented on pull request #${pr_id} for
5 repository ${pr_target_repo}
6
7 <p>
8 ${body}
9
10 %if status_change:
11 <span>New status -> ${status_change}</span>
12 %endif
13 </p>
14
15 View this comment here: ${pr_comment_url}
@@ -0,0 +1,116 b''
1 import os
2 import unittest
3 import functools
4 from rhodecode.tests import *
5
6
7 from rhodecode.model.repos_group import ReposGroupModel
8 from rhodecode.model.repo import RepoModel
9 from rhodecode.model.db import RepoGroup, Repository, User
10 from rhodecode.model.user import UserModel
11
12 from rhodecode.lib.auth import AuthUser
13 from rhodecode.model.meta import Session
14
15
16 def _make_group(path, desc='desc', parent_id=None,
17 skip_if_exists=False):
18
19 gr = RepoGroup.get_by_group_name(path)
20 if gr and skip_if_exists:
21 return gr
22 if isinstance(parent_id, RepoGroup):
23 parent_id = parent_id.group_id
24 gr = ReposGroupModel().create(path, desc, parent_id)
25 return gr
26
27
28 def _make_repo(name, repos_group=None, repo_type='hg'):
29 return RepoModel().create_repo(name, repo_type, 'desc',
30 TEST_USER_ADMIN_LOGIN,
31 repos_group=repos_group)
32
33
34 def _destroy_project_tree(test_u1_id):
35 Session.remove()
36 repos_group = RepoGroup.get_by_group_name(group_name='g0')
37 for el in reversed(repos_group.recursive_groups_and_repos()):
38 if isinstance(el, Repository):
39 RepoModel().delete(el)
40 elif isinstance(el, RepoGroup):
41 ReposGroupModel().delete(el, force_delete=True)
42
43 u = User.get(test_u1_id)
44 Session().delete(u)
45 Session().commit()
46
47
48 def _create_project_tree():
49 """
50 Creates a tree of groups and repositories to test permissions
51
52 structure
53 [g0] - group `g0` with 3 subgroups
54 |
55 |__[g0_1] group g0_1 with 2 groups 0 repos
56 | |
57 | |__[g0_1_1] group g0_1_1 with 1 group 2 repos
58 | | |__<g0/g0_1/g0_1_1/g0_1_1_r1>
59 | | |__<g0/g0_1/g0_1_1/g0_1_1_r2>
60 | |__<g0/g0_1/g0_1_r1>
61 |
62 |__[g0_2] 2 repos
63 | |
64 | |__<g0/g0_2/g0_2_r1>
65 | |__<g0/g0_2/g0_2_r2>
66 |
67 |__[g0_3] 1 repo
68 |
69 |_<g0/g0_3/g0_3_r1>
70
71 """
72 test_u1 = UserModel().create_or_update(
73 username=u'test_u1', password=u'qweqwe',
74 email=u'test_u1@rhodecode.org', firstname=u'test_u1', lastname=u'test_u1'
75 )
76 g0 = _make_group('g0')
77 g0_1 = _make_group('g0_1', parent_id=g0)
78 g0_1_1 = _make_group('g0_1_1', parent_id=g0_1)
79 g0_1_1_r1 = _make_repo('g0/g0_1/g0_1_1/g0_1_1_r1', repos_group=g0_1_1)
80 g0_1_1_r2 = _make_repo('g0/g0_1/g0_1_1/g0_1_1_r2', repos_group=g0_1_1)
81 g0_1_r1 = _make_repo('g0/g0_1/g0_1_r1', repos_group=g0_1)
82 g0_2 = _make_group('g0_2', parent_id=g0)
83 g0_2_r1 = _make_repo('g0/g0_2/g0_2_r1', repos_group=g0_2)
84 g0_2_r2 = _make_repo('g0/g0_2/g0_2_r2', repos_group=g0_2)
85 g0_3 = _make_group('g0_3', parent_id=g0)
86 g0_3_r1 = _make_repo('g0/g0_3/g0_3_r1', repos_group=g0_3)
87 return test_u1
88
89
90 def expected_count(group_name, objects=False):
91 repos_group = RepoGroup.get_by_group_name(group_name=group_name)
92 objs = repos_group.recursive_groups_and_repos()
93 if objects:
94 return objs
95 return len(objs)
96
97
98 def _check_expected_count(items, repo_items, expected):
99 should_be = len(items + repo_items)
100 there_are = len(expected)
101 assert should_be == there_are, ('%s != %s' % ((items + repo_items), expected))
102
103
104 def check_tree_perms(obj_name, repo_perm, prefix, expected_perm):
105 assert repo_perm == expected_perm, ('obj:`%s` got perm:`%s` should:`%s`'
106 % (obj_name, repo_perm, expected_perm))
107
108
109 def _get_perms(filter_='', recursive=True, key=None, test_u1_id=None):
110 test_u1 = AuthUser(user_id=test_u1_id)
111 for k, v in test_u1.permissions[key].items():
112 if recursive and k.startswith(filter_):
113 yield k, v
114 elif not recursive:
115 if k == filter_:
116 yield k, v
@@ -0,0 +1,161 b''
1 import os
2 import unittest
3 import functools
4 from rhodecode.tests import *
5
6 from rhodecode.model.repos_group import ReposGroupModel
7 from rhodecode.model.db import RepoGroup, Repository, User
8
9 from rhodecode.model.meta import Session
10 from nose.tools import with_setup
11 from rhodecode.tests.models.common import _create_project_tree, check_tree_perms, \
12 _get_perms, _check_expected_count, expected_count, _destroy_project_tree
13 from rhodecode.model.repo import RepoModel
14
15
16 test_u1_id = None
17 _get_repo_perms = None
18 _get_group_perms = None
19
20
21 def permissions_setup_func(group_name='g0', perm='group.read', recursive=True):
22 """
23 Resets all permissions to perm attribute
24 """
25 repos_group = RepoGroup.get_by_group_name(group_name=group_name)
26 if not repos_group:
27 raise Exception('Cannot get group %s' % group_name)
28 perms_updates = [[test_u1_id, perm, 'user']]
29 ReposGroupModel()._update_permissions(repos_group,
30 perms_updates=perms_updates,
31 recursive=recursive)
32 Session().commit()
33
34
35 def setup_module():
36 global test_u1_id, _get_repo_perms, _get_group_perms
37 test_u1 = _create_project_tree()
38 Session().commit()
39 test_u1_id = test_u1.user_id
40 _get_repo_perms = functools.partial(_get_perms, key='repositories',
41 test_u1_id=test_u1_id)
42 _get_group_perms = functools.partial(_get_perms, key='repositories_groups',
43 test_u1_id=test_u1_id)
44
45
46 def teardown_module():
47 _destroy_project_tree(test_u1_id)
48
49
50 @with_setup(permissions_setup_func)
51 def test_user_permissions_on_group_without_recursive_mode():
52 # set permission to g0 non-recursive mode
53 recursive = False
54 group = 'g0'
55 permissions_setup_func(group, 'group.write', recursive=recursive)
56
57 items = [x for x in _get_repo_perms(group, recursive)]
58 expected = 0
59 assert len(items) == expected, ' %s != %s' % (len(items), expected)
60 for name, perm in items:
61 yield check_tree_perms, name, perm, group, 'repository.read'
62
63 items = [x for x in _get_group_perms(group, recursive)]
64 expected = 1
65 assert len(items) == expected, ' %s != %s' % (len(items), expected)
66 for name, perm in items:
67 yield check_tree_perms, name, perm, group, 'group.write'
68
69
70 @with_setup(permissions_setup_func)
71 def test_user_permissions_on_group_without_recursive_mode_subgroup():
72 # set permission to g0 non-recursive mode
73 recursive = False
74 group = 'g0/g0_1'
75 permissions_setup_func(group, 'group.write', recursive=recursive)
76
77 items = [x for x in _get_repo_perms(group, recursive)]
78 expected = 0
79 assert len(items) == expected, ' %s != %s' % (len(items), expected)
80 for name, perm in items:
81 yield check_tree_perms, name, perm, group, 'repository.read'
82
83 items = [x for x in _get_group_perms(group, recursive)]
84 expected = 1
85 assert len(items) == expected, ' %s != %s' % (len(items), expected)
86 for name, perm in items:
87 yield check_tree_perms, name, perm, group, 'group.write'
88
89
90 @with_setup(permissions_setup_func)
91 def test_user_permissions_on_group_with_recursive_mode():
92
93 # set permission to g0 recursive mode, all children including
94 # other repos and groups should have this permission now set !
95 recursive = True
96 group = 'g0'
97 permissions_setup_func(group, 'group.write', recursive=recursive)
98
99 repo_items = [x for x in _get_repo_perms(group, recursive)]
100 items = [x for x in _get_group_perms(group, recursive)]
101 _check_expected_count(items, repo_items, expected_count(group, True))
102
103 for name, perm in repo_items:
104 yield check_tree_perms, name, perm, group, 'repository.write'
105
106 for name, perm in items:
107 yield check_tree_perms, name, perm, group, 'group.write'
108
109
110 @with_setup(permissions_setup_func)
111 def test_user_permissions_on_group_with_recursive_mode_inner_group():
112 ## set permission to g0_3 group to none
113 recursive = True
114 group = 'g0/g0_3'
115 permissions_setup_func(group, 'group.none', recursive=recursive)
116
117 repo_items = [x for x in _get_repo_perms(group, recursive)]
118 items = [x for x in _get_group_perms(group, recursive)]
119 _check_expected_count(items, repo_items, expected_count(group, True))
120
121 for name, perm in repo_items:
122 yield check_tree_perms, name, perm, group, 'repository.none'
123
124 for name, perm in items:
125 yield check_tree_perms, name, perm, group, 'group.none'
126
127
128 @with_setup(permissions_setup_func)
129 def test_user_permissions_on_group_with_recursive_mode_deepest():
130 ## set permission to g0_3 group to none
131 recursive = True
132 group = 'g0/g0_1/g0_1_1'
133 permissions_setup_func(group, 'group.write', recursive=recursive)
134
135 repo_items = [x for x in _get_repo_perms(group, recursive)]
136 items = [x for x in _get_group_perms(group, recursive)]
137 _check_expected_count(items, repo_items, expected_count(group, True))
138
139 for name, perm in repo_items:
140 yield check_tree_perms, name, perm, group, 'repository.write'
141
142 for name, perm in items:
143 yield check_tree_perms, name, perm, group, 'group.write'
144
145
146 @with_setup(permissions_setup_func)
147 def test_user_permissions_on_group_with_recursive_mode_only_with_repos():
148 ## set permission to g0_3 group to none
149 recursive = True
150 group = 'g0/g0_2'
151 permissions_setup_func(group, 'group.admin', recursive=recursive)
152
153 repo_items = [x for x in _get_repo_perms(group, recursive)]
154 items = [x for x in _get_group_perms(group, recursive)]
155 _check_expected_count(items, repo_items, expected_count(group, True))
156
157 for name, perm in repo_items:
158 yield check_tree_perms, name, perm, group, 'repository.admin'
159
160 for name, perm in items:
161 yield check_tree_perms, name, perm, group, 'group.admin'
@@ -0,0 +1,170 b''
1 import os
2 import unittest
3 import functools
4 from rhodecode.tests import *
5
6 from rhodecode.model.repos_group import ReposGroupModel
7 from rhodecode.model.db import RepoGroup, Repository, User
8
9 from rhodecode.model.meta import Session
10 from nose.tools import with_setup
11 from rhodecode.tests.models.common import _create_project_tree, check_tree_perms, \
12 _get_perms, _check_expected_count, expected_count, _destroy_project_tree
13 from rhodecode.model.users_group import UsersGroupModel
14 from rhodecode.model.repo import RepoModel
15
16
17 test_u2_id = None
18 test_u2_gr_id = None
19 _get_repo_perms = None
20 _get_group_perms = None
21
22
23 def permissions_setup_func(group_name='g0', perm='group.read', recursive=True):
24 """
25 Resets all permissions to perm attribute
26 """
27 repos_group = RepoGroup.get_by_group_name(group_name=group_name)
28 if not repos_group:
29 raise Exception('Cannot get group %s' % group_name)
30 perms_updates = [[test_u2_gr_id, perm, 'users_group']]
31 ReposGroupModel()._update_permissions(repos_group,
32 perms_updates=perms_updates,
33 recursive=recursive)
34 Session().commit()
35
36
37 def setup_module():
38 global test_u2_id, test_u2_gr_id, _get_repo_perms, _get_group_perms
39 test_u2 = _create_project_tree()
40 Session().commit()
41 test_u2_id = test_u2.user_id
42
43 gr1 = UsersGroupModel().create(name='perms_group_1')
44 Session().commit()
45 test_u2_gr_id = gr1.users_group_id
46 UsersGroupModel().add_user_to_group(gr1, user=test_u2_id)
47 Session().commit()
48
49 _get_repo_perms = functools.partial(_get_perms, key='repositories',
50 test_u1_id=test_u2_id)
51 _get_group_perms = functools.partial(_get_perms, key='repositories_groups',
52 test_u1_id=test_u2_id)
53
54
55 def teardown_module():
56 _destroy_project_tree(test_u2_id)
57
58
59 @with_setup(permissions_setup_func)
60 def test_user_permissions_on_group_without_recursive_mode():
61 # set permission to g0 non-recursive mode
62 recursive = False
63 group = 'g0'
64 permissions_setup_func(group, 'group.write', recursive=recursive)
65
66 items = [x for x in _get_repo_perms(group, recursive)]
67 expected = 0
68 assert len(items) == expected, ' %s != %s' % (len(items), expected)
69 for name, perm in items:
70 yield check_tree_perms, name, perm, group, 'repository.read'
71
72 items = [x for x in _get_group_perms(group, recursive)]
73 expected = 1
74 assert len(items) == expected, ' %s != %s' % (len(items), expected)
75 for name, perm in items:
76 yield check_tree_perms, name, perm, group, 'group.write'
77
78
79 @with_setup(permissions_setup_func)
80 def test_user_permissions_on_group_without_recursive_mode_subgroup():
81 # set permission to g0 non-recursive mode
82 recursive = False
83 group = 'g0/g0_1'
84 permissions_setup_func(group, 'group.write', recursive=recursive)
85
86 items = [x for x in _get_repo_perms(group, recursive)]
87 expected = 0
88 assert len(items) == expected, ' %s != %s' % (len(items), expected)
89 for name, perm in items:
90 yield check_tree_perms, name, perm, group, 'repository.read'
91
92 items = [x for x in _get_group_perms(group, recursive)]
93 expected = 1
94 assert len(items) == expected, ' %s != %s' % (len(items), expected)
95 for name, perm in items:
96 yield check_tree_perms, name, perm, group, 'group.write'
97
98
99 @with_setup(permissions_setup_func)
100 def test_user_permissions_on_group_with_recursive_mode():
101
102 # set permission to g0 recursive mode, all children including
103 # other repos and groups should have this permission now set !
104 recursive = True
105 group = 'g0'
106 permissions_setup_func(group, 'group.write', recursive=recursive)
107
108 repo_items = [x for x in _get_repo_perms(group, recursive)]
109 items = [x for x in _get_group_perms(group, recursive)]
110 _check_expected_count(items, repo_items, expected_count(group, True))
111
112 for name, perm in repo_items:
113 yield check_tree_perms, name, perm, group, 'repository.write'
114
115 for name, perm in items:
116 yield check_tree_perms, name, perm, group, 'group.write'
117
118
119 @with_setup(permissions_setup_func)
120 def test_user_permissions_on_group_with_recursive_mode_inner_group():
121 ## set permission to g0_3 group to none
122 recursive = True
123 group = 'g0/g0_3'
124 permissions_setup_func(group, 'group.none', recursive=recursive)
125
126 repo_items = [x for x in _get_repo_perms(group, recursive)]
127 items = [x for x in _get_group_perms(group, recursive)]
128 _check_expected_count(items, repo_items, expected_count(group, True))
129
130 for name, perm in repo_items:
131 yield check_tree_perms, name, perm, group, 'repository.none'
132
133 for name, perm in items:
134 yield check_tree_perms, name, perm, group, 'group.none'
135
136
137 @with_setup(permissions_setup_func)
138 def test_user_permissions_on_group_with_recursive_mode_deepest():
139 ## set permission to g0_3 group to none
140 recursive = True
141 group = 'g0/g0_1/g0_1_1'
142 permissions_setup_func(group, 'group.write', recursive=recursive)
143
144 repo_items = [x for x in _get_repo_perms(group, recursive)]
145 items = [x for x in _get_group_perms(group, recursive)]
146 _check_expected_count(items, repo_items, expected_count(group, True))
147
148 for name, perm in repo_items:
149 yield check_tree_perms, name, perm, group, 'repository.write'
150
151 for name, perm in items:
152 yield check_tree_perms, name, perm, group, 'group.write'
153
154
155 @with_setup(permissions_setup_func)
156 def test_user_permissions_on_group_with_recursive_mode_only_with_repos():
157 ## set permission to g0_3 group to none
158 recursive = True
159 group = 'g0/g0_2'
160 permissions_setup_func(group, 'group.admin', recursive=recursive)
161
162 repo_items = [x for x in _get_repo_perms(group, recursive)]
163 items = [x for x in _get_group_perms(group, recursive)]
164 _check_expected_count(items, repo_items, expected_count(group, True))
165
166 for name, perm in repo_items:
167 yield check_tree_perms, name, perm, group, 'repository.admin'
168
169 for name, perm in items:
170 yield check_tree_perms, name, perm, group, 'group.admin'
@@ -4,6 +4,45 b''
4 4 Changelog
5 5 =========
6 6
7
8 1.4.1 (**2012-09-07**)
9 ----------------------
10
11 :status: in-progress
12 :branch: beta
13
14 news
15 ++++
16
17 - always put a comment about code-review status change even if user send
18 empty data
19 - modified_on column saves repository update and it's going to be used
20 later for light version of main page ref #500
21 - pull request notifications send much nicer emails with details about pull
22 request
23 - #551 show breadcrumbs in summary view for repositories inside a group
24
25 fixes
26 +++++
27
28 - fixed migrations of permissions that can lead to inconsistency.
29 Some users sent feedback that after upgrading from older versions issues
30 with updating default permissions occurred. RhodeCode detects that now and
31 resets default user permission to initial state if there is a need for that.
32 Also forces users to set the default value for new forking permission.
33 - #535 improved apache wsgi example configuration in docs
34 - fixes #550 mercurial repositories comparision failed when origin repo had
35 additional not-common changesets
36 - fixed status of code-review in preview windows of pull request
37 - git forks were not initialized at bare repos
38 - fixes #555 fixes issues with comparing non-related repositories
39 - fixes #557 follower counter always counts up
40 - fixed issue #560 require push ssl checkbox wasn't shown when option was
41 enabled
42 - fixed #559
43 - fixed issue #559 fixed bug in routing that mapped repo names with <name>_<num> in name as
44 if it was a request to url by repository ID
45
7 46 1.4.0 (**2012-09-03**)
8 47 ----------------------
9 48
@@ -11,8 +11,8 b' clients. Minimal version of hg client kn'
11 11 **1.6**. If you're using older client, please upgrade.
12 12
13 13
14 Installing RhodeCode from Cheese Shop
15 -------------------------------------
14 Installing RhodeCode from PyPI (aka "Cheeseshop")
15 -------------------------------------------------
16 16
17 17 Rhodecode requires python version 2.5 or higher.
18 18
@@ -126,4 +126,4 b' You can now proceed to :ref:`setup`'
126 126 .. _python: http://www.python.org/
127 127 .. _mercurial: http://mercurial.selenic.com/
128 128 .. _celery: http://celeryproject.org/
129 .. _rabbitmq: http://www.rabbitmq.com/ No newline at end of file
129 .. _rabbitmq: http://www.rabbitmq.com/
@@ -667,12 +667,21 b" that, you'll need to:"
667 667
668 668 Here is a sample excerpt from an Apache Virtual Host configuration file::
669 669
670 WSGIDaemonProcess pylons user=www-data group=www-data processes=1 \
670 WSGIDaemonProcess pylons \
671 671 threads=4 \
672 672 python-path=/home/web/rhodecode/pyenv/lib/python2.6/site-packages
673 673 WSGIScriptAlias / /home/web/rhodecode/dispatch.wsgi
674 674 WSGIPassAuthorization On
675 675
676 .. note::
677 when running apache as root please add: `user=www-data group=www-data`
678 into above configuration
679
680 .. note::
681 RhodeCode cannot be runned in multiprocess mode in apache, make sure
682 you don't specify `processes=num` directive in the config
683
684
676 685 Example wsgi dispatch script::
677 686
678 687 import os
@@ -4,14 +4,43 b''
4 4 Upgrade
5 5 =======
6 6
7 Upgrading from Cheese Shop
8 --------------------------
7 Upgrading from PyPI (aka "Cheeseshop")
8 ---------------------------------------
9 9
10 10 .. note::
11 Firstly, it is recommended that you **always** perform a database backup
12 before doing an upgrade.
11 Firstly, it is recommended that you **always** perform a database and
12 configuration backup before doing an upgrade.
13
14 (These directions will use '{version}' to note that this is the version of
15 Rhodecode that these files were used with. If backing up your RhodeCode
16 instance from version 1.3.6 to 1.4.0, the ``production.ini`` file would be
17 backed up to ``production.ini.1-3-6``.)
18
19
20 If using a sqlite database, stop the Rhodecode process/daemon/service, and
21 then make a copy of the database file::
22
23 service rhodecode stop
24 cp rhodecode.db rhodecode.db.{version}
25
13 26
14 The easiest way to upgrade ``rhodecode`` is to run::
27 Back up your configuration file::
28
29 cp production.ini production.ini.{version}
30
31
32 Ensure that you are using the Python Virtual Environment that you'd originally
33 installed Rhodecode in::
34
35 pip freeze
36
37 will list all packages installed in the current environment. If Rhodecode
38 isn't listed, change virtual environments to your venv location::
39
40 source /opt/rhodecode-venv/bin/activate
41
42
43 Once you have verified the environment you can upgrade ``Rhodecode`` with::
15 44
16 45 easy_install -U rhodecode
17 46
@@ -20,14 +49,13 b' Or::'
20 49 pip install --upgrade rhodecode
21 50
22 51
23 Then make sure you run the following command from the installation directory::
52 Then run the following command from the installation directory::
24 53
25 54 paster make-config RhodeCode production.ini
26 55
27 56 This will display any changes made by the new version of RhodeCode to your
28 current configuration. It will try to perform an automerge. It's always better
29 to make a backup of your configuration file before hand and re check the
30 content after the automerge.
57 current configuration. It will try to perform an automerge. It's recommended
58 that you re-check the content after the automerge.
31 59
32 60 .. note::
33 61 Please always make sure your .ini files are up to date. Often errors are
@@ -41,12 +69,25 b' Read the changelog to see if there were '
41 69
42 70 The final step is to upgrade the database. To do this simply run::
43 71
44 paster upgrade-db production.ini
72 paster upgrade-db production.ini
45 73
46 74 This will upgrade the schema and update some of the defaults in the database,
47 75 and will always recheck the settings of the application, if there are no new
48 76 options that need to be set.
49 77
78 You may find it helpful to clear out your log file so that new errors are
79 readily apparent::
80
81 echo > rhodecode.log
82
83 Once that is complete, you may now start your upgraded Rhodecode Instance::
84
85 service rhodecode start
86
87 Or::
88
89 paster serve /var/www/rhodecode/production.ini
90
50 91 .. note::
51 92 If you're using Celery, make sure you restart all instances of it after
52 93 upgrade.
@@ -55,4 +96,4 b' options that need to be set.'
55 96 .. _python: http://www.python.org/
56 97 .. _mercurial: http://mercurial.selenic.com/
57 98 .. _celery: http://celeryproject.org/
58 .. _rabbitmq: http://www.rabbitmq.com/ No newline at end of file
99 .. _rabbitmq: http://www.rabbitmq.com/
@@ -26,7 +26,7 b''
26 26 import sys
27 27 import platform
28 28
29 VERSION = (1, 4, 0)
29 VERSION = (1, 4, 1)
30 30
31 31 try:
32 32 from rhodecode.lib import get_current_revision
@@ -38,7 +38,7 b' except ImportError:'
38 38
39 39 __version__ = ('.'.join((str(each) for each in VERSION[:3])) +
40 40 '.'.join(VERSION[3:]))
41 __dbversion__ = 6 # defines current db version for migrations
41 __dbversion__ = 7 # defines current db version for migrations
42 42 __platform__ = platform.system()
43 43 __license__ = 'GPLv3'
44 44 __py_version__ = sys.version_info
@@ -34,7 +34,7 b' def make_map(config):'
34 34
35 35 try:
36 36 by_id = repo_name.split('_')
37 if len(by_id) == 2 and by_id[1].isdigit():
37 if len(by_id) == 2 and by_id[1].isdigit() and by_id[0] == '':
38 38 repo_name = Repository.get(by_id[1]).repo_name
39 39 match_dict['repo_name'] = repo_name
40 40 except:
@@ -45,6 +45,7 b' from rhodecode.model.forms import ReposG'
45 45 from rhodecode.model.meta import Session
46 46 from rhodecode.model.repo import RepoModel
47 47 from webob.exc import HTTPInternalServerError, HTTPNotFound
48 from rhodecode.lib.utils2 import str2bool
48 49
49 50 log = logging.getLogger(__name__)
50 51
@@ -162,7 +163,7 b' class ReposGroupsController(BaseControll'
162 163 Session().commit()
163 164 h.flash(_('updated repos group %s') \
164 165 % form_result['group_name'], category='success')
165 #TODO: in futureaction_logger(, '', '', '', self.sa)
166 #TODO: in future action_logger(, '', '', '', self.sa)
166 167 except formencode.Invalid, errors:
167 168
168 169 return htmlfill.render(
@@ -227,10 +228,11 b' class ReposGroupsController(BaseControll'
227 228
228 229 :param group_name:
229 230 """
230
231 231 try:
232 ReposGroupModel().revoke_user_permission(
233 repos_group=group_name, user=request.POST['user_id']
232 recursive = str2bool(request.POST.get('recursive', False))
233 ReposGroupModel().delete_permission(
234 repos_group=group_name, obj=request.POST['user_id'],
235 obj_type='user', recursive=recursive
234 236 )
235 237 Session().commit()
236 238 except Exception:
@@ -248,9 +250,10 b' class ReposGroupsController(BaseControll'
248 250 """
249 251
250 252 try:
251 ReposGroupModel().revoke_users_group_permission(
252 repos_group=group_name,
253 group_name=request.POST['users_group_id']
253 recursive = str2bool(request.POST.get('recursive', False))
254 ReposGroupModel().delete_permission(
255 repos_group=group_name, obj=request.POST['users_group_id'],
256 obj_type='users_group', recursive=recursive
254 257 )
255 258 Session().commit()
256 259 except Exception:
@@ -51,6 +51,7 b' from rhodecode.model.user import UserMod'
51 51 from rhodecode.model.db import User
52 52 from rhodecode.model.notification import EmailNotificationModel
53 53 from rhodecode.model.meta import Session
54 from rhodecode.lib.utils2 import str2bool
54 55
55 56 log = logging.getLogger(__name__)
56 57
@@ -471,6 +472,9 b' class SettingsController(BaseController)'
471 472 if k == '/':
472 473 k = 'root_path'
473 474
475 if k == 'push_ssl':
476 v = str2bool(v)
477
474 478 if k.find('.') != -1:
475 479 k = k.replace('.', '_')
476 480
@@ -478,5 +482,4 b' class SettingsController(BaseController)'
478 482 v = each.ui_active
479 483
480 484 settings[each.ui_section + '_' + k] = v
481
482 485 return settings
@@ -376,9 +376,13 b' class ChangesetController(BaseRepoContro'
376 376 def comment(self, repo_name, revision):
377 377 status = request.POST.get('changeset_status')
378 378 change_status = request.POST.get('change_changeset_status')
379 text = request.POST.get('text')
380 if status and change_status:
381 text = text or (_('Status change -> %s')
382 % ChangesetStatus.get_status_lbl(status))
379 383
380 384 comm = ChangesetCommentsModel().create(
381 text=request.POST.get('text'),
385 text=text,
382 386 repo=c.rhodecode_db_repo.repo_id,
383 387 user=c.rhodecode_user.user_id,
384 388 revision=revision,
@@ -391,7 +395,7 b' class ChangesetController(BaseRepoContro'
391 395 # get status if set !
392 396 if status and change_status:
393 397 # if latest status was from pull request and it's closed
394 # disallow changing status !
398 # disallow changing status !
395 399 # dont_allow_on_closed_pull_request = True !
396 400
397 401 try:
@@ -249,8 +249,7 b' class PullrequestsController(BaseRepoCon'
249 249 org_repo, org_ref, other_repo, other_ref
250 250 )
251 251
252 c.statuses = c.rhodecode_db_repo.statuses([x.raw_id for x in
253 c.cs_ranges])
252 c.statuses = org_repo.statuses([x.raw_id for x in c.cs_ranges])
254 253 # defines that we need hidden inputs with changesets
255 254 c.as_form = request.GET.get('as_form', False)
256 255
@@ -277,6 +276,7 b' class PullrequestsController(BaseRepoCon'
277 276 c.users_array = repo_model.get_users_js()
278 277 c.users_groups_array = repo_model.get_users_groups_js()
279 278 c.pull_request = PullRequest.get_or_404(pull_request_id)
279 c.target_repo = c.pull_request.org_repo.repo_name
280 280
281 281 cc_model = ChangesetCommentsModel()
282 282 cs_model = ChangesetStatusModel()
@@ -322,12 +322,20 b' class PullrequestsController(BaseRepoCon'
322 322 c.comments = cc_model.get_comments(c.rhodecode_db_repo.repo_id,
323 323 pull_request=pull_request_id)
324 324
325 # changeset(pull-request) status
326 c.current_changeset_status = cs_model.calculate_status(
327 c.pull_request_reviewers
328 )
325 try:
326 cur_status = c.statuses[c.pull_request.revisions[0]][0]
327 except:
328 log.error(traceback.format_exc())
329 cur_status = 'undefined'
330 if c.pull_request.is_closed() and 0:
331 c.current_changeset_status = cur_status
332 else:
333 # changeset(pull-request) status calulation based on reviewers
334 c.current_changeset_status = cs_model.calculate_status(
335 c.pull_request_reviewers,
336 )
329 337 c.changeset_statuses = ChangesetStatus.STATUSES
330 c.target_repo = c.pull_request.org_repo.repo_name
338
331 339 return render('/pullrequests/pullrequest_show.html')
332 340
333 341 @NotAnonymous()
@@ -339,9 +347,12 b' class PullrequestsController(BaseRepoCon'
339 347
340 348 status = request.POST.get('changeset_status')
341 349 change_status = request.POST.get('change_changeset_status')
342
350 text = request.POST.get('text')
351 if status and change_status:
352 text = text or (_('Status change -> %s')
353 % ChangesetStatus.get_status_lbl(status))
343 354 comm = ChangesetCommentsModel().create(
344 text=request.POST.get('text'),
355 text=text,
345 356 repo=c.rhodecode_db_repo.repo_id,
346 357 user=c.rhodecode_user.user_id,
347 358 pull_request=pull_request_id,
@@ -400,9 +400,19 b' def create_repo_fork(form_data, cur_user'
400 400 log.info('creating fork of %s as %s', source_repo_path,
401 401 destination_fork_path)
402 402 backend = get_backend(repo_type)
403 backend(safe_str(destination_fork_path), create=True,
404 src_url=safe_str(source_repo_path),
405 update_after_clone=update_after_clone)
403
404 if repo_type == 'git':
405 backend(safe_str(destination_fork_path), create=True,
406 src_url=safe_str(source_repo_path),
407 update_after_clone=update_after_clone,
408 bare=True)
409 elif repo_type == 'hg':
410 backend(safe_str(destination_fork_path), create=True,
411 src_url=safe_str(source_repo_path),
412 update_after_clone=update_after_clone)
413 else:
414 raise Exception('Unknown backend type %s' % repo_type)
415
406 416 log_create_repository(fork_repo.get_dict(), created_by=cur_user.username)
407 417
408 418 action_logger(cur_user, 'user_forked_repo:%s' % fork_name,
@@ -589,6 +589,3 b' else:'
589 589 self.__cond.wait(timeout)
590 590 finally:
591 591 self.__cond.release()
592
593
594
@@ -247,7 +247,22 b' class DbManage(object):'
247 247 Session().add(hggit)
248 248
249 249 notify('re-check default permissions')
250 self.klass.populate_default_permissions()
250 default_user = User.get_by_username(User.DEFAULT_USER)
251 perm = Permission.get_by_key('hg.fork.repository')
252 reg_perm = UserToPerm()
253 reg_perm.user = default_user
254 reg_perm.permission = perm
255 Session().add(reg_perm)
256
257 def step_7(self):
258 perm_fixes = self.klass.reset_permissions(User.DEFAULT_USER)
259 Session().commit()
260 if perm_fixes:
261 notify('There was an inconsistent state of permissions '
262 'detected for default user. Permissions are now '
263 'reset to the default value for default user. '
264 'Please validate and check default permissions '
265 'in admin panel')
251 266
252 267 upgrade_steps = [0] + range(curr_version + 1, __dbversion__ + 1)
253 268
@@ -470,6 +485,28 b' class DbManage(object):'
470 485 log.debug('missing default permission for group %s adding' % g)
471 486 ReposGroupModel()._create_default_perms(g)
472 487
488 def reset_permissions(self, username):
489 """
490 Resets permissions to default state, usefull when old systems had
491 bad permissions, we must clean them up
492
493 :param username:
494 :type username:
495 """
496 default_user = User.get_by_username(username)
497 if not default_user:
498 return
499
500 u2p = UserToPerm.query()\
501 .filter(UserToPerm.user == default_user).all()
502 fixed = False
503 if len(u2p) != len(User.DEFAULT_PERMISSIONS):
504 for p in u2p:
505 Session().delete(p)
506 fixed = True
507 self.populate_default_permissions()
508 return fixed
509
473 510 def config_prompt(self, test_repo_path='', retries=3, defaults={}):
474 511 _path = defaults.get('repos_location')
475 512 if retries == 3:
@@ -506,7 +543,15 b' class DbManage(object):'
506 543 retries -= 1
507 544 return self.config_prompt(test_repo_path, retries)
508 545
509 return path
546 real_path = os.path.realpath(path)
547
548 if real_path != path:
549 if not ask_ok(('Path looks like a symlink, Rhodecode will store '
550 'given path as %s ? [y/n]') % (real_path)):
551 log.error('Canceled by user')
552 sys.exit(-1)
553
554 return real_path
510 555
511 556 def create_settings(self, path):
512 557
@@ -597,8 +642,7 b' class DbManage(object):'
597 642
598 643 default_user = User.get_by_username('default')
599 644
600 for def_perm in ['hg.register.manual_activate', 'hg.create.repository',
601 'hg.fork.repository', 'repository.read']:
645 for def_perm in User.DEFAULT_PERMISSIONS:
602 646
603 647 perm = self.sa.query(Permission)\
604 648 .filter(Permission.permission_name == def_perm)\
@@ -1317,4 +1317,4 b' class PullRequest(Base, BaseModel):'
1317 1317 org_repo_id = Column('org_repo_id', Integer(), ForeignKey('repositories.repo_id'), nullable=False)
1318 1318 org_ref = Column('org_ref', Unicode(256), nullable=False)
1319 1319 other_repo_id = Column('other_repo_id', Integer(), ForeignKey('repositories.repo_id'), nullable=False)
1320 other_ref = Column('other_ref', Unicode(256), nullable=False) No newline at end of file
1320 other_ref = Column('other_ref', Unicode(256), nullable=False)
@@ -49,7 +49,7 b' def upgrade(migrate_engine):'
49 49 tbl = ChangesetStatus.__table__
50 50 tbl.create()
51 51
52 ## RESET COMPLETLY THE metadata for sqlalchemy to use the 1_3_0 Base
52 ## RESET COMPLETLY THE metadata for sqlalchemy to use the 1_3_0 Base
53 53 Base = declarative_base()
54 54 Base.metadata.clear()
55 55 Base.metadata = MetaData()
@@ -610,7 +610,7 b' def differ(org_repo, org_ref, other_repo'
610 610 other_repo.ui.setconfig('hooks', k, None)
611 611
612 612 unbundle = other_repo.getbundle('incoming', common=common,
613 heads=rheads)
613 heads=None)
614 614
615 615 buf = BytesIO()
616 616 while True:
@@ -92,7 +92,7 b' try:'
92 92 return _obj_dump(obj)
93 93 except NotImplementedError:
94 94 pass
95 return json.JSONEncoder.default(self, obj)
95 raise TypeError("%r is not JSON serializable" % (obj,))
96 96 # monkey-patch JSON encoder to use extended version
97 97 json.dumps = functools.partial(json.dumps, cls=ExtendedEncoder)
98 98 json.dump = functools.partial(json.dump, cls=ExtendedEncoder)
@@ -34,10 +34,9 b' from rhodecode.lib import helpers as h'
34 34 from rhodecode.lib.utils import action_logger
35 35 from rhodecode.lib.vcs.backends.base import EmptyChangeset
36 36 from rhodecode.lib.compat import json
37 from rhodecode.model.db import Repository, User
37 from rhodecode.lib.exceptions import HTTPLockedRC
38 38 from rhodecode.lib.utils2 import safe_str
39 from rhodecode.lib.exceptions import HTTPLockedRC
40
39 from rhodecode.model.db import Repository, User
41 40
42 41 def _get_scm_size(alias, root_path):
43 42
@@ -330,7 +329,12 b' def handle_git_receive(repo_path, revs, '
330 329 # fix if it's not a bare repo
331 330 if repo_path.endswith('.git'):
332 331 repo_path = repo_path[:-4]
332
333 333 repo = Repository.get_by_full_path(repo_path)
334 if not repo:
335 raise OSError('Repository %s not found in database'
336 % (safe_str(repo_path)))
337
334 338 _hooks = dict(baseui.configitems('hooks')) or {}
335 339
336 340 extras = json.loads(env['RHODECODE_EXTRAS'])
@@ -206,7 +206,7 b' def get_repos(path, recursive=False):'
206 206 def is_valid_repo(repo_name, base_path, scm=None):
207 207 """
208 208 Returns True if given path is a valid repository False otherwise.
209 If scm param is given also compare if given scm is the same as expected
209 If scm param is given also compare if given scm is the same as expected
210 210 from scm parameter
211 211
212 212 :param repo_name:
@@ -413,6 +413,11 b' def repo2db_mapper(initial_repo_list, re'
413 413 raise Exception('Missing administrative account !')
414 414 added = []
415 415
416 # # clear cache keys
417 # log.debug("Clearing cache keys now...")
418 # CacheInvalidation.clear_cache()
419 # sa.commit()
420
416 421 for name, repo in initial_repo_list.items():
417 422 group = map_groups(name)
418 423 db_repo = rm.get_by_repo_name(name)
@@ -438,6 +443,11 b' def repo2db_mapper(initial_repo_list, re'
438 443 elif install_git_hook:
439 444 if db_repo.repo_type == 'git':
440 445 ScmModel().install_git_hook(db_repo.scm_instance)
446 # during starting install all cache keys for all repositories in the
447 # system, this will register all repos and multiple instances
448 key, _prefix, _org_key = CacheInvalidation._get_key(name)
449 log.debug("Creating cache key for %s instance_id:`%s`" % (name, _prefix))
450 CacheInvalidation._get_or_create_key(key, _prefix, _org_key, commit=False)
441 451 sa.commit()
442 452 removed = []
443 453 if remove_obsolete:
@@ -455,10 +465,6 b' def repo2db_mapper(initial_repo_list, re'
455 465 log.error(traceback.format_exc())
456 466 sa.rollback()
457 467
458 # clear cache keys
459 log.debug("Clearing cache keys now...")
460 CacheInvalidation.clear_cache()
461 sa.commit()
462 468 return added, removed
463 469
464 470
@@ -178,7 +178,7 b' class GitRepository(BaseRepository):'
178 178 raise urllib2.URLError("[%s] %s" % (url, e))
179 179
180 180 def _get_repo(self, create, src_url=None, update_after_clone=False,
181 bare=False):
181 bare=False):
182 182 if create and os.path.exists(self.path):
183 183 raise RepositoryError("Location already exist")
184 184 if src_url and not create:
@@ -14,4 +14,5 b' from mercurial.node import hex'
14 14 from mercurial.encoding import tolocal
15 15 from mercurial import discovery
16 16 from mercurial import localrepo
17 from mercurial import scmutil No newline at end of file
17 from mercurial import scmutil
18 from mercurial.discovery import findcommonoutgoing
@@ -64,7 +64,7 b' class ChangesetStatusModel(BaseModel):'
64 64
65 65 def calculate_status(self, statuses_by_reviewers):
66 66 """
67 leading one wins, if number of occurences are equal than weaker wins
67 leading one wins, if number of occurrences are equal than weaker wins
68 68
69 69 :param statuses_by_reviewers:
70 70 """
@@ -123,18 +123,20 b' class ChangesetCommentsModel(BaseModel):'
123 123 recipients = ChangesetComment.get_users(revision=revision)
124 124 # add changeset author if it's in rhodecode system
125 125 recipients += [User.get_by_email(author_email)]
126 email_kwargs = {
127 'status_change': status_change,
128 }
126 129 #pull request
127 130 elif pull_request:
131 _url = h.url('pullrequest_show',
132 repo_name=pull_request.other_repo.repo_name,
133 pull_request_id=pull_request.pull_request_id,
134 anchor='comment-%s' % comment.comment_id,
135 qualified=True,
136 )
128 137 subj = safe_unicode(
129 138 h.link_to('Re pull request: %(desc)s %(line)s' % \
130 {'desc': desc, 'line': line},
131 h.url('pullrequest_show',
132 repo_name=pull_request.other_repo.repo_name,
133 pull_request_id=pull_request.pull_request_id,
134 anchor='comment-%s' % comment.comment_id,
135 qualified=True,
136 )
137 )
139 {'desc': desc, 'line': line}, _url)
138 140 )
139 141
140 142 notification_type = Notification.TYPE_PULL_REQUEST_COMMENT
@@ -144,22 +146,36 b' class ChangesetCommentsModel(BaseModel):'
144 146 # add pull request author
145 147 recipients += [pull_request.author]
146 148
149 # add the reviewers to notification
150 recipients += [x.user for x in pull_request.reviewers]
151
152 #set some variables for email notification
153 email_kwargs = {
154 'pr_id': pull_request.pull_request_id,
155 'status_change': status_change,
156 'pr_comment_url': _url,
157 'pr_comment_user': h.person(user.email),
158 'pr_target_repo': h.url('summary_home',
159 repo_name=pull_request.other_repo.repo_name,
160 qualified=True)
161 }
147 162 # create notification objects, and emails
148 163 NotificationModel().create(
149 created_by=user, subject=subj, body=body,
150 recipients=recipients, type_=notification_type,
151 email_kwargs={'status_change': status_change}
164 created_by=user, subject=subj, body=body,
165 recipients=recipients, type_=notification_type,
166 email_kwargs=email_kwargs
152 167 )
153 168
154 169 mention_recipients = set(self._extract_mentions(body))\
155 170 .difference(recipients)
156 171 if mention_recipients:
172 email_kwargs.update({'pr_mention': True})
157 173 subj = _('[Mention]') + ' ' + subj
158 174 NotificationModel().create(
159 175 created_by=user, subject=subj, body=body,
160 176 recipients=mention_recipients,
161 177 type_=notification_type,
162 email_kwargs={'status_change': status_change}
178 email_kwargs=email_kwargs
163 179 )
164 180
165 181 return comment
@@ -278,6 +278,10 b' class RhodeCodeUi(Base, BaseModel):'
278 278
279 279 Session().add(new_ui)
280 280
281 def __repr__(self):
282 return '<DB:%s[%s:%s]>' % (self.__class__.__name__, self.ui_key,
283 self.ui_value)
284
281 285
282 286 class User(Base, BaseModel):
283 287 __tablename__ = 'users'
@@ -289,7 +293,10 b' class User(Base, BaseModel):'
289 293 'mysql_charset': 'utf8'}
290 294 )
291 295 DEFAULT_USER = 'default'
292
296 DEFAULT_PERMISSIONS = [
297 'hg.register.manual_activate', 'hg.create.repository',
298 'hg.fork.repository', 'repository.read'
299 ]
293 300 user_id = Column("user_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
294 301 username = Column("username", String(255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
295 302 password = Column("password", String(255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
@@ -602,6 +609,7 b' class Repository(Base, BaseModel):'
602 609 enable_downloads = Column("downloads", Boolean(), nullable=True, unique=None, default=True)
603 610 description = Column("description", String(10000, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
604 611 created_on = Column('created_on', DateTime(timezone=False), nullable=True, unique=None, default=datetime.datetime.now)
612 updated_on = Column('updated_on', DateTime(timezone=False), nullable=True, unique=None, default=datetime.datetime.now)
605 613 landing_rev = Column("landing_revision", String(255, convert_unicode=False, assert_unicode=None), nullable=False, unique=False, default=None)
606 614 enable_locking = Column("enable_locking", Boolean(), nullable=False, unique=None, default=False)
607 615 _locked = Column("locked", String(255, convert_unicode=False, assert_unicode=None), nullable=True, unique=False, default=None)
@@ -742,6 +750,16 b' class Repository(Base, BaseModel):'
742 750 p += self.repo_name.split(Repository.url_sep())
743 751 return os.path.join(*p)
744 752
753 @property
754 def cache_keys(self):
755 """
756 Returns associated cache keys for that repo
757 """
758 return CacheInvalidation.query()\
759 .filter(CacheInvalidation.cache_args == self.repo_name)\
760 .order_by(CacheInvalidation.cache_key)\
761 .all()
762
745 763 def get_new_name(self, repo_name):
746 764 """
747 765 returns new full repository name based on assigned group and new new
@@ -1398,6 +1416,13 b' class CacheInvalidation(Base, BaseModel)'
1398 1416 return u"<%s('%s:%s')>" % (self.__class__.__name__,
1399 1417 self.cache_id, self.cache_key)
1400 1418
1419 @property
1420 def prefix(self):
1421 _split = self.cache_key.split(self.cache_args, 1)
1422 if _split and len(_split) == 2:
1423 return _split[0]
1424 return ''
1425
1401 1426 @classmethod
1402 1427 def clear_cache(cls):
1403 1428 cls.query().delete()
@@ -1421,13 +1446,14 b' class CacheInvalidation(Base, BaseModel)'
1421 1446 return cls.query().filter(cls.cache_key == key).scalar()
1422 1447
1423 1448 @classmethod
1424 def _get_or_create_key(cls, key, prefix, org_key):
1449 def _get_or_create_key(cls, key, prefix, org_key, commit=True):
1425 1450 inv_obj = Session().query(cls).filter(cls.cache_key == key).scalar()
1426 1451 if not inv_obj:
1427 1452 try:
1428 1453 inv_obj = CacheInvalidation(key, org_key)
1429 1454 Session().add(inv_obj)
1430 Session().commit()
1455 if commit:
1456 Session().commit()
1431 1457 except Exception:
1432 1458 log.error(traceback.format_exc())
1433 1459 Session().rollback()
@@ -128,6 +128,7 b' def ReposGroupForm(edit=False, old_data='
128 128 testValueList=True,
129 129 if_missing=None, not_empty=False)
130 130 enable_locking = v.StringBoolean(if_missing=False)
131 recursive = v.StringBoolean(if_missing=False)
131 132 chained_validators = [v.ValidReposGroup(edit, old_data),
132 133 v.ValidPerms('group')]
133 134
@@ -340,4 +341,4 b' def PullRequestForm():'
340 341 pullrequest_title = v.UnicodeString(strip=True, required=True, min=3)
341 342 pullrequest_desc = v.UnicodeString(strip=True, required=False)
342 343
343 return _PullRequestForm No newline at end of file
344 return _PullRequestForm
@@ -245,6 +245,7 b' class EmailNotificationModel(BaseModel):'
245 245 TYPE_PASSWORD_RESET = 'passoword_link'
246 246 TYPE_REGISTRATION = Notification.TYPE_REGISTRATION
247 247 TYPE_PULL_REQUEST = Notification.TYPE_PULL_REQUEST
248 TYPE_PULL_REQUEST_COMMENT = Notification.TYPE_PULL_REQUEST_COMMENT
248 249 TYPE_DEFAULT = 'default'
249 250
250 251 def __init__(self):
@@ -255,7 +256,9 b' class EmailNotificationModel(BaseModel):'
255 256 self.TYPE_CHANGESET_COMMENT: 'email_templates/changeset_comment.html',
256 257 self.TYPE_PASSWORD_RESET: 'email_templates/password_reset.html',
257 258 self.TYPE_REGISTRATION: 'email_templates/registration.html',
258 self.TYPE_DEFAULT: 'email_templates/default.html'
259 self.TYPE_DEFAULT: 'email_templates/default.html',
260 self.TYPE_PULL_REQUEST: 'email_templates/pull_request.html',
261 self.TYPE_PULL_REQUEST_COMMENT: 'email_templates/pull_request_comment.html',
259 262 }
260 263
261 264 def get_email_tmpl(self, type_, **kwargs):
@@ -77,7 +77,7 b' class PermissionModel(BaseModel):'
77 77 form_result['perm_user_name']).scalar()
78 78 u2p = self.sa.query(UserToPerm).filter(UserToPerm.user ==
79 79 perm_user).all()
80 if len(u2p) != 4:
80 if len(u2p) != len(User.DEFAULT_PERMISSIONS):
81 81 raise Exception('Defined: %s should be 4 permissions for default'
82 82 ' user. This should not happen please verify'
83 83 ' your database' % len(u2p))
@@ -36,7 +36,8 b' from rhodecode.model.db import PullReque'
36 36 from rhodecode.model.notification import NotificationModel
37 37 from rhodecode.lib.utils2 import safe_unicode
38 38
39 from rhodecode.lib.vcs.utils.hgcompat import discovery, localrepo, scmutil
39 from rhodecode.lib.vcs.utils.hgcompat import discovery, localrepo, scmutil, \
40 findcommonoutgoing
40 41
41 42 log = logging.getLogger(__name__)
42 43
@@ -79,22 +80,30 b' class PullRequestModel(BaseModel):'
79 80 #notification to reviewers
80 81 notif = NotificationModel()
81 82
83 pr_url = h.url('pullrequest_show', repo_name=other_repo.repo_name,
84 pull_request_id=new.pull_request_id,
85 qualified=True,
86 )
82 87 subject = safe_unicode(
83 88 h.link_to(
84 89 _('%(user)s wants you to review pull request #%(pr_id)s') % \
85 90 {'user': created_by_user.username,
86 91 'pr_id': new.pull_request_id},
87 h.url('pullrequest_show', repo_name=other_repo.repo_name,
88 pull_request_id=new.pull_request_id,
89 qualified=True,
90 )
92 pr_url
91 93 )
92 94 )
93 95 body = description
96 kwargs = {
97 'pr_title': title,
98 'pr_user_created': h.person(created_by_user.email),
99 'pr_repo_url': h.url('summary_home', repo_name=other_repo.repo_name,
100 qualified=True,),
101 'pr_url': pr_url,
102 'pr_revisions': revisions
103 }
94 104 notif.create(created_by=created_by_user, subject=subject, body=body,
95 105 recipients=reviewers,
96 type_=Notification.TYPE_PULL_REQUEST,)
97
106 type_=Notification.TYPE_PULL_REQUEST, email_kwargs=kwargs)
98 107 return new
99 108
100 109 def update_reviewers(self, pull_request, reviewers_ids):
@@ -156,7 +165,10 b' class PullRequestModel(BaseModel):'
156 165 #case two independent repos
157 166 common, incoming, rheads = discovery_data
158 167 if org_repo != other_repo and incoming:
159 revs = org_repo._repo.changelog.findmissing(common, rheads)
168 obj = findcommonoutgoing(org_repo._repo,
169 localrepo.locallegacypeer(other_repo._repo.local()),
170 force=True)
171 revs = obj.missing
160 172
161 173 for cs in reversed(map(binascii.hexlify, revs)):
162 174 changesets.append(org_repo.get_changeset(cs))
@@ -205,6 +217,7 b' class PullRequestModel(BaseModel):'
205 217 log.debug('Doing discovery for %s@%s vs %s@%s' % (
206 218 org_repo, org_ref, other_repo, other_ref)
207 219 )
220
208 221 #log.debug('Filter heads are %s[%s]' % ('', org_ref[1]))
209 222 org_peer = localrepo.locallegacypeer(_org_repo.local())
210 223 tmp = discovery.findcommonincoming(
@@ -212,7 +225,7 b' class PullRequestModel(BaseModel):'
212 225 remote=org_peer, # org_repo source for incoming
213 226 heads=[_other_repo[other_rev].node(),
214 227 _org_repo[org_rev].node()],
215 force=False
228 force=True
216 229 )
217 230 return tmp
218 231
@@ -368,6 +368,7 b' class RepoModel(BaseModel):'
368 368 obj.user = user
369 369 obj.permission = permission
370 370 self.sa.add(obj)
371 log.debug('Granted perm %s to %s on %s' % (perm, user, repo))
371 372
372 373 def revoke_user_permission(self, repo, user):
373 374 """
@@ -383,8 +384,10 b' class RepoModel(BaseModel):'
383 384 obj = self.sa.query(UserRepoToPerm)\
384 385 .filter(UserRepoToPerm.repository == repo)\
385 386 .filter(UserRepoToPerm.user == user)\
386 .one()
387 self.sa.delete(obj)
387 .scalar()
388 if obj:
389 self.sa.delete(obj)
390 log.debug('Revoked perm on %s on %s' % (repo, user))
388 391
389 392 def grant_users_group_permission(self, repo, group_name, perm):
390 393 """
@@ -414,6 +417,7 b' class RepoModel(BaseModel):'
414 417 obj.users_group = group_name
415 418 obj.permission = permission
416 419 self.sa.add(obj)
420 log.debug('Granted perm %s to %s on %s' % (perm, group_name, repo))
417 421
418 422 def revoke_users_group_permission(self, repo, group_name):
419 423 """
@@ -429,8 +433,10 b' class RepoModel(BaseModel):'
429 433 obj = self.sa.query(UsersGroupRepoToPerm)\
430 434 .filter(UsersGroupRepoToPerm.repository == repo)\
431 435 .filter(UsersGroupRepoToPerm.users_group == group_name)\
432 .one()
433 self.sa.delete(obj)
436 .scalar()
437 if obj:
438 self.sa.delete(obj)
439 log.debug('Revoked perm to %s on %s' % (repo, group_name))
434 440
435 441 def delete_stats(self, repo_name):
436 442 """
@@ -32,7 +32,7 b' from rhodecode.lib.utils2 import LazyPro'
32 32
33 33 from rhodecode.model import BaseModel
34 34 from rhodecode.model.db import RepoGroup, RhodeCodeUi, UserRepoGroupToPerm, \
35 User, Permission, UsersGroupRepoGroupToPerm, UsersGroup
35 User, Permission, UsersGroupRepoGroupToPerm, UsersGroup, Repository
36 36
37 37 log = logging.getLogger(__name__)
38 38
@@ -115,11 +115,12 b' class ReposGroupModel(BaseModel):'
115 115 'existing dir %s' % new_path)
116 116 shutil.move(old_path, new_path)
117 117
118 def __delete_group(self, group):
118 def __delete_group(self, group, force_delete=False):
119 119 """
120 120 Deletes a group from a filesystem
121 121
122 122 :param group: instance of group from database
123 :param force_delete: use shutil rmtree to remove all objects
123 124 """
124 125 paths = group.full_path.split(RepoGroup.url_sep())
125 126 paths = os.sep.join(paths)
@@ -127,7 +128,10 b' class ReposGroupModel(BaseModel):'
127 128 rm_path = os.path.join(self.repos_path, paths)
128 129 if os.path.isdir(rm_path):
129 130 # delete only if that path really exists
130 os.rmdir(rm_path)
131 if force_delete:
132 shutil.rmtree(rm_path)
133 else:
134 os.rmdir(rm_path) # this raises an exception when there are still objects inside
131 135
132 136 def create(self, group_name, group_description, parent=None, just_db=False):
133 137 try:
@@ -150,32 +154,79 b' class ReposGroupModel(BaseModel):'
150 154 log.error(traceback.format_exc())
151 155 raise
152 156
157 def _update_permissions(self, repos_group, perms_new=None,
158 perms_updates=None, recursive=False):
159 from rhodecode.model.repo import RepoModel
160 if not perms_new:
161 perms_new = []
162 if not perms_updates:
163 perms_updates = []
164
165 def _set_perm_user(obj, user, perm):
166 if isinstance(obj, RepoGroup):
167 ReposGroupModel().grant_user_permission(
168 repos_group=obj, user=user, perm=perm
169 )
170 elif isinstance(obj, Repository):
171 # we set group permission but we have to switch to repo
172 # permission
173 perm = perm.replace('group.', 'repository.')
174 RepoModel().grant_user_permission(
175 repo=obj, user=user, perm=perm
176 )
177
178 def _set_perm_group(obj, users_group, perm):
179 if isinstance(obj, RepoGroup):
180 ReposGroupModel().grant_users_group_permission(
181 repos_group=obj, group_name=users_group, perm=perm
182 )
183 elif isinstance(obj, Repository):
184 # we set group permission but we have to switch to repo
185 # permission
186 perm = perm.replace('group.', 'repository.')
187 RepoModel().grant_users_group_permission(
188 repo=obj, group_name=users_group, perm=perm
189 )
190 updates = []
191 log.debug('Now updating permissions for %s in recursive mode:%s'
192 % (repos_group, recursive))
193
194 for obj in repos_group.recursive_groups_and_repos():
195 if not recursive:
196 obj = repos_group
197
198 # update permissions
199 for member, perm, member_type in perms_updates:
200 ## set for user
201 if member_type == 'user':
202 # this updates also current one if found
203 _set_perm_user(obj, user=member, perm=perm)
204 ## set for users group
205 else:
206 _set_perm_group(obj, users_group=member, perm=perm)
207 # set new permissions
208 for member, perm, member_type in perms_new:
209 if member_type == 'user':
210 _set_perm_user(obj, user=member, perm=perm)
211 else:
212 _set_perm_group(obj, users_group=member, perm=perm)
213 updates.append(obj)
214 #if it's not recursive call
215 # break the loop and don't proceed with other changes
216 if not recursive:
217 break
218 return updates
219
153 220 def update(self, repos_group_id, form_data):
154 221
155 222 try:
156 223 repos_group = RepoGroup.get(repos_group_id)
157
158 # update permissions
159 for member, perm, member_type in form_data['perms_updates']:
160 if member_type == 'user':
161 # this updates also current one if found
162 ReposGroupModel().grant_user_permission(
163 repos_group=repos_group, user=member, perm=perm
164 )
165 else:
166 ReposGroupModel().grant_users_group_permission(
167 repos_group=repos_group, group_name=member, perm=perm
168 )
169 # set new permissions
170 for member, perm, member_type in form_data['perms_new']:
171 if member_type == 'user':
172 ReposGroupModel().grant_user_permission(
173 repos_group=repos_group, user=member, perm=perm
174 )
175 else:
176 ReposGroupModel().grant_users_group_permission(
177 repos_group=repos_group, group_name=member, perm=perm
178 )
224 recursive = form_data['recursive']
225 # iterate over all members(if in recursive mode) of this groups and
226 # set the permissions !
227 # this can be potentially heavy operation
228 self._update_permissions(repos_group, form_data['perms_new'],
229 form_data['perms_updates'], recursive)
179 230
180 231 old_path = repos_group.full_path
181 232
@@ -191,7 +242,6 b' class ReposGroupModel(BaseModel):'
191 242
192 243 # iterate over all members of this groups and set the locking !
193 244 # this can be potentially heavy operation
194
195 245 for obj in repos_group.recursive_groups_and_repos():
196 246 #set the value from it's parent
197 247 obj.enable_locking = repos_group.enable_locking
@@ -210,15 +260,54 b' class ReposGroupModel(BaseModel):'
210 260 log.error(traceback.format_exc())
211 261 raise
212 262
213 def delete(self, repos_group):
263 def delete(self, repos_group, force_delete=False):
214 264 repos_group = self._get_repos_group(repos_group)
215 265 try:
216 266 self.sa.delete(repos_group)
217 self.__delete_group(repos_group)
267 self.__delete_group(repos_group, force_delete)
218 268 except:
219 269 log.exception('Error removing repos_group %s' % repos_group)
220 270 raise
221 271
272 def delete_permission(self, repos_group, obj, obj_type, recursive):
273 """
274 Revokes permission for repos_group for given obj(user or users_group),
275 obj_type can be user or users group
276
277 :param repos_group:
278 :param obj: user or users group id
279 :param obj_type: user or users group type
280 :param recursive: recurse to all children of group
281 """
282 from rhodecode.model.repo import RepoModel
283 repos_group = self._get_repos_group(repos_group)
284
285 for el in repos_group.recursive_groups_and_repos():
286 if not recursive:
287 # if we don't recurse set the permission on only the top level
288 # object
289 el = repos_group
290
291 if isinstance(el, RepoGroup):
292 if obj_type == 'user':
293 ReposGroupModel().revoke_user_permission(el, user=obj)
294 elif obj_type == 'users_group':
295 ReposGroupModel().revoke_users_group_permission(el, group_name=obj)
296 else:
297 raise Exception('undefined object type %s' % obj_type)
298 elif isinstance(el, Repository):
299 if obj_type == 'user':
300 RepoModel().revoke_user_permission(el, user=obj)
301 elif obj_type == 'users_group':
302 RepoModel().revoke_users_group_permission(el, group_name=obj)
303 else:
304 raise Exception('undefined object type %s' % obj_type)
305
306 #if it's not recursive call
307 # break the loop and don't proceed with other changes
308 if not recursive:
309 break
310
222 311 def grant_user_permission(self, repos_group, user, perm):
223 312 """
224 313 Grant permission for user on given repositories group, or update
@@ -246,6 +335,7 b' class ReposGroupModel(BaseModel):'
246 335 obj.user = user
247 336 obj.permission = permission
248 337 self.sa.add(obj)
338 log.debug('Granted perm %s to %s on %s' % (perm, user, repos_group))
249 339
250 340 def revoke_user_permission(self, repos_group, user):
251 341 """
@@ -262,8 +352,10 b' class ReposGroupModel(BaseModel):'
262 352 obj = self.sa.query(UserRepoGroupToPerm)\
263 353 .filter(UserRepoGroupToPerm.user == user)\
264 354 .filter(UserRepoGroupToPerm.group == repos_group)\
265 .one()
266 self.sa.delete(obj)
355 .scalar()
356 if obj:
357 self.sa.delete(obj)
358 log.debug('Revoked perm on %s on %s' % (repos_group, user))
267 359
268 360 def grant_users_group_permission(self, repos_group, group_name, perm):
269 361 """
@@ -294,6 +386,7 b' class ReposGroupModel(BaseModel):'
294 386 obj.users_group = group_name
295 387 obj.permission = permission
296 388 self.sa.add(obj)
389 log.debug('Granted perm %s to %s on %s' % (perm, group_name, repos_group))
297 390
298 391 def revoke_users_group_permission(self, repos_group, group_name):
299 392 """
@@ -310,5 +403,7 b' class ReposGroupModel(BaseModel):'
310 403 obj = self.sa.query(UsersGroupRepoGroupToPerm)\
311 404 .filter(UsersGroupRepoGroupToPerm.group == repos_group)\
312 405 .filter(UsersGroupRepoGroupToPerm.users_group == group_name)\
313 .one()
314 self.sa.delete(obj)
406 .scalar()
407 if obj:
408 self.sa.delete(obj)
409 log.debug('Revoked perm to %s on %s' % (repos_group, group_name))
@@ -564,7 +564,7 b' class UserModel(BaseModel):'
564 564 rg_k = perm.UserRepoGroupToPerm.group.group_name
565 565 p = perm.Permission.permission_name
566 566 cur_perm = user.permissions[GK][rg_k]
567 if PERM_WEIGHTS[p] > PERM_WEIGHTS[cur_perm]:
567 if PERM_WEIGHTS[p] > PERM_WEIGHTS[cur_perm] or 1: # disable check
568 568 user.permissions[GK][rg_k] = p
569 569
570 570 # REPO GROUP + USER GROUP
@@ -588,7 +588,7 b' class UserModel(BaseModel):'
588 588 cur_perm = user.permissions[GK][g_k]
589 589 # overwrite permission only if it's greater than permission
590 590 # given from other sources
591 if PERM_WEIGHTS[p] > PERM_WEIGHTS[cur_perm]:
591 if PERM_WEIGHTS[p] > PERM_WEIGHTS[cur_perm] or 1: # disable check
592 592 user.permissions[GK][g_k] = p
593 593
594 594 return user
@@ -499,9 +499,9 b" def ValidPerms(type_='repo'):"
499 499 # fill new permissions in order of how they were added
500 500 for k in sorted(map(int, new_perms_group.keys())):
501 501 perm_dict = new_perms_group[str(k)]
502 new_member = perm_dict['name']
503 new_perm = perm_dict['perm']
504 new_type = perm_dict['type']
502 new_member = perm_dict.get('name')
503 new_perm = perm_dict.get('perm')
504 new_type = perm_dict.get('type')
505 505 if new_member and new_perm and new_type:
506 506 perms_new.add((new_member, new_perm, new_type))
507 507
@@ -115,7 +115,7 b''
115 115 ${h.checkbox('enable_locking',value="True")}
116 116 <span class="help-block">${_('Enable lock-by-pulling on repository.')}</span>
117 117 </div>
118 </div>
118 </div>
119 119 <div class="field">
120 120 <div class="label">
121 121 <label for="user">${_('Owner')}:</label>
@@ -188,6 +188,20 b''
188 188 <div class="form">
189 189 <div class="fields">
190 190 ${h.submit('reset_cache_%s' % c.repo_info.repo_name,_('Invalidate repository cache'),class_="ui-btn",onclick="return confirm('"+_('Confirm to invalidate repository cache')+"');")}
191 <div class="field" style="border:none;color:#888">
192 <ul>
193 <li>${_('Manually invalidate cache for this repository. On first access repository will be cached again')}
194 </li>
195 </ul>
196 </div>
197 <div class="field" style="border:none;">
198 ${_('List of cached values')}
199 <ul>
200 %for cache in c.repo_info.cache_keys:
201 <li>INSTANCE ID:${cache.prefix or '-'} ${cache.cache_args} CACHED: ${h.bool2icon(cache.cache_active)}</li>
202 %endfor
203 </ul>
204 </div>
191 205 </div>
192 206 </div>
193 207 ${h.end_form()}
@@ -195,20 +209,20 b''
195 209 <h3>${_('Public journal')}</h3>
196 210 ${h.form(url('repo_public_journal', repo_name=c.repo_info.repo_name),method='put')}
197 211 <div class="form">
198 ${h.hidden('auth_token',str(h.get_token()))}
199 <div class="field">
200 %if c.in_public_journal:
201 ${h.submit('set_public_%s' % c.repo_info.repo_name,_('Remove from public journal'),class_="ui-btn")}
202 %else:
203 ${h.submit('set_public_%s' % c.repo_info.repo_name,_('Add to public journal'),class_="ui-btn")}
204 %endif
205 </div>
206 <div class="field" style="border:none;color:#888">
207 <ul>
208 <li>${_('All actions made on this repository will be accessible to everyone in public journal')}
209 </li>
210 </ul>
211 </div>
212 ${h.hidden('auth_token',str(h.get_token()))}
213 <div class="field">
214 %if c.in_public_journal:
215 ${h.submit('set_public_%s' % c.repo_info.repo_name,_('Remove from public journal'),class_="ui-btn")}
216 %else:
217 ${h.submit('set_public_%s' % c.repo_info.repo_name,_('Add to public journal'),class_="ui-btn")}
218 %endif
219 </div>
220 <div class="field" style="border:none;color:#888">
221 <ul>
222 <li>${_('All actions made on this repository will be accessible to everyone in public journal')}
223 </li>
224 </ul>
225 </div>
212 226 </div>
213 227 ${h.end_form()}
214 228
@@ -229,7 +243,7 b''
229 243 <li>${_('Force locking on repository. Works only when anonymous access is disabled')}
230 244 </li>
231 245 </ul>
232 </div>
246 </div>
233 247 </div>
234 248 ${h.end_form()}
235 249
@@ -245,9 +259,9 b''
245 259 <li>${_('''Manually set this repository as a fork of another from the list''')}</li>
246 260 </ul>
247 261 </div>
248 </div>
262 </div>
249 263 ${h.end_form()}
250
264
251 265 <h3>${_('Delete')}</h3>
252 266 ${h.form(url('repo', repo_name=c.repo_info.repo_name),method='delete')}
253 267 <div class="form">
@@ -262,7 +276,7 b''
262 276 </ul>
263 277 </div>
264 278 </div>
265 ${h.end_form()}
279 ${h.end_form()}
266 280 </div>
267 281
268 282 </%def>
@@ -74,8 +74,8 b''
74 74 </div> \
75 75 </td> \
76 76 <td></td>'""")
77 %>
78 ## ADD HERE DYNAMICALLY NEW INPUTS FROM THE '_tmpl'
77 %>
78 ## ADD HERE DYNAMICALLY NEW INPUTS FROM THE '_tmpl'
79 79 <tr class="new_members last_new_member" id="add_perm_input"></tr>
80 80 <tr>
81 81 <td colspan="6">
@@ -58,8 +58,8 b''
58 58 </div> \
59 59 </td> \
60 60 <td></td>'""")
61 %>
62 ## ADD HERE DYNAMICALLY NEW INPUTS FROM THE '_tmpl'
61 %>
62 ## ADD HERE DYNAMICALLY NEW INPUTS FROM THE '_tmpl'
63 63 <tr class="new_members last_new_member" id="add_perm_input"></tr>
64 64 <tr>
65 65 <td colspan="6">
@@ -68,6 +68,12 b''
68 68 </span>
69 69 </td>
70 70 </tr>
71 <tr>
72 <td colspan="6">
73 ${h.checkbox('recursive',value="True", label=_('apply to parents'))}
74 <span class="help-block">${_('Set or revoke permission to all children of that group, including repositories and other groups')}</span>
75 </td>
76 </tr>
71 77 </table>
72 78 <script type="text/javascript">
73 79 function ajaxActionUser(user_id, field_id) {
@@ -81,7 +87,8 b' function ajaxActionUser(user_id, field_i'
81 87 alert("${_('Failed to remove user')}");
82 88 },
83 89 };
84 var postData = '_method=delete&user_id=' + user_id;
90 var recursive = YUD.get('recursive').checked;
91 var postData = '_method=delete&recursive={0}&user_id={1}'.format(recursive,user_id);
85 92 var request = YAHOO.util.Connect.asyncRequest('POST', sUrl, callback, postData);
86 93 };
87 94
@@ -96,7 +103,8 b' function ajaxActionUsersGroup(users_grou'
96 103 alert("${_('Failed to remove users group')}");
97 104 },
98 105 };
99 var postData = '_method=delete&users_group_id='+users_group_id;
106 var recursive = YUD.get('recursive').checked;
107 var postData = '_method=delete&recursive={0}&users_group_id={1}'.format(recursive,users_group_id);
100 108 var request = YAHOO.util.Connect.asyncRequest('POST', sUrl, callback, postData);
101 109 };
102 110
@@ -5,7 +5,8 b''
5 5 </%def>
6 6
7 7 <%def name="breadcrumbs()">
8 <span class="groups_breadcrumbs"> ${_('Groups')}
8 <span class="groups_breadcrumbs">
9 ${h.link_to(_(u'Home'),h.url('/'))}
9 10 %if c.group.parent_group:
10 11 &raquo; ${h.link_to(c.group.parent_group.name,h.url('repos_group_home',group_name=c.group.parent_group.group_name))}
11 12 %endif
@@ -69,7 +69,7 b''
69 69 ${h.checkbox('enable_locking',value="True")}
70 70 <span class="help-block">${_('Enable lock-by-pulling on group. This option will be applied to all other groups and repositories inside')}</span>
71 71 </div>
72 </div>
72 </div>
73 73 <div class="buttons">
74 74 ${h.submit('save',_('Save'),class_="ui-btn large")}
75 75 ${h.reset('reset',_('Reset'),class_="ui-btn large")}
@@ -154,7 +154,7 b''
154 154 <li>[stale] <span class="metatag" tag="stale">stale</span></li>
155 155 <li>[dead] <span class="metatag" tag="dead">dead</span></li>
156 156 <li>[lang =&gt; lang] <span class="metatag" tag="lang" >lang</span></li>
157 <li>[license =&gt; License] <span class="metatag" tag="license"><a href="http://www.opensource.org/licenses/License" >License</a></span></li>
157 <li>[license =&gt; License] <span class="metatag" tag="license"><a href="http://www.opensource.org/licenses/License" >License</a></span></li>
158 158 <li>[requires =&gt; Repo] <span class="metatag" tag="requires" >requires =&gt; <a href="#" >Repo</a></span></li>
159 159 <li>[recommends =&gt; Repo] <span class="metatag" tag="recommends" >recommends =&gt; <a href="#" >Repo</a></span></li>
160 160 <li>[see =&gt; URI] <span class="metatag" tag="see">see =&gt; <a href="#">URI</a> </span></li>
@@ -186,7 +186,7 b''
186 186 </div>
187 187 <div class="checkboxes">
188 188 <div class="checkbox">
189 ${h.checkbox('web_push_ssl','true')}
189 ${h.checkbox('web_push_ssl', 'True')}
190 190 <label for="web_push_ssl">${_('require ssl for vcs operations')}</label>
191 191 </div>
192 192 <span class="help-block">${_('RhodeCode will require SSL for pushing or pulling. If SSL is missing it will return HTTP Error 406: Not Acceptable')}</span>
@@ -237,9 +237,9 b''
237 237 ## ${h.checkbox('extensions_hggit','True')}
238 238 ## <label for="extensions_hggit">${_('hg-git extensions')}</label>
239 239 ##</div>
240 ##<span class="help-block">${_('Requires hg-git library installed. Allows clonning from git remote locations')}</span>
240 ##<span class="help-block">${_('Requires hg-git library installed. Allows clonning from git remote locations')}</span>
241 241 </div>
242 </div>
242 </div>
243 243 <div class="field">
244 244 <div class="label">
245 245 <label for="paths_root_path">${_('Repositories location')}:</label>
@@ -152,7 +152,7 b''
152 152 <span class="help-block">${h.literal(_('Select to inherit permissions from %s settings. '
153 153 'With this selected below options does not have any action') % h.link_to('default', url('edit_permission', id='default')))}</span>
154 154 </div>
155 <div id="inherit_overlay" style="${'opacity:0.3' if c.user.inherit_default_permissions else ''}" >
155 <div id="inherit_overlay" style="${'opacity:0.3' if c.user.inherit_default_permissions else ''}" >
156 156 <div class="field">
157 157 <div class="label label-checkbox">
158 158 <label for="create_repo_perm">${_('Create repositories')}:</label>
@@ -169,7 +169,7 b''
169 169 ${h.checkbox('fork_repo_perm',value=True)}
170 170 </div>
171 171 </div>
172 </div>
172 </div>
173 173 <div class="buttons">
174 174 ${h.submit('save',_('Save'),class_="ui-btn large")}
175 175 ${h.reset('reset',_('Reset'),class_="ui-btn large")}
@@ -112,7 +112,7 b''
112 112 </div>
113 113 <span class="help-block">${h.literal(_('Select to inherit permissions from %s settings. '
114 114 'With this selected below options does not have any action') % h.link_to('default', url('edit_permission', id='default')))}</span>
115 </div>
115 </div>
116 116 <div id="inherit_overlay" style="${'opacity:0.3' if c.users_group.inherit_default_permissions else ''}" >
117 117 <div class="field">
118 118 <div class="label label-checkbox">
@@ -130,7 +130,7 b''
130 130 ${h.checkbox('fork_repo_perm',value=True)}
131 131 </div>
132 132 </div>
133 </div>
133 </div>
134 134 <div class="buttons">
135 135 ${h.submit('save',_('Save'),class_="ui-btn large")}
136 136 ${h.reset('reset',_('Reset'),class_="ui-btn large")}
@@ -90,7 +90,7 b''
90 90 f.setAttribute('class','follow');
91 91 f.setAttribute('title',_TM['Start following this repository']);
92 92 if(f_cnt){
93 var cnt = Number(f_cnt.innerHTML)+1;
93 var cnt = Number(f_cnt.innerHTML)-1;
94 94 f_cnt.innerHTML = cnt;
95 95 }
96 96 }
@@ -47,38 +47,38 b' var url_base = \'${h.url("files_nodelist_'
47 47
48 48 var ypjax_links = function(){
49 49 YUE.on(YUQ('.ypjax-link'), 'click',function(e){
50
50
51 51 //don't do ypjax on middle click
52 if(e.which == 2 || !History.enabled){
52 if(e.which == 2 || !History.enabled){
53 53 return true;
54 54 }
55
55
56 56 var el = e.currentTarget;
57 57 var url = el.href;
58 58
59 59 var _base_url = '${h.url("files_home",repo_name=c.repo_name,revision='',f_path='')}';
60 60 _base_url = _base_url.replace('//','/')
61
61
62 62 //extract rev and the f_path from url.
63 63 parts = url.split(_base_url)
64 64 if(parts.length != 2){
65 65 return false;
66 66 }
67
67
68 68 var parts2 = parts[1].split('/');
69 69 var rev = parts2.shift(); // pop the first element which is the revision
70 70 var f_path = parts2.join('/');
71
71
72 72 var title = "${_('%s files') % c.repo_name}" + " - " + f_path;
73
73
74 74 var _node_list_url = node_list_url.replace('__REV__',rev);
75 75 var _url_base = url_base.replace('__REV__',rev).replace('__FPATH__', f_path);
76 76
77 77 // Change our States and save some data for handling events
78 78 var data = {url:url,title:title, url_base:_url_base,
79 79 node_list_url:_node_list_url};
80 History.pushState(data, title, url);
81
80 History.pushState(data, title, url);
81
82 82 //now we're sure that we can do ypjax things
83 83 YUE.preventDefault(e)
84 84 return false;
@@ -92,10 +92,10 b' var callbacks = function(State){'
92 92 // Inform Google Analytics of the change
93 93 if ( typeof window.pageTracker !== 'undefined' ) {
94 94 window.pageTracker._trackPageview(State.url);
95 }
95 }
96 96 }
97 97
98 YUE.onDOMReady(function(){
98 YUE.onDOMReady(function(){
99 99 ypjax_links();
100 100 var container = 'files_data';
101 101 //Bind to StateChange Event
@@ -124,8 +124,8 b' YUE.onDOMReady(function(){'
124 124 }
125 125 });
126 126 }
127 });
128
127 });
128
129 129 // init the search filter
130 130 var _State = {
131 131 url: "${h.url.current()}",
@@ -9,7 +9,7 b''
9 9 <%include file='files_browser.html'/>
10 10 %else:
11 11 <%include file='files_source.html'/>
12 %endif
12 %endif
13 13 %else:
14 14 <h2>
15 15 <a href="#" onClick="javascript:parent.history.back();" target="main">${_('Go back')}</a>
@@ -20,10 +20,10 b''
20 20 ${self.breadcrumbs()}
21 21 </div>
22 22 %if c.pull_request.is_closed():
23 <div style="padding:10px; font-size:22px;width:100%;text-align: center; color:#88D882">${_('Closed %s') % (h.age(c.pull_request.updated_on))}</div>
23 <div style="padding:10px; font-size:22px;width:100%;text-align: center; color:#88D882">${_('Closed %s') % (h.age(c.pull_request.updated_on))} ${_('with status %s') % h.changeset_status_lbl(c.current_changeset_status)}</div>
24 24 %endif
25 25 <h3>${_('Title')}: ${c.pull_request.title}</h3>
26
26
27 27 <div class="form">
28 28 <div id="summary" class="fields">
29 29 <div class="field">
@@ -46,9 +46,9 b''
46 46 <div class="input">
47 47 <div class="tooltip" title="${h.tooltip(','.join([x.username for x in c.pull_request_pending_reviewers]))}">${ungettext('%d reviewer', '%d reviewers',len(c.pull_request_pending_reviewers)) % len(c.pull_request_pending_reviewers)}</div>
48 48 </div>
49 </div>
49 </div>
50 50 </div>
51 </div>
51 </div>
52 52 <div style="white-space:pre-wrap;padding:3px 3px 5px 20px">${h.literal(c.pull_request.description)}</div>
53 53 <div style="padding:4px 4px 10px 20px">
54 54 <div>${_('Created on')}: ${h.fmt_date(c.pull_request.created_on)}</div>
@@ -7,7 +7,7 b''
7 7 <%def name="breadcrumbs_links()">
8 8 ${h.link_to(_(u'Home'),h.url('/'))}
9 9 &raquo;
10 ${h.link_to(c.dbrepo.just_name,h.url('summary_home',repo_name=c.repo_name))}
10 ${h.repo_link(c.dbrepo.groups_and_repo)}
11 11 &raquo;
12 12 ${_('summary')}
13 13 </%def>
@@ -108,7 +108,7 b''
108 108 <div class="input ${summary(c.show_stats)} desc">${h.urlify_text(h.desc_stylize(c.dbrepo.description))}</div>
109 109 %else:
110 110 <div class="input ${summary(c.show_stats)} desc">${h.urlify_text(c.dbrepo.description)}</div>
111 %endif
111 %endif
112 112 </div>
113 113
114 114 <div class="field">
@@ -30,17 +30,17 b' class TestCompareController(TestControll'
30 30 response.mustcontain('''<a href="/%s/changeset/c5ddebc06eaaba3010c2d66ea6ec9d074eb0f678">r112:c5ddebc06eaa</a>''' % HG_REPO)
31 31
32 32 ## files diff
33 response.mustcontain('''<div class="node"><a href="/%s/compare/tag@%s...tag@%s#C--1c5cf9e91c12">docs/api/utils/index.rst</a></div>''' % (HG_REPO, tag1, tag2))
34 response.mustcontain('''<div class="node"><a href="/%s/compare/tag@%s...tag@%s#C--e3305437df55">test_and_report.sh</a></div>''' % (HG_REPO, tag1, tag2))
35 response.mustcontain('''<div class="node"><a href="/%s/compare/tag@%s...tag@%s#C--c8e92ef85cd1">.hgignore</a></div>''' % (HG_REPO, tag1, tag2))
36 response.mustcontain('''<div class="node"><a href="/%s/compare/tag@%s...tag@%s#C--6e08b694d687">.hgtags</a></div>''' % (HG_REPO, tag1, tag2))
37 response.mustcontain('''<div class="node"><a href="/%s/compare/tag@%s...tag@%s#C--2c14b00f3393">docs/api/index.rst</a></div>''' % (HG_REPO, tag1, tag2))
38 response.mustcontain('''<div class="node"><a href="/%s/compare/tag@%s...tag@%s#C--430ccbc82bdf">vcs/__init__.py</a></div>''' % (HG_REPO, tag1, tag2))
39 response.mustcontain('''<div class="node"><a href="/%s/compare/tag@%s...tag@%s#C--9c390eb52cd6">vcs/backends/hg.py</a></div>''' % (HG_REPO, tag1, tag2))
40 response.mustcontain('''<div class="node"><a href="/%s/compare/tag@%s...tag@%s#C--ebb592c595c0">vcs/utils/__init__.py</a></div>''' % (HG_REPO, tag1, tag2))
41 response.mustcontain('''<div class="node"><a href="/%s/compare/tag@%s...tag@%s#C--7abc741b5052">vcs/utils/annotate.py</a></div>''' % (HG_REPO, tag1, tag2))
42 response.mustcontain('''<div class="node"><a href="/%s/compare/tag@%s...tag@%s#C--2ef0ef106c56">vcs/utils/diffs.py</a></div>''' % (HG_REPO, tag1, tag2))
43 response.mustcontain('''<div class="node"><a href="/%s/compare/tag@%s...tag@%s#C--3150cb87d4b7">vcs/utils/lazy.py</a></div>''' % (HG_REPO, tag1, tag2))
33 response.mustcontain('''<div class="node"><a href="/%s/compare/tag@%s...tag@%s#C--1c5cf9e91c12">docs/api/utils/index.rst</a></div>''' % (HG_REPO, tag1, tag2))
34 response.mustcontain('''<div class="node"><a href="/%s/compare/tag@%s...tag@%s#C--e3305437df55">test_and_report.sh</a></div>''' % (HG_REPO, tag1, tag2))
35 response.mustcontain('''<div class="node"><a href="/%s/compare/tag@%s...tag@%s#C--c8e92ef85cd1">.hgignore</a></div>''' % (HG_REPO, tag1, tag2))
36 response.mustcontain('''<div class="node"><a href="/%s/compare/tag@%s...tag@%s#C--6e08b694d687">.hgtags</a></div>''' % (HG_REPO, tag1, tag2))
37 response.mustcontain('''<div class="node"><a href="/%s/compare/tag@%s...tag@%s#C--2c14b00f3393">docs/api/index.rst</a></div>''' % (HG_REPO, tag1, tag2))
38 response.mustcontain('''<div class="node"><a href="/%s/compare/tag@%s...tag@%s#C--430ccbc82bdf">vcs/__init__.py</a></div>''' % (HG_REPO, tag1, tag2))
39 response.mustcontain('''<div class="node"><a href="/%s/compare/tag@%s...tag@%s#C--9c390eb52cd6">vcs/backends/hg.py</a></div>''' % (HG_REPO, tag1, tag2))
40 response.mustcontain('''<div class="node"><a href="/%s/compare/tag@%s...tag@%s#C--ebb592c595c0">vcs/utils/__init__.py</a></div>''' % (HG_REPO, tag1, tag2))
41 response.mustcontain('''<div class="node"><a href="/%s/compare/tag@%s...tag@%s#C--7abc741b5052">vcs/utils/annotate.py</a></div>''' % (HG_REPO, tag1, tag2))
42 response.mustcontain('''<div class="node"><a href="/%s/compare/tag@%s...tag@%s#C--2ef0ef106c56">vcs/utils/diffs.py</a></div>''' % (HG_REPO, tag1, tag2))
43 response.mustcontain('''<div class="node"><a href="/%s/compare/tag@%s...tag@%s#C--3150cb87d4b7">vcs/utils/lazy.py</a></div>''' % (HG_REPO, tag1, tag2))
44 44
45 45 def test_index_branch(self):
46 46 self.log_user()
@@ -183,7 +183,111 b' class TestCompareController(TestControll'
183 183 ## files
184 184 response.mustcontain("""<a href="/%s/compare/branch@%s...branch@%s#C--826e8142e6ba">file1</a>""" % (r2_name, rev1, rev2))
185 185
186
187 186 finally:
188 187 RepoModel().delete(r1_id)
189 188 RepoModel().delete(r2_id)
189
190 def test_org_repo_new_commits_after_forking(self):
191 self.log_user()
192
193 repo1 = RepoModel().create_repo(repo_name='one', repo_type='hg',
194 description='diff-test',
195 owner=TEST_USER_ADMIN_LOGIN)
196
197 Session().commit()
198 r1_id = repo1.repo_id
199 r1_name = repo1.repo_name
200
201 #commit something initially !
202 cs0 = ScmModel().create_node(
203 repo=repo1.scm_instance, repo_name=r1_name,
204 cs=EmptyChangeset(alias='hg'), user=TEST_USER_ADMIN_LOGIN,
205 author=TEST_USER_ADMIN_LOGIN,
206 message='commit1',
207 content='line1',
208 f_path='file1'
209 )
210 Session().commit()
211 self.assertEqual(repo1.scm_instance.revisions, [cs0.raw_id])
212 #fork the repo1
213 repo2 = RepoModel().create_repo(repo_name='one-fork', repo_type='hg',
214 description='compare-test',
215 clone_uri=repo1.repo_full_path,
216 owner=TEST_USER_ADMIN_LOGIN, fork_of='one')
217 Session().commit()
218 self.assertEqual(repo2.scm_instance.revisions, [cs0.raw_id])
219 r2_id = repo2.repo_id
220 r2_name = repo2.repo_name
221
222 #make 3 new commits in fork
223 cs1 = ScmModel().create_node(
224 repo=repo2.scm_instance, repo_name=r2_name,
225 cs=repo2.scm_instance[-1], user=TEST_USER_ADMIN_LOGIN,
226 author=TEST_USER_ADMIN_LOGIN,
227 message='commit1-fork',
228 content='file1-line1-from-fork',
229 f_path='file1-fork'
230 )
231 cs2 = ScmModel().create_node(
232 repo=repo2.scm_instance, repo_name=r2_name,
233 cs=cs1, user=TEST_USER_ADMIN_LOGIN,
234 author=TEST_USER_ADMIN_LOGIN,
235 message='commit2-fork',
236 content='file2-line1-from-fork',
237 f_path='file2-fork'
238 )
239 cs3 = ScmModel().create_node(
240 repo=repo2.scm_instance, repo_name=r2_name,
241 cs=cs2, user=TEST_USER_ADMIN_LOGIN,
242 author=TEST_USER_ADMIN_LOGIN,
243 message='commit3-fork',
244 content='file3-line1-from-fork',
245 f_path='file3-fork'
246 )
247
248 #compare !
249 rev1 = 'default'
250 rev2 = 'default'
251 response = self.app.get(url(controller='compare', action='index',
252 repo_name=r2_name,
253 org_ref_type="branch",
254 org_ref=rev1,
255 other_ref_type="branch",
256 other_ref=rev2,
257 repo=r1_name
258 ))
259
260 try:
261 response.mustcontain('%s@%s -> %s@%s' % (r2_name, rev1, r1_name, rev2))
262 response.mustcontain("""file1-line1-from-fork""")
263 response.mustcontain("""file2-line1-from-fork""")
264 response.mustcontain("""file3-line1-from-fork""")
265
266 #add new commit into parent !
267 cs0 = ScmModel().create_node(
268 repo=repo1.scm_instance, repo_name=r1_name,
269 cs=EmptyChangeset(alias='hg'), user=TEST_USER_ADMIN_LOGIN,
270 author=TEST_USER_ADMIN_LOGIN,
271 message='commit2',
272 content='line1',
273 f_path='file2'
274 )
275 #compare !
276 rev1 = 'default'
277 rev2 = 'default'
278 response = self.app.get(url(controller='compare', action='index',
279 repo_name=r2_name,
280 org_ref_type="branch",
281 org_ref=rev1,
282 other_ref_type="branch",
283 other_ref=rev2,
284 repo=r1_name
285 ))
286
287 response.mustcontain('%s@%s -> %s@%s' % (r2_name, rev1, r1_name, rev2))
288 response.mustcontain("""file1-line1-from-fork""")
289 response.mustcontain("""file2-line1-from-fork""")
290 response.mustcontain("""file3-line1-from-fork""")
291 finally:
292 RepoModel().delete(r2_id)
293 RepoModel().delete(r1_id)
@@ -1,6 +1,9 b''
1 1 from rhodecode.tests import *
2 2 from rhodecode.model.db import Repository
3 3 from rhodecode.lib.utils import invalidate_cache
4 from rhodecode.model.repo import RepoModel
5 from rhodecode.tests.models.common import _make_repo
6 from rhodecode.model.meta import Session
4 7
5 8
6 9 class TestSummaryController(TestController):
@@ -82,6 +85,20 b' class TestSummaryController(TestControll'
82 85 """title="public repository" alt="public """
83 86 """repository" src="/images/icons/lock_open.png"/>""")
84 87
88 def test_index_by_repo_having_id_path_in_name_hg(self):
89 self.log_user()
90 _make_repo(name='repo_1')
91 Session().commit()
92 response = self.app.get(url(controller='summary',
93 action='index',
94 repo_name='repo_1'))
95
96 try:
97 response.mustcontain("""repo_1""")
98 finally:
99 RepoModel().delete(Repository.get_by_repo_name('repo_1'))
100 Session().commit()
101
85 102 def test_index_by_id_git(self):
86 103 self.log_user()
87 104 ID = Repository.get_by_repo_name(GIT_REPO).repo_id
@@ -1,7 +1,7 b''
1 1 import os
2 2 import unittest
3 3 from rhodecode.tests import *
4
4 from rhodecode.tests.models.common import _make_group
5 5 from rhodecode.model.repos_group import ReposGroupModel
6 6 from rhodecode.model.repo import RepoModel
7 7 from rhodecode.model.db import RepoGroup, User, UsersGroupRepoGroupToPerm
@@ -12,16 +12,6 b' from rhodecode.model.users_group import '
12 12 from rhodecode.lib.auth import AuthUser
13 13
14 14
15 def _make_group(path, desc='desc', parent_id=None,
16 skip_if_exists=False):
17
18 gr = RepoGroup.get_by_group_name(path)
19 if gr and skip_if_exists:
20 return gr
21
22 gr = ReposGroupModel().create(path, desc, parent_id)
23 return gr
24
25 15
26 16 class TestPermissions(unittest.TestCase):
27 17 def __init__(self, methodName='runTest'):
@@ -435,4 +425,3 b' class TestPermissions(unittest.TestCase)'
435 425 set(['hg.create.repository', 'hg.fork.repository',
436 426 'hg.register.manual_activate',
437 427 'repository.read']))
438
@@ -4,7 +4,7 b' from rhodecode.tests import *'
4 4
5 5 from rhodecode.model.repos_group import ReposGroupModel
6 6 from rhodecode.model.repo import RepoModel
7 from rhodecode.model.db import RepoGroup, User
7 from rhodecode.model.db import RepoGroup, User, Repository
8 8 from rhodecode.model.meta import Session
9 9 from sqlalchemy.exc import IntegrityError
10 10
@@ -15,7 +15,8 b" def _make_group(path, desc='desc', paren"
15 15 gr = RepoGroup.get_by_group_name(path)
16 16 if gr and skip_if_exists:
17 17 return gr
18
18 if isinstance(parent_id, RepoGroup):
19 parent_id = parent_id.group_id
19 20 gr = ReposGroupModel().create(path, desc, parent_id)
20 21 return gr
21 22
@@ -54,7 +55,8 b' class TestReposGroups(unittest.TestCase)'
54 55 group_parent_id=parent_id,
55 56 perms_updates=[],
56 57 perms_new=[],
57 enable_locking=False
58 enable_locking=False,
59 recursive=False
58 60 )
59 61 gr = ReposGroupModel().update(id_, form_data)
60 62 return gr
@@ -132,7 +134,8 b' class TestReposGroups(unittest.TestCase)'
132 134 repo_type='hg',
133 135 clone_uri=None,
134 136 landing_rev='tip',
135 enable_locking=False)
137 enable_locking=False,
138 recursive=False)
136 139 cur_user = User.get_by_username(TEST_USER_ADMIN_LOGIN)
137 140 r = RepoModel().create(form_data, cur_user)
138 141
@@ -3,10 +3,14 b" psql -U postgres -h localhost -c 'create"
3 3 paster setup-rhodecode rc.ini -q --user=marcink --password=qweqwe --email=marcin@python-blog.com --repos=/home/marcink/repos
4 4 API_KEY=`psql -R " " -A -U postgres -h localhost -c "select api_key from users where admin=TRUE" -d rhodecode | awk '{print $2}'`
5 5 echo "run those after running server"
6 echo "rhodecode-api --apikey=$API_KEY --apihost=http://127.0.0.1:5001 create_user username:demo1 password:qweqwe email:demo1@rhodecode.org"
7 echo "rhodecode-api --apikey=$API_KEY --apihost=http://127.0.0.1:5001 create_user username:demo2 password:qweqwe email:demo2@rhodecode.org"
8 echo "rhodecode-api --apikey=$API_KEY --apihost=http://127.0.0.1:5001 create_user username:demo3 password:qweqwe email:demo3@rhodecode.org"
9 echo "rhodecode-api --apikey=$API_KEY --apihost=http://127.0.0.1:5001 create_users_group group_name:demo12"
10 echo "rhodecode-api --apikey=$API_KEY --apihost=http://127.0.0.1:5001 add_user_to_users_group usersgroupid:demo12 userid:demo1"
11 echo "rhodecode-api --apikey=$API_KEY --apihost=http://127.0.0.1:5001 add_user_to_users_group usersgroupid:demo12 userid:demo2"
12
6 paster serve rc.ini --pid-file=rc.pid --daemon
7 sleep 3
8 rhodecode-api --apikey=$API_KEY --apihost=http://127.0.0.1:5001 create_user username:demo1 password:qweqwe email:demo1@rhodecode.org
9 rhodecode-api --apikey=$API_KEY --apihost=http://127.0.0.1:5001 create_user username:demo2 password:qweqwe email:demo2@rhodecode.org
10 rhodecode-api --apikey=$API_KEY --apihost=http://127.0.0.1:5001 create_user username:demo3 password:qweqwe email:demo3@rhodecode.org
11 rhodecode-api --apikey=$API_KEY --apihost=http://127.0.0.1:5001 create_users_group group_name:demo12
12 rhodecode-api --apikey=$API_KEY --apihost=http://127.0.0.1:5001 add_user_to_users_group usersgroupid:demo12 userid:demo1
13 rhodecode-api --apikey=$API_KEY --apihost=http://127.0.0.1:5001 add_user_to_users_group usersgroupid:demo12 userid:demo2
14 echo "killing server"
15 kill `cat rc.pid`
16 rm rc.pid
General Comments 0
You need to be logged in to leave comments. Login now